diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..ef874186d --- /dev/null +++ b/.clang-format @@ -0,0 +1,51 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignOperands: true +AllowShortBlocksOnASingleLine: true +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: false +AlwaysBreakTemplateDeclarations: Yes +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: false + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: true + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBraces: Custom +BreakConstructorInitializers: AfterColon +ColumnLimit: 120 +IncludeCategories: + - Regex: '^<.*' + Priority: 1 + - Regex: '^".*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseBlocks: true +IndentWidth: 4 +InsertNewlineAtEOF: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +SpaceAfterTemplateKeyword: false +SpacesInAngles: false +TabWidth: 4 +... diff --git a/.editorconfig b/.editorconfig index 25aaa3207..cb0ffabf0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,216 +1,1482 @@ [*] -charset = utf-8 -end_of_line = lf -trim_trailing_whitespace = false -insert_final_newline = false -indent_style = space -indent_size = 4 +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = false +max_line_length = 120 +tab_width = 2 +trim_trailing_whitespace = true +ij_continuation_indent_size = 4 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = true +ij_smart_tabs = false +ij_visual_guides = +ij_wrap_on_typing = false # Microsoft .NET properties -csharp_new_line_between_query_expression_clauses = false -csharp_preferred_modifier_order = public, private, protected, internal, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async:suggestion -csharp_prefer_braces = false:warning -csharp_space_after_keywords_in_control_flow_statements = false -csharp_style_var_elsewhere = false:suggestion -csharp_style_var_for_built_in_types = false:suggestion -csharp_style_var_when_type_is_apparent = true:suggestion -csharp_using_directive_placement = inside_namespace:silent -dotnet_naming_rule.unity_serialized_field_rule.import_to_resharper = True -dotnet_naming_rule.unity_serialized_field_rule.resharper_description = Unity serialized field -dotnet_naming_rule.unity_serialized_field_rule.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef -dotnet_naming_rule.unity_serialized_field_rule.severity = warning -dotnet_naming_rule.unity_serialized_field_rule.style = lower_camel_case_style -dotnet_naming_rule.unity_serialized_field_rule.symbols = unity_serialized_field_symbols -dotnet_naming_rule.unity_serialized_field_rule_1.import_to_resharper = True -dotnet_naming_rule.unity_serialized_field_rule_1.resharper_description = Unity serialized field -dotnet_naming_rule.unity_serialized_field_rule_1.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef -dotnet_naming_rule.unity_serialized_field_rule_1.severity = warning -dotnet_naming_rule.unity_serialized_field_rule_1.style = lower_camel_case_style -dotnet_naming_rule.unity_serialized_field_rule_1.symbols = unity_serialized_field_symbols_1 -dotnet_naming_style.lower_camel_case_style.capitalization = camel_case -dotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities = * -dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds = -dotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds = unity_serialised_field -dotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers = instance -dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_accessibilities = * -dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_kinds = -dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_applicable_kinds = unity_serialised_field -dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_required_modifiers = instance -dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:warning -dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:warning -dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:warning -dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion -dotnet_style_predefined_type_for_member_access = true:suggestion -dotnet_style_qualification_for_event = false:suggestion -dotnet_style_qualification_for_field = false:suggestion -dotnet_style_qualification_for_method = false:suggestion -dotnet_style_qualification_for_property = false:suggestion -dotnet_style_require_accessibility_modifiers = never:suggestion +csharp_preferred_modifier_order = public, private, protected, internal, file, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async, required:suggestion +csharp_space_after_keywords_in_control_flow_statements = false +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_prefer_utf8_string_literals = true:warning +csharp_style_var_elsewhere = false:suggestion +csharp_style_var_for_built_in_types = false:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_using_directive_placement = outside_namespace:silent +dotnet_naming_rule.constants_rule.import_to_resharper = True +dotnet_naming_rule.constants_rule.resharper_description = Constant fields (not private) +dotnet_naming_rule.constants_rule.resharper_guid = 669e5282-fb4b-4e90-91e7-07d269d04b60 +dotnet_naming_rule.constants_rule.severity = warning +dotnet_naming_rule.constants_rule.style = upper_camel_case_style +dotnet_naming_rule.constants_rule.symbols = constants_symbols +dotnet_naming_rule.private_constants_rule.import_to_resharper = True +dotnet_naming_rule.private_constants_rule.resharper_description = Constant fields (private) +dotnet_naming_rule.private_constants_rule.resharper_guid = 236f7aa5-7b06-43ca-bf2a-9b31bfcff09a +dotnet_naming_rule.private_constants_rule.severity = warning +dotnet_naming_rule.private_constants_rule.style = all_upper_style +dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols +dotnet_naming_rule.public_static_fields_rule.import_to_resharper = True +dotnet_naming_rule.public_static_fields_rule.resharper_description = Static fields (not private) +dotnet_naming_rule.public_static_fields_rule.resharper_guid = 70345118-4b40-4ece-937c-bbeb7a0b2e70 +dotnet_naming_rule.public_static_fields_rule.severity = warning +dotnet_naming_rule.public_static_fields_rule.style = lower_camel_case_style_1 +dotnet_naming_rule.public_static_fields_rule.symbols = public_static_fields_symbols +dotnet_naming_rule.static_readonly_rule.import_to_resharper = True +dotnet_naming_rule.static_readonly_rule.resharper_description = Static readonly fields (not private) +dotnet_naming_rule.static_readonly_rule.resharper_guid = c873eafb-d57f-481d-8c93-77f6863c2f88 +dotnet_naming_rule.static_readonly_rule.severity = warning +dotnet_naming_rule.static_readonly_rule.style = upper_camel_case_style +dotnet_naming_rule.static_readonly_rule.symbols = static_readonly_symbols +dotnet_naming_rule.unity_serialized_field_rule.import_to_resharper = True +dotnet_naming_rule.unity_serialized_field_rule.resharper_description = Unity serialized field +dotnet_naming_rule.unity_serialized_field_rule.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef +dotnet_naming_rule.unity_serialized_field_rule.severity = warning +dotnet_naming_rule.unity_serialized_field_rule.style = lower_camel_case_style +dotnet_naming_rule.unity_serialized_field_rule.symbols = unity_serialized_field_symbols +dotnet_naming_rule.unity_serialized_field_rule_1.import_to_resharper = True +dotnet_naming_rule.unity_serialized_field_rule_1.resharper_description = Unity serialized field +dotnet_naming_rule.unity_serialized_field_rule_1.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef +dotnet_naming_rule.unity_serialized_field_rule_1.severity = warning +dotnet_naming_rule.unity_serialized_field_rule_1.style = lower_camel_case_style +dotnet_naming_rule.unity_serialized_field_rule_1.symbols = unity_serialized_field_symbols_1 +dotnet_naming_style.all_upper_style.capitalization = all_upper +dotnet_naming_style.all_upper_style.word_separator = _ +dotnet_naming_style.lower_camel_case_style.capitalization = camel_case +dotnet_naming_style.lower_camel_case_style_1.capitalization = camel_case +dotnet_naming_style.lower_camel_case_style_1.required_prefix = _ +dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case +dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected +dotnet_naming_symbols.constants_symbols.applicable_kinds = field +dotnet_naming_symbols.constants_symbols.required_modifiers = const +dotnet_naming_symbols.constants_symbols.resharper_applicable_kinds = constant_field +dotnet_naming_symbols.constants_symbols.resharper_required_modifiers = any +dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field +dotnet_naming_symbols.private_constants_symbols.required_modifiers = const +dotnet_naming_symbols.public_static_fields_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected +dotnet_naming_symbols.public_static_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.public_static_fields_symbols.required_modifiers = static +dotnet_naming_symbols.public_static_fields_symbols.resharper_applicable_kinds = field +dotnet_naming_symbols.public_static_fields_symbols.resharper_required_modifiers = static +dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected +dotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field +dotnet_naming_symbols.static_readonly_symbols.required_modifiers = readonly, static +dotnet_naming_symbols.static_readonly_symbols.resharper_applicable_kinds = readonly_field +dotnet_naming_symbols.static_readonly_symbols.resharper_required_modifiers = static +dotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities = * +dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds = +dotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds = unity_serialised_field +dotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers = instance +dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_accessibilities = * +dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_kinds = +dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_applicable_kinds = unity_serialised_field +dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_required_modifiers = instance +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:warning +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:warning +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion +dotnet_style_qualification_for_event = false:suggestion +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_require_accessibility_modifiers = never:suggestion # ReSharper properties -resharper_align_first_arg_by_paren = true -resharper_align_linq_query = true -resharper_align_multiline_argument = true -resharper_align_multiline_binary_expressions_chain = true -resharper_align_multiline_binary_patterns = true -resharper_align_multiline_calls_chain = true -resharper_align_multiline_expression = true -resharper_align_multiline_extends_list = true -resharper_align_multiline_for_stmt = true -resharper_align_multiline_parameter = true -resharper_align_multiline_property_pattern = true -resharper_align_multiline_switch_expression = true -resharper_align_multiple_declaration = true -resharper_align_multline_type_parameter_constrains = true -resharper_align_multline_type_parameter_list = true -resharper_align_tuple_components = true -resharper_attribute_indent = align_by_first_attribute -resharper_attribute_style = on_single_line -resharper_autodetect_indent_settings = true -resharper_constructor_or_destructor_body = expression_body -resharper_cpp_brace_style = next_line -resharper_csharp_outdent_commas = true -resharper_default_value_when_type_not_evident = default_expression -resharper_empty_block_style = together_same_line -resharper_force_attribute_style = join -resharper_force_chop_compound_do_expression = true -resharper_force_chop_compound_if_expression = true -resharper_force_chop_compound_while_expression = true -resharper_for_built_in_types = use_var_when_evident -resharper_fsharp_type_declaration_braces = next_line -resharper_indent_nested_fixed_stmt = true -resharper_indent_nested_foreach_stmt = true -resharper_indent_nested_for_stmt = true -resharper_indent_nested_lock_stmt = true -resharper_indent_nested_usings_stmt = true -resharper_indent_nested_while_stmt = true -resharper_indent_preprocessor_if = outdent -resharper_indent_preprocessor_other = usual_indent -resharper_indent_switch_labels = true -resharper_int_align_assignments = true -resharper_int_align_binary_expressions = true -resharper_int_align_comments = true -resharper_int_align_fields = true -resharper_int_align_methods = true -resharper_int_align_nested_ternary = true -resharper_int_align_properties = true -resharper_int_align_property_patterns = true -resharper_int_align_switch_expressions = true -resharper_int_align_switch_sections = true -resharper_int_align_variables = true -resharper_keep_existing_arrangement = false -resharper_keep_user_linebreaks = false -resharper_linebreak_before_all_elements = true -resharper_local_function_body = expression_body -resharper_max_blank_lines_between_tags = 0 -resharper_max_enum_members_on_line = 1 -resharper_method_or_operator_body = expression_body -resharper_nested_ternary_style = expanded -resharper_new_line_before_while = false -resharper_normalize_tag_names = true -resharper_outdent_binary_ops = true -resharper_outdent_binary_pattern_ops = true -resharper_outdent_dots = true -resharper_outdent_statement_labels = true -resharper_place_attribute_on_same_line = false -resharper_place_expr_accessor_on_single_line = true -resharper_place_expr_method_on_single_line = true -resharper_place_expr_property_on_single_line = true -resharper_place_linq_into_on_new_line = false -resharper_place_simple_anonymousmethod_on_single_line = false -resharper_place_simple_case_statement_on_same_line = true -resharper_place_simple_embedded_statement_on_same_line = false -resharper_place_simple_initializer_on_single_line = false -resharper_place_simple_switch_expression_on_single_line = true -resharper_prefer_explicit_discard_declaration = true -resharper_qualified_using_at_nested_scope = true -resharper_show_autodetect_configure_formatting_tip = false -resharper_sort_attributes = true -resharper_sort_class_selectors = true -resharper_space_after_keywords_in_control_flow_statements = false -resharper_space_after_last_pi_attribute = true -resharper_space_after_unary_operator = false -resharper_space_around_binary_operator = true -resharper_space_before_self_closing = true -resharper_space_within_empty_braces = false -resharper_stick_comment = false -resharper_use_indent_from_vs = false -resharper_wrap_after_dot_in_method_calls = true -resharper_wrap_before_first_type_parameter_constraint = true -resharper_wrap_before_type_parameter_langle = true -resharper_wrap_enum_declaration = wrap_if_long -resharper_wrap_for_stmt_header_style = wrap_if_long -resharper_wrap_lines = true -resharper_wrap_multiple_declaration_style = wrap_if_long -resharper_wrap_multiple_type_parameter_constraints_style = wrap_if_long -resharper_wrap_object_and_collection_initializer_style = chop_always -resharper_wrap_ternary_expr_style = wrap_if_long -resharper_wrap_verbatim_interpolated_strings = wrap_if_long +resharper_align_first_arg_by_paren = false +resharper_align_linq_query = true +resharper_align_multiline_argument = true +resharper_align_multiline_array_and_object_initializer = false +resharper_align_multiline_binary_expressions_chain = true +resharper_align_multiline_binary_patterns = true +resharper_align_multiline_calls_chain = true +resharper_align_multiline_expression = true +resharper_align_multiline_expression_braces = true +resharper_align_multiline_extends_list = true +resharper_align_multiline_for_stmt = true +resharper_align_multiline_list_pattern = true +resharper_align_multiline_parameter = true +resharper_align_multiline_property_pattern = true +resharper_align_multiline_switch_expression = true +resharper_align_multiple_declaration = true +resharper_align_multline_type_parameter_constrains = true +resharper_align_multline_type_parameter_list = true +resharper_align_ternary = align_all +resharper_align_tuple_components = true +resharper_autodetect_indent_settings = true +resharper_blank_lines_after_multiline_statements = 1 +resharper_blank_lines_around_auto_property = 0 +resharper_blank_lines_before_block_statements = 1 +resharper_blank_lines_before_control_transfer_statements = 1 +resharper_blank_lines_before_multiline_statements = 1 +resharper_blank_lines_before_single_line_comment = 1 +resharper_braces_for_for = required_for_multiline +resharper_braces_for_foreach = required_for_multiline +resharper_braces_for_ifelse = required_for_multiline +resharper_braces_for_while = required_for_multiline +resharper_builtin_type_apply_to_native_integer = false +resharper_constructor_or_destructor_body = expression_body +resharper_continuous_indent_multiplier = 1 +resharper_cpp_allow_comment_after_lbrace = true +resharper_cpp_keep_blank_lines_in_code = 1 +resharper_cpp_keep_blank_lines_in_declarations = 1 +resharper_cpp_keep_user_linebreaks = false +resharper_cpp_wrap_parameters_style = chop_if_long +resharper_csharp_align_first_arg_by_paren = true +resharper_csharp_blank_lines_around_field = 0 +resharper_csharp_continuous_indent_multiplier = 1 +resharper_csharp_empty_block_style = together_same_line +resharper_csharp_int_align_fix_in_adjacent = true +resharper_csharp_place_comments_at_first_column = true +resharper_csharp_prefer_qualified_reference = false +resharper_csharp_wrap_arguments_style = chop_if_long +resharper_csharp_wrap_extends_list_style = chop_if_long +resharper_default_value_when_type_not_evident = default_expression +resharper_empty_block_style = together_same_line +resharper_enforce_line_ending_style = true +resharper_formatter_off_tag = @formatter:off +resharper_formatter_on_tag = @formatter:on +resharper_formatter_tags_enabled = true +resharper_for_built_in_types = use_var_when_evident +resharper_function_declaration_return_type_style = on_single_line +resharper_function_definition_return_type_style = on_single_line +resharper_html_attribute_style = on_single_line +resharper_html_max_blank_lines_between_tags = 1 +resharper_html_pi_attribute_style = first_attribute_on_single_line +resharper_indent_anonymous_method_block = false +resharper_indent_goto_labels = false +resharper_indent_nested_fixed_stmt = true +resharper_indent_nested_foreach_stmt = true +resharper_indent_nested_for_stmt = true +resharper_indent_nested_lock_stmt = true +resharper_indent_nested_usings_stmt = true +resharper_indent_nested_while_stmt = true +resharper_indent_preprocessor_if = no_indent +resharper_indent_preprocessor_other = no_indent +resharper_indent_preprocessor_region = no_indent +resharper_indent_primary_constructor_decl_pars = inside +resharper_indent_switch_labels = true +resharper_int_align = true +resharper_int_align_bitfield_sizes = true +resharper_int_align_comments = true +resharper_int_align_declaration_names = true +resharper_int_align_enum_initializers = true +resharper_int_align_eq = true +resharper_int_align_fix_in_adjacent = true +resharper_keep_existing_declaration_parens_arrangement = false +resharper_keep_existing_embedded_arrangement = false +resharper_keep_existing_enum_arrangement = false +resharper_keep_existing_expr_member_arrangement = false +resharper_keep_existing_initializer_arrangement = false +resharper_keep_existing_linebreaks = false +resharper_keep_existing_list_patterns_arrangement = false +resharper_keep_existing_primary_constructor_declaration_parens_arrangement = false +resharper_keep_existing_property_patterns_arrangement = false +resharper_keep_existing_switch_expression_arrangement = false +resharper_line_break_after_colon_in_member_initializer_lists = on_single_line +resharper_line_break_after_deref_in_trailing_return_types = on_single_line +resharper_line_break_before_deref_in_trailing_return_types = on_single_line +resharper_line_break_before_requires_clause = on_single_line +resharper_linkage_specification_braces = next_line +resharper_linkage_specification_indentation = all +resharper_local_function_body = expression_body +resharper_max_enum_members_on_line = 1 +resharper_max_initializer_elements_on_line = 1 +resharper_member_initializer_list_style = on_single_line +resharper_method_or_operator_body = expression_body +resharper_nested_ternary_style = expanded +resharper_normalize_tag_names = true +resharper_outdent_binary_ops = true +resharper_outdent_binary_pattern_ops = true +resharper_outdent_commas = true +resharper_outdent_dots = true +resharper_outdent_statement_labels = true +resharper_parentheses_redundancy_style = remove +resharper_place_attribute_on_same_line = false +resharper_place_expr_accessor_on_single_line = true +resharper_place_expr_method_on_single_line = true +resharper_place_expr_property_on_single_line = true +resharper_place_simple_embedded_statement_on_same_line = if_owner_is_single_line +resharper_place_simple_initializer_on_single_line = false +resharper_qualified_using_at_nested_scope = true +resharper_show_autodetect_configure_formatting_tip = false +resharper_simple_block_style = on_single_line +resharper_simple_case_statement_style = line_break +resharper_simple_embedded_statement_style = on_single_line +resharper_sort_attributes = true +resharper_sort_class_selectors = true +resharper_space_after_keywords_in_control_flow_statements = false +resharper_space_after_ptr_in_data_member = false +resharper_space_after_ptr_in_method = false +resharper_space_after_ref_in_data_member = false +resharper_space_after_ref_in_method = false +resharper_space_before_ptr_in_data_member = true +resharper_space_before_ptr_in_method = true +resharper_space_before_ref_in_data_member = true +resharper_space_before_ref_in_method = true +resharper_space_before_template_params = false +resharper_space_within_empty_braces = false +resharper_toplevel_function_declaration_return_type_style = on_single_line +resharper_toplevel_function_definition_return_type_style = on_single_line +resharper_use_continuous_indent_inside_initializer_braces = false +resharper_use_continuous_indent_inside_parens = false +resharper_use_indent_from_vs = false +resharper_wrap_after_dot_in_method_calls = false +resharper_wrap_base_clause_style = chop_if_long +resharper_wrap_before_primary_constructor_declaration_lpar = true +resharper_wrap_before_primary_constructor_declaration_rpar = true +resharper_wrap_braced_init_list_style = chop_if_long +resharper_wrap_chained_binary_expressions = chop_if_long +resharper_wrap_chained_binary_patterns = chop_if_long +resharper_wrap_chained_method_calls = chop_if_long +resharper_wrap_ctor_initializer_style = chop_if_long +resharper_wrap_enum_declaration = chop_if_long +resharper_wrap_lines = true +resharper_xmldoc_attribute_indent = align_by_first_attribute +resharper_xmldoc_attribute_style = first_attribute_on_single_line +resharper_xmldoc_pi_attribute_style = first_attribute_on_single_line +resharper_xml_attribute_style = first_attribute_on_single_line +resharper_xml_keep_user_linebreaks = false +resharper_xml_pi_attribute_style = first_attribute_on_single_line # ReSharper inspection severities -resharper_annotate_can_be_null_parameter_highlighting = warning -resharper_annotate_can_be_null_type_member_highlighting = warning -resharper_annotate_not_null_parameter_highlighting = warning -resharper_annotate_not_null_type_member_highlighting = warning -resharper_arrange_attributes_highlighting = hint -resharper_arrange_constructor_or_destructor_body_highlighting = warning -resharper_arrange_default_value_when_type_evident_highlighting = warning -resharper_arrange_default_value_when_type_not_evident_highlighting = warning -resharper_arrange_local_function_body_highlighting = warning -resharper_arrange_method_or_operator_body_highlighting = warning -resharper_arrange_object_creation_when_type_evident_highlighting = warning -resharper_arrange_object_creation_when_type_not_evident_highlighting = warning -resharper_arrange_redundant_parentheses_highlighting = hint -resharper_arrange_this_qualifier_highlighting = hint -resharper_arrange_type_member_modifiers_highlighting = hint -resharper_arrange_type_modifiers_highlighting = hint -resharper_async_void_method_highlighting = warning -resharper_built_in_type_reference_style_for_member_access_highlighting = hint -resharper_built_in_type_reference_style_highlighting = hint -resharper_compare_non_constrained_generic_with_null_highlighting = warning -resharper_heap_view_boxing_allocation_highlighting = none -resharper_heap_view_delegate_allocation_highlighting = none -resharper_heap_view_object_allocation_evident_highlighting = none -resharper_heap_view_object_allocation_highlighting = none -resharper_inheritdoc_consider_usage_highlighting = warning -resharper_local_function_can_be_made_static_highlighting = warning -resharper_loop_can_be_partly_converted_to_query_highlighting = warning -resharper_member_can_be_internal_highlighting = warning -resharper_nullable_warning_suppression_is_used_highlighting = warning -resharper_redundant_base_qualifier_highlighting = warning -resharper_remove_constructor_invocation_highlighting = warning -resharper_separate_control_transfer_statement_highlighting = warning -resharper_string_ends_with_is_culture_specific_highlighting = warning -resharper_string_starts_with_is_culture_specific_highlighting = warning -resharper_struct_member_can_be_made_read_only_highlighting = warning -resharper_suggest_var_or_type_built_in_types_highlighting = hint -resharper_suggest_var_or_type_elsewhere_highlighting = hint -resharper_suggest_var_or_type_simple_types_highlighting = hint -resharper_tabs_are_disallowed_highlighting = warning -resharper_unnecessary_whitespace_highlighting = warning -resharper_use_nameof_expression_for_part_of_the_string_highlighting = warning -resharper_use_positional_deconstruction_pattern_highlighting = warning -resharper_web_config_module_not_resolved_highlighting = warning -resharper_web_config_type_not_resolved_highlighting = warning -resharper_web_config_wrong_module_highlighting = warning +resharper_annotate_can_be_null_parameter_highlighting = warning +resharper_annotate_can_be_null_type_member_highlighting = warning +resharper_annotate_not_null_parameter_highlighting = warning +resharper_annotate_not_null_type_member_highlighting = warning +resharper_arguments_style_anonymous_function_highlighting = warning +resharper_arguments_style_literal_highlighting = warning +resharper_arguments_style_named_expression_highlighting = warning +resharper_arguments_style_other_highlighting = warning +resharper_arguments_style_string_literal_highlighting = warning +resharper_arrange_accessor_owner_body_highlighting = warning +resharper_arrange_constructor_or_destructor_body_highlighting = warning +resharper_arrange_local_function_body_highlighting = warning +resharper_arrange_method_or_operator_body_highlighting = warning +resharper_arrange_redundant_parentheses_highlighting = hint +resharper_arrange_static_member_qualifier_highlighting = warning +resharper_arrange_this_qualifier_highlighting = hint +resharper_arrange_trailing_comma_in_multiline_lists_highlighting = warning +resharper_arrange_trailing_comma_in_singleline_lists_highlighting = warning +resharper_arrange_type_member_modifiers_highlighting = hint +resharper_arrange_type_modifiers_highlighting = hint +resharper_arrange_var_keywords_in_deconstructing_declaration_highlighting = warning +resharper_async_void_method_highlighting = warning +resharper_auto_property_can_be_made_get_only_global_highlighting = warning +resharper_auto_property_can_be_made_get_only_local_highlighting = warning +resharper_bad_attribute_brackets_spaces_highlighting = warning +resharper_bad_braces_spaces_highlighting = warning +resharper_bad_colon_spaces_highlighting = warning +resharper_bad_comma_spaces_highlighting = warning +resharper_bad_control_braces_indent_highlighting = warning +resharper_bad_control_braces_line_breaks_highlighting = warning +resharper_bad_declaration_braces_indent_highlighting = warning +resharper_bad_declaration_braces_line_breaks_highlighting = warning +resharper_bad_empty_braces_line_breaks_highlighting = warning +resharper_bad_expression_braces_indent_highlighting = warning +resharper_bad_expression_braces_line_breaks_highlighting = warning +resharper_bad_generic_brackets_spaces_highlighting = warning +resharper_bad_indent_highlighting = warning +resharper_bad_linq_line_breaks_highlighting = warning +resharper_bad_member_access_spaces_highlighting = warning +resharper_bad_namespace_braces_indent_highlighting = warning +resharper_bad_parens_line_breaks_highlighting = warning +resharper_bad_parens_spaces_highlighting = warning +resharper_bad_preprocessor_indent_highlighting = warning +resharper_bad_semicolon_spaces_highlighting = warning +resharper_bad_spaces_after_keyword_highlighting = warning +resharper_bad_square_brackets_spaces_highlighting = warning +resharper_bad_switch_braces_indent_highlighting = warning +resharper_bad_symbol_spaces_highlighting = warning +resharper_built_in_type_reference_style_for_member_access_highlighting = hint +resharper_built_in_type_reference_style_highlighting = hint +resharper_check_for_reference_equality_instead_1_highlighting = warning +resharper_check_for_reference_equality_instead_2_highlighting = warning +resharper_check_for_reference_equality_instead_3_highlighting = warning +resharper_check_for_reference_equality_instead_4_highlighting = warning +resharper_class_can_be_sealed_global_highlighting = warning +resharper_class_can_be_sealed_local_highlighting = warning +resharper_class_never_instantiated_global_highlighting = warning +resharper_class_never_instantiated_local_highlighting = warning +resharper_class_with_virtual_members_never_inherited_global_highlighting = warning +resharper_class_with_virtual_members_never_inherited_local_highlighting = warning +resharper_comment_typo_highlighting = none +resharper_compare_non_constrained_generic_with_null_highlighting = warning +resharper_convert_closure_to_method_group_highlighting = warning +resharper_convert_conditional_ternary_expression_to_switch_expression_highlighting = warning +resharper_convert_if_do_to_while_highlighting = warning +resharper_convert_if_statement_to_conditional_ternary_expression_highlighting = warning +resharper_convert_if_statement_to_null_coalescing_assignment_highlighting = warning +resharper_convert_if_statement_to_null_coalescing_expression_highlighting = warning +resharper_convert_if_statement_to_return_statement_highlighting = warning +resharper_convert_if_statement_to_switch_statement_highlighting = warning +resharper_convert_if_to_or_expression_highlighting = warning +resharper_convert_nullable_to_short_form_highlighting = warning +resharper_convert_switch_statement_to_switch_expression_highlighting = warning +resharper_convert_to_auto_property_highlighting = warning +resharper_convert_to_auto_property_when_possible_highlighting = warning +resharper_convert_to_auto_property_with_private_setter_highlighting = warning +resharper_convert_to_compound_assignment_highlighting = warning +resharper_convert_to_constant_global_highlighting = warning +resharper_convert_to_constant_local_highlighting = warning +resharper_convert_to_lambda_expression_highlighting = warning +resharper_convert_to_local_function_highlighting = warning +resharper_convert_to_null_coalescing_compound_assignment_highlighting = warning +resharper_convert_to_primary_constructor_highlighting = warning +resharper_convert_to_static_class_highlighting = warning +resharper_convert_to_using_declaration_highlighting = warning +resharper_cpp_enforce_cv_qualifiers_order_highlighting = hint +resharper_cpp_enforce_cv_qualifiers_placement_highlighting = hint +resharper_cpp_enforce_do_statement_braces_highlighting = hint +resharper_cpp_enforce_for_statement_braces_highlighting = hint +resharper_cpp_enforce_function_declaration_style_highlighting = hint +resharper_cpp_enforce_if_statement_braces_highlighting = hint +resharper_cpp_enforce_type_alias_code_style_highlighting = hint +resharper_cpp_enforce_while_statement_braces_highlighting = hint +resharper_cpp_remove_redundant_braces_highlighting = hint +resharper_double_negation_in_pattern_highlighting = warning +resharper_double_negation_operator_highlighting = warning +resharper_event_never_invoked_global_highlighting = warning +resharper_event_never_subscribed_to_global_highlighting = warning +resharper_event_never_subscribed_to_local_highlighting = warning +resharper_field_can_be_made_read_only_global_highlighting = warning +resharper_field_can_be_made_read_only_local_highlighting = warning +resharper_foreach_can_be_converted_to_query_using_another_get_enumerator_highlighting = warning +resharper_foreach_can_be_partly_converted_to_query_using_another_get_enumerator_highlighting = none +resharper_for_can_be_converted_to_foreach_highlighting = warning +resharper_heap_view_boxing_allocation_highlighting = none +resharper_heap_view_closure_allocation_highlighting = none +resharper_heap_view_delegate_allocation_highlighting = none +resharper_heap_view_object_allocation_evident_highlighting = none +resharper_heap_view_object_allocation_highlighting = none +resharper_identifier_typo_highlighting = none +resharper_incorrect_blank_lines_near_braces_highlighting = warning +resharper_inheritdoc_consider_usage_highlighting = warning +resharper_inline_out_variable_declaration_highlighting = warning +resharper_inline_temporary_variable_highlighting = warning +resharper_introduce_optional_parameters_global_highlighting = warning +resharper_introduce_optional_parameters_local_highlighting = warning +resharper_invert_condition_1_highlighting = warning +resharper_invert_if_highlighting = warning +resharper_invocation_is_skipped_highlighting = warning +resharper_invoke_as_extension_method_highlighting = warning +resharper_join_declaration_and_initializer_highlighting = warning +resharper_join_null_check_with_usage_highlighting = warning +resharper_lambda_expression_must_be_static_highlighting = warning +resharper_localizable_element_highlighting = error +resharper_local_function_can_be_made_static_highlighting = warning +resharper_loop_can_be_converted_to_query_highlighting = warning +resharper_loop_can_be_partly_converted_to_query_highlighting = warning +resharper_member_can_be_file_local_highlighting = warning +resharper_member_can_be_internal_highlighting = warning +resharper_member_can_be_made_static_global_highlighting = warning +resharper_member_can_be_made_static_local_highlighting = warning +resharper_member_can_be_private_global_highlighting = warning +resharper_member_can_be_private_local_highlighting = warning +resharper_member_can_be_protected_global_highlighting = warning +resharper_member_can_be_protected_local_highlighting = warning +resharper_merge_and_pattern_highlighting = warning +resharper_merge_cast_with_type_check_highlighting = warning +resharper_merge_conditional_expression_highlighting = warning +resharper_merge_into_logical_pattern_highlighting = warning +resharper_merge_into_negated_pattern_highlighting = warning +resharper_merge_into_pattern_highlighting = warning +resharper_merge_nested_property_patterns_highlighting = warning +resharper_merge_sequential_checks_highlighting = warning +resharper_method_has_async_overload_highlighting = warning +resharper_method_has_async_overload_with_cancellation_highlighting = warning +resharper_method_supports_cancellation_highlighting = warning +resharper_missing_blank_lines_highlighting = warning +resharper_missing_linebreak_highlighting = warning +resharper_missing_space_highlighting = warning +resharper_more_specific_foreach_variable_type_available_highlighting = warning +resharper_move_to_existing_positional_deconstruction_pattern_highlighting = warning +resharper_move_variable_declaration_inside_loop_condition_highlighting = warning +resharper_multiple_spaces_highlighting = warning +resharper_multiple_statements_on_one_line_highlighting = warning +resharper_multiple_type_members_on_one_line_highlighting = warning +resharper_negation_of_relational_pattern_highlighting = warning +resharper_negative_equality_expression_highlighting = warning +resharper_nested_string_interpolation_highlighting = warning +resharper_not_accessed_field_global_highlighting = warning +resharper_nullable_warning_suppression_is_used_highlighting = warning +resharper_outdent_is_off_prev_level_highlighting = warning +resharper_out_parameter_value_is_always_discarded_global_highlighting = warning +resharper_parameter_only_used_for_precondition_check_global_highlighting = warning +resharper_parameter_type_can_be_enumerable_global_highlighting = warning +resharper_parameter_type_can_be_enumerable_local_highlighting = warning +resharper_pass_string_interpolation_highlighting = warning +resharper_possible_unintended_queryable_as_enumerable_highlighting = warning +resharper_property_can_be_made_init_only_global_highlighting = warning +resharper_property_can_be_made_init_only_local_highlighting = warning +resharper_public_constructor_in_abstract_class_highlighting = warning +resharper_raw_string_can_be_simplified_highlighting = warning +resharper_razor_assembly_not_resolved_highlighting = warning +resharper_redundant_accessor_body_highlighting = warning +resharper_redundant_always_match_subpattern_highlighting = warning +resharper_redundant_array_creation_expression_highlighting = warning +resharper_redundant_attribute_parentheses_highlighting = warning +resharper_redundant_attribute_usage_property_highlighting = warning +resharper_redundant_base_qualifier_highlighting = warning +resharper_redundant_blank_lines_highlighting = warning +resharper_redundant_collection_initializer_element_braces_highlighting = warning +resharper_redundant_configure_await_highlighting = warning +resharper_redundant_declaration_semicolon_highlighting = warning +resharper_redundant_discard_designation_highlighting = warning +resharper_redundant_empty_object_creation_argument_list_highlighting = warning +resharper_redundant_enum_case_label_for_default_section_highlighting = warning +resharper_redundant_explicit_params_array_creation_highlighting = warning +resharper_redundant_fixed_pointer_declaration_highlighting = warning +resharper_redundant_if_else_block_highlighting = warning +resharper_redundant_immediate_delegate_invocation_highlighting = warning +resharper_redundant_is_before_relational_pattern_highlighting = warning +resharper_redundant_lambda_signature_parentheses_highlighting = warning +resharper_redundant_overload_global_highlighting = warning +resharper_redundant_overload_local_highlighting = warning +resharper_redundant_pattern_parentheses_highlighting = warning +resharper_redundant_property_pattern_clause_highlighting = warning +resharper_redundant_query_order_by_ascending_keyword_highlighting = warning +resharper_redundant_range_bound_highlighting = warning +resharper_redundant_readonly_modifier_highlighting = warning +resharper_redundant_space_highlighting = warning +resharper_redundant_string_interpolation_highlighting = warning +resharper_redundant_to_string_call_for_value_type_highlighting = warning +resharper_redundant_verbatim_prefix_highlighting = warning +resharper_redundant_verbatim_string_prefix_highlighting = warning +resharper_redundant_with_expression_highlighting = warning +resharper_remove_constructor_invocation_highlighting = warning +resharper_remove_redundant_braces_highlighting = warning +resharper_remove_redundant_or_statement_false_highlighting = warning +resharper_remove_redundant_or_statement_true_highlighting = warning +resharper_remove_to_list_1_highlighting = warning +resharper_remove_to_list_2_highlighting = warning +resharper_replace_auto_property_with_computed_property_highlighting = warning +resharper_replace_conditional_expression_with_null_coalescing_highlighting = warning +resharper_replace_object_pattern_with_var_pattern_highlighting = warning +resharper_replace_slice_with_range_indexer_highlighting = warning +resharper_replace_substring_with_range_indexer_highlighting = warning +resharper_replace_with_field_keyword_highlighting = warning +resharper_replace_with_first_or_default_1_highlighting = warning +resharper_replace_with_first_or_default_2_highlighting = warning +resharper_replace_with_first_or_default_3_highlighting = warning +resharper_replace_with_first_or_default_4_highlighting = warning +resharper_replace_with_last_or_default_1_highlighting = warning +resharper_replace_with_last_or_default_2_highlighting = warning +resharper_replace_with_last_or_default_3_highlighting = warning +resharper_replace_with_last_or_default_4_highlighting = warning +resharper_replace_with_of_type_1_highlighting = warning +resharper_replace_with_of_type_2_highlighting = warning +resharper_replace_with_of_type_3_highlighting = warning +resharper_replace_with_of_type_any_1_highlighting = warning +resharper_replace_with_of_type_any_2_highlighting = warning +resharper_replace_with_of_type_count_1_highlighting = warning +resharper_replace_with_of_type_count_2_highlighting = warning +resharper_replace_with_of_type_first_1_highlighting = warning +resharper_replace_with_of_type_first_2_highlighting = warning +resharper_replace_with_of_type_first_or_default_1_highlighting = warning +resharper_replace_with_of_type_first_or_default_2_highlighting = warning +resharper_replace_with_of_type_last_1_highlighting = warning +resharper_replace_with_of_type_last_2_highlighting = warning +resharper_replace_with_of_type_last_or_default_1_highlighting = warning +resharper_replace_with_of_type_last_or_default_2_highlighting = warning +resharper_replace_with_of_type_long_count_highlighting = warning +resharper_replace_with_of_type_single_1_highlighting = warning +resharper_replace_with_of_type_single_2_highlighting = warning +resharper_replace_with_of_type_single_or_default_1_highlighting = warning +resharper_replace_with_of_type_single_or_default_2_highlighting = warning +resharper_replace_with_of_type_where_highlighting = warning +resharper_replace_with_simple_assignment_false_highlighting = warning +resharper_replace_with_simple_assignment_true_highlighting = warning +resharper_replace_with_single_assignment_false_highlighting = warning +resharper_replace_with_single_assignment_true_highlighting = warning +resharper_replace_with_single_call_to_any_highlighting = warning +resharper_replace_with_single_call_to_count_highlighting = warning +resharper_replace_with_single_call_to_first_highlighting = warning +resharper_replace_with_single_call_to_first_or_default_highlighting = warning +resharper_replace_with_single_call_to_last_highlighting = warning +resharper_replace_with_single_call_to_last_or_default_highlighting = warning +resharper_replace_with_single_call_to_single_highlighting = warning +resharper_replace_with_single_call_to_single_or_default_highlighting = warning +resharper_replace_with_single_or_default_1_highlighting = warning +resharper_replace_with_single_or_default_2_highlighting = warning +resharper_replace_with_single_or_default_3_highlighting = warning +resharper_replace_with_single_or_default_4_highlighting = warning +resharper_replace_with_string_is_null_or_empty_highlighting = warning +resharper_return_type_can_be_enumerable_global_highlighting = warning +resharper_return_type_can_be_enumerable_local_highlighting = warning +resharper_safe_cast_is_used_as_type_check_highlighting = warning +resharper_separate_control_transfer_statement_highlighting = warning +resharper_similar_anonymous_type_nearby_highlighting = warning +resharper_simplify_conditional_ternary_expression_highlighting = warning +resharper_simplify_linq_expression_use_all_highlighting = warning +resharper_simplify_linq_expression_use_any_highlighting = warning +resharper_simplify_linq_expression_use_min_by_and_max_by_highlighting = warning +resharper_simplify_string_interpolation_highlighting = warning +resharper_specify_string_comparison_highlighting = warning +resharper_string_ends_with_is_culture_specific_highlighting = warning +resharper_string_literal_as_interpolation_argument_highlighting = warning +resharper_string_literal_typo_highlighting = warning +resharper_string_starts_with_is_culture_specific_highlighting = warning +resharper_struct_can_be_made_read_only_highlighting = warning +resharper_struct_member_can_be_made_read_only_highlighting = warning +resharper_suggest_base_type_for_parameter_highlighting = none +resharper_suggest_base_type_for_parameter_in_constructor_highlighting = warning +resharper_suggest_discard_declaration_var_style_highlighting = hint +resharper_suggest_var_or_type_built_in_types_highlighting = hint +resharper_suggest_var_or_type_deconstruction_declarations_highlighting = warning +resharper_suggest_var_or_type_elsewhere_highlighting = hint +resharper_suggest_var_or_type_simple_types_highlighting = hint +resharper_swap_via_deconstruction_highlighting = warning +resharper_switch_expression_handles_some_known_enum_values_with_exception_in_default_highlighting = warning +resharper_switch_statement_handles_some_known_enum_values_with_default_highlighting = none +resharper_switch_statement_missing_some_enum_cases_no_default_highlighting = none +resharper_tabs_and_spaces_mismatch_highlighting = warning +resharper_tabs_are_disallowed_highlighting = warning +resharper_tabs_outside_indent_highlighting = warning +resharper_tail_recursive_call_highlighting = warning +resharper_too_wide_local_variable_scope_highlighting = warning +resharper_try_cast_always_succeeds_highlighting = warning +resharper_try_statements_can_be_merged_highlighting = warning +resharper_type_parameter_can_be_variant_highlighting = warning +resharper_unnecessary_whitespace_highlighting = warning +resharper_unused_member_global_highlighting = warning +resharper_unused_member_hierarchy_global_highlighting = warning +resharper_unused_member_in_super_global_highlighting = warning +resharper_unused_method_return_value_global_highlighting = warning +resharper_unused_parameter_global_highlighting = warning +resharper_unused_type_global_highlighting = warning +resharper_use_array_creation_expression_1_highlighting = warning +resharper_use_array_creation_expression_2_highlighting = warning +resharper_use_array_empty_method_highlighting = warning +resharper_use_await_using_highlighting = warning +resharper_use_cancellation_token_for_i_async_enumerable_highlighting = warning +resharper_use_collection_count_property_highlighting = warning +resharper_use_configure_await_false_highlighting = warning +resharper_use_deconstruction_highlighting = warning +resharper_use_empty_types_field_highlighting = warning +resharper_use_event_args_empty_field_highlighting = warning +resharper_use_format_specifier_in_format_string_highlighting = warning +resharper_use_indexed_property_highlighting = warning +resharper_use_index_from_end_expression_highlighting = warning +resharper_use_is_operator_1_highlighting = warning +resharper_use_is_operator_2_highlighting = warning +resharper_use_method_any_0_highlighting = warning +resharper_use_method_any_1_highlighting = warning +resharper_use_method_any_2_highlighting = warning +resharper_use_method_any_3_highlighting = warning +resharper_use_method_any_4_highlighting = warning +resharper_use_method_is_instance_of_type_highlighting = warning +resharper_use_nameof_expression_for_part_of_the_string_highlighting = warning +resharper_use_nameof_expression_highlighting = warning +resharper_use_nameof_for_dependency_property_highlighting = warning +resharper_use_name_of_instead_of_type_of_highlighting = warning +resharper_use_negated_pattern_in_is_expression_highlighting = warning +resharper_use_negated_pattern_matching_highlighting = warning +resharper_use_nullable_annotation_instead_of_attribute_highlighting = warning +resharper_use_nullable_attributes_supported_by_compiler_highlighting = warning +resharper_use_null_propagation_highlighting = warning +resharper_use_object_or_collection_initializer_highlighting = warning +resharper_use_pattern_matching_highlighting = warning +resharper_use_positional_deconstruction_pattern_highlighting = warning +resharper_use_raw_string_highlighting = warning +resharper_use_string_interpolation_highlighting = warning +resharper_use_switch_case_pattern_variable_highlighting = warning +resharper_use_throw_if_null_method_highlighting = warning +resharper_use_unsigned_right_shift_operator_highlighting = warning +resharper_use_verbatim_string_highlighting = warning +resharper_use_with_expression_to_copy_anonymous_object_highlighting = warning +resharper_use_with_expression_to_copy_record_highlighting = warning +resharper_use_with_expression_to_copy_struct_highlighting = warning +resharper_use_with_expression_to_copy_tuple_highlighting = warning +resharper_virtual_member_never_overridden_global_highlighting = warning +resharper_virtual_member_never_overridden_local_highlighting = warning +resharper_web_config_module_not_resolved_highlighting = warning +resharper_web_config_type_not_resolved_highlighting = warning +resharper_web_config_wrong_module_highlighting = warning +resharper_with_expression_instead_of_initializer_highlighting = warning +resharper_wrong_indent_size_highlighting = warning -[{*.har,*.inputactions,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config}] -indent_style = space -indent_size = 2 - -[{*.yaml,*.yml,.analysis_options}] -indent_style = space -indent_size = 2 +[*.css] +ij_css_align_closing_brace_with_properties = false +ij_css_blank_lines_around_nested_selector = 1 +ij_css_blank_lines_between_blocks = 1 +ij_css_block_comment_add_space = false +ij_css_brace_placement = end_of_line +ij_css_enforce_quotes_on_format = false +ij_css_hex_color_long_format = false +ij_css_hex_color_lower_case = false +ij_css_hex_color_short_format = false +ij_css_hex_color_upper_case = false +ij_css_keep_blank_lines_in_code = 2 +ij_css_keep_indents_on_empty_lines = false +ij_css_keep_single_line_blocks = false +ij_css_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow +ij_css_space_after_colon = true +ij_css_space_before_opening_brace = true +ij_css_use_double_quotes = true +ij_css_value_alignment = do_not_align [*.csv] -indent_style = tab -tab_width = 1 +max_line_length = 2147483647 +ij_csv_wrap_long_lines = false +indent_style = tab +tab_width = 1 -[{*.bash,*.sh,*.tool,*.zsh}] -indent_style = space -indent_size = 2 +[*.dart] +max_line_length = 80 -[*.{appxmanifest,asax,ascx,aspx,axaml,build,cg,cginc,compute,cs,cshtml,dtd,fs,fsi,fsscript,fsx,hlsl,hlsli,hlslinc,master,ml,mli,nuspec,paml,razor,resw,resx,shader,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}] +[*.less] +indent_size = 2 +ij_less_align_closing_brace_with_properties = false +ij_less_blank_lines_around_nested_selector = 1 +ij_less_blank_lines_between_blocks = 1 +ij_less_block_comment_add_space = false +ij_less_brace_placement = 0 +ij_less_enforce_quotes_on_format = false +ij_less_hex_color_long_format = false +ij_less_hex_color_lower_case = false +ij_less_hex_color_short_format = false +ij_less_hex_color_upper_case = false +ij_less_keep_blank_lines_in_code = 2 +ij_less_keep_indents_on_empty_lines = false +ij_less_keep_single_line_blocks = false +ij_less_line_comment_add_space = false +ij_less_line_comment_at_first_column = false +ij_less_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow +ij_less_space_after_colon = true +ij_less_space_before_opening_brace = true +ij_less_use_double_quotes = true +ij_less_value_alignment = 0 + +[*.pp] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 2 +ij_puppet_keep_indents_on_empty_lines = false + +[*.properties] +ij_properties_align_group_field_declarations = true +ij_properties_keep_blank_lines = false +ij_properties_key_value_delimiter = equals +ij_properties_spaces_around_key_value_delimiter = true + +[*.sass] +indent_size = 2 +ij_sass_align_closing_brace_with_properties = false +ij_sass_blank_lines_around_nested_selector = 1 +ij_sass_blank_lines_between_blocks = 1 +ij_sass_brace_placement = 0 +ij_sass_enforce_quotes_on_format = false +ij_sass_hex_color_long_format = false +ij_sass_hex_color_lower_case = false +ij_sass_hex_color_short_format = false +ij_sass_hex_color_upper_case = false +ij_sass_keep_blank_lines_in_code = 2 +ij_sass_keep_indents_on_empty_lines = false +ij_sass_keep_single_line_blocks = false +ij_sass_line_comment_add_space = false +ij_sass_line_comment_at_first_column = false +ij_sass_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow +ij_sass_space_after_colon = true +ij_sass_space_before_opening_brace = true +ij_sass_use_double_quotes = true +ij_sass_value_alignment = 0 + +[*.scss] +indent_size = 2 +ij_scss_align_closing_brace_with_properties = false +ij_scss_blank_lines_around_nested_selector = 1 +ij_scss_blank_lines_between_blocks = 1 +ij_scss_block_comment_add_space = false +ij_scss_brace_placement = 0 +ij_scss_enforce_quotes_on_format = false +ij_scss_hex_color_long_format = false +ij_scss_hex_color_lower_case = false +ij_scss_hex_color_short_format = false +ij_scss_hex_color_upper_case = false +ij_scss_keep_blank_lines_in_code = 2 +ij_scss_keep_indents_on_empty_lines = false +ij_scss_keep_single_line_blocks = false +ij_scss_line_comment_add_space = false +ij_scss_line_comment_at_first_column = false +ij_scss_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow +ij_scss_space_after_colon = true +ij_scss_space_before_opening_brace = true +ij_scss_use_double_quotes = true +ij_scss_value_alignment = 0 + +[*.slim] +indent_size = 2 +ij_slim_keep_indents_on_empty_lines = false + +[*.twig] +ij_twig_keep_indents_on_empty_lines = false +ij_twig_spaces_inside_comments_delimiters = true +ij_twig_spaces_inside_delimiters = true +ij_twig_spaces_inside_variable_delimiters = true + +[*.vue] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 4 +ij_vue_indent_children_of_top_level = template +ij_vue_interpolation_new_line_after_start_delimiter = true +ij_vue_interpolation_new_line_before_end_delimiter = true +ij_vue_interpolation_wrap = off +ij_vue_keep_indents_on_empty_lines = false +ij_vue_spaces_within_interpolation_expressions = true + +[.editorconfig] +ij_editorconfig_align_group_field_declarations = true +ij_editorconfig_space_after_colon = false +ij_editorconfig_space_after_comma = true +ij_editorconfig_space_before_colon = false +ij_editorconfig_space_before_comma = false +ij_editorconfig_spaces_around_assignment_operators = true + +[{*.ad,*.adoc,*.asciidoc,.asciidoctorconfig}] +ij_asciidoc_blank_lines_after_header = 1 +ij_asciidoc_blank_lines_keep_after_header = 1 +ij_asciidoc_formatting_enabled = true +ij_asciidoc_one_sentence_per_line = true + +[{*.ant,*.appxmanifest,*.axml,*.cscfg,*.csdef,*.disco,*.dotsettings,*.filelayout,*.fxml,*.jhm,*.jnlp,*.jrxml,*.manifest,*.myapp,*.nuspec,*.rng,*.sdef,*.stylecop,*.svcmap,*.tld,*.wadcfgx,*.webref,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,StyleCop.Cache}] +ij_xml_align_attributes = true +ij_xml_align_text = false +ij_xml_attribute_wrap = on_every_item +ij_xml_block_comment_add_space = false +ij_xml_block_comment_at_first_column = true +ij_xml_keep_blank_lines = 2 +ij_xml_keep_indents_on_empty_lines = false +ij_xml_keep_line_breaks = true +ij_xml_keep_line_breaks_in_text = true +ij_xml_keep_whitespaces = false +ij_xml_keep_whitespaces_around_cdata = preserve +ij_xml_keep_whitespaces_inside_cdata = false +ij_xml_line_comment_at_first_column = true +ij_xml_space_after_tag_name = false +ij_xml_space_around_equals_in_attribute = false +ij_xml_space_inside_empty_tag = false +ij_xml_text_wrap = normal +ij_xml_use_custom_settings = false +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 4 + +[{*.applescript,*.scpt}] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 4 +ij_applescript_align_multiline_binary_operation = true +ij_applescript_align_multiline_parameters = true +ij_applescript_align_multiline_parameters_in_calls = true +ij_applescript_binary_operation_sign_on_next_line = false +ij_applescript_binary_operation_wrap = off +ij_applescript_block_brace_style = next_line +ij_applescript_call_parameters_new_line_after_left_paren = false +ij_applescript_call_parameters_right_paren_on_new_line = false +ij_applescript_call_parameters_wrap = off +ij_applescript_else_on_new_line = true +ij_applescript_keep_blank_lines_in_code = 2 +ij_applescript_keep_first_column_comment = true +ij_applescript_keep_indents_on_empty_lines = false +ij_applescript_keep_line_breaks = true +ij_applescript_method_brace_style = next_line +ij_applescript_method_parameters_new_line_after_left_paren = false +ij_applescript_method_parameters_right_paren_on_new_line = false +ij_applescript_method_parameters_wrap = off +ij_applescript_parentheses_expression_new_line_after_left_paren = false +ij_applescript_parentheses_expression_right_paren_on_new_line = false +ij_applescript_space_after_colon = true +ij_applescript_space_after_comma = true +ij_applescript_space_after_comma_in_type_arguments = true +ij_applescript_space_before_colon = true +ij_applescript_space_before_comma = false +ij_applescript_space_before_else_keyword = true +ij_applescript_space_before_else_left_brace = true +ij_applescript_space_before_if_parentheses = false +ij_applescript_space_before_method_call_parentheses = false +ij_applescript_space_before_method_left_brace = true +ij_applescript_space_before_method_parentheses = false +ij_applescript_space_before_while_keyword = true +ij_applescript_spaces_around_additive_operators = true +ij_applescript_spaces_around_assignment_operators = true +ij_applescript_spaces_around_equality_operators = true +ij_applescript_spaces_around_logical_operators = true +ij_applescript_spaces_around_multiplicative_operators = true +ij_applescript_spaces_around_relational_operators = true +ij_applescript_spaces_around_shift_operators = true +ij_applescript_spaces_around_unary_operator = false +ij_applescript_spaces_within_if_parentheses = false +ij_applescript_spaces_within_method_call_parentheses = false +ij_applescript_spaces_within_method_parentheses = false +ij_applescript_special_else_if_treatment = true + +[{*.ats,*.cts,*.mts,*.ts}] +ij_continuation_indent_size = 4 +ij_typescript_align_imports = true +ij_typescript_align_multiline_array_initializer_expression = true +ij_typescript_align_multiline_binary_operation = true +ij_typescript_align_multiline_chained_methods = true +ij_typescript_align_multiline_extends_list = false +ij_typescript_align_multiline_for = true +ij_typescript_align_multiline_parameters = true +ij_typescript_align_multiline_parameters_in_calls = true +ij_typescript_align_multiline_ternary_operation = true +ij_typescript_align_object_properties = 1 +ij_typescript_align_union_types = true +ij_typescript_align_var_statements = 2 +ij_typescript_array_initializer_new_line_after_left_brace = false +ij_typescript_array_initializer_right_brace_on_new_line = false +ij_typescript_array_initializer_wrap = on_every_item +ij_typescript_assignment_wrap = on_every_item +ij_typescript_binary_operation_sign_on_next_line = false +ij_typescript_binary_operation_wrap = on_every_item +ij_typescript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** +ij_typescript_blank_lines_after_imports = 1 +ij_typescript_blank_lines_around_class = 1 +ij_typescript_blank_lines_around_field = 0 +ij_typescript_blank_lines_around_field_in_interface = 0 +ij_typescript_blank_lines_around_function = 1 +ij_typescript_blank_lines_around_method = 1 +ij_typescript_blank_lines_around_method_in_interface = 1 +ij_typescript_block_brace_style = next_line +ij_typescript_block_comment_add_space = false +ij_typescript_block_comment_at_first_column = true +ij_typescript_call_parameters_new_line_after_left_paren = false +ij_typescript_call_parameters_right_paren_on_new_line = false +ij_typescript_call_parameters_wrap = on_every_item +ij_typescript_catch_on_new_line = true +ij_typescript_chained_call_dot_on_new_line = true +ij_typescript_class_brace_style = next_line +ij_typescript_comma_on_new_line = false +ij_typescript_do_while_brace_force = always +ij_typescript_else_on_new_line = false +ij_typescript_enforce_trailing_comma = keep +ij_typescript_enum_constants_wrap = on_every_item +ij_typescript_extends_keyword_wrap = normal +ij_typescript_extends_list_wrap = on_every_item +ij_typescript_field_prefix = _ +ij_typescript_file_name_style = relaxed +ij_typescript_finally_on_new_line = true +ij_typescript_for_brace_force = if_multiline +ij_typescript_for_statement_new_line_after_left_paren = false +ij_typescript_for_statement_right_paren_on_new_line = false +ij_typescript_for_statement_wrap = on_every_item +ij_typescript_force_quote_style = true +ij_typescript_force_semicolon_style = true +ij_typescript_function_expression_brace_style = next_line +ij_typescript_if_brace_force = never +ij_typescript_import_merge_members = global +ij_typescript_import_prefer_absolute_path = true +ij_typescript_import_sort_members = true +ij_typescript_import_sort_module_name = true +ij_typescript_import_use_node_resolution = true +ij_typescript_imports_wrap = on_every_item +ij_typescript_indent_case_from_switch = true +ij_typescript_indent_chained_calls = true +ij_typescript_indent_package_children = 0 +ij_typescript_jsdoc_include_types = false +ij_typescript_jsx_attribute_value = braces +ij_typescript_keep_blank_lines_in_code = 2 +ij_typescript_keep_first_column_comment = true +ij_typescript_keep_indents_on_empty_lines = false +ij_typescript_keep_line_breaks = true +ij_typescript_keep_simple_blocks_in_one_line = false +ij_typescript_keep_simple_methods_in_one_line = false +ij_typescript_line_comment_add_space = true +ij_typescript_line_comment_at_first_column = false +ij_typescript_method_brace_style = next_line +ij_typescript_method_call_chain_wrap = on_every_item +ij_typescript_method_parameters_new_line_after_left_paren = false +ij_typescript_method_parameters_right_paren_on_new_line = false +ij_typescript_method_parameters_wrap = on_every_item +ij_typescript_object_literal_wrap = on_every_item +ij_typescript_object_types_wrap = on_every_item +ij_typescript_parentheses_expression_new_line_after_left_paren = false +ij_typescript_parentheses_expression_right_paren_on_new_line = false +ij_typescript_place_assignment_sign_on_next_line = false +ij_typescript_prefer_as_type_cast = false +ij_typescript_prefer_explicit_types_function_expression_returns = false +ij_typescript_prefer_explicit_types_function_returns = false +ij_typescript_prefer_explicit_types_vars_fields = false +ij_typescript_prefer_parameters_wrap = false +ij_typescript_property_prefix = +ij_typescript_reformat_c_style_comments = false +ij_typescript_space_after_colon = true +ij_typescript_space_after_comma = true +ij_typescript_space_after_dots_in_rest_parameter = false +ij_typescript_space_after_generator_mult = true +ij_typescript_space_after_property_colon = true +ij_typescript_space_after_quest = true +ij_typescript_space_after_type_colon = true +ij_typescript_space_after_unary_not = false +ij_typescript_space_before_async_arrow_lparen = false +ij_typescript_space_before_catch_keyword = true +ij_typescript_space_before_catch_left_brace = false +ij_typescript_space_before_catch_parentheses = false +ij_typescript_space_before_class_lbrace = false +ij_typescript_space_before_class_left_brace = true +ij_typescript_space_before_colon = true +ij_typescript_space_before_comma = false +ij_typescript_space_before_do_left_brace = false +ij_typescript_space_before_else_keyword = true +ij_typescript_space_before_else_left_brace = false +ij_typescript_space_before_finally_keyword = true +ij_typescript_space_before_finally_left_brace = false +ij_typescript_space_before_for_left_brace = false +ij_typescript_space_before_for_parentheses = false +ij_typescript_space_before_for_semicolon = false +ij_typescript_space_before_function_left_parenth = false +ij_typescript_space_before_generator_mult = false +ij_typescript_space_before_if_left_brace = false +ij_typescript_space_before_if_parentheses = false +ij_typescript_space_before_method_call_parentheses = false +ij_typescript_space_before_method_left_brace = false +ij_typescript_space_before_method_parentheses = false +ij_typescript_space_before_property_colon = false +ij_typescript_space_before_quest = true +ij_typescript_space_before_switch_left_brace = false +ij_typescript_space_before_switch_parentheses = false +ij_typescript_space_before_try_left_brace = false +ij_typescript_space_before_type_colon = false +ij_typescript_space_before_unary_not = false +ij_typescript_space_before_while_keyword = true +ij_typescript_space_before_while_left_brace = false +ij_typescript_space_before_while_parentheses = false +ij_typescript_spaces_around_additive_operators = true +ij_typescript_spaces_around_arrow_function_operator = true +ij_typescript_spaces_around_assignment_operators = true +ij_typescript_spaces_around_bitwise_operators = true +ij_typescript_spaces_around_equality_operators = true +ij_typescript_spaces_around_logical_operators = true +ij_typescript_spaces_around_multiplicative_operators = true +ij_typescript_spaces_around_relational_operators = true +ij_typescript_spaces_around_shift_operators = true +ij_typescript_spaces_around_unary_operator = false +ij_typescript_spaces_within_array_initializer_brackets = false +ij_typescript_spaces_within_brackets = false +ij_typescript_spaces_within_catch_parentheses = false +ij_typescript_spaces_within_for_parentheses = false +ij_typescript_spaces_within_if_parentheses = false +ij_typescript_spaces_within_imports = false +ij_typescript_spaces_within_interpolation_expressions = false +ij_typescript_spaces_within_method_call_parentheses = false +ij_typescript_spaces_within_method_parentheses = false +ij_typescript_spaces_within_object_literal_braces = false +ij_typescript_spaces_within_object_type_braces = true +ij_typescript_spaces_within_parentheses = false +ij_typescript_spaces_within_switch_parentheses = false +ij_typescript_spaces_within_type_assertion = false +ij_typescript_spaces_within_union_types = true +ij_typescript_spaces_within_while_parentheses = false +ij_typescript_special_else_if_treatment = true +ij_typescript_ternary_operation_signs_on_next_line = false +ij_typescript_ternary_operation_wrap = on_every_item +ij_typescript_union_types_wrap = on_every_item +ij_typescript_use_chained_calls_group_indents = false +ij_typescript_use_double_quotes = true +ij_typescript_use_explicit_js_extension = auto +ij_typescript_use_path_mapping = always +ij_typescript_use_public_modifier = false +ij_typescript_use_semicolon_after_statement = true +ij_typescript_var_declaration_wrap = normal +ij_typescript_while_brace_force = always +ij_typescript_while_on_new_line = false +ij_typescript_wrap_comments = false + +[{*.bash,*.sh,*.zsh}] +indent_size = 2 +tab_width = 2 +ij_shell_binary_ops_start_line = false +ij_shell_keep_column_alignment_padding = false +ij_shell_minify_program = false +ij_shell_redirect_followed_by_space = false +ij_shell_switch_cases_indented = true +ij_shell_use_unix_line_separator = true +indent_style = space + +[{*.cjs,*.js}] +ij_continuation_indent_size = 4 +ij_javascript_align_imports = true +ij_javascript_align_multiline_array_initializer_expression = true +ij_javascript_align_multiline_binary_operation = true +ij_javascript_align_multiline_chained_methods = false +ij_javascript_align_multiline_extends_list = true +ij_javascript_align_multiline_for = true +ij_javascript_align_multiline_parameters = true +ij_javascript_align_multiline_parameters_in_calls = true +ij_javascript_align_multiline_ternary_operation = true +ij_javascript_align_object_properties = 1 +ij_javascript_align_union_types = false +ij_javascript_align_var_statements = 2 +ij_javascript_array_initializer_new_line_after_left_brace = false +ij_javascript_array_initializer_right_brace_on_new_line = false +ij_javascript_array_initializer_wrap = on_every_item +ij_javascript_assignment_wrap = on_every_item +ij_javascript_binary_operation_sign_on_next_line = false +ij_javascript_binary_operation_wrap = on_every_item +ij_javascript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** +ij_javascript_blank_lines_after_imports = 1 +ij_javascript_blank_lines_around_class = 1 +ij_javascript_blank_lines_around_field = 0 +ij_javascript_blank_lines_around_function = 1 +ij_javascript_blank_lines_around_method = 1 +ij_javascript_block_brace_style = next_line +ij_javascript_block_comment_add_space = false +ij_javascript_block_comment_at_first_column = true +ij_javascript_call_parameters_new_line_after_left_paren = false +ij_javascript_call_parameters_right_paren_on_new_line = false +ij_javascript_call_parameters_wrap = on_every_item +ij_javascript_catch_on_new_line = true +ij_javascript_chained_call_dot_on_new_line = true +ij_javascript_class_brace_style = next_line +ij_javascript_comma_on_new_line = false +ij_javascript_do_while_brace_force = always +ij_javascript_else_on_new_line = true +ij_javascript_enforce_trailing_comma = remove +ij_javascript_extends_keyword_wrap = normal +ij_javascript_extends_list_wrap = on_every_item +ij_javascript_field_prefix = _ +ij_javascript_file_name_style = relaxed +ij_javascript_finally_on_new_line = true +ij_javascript_for_brace_force = if_multiline +ij_javascript_for_statement_new_line_after_left_paren = false +ij_javascript_for_statement_right_paren_on_new_line = false +ij_javascript_for_statement_wrap = on_every_item +ij_javascript_force_quote_style = true +ij_javascript_force_semicolon_style = true +ij_javascript_function_expression_brace_style = next_line +ij_javascript_if_brace_force = if_multiline +ij_javascript_import_merge_members = global +ij_javascript_import_prefer_absolute_path = true +ij_javascript_import_sort_members = true +ij_javascript_import_sort_module_name = true +ij_javascript_import_use_node_resolution = true +ij_javascript_imports_wrap = on_every_item +ij_javascript_indent_case_from_switch = true +ij_javascript_indent_chained_calls = true +ij_javascript_indent_package_children = 0 +ij_javascript_jsx_attribute_value = braces +ij_javascript_keep_blank_lines_in_code = 2 +ij_javascript_keep_first_column_comment = true +ij_javascript_keep_indents_on_empty_lines = false +ij_javascript_keep_line_breaks = true +ij_javascript_keep_simple_blocks_in_one_line = false +ij_javascript_keep_simple_methods_in_one_line = false +ij_javascript_line_comment_add_space = true +ij_javascript_line_comment_at_first_column = false +ij_javascript_method_brace_style = next_line +ij_javascript_method_call_chain_wrap = on_every_item +ij_javascript_method_parameters_new_line_after_left_paren = false +ij_javascript_method_parameters_right_paren_on_new_line = false +ij_javascript_method_parameters_wrap = on_every_item +ij_javascript_object_literal_wrap = on_every_item +ij_javascript_object_types_wrap = on_every_item +ij_javascript_parentheses_expression_new_line_after_left_paren = false +ij_javascript_parentheses_expression_right_paren_on_new_line = false +ij_javascript_place_assignment_sign_on_next_line = true +ij_javascript_prefer_as_type_cast = false +ij_javascript_prefer_explicit_types_function_expression_returns = false +ij_javascript_prefer_explicit_types_function_returns = false +ij_javascript_prefer_explicit_types_vars_fields = false +ij_javascript_prefer_parameters_wrap = false +ij_javascript_property_prefix = +ij_javascript_reformat_c_style_comments = true +ij_javascript_space_after_colon = true +ij_javascript_space_after_comma = true +ij_javascript_space_after_dots_in_rest_parameter = false +ij_javascript_space_after_generator_mult = true +ij_javascript_space_after_property_colon = true +ij_javascript_space_after_quest = true +ij_javascript_space_after_type_colon = true +ij_javascript_space_after_unary_not = false +ij_javascript_space_before_async_arrow_lparen = false +ij_javascript_space_before_catch_keyword = true +ij_javascript_space_before_catch_left_brace = false +ij_javascript_space_before_catch_parentheses = false +ij_javascript_space_before_class_lbrace = false +ij_javascript_space_before_class_left_brace = true +ij_javascript_space_before_colon = true +ij_javascript_space_before_comma = false +ij_javascript_space_before_do_left_brace = false +ij_javascript_space_before_else_keyword = true +ij_javascript_space_before_else_left_brace = false +ij_javascript_space_before_finally_keyword = true +ij_javascript_space_before_finally_left_brace = false +ij_javascript_space_before_for_left_brace = false +ij_javascript_space_before_for_parentheses = false +ij_javascript_space_before_for_semicolon = false +ij_javascript_space_before_function_left_parenth = false +ij_javascript_space_before_generator_mult = false +ij_javascript_space_before_if_left_brace = false +ij_javascript_space_before_if_parentheses = false +ij_javascript_space_before_method_call_parentheses = false +ij_javascript_space_before_method_left_brace = false +ij_javascript_space_before_method_parentheses = false +ij_javascript_space_before_property_colon = false +ij_javascript_space_before_quest = true +ij_javascript_space_before_switch_left_brace = false +ij_javascript_space_before_switch_parentheses = false +ij_javascript_space_before_try_left_brace = false +ij_javascript_space_before_type_colon = false +ij_javascript_space_before_unary_not = false +ij_javascript_space_before_while_keyword = true +ij_javascript_space_before_while_left_brace = false +ij_javascript_space_before_while_parentheses = false +ij_javascript_spaces_around_additive_operators = true +ij_javascript_spaces_around_arrow_function_operator = true +ij_javascript_spaces_around_assignment_operators = true +ij_javascript_spaces_around_bitwise_operators = true +ij_javascript_spaces_around_equality_operators = true +ij_javascript_spaces_around_logical_operators = true +ij_javascript_spaces_around_multiplicative_operators = true +ij_javascript_spaces_around_relational_operators = true +ij_javascript_spaces_around_shift_operators = true +ij_javascript_spaces_around_unary_operator = false +ij_javascript_spaces_within_array_initializer_brackets = false +ij_javascript_spaces_within_brackets = false +ij_javascript_spaces_within_catch_parentheses = false +ij_javascript_spaces_within_for_parentheses = false +ij_javascript_spaces_within_if_parentheses = false +ij_javascript_spaces_within_imports = false +ij_javascript_spaces_within_interpolation_expressions = false +ij_javascript_spaces_within_method_call_parentheses = false +ij_javascript_spaces_within_method_parentheses = false +ij_javascript_spaces_within_object_literal_braces = false +ij_javascript_spaces_within_object_type_braces = true +ij_javascript_spaces_within_parentheses = false +ij_javascript_spaces_within_switch_parentheses = false +ij_javascript_spaces_within_type_assertion = false +ij_javascript_spaces_within_union_types = true +ij_javascript_spaces_within_while_parentheses = false +ij_javascript_special_else_if_treatment = true +ij_javascript_ternary_operation_signs_on_next_line = false +ij_javascript_ternary_operation_wrap = on_every_item +ij_javascript_union_types_wrap = on_every_item +ij_javascript_use_chained_calls_group_indents = true +ij_javascript_use_double_quotes = true +ij_javascript_use_explicit_js_extension = auto +ij_javascript_use_path_mapping = always +ij_javascript_use_public_modifier = false +ij_javascript_use_semicolon_after_statement = true +ij_javascript_var_declaration_wrap = normal +ij_javascript_while_brace_force = always +ij_javascript_while_on_new_line = false +ij_javascript_wrap_comments = false + +[{*.comp,*.frag,*.fsh,*.geom,*.glsl,*.tesc,*.tese,*.vert,*.vsh}] +ij_glsl_keep_indents_on_empty_lines = false + +[{*.har,*.jsb2,*.jsb3,*.json,*.jsonc,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}] +indent_size = 2 +ij_json_array_wrapping = normal +ij_json_keep_blank_lines_in_code = 0 +ij_json_keep_indents_on_empty_lines = false +ij_json_keep_line_breaks = true +ij_json_keep_trailing_comma = false +ij_json_object_wrapping = normal +ij_json_property_alignment = align_on_value +ij_json_space_after_colon = true +ij_json_space_after_comma = true +ij_json_space_before_colon = false +ij_json_space_before_comma = false +ij_json_spaces_within_braces = false +ij_json_spaces_within_brackets = false +ij_json_wrap_long_lines = false +indent_style = space + +[{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}] +ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3 +ij_html_align_attributes = true +ij_html_align_text = false +ij_html_attribute_wrap = normal +ij_html_block_comment_add_space = false +ij_html_block_comment_at_first_column = true +ij_html_do_not_align_children_of_min_lines = 0 +ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p +ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot +ij_html_enforce_quotes = false +ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var +ij_html_keep_blank_lines = 2 +ij_html_keep_indents_on_empty_lines = false +ij_html_keep_line_breaks = true +ij_html_keep_line_breaks_in_text = true +ij_html_keep_whitespaces = false +ij_html_keep_whitespaces_inside = span, pre, textarea +ij_html_line_comment_at_first_column = true +ij_html_new_line_after_last_attribute = never +ij_html_new_line_before_first_attribute = never +ij_html_quote_style = double +ij_html_remove_new_line_before_tags = br +ij_html_space_after_tag_name = false +ij_html_space_around_equality_in_attribute = false +ij_html_space_inside_empty_tag = false +ij_html_text_wrap = normal + +[{*.http,*.rest}] +indent_size = 0 +ij_continuation_indent_size = 4 +ij_http-request_call_parameters_wrap = normal +ij_http-request_method_parameters_wrap = split_into_lines +ij_http-request_space_before_comma = true +ij_http-request_spaces_around_assignment_operators = true + +[{*.markdown,*.md}] +ij_markdown_force_one_space_after_blockquote_symbol = true +ij_markdown_force_one_space_after_header_symbol = true +ij_markdown_force_one_space_after_list_bullet = true +ij_markdown_force_one_space_between_words = true +ij_markdown_format_tables = true +ij_markdown_insert_quote_arrows_on_wrap = true +ij_markdown_keep_indents_on_empty_lines = false +ij_markdown_keep_line_breaks_inside_text_blocks = true +ij_markdown_max_lines_around_block_elements = 1 +ij_markdown_max_lines_around_header = 1 +ij_markdown_max_lines_between_paragraphs = 1 +ij_markdown_min_lines_around_block_elements = 1 +ij_markdown_min_lines_around_header = 1 +ij_markdown_min_lines_between_paragraphs = 1 +ij_markdown_wrap_text_if_long = true +ij_markdown_wrap_text_inside_blockquotes = true + +[{*.ps1,*.psd1,*.psm1}] +max_line_length = 115 +ij_powershell_align_multiline_binary_operation = true +ij_powershell_align_multiline_chained_methods = false +ij_powershell_align_multiline_for = true +ij_powershell_align_multiline_parameters = true +ij_powershell_align_multiline_parameters_in_calls = false +ij_powershell_binary_operation_wrap = on_every_item +ij_powershell_block_brace_style = next_line +ij_powershell_call_parameters_new_line_after_left_paren = false +ij_powershell_call_parameters_right_paren_on_new_line = false +ij_powershell_call_parameters_wrap = on_every_item +ij_powershell_catch_on_new_line = true +ij_powershell_class_annotation_wrap = split_into_lines +ij_powershell_class_brace_style = next_line +ij_powershell_else_on_new_line = true +ij_powershell_field_annotation_wrap = off +ij_powershell_finally_on_new_line = true +ij_powershell_for_statement_new_line_after_left_paren = false +ij_powershell_for_statement_right_paren_on_new_line = false +ij_powershell_for_statement_wrap = on_every_item +ij_powershell_keep_blank_lines_in_code = 2 +ij_powershell_keep_first_column_comment = true +ij_powershell_keep_line_breaks = true +ij_powershell_keep_simple_blocks_in_one_line = true +ij_powershell_keep_simple_classes_in_one_line = false +ij_powershell_keep_simple_lambdas_in_one_line = true +ij_powershell_keep_simple_methods_in_one_line = true +ij_powershell_method_annotation_wrap = split_into_lines +ij_powershell_method_brace_style = next_line +ij_powershell_method_call_chain_wrap = on_every_item +ij_powershell_method_parameters_new_line_after_left_paren = false +ij_powershell_method_parameters_right_paren_on_new_line = false +ij_powershell_method_parameters_wrap = on_every_item +ij_powershell_parameter_annotation_wrap = off +ij_powershell_parentheses_expression_new_line_after_left_paren = false +ij_powershell_parentheses_expression_right_paren_on_new_line = false +ij_powershell_space_after_colon = true +ij_powershell_space_after_comma = true +ij_powershell_space_after_for_semicolon = true +ij_powershell_space_after_type_cast = false +ij_powershell_space_before_annotation_parameter_list = false +ij_powershell_space_before_array_initializer_left_brace = false +ij_powershell_space_before_catch_keyword = true +ij_powershell_space_before_catch_left_brace = false +ij_powershell_space_before_class_left_brace = false +ij_powershell_space_before_colon = true +ij_powershell_space_before_comma = false +ij_powershell_space_before_do_left_brace = false +ij_powershell_space_before_else_keyword = true +ij_powershell_space_before_else_left_brace = false +ij_powershell_space_before_finally_keyword = true +ij_powershell_space_before_finally_left_brace = false +ij_powershell_space_before_for_left_brace = false +ij_powershell_space_before_for_parentheses = false +ij_powershell_space_before_for_semicolon = false +ij_powershell_space_before_if_left_brace = false +ij_powershell_space_before_if_parentheses = false +ij_powershell_space_before_method_call_parentheses = false +ij_powershell_space_before_method_left_brace = false +ij_powershell_space_before_method_parentheses = false +ij_powershell_space_before_switch_left_brace = false +ij_powershell_space_before_switch_parentheses = false +ij_powershell_space_before_try_left_brace = false +ij_powershell_space_before_while_keyword = true +ij_powershell_space_before_while_left_brace = false +ij_powershell_space_before_while_parentheses = false +ij_powershell_space_within_empty_method_call_parentheses = false +ij_powershell_space_within_empty_method_parentheses = false +ij_powershell_spaces_around_additive_operators = true +ij_powershell_spaces_around_assignment_operators = true +ij_powershell_spaces_around_bitwise_operators = true +ij_powershell_spaces_around_logical_operators = true +ij_powershell_spaces_around_method_ref_dbl_colon = false +ij_powershell_spaces_around_multiplicative_operators = true +ij_powershell_spaces_around_relational_operators = true +ij_powershell_spaces_around_unary_operator = false +ij_powershell_spaces_within_annotation_parentheses = false +ij_powershell_spaces_within_braces = true +ij_powershell_spaces_within_brackets = false +ij_powershell_spaces_within_cast_parentheses = false +ij_powershell_spaces_within_for_parentheses = false +ij_powershell_spaces_within_if_parentheses = false +ij_powershell_spaces_within_method_call_parentheses = false +ij_powershell_spaces_within_method_parentheses = false +ij_powershell_spaces_within_parentheses = false +ij_powershell_spaces_within_switch_parentheses = false +ij_powershell_spaces_within_while_parentheses = false +ij_powershell_special_else_if_treatment = true +ij_powershell_while_on_new_line = false +ij_powershell_wrap_first_method_in_call_chain = false +ij_powershell_wrap_long_lines = false + +[{*.py,*.pyw}] +ij_python_align_collections_and_comprehensions = true +ij_python_align_multiline_imports = true +ij_python_align_multiline_parameters = true +ij_python_align_multiline_parameters_in_calls = true +ij_python_blank_line_at_file_end = false +ij_python_blank_lines_after_imports = 1 +ij_python_blank_lines_after_local_imports = 0 +ij_python_blank_lines_around_class = 1 +ij_python_blank_lines_around_method = 1 +ij_python_blank_lines_around_top_level_classes_functions = 2 +ij_python_blank_lines_before_first_method = 0 +ij_python_call_parameters_new_line_after_left_paren = false +ij_python_call_parameters_right_paren_on_new_line = false +ij_python_call_parameters_wrap = on_every_item +ij_python_dict_alignment = 0 +ij_python_dict_new_line_after_left_brace = false +ij_python_dict_new_line_before_right_brace = false +ij_python_dict_wrapping = 5 +ij_python_from_import_new_line_after_left_parenthesis = false +ij_python_from_import_new_line_before_right_parenthesis = false +ij_python_from_import_parentheses_force_if_multiline = false +ij_python_from_import_trailing_comma_if_multiline = false +ij_python_from_import_wrapping = 5 +ij_python_hang_closing_brackets = true +ij_python_keep_blank_lines_in_code = 1 +ij_python_keep_blank_lines_in_declarations = 1 +ij_python_keep_indents_on_empty_lines = false +ij_python_keep_line_breaks = true +ij_python_method_parameters_new_line_after_left_paren = false +ij_python_method_parameters_right_paren_on_new_line = false +ij_python_method_parameters_wrap = on_every_item +ij_python_new_line_after_colon = false +ij_python_new_line_after_colon_multi_clause = true +ij_python_optimize_imports_always_split_from_imports = false +ij_python_optimize_imports_case_insensitive_order = true +ij_python_optimize_imports_join_from_imports_with_same_source = false +ij_python_optimize_imports_sort_by_type_first = true +ij_python_optimize_imports_sort_imports = true +ij_python_optimize_imports_sort_names_in_from_imports = true +ij_python_space_after_comma = true +ij_python_space_after_number_sign = true +ij_python_space_after_py_colon = true +ij_python_space_before_backslash = true +ij_python_space_before_comma = false +ij_python_space_before_for_semicolon = false +ij_python_space_before_lbracket = false +ij_python_space_before_method_call_parentheses = false +ij_python_space_before_method_parentheses = false +ij_python_space_before_number_sign = true +ij_python_space_before_py_colon = false +ij_python_space_within_empty_method_call_parentheses = false +ij_python_space_within_empty_method_parentheses = false +ij_python_spaces_around_additive_operators = true +ij_python_spaces_around_assignment_operators = true +ij_python_spaces_around_bitwise_operators = true +ij_python_spaces_around_eq_in_keyword_argument = false +ij_python_spaces_around_eq_in_named_parameter = false +ij_python_spaces_around_equality_operators = true +ij_python_spaces_around_multiplicative_operators = true +ij_python_spaces_around_power_operator = true +ij_python_spaces_around_relational_operators = true +ij_python_spaces_around_shift_operators = true +ij_python_spaces_within_braces = false +ij_python_spaces_within_brackets = false +ij_python_spaces_within_method_call_parentheses = false +ij_python_spaces_within_method_parentheses = false +ij_python_use_continuation_indent_for_arguments = false +ij_python_use_continuation_indent_for_collection_and_comprehensions = false +ij_python_use_continuation_indent_for_parameters = true +ij_python_wrap_long_lines = false + +[{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}] +ij_toml_keep_indents_on_empty_lines = false + +[{*.yaml,*.yml,pubspec.lock}] +indent_size = 2 +ij_yaml_align_values_properties = on_value +ij_yaml_autoinsert_sequence_marker = true +ij_yaml_block_mapping_on_new_line = false +ij_yaml_indent_sequence_value = true +ij_yaml_keep_indents_on_empty_lines = false +ij_yaml_keep_line_breaks = true +ij_yaml_sequence_on_new_line = false +ij_yaml_space_before_colon = false +ij_yaml_spaces_within_braces = true +ij_yaml_spaces_within_brackets = true +indent_style = space + +[*.{appxmanifest,asax,ascx,aspx,axaml,build,c,c++,cc,cginc,compute,cp,cpp,cppm,cs,cshtml,cu,cuh,cxx,dtd,fs,fsi,fsscript,fsx,fx,fxh,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,ixx,master,ml,mli,mpp,mq4,mq5,mqh,nuspec,paml,razor,resw,resx,shader,skin,tpp,usf,ush,uxml,vb,xaml,xamlx,xoml,xsd}] indent_style = space -indent_size = 4 -tab_width = 4 +indent_size = 4 +tab_width = 4 + +[*.{appxmanifest,asax,ascx,aspx,axaml,build,c,c++,c++m,cc,ccm,cginc,compute,cp,cpp,cppm,cs,cshtml,cu,cuh,cxx,cxxm,dtd,fs,fsi,fsscript,fsx,fx,fxh,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,ixx,master,ml,mli,mpp,mq4,mq5,mqh,mxx,nuspec,paml,razor,resw,resx,shader,skin,tpp,usf,ush,uxml,vb,xaml,xamlx,xoml,xsd}] +indent_style = space +indent_size = 4 +tab_width = 4 + +[*.{cs,vb}] +dotnet_diagnostic.ph2006.severity = none +dotnet_diagnostic.ph2021.severity = none +dotnet_diagnostic.ph2026.severity = none +dotnet_diagnostic.ph2028.severity = none +dotnet_diagnostic.ph2029.severity = none +dotnet_diagnostic.ph2031.severity = warning +dotnet_diagnostic.ph2045.severity = none +dotnet_diagnostic.ph2067.severity = none +dotnet_diagnostic.ph2068.severity = none +dotnet_diagnostic.ph2069.severity = warning +dotnet_diagnostic.ph2075.severity = none +dotnet_diagnostic.ph2079.severity = none +dotnet_diagnostic.ph2081.severity = none +dotnet_diagnostic.ph2082.severity = suggestion +dotnet_diagnostic.ph2083.severity = warning +dotnet_diagnostic.ph2086.severity = warning +dotnet_diagnostic.ph2089.severity = warning +dotnet_diagnostic.ph2096.severity = warning +dotnet_diagnostic.ph2097.severity = warning +dotnet_diagnostic.ph2098.severity = warning +dotnet_diagnostic.ph2101.severity = warning +dotnet_diagnostic.ph2102.severity = none +dotnet_diagnostic.mt1001.severity = warning + +[*.{razor}] +resharper_normalize_tag_names = false \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index d1436e196..b5d985a2f 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms # github: claunia -patreon: claunia -ko_fi: claunia +patreon: claunia +ko_fi: claunia open_collective: aaru diff --git a/.github/ISSUE_TEMPLATE/bug_report_general.yaml b/.github/ISSUE_TEMPLATE/bug_report_general.yaml index 9cd28c50b..bf2ddf4a5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_general.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report_general.yaml @@ -1,13 +1,13 @@ -name: General Bug Report +name: General Bug Report description: Bugs report on other commands. Use this to submit device reports. -labels: ["bug", "needs triage"] +labels: [ "bug", "needs triage" ] assignees: - silaslaspada body: - type: dropdown - id: version + id: version attributes: - label: Version + label: Version description: What version of Aaru are you running? options: - 5.3.0 @@ -18,22 +18,22 @@ body: validations: required: true - type: input - id: commit + id: commit attributes: - label: Commit hash + label: Commit hash description: If using a developmen commit, which one - type: checkboxes - id: debug + id: debug attributes: - label: Tested debug version? + label: Tested debug version? description: Have you reproduced the problem using the debug version? options: - - label: "Yes" + - label: "Yes" required: true - type: checkboxes - id: os + id: os attributes: - label: Which operating systems have you used? + label: Which operating systems have you used? description: You may select more than one. options: - label: Windows @@ -41,56 +41,56 @@ body: - label: macOS - label: Other - type: checkboxes - id: bitsize + id: bitsize attributes: - label: What is the architectural bit size you're using? + label: What is the architectural bit size you're using? description: You may select more than one. options: - label: 32-bit - label: 64-bit - label: Unsure or unknown - type: checkboxes - id: cpu + id: cpu attributes: - label: What processor are you using? + label: What processor are you using? description: You may select more than one. options: - label: An Intel or AMD - label: An ARM or Apple Silicon - label: Unsure or unknown - type: textarea - id: description + id: description attributes: - label: Description + label: Description description: Description of the bug validations: required: true - type: input - id: command_line + id: command_line attributes: - label: Exact command line used + label: Exact command line used placeholder: "`Aaru [command] [parameters]`" validations: required: true - type: textarea - id: expected + id: expected attributes: - label: Expected behavior + label: Expected behavior description: What did you expect to happen validations: required: true - type: textarea - id: actual + id: actual attributes: - label: Actual behavior + label: Actual behavior description: What actually happened validations: required: true - type: textarea - id: output + id: output attributes: - label: Output of command execution with debug output enabled + label: Output of command execution with debug output enabled placeholder: Paste the whole output of the executed command when you append '-d' to your command line parameters here - render: shell + render: shell validations: required: true diff --git a/.github/ISSUE_TEMPLATE/bug_report_image.yaml b/.github/ISSUE_TEMPLATE/bug_report_image.yaml index 69fc93f2e..b8a0d3d00 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_image.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report_image.yaml @@ -1,13 +1,13 @@ -name: Image Bug Report +name: Image Bug Report description: Bugs report on commands that handle images, like converting or extracting. -labels: ["bug", "needs triage", "dump image format"] +labels: [ "bug", "needs triage", "dump image format" ] assignees: - silaslaspada body: - type: dropdown - id: version + id: version attributes: - label: Version + label: Version description: What version of Aaru are you running? options: - 5.3.0 @@ -18,22 +18,22 @@ body: validations: required: true - type: input - id: commit + id: commit attributes: - label: Commit hash + label: Commit hash description: If using a developmen commit, which one - type: checkboxes - id: debug + id: debug attributes: - label: Tested debug version? + label: Tested debug version? description: Have you reproduced the problem using the debug version? options: - - label: "Yes" + - label: "Yes" required: true - type: checkboxes - id: os + id: os attributes: - label: Which operating systems have you used? + label: Which operating systems have you used? description: You may select more than one. options: - label: Windows @@ -41,39 +41,39 @@ body: - label: macOS - label: Other - type: checkboxes - id: bitsize + id: bitsize attributes: - label: What is the architectural bit size you're using? + label: What is the architectural bit size you're using? description: You may select more than one. options: - label: 32-bit - label: 64-bit - label: Unsure or unknown - type: checkboxes - id: cpu + id: cpu attributes: - label: What processor are you using? + label: What processor are you using? description: You may select more than one. options: - label: An Intel or AMD - label: An ARM or Apple Silicon - label: Unsure or unknown - type: input - id: format + id: format attributes: label: Image format validations: required: true - type: input - id: application + id: application attributes: label: Application that created the image validations: required: true - type: checkboxes - id: action + id: action attributes: - label: What were you doing when it failed? + label: What were you doing when it failed? description: Choose all that apply options: - label: I was converting the image to another format... @@ -86,54 +86,54 @@ body: - label: I was verifying the image... - label: I was calculating the image entropy... - type: input - id: target_format + id: target_format attributes: - label: Destination image format + label: Destination image format description: If you were converting the image format, what format were you trying to convert it into - type: input - id: filesystem + id: filesystem attributes: - label: Filesystem + label: Filesystem description: If you were listing information, contents, or extracting the contents of a filesystem, which filesystem is it? (leave empty if unknown) - type: textarea - id: description + id: description attributes: - label: Description + label: Description description: Description of the bug validations: required: true - type: input - id: command_line + id: command_line attributes: - label: Exact command line used + label: Exact command line used placeholder: "`Aaru [command] [parameters]`" validations: required: true - type: textarea - id: expected + id: expected attributes: - label: Expected behavior + label: Expected behavior description: What did you expect to happen validations: required: true - type: textarea - id: actual + id: actual attributes: - label: Actual behavior + label: Actual behavior description: What actually happened validations: required: true - type: textarea - id: output + id: output attributes: - label: Output of command execution with debug output enabled + label: Output of command execution with debug output enabled placeholder: Paste the whole output of the executed command when you append '-d' to your command line parameters here - render: shell + render: shell validations: required: true - type: textarea - id: image + id: image attributes: - label: Affected image + label: Affected image placeholder: Upload the image, compressed and with the number of this issue. If the image contains personal data contact the project lead, and the image contents will be handled confidentially under the GDPR requirements. diff --git a/.github/ISSUE_TEMPLATE/bug_report_media.yaml b/.github/ISSUE_TEMPLATE/bug_report_media.yaml index cb643343c..457281083 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_media.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report_media.yaml @@ -1,13 +1,13 @@ -name: Media Bug Report +name: Media Bug Report description: Bugs report on commands that handle media, like dumping or retrieving information. -labels: ["bug", "needs triage", "media"] +labels: [ "bug", "needs triage", "media" ] assignees: - silaslaspada body: - type: dropdown - id: version + id: version attributes: - label: Version + label: Version description: What version of Aaru are you running? options: - 5.3.0 @@ -18,22 +18,22 @@ body: validations: required: true - type: input - id: commit + id: commit attributes: - label: Commit hash + label: Commit hash description: If using a developmen commit, which one - type: checkboxes - id: debug + id: debug attributes: - label: Tested debug version? + label: Tested debug version? description: Have you reproduced the problem using the debug version? options: - - label: "Yes" + - label: "Yes" required: true - type: checkboxes - id: os + id: os attributes: - label: Which operating systems have you used? + label: Which operating systems have you used? description: You may select more than one. options: - label: Windows @@ -41,39 +41,39 @@ body: - label: macOS - label: Other - type: checkboxes - id: bitsize + id: bitsize attributes: - label: What is the architectural bit size you're using? + label: What is the architectural bit size you're using? description: You may select more than one. options: - label: 32-bit - label: 64-bit - label: Unsure or unknown - type: checkboxes - id: cpu + id: cpu attributes: - label: What processor are you using? + label: What processor are you using? description: You may select more than one. options: - label: An Intel or AMD - label: An ARM or Apple Silicon - label: Unsure or unknown - type: input - id: manufacturer + id: manufacturer attributes: label: Device manufacturer validations: required: true - type: input - id: model + id: model attributes: label: Device model validations: required: true - type: checkboxes - id: bus + id: bus attributes: - label: Bus the device uses to attach to the computer + label: Bus the device uses to attach to the computer description: Select the physical drive bus as well as the bus you're using if using a cable or card reader options: - label: Parallel ATA @@ -86,19 +86,19 @@ body: - label: SecureDigital - label: MultiMediaCard - type: input - id: usb_manufacturer + id: usb_manufacturer attributes: - label: USB cable or card reader manufacturer + label: USB cable or card reader manufacturer description: Fill if using a USB cable or a USB card reader - type: input - id: usb_model + id: usb_model attributes: - label: USB cable or card reader model + label: USB cable or card reader model description: Fill if using a USB cable or a USB card reader - type: checkboxes - id: action + id: action attributes: - label: What were you doing when it failed? + label: What were you doing when it failed? description: Choose all that apply options: - label: I was dumping media (disk, tape, etc)... @@ -106,43 +106,43 @@ body: - label: I was scanning media (disk, tape, etc)... - label: I was retrieving device information... - type: textarea - id: description + id: description attributes: - label: Description + label: Description description: Description of the bug validations: required: true - type: input - id: command_line + id: command_line attributes: - label: Exact command line used + label: Exact command line used placeholder: "`Aaru [command] [parameters]`" validations: required: true - type: textarea - id: expected + id: expected attributes: - label: Expected behavior + label: Expected behavior description: What did you expect to happen validations: required: true - type: textarea - id: actual + id: actual attributes: - label: Actual behavior + label: Actual behavior description: What actually happened validations: required: true - type: textarea - id: output + id: output attributes: - label: Output of command execution with debug output enabled + label: Output of command execution with debug output enabled placeholder: Paste the whole output of the executed command when you append '-d' to your command line parameters here - render: shell + render: shell validations: required: true - type: textarea - id: details + id: details attributes: - label: Media details + label: Media details placeholder: Photo, EAN-13, if possible eBay link diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 73c24c194..9cb175346 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -1,14 +1,14 @@ -name: Feature Request +name: Feature Request description: For feature requests. Please search for existing issues first. Also see CONTRIBUTING. -title: "[Feature request] " -labels: [feature request, needs triage] -assignees: +title: "[Feature request] " +labels: [ feature request, needs triage ] +assignees: - claunia body: - type: dropdown attributes: description: Type of feture you're requesting - label: Type + label: Type options: - Support for a new media image format... - Support for identifying a new filesystem... @@ -21,19 +21,19 @@ body: - type: textarea attributes: description: Detailed Description - label: Description + label: Description placeholder: Provide a detailed description of the change or addition you are proposing validations: required: true - type: textarea attributes: description: Context - label: Context + label: Context placeholder: Why is this change important to you? How would you use it? How can it benefit other users? validations: required: true - type: textarea attributes: description: Known documentation - label: Documentation + label: Documentation placeholder: Attach documentation, links to specifications or existing source code \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ae91a9c81..09a19f463 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,67 +1,52 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: "CodeQL" -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '29 15 * * 2' +on: [ push, pull_request ] jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest + CodeQL-Build: + # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest + runs-on: windows-latest - strategy: - fail-fast: false - matrix: - language: [ 'csharp' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + permissions: + # required for all workflows + security-events: write + + # only required for workflows in private repositories + actions: read + contents: read steps: - - name: Checkout repository - uses: actions/checkout@v2 + - name: Checkout repository + uses: actions/checkout@v3 + with: + submodules: recursive + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: | + 8.0.x + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + # Override language selection by uncommenting this and choosing your languages + with: + languages: csharp - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). + # If this step fails, then you should remove it and run the build manually (see below). + - name: Autobuild + uses: github/codeql-action/autobuild@v2 - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ✏️ If the Autobuild fails above, remove it and uncomment the following + # three lines and modify them (or add more) to build your code if your + # project uses a compiled language - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + #- run: | + # make bootstrap + # make release - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index ef97e09ca..44f660e08 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -1,10 +1,6 @@ name: .NET -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] +on: [ push, pull_request ] jobs: build: @@ -12,14 +8,14 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Checking submodules - uses: textbook/git-checkout-submodule-action@2.1.1 - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 3.1.301 - - name: Restore dependencies - run: dotnet restore Aaru.sln - - name: Build - run: dotnet build --no-restore Aaru.sln + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 8.0 + - name: Restore dependencies + run: dotnet restore Aaru.sln + - name: Build + run: dotnet build --no-restore Aaru.sln diff --git a/.gitmodules b/.gitmodules index 0a8499607..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,27 +0,0 @@ -[submodule "CICMMetadata"] - path = CICMMetadata - url = https://github.com/claunia/CICMMetadata -[submodule "Aaru.Checksums"] - path = Aaru.Checksums - url = https://github.com/aaru-dps/Aaru.Checksums -[submodule "Aaru.CommonTypes"] - path = Aaru.CommonTypes - url = https://github.com/aaru-dps/Aaru.CommonTypes -[submodule "Aaru.Console"] - path = Aaru.Console - url = https://github.com/aaru-dps/Aaru.Console -[submodule "Aaru.Decoders"] - path = Aaru.Decoders - url = https://github.com/aaru-dps/Aaru.Decoders -[submodule "Aaru.Dto"] - path = Aaru.Dto - url = https://github.com/aaru-dps/Aaru.Dto -[submodule "Aaru.Helpers"] - path = Aaru.Helpers - url = https://github.com/aaru-dps/Aaru.Helpers -[submodule "cuetools.net"] - path = Aaru.Compression/cuetools.net - url = https://github.com/gchudov/cuetools.net -[submodule "Aaru.Decryption"] - path = Aaru.Decryption - url = https://github.com/aaru-dps/Aaru.Decryption diff --git a/.globalconfig b/.globalconfig new file mode 100644 index 000000000..f06bb062e --- /dev/null +++ b/.globalconfig @@ -0,0 +1,2 @@ +is_global = true +dotnet_diagnostic.PH2075.severity = none diff --git a/.idea/.idea.Aaru/.idea/codeStyles/Project.xml b/.idea/.idea.Aaru/.idea/codeStyles/Project.xml new file mode 100644 index 000000000..2e7707de6 --- /dev/null +++ b/.idea/.idea.Aaru/.idea/codeStyles/Project.xml @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.Aaru/.idea/codeStyles/codeStyleConfig.xml b/.idea/.idea.Aaru/.idea/codeStyles/codeStyleConfig.xml index a55e7a179..6e6eec114 100644 --- a/.idea/.idea.Aaru/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/.idea.Aaru/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/.idea/.idea.Aaru/.idea/runConfigurations/Aaru.xml b/.idea/.idea.Aaru/.idea/runConfigurations/Aaru.xml index 441ef3f56..9fdac204a 100644 --- a/.idea/.idea.Aaru/.idea/runConfigurations/Aaru.xml +++ b/.idea/.idea.Aaru/.idea/runConfigurations/Aaru.xml @@ -1,8 +1,8 @@ - \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index c26513d81..b885216e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: csharp solution: Aaru.sln -mono: none -dotnet: 6.0.100 +mono: none +dotnet: 6.0.100 script: - dotnet restore Aaru.sln - dotnet build Aaru.sln diff --git a/Aaru.Archives/Aaru.Archives.csproj b/Aaru.Archives/Aaru.Archives.csproj index 907f36b79..177ef038b 100644 --- a/Aaru.Archives/Aaru.Archives.csproj +++ b/Aaru.Archives/Aaru.Archives.csproj @@ -1,108 +1,119 @@ - - Debug - AnyCPU - 2.0 - {282271D0-CCC2-4ED7-BA38-EC06A84BB974} - Library - Aaru.Archives - Aaru.Archives - $(Version) - false - true - 6.0.0-alpha8 - Claunia.com - Copyright © 2011-2022 Natalia Portillo - Aaru Data Preservation Suite - Aaru.Archives - $(Version) - net6.0 - 10 - Archive implementations used by the Aaru Data Preservation Suite. - https://github.com/aaru-dps/ - LGPL-2.1-only - https://github.com/aaru-dps/Aaru.Archives - true - en-US - true - true - snupkg - Natalia Portillo <claunia@claunia.com> - true - - - $(Version)+{chash:8} - true - true - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - true - bin\Release - prompt - 4 - false - - - - - - - LICENSE.LGPL - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - /Library/Frameworks/Mono.framework/Versions/Current/lib/mono - /usr/lib/mono - /usr/local/lib/mono - - $(BaseFrameworkPathOverrideForMono)/4.0-api - $(BaseFrameworkPathOverrideForMono)/4.5-api - $(BaseFrameworkPathOverrideForMono)/4.5.1-api - $(BaseFrameworkPathOverrideForMono)/4.5.2-api - $(BaseFrameworkPathOverrideForMono)/4.6-api - $(BaseFrameworkPathOverrideForMono)/4.6.1-api - $(BaseFrameworkPathOverrideForMono)/4.6.2-api - $(BaseFrameworkPathOverrideForMono)/4.7-api - $(BaseFrameworkPathOverrideForMono)/4.7.1-api - true - - $(FrameworkPathOverride)/Facades;$(AssemblySearchPaths) - + + 2.0 + {282271D0-CCC2-4ED7-BA38-EC06A84BB974} + Library + Aaru.Archives + Aaru.Archives + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Archives + $(Version) + net8.0 + 12 + Archive implementations used by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + LGPL-2.1-only + https://github.com/aaru-dps/Aaru.Archives + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + LICENSE.LGPL + + + ResXFileCodeGenerator + Localization.Designer.cs + + + ResXFileCodeGenerator + Localization.Designer.cs + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + True + True + Localization.resx + + diff --git a/Aaru.Archives/Aaru.Archives.csproj.DotSettings b/Aaru.Archives/Aaru.Archives.csproj.DotSettings new file mode 100644 index 000000000..45681b16d --- /dev/null +++ b/Aaru.Archives/Aaru.Archives.csproj.DotSettings @@ -0,0 +1,6 @@ + + True + True \ No newline at end of file diff --git a/Aaru.Archives/Authors.cs b/Aaru.Archives/Authors.cs new file mode 100644 index 000000000..9f350cfff --- /dev/null +++ b/Aaru.Archives/Authors.cs @@ -0,0 +1,37 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Authors.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru.Filesystems. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Archives; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +static class Authors +{ + internal const string NataliaPortillo = "Natalia Portillo"; +} \ No newline at end of file diff --git a/Aaru.Archives/Localization/Localization.Designer.cs b/Aaru.Archives/Localization/Localization.Designer.cs new file mode 100644 index 000000000..229a2d7ca --- /dev/null +++ b/Aaru.Archives/Localization/Localization.Designer.cs @@ -0,0 +1,728 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Aaru.Archives { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Localization { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Localization() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aaru.Archives.Localization.Localization", typeof(Localization).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Application ID: 0x{0:X8}. + /// + internal static string Application_ID_0 { + get { + return ResourceManager.GetString("Application_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Archive options: {0}. + /// + internal static string Archive_options_0 { + get { + return ResourceManager.GetString("Archive_options_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Capabilities:. + /// + internal static string Capabilities { + get { + return ResourceManager.GetString("Capabilities", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Component name for language with code {0}: {1}. + /// + internal static string Component_name_for_language_with_code_0_1 { + get { + return ResourceManager.GetString("Component_name_for_language_with_code_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Component version: {0}.{1}. + /// + internal static string Component_version_0_1 { + get { + return ResourceManager.GetString("Component_version_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CRC16 of header: 0x{0:X4}. + /// + internal static string CRC16_of_header_0 { + get { + return ResourceManager.GetString("CRC16_of_header_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Archive contains {0} files (pointer: {1}). + /// + internal static string File_contains_0_files_pointer_1 { + get { + return ResourceManager.GetString("File_contains_0_files_pointer_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Archive contains {0} languages:. + /// + internal static string File_contains_0_languages { + get { + return ResourceManager.GetString("File_contains_0_languages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Archive contains {0} requisites. + /// + internal static string File_contains_0_requisites { + get { + return ResourceManager.GetString("File_contains_0_requisites", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Files for `{0}` language:. + /// + internal static string Files_for_0_language { + get { + return ResourceManager.GetString("Files_for_0_language", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Files for all languages:. + /// + internal static string Files_for_all_languages { + get { + return ResourceManager.GetString("Files_for_all_languages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name for language {0}: {1}. + /// + internal static string Name_for_language_0_1 { + get { + return ResourceManager.GetString("Name_for_language_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Option {0}:. + /// + internal static string Option_0 { + get { + return ResourceManager.GetString("Option_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Required {0} version {1}.{2}. + /// + internal static string Required_UID_0_version_1_2 { + get { + return ResourceManager.GetString("Required_UID_0_version_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Required variant: {0}. + /// + internal static string Required_variant_0 { + get { + return ResourceManager.GetString("Required_variant_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Requisite #{0}:. + /// + internal static string Requisite_0 { + get { + return ResourceManager.GetString("Requisite_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Requisite for language {0}: {1}. + /// + internal static string Requisite_for_language_0_1 { + get { + return ResourceManager.GetString("Requisite_for_language_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SIS contains an application. + /// + internal static string SIS_contains_an_application { + get { + return ResourceManager.GetString("SIS_contains_an_application", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UID 0x{0:X8}. + /// + internal static string SIS_Platform_UID_0 { + get { + return ResourceManager.GetString("SIS_Platform_UID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 3230. + /// + internal static string SIS_Platform_UID_Nokia_3230 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_3230", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 3250. + /// + internal static string SIS_Platform_UID_Nokia_3250 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_3250", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 3650. + /// + internal static string SIS_Platform_UID_Nokia_3650 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_3650", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 6260. + /// + internal static string SIS_Platform_UID_Nokia_6260 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_6260", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 6600. + /// + internal static string SIS_Platform_UID_Nokia_6600 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_6600", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 6620. + /// + internal static string SIS_Platform_UID_Nokia_6620 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_6620", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 6630. + /// + internal static string SIS_Platform_UID_Nokia_6630 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_6630", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 6670. + /// + internal static string SIS_Platform_UID_Nokia_6670 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_6670", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 6680. + /// + internal static string SIS_Platform_UID_Nokia_6680 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_6680", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 6681. + /// + internal static string SIS_Platform_UID_Nokia_6681 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_6681", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 6682. + /// + internal static string SIS_Platform_UID_Nokia_6682 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_6682", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 7610. + /// + internal static string SIS_Platform_UID_Nokia_7610 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_7610", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 7650. + /// + internal static string SIS_Platform_UID_Nokia_7650 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_7650", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 7710 (Series 90). + /// + internal static string SIS_Platform_UID_Nokia_7710_Series_90 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_7710_Series_90", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 9300. + /// + internal static string SIS_Platform_UID_Nokia_9300 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_9300", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia 9500. + /// + internal static string SIS_Platform_UID_Nokia_9500 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_9500", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia Belle. + /// + internal static string SIS_Platform_UID_Nokia_Belle { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_Belle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia E60. + /// + internal static string SIS_Platform_UID_Nokia_E60 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_E60", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia E61. + /// + internal static string SIS_Platform_UID_Nokia_E61 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_E61", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia E70. + /// + internal static string SIS_Platform_UID_Nokia_E70 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_E70", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia N-Gage. + /// + internal static string SIS_Platform_UID_Nokia_N_Gage { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_N_Gage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia N70. + /// + internal static string SIS_Platform_UID_Nokia_N70 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_N70", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia N71. + /// + internal static string SIS_Platform_UID_Nokia_N71 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_N71", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia N73. + /// + internal static string SIS_Platform_UID_Nokia_N73 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_N73", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia N80. + /// + internal static string SIS_Platform_UID_Nokia_N80 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_N80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia N90. + /// + internal static string SIS_Platform_UID_Nokia_N90 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_N90", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia N91. + /// + internal static string SIS_Platform_UID_Nokia_N91 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_N91", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nokia N92. + /// + internal static string SIS_Platform_UID_Nokia_N92 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Nokia_N92", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 1st Edition. + /// + internal static string SIS_Platform_UID_Series_60_1st_Edition { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_1st_Edition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 1st Edition, Feature Pack 1. + /// + internal static string SIS_Platform_UID_Series_60_1st_Edition_Feature_Pack_1 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_1st_Edition_Feature_Pack_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 2nd Edition. + /// + internal static string SIS_Platform_UID_Series_60_2nd_Edition { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_2nd_Edition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 2nd Edition, Feature Pack 1. + /// + internal static string SIS_Platform_UID_Series_60_2nd_Edition_Feature_Pack_1 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_2nd_Edition_Feature_Pack_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 2nd Edition, Feature Pack 2. + /// + internal static string SIS_Platform_UID_Series_60_2nd_Edition_Feature_Pack_2 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_2nd_Edition_Feature_Pack_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 2nd Edition, Feature Pack 3. + /// + internal static string SIS_Platform_UID_Series_60_2nd_Edition_Feature_Pack_3 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_2nd_Edition_Feature_Pack_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 3rd Edition. + /// + internal static string SIS_Platform_UID_Series_60_3rd_Edition { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_3rd_Edition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 3rd Edition, Feature Pack 1. + /// + internal static string SIS_Platform_UID_Series_60_3rd_Edition_Feature_Pack_1 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_3rd_Edition_Feature_Pack_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 3rd Edition, Feature Pack 2. + /// + internal static string SIS_Platform_UID_Series_60_3rd_Edition_Feature_Pack_2 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_3rd_Edition_Feature_Pack_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 5th Edition. + /// + internal static string SIS_Platform_UID_Series_60_5th_Edition { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_5th_Edition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 v1.0. + /// + internal static string SIS_Platform_UID_Series_60_v1_0 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_v1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 60 v1.1. + /// + internal static string SIS_Platform_UID_Series_60_v1_1 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_60_v1_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Series 80 2nd Edition. + /// + internal static string SIS_Platform_UID_Series_80_2nd_edition { + get { + return ResourceManager.GetString("SIS_Platform_UID_Series_80_2nd_edition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Siemens SX1. + /// + internal static string SIS_Platform_UID_Siemens_SX1 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Siemens_SX1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SonyEricsson P80x. + /// + internal static string SIS_Platform_UID_SonyEricsson_P80x { + get { + return ResourceManager.GetString("SIS_Platform_UID_SonyEricsson_P80x", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SonyEricsson P90x. + /// + internal static string SIS_Platform_UID_SonyEricsson_P90x { + get { + return ResourceManager.GetString("SIS_Platform_UID_SonyEricsson_P90x", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Symbian^3. + /// + internal static string SIS_Platform_UID_Symbian_3 { + get { + return ResourceManager.GetString("SIS_Platform_UID_Symbian_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UIQ v2.0. + /// + internal static string SIS_Platform_UID_UIQ_20 { + get { + return ResourceManager.GetString("SIS_Platform_UID_UIQ_20", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UIQ v2.1. + /// + internal static string SIS_Platform_UID_UIQ_21 { + get { + return ResourceManager.GetString("SIS_Platform_UID_UIQ_21", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UIQ v3.0. + /// + internal static string SIS_Platform_UID_UIQ_30 { + get { + return ResourceManager.GetString("SIS_Platform_UID_UIQ_30", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SymbianOS 3 or later. + /// + internal static string Symbian_3_or_later { + get { + return ResourceManager.GetString("Symbian_3_or_later", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SymbianOS 6 or later. + /// + internal static string Symbian_6_or_later { + get { + return ResourceManager.GetString("Symbian_6_or_later", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SymbianOS 9.1 or later. + /// + internal static string Symbian_9_1_or_later { + get { + return ResourceManager.GetString("Symbian_9_1_or_later", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Symbian Installation File. + /// + internal static string Symbian_Installation_File { + get { + return ResourceManager.GetString("Symbian_Installation_File", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Symbian Installation File. + /// + internal static string Symbian_Name { + get { + return ResourceManager.GetString("Symbian_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UIDs checksum: 0x{0:X8}. + /// + internal static string UIDs_checksum_0 { + get { + return ResourceManager.GetString("UIDs_checksum_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown EPOC magic 0x{0:X8}. + /// + internal static string Unknown_EPOC_magic_0 { + get { + return ResourceManager.GetString("Unknown_EPOC_magic_0", resourceCulture); + } + } + } +} diff --git a/Aaru.Archives/Localization/Localization.es.resx b/Aaru.Archives/Localization/Localization.es.resx new file mode 100644 index 000000000..c2d248cc1 --- /dev/null +++ b/Aaru.Archives/Localization/Localization.es.resx @@ -0,0 +1,240 @@ + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + Fichero de Instalación de Symbian + + + ID de aplicación: 0x{0:X8} + + + Capacidades: + + + CRC16 de la cabecera: 0x{0:X4} + + + El archivo contiene {0} ficheros (pointer: {1}) + + + El archivo contiene {0} idiomas: + + + El archivo contiene {0} requisitos: + + + El archivo contiene una aplicación + + + SymbianOS 3 o superior + + + SymbianOS 6 o superior + + + SymbianOS 9.1 o superior + + + Fichero de Instalación de Symbian + + + Checksum de los UIDs: 0x{0:X8} + + + Mágica EPOC 0x{0:X8} desconocida + + + Nombre del componente para el idioma con código {0}: {1} + + + Versión del componente: {0}.{1} + + + Ficheros para el idioma `{0}`: + + + Ficheros para todos los idiomas: + + + Requerida {0} versión {1}.{2} + + + Variante requerida: {0} + + + Requisito nº {0}: + + + Requisito para el idioma {0}: {1} + + + Nokia Belle + + + Series 60 1ª Edición + + + Series 60 1ª Edición, Feature Pack 1 + + + Series 60 2ª Edición + + + Series 60 2ª Edición, Feature Pack 1 + + + Series 60 2ª Edición, Feature Pack 2 + + + Series 60 2ª Edición, Feature Pack 3 + + + Series 60 3ª Edición + + + Series 60 3ª Edición, Feature Pack 1 + + + Series 60 3ª Edición, Feature Pack 2 + + + Series 60 5ª Edición + + + Symbian^3 + + + UID 0x{0:X8} + + + Opciones del archivo: {0} + + + UIQ v2.1 + + + UIQ v3.0 + + + Nokia 7650 + + + Series 60 v1.0 + + + Nokia 3650 + + + Nokia 6600 + + + Nokia 6630 + + + SonyEricsson P80x + + + Series 60 v1.1 + + + Nokia N-Gage + + + Nokia 9500 + + + Nokia 9300 + + + Series 80 2ª Edición + + + Siemens SX1 + + + Nokia 6260 + + + SonyEricsson P90x + + + Nokia 7710 (Series 90) + + + Nokia 7610 + + + Nokia 6670 + + + UIQ v2.0 + + + Nokia 3230 + + + Nokia N90 + + + Nokia N70 + + + Nokia 6680 + + + Nokia 6620 + + + Nokia 6682 + + + Nokia 6681 + + + Nokia 3250 + + + Nokia N80 + + + Nokia N92 + + + Nokia N73 + + + Nokia N91 + + + Nokia N71 + + + Nokia E60 + + + Nokia E70 + + + Nokia E61 + + + Opción {0}: + + + Nombre para el idioma {0}: {1} + + \ No newline at end of file diff --git a/Aaru.Archives/Localization/Localization.resx b/Aaru.Archives/Localization/Localization.resx new file mode 100644 index 000000000..906e7a6fa --- /dev/null +++ b/Aaru.Archives/Localization/Localization.resx @@ -0,0 +1,248 @@ + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + Symbian Installation File + + + Symbian Installation File + + + SymbianOS 9.1 or later + + + Application ID: 0x{0:X8} + + + UIDs checksum: 0x{0:X8} + + + SymbianOS 3 or later + + + SymbianOS 6 or later + + + Unknown EPOC magic 0x{0:X8} + + + CRC16 of header: 0x{0:X4} + + + SIS contains an application + + + Archive contains {0} languages: + + + Archive contains {0} files (pointer: {1}) + + + Archive contains {0} requisites + + + Capabilities: + + + Component version: {0}.{1} + + + Component name for language with code {0}: {1} + + + Files for all languages: + + + Files for `{0}` language: + + + Requisite #{0}: + + + Required {0} version {1}.{2} + + + Required variant: {0} + + + Requisite for language {0}: {1} + + + Series 60 1st Edition + + + Series 60 1st Edition, Feature Pack 1 + + + Series 60 2nd Edition + + + Series 60 2nd Edition, Feature Pack 1 + + + Series 60 2nd Edition, Feature Pack 2 + + + Series 60 2nd Edition, Feature Pack 3 + + + Series 60 3rd Edition + + + Series 60 3rd Edition, Feature Pack 1 + + + Series 60 3rd Edition, Feature Pack 2 + + + Series 60 5th Edition + + + Symbian^3 + + + Nokia Belle + + + UID 0x{0:X8} + + + Archive options: {0} + + + UIQ v2.1 + + + UIQ v3.0 + + + Nokia 7650 + + + Series 60 v1.0 + + + Nokia 3650 + + + Nokia 6600 + + + Nokia 6630 + + + SonyEricsson P80x + + + Series 60 v1.1 + + + Nokia N-Gage + + + Nokia 9500 + + + Nokia 9300 + + + Series 80 2nd Edition + + + Siemens SX1 + + + Nokia 6260 + + + SonyEricsson P90x + + + Nokia 7710 (Series 90) + + + Nokia 7610 + + + Nokia 6670 + + + UIQ v2.0 + + + Nokia 3230 + + + Nokia N90 + + + Nokia N70 + + + Nokia 6680 + + + Nokia 6620 + + + Nokia 6682 + + + Nokia 6681 + + + Nokia 3250 + + + Nokia N80 + + + Nokia N92 + + + Nokia N73 + + + Nokia N91 + + + Nokia N71 + + + Nokia E60 + + + Nokia E70 + + + Nokia E61 + + + Option {0}: + + + Name for language {0}: {1} + + \ No newline at end of file diff --git a/Aaru.Archives/Register.cs b/Aaru.Archives/Register.cs index f5c059114..2c6ac1a12 100644 --- a/Aaru.Archives/Register.cs +++ b/Aaru.Archives/Register.cs @@ -1,4 +1,4 @@ -// /*************************************************************************** +// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // @@ -34,53 +34,15 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // ---------------------------------------------------------------------------- -// Copyright © 2021-2022 Michael Drüing -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2021-2024 Michael Drüing +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using Aaru.CommonTypes.Interfaces; + namespace Aaru.Archives; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Aaru.CommonTypes.Interfaces; - +// Needs to have the interface here so the source generator knows THIS IS the class +// ReSharper disable once RedundantExtendsListEntry /// -public sealed class Register : IPluginRegister -{ - /// - public List GetAllChecksumPlugins() => null; - - /// - public List GetAllFilesystemPlugins() => null; - - /// - public List GetAllFilterPlugins() => null; - - /// - public List GetAllFloppyImagePlugins() => null; - - /// - public List GetAllMediaImagePlugins() => null; - - /// - public List GetAllPartitionPlugins() => null; - - /// - public List GetAllReadOnlyFilesystemPlugins() => null; - - /// - public List GetAllWritableFloppyImagePlugins() => null; - - /// - public List GetAllWritableImagePlugins() => null; - - /// - public List GetAllArchivePlugins() => Assembly.GetExecutingAssembly().GetTypes(). - Where(t => t.GetInterfaces().Contains(typeof(IArchive))). - Where(t => t.IsClass).ToList(); - - /// - public List GetAllByteAddressablePlugins() => null; -} \ No newline at end of file +public sealed partial class Register : IPluginRegister; \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Conditions.cs b/Aaru.Archives/Symbian/Conditions.cs new file mode 100644 index 000000000..1647b1aab --- /dev/null +++ b/Aaru.Archives/Symbian/Conditions.cs @@ -0,0 +1,327 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.IO; +using System.Linq; +using System.Text; + +namespace Aaru.Archives; + +public sealed partial class Symbian +{ + ConditionalExpression ParseConditionalExpression(BinaryReader br, uint maxOffset, StringBuilder sb, + ref Attribute? attribute) + { + if(br.BaseStream.Position >= maxOffset) return null; + + var type = (ConditionalType)br.ReadUInt32(); + var operatorString = ""; + + SubConditionalExpression subExpression; + TwoSubsConditionalExpression twoSubsConditionalExpression; + + switch(type) + { + case ConditionalType.Equals: + if(type == ConditionalType.Equals) operatorString = " == "; + + twoSubsConditionalExpression = new TwoSubsConditionalExpression + { + type = type + }; + + sb.Append("("); + twoSubsConditionalExpression.leftOperand = ParseConditionalExpression(br, maxOffset, sb, ref attribute); + sb.Append(operatorString); + + twoSubsConditionalExpression.rightOperand = + ParseConditionalExpression(br, maxOffset, sb, ref attribute); + + sb.Append(")"); + + attribute = null; + + return twoSubsConditionalExpression; + case ConditionalType.Differs: + operatorString = " != "; + goto case ConditionalType.Equals; + case ConditionalType.GreaterThan: + operatorString = " > "; + goto case ConditionalType.Equals; + case ConditionalType.LessThan: + operatorString = " < "; + goto case ConditionalType.Equals; + case ConditionalType.GreaterOrEqualThan: + operatorString = " >= "; + goto case ConditionalType.Equals; + case ConditionalType.LessOrEqualThan: + operatorString = " <= "; + goto case ConditionalType.Equals; + case ConditionalType.And: + operatorString = " && "; + goto case ConditionalType.Equals; + case ConditionalType.Or: + operatorString = " || "; + goto case ConditionalType.Equals; + case ConditionalType.Exists: + sb.Append("exists("); + + subExpression = new SubConditionalExpression + { + type = type, + subExpression = ParseConditionalExpression(br, maxOffset, sb, ref attribute) + }; + + sb.Append(")"); + + attribute = null; + + return subExpression; + case ConditionalType.DeviceCapability: + sb.Append("devcap("); + + subExpression = new SubConditionalExpression + { + type = type, + subExpression = ParseConditionalExpression(br, maxOffset, sb, ref attribute) + }; + + sb.Append(')'); + + attribute = null; + + return subExpression; + case ConditionalType.ApplicationCapability: + twoSubsConditionalExpression = new TwoSubsConditionalExpression + { + type = type + }; + + sb.Append("appcap("); + twoSubsConditionalExpression.leftOperand = ParseConditionalExpression(br, maxOffset, sb, ref attribute); + sb.Append(", "); + + twoSubsConditionalExpression.rightOperand = + ParseConditionalExpression(br, maxOffset, sb, ref attribute); + + sb.Append(')'); + + attribute = null; + + return twoSubsConditionalExpression; + case ConditionalType.Not: + sb.Append('!'); + + subExpression = new SubConditionalExpression + { + type = type, + subExpression = ParseConditionalExpression(br, maxOffset, sb, ref attribute) + }; + + attribute = null; + + return subExpression; + case ConditionalType.String: + var stringExpression = new StringConditionalExpression + { + type = type, + length = br.ReadUInt32(), + pointer = br.ReadUInt32() + }; + + long position = br.BaseStream.Position; + + br.BaseStream.Seek(stringExpression.pointer, SeekOrigin.Begin); + byte[] buffer = br.ReadBytes((int)stringExpression.length); + stringExpression.@string = _encoding.GetString(buffer); + + br.BaseStream.Seek(position, SeekOrigin.Begin); + + sb.Append($"\"{stringExpression.@string}\""); + + attribute = null; + + break; + case ConditionalType.Attribute: + var attributeExpression = new AttributeConditionalExpression + { + type = type, + attribute = (Attribute)br.ReadUInt32(), + unused = br.ReadUInt32() + }; + + if((int)attributeExpression.attribute > 0x2000) + { + int optionIndex = (int)attributeExpression.attribute - 0x2000; + + if(optionIndex <= _options.Count) + { + OptionRecord option = _options[optionIndex - 1]; + option.names.TryGetValue("EN", out string optionName); + optionName ??= option.names.Values.FirstOrDefault() ?? optionIndex.ToString(); + sb.Append($"option(\"{optionName}\", ENABLED)"); + } + else + sb.Append($"option({optionIndex}, ENABLED"); + } + else + sb.Append($"{attributeExpression.attribute}"); + + attribute = attributeExpression.attribute; + + return attributeExpression; + case ConditionalType.Number: + var numberExpression = new NumberConditionalExpression + { + type = type, + number = br.ReadUInt32(), + unused = br.ReadUInt32() + }; + + if(attribute is null) + sb.Append($"0x{numberExpression.number:X8}"); + else if((uint)attribute.Value < 0x2000) + { + switch(attribute) + { + case Attribute.Manufacturer: + sb.Append($"{(ManufacturerCode)numberExpression.number}"); + + break; + case Attribute.ManufacturerHardwareRev: + case Attribute.ManufacturerSoftwareRev: + case Attribute.DeviceFamilyRev: + sb.Append($"{numberExpression.number >> 8}.{numberExpression.number & 0xFF}"); + + break; + case Attribute.MachineUid: + sb.Append($"{DecodeMachineUid(numberExpression.number)}"); + + break; + case Attribute.DeviceFamily: + sb.Append($"{(DeviceFamilyCode)numberExpression.number}"); + + break; + case Attribute.CPU: + sb.Append($"{(CpuCode)numberExpression.number}"); + + break; + case Attribute.CPUArch: + sb.Append($"{(CpuArchitecture)numberExpression.number}"); + + break; + case Attribute.CPUABI: + sb.Append($"{(CpuAbiCode)numberExpression.number}"); + + break; + case Attribute.CPUSpeed: + sb.Append($"{numberExpression.number / 1024}MHz"); + + break; + case Attribute.SystemTickPeriod: + sb.Append($"{numberExpression.number}μs"); + + break; + case Attribute.MemoryRAM: + case Attribute.MemoryRAMFree: + case Attribute.MemoryROM: + case Attribute.MemoryPageSize: + case Attribute.Keyboard: + case Attribute.KeyboardDeviceKeys: + case Attribute.KeyboardAppKeys: + case Attribute.KeyboardClickVolumeMax: + case Attribute.DisplayXPixels: + case Attribute.DisplayYPixels: + case Attribute.DisplayXTwips: + case Attribute.DisplayYTwips: + case Attribute.DisplayColors: + case Attribute.DisplayContrastMax: + case Attribute.PenX: + case Attribute.PenY: + case Attribute.PenClickVolumeMax: + case Attribute.MouseX: + case Attribute.MouseY: + case Attribute.MouseButtons: + case Attribute.LEDs: + case Attribute.DisplayBrightnessMax: + case Attribute.KeyboardBacklightState: + case Attribute.AccessoryPower: + case Attribute.NumHalAttributes: + case Attribute.Language: + sb.Append($"{numberExpression.number}"); + + break; + case Attribute.PowerBackup: + case Attribute.KeyboardClick: + case Attribute.Backlight: + case Attribute.Pen: + case Attribute.PenDisplayOn: + case Attribute.PenClick: + case Attribute.Mouse: + case Attribute.CaseSwitch: + case Attribute.IntegratedPhone: + case Attribute.RemoteInstall: + sb.Append(numberExpression.number == 0 ? "false" : "true"); + + break; + default: + sb.Append($"0x{numberExpression.number:X8}"); + + break; + } + } + else + { + int optionIndex = (int)attribute - 0x2000; + + if(optionIndex <= _options.Count) + { + OptionRecord option = _options[optionIndex - 1]; + option.names.TryGetValue("EN", out string optionName); + optionName ??= option.names.Values.FirstOrDefault() ?? optionIndex.ToString(); + sb.Append($"option(\"{optionName}\", {(numberExpression.number == 0 ? "DISABLED" : "ENABLED")})"); + } + else + sb.Append($"option({optionIndex}, {(numberExpression.number == 0 ? "DISABLED" : "ENABLED")}"); + } + + attribute = null; + + return numberExpression; + default: + throw new ArgumentOutOfRangeException(); + } + + return null; + } +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Consts.cs b/Aaru.Archives/Symbian/Consts.cs new file mode 100644 index 000000000..2429d7b96 --- /dev/null +++ b/Aaru.Archives/Symbian/Consts.cs @@ -0,0 +1,46 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Archives; + +[SuppressMessage("ReSharper", "UnusedType.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class Symbian +{ + // Magics + const uint SYMBIAN_MAGIC = 0x10000419; + const uint EPOC_MAGIC = 0x1000006D; + const uint EPOC6_MAGIC = 0x10003A12; + const uint SYMBIAN9_MAGIC = 0x10201A7A; +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Enums.cs b/Aaru.Archives/Symbian/Enums.cs new file mode 100644 index 000000000..571c47ae0 --- /dev/null +++ b/Aaru.Archives/Symbian/Enums.cs @@ -0,0 +1,637 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Archives; + +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +[SuppressMessage("ReSharper", "InconsistentNaming")] +public sealed partial class Symbian +{ +#region Nested type: Attribute + + enum Attribute : uint + { + /// + /// + /// + Manufacturer = 0x00000000, + /// + /// 0x0100 = 1.00 + /// + ManufacturerHardwareRev = 0x00000001, + /// + /// 0x0100 = 1.00 + /// + ManufacturerSoftwareRev = 0x00000002, + /// + /// Manufacturer specific + /// + ManufacturerSoftwareBuild = 0x00000003, + Model = 0x00000004, + /// + /// Device specific values for products as defined in epoc32\include\hal_data.h + /// + MachineUid = 0x00000005, + /// + /// + /// + DeviceFamily = 0x00000006, + /// + /// 0x0100 = 1.00 + /// + DeviceFamilyRev = 0x00000007, + /// + /// + /// + CPU = 0x00000008, + /// + /// + /// + CPUArch = 0x00000009, + /// + /// + /// + CPUABI = 0x0000000a, + /// + /// CPU clock speed / 1024, e.g. 36864=36MHz + /// + CPUSpeed = 0x0000000b, + /// + /// Tick period in microseconds + /// + SystemTickPeriod = 0x0000000e, + /// + /// Approximate speed relative to Psion Series 5 = 100 + /// + SystemSpeed = 0x0000000e, + /// + /// Total RAM size in bytes + /// + MemoryRAM = 0x0000000f, + /// + /// Free RAM size in bytes + /// + MemoryRAMFree = 0x00000010, + /// + /// Total ROM size + /// + MemoryROM = 0x00000011, + /// + /// Size of memory management unit pages + /// + MemoryPageSize = 0x00000012, + /// + /// 0=none, 1=supported + /// + PowerBackup = 0x00000015, + /// + /// 0=none, 1=keypad, 2=full, 3=both + /// + Keyboard = 0x00000018, + /// + /// Number of device specific keys + /// + KeyboardDeviceKeys = 0x00000019, + /// + /// Number of application keys + /// + KeyboardAppKeys = 0x0000001a, + /// + /// 0=none, 1=supported + /// + KeyboardClick = 0x0000001b, + KeyboardClickVolumeMax = 0x0000001e, + /// + /// Screen width in pixels + /// + DisplayXPixels = 0x0000001f, + /// + /// Screen height in pixels + /// + DisplayYPixels = 0x00000020, + /// + /// Screen width in twips (1/1440 inch) + /// + DisplayXTwips = 0x00000021, + /// + /// Screen height in twips (1/1440 inch) + /// + DisplayYTwips = 0x00000022, + /// + /// 2, 4, 16, 256, 65536, etc + /// + DisplayColors = 0x00000023, + DisplayContrastMax = 0x00000026, + /// + /// 0=none, 1=supported + /// + Backlight = 0x00000027, + /// + /// 0=none, 1=supported + /// + Pen = 0x00000029, + /// + /// Pen horizontal resolution + /// + PenX = 0x0000002a, + /// + /// Pen vertical resolution + /// + PenY = 0x0000002b, + /// + /// 0=no 1=yes + /// + PenDisplayOn = 0x0000002c, + /// + /// 0=none, 1=supported + /// + PenClick = 0x0000002d, + PenClickVolumeMax = 0x00000030, + /// + /// 0=none, 1=supported + /// + Mouse = 0x00000031, + /// + /// Mouse horizontal resolution + /// + MouseX = 0x00000032, + /// + /// Mouse vertical resolution + /// + MouseY = 0x00000033, + /// + /// Number of mouse buttons + /// + MouseButtons = 0x00000037, + /// + /// 0=none, 1=supported + /// + CaseSwitch = 0x0000003a, + /// + /// Number of LEDs + /// + LEDs = 0x0000003d, + /// + /// 0=none, 1=supported + /// + IntegratedPhone = 0x0000003f, + DisplayBrightnessMax = 0x00000041, + KeyboardBacklightState = 0x00000042, + AccessoryPower = 0x00000043, + /// + /// Number of supported HAL attributes + /// + NumHalAttributes = 0x00000059, + /// + /// Machine language + /// + Language = 0x00001000, + /// + /// 0=Symbian OS based install, 1=installation via a PC + /// + RemoteInstall = 0x00001001 + } + +#endregion + +#region Nested type: ConditionalType + + enum ConditionalType : uint + { + /// + /// a == b + /// + Equals, + /// + /// a != b + /// + Differs, + /// + /// a > b + /// + GreaterThan, + /// + /// a < b + /// + LessThan, + /// + /// a >= b + /// + GreaterOrEqualThan, + /// + /// a <= b + /// + LessOrEqualThan, + /// + /// a AND b + /// + And, + /// + /// a OR b + /// + Or, + /// + /// exists(filename) + /// + Exists, + /// + /// devcap(capability) + /// + DeviceCapability, + /// + /// appcap(uid, capability) + /// + ApplicationCapability, + /// + /// NOT a + /// + Not, + /// + /// String + /// + String, + /// + /// Attribute + /// + Attribute, + /// + /// Number + /// + Number + } + +#endregion + +#region Nested type: CpuAbiCode + + enum CpuAbiCode + { + ARM4 = 0, + ARMI = 1, + Thumb = 2, + MCORE = 3, + MSVC = 4 + } + +#endregion + +#region Nested type: CpuArchitecture + + enum CpuArchitecture + { + ARM4 = 0x400, + ARM4T = 0x410, + ARM5 = 0x500, + M340 = 0x300 + } + +#endregion + +#region Nested type: CpuCode + + enum CpuCode + { + ARM = 0, + MCORE = 1, + x86 = 2 + } + +#endregion + +#region Nested type: DeviceFamilyCode + + enum DeviceFamilyCode + { + Crystal = 0, + Pearl = 1, + Quartz = 2 + } + +#endregion + +#region Nested type: FileDetails + + /// + /// Gives some specific details about how to handle some special files + /// + enum FileDetails : uint + { + /// + /// Show the continue button and continue installing + /// + TextContinue = 0, + /// + /// Show a yes and a no button and skip next file on no + /// + TextSkip = 1, + /// + /// Show a yes and a no button and abort installation on no + /// + TextAbort = 2, + /// + /// Show a yes and a no button and abort and undo installation on no + /// + TextExit = 3, + /// + /// Run during installation + /// + RunInstall = 0, + /// + /// Run during uninstallation + /// + RunRemove = 1, + /// + /// Run during both installation and uninstallation + /// + RunBoth = 2, + /// + /// Works as a flag. Close when installation is complete. + /// + RunsEnd = 0x100, + /// + /// Works as a flag. Wait for it to close before continuing. + /// + RunWait = 0x200, + /// + /// Works as a flag. Close when installation is complete. + /// + OpenClose = 0x100, + /// + /// Works as a flag. Wait for it to close before continuing. + /// + OpenWait = 0x200 + } + +#endregion + +#region Nested type: FileRecordType + + /// + /// Define the file record type and therefore its structure + /// + enum FileRecordType : uint + { + /// + /// Points to a single file + /// + SimpleFile = 0, + /// + /// Points to an array of files sorted by the language codes + /// + MultipleLanguageFiles = 1, + /// + /// Points to an array of option strings + /// + Options = 2, + If = 3, + ElseIf = 4, + Else = 5, + EndIf = 6, + /// + /// Found in the wild, doesn't seem to contain any data, and doesn't count like a file entry either + /// + Skip = 0xFFFFFFFF + } + +#endregion + +#region Nested type: FileType + + /// + /// Defines the file type + /// + enum FileType : uint + { + /// + /// Standard file + /// + File = 0, + /// + /// Text file to show during installation + /// + FileText = 1, + /// + /// SIS component + /// + Component = 2, + /// + /// File to run during installation + /// + FileRun = 3, + /// + /// File does not exist in SIS, will be created when application runs + /// + FileNull = 4, + /// + /// Open file using whatever app is associated with its MIME type + /// + FileMime = 5 + } + +#endregion + +#region Nested type: LanguageCodes + + [SuppressMessage("ReSharper", "InconsistentNaming")] + enum LanguageCodes + { + Test = 0, + EN, + FR, + GE, + SP, + IT, + SW, + DA, + NO, + FI, + AM, + SF, + SG, + PO, + TU, + IC, + RU, + HU, + DU, + BL, + AU, + BF, + AS, + NZ, + IF, + CS, + SK, + PL, + SL, + TC, + HK, + ZH, + JA, + TH, + AF, + SQ, + AH, + AR, + HY, + TL, + BE, + BN, + BG, + MY, + CA, + HR, + CE, + IE, + ZA, + ET, + FA, + CF, + GD, + KA, + EL, + CG, + GU, + HE, + HI, + IN, + GA, + SZ, + KN, + KK, + KM, + KO, + LO, + LV, + LT, + MK, + MS, + ML, + MR, + MO, + MN, + NN, + BP, + PA, + RO, + SR, + SI, + SO, + OS, + LS, + SH, + FS, + TA, + TE, + BO, + TI, + CT, + TK, + UK, + UR, + VI, + CY, + ZU + } + +#endregion + +#region Nested type: ManufacturerCode + + enum ManufacturerCode + { + Ericsson = 0, + Motorola = 1, + Nokia = 2, + Panasonic = 3, + Psion = 4, + Intel = 5, + Cogent = 6, + Cirrus = 7 + } + +#endregion + +#region Nested type: SymbianOptions + + /// + /// Options + /// + [Flags] + enum SymbianOptions : ushort + { + IsUnicode = 0x0001, + IsDistributable = 0x0002, + NoCompress = 0x0008, + ShutdownApps = 0x0010 + } + +#endregion + +#region Nested type: SymbianType + + // Types + enum SymbianType : ushort + { + /// + /// Application + /// + Application = 0x0000, + /// + /// System component (library) + /// + SystemComponent = 0x0001, + /// + /// Optional component + /// + OptionalComponent = 0x0002, + /// + /// Configures an application + /// + Configurator = 0x0003, + /// + /// Patch + /// + Patch = 0x0004, + /// + /// Upgrade + /// + Upgrade = 0x0005 + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Files.cs b/Aaru.Archives/Symbian/Files.cs new file mode 100644 index 000000000..fca292e10 --- /dev/null +++ b/Aaru.Archives/Symbian/Files.cs @@ -0,0 +1,182 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.IO; +using System.IO.Compression; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.CommonTypes.Structs; +using Aaru.Filters; +using Aaru.Helpers.IO; +using FileAttributes = System.IO.FileAttributes; + +namespace Aaru.Archives; + +public sealed partial class Symbian +{ +#region IArchive Members + + /// + public int NumberOfEntries => Opened ? _files.Count : -1; + + /// + public ErrorNumber GetFilename(int entryNumber, out string fileName) + { + fileName = null; + + if(!Opened) return ErrorNumber.NotOpened; + + if(entryNumber < 0 || entryNumber >= _files.Count) return ErrorNumber.OutOfRange; + + fileName = _files[entryNumber].destinationName; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber GetEntryNumber(string fileName, bool caseInsensitiveMatch, out int entryNumber) + { + entryNumber = -1; + + if(!Opened) return ErrorNumber.NotOpened; + + if(string.IsNullOrEmpty(fileName)) return ErrorNumber.InvalidArgument; + + entryNumber = _files.FindIndex(x => caseInsensitiveMatch + ? x.destinationName.Equals(fileName, + StringComparison.CurrentCultureIgnoreCase) + : x.destinationName.Equals(fileName, StringComparison.CurrentCulture)); + + return entryNumber < 0 ? ErrorNumber.NoSuchFile : ErrorNumber.NoError; + } + + /// + public ErrorNumber GetCompressedSize(int entryNumber, out long length) + { + length = -1; + + if(!Opened) return ErrorNumber.NotOpened; + + if(entryNumber < 0 || entryNumber >= _files.Count) return ErrorNumber.OutOfRange; + + length = _files[entryNumber].length; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber GetUncompressedSize(int entryNumber, out long length) + { + length = -1; + + if(!Opened) return ErrorNumber.NotOpened; + + if(entryNumber < 0 || entryNumber >= _files.Count) return ErrorNumber.OutOfRange; + + length = _compressed ? _files[entryNumber].originalLength : _files[entryNumber].length; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber GetAttributes(int entryNumber, out FileAttributes attributes) + { + attributes = FileAttributes.None; + + if(!Opened) return ErrorNumber.NotOpened; + + if(entryNumber < 0 || entryNumber >= _files.Count) return ErrorNumber.OutOfRange; + + attributes = FileAttributes.Normal; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber Stat(int entryNumber, out FileEntryInfo stat) + { + stat = null; + + if(!Opened) return ErrorNumber.NotOpened; + + if(entryNumber < 0 || entryNumber >= _files.Count) return ErrorNumber.OutOfRange; + + stat = new FileEntryInfo + { + Length = _compressed ? _files[entryNumber].originalLength : _files[entryNumber].length, + Attributes = CommonTypes.Structs.FileAttributes.File, + Inode = (ulong)entryNumber + }; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber GetEntry(int entryNumber, out IFilter filter) + { + filter = null; + + if(!Opened) return ErrorNumber.NotOpened; + + if(entryNumber < 0 || entryNumber >= _files.Count) return ErrorNumber.OutOfRange; + + Stream stream = new OffsetStream(new NonClosableStream(_stream), + _files[entryNumber].pointer, + _files[entryNumber].pointer + _files[entryNumber].length); + + ErrorNumber errno; + + if(_compressed) + { + if(_files[entryNumber].originalLength == 0) + stream = new MemoryStream([]); + else + { + stream = new ForcedSeekStream(_files[entryNumber].originalLength, + stream, + CompressionMode.Decompress); + } + } + + filter = new ZZZNoFilter(); + errno = filter.Open(stream); + + if(errno == ErrorNumber.NoError) return ErrorNumber.NoError; + + stream.Close(); + + return errno; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Info.cs b/Aaru.Archives/Symbian/Info.cs new file mode 100644 index 000000000..0c26390f6 --- /dev/null +++ b/Aaru.Archives/Symbian/Info.cs @@ -0,0 +1,390 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Marshal = Aaru.Helpers.Marshal; + +namespace Aaru.Archives; + +public sealed partial class Symbian +{ +#region IArchive Members + + /// + public bool Identify(IFilter filter) + { + if(filter.DataForkLength < Marshal.SizeOf()) return false; + + Stream stream = filter.GetDataForkStream(); + + var hdr = new byte[Marshal.SizeOf()]; + + stream.EnsureRead(hdr, 0, hdr.Length); + + SymbianHeader header = Marshal.ByteArrayToStructureLittleEndian(hdr); + + if(header.uid1 == SYMBIAN9_MAGIC) return true; + + if(header.uid3 != SYMBIAN_MAGIC) return false; + + return header.uid2 is EPOC_MAGIC or EPOC6_MAGIC; + } + + public void GetInformation(IFilter filter, Encoding encoding, out string information) + { + information = ""; + var description = new StringBuilder(); + var languages = new List(); + var capabilities = new Dictionary(); + Stream stream = filter.GetDataForkStream(); + + if(stream.Length < Marshal.SizeOf()) return; + + var buffer = new byte[Marshal.SizeOf()]; + + stream.Seek(0, SeekOrigin.Begin); + stream.EnsureRead(buffer, 0, buffer.Length); + SymbianHeader sh = Marshal.ByteArrayToStructureLittleEndian(buffer); + + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.uid1 = {0}", sh.uid1); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.uid2 = {0}", sh.uid2); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.uid3 = {0}", sh.uid3); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.uid4 = {0}", sh.uid4); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.crc16 = {0}", sh.crc16); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.languages = {0}", sh.languages); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.files = {0}", sh.files); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.requisites = {0}", sh.requisites); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.inst_lang = {0}", sh.inst_lang); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.inst_files = {0}", sh.inst_files); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.inst_drive = {0}", sh.inst_drive); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.capabilities = {0}", sh.capabilities); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.inst_version = {0}", sh.inst_version); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.options = {0}", sh.options); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.type = {0}", sh.type); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.major = {0}", sh.major); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.minor = {0}", sh.minor); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.variant = {0}", sh.variant); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.lang_ptr = {0}", sh.lang_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.files_ptr = {0}", sh.files_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.reqs_ptr = {0}", sh.reqs_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.certs_ptr = {0}", sh.certs_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.comp_ptr = {0}", sh.comp_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.sig_ptr = {0}", sh.sig_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.caps_ptr = {0}", sh.caps_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.instspace = {0}", sh.instspace); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.maxinsspc = {0}", sh.maxinsspc); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.reserved1 = {0}", sh.reserved1); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.reserved2 = {0}", sh.reserved2); + + _release6 = false; + + if(sh.uid1 == SYMBIAN9_MAGIC) + { + description.AppendLine(Localization.Symbian_Installation_File); + description.AppendLine(Localization.Symbian_9_1_or_later); + description.AppendFormat(Localization.Application_ID_0, sh.uid3).AppendLine(); + _release6 = true; + + description.AppendLine(); + description.AppendLine("This file format is not yet implemented, no more information can be decoded."); + + information = description.ToString(); + + return; + } + + if(sh.uid3 == SYMBIAN_MAGIC) + { + description.AppendLine(Localization.Symbian_Installation_File); + + switch(sh.uid2) + { + case EPOC_MAGIC: + description.AppendLine(Localization.Symbian_3_or_later); + + break; + case EPOC6_MAGIC: + description.AppendLine(Localization.Symbian_6_or_later); + _release6 = true; + + break; + default: + description.AppendFormat(Localization.Unknown_EPOC_magic_0, sh.uid2).AppendLine(); + + break; + } + + description.AppendFormat(Localization.Application_ID_0, sh.uid1).AppendLine(); + } + + if(sh.options.HasFlag(SymbianOptions.IsUnicode)) + _encoding = Encoding.Unicode; + else + _encoding = encoding ?? Encoding.GetEncoding("windows-1252"); + + var br = new BinaryReader(stream); + + // Go to enumerate languages + br.BaseStream.Seek(sh.lang_ptr, SeekOrigin.Begin); + for(var i = 0; i < sh.languages; i++) languages.Add(((LanguageCodes)br.ReadUInt16()).ToString("G")); + + // Go to component record + br.BaseStream.Seek(sh.comp_ptr, SeekOrigin.Begin); + + var componentRecord = new ComponentRecord + { + names = new string[languages.Count] + }; + + buffer = new byte[sizeof(uint) * languages.Count]; + + // Read the component string lenghts + stream.EnsureRead(buffer, 0, buffer.Length); + ReadOnlySpan span = buffer; + componentRecord.namesLengths = MemoryMarshal.Cast(span)[..languages.Count].ToArray(); + + // Read the component string pointers + stream.EnsureRead(buffer, 0, buffer.Length); + span = buffer; + componentRecord.namesPointers = MemoryMarshal.Cast(span)[..languages.Count].ToArray(); + + for(var i = 0; i < sh.languages; i++) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "Found component name for language {0} at {1} with a length of {2} bytes", + languages[i], + componentRecord.namesPointers[i], + componentRecord.namesLengths[i]); + + br.BaseStream.Seek(componentRecord.namesPointers[i], SeekOrigin.Begin); + buffer = br.ReadBytes((int)componentRecord.namesLengths[i]); + componentRecord.names[i] = _encoding.GetString(buffer); + } + + // Go to capabilities (???) + br.BaseStream.Seek(sh.caps_ptr, SeekOrigin.Begin); + + for(var i = 0; i < sh.capabilities; i++) + { + uint cap_Key = br.ReadUInt32(); + uint cap_Value = br.ReadUInt32(); + capabilities.Add(cap_Key, cap_Value); + } + + description.AppendFormat(Localization.UIDs_checksum_0, sh.uid4).AppendLine(); + description.AppendFormat(Localization.Archive_options_0, sh.options).AppendLine(); + description.AppendFormat(Localization.CRC16_of_header_0, sh.crc16).AppendLine(); + description.AppendLine(); + + switch(sh.type) + { + case SymbianType.Application: + description.AppendLine(Localization.SIS_contains_an_application); + + break; + } + + description.AppendFormat(Localization.Component_version_0_1, sh.major, sh.minor).AppendLine(); + + description.AppendLine(); + + description.AppendFormat(Localization.File_contains_0_languages, sh.languages).AppendLine(); + + for(var i = 0; i < languages.Count; i++) + { + if(i > 0) description.Append(", "); + description.Append($"{languages[i]}"); + } + + description.AppendLine(); + description.AppendLine(); + + for(var i = 0; i < languages.Count; i++) + { + description.AppendFormat(Localization.Component_name_for_language_with_code_0_1, + languages[i], + componentRecord.names[i]) + .AppendLine(); + } + + description.AppendLine(); + + description.AppendFormat(Localization.File_contains_0_files_pointer_1, sh.files, sh.files_ptr).AppendLine(); + description.AppendFormat(Localization.File_contains_0_requisites, sh.requisites).AppendLine(); + + uint offset = sh.reqs_ptr; + + if(sh.requisites > 0) + { + for(var r = 0; r < sh.requisites; r++) + { + br.BaseStream.Seek(offset, SeekOrigin.Begin); + + var requisiteRecord = new RequisiteRecord + { + uid = br.ReadUInt32(), + majorVersion = br.ReadUInt16(), + minorVersion = br.ReadUInt16(), + variant = br.ReadUInt32() + }; + + buffer = br.ReadBytes(sizeof(uint) * languages.Count); + span = buffer; + requisiteRecord.namesLengths = MemoryMarshal.Cast(span)[..languages.Count].ToArray(); + + buffer = br.ReadBytes(sizeof(uint) * languages.Count); + span = buffer; + requisiteRecord.namesPointers = MemoryMarshal.Cast(span)[..languages.Count].ToArray(); + + description.AppendFormat(Localization.Requisite_0, r).AppendLine(); + + description.AppendFormat("\t" + Localization.Required_UID_0_version_1_2, + DecodePlatformUid(requisiteRecord.uid), + requisiteRecord.majorVersion, + requisiteRecord.minorVersion) + .AppendLine(); + + description.AppendFormat("\t" + Localization.Required_variant_0, requisiteRecord.variant).AppendLine(); + + offset = (uint)br.BaseStream.Position; + + for(var i = 0; i < languages.Count; i++) + { + br.BaseStream.Seek(requisiteRecord.namesPointers[i], SeekOrigin.Begin); + buffer = br.ReadBytes((int)requisiteRecord.namesLengths[i]); + + description.AppendFormat("\t" + Localization.Requisite_for_language_0_1, + languages[i], + _encoding.GetString(buffer)) + .AppendLine(); + } + + description.AppendLine(); + } + } + +// description.AppendLine(Localization.Capabilities); +// foreach(KeyValuePair kvp in capabilities) +// description.AppendFormat("{0} = {1}", kvp.Key, kvp.Value).AppendLine(); + + // Set instance values + _files = []; + _conditions = []; + + uint currentFile = 0; + offset = sh.files_ptr; + var conditionLevel = 0; + _options = []; + + // Get only the options records + do + { + Parse(br, ref offset, ref currentFile, sh.files, languages, ref conditionLevel, true); + } while(currentFile < sh.files); + + // Get all other records + offset = sh.files_ptr; + currentFile = 0; + conditionLevel = 0; + + do + { + Parse(br, ref offset, ref currentFile, sh.files, languages, ref conditionLevel, false); + } while(currentFile < sh.files); + + description.AppendLine(); + + // Files appear on .sis in the reverse order they should be processed + _files.Reverse(); + + // Conditions do as well + _conditions.Reverse(); + + if(_files.Any(t => t.language is null)) + { + description.AppendLine(Localization.Files_for_all_languages); + + foreach(DecodedFileRecord file in _files.Where(t => t.language is null)) + description.AppendLine($"{file.destinationName}"); + + description.AppendLine(); + } + + foreach(string lang in languages) + { + if(_files.All(t => t.language != lang)) continue; + + description.AppendFormat(Localization.Files_for_0_language, lang).AppendLine(); + + foreach(DecodedFileRecord file in _files.Where(t => t.language == lang)) + description.AppendLine($"{file.destinationName}"); + + description.AppendLine(); + } + + if(_options.Count > 0) + { + for(var i = 0; i < _options.Count; i++) + { + OptionRecord option = _options[i]; + + description.AppendFormat(Localization.Option_0, i + 1).AppendLine(); + + foreach(KeyValuePair kvp in option.names) + { + description.AppendFormat("\t" + Localization.Name_for_language_0_1, kvp.Key, kvp.Value) + .AppendLine(); + } + } + + description.AppendLine(); + } + + if(_conditions.Count > 0) + { + description.AppendLine("Conditions:"); + foreach(string condition in _conditions) description.AppendLine(condition); + } + + information = description.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Open.cs b/Aaru.Archives/Symbian/Open.cs new file mode 100644 index 000000000..a556c4215 --- /dev/null +++ b/Aaru.Archives/Symbian/Open.cs @@ -0,0 +1,201 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Archives; + +public sealed partial class Symbian +{ +#region IArchive Members + + /// + public ErrorNumber Open(IFilter filter, Encoding encoding) + { + // Already opened! + if(Opened) return ErrorNumber.InvalidArgument; + + var languages = new List(); + _stream = filter.GetDataForkStream(); + + if(_stream.Length < Marshal.SizeOf()) return ErrorNumber.InvalidArgument; + + var buffer = new byte[Marshal.SizeOf()]; + + _stream.Seek(0, SeekOrigin.Begin); + _stream.EnsureRead(buffer, 0, buffer.Length); + SymbianHeader sh = Marshal.ByteArrayToStructureLittleEndian(buffer); + + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.uid1 = {0}", sh.uid1); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.uid2 = {0}", sh.uid2); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.uid3 = {0}", sh.uid3); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.uid4 = {0}", sh.uid4); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.crc16 = {0}", sh.crc16); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.languages = {0}", sh.languages); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.files = {0}", sh.files); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.requisites = {0}", sh.requisites); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.inst_lang = {0}", sh.inst_lang); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.inst_files = {0}", sh.inst_files); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.inst_drive = {0}", sh.inst_drive); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.capabilities = {0}", sh.capabilities); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.inst_version = {0}", sh.inst_version); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.options = {0}", sh.options); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.type = {0}", sh.type); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.major = {0}", sh.major); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.minor = {0}", sh.minor); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.variant = {0}", sh.variant); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.lang_ptr = {0}", sh.lang_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.files_ptr = {0}", sh.files_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.reqs_ptr = {0}", sh.reqs_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.certs_ptr = {0}", sh.certs_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.comp_ptr = {0}", sh.comp_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.sig_ptr = {0}", sh.sig_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.caps_ptr = {0}", sh.caps_ptr); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.instspace = {0}", sh.instspace); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.maxinsspc = {0}", sh.maxinsspc); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.reserved1 = {0}", sh.reserved1); + AaruConsole.DebugWriteLine(MODULE_NAME, "sh.reserved2 = {0}", sh.reserved2); + + _release6 = false; + + if(sh.uid1 == SYMBIAN9_MAGIC) + { + AaruConsole.ErrorWriteLine("Symbian Installation Files from Symbian OS 9 or later are not yet supported."); + + return ErrorNumber.NotSupported; + } + + if(sh.uid3 == SYMBIAN_MAGIC) + { + switch(sh.uid2) + { + case EPOC_MAGIC: + break; + case EPOC6_MAGIC: + _release6 = true; + + break; + } + } + + if(sh.options.HasFlag(SymbianOptions.IsUnicode)) + _encoding = Encoding.Unicode; + else + _encoding = encoding ?? Encoding.GetEncoding("windows-1252"); + + var br = new BinaryReader(_stream); + + // Go to enumerate languages + br.BaseStream.Seek(sh.lang_ptr, SeekOrigin.Begin); + for(var i = 0; i < sh.languages; i++) languages.Add(((LanguageCodes)br.ReadUInt16()).ToString("G")); + + _files = []; + _conditions = []; + _options = []; + + uint currentFile = 0; + uint offset = sh.files_ptr; + var conditionLevel = 0; + + // Get only the options records + do + { + Parse(br, ref offset, ref currentFile, sh.files, languages, ref conditionLevel, true); + } while(currentFile < sh.files); + + // Get all other records + offset = sh.files_ptr; + currentFile = 0; + conditionLevel = 0; + + do + { + Parse(br, ref offset, ref currentFile, sh.files, languages, ref conditionLevel, false); + } while(currentFile < sh.files); + + // Files appear on .sis in the reverse order they should be processed + _files.Reverse(); + + List filesWithFixedFilenames = []; + + foreach(DecodedFileRecord f in _files) + { + DecodedFileRecord file = f; + + if(file.destinationName.Length > 3 && file.destinationName[1] == ':' && file.destinationName[2] == '\\') + file.destinationName = file.destinationName[3..]; + + file.destinationName = file.destinationName.Replace('\\', '/'); + + if(file.language != null) file.destinationName = $"{file.language}/{file.destinationName}"; + + filesWithFixedFilenames.Add(file); + } + + _files = filesWithFixedFilenames; + + _features = ArchiveSupportedFeature.SupportsFilenames | ArchiveSupportedFeature.SupportsSubdirectories; + + if(_release6 && !sh.options.HasFlag(SymbianOptions.NoCompress)) + { + _features |= ArchiveSupportedFeature.SupportsCompression; + _compressed = true; + } + + if(_files.Any(t => t.mime is not null)) _features |= ArchiveSupportedFeature.SupportsXAttrs; + + Opened = true; + + return ErrorNumber.NoError; + } + + /// + public void Close() + { + // Already closed + if(!Opened) return; + + _stream?.Close(); + + _stream = null; + Opened = false; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Parser.cs b/Aaru.Archives/Symbian/Parser.cs new file mode 100644 index 000000000..0d6af29ef --- /dev/null +++ b/Aaru.Archives/Symbian/Parser.cs @@ -0,0 +1,608 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using Aaru.Console; +using Marshal = Aaru.Helpers.Marshal; + +namespace Aaru.Archives; + +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class Symbian +{ + void Parse(BinaryReader br, ref uint offset, ref uint currentFile, uint maxFiles, List languages, + ref int conditionLevel, bool optionsOnly) + { + currentFile++; + + if(currentFile > maxFiles) return; + + var tabulationChars = new char[conditionLevel]; + for(var i = 0; i < conditionLevel; i++) tabulationChars[i] = '\t'; + string tabulation = new(tabulationChars); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "Seeking to {0} for parsing of file {1} of {2}", + offset, + currentFile, + maxFiles); + + br.BaseStream.Seek(offset, SeekOrigin.Begin); + var recordType = (FileRecordType)br.ReadUInt32(); + + AaruConsole.DebugWriteLine(MODULE_NAME, "Found record with type {0}", recordType); + + br.BaseStream.Seek(-sizeof(FileRecordType), SeekOrigin.Current); + + byte[] buffer; + ConditionalRecord conditionalRecord; + + StringBuilder conditionSb; + Attribute? nullAttribute; + + switch(recordType) + { + case FileRecordType.SimpleFile: + buffer = br.ReadBytes(Marshal.SizeOf()); + SimpleFileRecord simpleFileRecord = Marshal.ByteArrayToStructureLittleEndian(buffer); + + offset = (uint)br.BaseStream.Position; + + // Remove the 3 fields that exist only on >= ER6 + if(!_release6) offset -= sizeof(uint) * 3; + + if(optionsOnly) break; + + var decodedFileRecord = new DecodedFileRecord + { + type = simpleFileRecord.record.type, + details = simpleFileRecord.record.details, + length = simpleFileRecord.length, + pointer = simpleFileRecord.pointer + }; + + br.BaseStream.Seek(simpleFileRecord.record.sourceNamePtr, SeekOrigin.Begin); + buffer = br.ReadBytes((int)simpleFileRecord.record.sourceNameLen); + decodedFileRecord.sourceName = _encoding.GetString(buffer); + + // Files that are not written to disk but shown or installed components do not have a destination name. + if(simpleFileRecord.record.destinationNameLen > 0) + { + br.BaseStream.Seek(simpleFileRecord.record.destinationNamePtr, SeekOrigin.Begin); + buffer = br.ReadBytes((int)simpleFileRecord.record.destinationNameLen); + decodedFileRecord.destinationName = _encoding.GetString(buffer); + } + else + decodedFileRecord.destinationName = decodedFileRecord.sourceName; + + if(_release6) + { + decodedFileRecord.originalLength = simpleFileRecord.originalLength; + + br.BaseStream.Seek(simpleFileRecord.mimePtr, SeekOrigin.Begin); + buffer = br.ReadBytes((int)simpleFileRecord.mimeLen); + decodedFileRecord.mime = _encoding.GetString(buffer); + } + + AaruConsole.DebugWriteLine(MODULE_NAME, + "Found file for \"{0}\" with length {1} at {2}", + decodedFileRecord.destinationName, + decodedFileRecord.length, + decodedFileRecord.pointer); + + _files.Add(decodedFileRecord); + + if(conditionLevel > 0) + { + bool wait, close; + + switch(decodedFileRecord.type) + { + case FileType.File: + _conditions.Add(tabulation + $"InstallFileTo(\"{decodedFileRecord.destinationName}\")"); + + break; + case FileType.FileText: + switch((FileDetails)((uint)decodedFileRecord.details & 0xFF)) + { + case FileDetails.TextContinue: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecord.sourceName}\", BUTTONS_CONTINUE, ACTION_CONTINUE)"); + + break; + case FileDetails.TextSkip: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecord.sourceName}\", BUTTONS_YES_NO, ACTION_SKIP)"); + + break; + case FileDetails.TextAbort: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecord.sourceName}\", BUTTONS_YES_NO, ACTION_ABORT)"); + + break; + case FileDetails.TextExit: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecord.sourceName}\", BUTTONS_YES_NO, ACTION_EXIT)"); + + break; + } + + break; + case FileType.FileRun: + // ReSharper disable BitwiseOperatorOnEnumWithoutFlags + wait = (decodedFileRecord.details & FileDetails.RunWait) != 0; + close = (decodedFileRecord.details & FileDetails.RunsEnd) != 0; + + // ReSharper restore BitwiseOperatorOnEnumWithoutFlags + + switch((FileDetails)((uint)decodedFileRecord.details & 0xFF)) + { + case FileDetails.RunInstall: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL, 0)"); + } + + break; + case FileDetails.RunRemove: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_REMOVE, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_REMOVE, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_REMOVE, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_REMOVE, 0)"); + } + + break; + case FileDetails.RunBoth: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL | ON_REMOVE, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL | ON_REMOVE, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL | ON_REMOVE, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL | ON_REMOVE, 0)"); + } + + break; + } + + break; + case FileType.FileMime: + // ReSharper disable BitwiseOperatorOnEnumWithoutFlags + wait = (decodedFileRecord.details & FileDetails.RunWait) != 0; + close = (decodedFileRecord.details & FileDetails.RunsEnd) != 0; + + // ReSharper restore BitwiseOperatorOnEnumWithoutFlags + + if(wait && close) + _conditions.Add(tabulation + $"Open(\"{decodedFileRecord.sourceName}\", WAIT | CLOSE)"); + else if(close) + _conditions.Add(tabulation + $"Open(\"{decodedFileRecord.sourceName}\", CLOSE)"); + else if(wait) + _conditions.Add(tabulation + $"Open(\"{decodedFileRecord.sourceName}\", WAIT)"); + else + _conditions.Add(tabulation + $"Open(\"{decodedFileRecord.sourceName}\", 0)"); + + break; + } + } + + break; + case FileRecordType.MultipleLanguageFiles: + MultipleFileRecord multipleFileRecord = new(); + + // Read common file record fields + buffer = br.ReadBytes(Marshal.SizeOf()); + multipleFileRecord.record = Marshal.ByteArrayToStructureLittleEndian(buffer); + + buffer = br.ReadBytes(sizeof(uint) * languages.Count); + ReadOnlySpan span = buffer; + multipleFileRecord.lengths = MemoryMarshal.Cast(span)[..languages.Count].ToArray(); + + buffer = br.ReadBytes(sizeof(uint) * languages.Count); + span = buffer; + multipleFileRecord.pointers = MemoryMarshal.Cast(span)[..languages.Count].ToArray(); + + if(_release6) + { + buffer = br.ReadBytes(sizeof(uint) * languages.Count); + span = buffer; + + multipleFileRecord.originalLengths = + MemoryMarshal.Cast(span)[..languages.Count].ToArray(); + + multipleFileRecord.mimeLen = br.ReadUInt32(); + multipleFileRecord.mimePtr = br.ReadUInt32(); + } + else + multipleFileRecord.originalLengths = multipleFileRecord.lengths; + + offset = (uint)br.BaseStream.Position; + + if(optionsOnly) break; + + br.BaseStream.Seek(multipleFileRecord.record.sourceNamePtr, SeekOrigin.Begin); + buffer = br.ReadBytes((int)multipleFileRecord.record.sourceNameLen); + string sourceName = _encoding.GetString(buffer); + string destinationName; + + // Files that are not written to disk but shown or installed components do not have a destination name. + if(multipleFileRecord.record.destinationNameLen > 0) + { + br.BaseStream.Seek(multipleFileRecord.record.destinationNamePtr, SeekOrigin.Begin); + buffer = br.ReadBytes((int)multipleFileRecord.record.destinationNameLen); + destinationName = _encoding.GetString(buffer); + } + else + destinationName = sourceName; + + string mimeType = null; + + if(_release6) + { + br.BaseStream.Seek(multipleFileRecord.mimePtr, SeekOrigin.Begin); + buffer = br.ReadBytes((int)multipleFileRecord.mimeLen); + mimeType = _encoding.GetString(buffer); + } + + var decodedFileRecords = new DecodedFileRecord[languages.Count]; + + for(var i = 0; i < languages.Count; i++) + { + decodedFileRecords[i].type = multipleFileRecord.record.type; + decodedFileRecords[i].details = multipleFileRecord.record.details; + decodedFileRecords[i].sourceName = sourceName; + decodedFileRecords[i].destinationName = destinationName; + decodedFileRecords[i].length = multipleFileRecord.lengths[i]; + decodedFileRecords[i].pointer = multipleFileRecord.pointers[i]; + decodedFileRecords[i].originalLength = multipleFileRecord.originalLengths[i]; + decodedFileRecords[i].mime = mimeType; + decodedFileRecords[i].language = languages[i]; + } + + _files.AddRange(decodedFileRecords); + + if(conditionLevel > 0) + { + bool wait, close; + + switch(decodedFileRecords[0].type) + { + case FileType.File: + _conditions.Add(tabulation + $"InstallFileTo(\"{decodedFileRecords[0].destinationName}\")"); + + break; + case FileType.FileText: + switch((FileDetails)((uint)decodedFileRecords[0].details & 0xFF)) + { + case FileDetails.TextContinue: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecords[0].sourceName}\", BUTTONS_CONTINUE, ACTION_CONTINUE)"); + + break; + case FileDetails.TextSkip: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecords[0].sourceName}\", BUTTONS_YES_NO, ACTION_SKIP)"); + + break; + case FileDetails.TextAbort: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecords[0].sourceName}\", BUTTONS_YES_NO, ACTION_ABORT)"); + + break; + case FileDetails.TextExit: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecords[0].sourceName}\", BUTTONS_YES_NO, ACTION_EXIT)"); + + break; + } + + break; + case FileType.FileRun: + // ReSharper disable BitwiseOperatorOnEnumWithoutFlags + wait = (decodedFileRecords[0].details & FileDetails.RunWait) != 0; + close = (decodedFileRecords[0].details & FileDetails.RunsEnd) != 0; + + // ReSharper restore BitwiseOperatorOnEnumWithoutFlags + + switch((FileDetails)((uint)decodedFileRecords[0].details & 0xFF)) + { + case FileDetails.RunInstall: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL, 0)"); + } + + break; + case FileDetails.RunRemove: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_REMOVE, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_REMOVE, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_REMOVE, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_REMOVE, 0)"); + } + + break; + case FileDetails.RunBoth: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL | ON_REMOVE, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL | ON_REMOVE, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL | ON_REMOVE, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL | ON_REMOVE, 0)"); + } + + break; + } + + break; + case FileType.FileMime: + // ReSharper disable BitwiseOperatorOnEnumWithoutFlags + wait = (decodedFileRecords[0].details & FileDetails.RunWait) != 0; + close = (decodedFileRecords[0].details & FileDetails.RunsEnd) != 0; + + // ReSharper restore BitwiseOperatorOnEnumWithoutFlags + + if(wait && close) + { + _conditions.Add(tabulation + + $"Open(\"{decodedFileRecords[0].sourceName}\", WAIT | CLOSE)"); + } + else if(close) + _conditions.Add(tabulation + $"Open(\"{decodedFileRecords[0].sourceName}\", CLOSE)"); + else if(wait) + _conditions.Add(tabulation + $"Open(\"{decodedFileRecords[0].sourceName}\", WAIT)"); + else + _conditions.Add(tabulation + $"Open(\"{decodedFileRecords[0].sourceName}\", 0)"); + + break; + } + } + + break; + case FileRecordType.Options: + OptionsLineRecord optionsLineRecord = new() + { + recordType = (FileRecordType)br.ReadUInt32(), + numberOfOptions = br.ReadUInt32() + }; + + optionsLineRecord.options = new OptionRecord[(int)optionsLineRecord.numberOfOptions]; + + for(var i = 0; i < optionsLineRecord.numberOfOptions; i++) + { + optionsLineRecord.options[i] = new OptionRecord(); + + buffer = br.ReadBytes(sizeof(uint) * languages.Count); + span = buffer; + + optionsLineRecord.options[i].lengths = + MemoryMarshal.Cast(span)[..languages.Count].ToArray(); + + buffer = br.ReadBytes(sizeof(uint) * languages.Count); + span = buffer; + + optionsLineRecord.options[i].pointers = + MemoryMarshal.Cast(span)[..languages.Count].ToArray(); + + optionsLineRecord.options[i].names = new Dictionary(); + + offset = (uint)br.BaseStream.Position; + + for(var j = 0; j < languages.Count; j++) + { + br.BaseStream.Seek(optionsLineRecord.options[i].pointers[j], SeekOrigin.Begin); + buffer = br.ReadBytes((int)optionsLineRecord.options[i].lengths[j]); + optionsLineRecord.options[i].names.Add(languages[j], _encoding.GetString(buffer)); + } + + br.BaseStream.Seek(offset, SeekOrigin.Begin); + + if(optionsOnly) _options.Add(optionsLineRecord.options[i]); + } + + offset = (uint)br.BaseStream.Position; + + break; + case FileRecordType.If: + conditionLevel--; + + tabulationChars = new char[conditionLevel]; + for(var i = 0; i < conditionLevel; i++) tabulationChars[i] = '\t'; + tabulation = new string(tabulationChars); + + conditionalRecord = new ConditionalRecord + { + recordType = (FileRecordType)br.ReadUInt32(), + length = br.ReadUInt32() + }; + + offset = (uint)(br.BaseStream.Position + conditionalRecord.length); + + if(optionsOnly) break; + + conditionSb = new StringBuilder(); + nullAttribute = null; + + conditionSb.Append(tabulation + "if("); + ParseConditionalExpression(br, offset, conditionSb, ref nullAttribute); + conditionSb.Append(")"); + + _conditions.Add(conditionSb.ToString()); + + break; + case FileRecordType.ElseIf: + tabulationChars = new char[conditionLevel - 1]; + for(var i = 0; i < conditionLevel - 1; i++) tabulationChars[i] = '\t'; + tabulation = new string(tabulationChars); + + conditionalRecord = new ConditionalRecord + { + recordType = (FileRecordType)br.ReadUInt32(), + length = br.ReadUInt32() + }; + + offset = (uint)(br.BaseStream.Position + conditionalRecord.length); + + if(optionsOnly) break; + + conditionSb = new StringBuilder(); + nullAttribute = null; + + conditionSb.Append(tabulation + "else if("); + ParseConditionalExpression(br, offset, conditionSb, ref nullAttribute); + conditionSb.Append(")"); + + _conditions.Add(conditionSb.ToString()); + + break; + case FileRecordType.Else: + tabulationChars = new char[conditionLevel - 1]; + for(var i = 0; i < conditionLevel - 1; i++) tabulationChars[i] = '\t'; + tabulation = new string(tabulationChars); + + offset = (uint)(br.BaseStream.Position + Marshal.SizeOf()); + + if(optionsOnly) break; + + _conditions.Add(tabulation + "else"); + + break; + case FileRecordType.EndIf: + conditionLevel++; + offset = (uint)(br.BaseStream.Position + Marshal.SizeOf()); + + if(optionsOnly) break; + + _conditions.Add(tabulation + "endif()" + Environment.NewLine); + + break; + case FileRecordType.Skip: + offset = (uint)br.BaseStream.Seek(sizeof(FileRecordType), SeekOrigin.Current); + currentFile--; + + break; + default: + throw new ArgumentOutOfRangeException(); + } + } +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Structs.cs b/Aaru.Archives/Symbian/Structs.cs new file mode 100644 index 000000000..18d3b4b0c --- /dev/null +++ b/Aaru.Archives/Symbian/Structs.cs @@ -0,0 +1,593 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +#pragma warning disable CS0169 // Field is never used + +#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value + +namespace Aaru.Archives; + +[SuppressMessage("ReSharper", "UnusedType.Global")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "InheritdocConsiderUsage")] +[SuppressMessage("ReSharper", "NotAccessedField.Local")] +[SuppressMessage("ReSharper", "ClassCanBeSealed.Local")] +public sealed partial class Symbian +{ +#region Nested type: AttributeConditionalExpression + + /// + /// Contains an attribute to be used as a parameter in a conditional expression + /// + class AttributeConditionalExpression : ConditionalExpression + { + public Attribute attribute; + public uint unused; + } + +#endregion + +#region Nested type: BaseFileRecord + + /// + /// Common fields to simple file record and multiple file record + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BaseFileRecord + { + /// + /// File record type, in this case or + /// + /// + public FileRecordType recordType; + /// + /// File type + /// + public FileType type; + /// + /// File details + /// + public FileDetails details; + /// + /// Length in bytes of the source name (filename on the machine that built the SIS) + /// + public uint sourceNameLen; + /// + /// Pointer to the source name + /// + public uint sourceNamePtr; + /// + /// Length in bytes of the destination name (filename+path it will be installed to. '!:' for drive means allow the user + /// to pick destination drive) + /// + public uint destinationNameLen; + /// + /// Pointer to the destination name + /// + public uint destinationNamePtr; + } + +#endregion + +#region Nested type: CapabilitiesRecord + + /// + /// TODO: Unclear, check on real files + /// + struct CapabilitiesRecord + { + public uint[] keys; + public uint[] values; + } + +#endregion + +#region Nested type: CertificatesRecord + + /// + /// Holds signature certifications, but the exact distribution of them is unclear + /// + struct CertificatesRecord + { + public ushort year; + public ushort month; + public ushort day; + public ushort hour; + public ushort minute; + public ushort second; + public uint numberOfCertificates; + } + +#endregion + +#region Nested type: ComponentRecord + + /// + /// Component record as pointed by the header + /// + struct ComponentRecord + { + /// + /// Lengths of the component names, array sorted as language records + /// + public uint[] namesLengths; + /// + /// Pointers to the component names, array sorted as language records + /// + public uint[] namesPointers; + /// + /// Decoded names, not on-disk + /// + public string[] names; + } + +#endregion + +#region Nested type: ConditionalEndRecord + + /// + /// Contains an 'else' or 'endif' expression + /// + struct ConditionalEndRecord + { + /// + /// File record type in this case or + /// + public FileRecordType recordType; + } + +#endregion + +#region Nested type: ConditionalExpression + + /// + /// Conditional expression base + /// + class ConditionalExpression + { + /// + /// Conditional type + /// + public ConditionalType type; + } + +#endregion + +#region Nested type: ConditionalRecord + + /// + /// Contains an 'if' or 'else if' condition + /// + struct ConditionalRecord + { + /// + /// File record type in this case or + /// + public FileRecordType recordType; + /// + /// Length in bytes of the record and all contained expressions + /// + public uint length; + /// + /// Conditional expression(s) (chain) + /// + public ConditionalExpression expression; + } + +#endregion + +#region Nested type: DecodedFileRecord + + /// + /// On-memory structure + /// + struct DecodedFileRecord + { + /// + /// File type + /// + public FileType type; + /// + /// File details + /// + public FileDetails details; + /// + /// Source name (filename on the machine that built the SIS) + /// + public string sourceName; + /// + /// Destination name (filename+path it will be installed to. '!:' for drive means allow the user + /// to pick destination drive) + /// + public string destinationName; + /// + /// Length in bytes of the (compressed or uncompressed) file + /// + public uint length; + /// + /// Pointer to the (compressed or uncompressed) file data + /// + public uint pointer; + /// + /// EPOC Release >= 6, uncompressed file length + /// + public uint originalLength; + /// + /// EPOC Release >= 6, MIME type string + /// + public string mime; + /// + /// Language, or null for no language + /// + public string language; + } + +#endregion + +#region Nested type: MultipleFileRecord + + /// + /// Multiple language file record, cannot be marshalled + /// + struct MultipleFileRecord + { + /// + /// Common fields to simple file record and multiple file record + /// + public BaseFileRecord record; + /// + /// Lengths in bytes of the (compressed or uncompressed) files, array sorted as language records + /// + public uint[] lengths; + /// + /// Pointers to the (compressed or uncompressed) files data, array sorted as language records + /// + public uint[] pointers; + /// + /// EPOC Release >= 6, uncompressed files lengths, array sorted as language records + /// + public uint[] originalLengths; + /// + /// EPOC Release >= 6, length in bytes of MIME type string + /// + public uint mimeLen; + /// + /// EPOC Release >= 6, pointer to MIME type string + /// + public uint mimePtr; + } + +#endregion + +#region Nested type: NumberConditionalExpression + + /// + /// Contains a number to be used as a parameter in a conditional expression + /// + class NumberConditionalExpression : ConditionalExpression + { + public uint number; + public uint unused; + } + +#endregion + +#region Nested type: OptionRecord + + struct OptionRecord + { + /// + /// Pointer to the option name lengths, array sorted as language records + /// + public uint[] lengths; + /// + /// Pointer to the option names, array sorted as language records + /// + public uint[] pointers; + public Dictionary names; + } + +#endregion + +#region Nested type: OptionsLineRecord + + struct OptionsLineRecord + { + /// + /// File record type in this case + /// + public FileRecordType recordType; + /// + /// How many options follow + /// + public uint numberOfOptions; + /// + /// Option records + /// + public OptionRecord[] options; + /// + /// 128-bit bitmap of selected options + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public ulong[] selectedOptions; + } + +#endregion + +#region Nested type: RequisiteRecord + + struct RequisiteRecord + { + /// + /// UID of the required component + /// + public uint uid; + /// + /// Major version of the required component + /// + public ushort majorVersion; + /// + /// Minor version of the required component + /// + public ushort minorVersion; + /// + /// Variant of the required component, usually set to 0 and not checked by installer + /// + public uint variant; + /// + /// Lengths of the requisite names, array sorted as language records + /// + public uint[] namesLengths; + /// + /// Pointers to the requisite names, array sorted as language records + /// + public uint[] namesPointers; + } + +#endregion + +#region Nested type: SimpleFileRecord + + /// + /// Simple file record, can be marshalled + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SimpleFileRecord + { + /// + /// Common fields to simple file record and multiple file record + /// + public BaseFileRecord record; + /// + /// Length in bytes of the (compressed or uncompressed) file + /// + public uint length; + /// + /// Pointer to the (compressed or uncompressed) file data + /// + public uint pointer; + /// + /// EPOC Release >= 6, uncompressed file length + /// + public uint originalLength; + /// + /// EPOC Release >= 6, length in bytes of MIME type string + /// + public uint mimeLen; + /// + /// EPOC Release >= 6, pointer to MIME type string + /// + public uint mimePtr; + } + +#endregion + +#region Nested type: StringConditionalExpression + + /// + /// Points to a string used as a parameter in a conditional expression + /// + class StringConditionalExpression : ConditionalExpression + { + public uint length; + public uint pointer; + public string @string; + } + +#endregion + +#region Nested type: SubConditionalExpression + + /// + /// Conditional expression that contains a single sub-expression + /// + class SubConditionalExpression : ConditionalExpression + { + /// + /// Sub-expression + /// + public ConditionalExpression subExpression; + } + +#endregion + +#region Nested type: SymbianHeader + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SymbianHeader + { + /// + /// Application UID before SymbianOS 9, magic after + /// + public uint uid1; + /// + /// EPOC release magic before SOS 9, NULLs after + /// + public uint uid2; + /// + /// Application UID after SOS 9, magic before + /// + public uint uid3; + /// + /// Checksum of UIDs 1 to 3 + /// + public uint uid4; + /// + /// CRC16 of all header + /// + public ushort crc16; + /// + /// Number of languages + /// + public ushort languages; + /// + /// Number of files + /// + public ushort files; + /// + /// Number of requisites + /// + public ushort requisites; + /// + /// Installed language (only residual SIS) + /// + public ushort inst_lang; + /// + /// Installed files (only residual SIS) + /// + public ushort inst_files; + /// + /// Installed drive (only residual SIS), NULL or 0x0021 + /// + public ushort inst_drive; + /// + /// Number of capabilities + /// + public ushort capabilities; + /// + /// Version of Symbian Installer required + /// + public uint inst_version; + /// + /// Option flags + /// + public SymbianOptions options; + /// + /// Type + /// + public SymbianType type; + /// + /// Major version of application + /// + public ushort major; + /// + /// Minor version of application + /// + public ushort minor; + /// + /// Variant when SIS is a prerequisite for other SISs + /// + public uint variant; + /// + /// Pointer to language records + /// + public uint lang_ptr; + /// + /// Pointer to file records + /// + public uint files_ptr; + /// + /// Pointer to requisite records + /// + public uint reqs_ptr; + /// + /// Pointer to certificate records + /// + public uint certs_ptr; + /// + /// Pointer to component name record + /// + public uint comp_ptr; + + // From EPOC Release 6 + /// + /// Pointer to signature record + /// + public uint sig_ptr; + /// + /// Pointer to capability records + /// + public uint caps_ptr; + /// + /// Installed space (only residual SIS) + /// + public uint instspace; + /// + /// Space required + /// + public uint maxinsspc; + /// + /// Reserved + /// + public ulong reserved1; + /// + /// Reserved + /// + public ulong reserved2; + } + +#endregion + +#region Nested type: TwoSubsConditionalExpression + + /// + /// Conditional expression that contains two sub-expressions + /// + class TwoSubsConditionalExpression : ConditionalExpression + { + /// + /// Left hand side sub-expression + /// + public ConditionalExpression leftOperand; + /// + /// Right hand side sub-expression + /// + public ConditionalExpression rightOperand; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Symbian.cs b/Aaru.Archives/Symbian/Symbian.cs new file mode 100644 index 000000000..3c2daf801 --- /dev/null +++ b/Aaru.Archives/Symbian/Symbian.cs @@ -0,0 +1,73 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Archives; + +// Information from https://thoukydides.github.io/riscos-psifs/sis.html +public sealed partial class Symbian : IArchive +{ + const string MODULE_NAME = "Symbian Installation File Plugin"; + bool _compressed; + List _conditions; + Encoding _encoding; + ArchiveSupportedFeature _features; + List _files; + List _options; + bool _release6; + Stream _stream; + +#region IArchive Members + + /// + public bool Opened { get; private set; } + + public string Author => Authors.NataliaPortillo; + + public string Name => Localization.Symbian_Name; + public Guid Id => new("0EC84EC7-EAE6-4196-83FE-943B3FE48DBD"); + + /// + public ArchiveSupportedFeature ArchiveFeatures => !Opened + ? ArchiveSupportedFeature.SupportsFilenames | + ArchiveSupportedFeature.SupportsCompression | + ArchiveSupportedFeature.SupportsSubdirectories | + ArchiveSupportedFeature.SupportsXAttrs + : _features; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/UID.cs b/Aaru.Archives/Symbian/UID.cs new file mode 100644 index 000000000..c6c0cf8d2 --- /dev/null +++ b/Aaru.Archives/Symbian/UID.cs @@ -0,0 +1,229 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Archives; + +public sealed partial class Symbian +{ + static string DecodePlatformUid(uint uid) => uid switch + { + 0x101F61CE => Localization.SIS_Platform_UID_UIQ_21, + 0x101F6300 => Localization.SIS_Platform_UID_UIQ_30, + 0x101F6F87 => Localization.SIS_Platform_UID_Nokia_7650, + 0x101F6F88 => Localization.SIS_Platform_UID_Series_60_1st_Edition, + 0x101F795F => Localization.SIS_Platform_UID_Series_60_v1_0, + 0x101F7960 => Localization.SIS_Platform_UID_Series_60_2nd_Edition, + 0x101F7961 => Localization.SIS_Platform_UID_Series_60_3rd_Edition, + 0x101F7962 => Localization.SIS_Platform_UID_Nokia_3650, + 0x101F7963 => Localization.SIS_Platform_UID_Nokia_6600, + 0x101F7964 => Localization.SIS_Platform_UID_Nokia_6630, + 0x101F80BE => Localization.SIS_Platform_UID_SonyEricsson_P80x, + 0x101F8201 => Localization.SIS_Platform_UID_Series_60_v1_1, + 0x101F8202 => Localization + .SIS_Platform_UID_Series_60_1st_Edition_Feature_Pack_1, + 0x101F8A64 => Localization.SIS_Platform_UID_Nokia_N_Gage, + 0x101F8DDB => Localization.SIS_Platform_UID_Nokia_9500, + 0x101F8ED1 => Localization.SIS_Platform_UID_Nokia_9300, + 0x101F8ED2 => Localization.SIS_Platform_UID_Series_80_2nd_edition, + 0x101F9071 => Localization.SIS_Platform_UID_Siemens_SX1, + 0x101F9115 => Localization + .SIS_Platform_UID_Series_60_2nd_Edition_Feature_Pack_1, + 0x101FB3F4 => Localization.SIS_Platform_UID_Nokia_6260, + 0x101FBB35 => Localization.SIS_Platform_UID_SonyEricsson_P90x, + 0x101FBE05 => Localization.SIS_Platform_UID_Nokia_7710_Series_90, + 0x101FD5DB => Localization.SIS_Platform_UID_Nokia_7610, + 0x101FD5DC => Localization.SIS_Platform_UID_Nokia_6670, + 0x101f617b => Localization.SIS_Platform_UID_UIQ_20, + 0x10200BAB => Localization + .SIS_Platform_UID_Series_60_2nd_Edition_Feature_Pack_2, + 0x10200F97 => Localization.SIS_Platform_UID_Nokia_3230, + 0x10200F98 => Localization.SIS_Platform_UID_Nokia_N90, + 0x10200F9A => Localization.SIS_Platform_UID_Nokia_N70, + 0x10200f99 => Localization.SIS_Platform_UID_Nokia_6680, + 0x1020216B => Localization.SIS_Platform_UID_Nokia_6620, + 0x102032BD => Localization + .SIS_Platform_UID_Series_60_2nd_Edition_Feature_Pack_3, + 0x102032BE => Localization + .SIS_Platform_UID_Series_60_3rd_Edition_Feature_Pack_1, + 0x102078CF => Localization.SIS_Platform_UID_Nokia_6682, + 0x102078D0 => Localization.SIS_Platform_UID_Nokia_6681, + 0x102752AE => Localization + .SIS_Platform_UID_Series_60_3rd_Edition_Feature_Pack_2, + 0x1028315F => Localization.SIS_Platform_UID_Series_60_5th_Edition, + 0x200005F8 => Localization.SIS_Platform_UID_Nokia_3250, + 0x200005F9 => Localization.SIS_Platform_UID_Nokia_N80, + 0x200005FA => Localization.SIS_Platform_UID_Nokia_N92, + 0x200005FB => Localization.SIS_Platform_UID_Nokia_N73, + 0x200005FC => Localization.SIS_Platform_UID_Nokia_N91, + 0x200005FF => Localization.SIS_Platform_UID_Nokia_N71, + 0x20001856 => Localization.SIS_Platform_UID_Nokia_E60, + 0x20001857 => Localization.SIS_Platform_UID_Nokia_E70, + 0x20001858 => Localization.SIS_Platform_UID_Nokia_E61, + 0x20022E6D => Localization.SIS_Platform_UID_Symbian_3, + 0x2003A678 => Localization.SIS_Platform_UID_Nokia_Belle, + _ => string.Format(Localization.SIS_Platform_UID_0, uid) + }; + + static string DecodeMachineUid(uint uid) => uid switch + { + 0x200005f8 => "UID_NOKIA_3250", + 0x20024104 => "UID_NOKIA_5228", + 0x20023763 => "UID_NOKIA_5230", + 0x20023764 => "UID_NOKIA_5230a", + 0x2002376b => "UID_NOKIA_5230_NURON", + 0x20024105 => "UID_NOKIA_5235", + 0x2002bf93 => "UID_NOKIA_5250", + 0x2000da5a => "UID_NOKIA_5320", + 0x20000602 => "UID_NOKIA_5500", + 0x2001de9d => "UID_NOKIA_5530", + 0x2001de9e => "UID_NOKIA_5530_chinese", + 0x2000da61 => "UID_NOKIA_5630", + 0x20002d7c => "UID_NOKIA_5700", + 0x20014dd3 => "UID_NOKIA_5730", + 0x2000da56 => "UID_NOKIA_5800", + 0x20002d7b => "UID_NOKIA_6110", + 0x20002d7e => "UID_NOKIA_6120", + 0x2000da55 => "UID_NOKIA_6124", + 0x2000da54 => "UID_NOKIA_6210", + 0x2000da52 => "UID_NOKIA_6220", + 0x2000da53 => "UID_NOKIA_6220_cn", + 0x20000606 => "UID_NOKIA_6290", + 0x2000da57 => "UID_NOKIA_6650", + 0x2001de9b => "UID_NOKIA_6700", + 0x20014dd1 => "UID_NOKIA_6710", + 0x20014dcd => "UID_NOKIA_6720", + 0x2001de9a => "UID_NOKIA_6730", + 0x200227e2 => "UID_NOKIA_6760", + 0x200227e6 => "UID_NOKIA_6788", + 0x2001de98 => "UID_NOKIA_6790", + 0x20024107 => "UID_NOKIA_C5_00", + 0x20029a75 => "UID_NOKIA_C5_01", + 0x2002bf91 => "UID_NOKIA_C6_00", + 0x2002376a => "UID_NOKIA_C6_01", + 0x2002bf92 => "UID_NOKIA_C7_00", + 0x20002495 => "UID_NOKIA_E50", + 0x20002498 => "UID_NOKIA_E51", + 0x20014dcc => "UID_NOKIA_E52", + 0x20014dcf => "UID_NOKIA_E55", + 0x20001856 => "UID_NOKIA_E60", + 0x20001858 => "UID_NOKIA_E61", + 0x20002d7f => "UID_NOKIA_E61i", + 0x20001859 => "UID_NOKIA_E62", + 0x200025c3 => "UID_NOKIA_E63", + 0x20000604 => "UID_NOKIA_E65", + 0x2000249c => "UID_NOKIA_E66", + 0x2002bf96 => "UID_NOKIA_E7_00", + 0x20001857 => "UID_NOKIA_E70", + 0x2000249b => "UID_NOKIA_E71", + 0x20014dd8 => "UID_NOKIA_E71x", + 0x20014dd0 => "UID_NOKIA_E72", + 0x20029a6d => "UID_NOKIA_E73", + 0x2000249d => "UID_NOKIA_E75", + 0x20002496 => "UID_NOKIA_E90", + 0x20024100 => "UID_NOKIA_E5_00", + 0x10200f9a => "UID_NOKIA_N70", + 0x200005ff => "UID_NOKIA_N71", + 0x200005fb => "UID_NOKIA_N73", + 0x200005fe => "UID_NOKIA_N75", + 0x2000060a => "UID_NOKIA_N76", + 0x20000601 => "UID_NOKIA_N77", + 0x20002d81 => "UID_NOKIA_N78", + 0x2000da64 => "UID_NOKIA_N79", + 0x20029a73 => "UID_NOKIA_N8_00", + 0x200005f9 => "UID_NOKIA_N80", + 0x20002d83 => "UID_NOKIA_N81", + 0x20002d85 => "UID_NOKIA_N82", + 0x20002d86 => "UID_NOKIA_N85", + 0x20014dd2 => "UID_NOKIA_N86", + 0x200005fc => "UID_NOKIA_N91", + 0x200005fa => "UID_NOKIA_N92", + 0x20000600 => "UID_NOKIA_N93", + 0x20000605 => "UID_NOKIA_N93i", + 0x2000060b => "UID_NOKIA_N95", + 0x20002d84 => "UID_NOKIA_N95_8GB", + 0x20002d82 => "UID_NOKIA_N96", + 0x20014ddd => "UID_NOKIA_N97", + 0x20014dde => "UID_NOKIA_N97a", + 0x20023766 => "UID_NOKIA_N97_mini", + 0x20029a76 => "UID_NOKIA_X5_00", + 0x20024101 => "UID_NOKIA_X5_01", + 0x200227dd => "UID_NOKIA_X6", + 0x20008610 => "UID_SAMSUNG_I400", + 0x2000a677 => "UID_SAMSUNG_I450", + 0x20003abd => "UID_SAMSUNG_I520", + 0x2000a678 => "UID_SAMSUNG_I550", + 0x2000c51c => "UID_SAMSUNG_I560", + 0x2000a679 => "UID_SAMSUNG_I590", + 0x2000c51f => "UID_SAMSUNG_I7110", + 0x2000c51e => "UID_SAMSUNG_I8510", + 0x2000c520 => "UID_SAMSUNG_I8910", + 0x2001f0a1 => "UID_SONYERICSSON_SATIO", + 0x10274bf9 => "UID_SONYERICSSON_M600", + 0x10274bfa => "UID_SONYERICSSON_W950", + 0x20002e6a => "UID_SONYERICSSON_W960", + 0x1020e285 => "UID_SONYERICSSON_P990", + 0x20002e69 => "UID_SONYERICSSON_P1", + 0x2000cc70 => "UID_SONYERICSSON_G700", + 0x2000cc6c => "UID_SONYERICSSON_G900", + 0x20024eec => "UID_SONYERICSSON_VIVAZ_U5i", + 0x20024eed => "UID_SONYERICSSON_VIVAZ_U8", + 0x1027400d => "UID_MOTOROLA_Z8", + 0x101ff809 => "UID_LG_KT610", + 0x10200f97 => "UID_NOKIA_3230", + 0x101f466a => "UID_NOKIA_3650", + 0x101f8c19 => "UID_NOKIA_NGAGE", + 0x101fb2b1 => "UID_NOKIA_NGAGE_QD", + 0x101fb3f4 => "UID_NOKIA_6260", + 0x101fb3dd => "UID_NOKIA_6600", + 0x101f3ee3 => "UID_NOKIA_6620", + 0x101fbb55 => "UID_NOKIA_6630", + 0x101fb3f3 => "UID_NOKIA_6670", + 0x10200f99 => "UID_NOKIA_6680", + 0x10200f9c => "UID_NOKIA_6681", + 0x10200f9b => "UID_NOKIA_6682", + 0x101f4fc3 => "UID_NOKIA_7650", + 0x10005e33 => "UID_NOKIA_92XX", + 0x101f8ddb => "UID_NOKIA_9x00", + 0x1020e048 => "UID_NOKIA_9300i", + 0x10200f98 => "UID_NOKIA_N90", + 0x101fbe09 => "UID_NOKIA_7710", + 0x101fa031 => "UID_SENDO_X", + 0x101f9071 => "UID_SIEMENS_SX1", + 0x101fe7b7 => "SAMSUNG_SGH_D730", + 0x101f408b => "UID_SONYERICSSON_P800", + 0x101fb2ae => "UID_SONYERICSSON_P900", + 0x10200ac6 => "UID_SONYERICSSON_P910", + 0x101f6b26 => "UID_MOTOROLA_A9XX", + 0x101f6b27 => "UID_MOTOROLA_A1000", + _ => $"{uid:X8}" + }; +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Xattrs.cs b/Aaru.Archives/Symbian/Xattrs.cs new file mode 100644 index 000000000..e70a2595a --- /dev/null +++ b/Aaru.Archives/Symbian/Xattrs.cs @@ -0,0 +1,77 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.Text; +using Aaru.CommonTypes.Enums; + +namespace Aaru.Archives; + +public sealed partial class Symbian +{ +#region IArchive Members + + /// + public ErrorNumber ListXAttr(int entryNumber, out List xattrs) + { + xattrs = null; + + if(!Opened) return ErrorNumber.NotOpened; + + if(entryNumber < 0 || entryNumber >= _files.Count) return ErrorNumber.OutOfRange; + + xattrs = []; + + if(_files[entryNumber].mime is not null) xattrs.Add("org.iana.mime_type"); + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber GetXattr(int entryNumber, string xattr, ref byte[] buffer) + { + buffer = null; + + if(!Opened) return ErrorNumber.NotOpened; + + if(entryNumber < 0 || entryNumber >= _files.Count) return ErrorNumber.OutOfRange; + + if(xattr != "org.iana.mime_type" || _files[entryNumber].mime is null) + return ErrorNumber.NoSuchExtendedAttribute; + + buffer = Encoding.ASCII.GetBytes(_files[entryNumber].mime); + + return ErrorNumber.NoError; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Checksums b/Aaru.Checksums deleted file mode 160000 index 3362cdcd7..000000000 --- a/Aaru.Checksums +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3362cdcd74318e4fb51779f88579fddfa7ddd8cc diff --git a/Aaru.Checksums/.gitignore b/Aaru.Checksums/.gitignore new file mode 100644 index 000000000..05c540d38 --- /dev/null +++ b/Aaru.Checksums/.gitignore @@ -0,0 +1,595 @@ +### VisualStudio template +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ +### Linux template + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +### C++ template +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o + +# Precompiled Headers +*.gch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### MonoDevelop template +#User Specific +*.usertasks + +#Mono Project Files +*.resources +test-results/ +### GPG template +secring.* + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests +### CMake template +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +### C template +# Object files +*.ko +*.elf + +# Linker output +*.map +*.exp + +*.so.* + +# Executables +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# NuGet Packages Directory +packages/ +## TODO: If the tool you use requires repositories.config uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +# This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) +!packages/build/ + + +# Others +sql/ +*.Cache + +# Visual Studio 2017 +.vs + +workspace.xml +cmake-build-debug +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +pkg/**/pkg +pkg/**/src +pkg/**/*.asc +pkg/**/*.sig +pkg/**/*.tar.xz +pkg/**/*.zip +pkg/**/aaru + +.sonarqube \ No newline at end of file diff --git a/Aaru.Checksums/Aaru.Checksums.csproj b/Aaru.Checksums/Aaru.Checksums.csproj new file mode 100644 index 000000000..549091c54 --- /dev/null +++ b/Aaru.Checksums/Aaru.Checksums.csproj @@ -0,0 +1,108 @@ + + + + 2.0 + {CC48B324-A532-4A45-87A6-6F91F7141E8D} + Library + Aaru.Checksums + Aaru.Checksums + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Checksums + $(Version) + net8.0 + 12 + C# implementation of CRC16, CRC32, CRC64, Fletcher, MD5, SHA1, SHA2 and SpamSum. + https://github.com/aaru-dps/ + LGPL-2.1-only + https://github.com/aaru-dps/Aaru.Checksums + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + + + + + + LICENSE.LGPL + + + LICENSE + + + ResXFileCodeGenerator + Localization.Designer.cs + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + \ No newline at end of file diff --git a/Aaru.Checksums/Aaru.Checksums.csproj.DotSettings b/Aaru.Checksums/Aaru.Checksums.csproj.DotSettings new file mode 100644 index 000000000..50c5847b4 --- /dev/null +++ b/Aaru.Checksums/Aaru.Checksums.csproj.DotSettings @@ -0,0 +1,6 @@ + + True \ No newline at end of file diff --git a/Aaru.Checksums/Adler32/neon.cs b/Aaru.Checksums/Adler32/neon.cs new file mode 100644 index 000000000..2057f373a --- /dev/null +++ b/Aaru.Checksums/Adler32/neon.cs @@ -0,0 +1,242 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : neon.cs +// Author(s) : Natalia Portillo +// The Chromium Authors +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Compute Adler32 checksum using NEON vectorization. +// +// --[ License ] -------------------------------------------------------------- +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright 2017 The Chromium Authors. All rights reserved. +// ****************************************************************************/ + +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace Aaru.Checksums.Adler32; + +static class Neon +{ + internal static void Step(ref ushort preSum1, ref ushort preSum2, byte[] buf, uint len) + { + /* + * Split Adler-32 into component sums. + */ + uint s1 = preSum1; + uint s2 = preSum2; + + var bufPos = 0; + + /* + * Process the data in blocks. + */ + const uint blockSize = 1 << 5; + uint blocks = len / blockSize; + len -= blocks * blockSize; + + while(blocks != 0) + { + uint n = Adler32Context.NMax / blockSize; /* The NMAX constraint. */ + + if(n > blocks) n = blocks; + + blocks -= n; + /* + * Process n blocks of data. At most NMAX data bytes can be + * processed before s2 must be reduced modulo ADLER_MODULE. + */ + var vS2 = Vector128.Create(s1 * n, 0, 0, 0); + var vS1 = Vector128.Create(0u, 0, 0, 0); + Vector128 vColumnSum1 = AdvSimd.DuplicateToVector128((ushort)0); + Vector128 vColumnSum2 = AdvSimd.DuplicateToVector128((ushort)0); + Vector128 vColumnSum3 = AdvSimd.DuplicateToVector128((ushort)0); + Vector128 vColumnSum4 = AdvSimd.DuplicateToVector128((ushort)0); + + do + { + /* + * Load 32 input bytes. + */ + var bytes1 = Vector128.Create(buf[bufPos], + buf[bufPos + 1], + buf[bufPos + 2], + buf[bufPos + 3], + buf[bufPos + 4], + buf[bufPos + 5], + buf[bufPos + 6], + buf[bufPos + 7], + buf[bufPos + 8], + buf[bufPos + 9], + buf[bufPos + 10], + buf[bufPos + 11], + buf[bufPos + 12], + buf[bufPos + 13], + buf[bufPos + 14], + buf[bufPos + 15]); + + bufPos += 16; + + var bytes2 = Vector128.Create(buf[bufPos], + buf[bufPos + 1], + buf[bufPos + 2], + buf[bufPos + 3], + buf[bufPos + 4], + buf[bufPos + 5], + buf[bufPos + 6], + buf[bufPos + 7], + buf[bufPos + 8], + buf[bufPos + 9], + buf[bufPos + 10], + buf[bufPos + 11], + buf[bufPos + 12], + buf[bufPos + 13], + buf[bufPos + 14], + buf[bufPos + 15]); + + bufPos += 16; + /* + * Add previous block byte sum to v_s2. + */ + vS2 = AdvSimd.Add(vS2, vS1); + + /* + * Horizontally add the bytes for s1. + */ + vS1 = AdvSimd.AddPairwiseWideningAndAdd(vS1, + AdvSimd + .AddPairwiseWideningAndAdd(AdvSimd + .AddPairwiseWidening(bytes1), + bytes2)); + + /* + * Vertically add the bytes for s2. + */ + vColumnSum1 = AdvSimd.AddWideningLower(vColumnSum1, bytes1.GetLower()); + vColumnSum2 = AdvSimd.AddWideningLower(vColumnSum2, bytes1.GetUpper()); + vColumnSum3 = AdvSimd.AddWideningLower(vColumnSum3, bytes2.GetLower()); + vColumnSum4 = AdvSimd.AddWideningLower(vColumnSum4, bytes2.GetUpper()); + } while(--n != 0); + + vS2 = AdvSimd.ShiftLeftLogical(vS2, 5); + + /* + * Multiply-add bytes by [ 32, 31, 30, ... ] for s2. + */ + vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, + vColumnSum1.GetLower(), + Vector64.Create((ushort)32, 31, 30, 29)); + + vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, + vColumnSum1.GetUpper(), + Vector64.Create((ushort)28, 27, 26, 25)); + + vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, + vColumnSum2.GetLower(), + Vector64.Create((ushort)24, 23, 22, 21)); + + vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, + vColumnSum2.GetUpper(), + Vector64.Create((ushort)20, 19, 18, 17)); + + vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, + vColumnSum3.GetLower(), + Vector64.Create((ushort)16, 15, 14, 13)); + + vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, + vColumnSum3.GetUpper(), + Vector64.Create((ushort)12, 11, 10, 9)); + + vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum4.GetLower(), Vector64.Create((ushort)8, 7, 6, 5)); + + vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum4.GetUpper(), Vector64.Create((ushort)4, 3, 2, 1)); + + /* + * Sum epi32 ints v_s1(s2) and accumulate in s1(s2). + */ + Vector64 sum1 = AdvSimd.AddPairwise(vS1.GetLower(), vS1.GetUpper()); + Vector64 sum2 = AdvSimd.AddPairwise(vS2.GetLower(), vS2.GetUpper()); + Vector64 s1S2 = AdvSimd.AddPairwise(sum1, sum2); + s1 += AdvSimd.Extract(s1S2, 0); + s2 += AdvSimd.Extract(s1S2, 1); + /* + * Reduce. + */ + s1 %= Adler32Context.AdlerModule; + s2 %= Adler32Context.AdlerModule; + } + + /* + * Handle leftover data. + */ + if(len != 0) + { + if(len >= 16) + { + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + len -= 16; + } + + while(len-- != 0) s2 += s1 += buf[bufPos++]; + + if(s1 >= Adler32Context.AdlerModule) s1 -= Adler32Context.AdlerModule; + + s2 %= Adler32Context.AdlerModule; + } + + /* + * Return the recombined sums. + */ + preSum1 = (ushort)(s1 & 0xFFFF); + preSum2 = (ushort)(s2 & 0xFFFF); + } +} \ No newline at end of file diff --git a/Aaru.Checksums/Adler32/ssse3.cs b/Aaru.Checksums/Adler32/ssse3.cs new file mode 100644 index 000000000..e03300cd5 --- /dev/null +++ b/Aaru.Checksums/Adler32/ssse3.cs @@ -0,0 +1,188 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ssse3.cs +// Author(s) : Natalia Portillo +// The Chromium Authors +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Compute Adler32 checksum using SSSE3 vectorization. +// +// --[ License ] -------------------------------------------------------------- +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright 2017 The Chromium Authors. All rights reserved. +// ****************************************************************************/ + +using System; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace Aaru.Checksums.Adler32; + +static class Ssse3 +{ + internal static void Step(ref ushort sum1, ref ushort sum2, byte[] buf, uint len) + { + uint s1 = sum1; + uint s2 = sum2; + var bufPos = 0; + + /* + * Process the data in blocks. + */ + const uint blockSize = 1 << 5; + uint blocks = len / blockSize; + len -= blocks * blockSize; + + while(blocks != 0) + { + uint n = Adler32Context.NMax / blockSize; /* The NMAX constraint. */ + + if(n > blocks) n = blocks; + + blocks -= n; + + Vector128 tap1 = Vector128.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17) + .AsByte(); + + Vector128 tap2 = Vector128.Create(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1).AsByte(); + Vector128 zero = Vector128.Create(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).AsByte(); + var ones = Vector128.Create(1, 1, 1, 1, 1, 1, 1, 1); + /* + * Process n blocks of data. At most NMAX data bytes can be + * processed before s2 must be reduced modulo BASE. + */ + var vPs = Vector128.Create(s1 * n, 0, 0, 0); + var vS2 = Vector128.Create(s2, 0, 0, 0); + var vS1 = Vector128.Create(0u, 0, 0, 0); + + do + { + /* + * Load 32 input bytes. + */ + var bytes1 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos), + BitConverter.ToUInt32(buf, bufPos + 4), + BitConverter.ToUInt32(buf, bufPos + 8), + BitConverter.ToUInt32(buf, bufPos + 12)); + + bufPos += 16; + + var bytes2 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos), + BitConverter.ToUInt32(buf, bufPos + 4), + BitConverter.ToUInt32(buf, bufPos + 8), + BitConverter.ToUInt32(buf, bufPos + 12)); + + bufPos += 16; + + /* + * Add previous block byte sum to v_ps. + */ + vPs = Sse2.Add(vPs, vS1); + /* + * Horizontally add the bytes for s1, multiply-adds the + * bytes by [ 32, 31, 30, ... ] for s2. + */ + vS1 = Sse2.Add(vS1, Sse2.SumAbsoluteDifferences(bytes1.AsByte(), zero).AsUInt32()); + + Vector128 mad1 = + System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes1.AsByte(), tap1.AsSByte()); + + vS2 = Sse2.Add(vS2, Sse2.MultiplyAddAdjacent(mad1.AsInt16(), ones.AsInt16()).AsUInt32()); + vS1 = Sse2.Add(vS1, Sse2.SumAbsoluteDifferences(bytes2.AsByte(), zero).AsUInt32()); + + Vector128 mad2 = + System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes2.AsByte(), tap2.AsSByte()); + + vS2 = Sse2.Add(vS2, Sse2.MultiplyAddAdjacent(mad2.AsInt16(), ones.AsInt16()).AsUInt32()); + } while(--n != 0); + + vS2 = Sse2.Add(vS2, Sse2.ShiftLeftLogical(vPs, 5)); + /* + * Sum epi32 ints v_s1(s2) and accumulate in s1(s2). + */ + vS1 = Sse2.Add(vS1, Sse2.Shuffle(vS1, 177)); + vS1 = Sse2.Add(vS1, Sse2.Shuffle(vS1, 78)); + s1 += (uint)Sse2.ConvertToInt32(vS1.AsInt32()); + vS2 = Sse2.Add(vS2, Sse2.Shuffle(vS2, 177)); + vS2 = Sse2.Add(vS2, Sse2.Shuffle(vS2, 78)); + s2 = (uint)Sse2.ConvertToInt32(vS2.AsInt32()); + /* + * Reduce. + */ + s1 %= Adler32Context.AdlerModule; + s2 %= Adler32Context.AdlerModule; + } + + /* + * Handle leftover data. + */ + if(len != 0) + { + if(len >= 16) + { + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + len -= 16; + } + + while(len-- != 0) s2 += s1 += buf[bufPos++]; + + if(s1 >= Adler32Context.AdlerModule) s1 -= Adler32Context.AdlerModule; + + s2 %= Adler32Context.AdlerModule; + } + + /* + * Return the recombined sums. + */ + sum1 = (ushort)(s1 & 0xFFFF); + sum2 = (ushort)(s2 & 0xFFFF); + } +} \ No newline at end of file diff --git a/Aaru.Checksums/Adler32Context.cs b/Aaru.Checksums/Adler32Context.cs new file mode 100644 index 000000000..cb9837330 --- /dev/null +++ b/Aaru.Checksums/Adler32Context.cs @@ -0,0 +1,415 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Adler32Context.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Implements an Adler-32 algorithm. +// +// --[ License ] -------------------------------------------------------------- +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright (C) 1995-2011 Mark Adler +// Copyright (C) Jean-loup Gailly +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Arm; +using System.Text; +using Aaru.Checksums.Adler32; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Ssse3 = System.Runtime.Intrinsics.X86.Ssse3; + +namespace Aaru.Checksums; + +/// +/// Implements the Adler-32 algorithm +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +public sealed partial class Adler32Context : IChecksum +{ + internal const ushort AdlerModule = 65521; + internal const uint NMax = 5552; + readonly IntPtr _nativeContext; + readonly bool _useNative; + ushort _sum1, _sum2; + + /// Initializes the Adler-32 sums + public Adler32Context() + { + _sum1 = 1; + _sum2 = 0; + + if(!Native.IsSupported) return; + + _nativeContext = adler32_init(); + _useNative = _nativeContext != IntPtr.Zero; + } + +#region IChecksum Members + + /// + public string Name => Localization.Adler32_Name; + + /// + public Guid Id => new("D69CF1E7-4A7B-4605-9291-3A1BE4C2951F"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + var finalSum = (uint)(_sum2 << 16 | _sum1); + + if(!_useNative) return BigEndianBitConverter.GetBytes(finalSum); + + adler32_final(_nativeContext, ref finalSum); + adler32_free(_nativeContext); + + return BigEndianBitConverter.GetBytes(finalSum); + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + var finalSum = (uint)(_sum2 << 16 | _sum1); + + if(_useNative) + { + adler32_final(_nativeContext, ref finalSum); + adler32_free(_nativeContext); + } + + var adlerOutput = new StringBuilder(); + + for(var i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++) + adlerOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2")); + + return adlerOutput.ToString(); + } + +#endregion + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial IntPtr adler32_init(); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int adler32_update(IntPtr ctx, byte[] data, uint len); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int adler32_final(IntPtr ctx, ref uint checksum); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial void adler32_free(IntPtr ctx); + + static void Step(ref ushort preSum1, ref ushort preSum2, byte[] data, uint len, bool useNative, + IntPtr nativeContext) + { + if(useNative) + { + adler32_update(nativeContext, data, len); + + return; + } + + if(Ssse3.IsSupported) + { + Adler32.Ssse3.Step(ref preSum1, ref preSum2, data, len); + + return; + } + + if(AdvSimd.IsSupported) + { + Neon.Step(ref preSum1, ref preSum2, data, len); + + return; + } + + uint sum1 = preSum1; + uint sum2 = preSum2; + var dataOff = 0; + + switch(len) + { + /* in case user likes doing a byte at a time, keep it fast */ + case 1: + { + sum1 += data[dataOff]; + + if(sum1 >= AdlerModule) sum1 -= AdlerModule; + + sum2 += sum1; + + if(sum2 >= AdlerModule) sum2 -= AdlerModule; + + preSum1 = (ushort)(sum1 & 0xFFFF); + preSum2 = (ushort)(sum2 & 0xFFFF); + + return; + } + /* in case short lengths are provided, keep it somewhat fast */ + case < 16: + { + while(len-- > 0) + { + sum1 += data[dataOff++]; + sum2 += sum1; + } + + if(sum1 >= AdlerModule) sum1 -= AdlerModule; + + sum2 %= AdlerModule; /* only added so many ADLER_MODULE's */ + preSum1 = (ushort)(sum1 & 0xFFFF); + preSum2 = (ushort)(sum2 & 0xFFFF); + + return; + } + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while(len >= NMax) + { + len -= NMax; + uint n = NMax / 16; + + do + { + sum1 += data[dataOff]; + sum2 += sum1; + sum1 += data[dataOff + 1]; + sum2 += sum1; + sum1 += data[dataOff + 2]; + sum2 += sum1; + sum1 += data[dataOff + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 2 + 1]; + sum2 += sum1; + + /* 16 sums unrolled */ + dataOff += 16; + } while(--n != 0); + + sum1 %= AdlerModule; + sum2 %= AdlerModule; + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if(len != 0) + { + /* avoid modulos if none remaining */ + while(len >= 16) + { + len -= 16; + sum1 += data[dataOff]; + sum2 += sum1; + sum1 += data[dataOff + 1]; + sum2 += sum1; + sum1 += data[dataOff + 2]; + sum2 += sum1; + sum1 += data[dataOff + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 2 + 1]; + sum2 += sum1; + + dataOff += 16; + } + + while(len-- != 0) + { + sum1 += data[dataOff++]; + sum2 += sum1; + } + + sum1 %= AdlerModule; + sum2 %= AdlerModule; + } + + preSum1 = (ushort)(sum1 & 0xFFFF); + preSum2 = (ushort)(sum2 & 0xFFFF); + } + + /// Gets the hash of a file + /// File path. + public static byte[] File(string filename) + { + File(filename, out byte[] hash); + + return hash; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + bool useNative = Native.IsSupported; + IntPtr nativeContext = IntPtr.Zero; + + if(useNative) + { + nativeContext = adler32_init(); + + if(nativeContext == IntPtr.Zero) useNative = false; + } + + var fileStream = new FileStream(filename, FileMode.Open); + + ushort localSum1 = 1; + ushort localSum2 = 0; + + var buffer = new byte[65536]; + int read = fileStream.EnsureRead(buffer, 0, 65536); + + while(read > 0) + { + Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext); + read = fileStream.EnsureRead(buffer, 0, 65536); + } + + var finalSum = (uint)(localSum2 << 16 | localSum1); + + if(useNative) + { + adler32_final(nativeContext, ref finalSum); + adler32_free(nativeContext); + } + + hash = BigEndianBitConverter.GetBytes(finalSum); + + var adlerOutput = new StringBuilder(); + + foreach(byte h in hash) adlerOutput.Append(h.ToString("x2")); + + fileStream.Close(); + + return adlerOutput.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + bool useNative = Native.IsSupported; + IntPtr nativeContext = IntPtr.Zero; + + if(useNative) + { + nativeContext = adler32_init(); + + if(nativeContext == IntPtr.Zero) useNative = false; + } + + ushort localSum1 = 1; + ushort localSum2 = 0; + + Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext); + + var finalSum = (uint)(localSum2 << 16 | localSum1); + + if(useNative) + { + adler32_final(nativeContext, ref finalSum); + adler32_free(nativeContext); + } + + hash = BigEndianBitConverter.GetBytes(finalSum); + + var adlerOutput = new StringBuilder(); + + foreach(byte h in hash) adlerOutput.Append(h.ToString("x2")); + + return adlerOutput.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} \ No newline at end of file diff --git a/Aaru.Checksums/Authors.cs b/Aaru.Checksums/Authors.cs new file mode 100644 index 000000000..ee56b2442 --- /dev/null +++ b/Aaru.Checksums/Authors.cs @@ -0,0 +1,37 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Authors.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru.Checksums. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Checksums; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +static class Authors +{ + internal const string NataliaPortillo = "Natalia Portillo"; +} \ No newline at end of file diff --git a/Aaru.Checksums/CDChecksums.cs b/Aaru.Checksums/CDChecksums.cs new file mode 100644 index 000000000..891f4c063 --- /dev/null +++ b/Aaru.Checksums/CDChecksums.cs @@ -0,0 +1,673 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CDChecksums.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Implements CD checksums. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.If not, see. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ECC algorithm from ECM(c) 2002-2011 Neill Corlett +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Checksums; + +/// Implements ReedSolomon and CRC32 algorithms as used by CD-ROM +public static class CdChecksums +{ + const string MODULE_NAME = "CD checksums"; + static byte[] _eccFTable; + static byte[] _eccBTable; + static uint[] _edcTable; + + /// Checks the EDC and ECC of a CD sector + /// CD sector + /// + /// true if all checks were correct, false if any of them weren't, and null if none of them + /// are present. + /// + public static bool? CheckCdSector(byte[] buffer) => CheckCdSector(buffer, out _, out _, out _); + + /// Checks the EDC and ECC of a CD sector + /// CD sector + /// + /// true if ECC P is correct, false if it isn't, and null if there is no ECC + /// P in sector. + /// + /// + /// true if ECC Q is correct, false if it isn't, and null if there is no ECC + /// Q in sector. + /// + /// + /// true if EDC is correct, false if it isn't, and null if there is no EDC in + /// sector. + /// + /// + /// true if all checks were correct, false if any of them weren't, and null if none of them + /// are present. + /// + public static bool? CheckCdSector(byte[] buffer, out bool? correctEccP, out bool? correctEccQ, out bool? correctEdc) + { + correctEccP = null; + correctEccQ = null; + correctEdc = null; + + switch(buffer.Length) + { + case 2448: + { + var subchannel = new byte[96]; + var channel = new byte[2352]; + + Array.Copy(buffer, 0, channel, 0, 2352); + Array.Copy(buffer, 2352, subchannel, 0, 96); + + bool? channelStatus = CheckCdSectorChannel(channel, out correctEccP, out correctEccQ, out correctEdc); + + bool? subchannelStatus = CheckCdSectorSubChannel(subchannel); + bool? status = null; + + if(channelStatus == false || subchannelStatus == false) status = false; + + status = channelStatus switch + { + null when subchannelStatus == true => true, + true when subchannelStatus == null => true, + _ => status + }; + + return status; + } + + case 2352: + return CheckCdSectorChannel(buffer, out correctEccP, out correctEccQ, out correctEdc); + default: + return null; + } + } + + static void EccInit() + { + _eccFTable = new byte[256]; + _eccBTable = new byte[256]; + _edcTable = new uint[256]; + + for(uint i = 0; i < 256; i++) + { + uint edc = i; + var j = (uint)(i << 1 ^ ((i & 0x80) == 0x80 ? 0x11D : 0)); + _eccFTable[i] = (byte)j; + _eccBTable[i ^ j] = (byte)i; + + for(j = 0; j < 8; j++) edc = edc >> 1 ^ ((edc & 1) > 0 ? 0xD8018001 : 0); + + _edcTable[i] = edc; + } + } + + static bool CheckEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult, uint minorInc, + byte[] ecc) + { + uint size = majorCount * minorCount; + uint major; + + for(major = 0; major < majorCount; major++) + { + uint index = (major >> 1) * majorMult + (major & 1); + byte eccA = 0; + byte eccB = 0; + uint minor; + + for(minor = 0; minor < minorCount; minor++) + { + byte temp = index < 4 ? address[index] : data[index - 4]; + index += minorInc; + + if(index >= size) index -= size; + + eccA ^= temp; + eccB ^= temp; + eccA = _eccFTable[eccA]; + } + + eccA = _eccBTable[_eccFTable[eccA] ^ eccB]; + + if(ecc[major] != eccA || ecc[major + majorCount] != (eccA ^ eccB)) return false; + } + + return true; + } + + static bool? CheckCdSectorChannel(byte[] channel, out bool? correctEccP, out bool? correctEccQ, + out bool? correctEdc) + { + EccInit(); + + correctEccP = null; + correctEccQ = null; + correctEdc = null; + + if(channel[0x000] != 0x00 || + channel[0x001] != 0xFF || + channel[0x002] != 0xFF || + channel[0x003] != 0xFF || + channel[0x004] != 0xFF || + channel[0x005] != 0xFF || + channel[0x006] != 0xFF || + channel[0x007] != 0xFF || + channel[0x008] != 0xFF || + channel[0x009] != 0xFF || + channel[0x00A] != 0xFF || + channel[0x00B] != 0x00) + return null; + + //AaruConsole.DebugWriteLine(MODULE_NAME, "Data sector, address {0:X2}:{1:X2}:{2:X2}", channel[0x00C], + // channel[0x00D], channel[0x00E]); + + switch(channel[0x00F] & 0x03) + { + // mode (1 byte) + case 0x00: + { + //AaruConsole.DebugWriteLine(MODULE_NAME, "Mode 0 sector at address {0:X2}:{1:X2}:{2:X2}", + // channel[0x00C], channel[0x00D], channel[0x00E]); + for(var i = 0x010; i < 0x930; i++) + { + if(channel[i] == 0x00) continue; + + AaruConsole.DebugWriteLine(MODULE_NAME, + "Mode 0 sector with error at address: {0:X2}:{1:X2}:{2:X2}", + channel[0x00C], + channel[0x00D], + channel[0x00E]); + + return false; + } + + return true; + } + + // mode (1 byte) + //AaruConsole.DebugWriteLine(MODULE_NAME, "Mode 1 sector at address {0:X2}:{1:X2}:{2:X2}", + // channel[0x00C], channel[0x00D], channel[0x00E]); + case 0x01 when channel[0x814] != 0x00 || // reserved (8 bytes) + channel[0x815] != 0x00 || + channel[0x816] != 0x00 || + channel[0x817] != 0x00 || + channel[0x818] != 0x00 || + channel[0x819] != 0x00 || + channel[0x81A] != 0x00 || + channel[0x81B] != 0x00: + AaruConsole.DebugWriteLine(MODULE_NAME, + "Mode 1 sector with data in reserved bytes at address: {0:X2}:{1:X2}:{2:X2}", + channel[0x00C], + channel[0x00D], + channel[0x00E]); + + return false; + case 0x01: + { + var address = new byte[4]; + var data = new byte[2060]; + var data2 = new byte[2232]; + var eccP = new byte[172]; + var eccQ = new byte[104]; + + Array.Copy(channel, 0x0C, address, 0, 4); + Array.Copy(channel, 0x10, data, 0, 2060); + Array.Copy(channel, 0x10, data2, 0, 2232); + Array.Copy(channel, 0x81C, eccP, 0, 172); + Array.Copy(channel, 0x8C8, eccQ, 0, 104); + + bool failedEccP = !CheckEcc(address, data, 86, 24, 2, 86, eccP); + bool failedEccQ = !CheckEcc(address, data2, 52, 43, 86, 88, eccQ); + + correctEccP = !failedEccP; + correctEccQ = !failedEccQ; + + if(failedEccP) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "Mode 1 sector at address: {0:X2}:{1:X2}:{2:X2}, fails ECC P check", + channel[0x00C], + channel[0x00D], + channel[0x00E]); + } + + if(failedEccQ) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "Mode 1 sector at address: {0:X2}:{1:X2}:{2:X2}, fails ECC Q check", + channel[0x00C], + channel[0x00D], + channel[0x00E]); + } + + var storedEdc = BitConverter.ToUInt32(channel, 0x810); + uint calculatedEdc = ComputeEdc(0, channel, 0x810); + + correctEdc = calculatedEdc == storedEdc; + + if(calculatedEdc == storedEdc) return !failedEccP && !failedEccQ; + + AaruConsole.DebugWriteLine(MODULE_NAME, + "Mode 1 sector at address: {0:X2}:{1:X2}:{2:X2}, got CRC 0x{3:X8} expected 0x{4:X8}", + channel[0x00C], + channel[0x00D], + channel[0x00E], + calculatedEdc, + storedEdc); + + return false; + } + + // mode (1 byte) + case 0x02: + { + //AaruConsole.DebugWriteLine(MODULE_NAME, "Mode 2 sector at address {0:X2}:{1:X2}:{2:X2}", + // channel[0x00C], channel[0x00D], channel[0x00E]); + var mode2Sector = new byte[channel.Length - 0x10]; + Array.Copy(channel, 0x10, mode2Sector, 0, mode2Sector.Length); + + if((channel[0x012] & 0x20) == 0x20) // mode 2 form 2 + { + if(channel[0x010] != channel[0x014] || + channel[0x011] != channel[0x015] || + channel[0x012] != channel[0x016] || + channel[0x013] != channel[0x017]) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "Subheader copies differ in mode 2 form 2 sector at address: {0:X2}:{1:X2}:{2:X2}", + channel[0x00C], + channel[0x00D], + channel[0x00E]); + } + + var storedEdc = BitConverter.ToUInt32(mode2Sector, 0x91C); + + // No CRC stored! + if(storedEdc == 0x00000000) return true; + + uint calculatedEdc = ComputeEdc(0, mode2Sector, 0x91C); + + correctEdc = calculatedEdc == storedEdc; + + if(calculatedEdc == storedEdc) return true; + + AaruConsole.DebugWriteLine(MODULE_NAME, + "Mode 2 form 2 sector at address: {0:X2}:{1:X2}:{2:X2}, got CRC 0x{3:X8} expected 0x{4:X8}", + channel[0x00C], + channel[0x00D], + channel[0x00E], + calculatedEdc, + storedEdc); + + return false; + } + else + { + if(channel[0x010] != channel[0x014] || + channel[0x011] != channel[0x015] || + channel[0x012] != channel[0x016] || + channel[0x013] != channel[0x017]) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "Subheader copies differ in mode 2 form 1 sector at address: {0:X2}:{1:X2}:{2:X2}", + channel[0x00C], + channel[0x00D], + channel[0x00E]); + } + + var address = new byte[4]; + var eccP = new byte[172]; + var eccQ = new byte[104]; + + Array.Copy(mode2Sector, 0x80C, eccP, 0, 172); + Array.Copy(mode2Sector, 0x8B8, eccQ, 0, 104); + + bool failedEccP = !CheckEcc(address, mode2Sector, 86, 24, 2, 86, eccP); + bool failedEccQ = !CheckEcc(address, mode2Sector, 52, 43, 86, 88, eccQ); + + correctEccP = !failedEccP; + correctEccQ = !failedEccQ; + + if(failedEccP) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "Mode 2 form 1 sector at address: {0:X2}:{1:X2}:{2:X2}, fails ECC P check", + channel[0x00C], + channel[0x00D], + channel[0x00E]); + } + + if(failedEccQ) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "Mode 2 form 1 sector at address: {0:X2}:{1:X2}:{2:X2}, fails ECC Q check", + channel[0x00C], + channel[0x00D], + channel[0x00E]); + } + + var storedEdc = BitConverter.ToUInt32(mode2Sector, 0x808); + uint calculatedEdc = ComputeEdc(0, mode2Sector, 0x808); + + correctEdc = calculatedEdc == storedEdc; + + if(calculatedEdc == storedEdc) return !failedEccP && !failedEccQ; + + AaruConsole.DebugWriteLine(MODULE_NAME, + "Mode 2 sector at address: {0:X2}:{1:X2}:{2:X2}, got CRC 0x{3:X8} expected 0x{4:X8}", + channel[0x00C], + channel[0x00D], + channel[0x00E], + calculatedEdc, + storedEdc); + + return false; + } + } + default: + AaruConsole.DebugWriteLine(MODULE_NAME, + "Unknown mode {0} sector at address: {1:X2}:{2:X2}:{3:X2}", + channel[0x00F], + channel[0x00C], + channel[0x00D], + channel[0x00E]); + + return null; + } + } + + static uint ComputeEdc(uint edc, IReadOnlyList src, int size) + { + var pos = 0; + + for(; size > 0; size--) edc = edc >> 8 ^ _edcTable[(edc ^ src[pos++]) & 0xFF]; + + return edc; + } + + static bool? CheckCdSectorSubChannel(IReadOnlyList subchannel) + { + bool? status = true; + var qSubChannel = new byte[12]; + var cdTextPack1 = new byte[18]; + var cdTextPack2 = new byte[18]; + var cdTextPack3 = new byte[18]; + var cdTextPack4 = new byte[18]; + var cdSubRwPack1 = new byte[24]; + var cdSubRwPack2 = new byte[24]; + var cdSubRwPack3 = new byte[24]; + var cdSubRwPack4 = new byte[24]; + + var i = 0; + + for(var j = 0; j < 12; j++) qSubChannel[j] = 0; + + for(var j = 0; j < 18; j++) + { + cdTextPack1[j] = 0; + cdTextPack2[j] = 0; + cdTextPack3[j] = 0; + cdTextPack4[j] = 0; + } + + for(var j = 0; j < 24; j++) + { + cdSubRwPack1[j] = 0; + cdSubRwPack2[j] = 0; + cdSubRwPack3[j] = 0; + cdSubRwPack4[j] = 0; + } + + for(var j = 0; j < 12; j++) + { + qSubChannel[j] = (byte)(qSubChannel[j] | (subchannel[i++] & 0x40) << 1); + qSubChannel[j] = (byte)(qSubChannel[j] | subchannel[i++] & 0x40); + qSubChannel[j] = (byte)(qSubChannel[j] | (subchannel[i++] & 0x40) >> 1); + qSubChannel[j] = (byte)(qSubChannel[j] | (subchannel[i++] & 0x40) >> 2); + qSubChannel[j] = (byte)(qSubChannel[j] | (subchannel[i++] & 0x40) >> 3); + qSubChannel[j] = (byte)(qSubChannel[j] | (subchannel[i++] & 0x40) >> 4); + qSubChannel[j] = (byte)(qSubChannel[j] | (subchannel[i++] & 0x40) >> 5); + qSubChannel[j] = (byte)(qSubChannel[j] | (subchannel[i++] & 0x40) >> 6); + } + + i = 0; + + for(var j = 0; j < 18; j++) + { + cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x3F) << 2); + + if(j < 17) cdTextPack1[j] = (byte)(cdTextPack1[j++] | (subchannel[i] & 0xC0) >> 4); + + cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x0F) << 4); + + if(j < 17) cdTextPack1[j] = (byte)(cdTextPack1[j++] | (subchannel[i] & 0x3C) >> 2); + + cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x03) << 6); + + cdTextPack1[j] = (byte)(cdTextPack1[j] | subchannel[i++] & 0x3F); + } + + for(var j = 0; j < 18; j++) + { + cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x3F) << 2); + + if(j < 17) cdTextPack2[j] = (byte)(cdTextPack2[j++] | (subchannel[i] & 0xC0) >> 4); + + cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x0F) << 4); + + if(j < 17) cdTextPack2[j] = (byte)(cdTextPack2[j++] | (subchannel[i] & 0x3C) >> 2); + + cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x03) << 6); + + cdTextPack2[j] = (byte)(cdTextPack2[j] | subchannel[i++] & 0x3F); + } + + for(var j = 0; j < 18; j++) + { + cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x3F) << 2); + + if(j < 17) cdTextPack3[j] = (byte)(cdTextPack3[j++] | (subchannel[i] & 0xC0) >> 4); + + cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x0F) << 4); + + if(j < 17) cdTextPack3[j] = (byte)(cdTextPack3[j++] | (subchannel[i] & 0x3C) >> 2); + + cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x03) << 6); + + cdTextPack3[j] = (byte)(cdTextPack3[j] | subchannel[i++] & 0x3F); + } + + for(var j = 0; j < 18; j++) + { + cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x3F) << 2); + + if(j < 17) cdTextPack4[j] = (byte)(cdTextPack4[j++] | (subchannel[i] & 0xC0) >> 4); + + cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x0F) << 4); + + if(j < 17) cdTextPack4[j] = (byte)(cdTextPack4[j++] | (subchannel[i] & 0x3C) >> 2); + + cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x03) << 6); + + cdTextPack4[j] = (byte)(cdTextPack4[j] | subchannel[i++] & 0x3F); + } + + i = 0; + + for(var j = 0; j < 24; j++) cdSubRwPack1[j] = (byte)(subchannel[i++] & 0x3F); + + for(var j = 0; j < 24; j++) cdSubRwPack2[j] = (byte)(subchannel[i++] & 0x3F); + + for(var j = 0; j < 24; j++) cdSubRwPack3[j] = (byte)(subchannel[i++] & 0x3F); + + for(var j = 0; j < 24; j++) cdSubRwPack4[j] = (byte)(subchannel[i++] & 0x3F); + + switch(cdSubRwPack1[0]) + { + case 0x00: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Detected_Zero_Pack_in_subchannel); + + break; + case 0x08: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Detected_Line_Graphics_Pack_in_subchannel); + + break; + case 0x09: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Detected_CD_G_Pack_in_subchannel); + + break; + case 0x0A: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Detected_CD_EG_Pack_in_subchannel); + + break; + case 0x14: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Detected_CD_TEXT_Pack_in_subchannel); + + break; + case 0x18: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Detected_CD_MIDI_Pack_in_subchannel); + + break; + case 0x38: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Detected_User_Pack_in_subchannel); + + break; + default: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Detected_unknown_Pack_type_in_subchannel_mode_0_item_1, + Convert.ToString(cdSubRwPack1[0] & 0x38, 2), + Convert.ToString(cdSubRwPack1[0] & 0x07, 2)); + + break; + } + + var qSubChannelCrc = BigEndianBitConverter.ToUInt16(qSubChannel, 10); + var qSubChannelForCrc = new byte[10]; + Array.Copy(qSubChannel, 0, qSubChannelForCrc, 0, 10); + ushort calculatedQcrc = CRC16CcittContext.Calculate(qSubChannelForCrc); + + if(qSubChannelCrc != calculatedQcrc) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Q_subchannel_CRC_0_expected_1, + calculatedQcrc, + qSubChannelCrc); + + status = false; + } + + if((cdTextPack1[0] & 0x80) == 0x80) + { + var cdTextPack1Crc = BigEndianBitConverter.ToUInt16(cdTextPack1, 16); + var cdTextPack1ForCrc = new byte[16]; + Array.Copy(cdTextPack1, 0, cdTextPack1ForCrc, 0, 16); + ushort calculatedCdtp1Crc = CRC16CcittContext.Calculate(cdTextPack1ForCrc); + + if(cdTextPack1Crc != calculatedCdtp1Crc && cdTextPack1Crc != 0) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.CD_Text_Pack_one_CRC_0_expected_1, + cdTextPack1Crc, + calculatedCdtp1Crc); + + status = false; + } + } + + if((cdTextPack2[0] & 0x80) == 0x80) + { + var cdTextPack2Crc = BigEndianBitConverter.ToUInt16(cdTextPack2, 16); + var cdTextPack2ForCrc = new byte[16]; + Array.Copy(cdTextPack2, 0, cdTextPack2ForCrc, 0, 16); + ushort calculatedCdtp2Crc = CRC16CcittContext.Calculate(cdTextPack2ForCrc); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Cyclic_CDTP2_0_Calc_CDTP2_1, + cdTextPack2Crc, + calculatedCdtp2Crc); + + if(cdTextPack2Crc != calculatedCdtp2Crc && cdTextPack2Crc != 0) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.CD_Text_Pack_two_CRC_0_expected_1, + cdTextPack2Crc, + calculatedCdtp2Crc); + + status = false; + } + } + + if((cdTextPack3[0] & 0x80) == 0x80) + { + var cdTextPack3Crc = BigEndianBitConverter.ToUInt16(cdTextPack3, 16); + var cdTextPack3ForCrc = new byte[16]; + Array.Copy(cdTextPack3, 0, cdTextPack3ForCrc, 0, 16); + ushort calculatedCdtp3Crc = CRC16CcittContext.Calculate(cdTextPack3ForCrc); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Cyclic_CDTP3_0_Calc_CDTP3_1, + cdTextPack3Crc, + calculatedCdtp3Crc); + + if(cdTextPack3Crc != calculatedCdtp3Crc && cdTextPack3Crc != 0) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.CD_Text_Pack_three_CRC_0_expected_1, + cdTextPack3Crc, + calculatedCdtp3Crc); + + status = false; + } + } + + if((cdTextPack4[0] & 0x80) != 0x80) return status; + + var cdTextPack4Crc = BigEndianBitConverter.ToUInt16(cdTextPack4, 16); + var cdTextPack4ForCrc = new byte[16]; + Array.Copy(cdTextPack4, 0, cdTextPack4ForCrc, 0, 16); + ushort calculatedCdtp4Crc = CRC16CcittContext.Calculate(cdTextPack4ForCrc); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Cyclic_CDTP4_0_Calc_CDTP4_1, + cdTextPack4Crc, + calculatedCdtp4Crc); + + if(cdTextPack4Crc == calculatedCdtp4Crc || cdTextPack4Crc == 0) return status; + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.CD_Text_Pack_four_CRC_0_expected_1, + cdTextPack4Crc, + calculatedCdtp4Crc); + + return false; + } +} \ No newline at end of file diff --git a/Aaru.Checksums/CRC16CCITTContext.cs b/Aaru.Checksums/CRC16CCITTContext.cs new file mode 100644 index 000000000..4762c6d7a --- /dev/null +++ b/Aaru.Checksums/CRC16CCITTContext.cs @@ -0,0 +1,266 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CRC16CCITTContext.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Implements a CRC16 algorithm with the CCITT polynomial. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Checksums; + +/// +/// Implements the CRC16 algorithm with CCITT polynomial and seed +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +public sealed class CRC16CcittContext : Crc16Context +{ + /// CCITT CRC16 polynomial + public const ushort CRC16CcittPoly = 0x8408; + /// CCITT CRC16 seed + public const ushort CRC16CcittSeed = 0x0000; + static readonly ushort[][] _ccittCrc16Table = + [ + [ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, + 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, + 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, + 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, + 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, + 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, + 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, + 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, + 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, + 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, + 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, + 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, + 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, + 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, + 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, + 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, + 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, + 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 + ], + [ + 0x0000, 0x3331, 0x6662, 0x5553, 0xCCC4, 0xFFF5, 0xAAA6, 0x9997, 0x89A9, 0xBA98, 0xEFCB, 0xDCFA, 0x456D, + 0x765C, 0x230F, 0x103E, 0x0373, 0x3042, 0x6511, 0x5620, 0xCFB7, 0xFC86, 0xA9D5, 0x9AE4, 0x8ADA, 0xB9EB, + 0xECB8, 0xDF89, 0x461E, 0x752F, 0x207C, 0x134D, 0x06E6, 0x35D7, 0x6084, 0x53B5, 0xCA22, 0xF913, 0xAC40, + 0x9F71, 0x8F4F, 0xBC7E, 0xE92D, 0xDA1C, 0x438B, 0x70BA, 0x25E9, 0x16D8, 0x0595, 0x36A4, 0x63F7, 0x50C6, + 0xC951, 0xFA60, 0xAF33, 0x9C02, 0x8C3C, 0xBF0D, 0xEA5E, 0xD96F, 0x40F8, 0x73C9, 0x269A, 0x15AB, 0x0DCC, + 0x3EFD, 0x6BAE, 0x589F, 0xC108, 0xF239, 0xA76A, 0x945B, 0x8465, 0xB754, 0xE207, 0xD136, 0x48A1, 0x7B90, + 0x2EC3, 0x1DF2, 0x0EBF, 0x3D8E, 0x68DD, 0x5BEC, 0xC27B, 0xF14A, 0xA419, 0x9728, 0x8716, 0xB427, 0xE174, + 0xD245, 0x4BD2, 0x78E3, 0x2DB0, 0x1E81, 0x0B2A, 0x381B, 0x6D48, 0x5E79, 0xC7EE, 0xF4DF, 0xA18C, 0x92BD, + 0x8283, 0xB1B2, 0xE4E1, 0xD7D0, 0x4E47, 0x7D76, 0x2825, 0x1B14, 0x0859, 0x3B68, 0x6E3B, 0x5D0A, 0xC49D, + 0xF7AC, 0xA2FF, 0x91CE, 0x81F0, 0xB2C1, 0xE792, 0xD4A3, 0x4D34, 0x7E05, 0x2B56, 0x1867, 0x1B98, 0x28A9, + 0x7DFA, 0x4ECB, 0xD75C, 0xE46D, 0xB13E, 0x820F, 0x9231, 0xA100, 0xF453, 0xC762, 0x5EF5, 0x6DC4, 0x3897, + 0x0BA6, 0x18EB, 0x2BDA, 0x7E89, 0x4DB8, 0xD42F, 0xE71E, 0xB24D, 0x817C, 0x9142, 0xA273, 0xF720, 0xC411, + 0x5D86, 0x6EB7, 0x3BE4, 0x08D5, 0x1D7E, 0x2E4F, 0x7B1C, 0x482D, 0xD1BA, 0xE28B, 0xB7D8, 0x84E9, 0x94D7, + 0xA7E6, 0xF2B5, 0xC184, 0x5813, 0x6B22, 0x3E71, 0x0D40, 0x1E0D, 0x2D3C, 0x786F, 0x4B5E, 0xD2C9, 0xE1F8, + 0xB4AB, 0x879A, 0x97A4, 0xA495, 0xF1C6, 0xC2F7, 0x5B60, 0x6851, 0x3D02, 0x0E33, 0x1654, 0x2565, 0x7036, + 0x4307, 0xDA90, 0xE9A1, 0xBCF2, 0x8FC3, 0x9FFD, 0xACCC, 0xF99F, 0xCAAE, 0x5339, 0x6008, 0x355B, 0x066A, + 0x1527, 0x2616, 0x7345, 0x4074, 0xD9E3, 0xEAD2, 0xBF81, 0x8CB0, 0x9C8E, 0xAFBF, 0xFAEC, 0xC9DD, 0x504A, + 0x637B, 0x3628, 0x0519, 0x10B2, 0x2383, 0x76D0, 0x45E1, 0xDC76, 0xEF47, 0xBA14, 0x8925, 0x991B, 0xAA2A, + 0xFF79, 0xCC48, 0x55DF, 0x66EE, 0x33BD, 0x008C, 0x13C1, 0x20F0, 0x75A3, 0x4692, 0xDF05, 0xEC34, 0xB967, + 0x8A56, 0x9A68, 0xA959, 0xFC0A, 0xCF3B, 0x56AC, 0x659D, 0x30CE, 0x03FF + ], + [ + 0x0000, 0x3730, 0x6E60, 0x5950, 0xDCC0, 0xEBF0, 0xB2A0, 0x8590, 0xA9A1, 0x9E91, 0xC7C1, 0xF0F1, 0x7561, + 0x4251, 0x1B01, 0x2C31, 0x4363, 0x7453, 0x2D03, 0x1A33, 0x9FA3, 0xA893, 0xF1C3, 0xC6F3, 0xEAC2, 0xDDF2, + 0x84A2, 0xB392, 0x3602, 0x0132, 0x5862, 0x6F52, 0x86C6, 0xB1F6, 0xE8A6, 0xDF96, 0x5A06, 0x6D36, 0x3466, + 0x0356, 0x2F67, 0x1857, 0x4107, 0x7637, 0xF3A7, 0xC497, 0x9DC7, 0xAAF7, 0xC5A5, 0xF295, 0xABC5, 0x9CF5, + 0x1965, 0x2E55, 0x7705, 0x4035, 0x6C04, 0x5B34, 0x0264, 0x3554, 0xB0C4, 0x87F4, 0xDEA4, 0xE994, 0x1DAD, + 0x2A9D, 0x73CD, 0x44FD, 0xC16D, 0xF65D, 0xAF0D, 0x983D, 0xB40C, 0x833C, 0xDA6C, 0xED5C, 0x68CC, 0x5FFC, + 0x06AC, 0x319C, 0x5ECE, 0x69FE, 0x30AE, 0x079E, 0x820E, 0xB53E, 0xEC6E, 0xDB5E, 0xF76F, 0xC05F, 0x990F, + 0xAE3F, 0x2BAF, 0x1C9F, 0x45CF, 0x72FF, 0x9B6B, 0xAC5B, 0xF50B, 0xC23B, 0x47AB, 0x709B, 0x29CB, 0x1EFB, + 0x32CA, 0x05FA, 0x5CAA, 0x6B9A, 0xEE0A, 0xD93A, 0x806A, 0xB75A, 0xD808, 0xEF38, 0xB668, 0x8158, 0x04C8, + 0x33F8, 0x6AA8, 0x5D98, 0x71A9, 0x4699, 0x1FC9, 0x28F9, 0xAD69, 0x9A59, 0xC309, 0xF439, 0x3B5A, 0x0C6A, + 0x553A, 0x620A, 0xE79A, 0xD0AA, 0x89FA, 0xBECA, 0x92FB, 0xA5CB, 0xFC9B, 0xCBAB, 0x4E3B, 0x790B, 0x205B, + 0x176B, 0x7839, 0x4F09, 0x1659, 0x2169, 0xA4F9, 0x93C9, 0xCA99, 0xFDA9, 0xD198, 0xE6A8, 0xBFF8, 0x88C8, + 0x0D58, 0x3A68, 0x6338, 0x5408, 0xBD9C, 0x8AAC, 0xD3FC, 0xE4CC, 0x615C, 0x566C, 0x0F3C, 0x380C, 0x143D, + 0x230D, 0x7A5D, 0x4D6D, 0xC8FD, 0xFFCD, 0xA69D, 0x91AD, 0xFEFF, 0xC9CF, 0x909F, 0xA7AF, 0x223F, 0x150F, + 0x4C5F, 0x7B6F, 0x575E, 0x606E, 0x393E, 0x0E0E, 0x8B9E, 0xBCAE, 0xE5FE, 0xD2CE, 0x26F7, 0x11C7, 0x4897, + 0x7FA7, 0xFA37, 0xCD07, 0x9457, 0xA367, 0x8F56, 0xB866, 0xE136, 0xD606, 0x5396, 0x64A6, 0x3DF6, 0x0AC6, + 0x6594, 0x52A4, 0x0BF4, 0x3CC4, 0xB954, 0x8E64, 0xD734, 0xE004, 0xCC35, 0xFB05, 0xA255, 0x9565, 0x10F5, + 0x27C5, 0x7E95, 0x49A5, 0xA031, 0x9701, 0xCE51, 0xF961, 0x7CF1, 0x4BC1, 0x1291, 0x25A1, 0x0990, 0x3EA0, + 0x67F0, 0x50C0, 0xD550, 0xE260, 0xBB30, 0x8C00, 0xE352, 0xD462, 0x8D32, 0xBA02, 0x3F92, 0x08A2, 0x51F2, + 0x66C2, 0x4AF3, 0x7DC3, 0x2493, 0x13A3, 0x9633, 0xA103, 0xF853, 0xCF63 + ], + [ + 0x0000, 0x76B4, 0xED68, 0x9BDC, 0xCAF1, 0xBC45, 0x2799, 0x512D, 0x85C3, 0xF377, 0x68AB, 0x1E1F, 0x4F32, + 0x3986, 0xA25A, 0xD4EE, 0x1BA7, 0x6D13, 0xF6CF, 0x807B, 0xD156, 0xA7E2, 0x3C3E, 0x4A8A, 0x9E64, 0xE8D0, + 0x730C, 0x05B8, 0x5495, 0x2221, 0xB9FD, 0xCF49, 0x374E, 0x41FA, 0xDA26, 0xAC92, 0xFDBF, 0x8B0B, 0x10D7, + 0x6663, 0xB28D, 0xC439, 0x5FE5, 0x2951, 0x787C, 0x0EC8, 0x9514, 0xE3A0, 0x2CE9, 0x5A5D, 0xC181, 0xB735, + 0xE618, 0x90AC, 0x0B70, 0x7DC4, 0xA92A, 0xDF9E, 0x4442, 0x32F6, 0x63DB, 0x156F, 0x8EB3, 0xF807, 0x6E9C, + 0x1828, 0x83F4, 0xF540, 0xA46D, 0xD2D9, 0x4905, 0x3FB1, 0xEB5F, 0x9DEB, 0x0637, 0x7083, 0x21AE, 0x571A, + 0xCCC6, 0xBA72, 0x753B, 0x038F, 0x9853, 0xEEE7, 0xBFCA, 0xC97E, 0x52A2, 0x2416, 0xF0F8, 0x864C, 0x1D90, + 0x6B24, 0x3A09, 0x4CBD, 0xD761, 0xA1D5, 0x59D2, 0x2F66, 0xB4BA, 0xC20E, 0x9323, 0xE597, 0x7E4B, 0x08FF, + 0xDC11, 0xAAA5, 0x3179, 0x47CD, 0x16E0, 0x6054, 0xFB88, 0x8D3C, 0x4275, 0x34C1, 0xAF1D, 0xD9A9, 0x8884, + 0xFE30, 0x65EC, 0x1358, 0xC7B6, 0xB102, 0x2ADE, 0x5C6A, 0x0D47, 0x7BF3, 0xE02F, 0x969B, 0xDD38, 0xAB8C, + 0x3050, 0x46E4, 0x17C9, 0x617D, 0xFAA1, 0x8C15, 0x58FB, 0x2E4F, 0xB593, 0xC327, 0x920A, 0xE4BE, 0x7F62, + 0x09D6, 0xC69F, 0xB02B, 0x2BF7, 0x5D43, 0x0C6E, 0x7ADA, 0xE106, 0x97B2, 0x435C, 0x35E8, 0xAE34, 0xD880, + 0x89AD, 0xFF19, 0x64C5, 0x1271, 0xEA76, 0x9CC2, 0x071E, 0x71AA, 0x2087, 0x5633, 0xCDEF, 0xBB5B, 0x6FB5, + 0x1901, 0x82DD, 0xF469, 0xA544, 0xD3F0, 0x482C, 0x3E98, 0xF1D1, 0x8765, 0x1CB9, 0x6A0D, 0x3B20, 0x4D94, + 0xD648, 0xA0FC, 0x7412, 0x02A6, 0x997A, 0xEFCE, 0xBEE3, 0xC857, 0x538B, 0x253F, 0xB3A4, 0xC510, 0x5ECC, + 0x2878, 0x7955, 0x0FE1, 0x943D, 0xE289, 0x3667, 0x40D3, 0xDB0F, 0xADBB, 0xFC96, 0x8A22, 0x11FE, 0x674A, + 0xA803, 0xDEB7, 0x456B, 0x33DF, 0x62F2, 0x1446, 0x8F9A, 0xF92E, 0x2DC0, 0x5B74, 0xC0A8, 0xB61C, 0xE731, + 0x9185, 0x0A59, 0x7CED, 0x84EA, 0xF25E, 0x6982, 0x1F36, 0x4E1B, 0x38AF, 0xA373, 0xD5C7, 0x0129, 0x779D, + 0xEC41, 0x9AF5, 0xCBD8, 0xBD6C, 0x26B0, 0x5004, 0x9F4D, 0xE9F9, 0x7225, 0x0491, 0x55BC, 0x2308, 0xB8D4, + 0xCE60, 0x1A8E, 0x6C3A, 0xF7E6, 0x8152, 0xD07F, 0xA6CB, 0x3D17, 0x4BA3 + ], + [ + 0x0000, 0xAA51, 0x4483, 0xEED2, 0x8906, 0x2357, 0xCD85, 0x67D4, 0x022D, 0xA87C, 0x46AE, 0xECFF, 0x8B2B, + 0x217A, 0xCFA8, 0x65F9, 0x045A, 0xAE0B, 0x40D9, 0xEA88, 0x8D5C, 0x270D, 0xC9DF, 0x638E, 0x0677, 0xAC26, + 0x42F4, 0xE8A5, 0x8F71, 0x2520, 0xCBF2, 0x61A3, 0x08B4, 0xA2E5, 0x4C37, 0xE666, 0x81B2, 0x2BE3, 0xC531, + 0x6F60, 0x0A99, 0xA0C8, 0x4E1A, 0xE44B, 0x839F, 0x29CE, 0xC71C, 0x6D4D, 0x0CEE, 0xA6BF, 0x486D, 0xE23C, + 0x85E8, 0x2FB9, 0xC16B, 0x6B3A, 0x0EC3, 0xA492, 0x4A40, 0xE011, 0x87C5, 0x2D94, 0xC346, 0x6917, 0x1168, + 0xBB39, 0x55EB, 0xFFBA, 0x986E, 0x323F, 0xDCED, 0x76BC, 0x1345, 0xB914, 0x57C6, 0xFD97, 0x9A43, 0x3012, + 0xDEC0, 0x7491, 0x1532, 0xBF63, 0x51B1, 0xFBE0, 0x9C34, 0x3665, 0xD8B7, 0x72E6, 0x171F, 0xBD4E, 0x539C, + 0xF9CD, 0x9E19, 0x3448, 0xDA9A, 0x70CB, 0x19DC, 0xB38D, 0x5D5F, 0xF70E, 0x90DA, 0x3A8B, 0xD459, 0x7E08, + 0x1BF1, 0xB1A0, 0x5F72, 0xF523, 0x92F7, 0x38A6, 0xD674, 0x7C25, 0x1D86, 0xB7D7, 0x5905, 0xF354, 0x9480, + 0x3ED1, 0xD003, 0x7A52, 0x1FAB, 0xB5FA, 0x5B28, 0xF179, 0x96AD, 0x3CFC, 0xD22E, 0x787F, 0x22D0, 0x8881, + 0x6653, 0xCC02, 0xABD6, 0x0187, 0xEF55, 0x4504, 0x20FD, 0x8AAC, 0x647E, 0xCE2F, 0xA9FB, 0x03AA, 0xED78, + 0x4729, 0x268A, 0x8CDB, 0x6209, 0xC858, 0xAF8C, 0x05DD, 0xEB0F, 0x415E, 0x24A7, 0x8EF6, 0x6024, 0xCA75, + 0xADA1, 0x07F0, 0xE922, 0x4373, 0x2A64, 0x8035, 0x6EE7, 0xC4B6, 0xA362, 0x0933, 0xE7E1, 0x4DB0, 0x2849, + 0x8218, 0x6CCA, 0xC69B, 0xA14F, 0x0B1E, 0xE5CC, 0x4F9D, 0x2E3E, 0x846F, 0x6ABD, 0xC0EC, 0xA738, 0x0D69, + 0xE3BB, 0x49EA, 0x2C13, 0x8642, 0x6890, 0xC2C1, 0xA515, 0x0F44, 0xE196, 0x4BC7, 0x33B8, 0x99E9, 0x773B, + 0xDD6A, 0xBABE, 0x10EF, 0xFE3D, 0x546C, 0x3195, 0x9BC4, 0x7516, 0xDF47, 0xB893, 0x12C2, 0xFC10, 0x5641, + 0x37E2, 0x9DB3, 0x7361, 0xD930, 0xBEE4, 0x14B5, 0xFA67, 0x5036, 0x35CF, 0x9F9E, 0x714C, 0xDB1D, 0xBCC9, + 0x1698, 0xF84A, 0x521B, 0x3B0C, 0x915D, 0x7F8F, 0xD5DE, 0xB20A, 0x185B, 0xF689, 0x5CD8, 0x3921, 0x9370, + 0x7DA2, 0xD7F3, 0xB027, 0x1A76, 0xF4A4, 0x5EF5, 0x3F56, 0x9507, 0x7BD5, 0xD184, 0xB650, 0x1C01, 0xF2D3, + 0x5882, 0x3D7B, 0x972A, 0x79F8, 0xD3A9, 0xB47D, 0x1E2C, 0xF0FE, 0x5AAF + ], + [ + 0x0000, 0x45A0, 0x8B40, 0xCEE0, 0x06A1, 0x4301, 0x8DE1, 0xC841, 0x0D42, 0x48E2, 0x8602, 0xC3A2, 0x0BE3, + 0x4E43, 0x80A3, 0xC503, 0x1A84, 0x5F24, 0x91C4, 0xD464, 0x1C25, 0x5985, 0x9765, 0xD2C5, 0x17C6, 0x5266, + 0x9C86, 0xD926, 0x1167, 0x54C7, 0x9A27, 0xDF87, 0x3508, 0x70A8, 0xBE48, 0xFBE8, 0x33A9, 0x7609, 0xB8E9, + 0xFD49, 0x384A, 0x7DEA, 0xB30A, 0xF6AA, 0x3EEB, 0x7B4B, 0xB5AB, 0xF00B, 0x2F8C, 0x6A2C, 0xA4CC, 0xE16C, + 0x292D, 0x6C8D, 0xA26D, 0xE7CD, 0x22CE, 0x676E, 0xA98E, 0xEC2E, 0x246F, 0x61CF, 0xAF2F, 0xEA8F, 0x6A10, + 0x2FB0, 0xE150, 0xA4F0, 0x6CB1, 0x2911, 0xE7F1, 0xA251, 0x6752, 0x22F2, 0xEC12, 0xA9B2, 0x61F3, 0x2453, + 0xEAB3, 0xAF13, 0x7094, 0x3534, 0xFBD4, 0xBE74, 0x7635, 0x3395, 0xFD75, 0xB8D5, 0x7DD6, 0x3876, 0xF696, + 0xB336, 0x7B77, 0x3ED7, 0xF037, 0xB597, 0x5F18, 0x1AB8, 0xD458, 0x91F8, 0x59B9, 0x1C19, 0xD2F9, 0x9759, + 0x525A, 0x17FA, 0xD91A, 0x9CBA, 0x54FB, 0x115B, 0xDFBB, 0x9A1B, 0x459C, 0x003C, 0xCEDC, 0x8B7C, 0x433D, + 0x069D, 0xC87D, 0x8DDD, 0x48DE, 0x0D7E, 0xC39E, 0x863E, 0x4E7F, 0x0BDF, 0xC53F, 0x809F, 0xD420, 0x9180, + 0x5F60, 0x1AC0, 0xD281, 0x9721, 0x59C1, 0x1C61, 0xD962, 0x9CC2, 0x5222, 0x1782, 0xDFC3, 0x9A63, 0x5483, + 0x1123, 0xCEA4, 0x8B04, 0x45E4, 0x0044, 0xC805, 0x8DA5, 0x4345, 0x06E5, 0xC3E6, 0x8646, 0x48A6, 0x0D06, + 0xC547, 0x80E7, 0x4E07, 0x0BA7, 0xE128, 0xA488, 0x6A68, 0x2FC8, 0xE789, 0xA229, 0x6CC9, 0x2969, 0xEC6A, + 0xA9CA, 0x672A, 0x228A, 0xEACB, 0xAF6B, 0x618B, 0x242B, 0xFBAC, 0xBE0C, 0x70EC, 0x354C, 0xFD0D, 0xB8AD, + 0x764D, 0x33ED, 0xF6EE, 0xB34E, 0x7DAE, 0x380E, 0xF04F, 0xB5EF, 0x7B0F, 0x3EAF, 0xBE30, 0xFB90, 0x3570, + 0x70D0, 0xB891, 0xFD31, 0x33D1, 0x7671, 0xB372, 0xF6D2, 0x3832, 0x7D92, 0xB5D3, 0xF073, 0x3E93, 0x7B33, + 0xA4B4, 0xE114, 0x2FF4, 0x6A54, 0xA215, 0xE7B5, 0x2955, 0x6CF5, 0xA9F6, 0xEC56, 0x22B6, 0x6716, 0xAF57, + 0xEAF7, 0x2417, 0x61B7, 0x8B38, 0xCE98, 0x0078, 0x45D8, 0x8D99, 0xC839, 0x06D9, 0x4379, 0x867A, 0xC3DA, + 0x0D3A, 0x489A, 0x80DB, 0xC57B, 0x0B9B, 0x4E3B, 0x91BC, 0xD41C, 0x1AFC, 0x5F5C, 0x971D, 0xD2BD, 0x1C5D, + 0x59FD, 0x9CFE, 0xD95E, 0x17BE, 0x521E, 0x9A5F, 0xDFFF, 0x111F, 0x54BF + ], + [ + 0x0000, 0xB861, 0x60E3, 0xD882, 0xC1C6, 0x79A7, 0xA125, 0x1944, 0x93AD, 0x2BCC, 0xF34E, 0x4B2F, 0x526B, + 0xEA0A, 0x3288, 0x8AE9, 0x377B, 0x8F1A, 0x5798, 0xEFF9, 0xF6BD, 0x4EDC, 0x965E, 0x2E3F, 0xA4D6, 0x1CB7, + 0xC435, 0x7C54, 0x6510, 0xDD71, 0x05F3, 0xBD92, 0x6EF6, 0xD697, 0x0E15, 0xB674, 0xAF30, 0x1751, 0xCFD3, + 0x77B2, 0xFD5B, 0x453A, 0x9DB8, 0x25D9, 0x3C9D, 0x84FC, 0x5C7E, 0xE41F, 0x598D, 0xE1EC, 0x396E, 0x810F, + 0x984B, 0x202A, 0xF8A8, 0x40C9, 0xCA20, 0x7241, 0xAAC3, 0x12A2, 0x0BE6, 0xB387, 0x6B05, 0xD364, 0xDDEC, + 0x658D, 0xBD0F, 0x056E, 0x1C2A, 0xA44B, 0x7CC9, 0xC4A8, 0x4E41, 0xF620, 0x2EA2, 0x96C3, 0x8F87, 0x37E6, + 0xEF64, 0x5705, 0xEA97, 0x52F6, 0x8A74, 0x3215, 0x2B51, 0x9330, 0x4BB2, 0xF3D3, 0x793A, 0xC15B, 0x19D9, + 0xA1B8, 0xB8FC, 0x009D, 0xD81F, 0x607E, 0xB31A, 0x0B7B, 0xD3F9, 0x6B98, 0x72DC, 0xCABD, 0x123F, 0xAA5E, + 0x20B7, 0x98D6, 0x4054, 0xF835, 0xE171, 0x5910, 0x8192, 0x39F3, 0x8461, 0x3C00, 0xE482, 0x5CE3, 0x45A7, + 0xFDC6, 0x2544, 0x9D25, 0x17CC, 0xAFAD, 0x772F, 0xCF4E, 0xD60A, 0x6E6B, 0xB6E9, 0x0E88, 0xABF9, 0x1398, + 0xCB1A, 0x737B, 0x6A3F, 0xD25E, 0x0ADC, 0xB2BD, 0x3854, 0x8035, 0x58B7, 0xE0D6, 0xF992, 0x41F3, 0x9971, + 0x2110, 0x9C82, 0x24E3, 0xFC61, 0x4400, 0x5D44, 0xE525, 0x3DA7, 0x85C6, 0x0F2F, 0xB74E, 0x6FCC, 0xD7AD, + 0xCEE9, 0x7688, 0xAE0A, 0x166B, 0xC50F, 0x7D6E, 0xA5EC, 0x1D8D, 0x04C9, 0xBCA8, 0x642A, 0xDC4B, 0x56A2, + 0xEEC3, 0x3641, 0x8E20, 0x9764, 0x2F05, 0xF787, 0x4FE6, 0xF274, 0x4A15, 0x9297, 0x2AF6, 0x33B2, 0x8BD3, + 0x5351, 0xEB30, 0x61D9, 0xD9B8, 0x013A, 0xB95B, 0xA01F, 0x187E, 0xC0FC, 0x789D, 0x7615, 0xCE74, 0x16F6, + 0xAE97, 0xB7D3, 0x0FB2, 0xD730, 0x6F51, 0xE5B8, 0x5DD9, 0x855B, 0x3D3A, 0x247E, 0x9C1F, 0x449D, 0xFCFC, + 0x416E, 0xF90F, 0x218D, 0x99EC, 0x80A8, 0x38C9, 0xE04B, 0x582A, 0xD2C3, 0x6AA2, 0xB220, 0x0A41, 0x1305, + 0xAB64, 0x73E6, 0xCB87, 0x18E3, 0xA082, 0x7800, 0xC061, 0xD925, 0x6144, 0xB9C6, 0x01A7, 0x8B4E, 0x332F, + 0xEBAD, 0x53CC, 0x4A88, 0xF2E9, 0x2A6B, 0x920A, 0x2F98, 0x97F9, 0x4F7B, 0xF71A, 0xEE5E, 0x563F, 0x8EBD, + 0x36DC, 0xBC35, 0x0454, 0xDCD6, 0x64B7, 0x7DF3, 0xC592, 0x1D10, 0xA571 + ], + [ + 0x0000, 0x47D3, 0x8FA6, 0xC875, 0x0F6D, 0x48BE, 0x80CB, 0xC718, 0x1EDA, 0x5909, 0x917C, 0xD6AF, 0x11B7, + 0x5664, 0x9E11, 0xD9C2, 0x3DB4, 0x7A67, 0xB212, 0xF5C1, 0x32D9, 0x750A, 0xBD7F, 0xFAAC, 0x236E, 0x64BD, + 0xACC8, 0xEB1B, 0x2C03, 0x6BD0, 0xA3A5, 0xE476, 0x7B68, 0x3CBB, 0xF4CE, 0xB31D, 0x7405, 0x33D6, 0xFBA3, + 0xBC70, 0x65B2, 0x2261, 0xEA14, 0xADC7, 0x6ADF, 0x2D0C, 0xE579, 0xA2AA, 0x46DC, 0x010F, 0xC97A, 0x8EA9, + 0x49B1, 0x0E62, 0xC617, 0x81C4, 0x5806, 0x1FD5, 0xD7A0, 0x9073, 0x576B, 0x10B8, 0xD8CD, 0x9F1E, 0xF6D0, + 0xB103, 0x7976, 0x3EA5, 0xF9BD, 0xBE6E, 0x761B, 0x31C8, 0xE80A, 0xAFD9, 0x67AC, 0x207F, 0xE767, 0xA0B4, + 0x68C1, 0x2F12, 0xCB64, 0x8CB7, 0x44C2, 0x0311, 0xC409, 0x83DA, 0x4BAF, 0x0C7C, 0xD5BE, 0x926D, 0x5A18, + 0x1DCB, 0xDAD3, 0x9D00, 0x5575, 0x12A6, 0x8DB8, 0xCA6B, 0x021E, 0x45CD, 0x82D5, 0xC506, 0x0D73, 0x4AA0, + 0x9362, 0xD4B1, 0x1CC4, 0x5B17, 0x9C0F, 0xDBDC, 0x13A9, 0x547A, 0xB00C, 0xF7DF, 0x3FAA, 0x7879, 0xBF61, + 0xF8B2, 0x30C7, 0x7714, 0xAED6, 0xE905, 0x2170, 0x66A3, 0xA1BB, 0xE668, 0x2E1D, 0x69CE, 0xFD81, 0xBA52, + 0x7227, 0x35F4, 0xF2EC, 0xB53F, 0x7D4A, 0x3A99, 0xE35B, 0xA488, 0x6CFD, 0x2B2E, 0xEC36, 0xABE5, 0x6390, + 0x2443, 0xC035, 0x87E6, 0x4F93, 0x0840, 0xCF58, 0x888B, 0x40FE, 0x072D, 0xDEEF, 0x993C, 0x5149, 0x169A, + 0xD182, 0x9651, 0x5E24, 0x19F7, 0x86E9, 0xC13A, 0x094F, 0x4E9C, 0x8984, 0xCE57, 0x0622, 0x41F1, 0x9833, + 0xDFE0, 0x1795, 0x5046, 0x975E, 0xD08D, 0x18F8, 0x5F2B, 0xBB5D, 0xFC8E, 0x34FB, 0x7328, 0xB430, 0xF3E3, + 0x3B96, 0x7C45, 0xA587, 0xE254, 0x2A21, 0x6DF2, 0xAAEA, 0xED39, 0x254C, 0x629F, 0x0B51, 0x4C82, 0x84F7, + 0xC324, 0x043C, 0x43EF, 0x8B9A, 0xCC49, 0x158B, 0x5258, 0x9A2D, 0xDDFE, 0x1AE6, 0x5D35, 0x9540, 0xD293, + 0x36E5, 0x7136, 0xB943, 0xFE90, 0x3988, 0x7E5B, 0xB62E, 0xF1FD, 0x283F, 0x6FEC, 0xA799, 0xE04A, 0x2752, + 0x6081, 0xA8F4, 0xEF27, 0x7039, 0x37EA, 0xFF9F, 0xB84C, 0x7F54, 0x3887, 0xF0F2, 0xB721, 0x6EE3, 0x2930, + 0xE145, 0xA696, 0x618E, 0x265D, 0xEE28, 0xA9FB, 0x4D8D, 0x0A5E, 0xC22B, 0x85F8, 0x42E0, 0x0533, 0xCD46, + 0x8A95, 0x5357, 0x1484, 0xDCF1, 0x9B22, 0x5C3A, 0x1BE9, 0xD39C, 0x944F + ] + ]; + + /// Initializes an instance of the CRC16 with CCITT polynomial and seed. + /// + public CRC16CcittContext() : base(CRC16CcittPoly, CRC16CcittSeed, _ccittCrc16Table, true) {} + + public new string Name => Localization.CRC16_CCITT_Name; + public new Guid Id => new("4C3BD0D5-24BD-4D45-BC19-A90A5AA5CC9D"); + public new string Author => Authors.NataliaPortillo; + + /// Gets the hash of a file + /// File path. + public static byte[] File(string filename) + { + File(filename, out byte[] hash); + + return hash; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) => + File(filename, out hash, CRC16CcittPoly, CRC16CcittSeed, _ccittCrc16Table, true); + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) => + Data(data, len, out hash, CRC16CcittPoly, CRC16CcittSeed, _ccittCrc16Table, true); + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); + + /// Calculates the CCITT CRC16 of the specified buffer with the specified parameters + /// Buffer + public static ushort Calculate(byte[] buffer) => + Calculate(buffer, CRC16CcittPoly, CRC16CcittSeed, _ccittCrc16Table, true); +} \ No newline at end of file diff --git a/Aaru.Checksums/CRC16Context.cs b/Aaru.Checksums/CRC16Context.cs new file mode 100644 index 000000000..f35c15ab9 --- /dev/null +++ b/Aaru.Checksums/CRC16Context.cs @@ -0,0 +1,635 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CRC16Context.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Implements a CRC16 algorithm. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; + +namespace Aaru.Checksums; + +/// +/// Implements a CRC16 algorithm +public partial class Crc16Context : IChecksum +{ + readonly ushort _finalSeed; + readonly bool _inverse; + readonly IntPtr _nativeContext; + readonly ushort[][] _table; + readonly bool _useCcitt; + readonly bool _useIbm; + readonly bool _useNative; + ushort _hashInt; + + /// Initializes the CRC16 table with a custom polynomial and seed + public Crc16Context(ushort polynomial, ushort seed, ushort[][] table, bool inverse) + { + _hashInt = seed; + _finalSeed = seed; + _inverse = inverse; + + _useNative = Native.IsSupported; + + _useCcitt = polynomial == CRC16CcittContext.CRC16CcittPoly && + seed == CRC16CcittContext.CRC16CcittSeed && + inverse; + + _useIbm = polynomial == CRC16IbmContext.CRC16IbmPoly && seed == CRC16IbmContext.CRC16IbmSeed && !inverse; + + if(_useCcitt && _useNative) + { + _nativeContext = crc16_ccitt_init(); + _useNative = _nativeContext != IntPtr.Zero; + } + else if(_useIbm && _useNative) + { + _nativeContext = crc16_init(); + _useNative = _nativeContext != IntPtr.Zero; + } + else + _useNative = false; + + if(!_useNative) _table = table ?? GenerateTable(polynomial, inverse); + } + +#region IChecksum Members + + /// + public string Name => "Adler-32"; + + /// + public Guid Id => new("D69CF1E7-4A7B-4605-9291-3A1BE4C2951F"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) + { + switch(_useNative) + { + case true when _useCcitt: + crc16_ccitt_update(_nativeContext, data, len); + + break; + case true when _useIbm: + crc16_update(_nativeContext, data, len); + + break; + default: + { + if(_inverse) + StepInverse(ref _hashInt, _table, data, len); + else + Step(ref _hashInt, _table, data, len); + + break; + } + } + } + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + ushort crc = 0; + + switch(_useNative) + { + case true when _useCcitt: + crc16_ccitt_final(_nativeContext, ref crc); + crc16_ccitt_free(_nativeContext); + + break; + case true when _useIbm: + crc16_final(_nativeContext, ref crc); + crc16_free(_nativeContext); + + break; + default: + { + if(_inverse) + crc = (ushort)~(_hashInt ^ _finalSeed); + else + crc = (ushort)(_hashInt ^ _finalSeed); + + break; + } + } + + return BigEndianBitConverter.GetBytes(crc); + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + var crc16Output = new StringBuilder(); + ushort final = 0; + + switch(_useNative) + { + case true when _useCcitt: + crc16_ccitt_final(_nativeContext, ref final); + crc16_ccitt_free(_nativeContext); + + break; + case true when _useIbm: + crc16_final(_nativeContext, ref final); + crc16_free(_nativeContext); + + break; + default: + { + if(_inverse) + final = (ushort)~(_hashInt ^ _finalSeed); + else + final = (ushort)(_hashInt ^ _finalSeed); + + break; + } + } + + byte[] finalBytes = BigEndianBitConverter.GetBytes(final); + + foreach(byte t in finalBytes) crc16Output.Append(t.ToString("x2")); + + return crc16Output.ToString(); + } + +#endregion + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial IntPtr crc16_init(); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int crc16_update(IntPtr ctx, byte[] data, uint len); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int crc16_final(IntPtr ctx, ref ushort crc); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial void crc16_free(IntPtr ctx); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial IntPtr crc16_ccitt_init(); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int crc16_ccitt_update(IntPtr ctx, byte[] data, uint len); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int crc16_ccitt_final(IntPtr ctx, ref ushort crc); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial void crc16_ccitt_free(IntPtr ctx); + + static void Step(ref ushort previousCrc, ushort[][] table, byte[] data, uint len) + { + // Unroll according to Intel slicing by uint8_t + // http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf + // http://sourceforge.net/projects/slicing-by-8/ + + var currentPos = 0; + const int unroll = 4; + const int bytesAtOnce = 8 * unroll; + + ushort crc = previousCrc; + + while(len >= bytesAtOnce) + { + int unrolling; + + for(unrolling = 0; unrolling < unroll; unrolling++) + { + // TODO: What trick is Microsoft doing here that's faster than arithmetic conversion + uint one = BitConverter.ToUInt32(data, currentPos) ^ crc; + currentPos += 4; + var two = BitConverter.ToUInt32(data, currentPos); + currentPos += 4; + + crc = (ushort)(table[0][two >> 24 & 0xFF] ^ + table[1][two >> 16 & 0xFF] ^ + table[2][two >> 8 & 0xFF] ^ + table[3][two & 0xFF] ^ + table[4][one >> 24 & 0xFF] ^ + table[5][one >> 16 & 0xFF] ^ + table[6][one >> 8 & 0xFF] ^ + table[7][one & 0xFF]); + } + + len -= bytesAtOnce; + } + + while(len-- != 0) crc = (ushort)(crc >> 8 ^ table[0][crc & 0xFF ^ data[currentPos++]]); + + previousCrc = crc; + } + + static void StepInverse(ref ushort previousCrc, ushort[][] table, byte[] data, uint len) + { + // Unroll according to Intel slicing by uint8_t + // http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf + // http://sourceforge.net/projects/slicing-by-8/ + + var currentPos = 0; + const int unroll = 4; + const int bytesAtOnce = 8 * unroll; + + ushort crc = previousCrc; + + while(len >= bytesAtOnce) + { + int unrolling; + + for(unrolling = 0; unrolling < unroll; unrolling++) + { + crc = (ushort)(table[7][data[currentPos + 0] ^ crc >> 8] ^ + table[6][data[currentPos + 1] ^ crc & 0xFF] ^ + table[5][data[currentPos + 2]] ^ + table[4][data[currentPos + 3]] ^ + table[3][data[currentPos + 4]] ^ + table[2][data[currentPos + 5]] ^ + table[1][data[currentPos + 6]] ^ + table[0][data[currentPos + 7]]); + + currentPos += 8; + } + + len -= bytesAtOnce; + } + + while(len-- != 0) crc = (ushort)(crc << 8 ^ table[0][crc >> 8 ^ data[currentPos++]]); + + previousCrc = crc; + } + + static ushort[][] GenerateTable(ushort polynomial, bool inverseTable) + { + var table = new ushort[8][]; + + for(var i = 0; i < 8; i++) table[i] = new ushort[256]; + + if(!inverseTable) + { + for(uint i = 0; i < 256; i++) + { + uint entry = i; + + for(var j = 0; j < 8; j++) + { + if((entry & 1) == 1) + entry = entry >> 1 ^ polynomial; + else + entry >>= 1; + } + + table[0][i] = (ushort)entry; + } + } + else + { + for(uint i = 0; i < 256; i++) + { + uint entry = i << 8; + + for(uint j = 0; j < 8; j++) + { + if((entry & 0x8000) > 0) + entry = entry << 1 ^ polynomial; + else + entry <<= 1; + + table[0][i] = (ushort)entry; + } + } + } + + for(var slice = 1; slice < 8; slice++) + { + for(var i = 0; i < 256; i++) + { + if(inverseTable) + table[slice][i] = (ushort)(table[slice - 1][i] << 8 ^ table[0][table[slice - 1][i] >> 8]); + else + table[slice][i] = (ushort)(table[slice - 1][i] >> 8 ^ table[0][table[slice - 1][i] & 0xFF]); + } + } + + return table; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + /// CRC polynomial + /// CRC seed + /// CRC lookup table + /// Is CRC inverted? + public static string File(string filename, out byte[] hash, ushort polynomial, ushort seed, ushort[][] table, + bool inverse) + { + bool useNative = Native.IsSupported; + + bool useCcitt = polynomial == CRC16CcittContext.CRC16CcittPoly && + seed == CRC16CcittContext.CRC16CcittSeed && + inverse; + + bool useIbm = polynomial == CRC16IbmContext.CRC16IbmPoly && seed == CRC16IbmContext.CRC16IbmSeed && !inverse; + + IntPtr nativeContext = IntPtr.Zero; + + var fileStream = new FileStream(filename, FileMode.Open); + + ushort localHashInt = seed; + + switch(useNative) + { + case true when useCcitt: + nativeContext = crc16_ccitt_init(); + useNative = nativeContext != IntPtr.Zero; + + break; + case true when useIbm: + nativeContext = crc16_init(); + useNative = nativeContext != IntPtr.Zero; + + break; + } + + ushort[][] localTable = table ?? GenerateTable(polynomial, inverse); + + var buffer = new byte[65536]; + int read = fileStream.EnsureRead(buffer, 0, 65536); + + while(read > 0) + { + switch(useNative) + { + case true when useCcitt: + crc16_ccitt_update(nativeContext, buffer, (uint)read); + + break; + case true when useIbm: + crc16_update(nativeContext, buffer, (uint)read); + + break; + default: + { + if(inverse) + StepInverse(ref localHashInt, localTable, buffer, (uint)read); + else + Step(ref localHashInt, localTable, buffer, (uint)read); + + break; + } + } + + read = fileStream.EnsureRead(buffer, 0, 65536); + } + + localHashInt ^= seed; + + switch(useNative) + { + case true when useCcitt: + crc16_ccitt_final(nativeContext, ref localHashInt); + crc16_ccitt_free(nativeContext); + + break; + case true when useIbm: + crc16_final(nativeContext, ref localHashInt); + crc16_free(nativeContext); + + break; + default: + { + if(inverse) localHashInt = (ushort)~localHashInt; + + break; + } + } + + hash = BigEndianBitConverter.GetBytes(localHashInt); + + var crc16Output = new StringBuilder(); + + foreach(byte h in hash) crc16Output.Append(h.ToString("x2")); + + fileStream.Close(); + + return crc16Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + /// CRC polynomial + /// CRC seed + /// CRC lookup table + /// Is CRC inverted? + public static string Data(byte[] data, uint len, out byte[] hash, ushort polynomial, ushort seed, ushort[][] table, + bool inverse) + { + bool useNative = Native.IsSupported; + + bool useCcitt = polynomial == CRC16CcittContext.CRC16CcittPoly && + seed == CRC16CcittContext.CRC16CcittSeed && + inverse; + + bool useIbm = polynomial == CRC16IbmContext.CRC16IbmPoly && seed == CRC16IbmContext.CRC16IbmSeed && !inverse; + + IntPtr nativeContext = IntPtr.Zero; + + ushort localHashInt = seed; + + switch(useNative) + { + case true when useCcitt: + nativeContext = crc16_ccitt_init(); + useNative = nativeContext != IntPtr.Zero; + + break; + case true when useIbm: + nativeContext = crc16_init(); + useNative = nativeContext != IntPtr.Zero; + + break; + } + + ushort[][] localTable = table ?? GenerateTable(polynomial, inverse); + + switch(useNative) + { + case true when useCcitt: + crc16_ccitt_update(nativeContext, data, len); + + break; + case true when useIbm: + crc16_update(nativeContext, data, len); + + break; + default: + { + if(inverse) + StepInverse(ref localHashInt, localTable, data, len); + else + Step(ref localHashInt, localTable, data, len); + + break; + } + } + + localHashInt ^= seed; + + switch(useNative) + { + case true when useCcitt: + crc16_ccitt_final(nativeContext, ref localHashInt); + crc16_ccitt_free(nativeContext); + + break; + case true when useIbm: + crc16_final(nativeContext, ref localHashInt); + crc16_free(nativeContext); + + break; + default: + { + if(inverse) localHashInt = (ushort)~localHashInt; + + break; + } + } + + hash = BigEndianBitConverter.GetBytes(localHashInt); + + var crc16Output = new StringBuilder(); + + foreach(byte h in hash) crc16Output.Append(h.ToString("x2")); + + return crc16Output.ToString(); + } + + /// Calculates the CRC16 of the specified buffer with the specified parameters + /// Buffer + /// Polynomial + /// Seed + /// Pre-generated lookup table + /// Inverse CRC + /// CRC16 + public static ushort Calculate(byte[] buffer, ushort polynomial, ushort seed, ushort[][] table, bool inverse) + { + bool useNative = Native.IsSupported; + + bool useCcitt = polynomial == CRC16CcittContext.CRC16CcittPoly && + seed == CRC16CcittContext.CRC16CcittSeed && + inverse; + + bool useIbm = polynomial == CRC16IbmContext.CRC16IbmPoly && seed == CRC16IbmContext.CRC16IbmSeed && !inverse; + + IntPtr nativeContext = IntPtr.Zero; + + ushort localHashInt = seed; + + switch(useNative) + { + case true when useCcitt: + nativeContext = crc16_ccitt_init(); + useNative = nativeContext != IntPtr.Zero; + + break; + case true when useIbm: + nativeContext = crc16_init(); + useNative = nativeContext != IntPtr.Zero; + + break; + } + + ushort[][] localTable = table ?? GenerateTable(polynomial, inverse); + + switch(useNative) + { + case true when useCcitt: + crc16_ccitt_update(nativeContext, buffer, (uint)buffer.Length); + + break; + case true when useIbm: + crc16_update(nativeContext, buffer, (uint)buffer.Length); + + break; + default: + { + if(inverse) + StepInverse(ref localHashInt, localTable, buffer, (uint)buffer.Length); + else + Step(ref localHashInt, localTable, buffer, (uint)buffer.Length); + + break; + } + } + + localHashInt ^= seed; + + switch(useNative) + { + case true when useCcitt: + crc16_ccitt_final(nativeContext, ref localHashInt); + crc16_ccitt_free(nativeContext); + + break; + case true when useIbm: + crc16_final(nativeContext, ref localHashInt); + crc16_free(nativeContext); + + break; + default: + { + if(inverse) localHashInt = (ushort)~localHashInt; + + break; + } + } + + return localHashInt; + } +} \ No newline at end of file diff --git a/Aaru.Checksums/CRC16IBMContext.cs b/Aaru.Checksums/CRC16IBMContext.cs new file mode 100644 index 000000000..1070befb0 --- /dev/null +++ b/Aaru.Checksums/CRC16IBMContext.cs @@ -0,0 +1,264 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CRC16IBMContext.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Implements a CRC16 algorithm with the IBM polynomial. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Checksums; + +/// +/// Implements the CRC16 algorithm with IBM polynomial and seed +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +public sealed class CRC16IbmContext : Crc16Context +{ + internal const ushort CRC16IbmPoly = 0xA001; + internal const ushort CRC16IbmSeed = 0x0000; + + static readonly ushort[][] _ibmCrc16Table = + [ + [ + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, + 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, + 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, + 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, + 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, + 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, + 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, + 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, + 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, + 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, + 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, + 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, + 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, + 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, + 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, + 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, + 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, + 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 + ], + [ + 0x0000, 0x9001, 0x6001, 0xF000, 0xC002, 0x5003, 0xA003, 0x3002, 0xC007, 0x5006, 0xA006, 0x3007, 0x0005, + 0x9004, 0x6004, 0xF005, 0xC00D, 0x500C, 0xA00C, 0x300D, 0x000F, 0x900E, 0x600E, 0xF00F, 0x000A, 0x900B, + 0x600B, 0xF00A, 0xC008, 0x5009, 0xA009, 0x3008, 0xC019, 0x5018, 0xA018, 0x3019, 0x001B, 0x901A, 0x601A, + 0xF01B, 0x001E, 0x901F, 0x601F, 0xF01E, 0xC01C, 0x501D, 0xA01D, 0x301C, 0x0014, 0x9015, 0x6015, 0xF014, + 0xC016, 0x5017, 0xA017, 0x3016, 0xC013, 0x5012, 0xA012, 0x3013, 0x0011, 0x9010, 0x6010, 0xF011, 0xC031, + 0x5030, 0xA030, 0x3031, 0x0033, 0x9032, 0x6032, 0xF033, 0x0036, 0x9037, 0x6037, 0xF036, 0xC034, 0x5035, + 0xA035, 0x3034, 0x003C, 0x903D, 0x603D, 0xF03C, 0xC03E, 0x503F, 0xA03F, 0x303E, 0xC03B, 0x503A, 0xA03A, + 0x303B, 0x0039, 0x9038, 0x6038, 0xF039, 0x0028, 0x9029, 0x6029, 0xF028, 0xC02A, 0x502B, 0xA02B, 0x302A, + 0xC02F, 0x502E, 0xA02E, 0x302F, 0x002D, 0x902C, 0x602C, 0xF02D, 0xC025, 0x5024, 0xA024, 0x3025, 0x0027, + 0x9026, 0x6026, 0xF027, 0x0022, 0x9023, 0x6023, 0xF022, 0xC020, 0x5021, 0xA021, 0x3020, 0xC061, 0x5060, + 0xA060, 0x3061, 0x0063, 0x9062, 0x6062, 0xF063, 0x0066, 0x9067, 0x6067, 0xF066, 0xC064, 0x5065, 0xA065, + 0x3064, 0x006C, 0x906D, 0x606D, 0xF06C, 0xC06E, 0x506F, 0xA06F, 0x306E, 0xC06B, 0x506A, 0xA06A, 0x306B, + 0x0069, 0x9068, 0x6068, 0xF069, 0x0078, 0x9079, 0x6079, 0xF078, 0xC07A, 0x507B, 0xA07B, 0x307A, 0xC07F, + 0x507E, 0xA07E, 0x307F, 0x007D, 0x907C, 0x607C, 0xF07D, 0xC075, 0x5074, 0xA074, 0x3075, 0x0077, 0x9076, + 0x6076, 0xF077, 0x0072, 0x9073, 0x6073, 0xF072, 0xC070, 0x5071, 0xA071, 0x3070, 0x0050, 0x9051, 0x6051, + 0xF050, 0xC052, 0x5053, 0xA053, 0x3052, 0xC057, 0x5056, 0xA056, 0x3057, 0x0055, 0x9054, 0x6054, 0xF055, + 0xC05D, 0x505C, 0xA05C, 0x305D, 0x005F, 0x905E, 0x605E, 0xF05F, 0x005A, 0x905B, 0x605B, 0xF05A, 0xC058, + 0x5059, 0xA059, 0x3058, 0xC049, 0x5048, 0xA048, 0x3049, 0x004B, 0x904A, 0x604A, 0xF04B, 0x004E, 0x904F, + 0x604F, 0xF04E, 0xC04C, 0x504D, 0xA04D, 0x304C, 0x0044, 0x9045, 0x6045, 0xF044, 0xC046, 0x5047, 0xA047, + 0x3046, 0xC043, 0x5042, 0xA042, 0x3043, 0x0041, 0x9040, 0x6040, 0xF041 + ], + [ + 0x0000, 0xC051, 0xC0A1, 0x00F0, 0xC141, 0x0110, 0x01E0, 0xC1B1, 0xC281, 0x02D0, 0x0220, 0xC271, 0x03C0, + 0xC391, 0xC361, 0x0330, 0xC501, 0x0550, 0x05A0, 0xC5F1, 0x0440, 0xC411, 0xC4E1, 0x04B0, 0x0780, 0xC7D1, + 0xC721, 0x0770, 0xC6C1, 0x0690, 0x0660, 0xC631, 0xCA01, 0x0A50, 0x0AA0, 0xCAF1, 0x0B40, 0xCB11, 0xCBE1, + 0x0BB0, 0x0880, 0xC8D1, 0xC821, 0x0870, 0xC9C1, 0x0990, 0x0960, 0xC931, 0x0F00, 0xCF51, 0xCFA1, 0x0FF0, + 0xCE41, 0x0E10, 0x0EE0, 0xCEB1, 0xCD81, 0x0DD0, 0x0D20, 0xCD71, 0x0CC0, 0xCC91, 0xCC61, 0x0C30, 0xD401, + 0x1450, 0x14A0, 0xD4F1, 0x1540, 0xD511, 0xD5E1, 0x15B0, 0x1680, 0xD6D1, 0xD621, 0x1670, 0xD7C1, 0x1790, + 0x1760, 0xD731, 0x1100, 0xD151, 0xD1A1, 0x11F0, 0xD041, 0x1010, 0x10E0, 0xD0B1, 0xD381, 0x13D0, 0x1320, + 0xD371, 0x12C0, 0xD291, 0xD261, 0x1230, 0x1E00, 0xDE51, 0xDEA1, 0x1EF0, 0xDF41, 0x1F10, 0x1FE0, 0xDFB1, + 0xDC81, 0x1CD0, 0x1C20, 0xDC71, 0x1DC0, 0xDD91, 0xDD61, 0x1D30, 0xDB01, 0x1B50, 0x1BA0, 0xDBF1, 0x1A40, + 0xDA11, 0xDAE1, 0x1AB0, 0x1980, 0xD9D1, 0xD921, 0x1970, 0xD8C1, 0x1890, 0x1860, 0xD831, 0xE801, 0x2850, + 0x28A0, 0xE8F1, 0x2940, 0xE911, 0xE9E1, 0x29B0, 0x2A80, 0xEAD1, 0xEA21, 0x2A70, 0xEBC1, 0x2B90, 0x2B60, + 0xEB31, 0x2D00, 0xED51, 0xEDA1, 0x2DF0, 0xEC41, 0x2C10, 0x2CE0, 0xECB1, 0xEF81, 0x2FD0, 0x2F20, 0xEF71, + 0x2EC0, 0xEE91, 0xEE61, 0x2E30, 0x2200, 0xE251, 0xE2A1, 0x22F0, 0xE341, 0x2310, 0x23E0, 0xE3B1, 0xE081, + 0x20D0, 0x2020, 0xE071, 0x21C0, 0xE191, 0xE161, 0x2130, 0xE701, 0x2750, 0x27A0, 0xE7F1, 0x2640, 0xE611, + 0xE6E1, 0x26B0, 0x2580, 0xE5D1, 0xE521, 0x2570, 0xE4C1, 0x2490, 0x2460, 0xE431, 0x3C00, 0xFC51, 0xFCA1, + 0x3CF0, 0xFD41, 0x3D10, 0x3DE0, 0xFDB1, 0xFE81, 0x3ED0, 0x3E20, 0xFE71, 0x3FC0, 0xFF91, 0xFF61, 0x3F30, + 0xF901, 0x3950, 0x39A0, 0xF9F1, 0x3840, 0xF811, 0xF8E1, 0x38B0, 0x3B80, 0xFBD1, 0xFB21, 0x3B70, 0xFAC1, + 0x3A90, 0x3A60, 0xFA31, 0xF601, 0x3650, 0x36A0, 0xF6F1, 0x3740, 0xF711, 0xF7E1, 0x37B0, 0x3480, 0xF4D1, + 0xF421, 0x3470, 0xF5C1, 0x3590, 0x3560, 0xF531, 0x3300, 0xF351, 0xF3A1, 0x33F0, 0xF241, 0x3210, 0x32E0, + 0xF2B1, 0xF181, 0x31D0, 0x3120, 0xF171, 0x30C0, 0xF091, 0xF061, 0x3030 + ], + [ + 0x0000, 0xFC01, 0xB801, 0x4400, 0x3001, 0xCC00, 0x8800, 0x7401, 0x6002, 0x9C03, 0xD803, 0x2402, 0x5003, + 0xAC02, 0xE802, 0x1403, 0xC004, 0x3C05, 0x7805, 0x8404, 0xF005, 0x0C04, 0x4804, 0xB405, 0xA006, 0x5C07, + 0x1807, 0xE406, 0x9007, 0x6C06, 0x2806, 0xD407, 0xC00B, 0x3C0A, 0x780A, 0x840B, 0xF00A, 0x0C0B, 0x480B, + 0xB40A, 0xA009, 0x5C08, 0x1808, 0xE409, 0x9008, 0x6C09, 0x2809, 0xD408, 0x000F, 0xFC0E, 0xB80E, 0x440F, + 0x300E, 0xCC0F, 0x880F, 0x740E, 0x600D, 0x9C0C, 0xD80C, 0x240D, 0x500C, 0xAC0D, 0xE80D, 0x140C, 0xC015, + 0x3C14, 0x7814, 0x8415, 0xF014, 0x0C15, 0x4815, 0xB414, 0xA017, 0x5C16, 0x1816, 0xE417, 0x9016, 0x6C17, + 0x2817, 0xD416, 0x0011, 0xFC10, 0xB810, 0x4411, 0x3010, 0xCC11, 0x8811, 0x7410, 0x6013, 0x9C12, 0xD812, + 0x2413, 0x5012, 0xAC13, 0xE813, 0x1412, 0x001E, 0xFC1F, 0xB81F, 0x441E, 0x301F, 0xCC1E, 0x881E, 0x741F, + 0x601C, 0x9C1D, 0xD81D, 0x241C, 0x501D, 0xAC1C, 0xE81C, 0x141D, 0xC01A, 0x3C1B, 0x781B, 0x841A, 0xF01B, + 0x0C1A, 0x481A, 0xB41B, 0xA018, 0x5C19, 0x1819, 0xE418, 0x9019, 0x6C18, 0x2818, 0xD419, 0xC029, 0x3C28, + 0x7828, 0x8429, 0xF028, 0x0C29, 0x4829, 0xB428, 0xA02B, 0x5C2A, 0x182A, 0xE42B, 0x902A, 0x6C2B, 0x282B, + 0xD42A, 0x002D, 0xFC2C, 0xB82C, 0x442D, 0x302C, 0xCC2D, 0x882D, 0x742C, 0x602F, 0x9C2E, 0xD82E, 0x242F, + 0x502E, 0xAC2F, 0xE82F, 0x142E, 0x0022, 0xFC23, 0xB823, 0x4422, 0x3023, 0xCC22, 0x8822, 0x7423, 0x6020, + 0x9C21, 0xD821, 0x2420, 0x5021, 0xAC20, 0xE820, 0x1421, 0xC026, 0x3C27, 0x7827, 0x8426, 0xF027, 0x0C26, + 0x4826, 0xB427, 0xA024, 0x5C25, 0x1825, 0xE424, 0x9025, 0x6C24, 0x2824, 0xD425, 0x003C, 0xFC3D, 0xB83D, + 0x443C, 0x303D, 0xCC3C, 0x883C, 0x743D, 0x603E, 0x9C3F, 0xD83F, 0x243E, 0x503F, 0xAC3E, 0xE83E, 0x143F, + 0xC038, 0x3C39, 0x7839, 0x8438, 0xF039, 0x0C38, 0x4838, 0xB439, 0xA03A, 0x5C3B, 0x183B, 0xE43A, 0x903B, + 0x6C3A, 0x283A, 0xD43B, 0xC037, 0x3C36, 0x7836, 0x8437, 0xF036, 0x0C37, 0x4837, 0xB436, 0xA035, 0x5C34, + 0x1834, 0xE435, 0x9034, 0x6C35, 0x2835, 0xD434, 0x0033, 0xFC32, 0xB832, 0x4433, 0x3032, 0xCC33, 0x8833, + 0x7432, 0x6031, 0x9C30, 0xD830, 0x2431, 0x5030, 0xAC31, 0xE831, 0x1430 + ], + [ + 0x0000, 0xC03D, 0xC079, 0x0044, 0xC0F1, 0x00CC, 0x0088, 0xC0B5, 0xC1E1, 0x01DC, 0x0198, 0xC1A5, 0x0110, + 0xC12D, 0xC169, 0x0154, 0xC3C1, 0x03FC, 0x03B8, 0xC385, 0x0330, 0xC30D, 0xC349, 0x0374, 0x0220, 0xC21D, + 0xC259, 0x0264, 0xC2D1, 0x02EC, 0x02A8, 0xC295, 0xC781, 0x07BC, 0x07F8, 0xC7C5, 0x0770, 0xC74D, 0xC709, + 0x0734, 0x0660, 0xC65D, 0xC619, 0x0624, 0xC691, 0x06AC, 0x06E8, 0xC6D5, 0x0440, 0xC47D, 0xC439, 0x0404, + 0xC4B1, 0x048C, 0x04C8, 0xC4F5, 0xC5A1, 0x059C, 0x05D8, 0xC5E5, 0x0550, 0xC56D, 0xC529, 0x0514, 0xCF01, + 0x0F3C, 0x0F78, 0xCF45, 0x0FF0, 0xCFCD, 0xCF89, 0x0FB4, 0x0EE0, 0xCEDD, 0xCE99, 0x0EA4, 0xCE11, 0x0E2C, + 0x0E68, 0xCE55, 0x0CC0, 0xCCFD, 0xCCB9, 0x0C84, 0xCC31, 0x0C0C, 0x0C48, 0xCC75, 0xCD21, 0x0D1C, 0x0D58, + 0xCD65, 0x0DD0, 0xCDED, 0xCDA9, 0x0D94, 0x0880, 0xC8BD, 0xC8F9, 0x08C4, 0xC871, 0x084C, 0x0808, 0xC835, + 0xC961, 0x095C, 0x0918, 0xC925, 0x0990, 0xC9AD, 0xC9E9, 0x09D4, 0xCB41, 0x0B7C, 0x0B38, 0xCB05, 0x0BB0, + 0xCB8D, 0xCBC9, 0x0BF4, 0x0AA0, 0xCA9D, 0xCAD9, 0x0AE4, 0xCA51, 0x0A6C, 0x0A28, 0xCA15, 0xDE01, 0x1E3C, + 0x1E78, 0xDE45, 0x1EF0, 0xDECD, 0xDE89, 0x1EB4, 0x1FE0, 0xDFDD, 0xDF99, 0x1FA4, 0xDF11, 0x1F2C, 0x1F68, + 0xDF55, 0x1DC0, 0xDDFD, 0xDDB9, 0x1D84, 0xDD31, 0x1D0C, 0x1D48, 0xDD75, 0xDC21, 0x1C1C, 0x1C58, 0xDC65, + 0x1CD0, 0xDCED, 0xDCA9, 0x1C94, 0x1980, 0xD9BD, 0xD9F9, 0x19C4, 0xD971, 0x194C, 0x1908, 0xD935, 0xD861, + 0x185C, 0x1818, 0xD825, 0x1890, 0xD8AD, 0xD8E9, 0x18D4, 0xDA41, 0x1A7C, 0x1A38, 0xDA05, 0x1AB0, 0xDA8D, + 0xDAC9, 0x1AF4, 0x1BA0, 0xDB9D, 0xDBD9, 0x1BE4, 0xDB51, 0x1B6C, 0x1B28, 0xDB15, 0x1100, 0xD13D, 0xD179, + 0x1144, 0xD1F1, 0x11CC, 0x1188, 0xD1B5, 0xD0E1, 0x10DC, 0x1098, 0xD0A5, 0x1010, 0xD02D, 0xD069, 0x1054, + 0xD2C1, 0x12FC, 0x12B8, 0xD285, 0x1230, 0xD20D, 0xD249, 0x1274, 0x1320, 0xD31D, 0xD359, 0x1364, 0xD3D1, + 0x13EC, 0x13A8, 0xD395, 0xD681, 0x16BC, 0x16F8, 0xD6C5, 0x1670, 0xD64D, 0xD609, 0x1634, 0x1760, 0xD75D, + 0xD719, 0x1724, 0xD791, 0x17AC, 0x17E8, 0xD7D5, 0x1540, 0xD57D, 0xD539, 0x1504, 0xD5B1, 0x158C, 0x15C8, + 0xD5F5, 0xD4A1, 0x149C, 0x14D8, 0xD4E5, 0x1450, 0xD46D, 0xD429, 0x1414 + ], + [ + 0x0000, 0xD101, 0xE201, 0x3300, 0x8401, 0x5500, 0x6600, 0xB701, 0x4801, 0x9900, 0xAA00, 0x7B01, 0xCC00, + 0x1D01, 0x2E01, 0xFF00, 0x9002, 0x4103, 0x7203, 0xA302, 0x1403, 0xC502, 0xF602, 0x2703, 0xD803, 0x0902, + 0x3A02, 0xEB03, 0x5C02, 0x8D03, 0xBE03, 0x6F02, 0x6007, 0xB106, 0x8206, 0x5307, 0xE406, 0x3507, 0x0607, + 0xD706, 0x2806, 0xF907, 0xCA07, 0x1B06, 0xAC07, 0x7D06, 0x4E06, 0x9F07, 0xF005, 0x2104, 0x1204, 0xC305, + 0x7404, 0xA505, 0x9605, 0x4704, 0xB804, 0x6905, 0x5A05, 0x8B04, 0x3C05, 0xED04, 0xDE04, 0x0F05, 0xC00E, + 0x110F, 0x220F, 0xF30E, 0x440F, 0x950E, 0xA60E, 0x770F, 0x880F, 0x590E, 0x6A0E, 0xBB0F, 0x0C0E, 0xDD0F, + 0xEE0F, 0x3F0E, 0x500C, 0x810D, 0xB20D, 0x630C, 0xD40D, 0x050C, 0x360C, 0xE70D, 0x180D, 0xC90C, 0xFA0C, + 0x2B0D, 0x9C0C, 0x4D0D, 0x7E0D, 0xAF0C, 0xA009, 0x7108, 0x4208, 0x9309, 0x2408, 0xF509, 0xC609, 0x1708, + 0xE808, 0x3909, 0x0A09, 0xDB08, 0x6C09, 0xBD08, 0x8E08, 0x5F09, 0x300B, 0xE10A, 0xD20A, 0x030B, 0xB40A, + 0x650B, 0x560B, 0x870A, 0x780A, 0xA90B, 0x9A0B, 0x4B0A, 0xFC0B, 0x2D0A, 0x1E0A, 0xCF0B, 0xC01F, 0x111E, + 0x221E, 0xF31F, 0x441E, 0x951F, 0xA61F, 0x771E, 0x881E, 0x591F, 0x6A1F, 0xBB1E, 0x0C1F, 0xDD1E, 0xEE1E, + 0x3F1F, 0x501D, 0x811C, 0xB21C, 0x631D, 0xD41C, 0x051D, 0x361D, 0xE71C, 0x181C, 0xC91D, 0xFA1D, 0x2B1C, + 0x9C1D, 0x4D1C, 0x7E1C, 0xAF1D, 0xA018, 0x7119, 0x4219, 0x9318, 0x2419, 0xF518, 0xC618, 0x1719, 0xE819, + 0x3918, 0x0A18, 0xDB19, 0x6C18, 0xBD19, 0x8E19, 0x5F18, 0x301A, 0xE11B, 0xD21B, 0x031A, 0xB41B, 0x651A, + 0x561A, 0x871B, 0x781B, 0xA91A, 0x9A1A, 0x4B1B, 0xFC1A, 0x2D1B, 0x1E1B, 0xCF1A, 0x0011, 0xD110, 0xE210, + 0x3311, 0x8410, 0x5511, 0x6611, 0xB710, 0x4810, 0x9911, 0xAA11, 0x7B10, 0xCC11, 0x1D10, 0x2E10, 0xFF11, + 0x9013, 0x4112, 0x7212, 0xA313, 0x1412, 0xC513, 0xF613, 0x2712, 0xD812, 0x0913, 0x3A13, 0xEB12, 0x5C13, + 0x8D12, 0xBE12, 0x6F13, 0x6016, 0xB117, 0x8217, 0x5316, 0xE417, 0x3516, 0x0616, 0xD717, 0x2817, 0xF916, + 0xCA16, 0x1B17, 0xAC16, 0x7D17, 0x4E17, 0x9F16, 0xF014, 0x2115, 0x1215, 0xC314, 0x7415, 0xA514, 0x9614, + 0x4715, 0xB815, 0x6914, 0x5A14, 0x8B15, 0x3C14, 0xED15, 0xDE15, 0x0F14 + ], + [ + 0x0000, 0xC010, 0xC023, 0x0033, 0xC045, 0x0055, 0x0066, 0xC076, 0xC089, 0x0099, 0x00AA, 0xC0BA, 0x00CC, + 0xC0DC, 0xC0EF, 0x00FF, 0xC111, 0x0101, 0x0132, 0xC122, 0x0154, 0xC144, 0xC177, 0x0167, 0x0198, 0xC188, + 0xC1BB, 0x01AB, 0xC1DD, 0x01CD, 0x01FE, 0xC1EE, 0xC221, 0x0231, 0x0202, 0xC212, 0x0264, 0xC274, 0xC247, + 0x0257, 0x02A8, 0xC2B8, 0xC28B, 0x029B, 0xC2ED, 0x02FD, 0x02CE, 0xC2DE, 0x0330, 0xC320, 0xC313, 0x0303, + 0xC375, 0x0365, 0x0356, 0xC346, 0xC3B9, 0x03A9, 0x039A, 0xC38A, 0x03FC, 0xC3EC, 0xC3DF, 0x03CF, 0xC441, + 0x0451, 0x0462, 0xC472, 0x0404, 0xC414, 0xC427, 0x0437, 0x04C8, 0xC4D8, 0xC4EB, 0x04FB, 0xC48D, 0x049D, + 0x04AE, 0xC4BE, 0x0550, 0xC540, 0xC573, 0x0563, 0xC515, 0x0505, 0x0536, 0xC526, 0xC5D9, 0x05C9, 0x05FA, + 0xC5EA, 0x059C, 0xC58C, 0xC5BF, 0x05AF, 0x0660, 0xC670, 0xC643, 0x0653, 0xC625, 0x0635, 0x0606, 0xC616, + 0xC6E9, 0x06F9, 0x06CA, 0xC6DA, 0x06AC, 0xC6BC, 0xC68F, 0x069F, 0xC771, 0x0761, 0x0752, 0xC742, 0x0734, + 0xC724, 0xC717, 0x0707, 0x07F8, 0xC7E8, 0xC7DB, 0x07CB, 0xC7BD, 0x07AD, 0x079E, 0xC78E, 0xC881, 0x0891, + 0x08A2, 0xC8B2, 0x08C4, 0xC8D4, 0xC8E7, 0x08F7, 0x0808, 0xC818, 0xC82B, 0x083B, 0xC84D, 0x085D, 0x086E, + 0xC87E, 0x0990, 0xC980, 0xC9B3, 0x09A3, 0xC9D5, 0x09C5, 0x09F6, 0xC9E6, 0xC919, 0x0909, 0x093A, 0xC92A, + 0x095C, 0xC94C, 0xC97F, 0x096F, 0x0AA0, 0xCAB0, 0xCA83, 0x0A93, 0xCAE5, 0x0AF5, 0x0AC6, 0xCAD6, 0xCA29, + 0x0A39, 0x0A0A, 0xCA1A, 0x0A6C, 0xCA7C, 0xCA4F, 0x0A5F, 0xCBB1, 0x0BA1, 0x0B92, 0xCB82, 0x0BF4, 0xCBE4, + 0xCBD7, 0x0BC7, 0x0B38, 0xCB28, 0xCB1B, 0x0B0B, 0xCB7D, 0x0B6D, 0x0B5E, 0xCB4E, 0x0CC0, 0xCCD0, 0xCCE3, + 0x0CF3, 0xCC85, 0x0C95, 0x0CA6, 0xCCB6, 0xCC49, 0x0C59, 0x0C6A, 0xCC7A, 0x0C0C, 0xCC1C, 0xCC2F, 0x0C3F, + 0xCDD1, 0x0DC1, 0x0DF2, 0xCDE2, 0x0D94, 0xCD84, 0xCDB7, 0x0DA7, 0x0D58, 0xCD48, 0xCD7B, 0x0D6B, 0xCD1D, + 0x0D0D, 0x0D3E, 0xCD2E, 0xCEE1, 0x0EF1, 0x0EC2, 0xCED2, 0x0EA4, 0xCEB4, 0xCE87, 0x0E97, 0x0E68, 0xCE78, + 0xCE4B, 0x0E5B, 0xCE2D, 0x0E3D, 0x0E0E, 0xCE1E, 0x0FF0, 0xCFE0, 0xCFD3, 0x0FC3, 0xCFB5, 0x0FA5, 0x0F96, + 0xCF86, 0xCF79, 0x0F69, 0x0F5A, 0xCF4A, 0x0F3C, 0xCF2C, 0xCF1F, 0x0F0F + ], + [ + 0x0000, 0xCCC1, 0xD981, 0x1540, 0xF301, 0x3FC0, 0x2A80, 0xE641, 0xA601, 0x6AC0, 0x7F80, 0xB341, 0x5500, + 0x99C1, 0x8C81, 0x4040, 0x0C01, 0xC0C0, 0xD580, 0x1941, 0xFF00, 0x33C1, 0x2681, 0xEA40, 0xAA00, 0x66C1, + 0x7381, 0xBF40, 0x5901, 0x95C0, 0x8080, 0x4C41, 0x1802, 0xD4C3, 0xC183, 0x0D42, 0xEB03, 0x27C2, 0x3282, + 0xFE43, 0xBE03, 0x72C2, 0x6782, 0xAB43, 0x4D02, 0x81C3, 0x9483, 0x5842, 0x1403, 0xD8C2, 0xCD82, 0x0143, + 0xE702, 0x2BC3, 0x3E83, 0xF242, 0xB202, 0x7EC3, 0x6B83, 0xA742, 0x4103, 0x8DC2, 0x9882, 0x5443, 0x3004, + 0xFCC5, 0xE985, 0x2544, 0xC305, 0x0FC4, 0x1A84, 0xD645, 0x9605, 0x5AC4, 0x4F84, 0x8345, 0x6504, 0xA9C5, + 0xBC85, 0x7044, 0x3C05, 0xF0C4, 0xE584, 0x2945, 0xCF04, 0x03C5, 0x1685, 0xDA44, 0x9A04, 0x56C5, 0x4385, + 0x8F44, 0x6905, 0xA5C4, 0xB084, 0x7C45, 0x2806, 0xE4C7, 0xF187, 0x3D46, 0xDB07, 0x17C6, 0x0286, 0xCE47, + 0x8E07, 0x42C6, 0x5786, 0x9B47, 0x7D06, 0xB1C7, 0xA487, 0x6846, 0x2407, 0xE8C6, 0xFD86, 0x3147, 0xD706, + 0x1BC7, 0x0E87, 0xC246, 0x8206, 0x4EC7, 0x5B87, 0x9746, 0x7107, 0xBDC6, 0xA886, 0x6447, 0x6008, 0xACC9, + 0xB989, 0x7548, 0x9309, 0x5FC8, 0x4A88, 0x8649, 0xC609, 0x0AC8, 0x1F88, 0xD349, 0x3508, 0xF9C9, 0xEC89, + 0x2048, 0x6C09, 0xA0C8, 0xB588, 0x7949, 0x9F08, 0x53C9, 0x4689, 0x8A48, 0xCA08, 0x06C9, 0x1389, 0xDF48, + 0x3909, 0xF5C8, 0xE088, 0x2C49, 0x780A, 0xB4CB, 0xA18B, 0x6D4A, 0x8B0B, 0x47CA, 0x528A, 0x9E4B, 0xDE0B, + 0x12CA, 0x078A, 0xCB4B, 0x2D0A, 0xE1CB, 0xF48B, 0x384A, 0x740B, 0xB8CA, 0xAD8A, 0x614B, 0x870A, 0x4BCB, + 0x5E8B, 0x924A, 0xD20A, 0x1ECB, 0x0B8B, 0xC74A, 0x210B, 0xEDCA, 0xF88A, 0x344B, 0x500C, 0x9CCD, 0x898D, + 0x454C, 0xA30D, 0x6FCC, 0x7A8C, 0xB64D, 0xF60D, 0x3ACC, 0x2F8C, 0xE34D, 0x050C, 0xC9CD, 0xDC8D, 0x104C, + 0x5C0D, 0x90CC, 0x858C, 0x494D, 0xAF0C, 0x63CD, 0x768D, 0xBA4C, 0xFA0C, 0x36CD, 0x238D, 0xEF4C, 0x090D, + 0xC5CC, 0xD08C, 0x1C4D, 0x480E, 0x84CF, 0x918F, 0x5D4E, 0xBB0F, 0x77CE, 0x628E, 0xAE4F, 0xEE0F, 0x22CE, + 0x378E, 0xFB4F, 0x1D0E, 0xD1CF, 0xC48F, 0x084E, 0x440F, 0x88CE, 0x9D8E, 0x514F, 0xB70E, 0x7BCF, 0x6E8F, + 0xA24E, 0xE20E, 0x2ECF, 0x3B8F, 0xF74E, 0x110F, 0xDDCE, 0xC88E, 0x044F + ] + ]; + + /// Initializes an instance of the CRC16 with IBM polynomial and seed. + /// + public CRC16IbmContext() : base(CRC16IbmPoly, CRC16IbmSeed, _ibmCrc16Table, false) {} + + public new string Name => Localization.CRC16_IBM_Name; + public new Guid Id => new("0470433E-0C78-4C37-8C9F-BD8E72340E78"); + public new string Author => Authors.NataliaPortillo; + + /// Gets the hash of a file + /// File path. + + // ReSharper disable once ReturnTypeCanBeEnumerable.Global + public static byte[] File(string filename) + { + File(filename, out byte[] hash); + + return hash; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) => + File(filename, out hash, CRC16IbmPoly, CRC16IbmSeed, _ibmCrc16Table, false); + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) => + Data(data, len, out hash, CRC16IbmPoly, CRC16IbmSeed, _ibmCrc16Table, false); + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} \ No newline at end of file diff --git a/Aaru.Checksums/CRC32/arm_simd.cs b/Aaru.Checksums/CRC32/arm_simd.cs new file mode 100644 index 000000000..4d4e6bac0 --- /dev/null +++ b/Aaru.Checksums/CRC32/arm_simd.cs @@ -0,0 +1,132 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : arm_simd.cs +// Author(s) : Natalia Portillo +// The Chromium Authors +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Compute CRC32 checksum using ARM special instructions.. +// +// --[ License ] -------------------------------------------------------------- +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright 2017 The Chromium Authors. All rights reserved. +// ****************************************************************************/ + +using System; +using System.Runtime.Intrinsics.Arm; + +namespace Aaru.Checksums.CRC32; + +static class ArmSimd +{ + internal static uint Step64(byte[] buf, long len, uint crc) + { + uint c = crc; + + var bufPos = 0; + + while(len >= 64) + { + c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos)); + bufPos += 8; + c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos)); + bufPos += 8; + c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos)); + bufPos += 8; + c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos)); + bufPos += 8; + c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos)); + bufPos += 8; + c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos)); + bufPos += 8; + c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos)); + bufPos += 8; + c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos)); + bufPos += 8; + len -= 64; + } + + while(len >= 8) + { + c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos)); + bufPos += 8; + len -= 8; + } + + while(len-- > 0) c = Crc32.ComputeCrc32(c, buf[bufPos++]); + + return c; + } + + internal static uint Step32(byte[] buf, long len, uint crc) + { + uint c = crc; + + var bufPos = 0; + + while(len >= 32) + { + c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos)); + bufPos += 4; + c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos)); + bufPos += 4; + c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos)); + bufPos += 4; + c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos)); + bufPos += 4; + c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos)); + bufPos += 4; + c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos)); + bufPos += 4; + c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos)); + bufPos += 4; + c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos)); + bufPos += 4; + len -= 32; + } + + while(len >= 4) + { + c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos)); + bufPos += 4; + len -= 4; + } + + while(len-- > 0) c = Crc32.ComputeCrc32(c, buf[bufPos++]); + + return c; + } +} \ No newline at end of file diff --git a/Aaru.Checksums/CRC32/clmul.cs b/Aaru.Checksums/CRC32/clmul.cs new file mode 100644 index 000000000..03a1e5d87 --- /dev/null +++ b/Aaru.Checksums/CRC32/clmul.cs @@ -0,0 +1,229 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : clmul.cs +// Author(s) : Natalia Portillo +// Wajdi Feghali +// Jim Guilford +// Vinodh Gopal +// Erdinc Ozturk +// Jim Kukunas +// Marian Beermann +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ +// instruction. +// +// A white paper describing this algorithm can be found at: +// http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf +// +// --[ License ] -------------------------------------------------------------- +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from +// the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright (c) 2016 Marian Beermann (add support for initial value, restructuring) +// Copyright (C) 2013 Intel Corporation. All rights reserved. +// ****************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace Aaru.Checksums.CRC32; + +static class Clmul +{ + static readonly uint[] _crcK = + [ + 0xccaa009e, 0x00000000, /* rk1 */ 0x751997d0, 0x00000001, /* rk2 */ 0xccaa009e, 0x00000000, /* rk5 */ + 0x63cd6124, 0x00000001, /* rk6 */ 0xf7011640, 0x00000001, /* rk7 */ 0xdb710640, 0x00000001 /* rk8 */ + ]; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static void Fold4(ref Vector128 xmmCRC0, ref Vector128 xmmCRC1, ref Vector128 xmmCRC2, + ref Vector128 xmmCRC3) + { + var xmmFold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001); + + Vector128 xTmp0 = xmmCRC0; + Vector128 xTmp1 = xmmCRC1; + Vector128 xTmp2 = xmmCRC2; + Vector128 xTmp3 = xmmCRC3; + + xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xTmp0 = Pclmulqdq.CarrylessMultiply(xTmp0.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC0 = xmmCRC0.AsSingle(); + Vector128 psT0 = xTmp0.AsSingle(); + Vector128 psRes0 = Sse.Xor(psCRC0, psT0); + + xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xTmp1 = Pclmulqdq.CarrylessMultiply(xTmp1.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC1 = xmmCRC1.AsSingle(); + Vector128 psT1 = xTmp1.AsSingle(); + Vector128 psRes1 = Sse.Xor(psCRC1, psT1); + + xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xTmp2 = Pclmulqdq.CarrylessMultiply(xTmp2.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC2 = xmmCRC2.AsSingle(); + Vector128 psT2 = xTmp2.AsSingle(); + Vector128 psRes2 = Sse.Xor(psCRC2, psT2); + + xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xTmp3 = Pclmulqdq.CarrylessMultiply(xTmp3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC3 = xmmCRC3.AsSingle(); + Vector128 psT3 = xTmp3.AsSingle(); + Vector128 psRes3 = Sse.Xor(psCRC3, psT3); + + xmmCRC0 = psRes0.AsUInt32(); + xmmCRC1 = psRes1.AsUInt32(); + xmmCRC2 = psRes2.AsUInt32(); + xmmCRC3 = psRes3.AsUInt32(); + } + + internal static uint Step(byte[] src, long len, uint initialCRC) + { + Vector128 xmmInitial = Sse2.ConvertScalarToVector128UInt32(initialCRC); + Vector128 xmmCRC0 = Sse2.ConvertScalarToVector128UInt32(0x9db42487); + Vector128 xmmCRC1 = Vector128.Zero; + Vector128 xmmCRC2 = Vector128.Zero; + Vector128 xmmCRC3 = Vector128.Zero; + var bufPos = 0; + + var first = true; + + /* fold 512 to 32 step variable declarations for ISO-C90 compat. */ + var xmmMask = Vector128.Create(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000); + var xmmMask2 = Vector128.Create(0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); + + while((len -= 64) >= 0) + { + var xmmT0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), + BitConverter.ToUInt32(src, bufPos + 4), + BitConverter.ToUInt32(src, bufPos + 8), + BitConverter.ToUInt32(src, bufPos + 12)); + + bufPos += 16; + + var xmmT1 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), + BitConverter.ToUInt32(src, bufPos + 4), + BitConverter.ToUInt32(src, bufPos + 8), + BitConverter.ToUInt32(src, bufPos + 12)); + + bufPos += 16; + + var xmmT2 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), + BitConverter.ToUInt32(src, bufPos + 4), + BitConverter.ToUInt32(src, bufPos + 8), + BitConverter.ToUInt32(src, bufPos + 12)); + + bufPos += 16; + + var xmmT3 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), + BitConverter.ToUInt32(src, bufPos + 4), + BitConverter.ToUInt32(src, bufPos + 8), + BitConverter.ToUInt32(src, bufPos + 12)); + + bufPos += 16; + + if(first) + { + first = false; + xmmT0 = Sse2.Xor(xmmT0, xmmInitial); + } + + Fold4(ref xmmCRC0, ref xmmCRC1, ref xmmCRC2, ref xmmCRC3); + + xmmCRC0 = Sse2.Xor(xmmCRC0, xmmT0); + xmmCRC1 = Sse2.Xor(xmmCRC1, xmmT1); + xmmCRC2 = Sse2.Xor(xmmCRC2, xmmT2); + xmmCRC3 = Sse2.Xor(xmmCRC3, xmmT3); + } + + /* fold 512 to 32 */ + + /* + * k1 + */ + var crcFold = Vector128.Create(_crcK[0], _crcK[1], _crcK[2], _crcK[3]); + + Vector128 xTmp0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32(); + + xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32(); + xmmCRC1 = Sse2.Xor(xmmCRC1, xTmp0); + xmmCRC1 = Sse2.Xor(xmmCRC1, xmmCRC0); + + Vector128 xTmp1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32(); + + xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32(); + xmmCRC2 = Sse2.Xor(xmmCRC2, xTmp1); + xmmCRC2 = Sse2.Xor(xmmCRC2, xmmCRC1); + + Vector128 xTmp2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32(); + + xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32(); + xmmCRC3 = Sse2.Xor(xmmCRC3, xTmp2); + xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2); + + /* + * k5 + */ + crcFold = Vector128.Create(_crcK[4], _crcK[5], _crcK[6], _crcK[7]); + + xmmCRC0 = xmmCRC3; + xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0).AsUInt32(); + xmmCRC0 = Sse2.ShiftRightLogical128BitLane(xmmCRC0, 8); + xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC0); + + xmmCRC0 = xmmCRC3; + xmmCRC3 = Sse2.ShiftLeftLogical128BitLane(xmmCRC3, 4); + xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32(); + xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC0); + xmmCRC3 = Sse2.And(xmmCRC3, xmmMask2); + + /* + * k7 + */ + xmmCRC1 = xmmCRC3; + xmmCRC2 = xmmCRC3; + crcFold = Vector128.Create(_crcK[8], _crcK[9], _crcK[10], _crcK[11]); + + xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0).AsUInt32(); + xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2); + xmmCRC3 = Sse2.And(xmmCRC3, xmmMask); + + xmmCRC2 = xmmCRC3; + xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32(); + xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2); + xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC1); + + /* + * could just as well write xmm_crc3[2], doing a movaps and truncating, but + * no real advantage - it's a tiny bit slower per call, while no additional CPUs + * would be supported by only requiring SSSE3 and CLMUL instead of SSE4.1 + CLMUL + */ + return ~Sse41.Extract(xmmCRC3, 2); + } +} \ No newline at end of file diff --git a/Aaru.Checksums/CRC32Context.cs b/Aaru.Checksums/CRC32Context.cs new file mode 100644 index 000000000..409fbe25c --- /dev/null +++ b/Aaru.Checksums/CRC32Context.cs @@ -0,0 +1,673 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CRC32Context.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Implements a CRC32 algorithm. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.X86; +using System.Text; +using Aaru.Checksums.CRC32; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; + +namespace Aaru.Checksums; + +/// +/// Implements a CRC32 algorithm +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public sealed partial class Crc32Context : IChecksum +{ + const uint CRC32_ISO_POLY = 0xEDB88320; + const uint CRC32_ISO_SEED = 0xFFFFFFFF; + + internal static readonly uint[][] ISOCrc32Table = + [ + [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + ], + [ + 0x00000000, 0x191B3141, 0x32366282, 0x2B2D53C3, 0x646CC504, 0x7D77F445, 0x565AA786, 0x4F4196C7, + 0xC8D98A08, 0xD1C2BB49, 0xFAEFE88A, 0xE3F4D9CB, 0xACB54F0C, 0xB5AE7E4D, 0x9E832D8E, 0x87981CCF, + 0x4AC21251, 0x53D92310, 0x78F470D3, 0x61EF4192, 0x2EAED755, 0x37B5E614, 0x1C98B5D7, 0x05838496, + 0x821B9859, 0x9B00A918, 0xB02DFADB, 0xA936CB9A, 0xE6775D5D, 0xFF6C6C1C, 0xD4413FDF, 0xCD5A0E9E, + 0x958424A2, 0x8C9F15E3, 0xA7B24620, 0xBEA97761, 0xF1E8E1A6, 0xE8F3D0E7, 0xC3DE8324, 0xDAC5B265, + 0x5D5DAEAA, 0x44469FEB, 0x6F6BCC28, 0x7670FD69, 0x39316BAE, 0x202A5AEF, 0x0B07092C, 0x121C386D, + 0xDF4636F3, 0xC65D07B2, 0xED705471, 0xF46B6530, 0xBB2AF3F7, 0xA231C2B6, 0x891C9175, 0x9007A034, + 0x179FBCFB, 0x0E848DBA, 0x25A9DE79, 0x3CB2EF38, 0x73F379FF, 0x6AE848BE, 0x41C51B7D, 0x58DE2A3C, + 0xF0794F05, 0xE9627E44, 0xC24F2D87, 0xDB541CC6, 0x94158A01, 0x8D0EBB40, 0xA623E883, 0xBF38D9C2, + 0x38A0C50D, 0x21BBF44C, 0x0A96A78F, 0x138D96CE, 0x5CCC0009, 0x45D73148, 0x6EFA628B, 0x77E153CA, + 0xBABB5D54, 0xA3A06C15, 0x888D3FD6, 0x91960E97, 0xDED79850, 0xC7CCA911, 0xECE1FAD2, 0xF5FACB93, + 0x7262D75C, 0x6B79E61D, 0x4054B5DE, 0x594F849F, 0x160E1258, 0x0F152319, 0x243870DA, 0x3D23419B, + 0x65FD6BA7, 0x7CE65AE6, 0x57CB0925, 0x4ED03864, 0x0191AEA3, 0x188A9FE2, 0x33A7CC21, 0x2ABCFD60, + 0xAD24E1AF, 0xB43FD0EE, 0x9F12832D, 0x8609B26C, 0xC94824AB, 0xD05315EA, 0xFB7E4629, 0xE2657768, + 0x2F3F79F6, 0x362448B7, 0x1D091B74, 0x04122A35, 0x4B53BCF2, 0x52488DB3, 0x7965DE70, 0x607EEF31, + 0xE7E6F3FE, 0xFEFDC2BF, 0xD5D0917C, 0xCCCBA03D, 0x838A36FA, 0x9A9107BB, 0xB1BC5478, 0xA8A76539, + 0x3B83984B, 0x2298A90A, 0x09B5FAC9, 0x10AECB88, 0x5FEF5D4F, 0x46F46C0E, 0x6DD93FCD, 0x74C20E8C, + 0xF35A1243, 0xEA412302, 0xC16C70C1, 0xD8774180, 0x9736D747, 0x8E2DE606, 0xA500B5C5, 0xBC1B8484, + 0x71418A1A, 0x685ABB5B, 0x4377E898, 0x5A6CD9D9, 0x152D4F1E, 0x0C367E5F, 0x271B2D9C, 0x3E001CDD, + 0xB9980012, 0xA0833153, 0x8BAE6290, 0x92B553D1, 0xDDF4C516, 0xC4EFF457, 0xEFC2A794, 0xF6D996D5, + 0xAE07BCE9, 0xB71C8DA8, 0x9C31DE6B, 0x852AEF2A, 0xCA6B79ED, 0xD37048AC, 0xF85D1B6F, 0xE1462A2E, + 0x66DE36E1, 0x7FC507A0, 0x54E85463, 0x4DF36522, 0x02B2F3E5, 0x1BA9C2A4, 0x30849167, 0x299FA026, + 0xE4C5AEB8, 0xFDDE9FF9, 0xD6F3CC3A, 0xCFE8FD7B, 0x80A96BBC, 0x99B25AFD, 0xB29F093E, 0xAB84387F, + 0x2C1C24B0, 0x350715F1, 0x1E2A4632, 0x07317773, 0x4870E1B4, 0x516BD0F5, 0x7A468336, 0x635DB277, + 0xCBFAD74E, 0xD2E1E60F, 0xF9CCB5CC, 0xE0D7848D, 0xAF96124A, 0xB68D230B, 0x9DA070C8, 0x84BB4189, + 0x03235D46, 0x1A386C07, 0x31153FC4, 0x280E0E85, 0x674F9842, 0x7E54A903, 0x5579FAC0, 0x4C62CB81, + 0x8138C51F, 0x9823F45E, 0xB30EA79D, 0xAA1596DC, 0xE554001B, 0xFC4F315A, 0xD7626299, 0xCE7953D8, + 0x49E14F17, 0x50FA7E56, 0x7BD72D95, 0x62CC1CD4, 0x2D8D8A13, 0x3496BB52, 0x1FBBE891, 0x06A0D9D0, + 0x5E7EF3EC, 0x4765C2AD, 0x6C48916E, 0x7553A02F, 0x3A1236E8, 0x230907A9, 0x0824546A, 0x113F652B, + 0x96A779E4, 0x8FBC48A5, 0xA4911B66, 0xBD8A2A27, 0xF2CBBCE0, 0xEBD08DA1, 0xC0FDDE62, 0xD9E6EF23, + 0x14BCE1BD, 0x0DA7D0FC, 0x268A833F, 0x3F91B27E, 0x70D024B9, 0x69CB15F8, 0x42E6463B, 0x5BFD777A, + 0xDC656BB5, 0xC57E5AF4, 0xEE530937, 0xF7483876, 0xB809AEB1, 0xA1129FF0, 0x8A3FCC33, 0x9324FD72 + ], + [ + 0x00000000, 0x01C26A37, 0x0384D46E, 0x0246BE59, 0x0709A8DC, 0x06CBC2EB, 0x048D7CB2, 0x054F1685, + 0x0E1351B8, 0x0FD13B8F, 0x0D9785D6, 0x0C55EFE1, 0x091AF964, 0x08D89353, 0x0A9E2D0A, 0x0B5C473D, + 0x1C26A370, 0x1DE4C947, 0x1FA2771E, 0x1E601D29, 0x1B2F0BAC, 0x1AED619B, 0x18ABDFC2, 0x1969B5F5, + 0x1235F2C8, 0x13F798FF, 0x11B126A6, 0x10734C91, 0x153C5A14, 0x14FE3023, 0x16B88E7A, 0x177AE44D, + 0x384D46E0, 0x398F2CD7, 0x3BC9928E, 0x3A0BF8B9, 0x3F44EE3C, 0x3E86840B, 0x3CC03A52, 0x3D025065, + 0x365E1758, 0x379C7D6F, 0x35DAC336, 0x3418A901, 0x3157BF84, 0x3095D5B3, 0x32D36BEA, 0x331101DD, + 0x246BE590, 0x25A98FA7, 0x27EF31FE, 0x262D5BC9, 0x23624D4C, 0x22A0277B, 0x20E69922, 0x2124F315, + 0x2A78B428, 0x2BBADE1F, 0x29FC6046, 0x283E0A71, 0x2D711CF4, 0x2CB376C3, 0x2EF5C89A, 0x2F37A2AD, + 0x709A8DC0, 0x7158E7F7, 0x731E59AE, 0x72DC3399, 0x7793251C, 0x76514F2B, 0x7417F172, 0x75D59B45, + 0x7E89DC78, 0x7F4BB64F, 0x7D0D0816, 0x7CCF6221, 0x798074A4, 0x78421E93, 0x7A04A0CA, 0x7BC6CAFD, + 0x6CBC2EB0, 0x6D7E4487, 0x6F38FADE, 0x6EFA90E9, 0x6BB5866C, 0x6A77EC5B, 0x68315202, 0x69F33835, + 0x62AF7F08, 0x636D153F, 0x612BAB66, 0x60E9C151, 0x65A6D7D4, 0x6464BDE3, 0x662203BA, 0x67E0698D, + 0x48D7CB20, 0x4915A117, 0x4B531F4E, 0x4A917579, 0x4FDE63FC, 0x4E1C09CB, 0x4C5AB792, 0x4D98DDA5, + 0x46C49A98, 0x4706F0AF, 0x45404EF6, 0x448224C1, 0x41CD3244, 0x400F5873, 0x4249E62A, 0x438B8C1D, + 0x54F16850, 0x55330267, 0x5775BC3E, 0x56B7D609, 0x53F8C08C, 0x523AAABB, 0x507C14E2, 0x51BE7ED5, + 0x5AE239E8, 0x5B2053DF, 0x5966ED86, 0x58A487B1, 0x5DEB9134, 0x5C29FB03, 0x5E6F455A, 0x5FAD2F6D, + 0xE1351B80, 0xE0F771B7, 0xE2B1CFEE, 0xE373A5D9, 0xE63CB35C, 0xE7FED96B, 0xE5B86732, 0xE47A0D05, + 0xEF264A38, 0xEEE4200F, 0xECA29E56, 0xED60F461, 0xE82FE2E4, 0xE9ED88D3, 0xEBAB368A, 0xEA695CBD, + 0xFD13B8F0, 0xFCD1D2C7, 0xFE976C9E, 0xFF5506A9, 0xFA1A102C, 0xFBD87A1B, 0xF99EC442, 0xF85CAE75, + 0xF300E948, 0xF2C2837F, 0xF0843D26, 0xF1465711, 0xF4094194, 0xF5CB2BA3, 0xF78D95FA, 0xF64FFFCD, + 0xD9785D60, 0xD8BA3757, 0xDAFC890E, 0xDB3EE339, 0xDE71F5BC, 0xDFB39F8B, 0xDDF521D2, 0xDC374BE5, + 0xD76B0CD8, 0xD6A966EF, 0xD4EFD8B6, 0xD52DB281, 0xD062A404, 0xD1A0CE33, 0xD3E6706A, 0xD2241A5D, + 0xC55EFE10, 0xC49C9427, 0xC6DA2A7E, 0xC7184049, 0xC25756CC, 0xC3953CFB, 0xC1D382A2, 0xC011E895, + 0xCB4DAFA8, 0xCA8FC59F, 0xC8C97BC6, 0xC90B11F1, 0xCC440774, 0xCD866D43, 0xCFC0D31A, 0xCE02B92D, + 0x91AF9640, 0x906DFC77, 0x922B422E, 0x93E92819, 0x96A63E9C, 0x976454AB, 0x9522EAF2, 0x94E080C5, + 0x9FBCC7F8, 0x9E7EADCF, 0x9C381396, 0x9DFA79A1, 0x98B56F24, 0x99770513, 0x9B31BB4A, 0x9AF3D17D, + 0x8D893530, 0x8C4B5F07, 0x8E0DE15E, 0x8FCF8B69, 0x8A809DEC, 0x8B42F7DB, 0x89044982, 0x88C623B5, + 0x839A6488, 0x82580EBF, 0x801EB0E6, 0x81DCDAD1, 0x8493CC54, 0x8551A663, 0x8717183A, 0x86D5720D, + 0xA9E2D0A0, 0xA820BA97, 0xAA6604CE, 0xABA46EF9, 0xAEEB787C, 0xAF29124B, 0xAD6FAC12, 0xACADC625, + 0xA7F18118, 0xA633EB2F, 0xA4755576, 0xA5B73F41, 0xA0F829C4, 0xA13A43F3, 0xA37CFDAA, 0xA2BE979D, + 0xB5C473D0, 0xB40619E7, 0xB640A7BE, 0xB782CD89, 0xB2CDDB0C, 0xB30FB13B, 0xB1490F62, 0xB08B6555, + 0xBBD72268, 0xBA15485F, 0xB853F606, 0xB9919C31, 0xBCDE8AB4, 0xBD1CE083, 0xBF5A5EDA, 0xBE9834ED + ], + [ + 0x00000000, 0xB8BC6765, 0xAA09C88B, 0x12B5AFEE, 0x8F629757, 0x37DEF032, 0x256B5FDC, 0x9DD738B9, + 0xC5B428EF, 0x7D084F8A, 0x6FBDE064, 0xD7018701, 0x4AD6BFB8, 0xF26AD8DD, 0xE0DF7733, 0x58631056, + 0x5019579F, 0xE8A530FA, 0xFA109F14, 0x42ACF871, 0xDF7BC0C8, 0x67C7A7AD, 0x75720843, 0xCDCE6F26, + 0x95AD7F70, 0x2D111815, 0x3FA4B7FB, 0x8718D09E, 0x1ACFE827, 0xA2738F42, 0xB0C620AC, 0x087A47C9, + 0xA032AF3E, 0x188EC85B, 0x0A3B67B5, 0xB28700D0, 0x2F503869, 0x97EC5F0C, 0x8559F0E2, 0x3DE59787, + 0x658687D1, 0xDD3AE0B4, 0xCF8F4F5A, 0x7733283F, 0xEAE41086, 0x525877E3, 0x40EDD80D, 0xF851BF68, + 0xF02BF8A1, 0x48979FC4, 0x5A22302A, 0xE29E574F, 0x7F496FF6, 0xC7F50893, 0xD540A77D, 0x6DFCC018, + 0x359FD04E, 0x8D23B72B, 0x9F9618C5, 0x272A7FA0, 0xBAFD4719, 0x0241207C, 0x10F48F92, 0xA848E8F7, + 0x9B14583D, 0x23A83F58, 0x311D90B6, 0x89A1F7D3, 0x1476CF6A, 0xACCAA80F, 0xBE7F07E1, 0x06C36084, + 0x5EA070D2, 0xE61C17B7, 0xF4A9B859, 0x4C15DF3C, 0xD1C2E785, 0x697E80E0, 0x7BCB2F0E, 0xC377486B, + 0xCB0D0FA2, 0x73B168C7, 0x6104C729, 0xD9B8A04C, 0x446F98F5, 0xFCD3FF90, 0xEE66507E, 0x56DA371B, + 0x0EB9274D, 0xB6054028, 0xA4B0EFC6, 0x1C0C88A3, 0x81DBB01A, 0x3967D77F, 0x2BD27891, 0x936E1FF4, + 0x3B26F703, 0x839A9066, 0x912F3F88, 0x299358ED, 0xB4446054, 0x0CF80731, 0x1E4DA8DF, 0xA6F1CFBA, + 0xFE92DFEC, 0x462EB889, 0x549B1767, 0xEC277002, 0x71F048BB, 0xC94C2FDE, 0xDBF98030, 0x6345E755, + 0x6B3FA09C, 0xD383C7F9, 0xC1366817, 0x798A0F72, 0xE45D37CB, 0x5CE150AE, 0x4E54FF40, 0xF6E89825, + 0xAE8B8873, 0x1637EF16, 0x048240F8, 0xBC3E279D, 0x21E91F24, 0x99557841, 0x8BE0D7AF, 0x335CB0CA, + 0xED59B63B, 0x55E5D15E, 0x47507EB0, 0xFFEC19D5, 0x623B216C, 0xDA874609, 0xC832E9E7, 0x708E8E82, + 0x28ED9ED4, 0x9051F9B1, 0x82E4565F, 0x3A58313A, 0xA78F0983, 0x1F336EE6, 0x0D86C108, 0xB53AA66D, + 0xBD40E1A4, 0x05FC86C1, 0x1749292F, 0xAFF54E4A, 0x322276F3, 0x8A9E1196, 0x982BBE78, 0x2097D91D, + 0x78F4C94B, 0xC048AE2E, 0xD2FD01C0, 0x6A4166A5, 0xF7965E1C, 0x4F2A3979, 0x5D9F9697, 0xE523F1F2, + 0x4D6B1905, 0xF5D77E60, 0xE762D18E, 0x5FDEB6EB, 0xC2098E52, 0x7AB5E937, 0x680046D9, 0xD0BC21BC, + 0x88DF31EA, 0x3063568F, 0x22D6F961, 0x9A6A9E04, 0x07BDA6BD, 0xBF01C1D8, 0xADB46E36, 0x15080953, + 0x1D724E9A, 0xA5CE29FF, 0xB77B8611, 0x0FC7E174, 0x9210D9CD, 0x2AACBEA8, 0x38191146, 0x80A57623, + 0xD8C66675, 0x607A0110, 0x72CFAEFE, 0xCA73C99B, 0x57A4F122, 0xEF189647, 0xFDAD39A9, 0x45115ECC, + 0x764DEE06, 0xCEF18963, 0xDC44268D, 0x64F841E8, 0xF92F7951, 0x41931E34, 0x5326B1DA, 0xEB9AD6BF, + 0xB3F9C6E9, 0x0B45A18C, 0x19F00E62, 0xA14C6907, 0x3C9B51BE, 0x842736DB, 0x96929935, 0x2E2EFE50, + 0x2654B999, 0x9EE8DEFC, 0x8C5D7112, 0x34E11677, 0xA9362ECE, 0x118A49AB, 0x033FE645, 0xBB838120, + 0xE3E09176, 0x5B5CF613, 0x49E959FD, 0xF1553E98, 0x6C820621, 0xD43E6144, 0xC68BCEAA, 0x7E37A9CF, + 0xD67F4138, 0x6EC3265D, 0x7C7689B3, 0xC4CAEED6, 0x591DD66F, 0xE1A1B10A, 0xF3141EE4, 0x4BA87981, + 0x13CB69D7, 0xAB770EB2, 0xB9C2A15C, 0x017EC639, 0x9CA9FE80, 0x241599E5, 0x36A0360B, 0x8E1C516E, + 0x866616A7, 0x3EDA71C2, 0x2C6FDE2C, 0x94D3B949, 0x090481F0, 0xB1B8E695, 0xA30D497B, 0x1BB12E1E, + 0x43D23E48, 0xFB6E592D, 0xE9DBF6C3, 0x516791A6, 0xCCB0A91F, 0x740CCE7A, 0x66B96194, 0xDE0506F1 + ], + [ + 0x00000000, 0x3D6029B0, 0x7AC05360, 0x47A07AD0, 0xF580A6C0, 0xC8E08F70, 0x8F40F5A0, 0xB220DC10, + 0x30704BC1, 0x0D106271, 0x4AB018A1, 0x77D03111, 0xC5F0ED01, 0xF890C4B1, 0xBF30BE61, 0x825097D1, + 0x60E09782, 0x5D80BE32, 0x1A20C4E2, 0x2740ED52, 0x95603142, 0xA80018F2, 0xEFA06222, 0xD2C04B92, + 0x5090DC43, 0x6DF0F5F3, 0x2A508F23, 0x1730A693, 0xA5107A83, 0x98705333, 0xDFD029E3, 0xE2B00053, + 0xC1C12F04, 0xFCA106B4, 0xBB017C64, 0x866155D4, 0x344189C4, 0x0921A074, 0x4E81DAA4, 0x73E1F314, + 0xF1B164C5, 0xCCD14D75, 0x8B7137A5, 0xB6111E15, 0x0431C205, 0x3951EBB5, 0x7EF19165, 0x4391B8D5, + 0xA121B886, 0x9C419136, 0xDBE1EBE6, 0xE681C256, 0x54A11E46, 0x69C137F6, 0x2E614D26, 0x13016496, + 0x9151F347, 0xAC31DAF7, 0xEB91A027, 0xD6F18997, 0x64D15587, 0x59B17C37, 0x1E1106E7, 0x23712F57, + 0x58F35849, 0x659371F9, 0x22330B29, 0x1F532299, 0xAD73FE89, 0x9013D739, 0xD7B3ADE9, 0xEAD38459, + 0x68831388, 0x55E33A38, 0x124340E8, 0x2F236958, 0x9D03B548, 0xA0639CF8, 0xE7C3E628, 0xDAA3CF98, + 0x3813CFCB, 0x0573E67B, 0x42D39CAB, 0x7FB3B51B, 0xCD93690B, 0xF0F340BB, 0xB7533A6B, 0x8A3313DB, + 0x0863840A, 0x3503ADBA, 0x72A3D76A, 0x4FC3FEDA, 0xFDE322CA, 0xC0830B7A, 0x872371AA, 0xBA43581A, + 0x9932774D, 0xA4525EFD, 0xE3F2242D, 0xDE920D9D, 0x6CB2D18D, 0x51D2F83D, 0x167282ED, 0x2B12AB5D, + 0xA9423C8C, 0x9422153C, 0xD3826FEC, 0xEEE2465C, 0x5CC29A4C, 0x61A2B3FC, 0x2602C92C, 0x1B62E09C, + 0xF9D2E0CF, 0xC4B2C97F, 0x8312B3AF, 0xBE729A1F, 0x0C52460F, 0x31326FBF, 0x7692156F, 0x4BF23CDF, + 0xC9A2AB0E, 0xF4C282BE, 0xB362F86E, 0x8E02D1DE, 0x3C220DCE, 0x0142247E, 0x46E25EAE, 0x7B82771E, + 0xB1E6B092, 0x8C869922, 0xCB26E3F2, 0xF646CA42, 0x44661652, 0x79063FE2, 0x3EA64532, 0x03C66C82, + 0x8196FB53, 0xBCF6D2E3, 0xFB56A833, 0xC6368183, 0x74165D93, 0x49767423, 0x0ED60EF3, 0x33B62743, + 0xD1062710, 0xEC660EA0, 0xABC67470, 0x96A65DC0, 0x248681D0, 0x19E6A860, 0x5E46D2B0, 0x6326FB00, + 0xE1766CD1, 0xDC164561, 0x9BB63FB1, 0xA6D61601, 0x14F6CA11, 0x2996E3A1, 0x6E369971, 0x5356B0C1, + 0x70279F96, 0x4D47B626, 0x0AE7CCF6, 0x3787E546, 0x85A73956, 0xB8C710E6, 0xFF676A36, 0xC2074386, + 0x4057D457, 0x7D37FDE7, 0x3A978737, 0x07F7AE87, 0xB5D77297, 0x88B75B27, 0xCF1721F7, 0xF2770847, + 0x10C70814, 0x2DA721A4, 0x6A075B74, 0x576772C4, 0xE547AED4, 0xD8278764, 0x9F87FDB4, 0xA2E7D404, + 0x20B743D5, 0x1DD76A65, 0x5A7710B5, 0x67173905, 0xD537E515, 0xE857CCA5, 0xAFF7B675, 0x92979FC5, + 0xE915E8DB, 0xD475C16B, 0x93D5BBBB, 0xAEB5920B, 0x1C954E1B, 0x21F567AB, 0x66551D7B, 0x5B3534CB, + 0xD965A31A, 0xE4058AAA, 0xA3A5F07A, 0x9EC5D9CA, 0x2CE505DA, 0x11852C6A, 0x562556BA, 0x6B457F0A, + 0x89F57F59, 0xB49556E9, 0xF3352C39, 0xCE550589, 0x7C75D999, 0x4115F029, 0x06B58AF9, 0x3BD5A349, + 0xB9853498, 0x84E51D28, 0xC34567F8, 0xFE254E48, 0x4C059258, 0x7165BBE8, 0x36C5C138, 0x0BA5E888, + 0x28D4C7DF, 0x15B4EE6F, 0x521494BF, 0x6F74BD0F, 0xDD54611F, 0xE03448AF, 0xA794327F, 0x9AF41BCF, + 0x18A48C1E, 0x25C4A5AE, 0x6264DF7E, 0x5F04F6CE, 0xED242ADE, 0xD044036E, 0x97E479BE, 0xAA84500E, + 0x4834505D, 0x755479ED, 0x32F4033D, 0x0F942A8D, 0xBDB4F69D, 0x80D4DF2D, 0xC774A5FD, 0xFA148C4D, + 0x78441B9C, 0x4524322C, 0x028448FC, 0x3FE4614C, 0x8DC4BD5C, 0xB0A494EC, 0xF704EE3C, 0xCA64C78C + ], + [ + 0x00000000, 0xCB5CD3A5, 0x4DC8A10B, 0x869472AE, 0x9B914216, 0x50CD91B3, 0xD659E31D, 0x1D0530B8, + 0xEC53826D, 0x270F51C8, 0xA19B2366, 0x6AC7F0C3, 0x77C2C07B, 0xBC9E13DE, 0x3A0A6170, 0xF156B2D5, + 0x03D6029B, 0xC88AD13E, 0x4E1EA390, 0x85427035, 0x9847408D, 0x531B9328, 0xD58FE186, 0x1ED33223, + 0xEF8580F6, 0x24D95353, 0xA24D21FD, 0x6911F258, 0x7414C2E0, 0xBF481145, 0x39DC63EB, 0xF280B04E, + 0x07AC0536, 0xCCF0D693, 0x4A64A43D, 0x81387798, 0x9C3D4720, 0x57619485, 0xD1F5E62B, 0x1AA9358E, + 0xEBFF875B, 0x20A354FE, 0xA6372650, 0x6D6BF5F5, 0x706EC54D, 0xBB3216E8, 0x3DA66446, 0xF6FAB7E3, + 0x047A07AD, 0xCF26D408, 0x49B2A6A6, 0x82EE7503, 0x9FEB45BB, 0x54B7961E, 0xD223E4B0, 0x197F3715, + 0xE82985C0, 0x23755665, 0xA5E124CB, 0x6EBDF76E, 0x73B8C7D6, 0xB8E41473, 0x3E7066DD, 0xF52CB578, + 0x0F580A6C, 0xC404D9C9, 0x4290AB67, 0x89CC78C2, 0x94C9487A, 0x5F959BDF, 0xD901E971, 0x125D3AD4, + 0xE30B8801, 0x28575BA4, 0xAEC3290A, 0x659FFAAF, 0x789ACA17, 0xB3C619B2, 0x35526B1C, 0xFE0EB8B9, + 0x0C8E08F7, 0xC7D2DB52, 0x4146A9FC, 0x8A1A7A59, 0x971F4AE1, 0x5C439944, 0xDAD7EBEA, 0x118B384F, + 0xE0DD8A9A, 0x2B81593F, 0xAD152B91, 0x6649F834, 0x7B4CC88C, 0xB0101B29, 0x36846987, 0xFDD8BA22, + 0x08F40F5A, 0xC3A8DCFF, 0x453CAE51, 0x8E607DF4, 0x93654D4C, 0x58399EE9, 0xDEADEC47, 0x15F13FE2, + 0xE4A78D37, 0x2FFB5E92, 0xA96F2C3C, 0x6233FF99, 0x7F36CF21, 0xB46A1C84, 0x32FE6E2A, 0xF9A2BD8F, + 0x0B220DC1, 0xC07EDE64, 0x46EAACCA, 0x8DB67F6F, 0x90B34FD7, 0x5BEF9C72, 0xDD7BEEDC, 0x16273D79, + 0xE7718FAC, 0x2C2D5C09, 0xAAB92EA7, 0x61E5FD02, 0x7CE0CDBA, 0xB7BC1E1F, 0x31286CB1, 0xFA74BF14, + 0x1EB014D8, 0xD5ECC77D, 0x5378B5D3, 0x98246676, 0x852156CE, 0x4E7D856B, 0xC8E9F7C5, 0x03B52460, + 0xF2E396B5, 0x39BF4510, 0xBF2B37BE, 0x7477E41B, 0x6972D4A3, 0xA22E0706, 0x24BA75A8, 0xEFE6A60D, + 0x1D661643, 0xD63AC5E6, 0x50AEB748, 0x9BF264ED, 0x86F75455, 0x4DAB87F0, 0xCB3FF55E, 0x006326FB, + 0xF135942E, 0x3A69478B, 0xBCFD3525, 0x77A1E680, 0x6AA4D638, 0xA1F8059D, 0x276C7733, 0xEC30A496, + 0x191C11EE, 0xD240C24B, 0x54D4B0E5, 0x9F886340, 0x828D53F8, 0x49D1805D, 0xCF45F2F3, 0x04192156, + 0xF54F9383, 0x3E134026, 0xB8873288, 0x73DBE12D, 0x6EDED195, 0xA5820230, 0x2316709E, 0xE84AA33B, + 0x1ACA1375, 0xD196C0D0, 0x5702B27E, 0x9C5E61DB, 0x815B5163, 0x4A0782C6, 0xCC93F068, 0x07CF23CD, + 0xF6999118, 0x3DC542BD, 0xBB513013, 0x700DE3B6, 0x6D08D30E, 0xA65400AB, 0x20C07205, 0xEB9CA1A0, + 0x11E81EB4, 0xDAB4CD11, 0x5C20BFBF, 0x977C6C1A, 0x8A795CA2, 0x41258F07, 0xC7B1FDA9, 0x0CED2E0C, + 0xFDBB9CD9, 0x36E74F7C, 0xB0733DD2, 0x7B2FEE77, 0x662ADECF, 0xAD760D6A, 0x2BE27FC4, 0xE0BEAC61, + 0x123E1C2F, 0xD962CF8A, 0x5FF6BD24, 0x94AA6E81, 0x89AF5E39, 0x42F38D9C, 0xC467FF32, 0x0F3B2C97, + 0xFE6D9E42, 0x35314DE7, 0xB3A53F49, 0x78F9ECEC, 0x65FCDC54, 0xAEA00FF1, 0x28347D5F, 0xE368AEFA, + 0x16441B82, 0xDD18C827, 0x5B8CBA89, 0x90D0692C, 0x8DD55994, 0x46898A31, 0xC01DF89F, 0x0B412B3A, + 0xFA1799EF, 0x314B4A4A, 0xB7DF38E4, 0x7C83EB41, 0x6186DBF9, 0xAADA085C, 0x2C4E7AF2, 0xE712A957, + 0x15921919, 0xDECECABC, 0x585AB812, 0x93066BB7, 0x8E035B0F, 0x455F88AA, 0xC3CBFA04, 0x089729A1, + 0xF9C19B74, 0x329D48D1, 0xB4093A7F, 0x7F55E9DA, 0x6250D962, 0xA90C0AC7, 0x2F987869, 0xE4C4ABCC + ], + [ + 0x00000000, 0xA6770BB4, 0x979F1129, 0x31E81A9D, 0xF44F2413, 0x52382FA7, 0x63D0353A, 0xC5A73E8E, + 0x33EF4E67, 0x959845D3, 0xA4705F4E, 0x020754FA, 0xC7A06A74, 0x61D761C0, 0x503F7B5D, 0xF64870E9, + 0x67DE9CCE, 0xC1A9977A, 0xF0418DE7, 0x56368653, 0x9391B8DD, 0x35E6B369, 0x040EA9F4, 0xA279A240, + 0x5431D2A9, 0xF246D91D, 0xC3AEC380, 0x65D9C834, 0xA07EF6BA, 0x0609FD0E, 0x37E1E793, 0x9196EC27, + 0xCFBD399C, 0x69CA3228, 0x582228B5, 0xFE552301, 0x3BF21D8F, 0x9D85163B, 0xAC6D0CA6, 0x0A1A0712, + 0xFC5277FB, 0x5A257C4F, 0x6BCD66D2, 0xCDBA6D66, 0x081D53E8, 0xAE6A585C, 0x9F8242C1, 0x39F54975, + 0xA863A552, 0x0E14AEE6, 0x3FFCB47B, 0x998BBFCF, 0x5C2C8141, 0xFA5B8AF5, 0xCBB39068, 0x6DC49BDC, + 0x9B8CEB35, 0x3DFBE081, 0x0C13FA1C, 0xAA64F1A8, 0x6FC3CF26, 0xC9B4C492, 0xF85CDE0F, 0x5E2BD5BB, + 0x440B7579, 0xE27C7ECD, 0xD3946450, 0x75E36FE4, 0xB044516A, 0x16335ADE, 0x27DB4043, 0x81AC4BF7, + 0x77E43B1E, 0xD19330AA, 0xE07B2A37, 0x460C2183, 0x83AB1F0D, 0x25DC14B9, 0x14340E24, 0xB2430590, + 0x23D5E9B7, 0x85A2E203, 0xB44AF89E, 0x123DF32A, 0xD79ACDA4, 0x71EDC610, 0x4005DC8D, 0xE672D739, + 0x103AA7D0, 0xB64DAC64, 0x87A5B6F9, 0x21D2BD4D, 0xE47583C3, 0x42028877, 0x73EA92EA, 0xD59D995E, + 0x8BB64CE5, 0x2DC14751, 0x1C295DCC, 0xBA5E5678, 0x7FF968F6, 0xD98E6342, 0xE86679DF, 0x4E11726B, + 0xB8590282, 0x1E2E0936, 0x2FC613AB, 0x89B1181F, 0x4C162691, 0xEA612D25, 0xDB8937B8, 0x7DFE3C0C, + 0xEC68D02B, 0x4A1FDB9F, 0x7BF7C102, 0xDD80CAB6, 0x1827F438, 0xBE50FF8C, 0x8FB8E511, 0x29CFEEA5, + 0xDF879E4C, 0x79F095F8, 0x48188F65, 0xEE6F84D1, 0x2BC8BA5F, 0x8DBFB1EB, 0xBC57AB76, 0x1A20A0C2, + 0x8816EAF2, 0x2E61E146, 0x1F89FBDB, 0xB9FEF06F, 0x7C59CEE1, 0xDA2EC555, 0xEBC6DFC8, 0x4DB1D47C, + 0xBBF9A495, 0x1D8EAF21, 0x2C66B5BC, 0x8A11BE08, 0x4FB68086, 0xE9C18B32, 0xD82991AF, 0x7E5E9A1B, + 0xEFC8763C, 0x49BF7D88, 0x78576715, 0xDE206CA1, 0x1B87522F, 0xBDF0599B, 0x8C184306, 0x2A6F48B2, + 0xDC27385B, 0x7A5033EF, 0x4BB82972, 0xEDCF22C6, 0x28681C48, 0x8E1F17FC, 0xBFF70D61, 0x198006D5, + 0x47ABD36E, 0xE1DCD8DA, 0xD034C247, 0x7643C9F3, 0xB3E4F77D, 0x1593FCC9, 0x247BE654, 0x820CEDE0, + 0x74449D09, 0xD23396BD, 0xE3DB8C20, 0x45AC8794, 0x800BB91A, 0x267CB2AE, 0x1794A833, 0xB1E3A387, + 0x20754FA0, 0x86024414, 0xB7EA5E89, 0x119D553D, 0xD43A6BB3, 0x724D6007, 0x43A57A9A, 0xE5D2712E, + 0x139A01C7, 0xB5ED0A73, 0x840510EE, 0x22721B5A, 0xE7D525D4, 0x41A22E60, 0x704A34FD, 0xD63D3F49, + 0xCC1D9F8B, 0x6A6A943F, 0x5B828EA2, 0xFDF58516, 0x3852BB98, 0x9E25B02C, 0xAFCDAAB1, 0x09BAA105, + 0xFFF2D1EC, 0x5985DA58, 0x686DC0C5, 0xCE1ACB71, 0x0BBDF5FF, 0xADCAFE4B, 0x9C22E4D6, 0x3A55EF62, + 0xABC30345, 0x0DB408F1, 0x3C5C126C, 0x9A2B19D8, 0x5F8C2756, 0xF9FB2CE2, 0xC813367F, 0x6E643DCB, + 0x982C4D22, 0x3E5B4696, 0x0FB35C0B, 0xA9C457BF, 0x6C636931, 0xCA146285, 0xFBFC7818, 0x5D8B73AC, + 0x03A0A617, 0xA5D7ADA3, 0x943FB73E, 0x3248BC8A, 0xF7EF8204, 0x519889B0, 0x6070932D, 0xC6079899, + 0x304FE870, 0x9638E3C4, 0xA7D0F959, 0x01A7F2ED, 0xC400CC63, 0x6277C7D7, 0x539FDD4A, 0xF5E8D6FE, + 0x647E3AD9, 0xC209316D, 0xF3E12BF0, 0x55962044, 0x90311ECA, 0x3646157E, 0x07AE0FE3, 0xA1D90457, + 0x579174BE, 0xF1E67F0A, 0xC00E6597, 0x66796E23, 0xA3DE50AD, 0x05A95B19, 0x34414184, 0x92364A30 + ], + [ + 0x00000000, 0xCCAA009E, 0x4225077D, 0x8E8F07E3, 0x844A0EFA, 0x48E00E64, 0xC66F0987, 0x0AC50919, + 0xD3E51BB5, 0x1F4F1B2B, 0x91C01CC8, 0x5D6A1C56, 0x57AF154F, 0x9B0515D1, 0x158A1232, 0xD92012AC, + 0x7CBB312B, 0xB01131B5, 0x3E9E3656, 0xF23436C8, 0xF8F13FD1, 0x345B3F4F, 0xBAD438AC, 0x767E3832, + 0xAF5E2A9E, 0x63F42A00, 0xED7B2DE3, 0x21D12D7D, 0x2B142464, 0xE7BE24FA, 0x69312319, 0xA59B2387, + 0xF9766256, 0x35DC62C8, 0xBB53652B, 0x77F965B5, 0x7D3C6CAC, 0xB1966C32, 0x3F196BD1, 0xF3B36B4F, + 0x2A9379E3, 0xE639797D, 0x68B67E9E, 0xA41C7E00, 0xAED97719, 0x62737787, 0xECFC7064, 0x205670FA, + 0x85CD537D, 0x496753E3, 0xC7E85400, 0x0B42549E, 0x01875D87, 0xCD2D5D19, 0x43A25AFA, 0x8F085A64, + 0x562848C8, 0x9A824856, 0x140D4FB5, 0xD8A74F2B, 0xD2624632, 0x1EC846AC, 0x9047414F, 0x5CED41D1, + 0x299DC2ED, 0xE537C273, 0x6BB8C590, 0xA712C50E, 0xADD7CC17, 0x617DCC89, 0xEFF2CB6A, 0x2358CBF4, + 0xFA78D958, 0x36D2D9C6, 0xB85DDE25, 0x74F7DEBB, 0x7E32D7A2, 0xB298D73C, 0x3C17D0DF, 0xF0BDD041, + 0x5526F3C6, 0x998CF358, 0x1703F4BB, 0xDBA9F425, 0xD16CFD3C, 0x1DC6FDA2, 0x9349FA41, 0x5FE3FADF, + 0x86C3E873, 0x4A69E8ED, 0xC4E6EF0E, 0x084CEF90, 0x0289E689, 0xCE23E617, 0x40ACE1F4, 0x8C06E16A, + 0xD0EBA0BB, 0x1C41A025, 0x92CEA7C6, 0x5E64A758, 0x54A1AE41, 0x980BAEDF, 0x1684A93C, 0xDA2EA9A2, + 0x030EBB0E, 0xCFA4BB90, 0x412BBC73, 0x8D81BCED, 0x8744B5F4, 0x4BEEB56A, 0xC561B289, 0x09CBB217, + 0xAC509190, 0x60FA910E, 0xEE7596ED, 0x22DF9673, 0x281A9F6A, 0xE4B09FF4, 0x6A3F9817, 0xA6959889, + 0x7FB58A25, 0xB31F8ABB, 0x3D908D58, 0xF13A8DC6, 0xFBFF84DF, 0x37558441, 0xB9DA83A2, 0x7570833C, + 0x533B85DA, 0x9F918544, 0x111E82A7, 0xDDB48239, 0xD7718B20, 0x1BDB8BBE, 0x95548C5D, 0x59FE8CC3, + 0x80DE9E6F, 0x4C749EF1, 0xC2FB9912, 0x0E51998C, 0x04949095, 0xC83E900B, 0x46B197E8, 0x8A1B9776, + 0x2F80B4F1, 0xE32AB46F, 0x6DA5B38C, 0xA10FB312, 0xABCABA0B, 0x6760BA95, 0xE9EFBD76, 0x2545BDE8, + 0xFC65AF44, 0x30CFAFDA, 0xBE40A839, 0x72EAA8A7, 0x782FA1BE, 0xB485A120, 0x3A0AA6C3, 0xF6A0A65D, + 0xAA4DE78C, 0x66E7E712, 0xE868E0F1, 0x24C2E06F, 0x2E07E976, 0xE2ADE9E8, 0x6C22EE0B, 0xA088EE95, + 0x79A8FC39, 0xB502FCA7, 0x3B8DFB44, 0xF727FBDA, 0xFDE2F2C3, 0x3148F25D, 0xBFC7F5BE, 0x736DF520, + 0xD6F6D6A7, 0x1A5CD639, 0x94D3D1DA, 0x5879D144, 0x52BCD85D, 0x9E16D8C3, 0x1099DF20, 0xDC33DFBE, + 0x0513CD12, 0xC9B9CD8C, 0x4736CA6F, 0x8B9CCAF1, 0x8159C3E8, 0x4DF3C376, 0xC37CC495, 0x0FD6C40B, + 0x7AA64737, 0xB60C47A9, 0x3883404A, 0xF42940D4, 0xFEEC49CD, 0x32464953, 0xBCC94EB0, 0x70634E2E, + 0xA9435C82, 0x65E95C1C, 0xEB665BFF, 0x27CC5B61, 0x2D095278, 0xE1A352E6, 0x6F2C5505, 0xA386559B, + 0x061D761C, 0xCAB77682, 0x44387161, 0x889271FF, 0x825778E6, 0x4EFD7878, 0xC0727F9B, 0x0CD87F05, + 0xD5F86DA9, 0x19526D37, 0x97DD6AD4, 0x5B776A4A, 0x51B26353, 0x9D1863CD, 0x1397642E, 0xDF3D64B0, + 0x83D02561, 0x4F7A25FF, 0xC1F5221C, 0x0D5F2282, 0x079A2B9B, 0xCB302B05, 0x45BF2CE6, 0x89152C78, + 0x50353ED4, 0x9C9F3E4A, 0x121039A9, 0xDEBA3937, 0xD47F302E, 0x18D530B0, 0x965A3753, 0x5AF037CD, + 0xFF6B144A, 0x33C114D4, 0xBD4E1337, 0x71E413A9, 0x7B211AB0, 0xB78B1A2E, 0x39041DCD, 0xF5AE1D53, + 0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C, 0xA8C40105, 0x646E019B, 0xEAE10678, 0x264B06E6 + ] + ]; + + readonly uint _finalSeed; + readonly IntPtr _nativeContext; + readonly uint[][] _table; + readonly bool _useIso; + readonly bool _useNative; + uint _hashInt; + + /// Initializes the CRC32 table and seed as CRC32-ISO + public Crc32Context() + { + _hashInt = CRC32_ISO_SEED; + _finalSeed = CRC32_ISO_SEED; + _table = ISOCrc32Table; + _useIso = true; + + if(!Native.IsSupported) return; + + _nativeContext = crc32_init(); + _useNative = _nativeContext != IntPtr.Zero; + } + + /// Initializes the CRC32 table with a custom polynomial and seed + public Crc32Context(uint polynomial, uint seed) + { + _hashInt = seed; + _finalSeed = seed; + _useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED; + + if(Native.IsSupported && _useIso) + { + _nativeContext = crc32_init(); + _useNative = _nativeContext != IntPtr.Zero; + } + else + _table = GenerateTable(polynomial); + } + +#region IChecksum Members + + /// + public string Name => Localization.CRC32_Name; + + /// + public Guid Id => new("BCC4E18A-79CD-4B52-8A57-2B599E5176B3"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) => + Step(ref _hashInt, _table, data, len, _useIso, _useNative, _nativeContext); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + uint crc = _hashInt ^ _finalSeed; + + if(!_useNative || !_useIso) return BigEndianBitConverter.GetBytes(crc); + + crc32_final(_nativeContext, ref crc); + crc32_free(_nativeContext); + + return BigEndianBitConverter.GetBytes(crc); + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + uint crc = _hashInt ^ _finalSeed; + + var crc32Output = new StringBuilder(); + + if(_useNative && _useIso) + { + crc32_final(_nativeContext, ref crc); + crc32_free(_nativeContext); + } + + for(var i = 0; i < BigEndianBitConverter.GetBytes(crc).Length; i++) + crc32Output.Append(BigEndianBitConverter.GetBytes(crc)[i].ToString("x2")); + + return crc32Output.ToString(); + } + +#endregion + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial IntPtr crc32_init(); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int crc32_update(IntPtr ctx, byte[] data, uint len); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int crc32_final(IntPtr ctx, ref uint crc); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial void crc32_free(IntPtr ctx); + + static uint[][] GenerateTable(uint polynomial) + { + var table = new uint[8][]; + + for(var i = 0; i < 8; i++) table[i] = new uint[256]; + + for(var i = 0; i < 256; i++) + { + var entry = (uint)i; + + for(var j = 0; j < 8; j++) + { + if((entry & 1) == 1) + entry = entry >> 1 ^ polynomial; + else + entry >>= 1; + } + + table[0][i] = entry; + } + + for(var slice = 1; slice < 8; slice++) + { + for(var i = 0; i < 256; i++) + table[slice][i] = table[slice - 1][i] >> 8 ^ table[0][table[slice - 1][i] & 0xFF]; + } + + return table; + } + + static void Step(ref uint previousCrc, uint[][] table, byte[] data, uint len, bool useIso, bool useNative, + IntPtr nativeContext) + { + if(useNative && useIso) + { + crc32_update(nativeContext, data, len); + + return; + } + + var currentPos = 0; + + if(useIso) + { + if(Pclmulqdq.IsSupported && Sse41.IsSupported && Ssse3.IsSupported && Sse2.IsSupported) + { + // Only works in blocks of 16 bytes + uint blocks = len / 64; + + if(blocks > 0) + { + previousCrc = ~Clmul.Step(data, blocks * 64, ~previousCrc); + + currentPos = (int)(blocks * 64); + len -= blocks * 64; + } + + if(len == 0) return; + } + + if(Crc32.Arm64.IsSupported) + { + previousCrc = ArmSimd.Step64(data, len, previousCrc); + + return; + } + + if(Crc32.IsSupported) + { + previousCrc = ArmSimd.Step32(data, len, previousCrc); + + return; + } + } + + // Unroll according to Intel slicing by uint8_t + // http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf + // http://sourceforge.net/projects/slicing-by-8/ + const int unroll = 4; + const int bytesAtOnce = 8 * unroll; + uint crc = previousCrc; + + while(len >= bytesAtOnce) + { + int unrolling; + + for(unrolling = 0; unrolling < unroll; unrolling++) + { + uint one = BitConverter.ToUInt32(data, currentPos) ^ crc; + currentPos += 4; + var two = BitConverter.ToUInt32(data, currentPos); + currentPos += 4; + + crc = table[0][two >> 24 & 0xFF] ^ + table[1][two >> 16 & 0xFF] ^ + table[2][two >> 8 & 0xFF] ^ + table[3][two & 0xFF] ^ + table[4][one >> 24 & 0xFF] ^ + table[5][one >> 16 & 0xFF] ^ + table[6][one >> 8 & 0xFF] ^ + table[7][one & 0xFF]; + } + + len -= bytesAtOnce; + } + + while(len-- != 0) crc = crc >> 8 ^ table[0][crc & 0xFF ^ data[currentPos++]]; + + previousCrc = crc; + } + + /// Gets the hash of a file + /// File path. + + // ReSharper disable once ReturnTypeCanBeEnumerable.Global + public static byte[] File(string filename) + { + File(filename, out byte[] hash); + + return hash; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) => + File(filename, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED); + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + /// CRC polynomial + /// CRC seed + public static string File(string filename, out byte[] hash, uint polynomial, uint seed) + { + bool useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED; + bool useNative = Native.IsSupported; + IntPtr nativeContext = IntPtr.Zero; + + if(useNative && useIso) + { + nativeContext = crc32_init(); + useNative = nativeContext != IntPtr.Zero; + } + + var fileStream = new FileStream(filename, FileMode.Open); + + uint localHashInt = seed; + + uint[][] localTable = GenerateTable(polynomial); + + var buffer = new byte[65536]; + int read = fileStream.EnsureRead(buffer, 0, 65536); + + while(read > 0) + { + Step(ref localHashInt, localTable, buffer, (uint)read, useIso, useNative, nativeContext); + + read = fileStream.EnsureRead(buffer, 0, 65536); + } + + localHashInt ^= seed; + + if(useNative && useIso) + { + crc32_final(nativeContext, ref localHashInt); + crc32_free(nativeContext); + } + + hash = BigEndianBitConverter.GetBytes(localHashInt); + + var crc32Output = new StringBuilder(); + + foreach(byte h in hash) crc32Output.Append(h.ToString("x2")); + + fileStream.Close(); + + return crc32Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) => + Data(data, len, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED); + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + /// CRC polynomial + /// CRC seed + public static string Data(byte[] data, uint len, out byte[] hash, uint polynomial, uint seed) + { + bool useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED; + bool useNative = Native.IsSupported; + IntPtr nativeContext = IntPtr.Zero; + + if(useNative && useIso) + { + nativeContext = crc32_init(); + useNative = nativeContext != IntPtr.Zero; + } + + uint localHashInt = seed; + + uint[][] localTable = GenerateTable(polynomial); + + Step(ref localHashInt, localTable, data, len, useIso, useNative, nativeContext); + + localHashInt ^= seed; + + if(useNative && useIso) + { + crc32_final(nativeContext, ref localHashInt); + crc32_free(nativeContext); + } + + hash = BigEndianBitConverter.GetBytes(localHashInt); + + var crc32Output = new StringBuilder(); + + foreach(byte h in hash) crc32Output.Append(h.ToString("x2")); + + return crc32Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} \ No newline at end of file diff --git a/Aaru.Checksums/CRC64/clmul.cs b/Aaru.Checksums/CRC64/clmul.cs new file mode 100644 index 000000000..018861e48 --- /dev/null +++ b/Aaru.Checksums/CRC64/clmul.cs @@ -0,0 +1,122 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : clmul.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Compute the CRC64 using a parallelized folding approach with the PCLMULQDQ +// instruction. +// +// --[ License ] -------------------------------------------------------------- +// +// This file is under the public domain: +// https://github.com/rawrunprotected/crc +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace Aaru.Checksums.CRC64; + +static class Clmul +{ + static readonly byte[] _shuffleMasks = + [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x8f, 0x8e, + 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80 + ]; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static void ShiftRight128(Vector128 initial, uint n, out Vector128 outLeft, + out Vector128 outRight) + { + uint maskPos = 16 - n; + + var maskA = Vector128.Create(_shuffleMasks[maskPos], + _shuffleMasks[maskPos + 1], + _shuffleMasks[maskPos + 2], + _shuffleMasks[maskPos + 3], + _shuffleMasks[maskPos + 4], + _shuffleMasks[maskPos + 5], + _shuffleMasks[maskPos + 6], + _shuffleMasks[maskPos + 7], + _shuffleMasks[maskPos + 8], + _shuffleMasks[maskPos + 9], + _shuffleMasks[maskPos + 10], + _shuffleMasks[maskPos + 11], + _shuffleMasks[maskPos + 12], + _shuffleMasks[maskPos + 13], + _shuffleMasks[maskPos + 14], + _shuffleMasks[maskPos + 15]); + + Vector128 maskB = Sse2.Xor(maskA, Sse2.CompareEqual(Vector128.Zero, Vector128.Zero)); + + outLeft = Ssse3.Shuffle(initial.AsByte(), maskB).AsUInt64(); + outRight = Ssse3.Shuffle(initial.AsByte(), maskA).AsUInt64(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static Vector128 Fold(Vector128 input, Vector128 foldConstants) => + Sse2.Xor(Pclmulqdq.CarrylessMultiply(input, foldConstants, 0x00), + Pclmulqdq.CarrylessMultiply(input, foldConstants, 0x11)); + + internal static ulong Step(ulong crc, byte[] data, uint length) + { + var bufPos = 16; + const ulong k1 = 0xe05dd497ca393ae4; + const ulong k2 = 0xdabe95afc7875f40; + const ulong mu = 0x9c3e466c172963d5; + const ulong pol = 0x92d8af2baf0e1e85; + var foldConstants1 = Vector128.Create(k1, k2); + var foldConstants2 = Vector128.Create(mu, pol); + var initialCrc = Vector128.Create(~crc, 0); + length -= 16; + + // Initial CRC can simply be added to data + ShiftRight128(initialCrc, 0, out Vector128 crc0, out Vector128 crc1); + + Vector128 accumulator = + Sse2.Xor(Fold(Sse2.Xor(crc0, + Vector128.Create(BitConverter.ToUInt64(data, 0), BitConverter.ToUInt64(data, 8))), + foldConstants1), + crc1); + + while(length >= 32) + { + accumulator = + Fold(Sse2.Xor(Vector128.Create(BitConverter.ToUInt64(data, bufPos), + BitConverter.ToUInt64(data, bufPos + 8)), + accumulator), + foldConstants1); + + length -= 16; + bufPos += 16; + } + + Vector128 p = Sse2.Xor(accumulator, + Vector128.Create(BitConverter.ToUInt64(data, bufPos), + BitConverter.ToUInt64(data, bufPos + 8))); + + Vector128 r = Sse2.Xor(Pclmulqdq.CarrylessMultiply(p, foldConstants1, 0x10), + Sse2.ShiftRightLogical128BitLane(p, 8)); + + // Final Barrett reduction + Vector128 t1 = Pclmulqdq.CarrylessMultiply(r, foldConstants2, 0x00); + + Vector128 t2 = Sse2.Xor(Sse2.Xor(Pclmulqdq.CarrylessMultiply(t1, foldConstants2, 0x10), + Sse2.ShiftLeftLogical128BitLane(t1, 8)), + r); + + return ~((ulong)Sse41.Extract(t2.AsUInt32(), 3) << 32 | Sse41.Extract(t2.AsUInt32(), 2)); + } +} \ No newline at end of file diff --git a/Aaru.Checksums/CRC64Context.cs b/Aaru.Checksums/CRC64Context.cs new file mode 100644 index 000000000..e0572eaa5 --- /dev/null +++ b/Aaru.Checksums/CRC64Context.cs @@ -0,0 +1,594 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CRC64Context.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Implements a CRC64 algorithm. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +using System.Text; +using Aaru.Checksums.CRC64; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; + +namespace Aaru.Checksums; + +/// +/// Implements a CRC64 algorithm +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +public sealed partial class Crc64Context : IChecksum +{ + /// ECMA CRC64 polynomial + const ulong CRC64_ECMA_POLY = 0xC96C5795D7870F42; + /// ECMA CRC64 seed + const ulong CRC64_ECMA_SEED = 0xFFFFFFFFFFFFFFFF; + + static readonly ulong[][] _ecmaCrc64Table = + [ + [ + 0x0000000000000000, 0xB32E4CBE03A75F6F, 0xF4843657A840A05B, 0x47AA7AE9ABE7FF34, 0x7BD0C384FF8F5E33, + 0xC8FE8F3AFC28015C, 0x8F54F5D357CFFE68, 0x3C7AB96D5468A107, 0xF7A18709FF1EBC66, 0x448FCBB7FCB9E309, + 0x0325B15E575E1C3D, 0xB00BFDE054F94352, 0x8C71448D0091E255, 0x3F5F08330336BD3A, 0x78F572DAA8D1420E, + 0xCBDB3E64AB761D61, 0x7D9BA13851336649, 0xCEB5ED8652943926, 0x891F976FF973C612, 0x3A31DBD1FAD4997D, + 0x064B62BCAEBC387A, 0xB5652E02AD1B6715, 0xF2CF54EB06FC9821, 0x41E11855055BC74E, 0x8A3A2631AE2DDA2F, + 0x39146A8FAD8A8540, 0x7EBE1066066D7A74, 0xCD905CD805CA251B, 0xF1EAE5B551A2841C, 0x42C4A90B5205DB73, + 0x056ED3E2F9E22447, 0xB6409F5CFA457B28, 0xFB374270A266CC92, 0x48190ECEA1C193FD, 0x0FB374270A266CC9, + 0xBC9D3899098133A6, 0x80E781F45DE992A1, 0x33C9CD4A5E4ECDCE, 0x7463B7A3F5A932FA, 0xC74DFB1DF60E6D95, + 0x0C96C5795D7870F4, 0xBFB889C75EDF2F9B, 0xF812F32EF538D0AF, 0x4B3CBF90F69F8FC0, 0x774606FDA2F72EC7, + 0xC4684A43A15071A8, 0x83C230AA0AB78E9C, 0x30EC7C140910D1F3, 0x86ACE348F355AADB, 0x3582AFF6F0F2F5B4, + 0x7228D51F5B150A80, 0xC10699A158B255EF, 0xFD7C20CC0CDAF4E8, 0x4E526C720F7DAB87, 0x09F8169BA49A54B3, + 0xBAD65A25A73D0BDC, 0x710D64410C4B16BD, 0xC22328FF0FEC49D2, 0x85895216A40BB6E6, 0x36A71EA8A7ACE989, + 0x0ADDA7C5F3C4488E, 0xB9F3EB7BF06317E1, 0xFE5991925B84E8D5, 0x4D77DD2C5823B7BA, 0x64B62BCAEBC387A1, + 0xD7986774E864D8CE, 0x90321D9D438327FA, 0x231C512340247895, 0x1F66E84E144CD992, 0xAC48A4F017EB86FD, + 0xEBE2DE19BC0C79C9, 0x58CC92A7BFAB26A6, 0x9317ACC314DD3BC7, 0x2039E07D177A64A8, 0x67939A94BC9D9B9C, + 0xD4BDD62ABF3AC4F3, 0xE8C76F47EB5265F4, 0x5BE923F9E8F53A9B, 0x1C4359104312C5AF, 0xAF6D15AE40B59AC0, + 0x192D8AF2BAF0E1E8, 0xAA03C64CB957BE87, 0xEDA9BCA512B041B3, 0x5E87F01B11171EDC, 0x62FD4976457FBFDB, + 0xD1D305C846D8E0B4, 0x96797F21ED3F1F80, 0x2557339FEE9840EF, 0xEE8C0DFB45EE5D8E, 0x5DA24145464902E1, + 0x1A083BACEDAEFDD5, 0xA9267712EE09A2BA, 0x955CCE7FBA6103BD, 0x267282C1B9C65CD2, 0x61D8F8281221A3E6, + 0xD2F6B4961186FC89, 0x9F8169BA49A54B33, 0x2CAF25044A02145C, 0x6B055FEDE1E5EB68, 0xD82B1353E242B407, + 0xE451AA3EB62A1500, 0x577FE680B58D4A6F, 0x10D59C691E6AB55B, 0xA3FBD0D71DCDEA34, 0x6820EEB3B6BBF755, + 0xDB0EA20DB51CA83A, 0x9CA4D8E41EFB570E, 0x2F8A945A1D5C0861, 0x13F02D374934A966, 0xA0DE61894A93F609, + 0xE7741B60E174093D, 0x545A57DEE2D35652, 0xE21AC88218962D7A, 0x5134843C1B317215, 0x169EFED5B0D68D21, + 0xA5B0B26BB371D24E, 0x99CA0B06E7197349, 0x2AE447B8E4BE2C26, 0x6D4E3D514F59D312, 0xDE6071EF4CFE8C7D, + 0x15BB4F8BE788911C, 0xA6950335E42FCE73, 0xE13F79DC4FC83147, 0x521135624C6F6E28, 0x6E6B8C0F1807CF2F, + 0xDD45C0B11BA09040, 0x9AEFBA58B0476F74, 0x29C1F6E6B3E0301B, 0xC96C5795D7870F42, 0x7A421B2BD420502D, + 0x3DE861C27FC7AF19, 0x8EC62D7C7C60F076, 0xB2BC941128085171, 0x0192D8AF2BAF0E1E, 0x4638A2468048F12A, + 0xF516EEF883EFAE45, 0x3ECDD09C2899B324, 0x8DE39C222B3EEC4B, 0xCA49E6CB80D9137F, 0x7967AA75837E4C10, + 0x451D1318D716ED17, 0xF6335FA6D4B1B278, 0xB199254F7F564D4C, 0x02B769F17CF11223, 0xB4F7F6AD86B4690B, + 0x07D9BA1385133664, 0x4073C0FA2EF4C950, 0xF35D8C442D53963F, 0xCF273529793B3738, 0x7C0979977A9C6857, + 0x3BA3037ED17B9763, 0x888D4FC0D2DCC80C, 0x435671A479AAD56D, 0xF0783D1A7A0D8A02, 0xB7D247F3D1EA7536, + 0x04FC0B4DD24D2A59, 0x3886B22086258B5E, 0x8BA8FE9E8582D431, 0xCC0284772E652B05, 0x7F2CC8C92DC2746A, + 0x325B15E575E1C3D0, 0x8175595B76469CBF, 0xC6DF23B2DDA1638B, 0x75F16F0CDE063CE4, 0x498BD6618A6E9DE3, + 0xFAA59ADF89C9C28C, 0xBD0FE036222E3DB8, 0x0E21AC88218962D7, 0xC5FA92EC8AFF7FB6, 0x76D4DE52895820D9, + 0x317EA4BB22BFDFED, 0x8250E80521188082, 0xBE2A516875702185, 0x0D041DD676D77EEA, 0x4AAE673FDD3081DE, + 0xF9802B81DE97DEB1, 0x4FC0B4DD24D2A599, 0xFCEEF8632775FAF6, 0xBB44828A8C9205C2, 0x086ACE348F355AAD, + 0x34107759DB5DFBAA, 0x873E3BE7D8FAA4C5, 0xC094410E731D5BF1, 0x73BA0DB070BA049E, 0xB86133D4DBCC19FF, + 0x0B4F7F6AD86B4690, 0x4CE50583738CB9A4, 0xFFCB493D702BE6CB, 0xC3B1F050244347CC, 0x709FBCEE27E418A3, + 0x3735C6078C03E797, 0x841B8AB98FA4B8F8, 0xADDA7C5F3C4488E3, 0x1EF430E13FE3D78C, 0x595E4A08940428B8, + 0xEA7006B697A377D7, 0xD60ABFDBC3CBD6D0, 0x6524F365C06C89BF, 0x228E898C6B8B768B, 0x91A0C532682C29E4, + 0x5A7BFB56C35A3485, 0xE955B7E8C0FD6BEA, 0xAEFFCD016B1A94DE, 0x1DD181BF68BDCBB1, 0x21AB38D23CD56AB6, + 0x9285746C3F7235D9, 0xD52F0E859495CAED, 0x6601423B97329582, 0xD041DD676D77EEAA, 0x636F91D96ED0B1C5, + 0x24C5EB30C5374EF1, 0x97EBA78EC690119E, 0xAB911EE392F8B099, 0x18BF525D915FEFF6, 0x5F1528B43AB810C2, + 0xEC3B640A391F4FAD, 0x27E05A6E926952CC, 0x94CE16D091CE0DA3, 0xD3646C393A29F297, 0x604A2087398EADF8, + 0x5C3099EA6DE60CFF, 0xEF1ED5546E415390, 0xA8B4AFBDC5A6ACA4, 0x1B9AE303C601F3CB, 0x56ED3E2F9E224471, + 0xE5C372919D851B1E, 0xA26908783662E42A, 0x114744C635C5BB45, 0x2D3DFDAB61AD1A42, 0x9E13B115620A452D, + 0xD9B9CBFCC9EDBA19, 0x6A978742CA4AE576, 0xA14CB926613CF817, 0x1262F598629BA778, 0x55C88F71C97C584C, + 0xE6E6C3CFCADB0723, 0xDA9C7AA29EB3A624, 0x69B2361C9D14F94B, 0x2E184CF536F3067F, 0x9D36004B35545910, + 0x2B769F17CF112238, 0x9858D3A9CCB67D57, 0xDFF2A94067518263, 0x6CDCE5FE64F6DD0C, 0x50A65C93309E7C0B, + 0xE388102D33392364, 0xA4226AC498DEDC50, 0x170C267A9B79833F, 0xDCD7181E300F9E5E, 0x6FF954A033A8C131, + 0x28532E49984F3E05, 0x9B7D62F79BE8616A, 0xA707DB9ACF80C06D, 0x14299724CC279F02, 0x5383EDCD67C06036, + 0xE0ADA17364673F59 + ], + [ + 0x0000000000000000, 0x54E979925CD0F10D, 0xA9D2F324B9A1E21A, 0xFD3B8AB6E5711317, 0xC17D4962DC4DDAB1, + 0x959430F0809D2BBC, 0x68AFBA4665EC38AB, 0x3C46C3D4393CC9A6, 0x10223DEE1795ABE7, 0x44CB447C4B455AEA, + 0xB9F0CECAAE3449FD, 0xED19B758F2E4B8F0, 0xD15F748CCBD87156, 0x85B60D1E9708805B, 0x788D87A87279934C, + 0x2C64FE3A2EA96241, 0x20447BDC2F2B57CE, 0x74AD024E73FBA6C3, 0x899688F8968AB5D4, 0xDD7FF16ACA5A44D9, + 0xE13932BEF3668D7F, 0xB5D04B2CAFB67C72, 0x48EBC19A4AC76F65, 0x1C02B80816179E68, 0x3066463238BEFC29, + 0x648F3FA0646E0D24, 0x99B4B516811F1E33, 0xCD5DCC84DDCFEF3E, 0xF11B0F50E4F32698, 0xA5F276C2B823D795, + 0x58C9FC745D52C482, 0x0C2085E60182358F, 0x4088F7B85E56AF9C, 0x14618E2A02865E91, 0xE95A049CE7F74D86, + 0xBDB37D0EBB27BC8B, 0x81F5BEDA821B752D, 0xD51CC748DECB8420, 0x28274DFE3BBA9737, 0x7CCE346C676A663A, + 0x50AACA5649C3047B, 0x0443B3C41513F576, 0xF9783972F062E661, 0xAD9140E0ACB2176C, 0x91D78334958EDECA, + 0xC53EFAA6C95E2FC7, 0x380570102C2F3CD0, 0x6CEC098270FFCDDD, 0x60CC8C64717DF852, 0x3425F5F62DAD095F, + 0xC91E7F40C8DC1A48, 0x9DF706D2940CEB45, 0xA1B1C506AD3022E3, 0xF558BC94F1E0D3EE, 0x086336221491C0F9, + 0x5C8A4FB0484131F4, 0x70EEB18A66E853B5, 0x2407C8183A38A2B8, 0xD93C42AEDF49B1AF, 0x8DD53B3C839940A2, + 0xB193F8E8BAA58904, 0xE57A817AE6757809, 0x18410BCC03046B1E, 0x4CA8725E5FD49A13, 0x8111EF70BCAD5F38, + 0xD5F896E2E07DAE35, 0x28C31C54050CBD22, 0x7C2A65C659DC4C2F, 0x406CA61260E08589, 0x1485DF803C307484, + 0xE9BE5536D9416793, 0xBD572CA48591969E, 0x9133D29EAB38F4DF, 0xC5DAAB0CF7E805D2, 0x38E121BA129916C5, + 0x6C0858284E49E7C8, 0x504E9BFC77752E6E, 0x04A7E26E2BA5DF63, 0xF99C68D8CED4CC74, 0xAD75114A92043D79, + 0xA15594AC938608F6, 0xF5BCED3ECF56F9FB, 0x088767882A27EAEC, 0x5C6E1E1A76F71BE1, 0x6028DDCE4FCBD247, + 0x34C1A45C131B234A, 0xC9FA2EEAF66A305D, 0x9D135778AABAC150, 0xB177A9428413A311, 0xE59ED0D0D8C3521C, + 0x18A55A663DB2410B, 0x4C4C23F46162B006, 0x700AE020585E79A0, 0x24E399B2048E88AD, 0xD9D81304E1FF9BBA, + 0x8D316A96BD2F6AB7, 0xC19918C8E2FBF0A4, 0x9570615ABE2B01A9, 0x684BEBEC5B5A12BE, 0x3CA2927E078AE3B3, + 0x00E451AA3EB62A15, 0x540D28386266DB18, 0xA936A28E8717C80F, 0xFDDFDB1CDBC73902, 0xD1BB2526F56E5B43, + 0x85525CB4A9BEAA4E, 0x7869D6024CCFB959, 0x2C80AF90101F4854, 0x10C66C44292381F2, 0x442F15D675F370FF, + 0xB9149F60908263E8, 0xEDFDE6F2CC5292E5, 0xE1DD6314CDD0A76A, 0xB5341A8691005667, 0x480F903074714570, + 0x1CE6E9A228A1B47D, 0x20A02A76119D7DDB, 0x744953E44D4D8CD6, 0x8972D952A83C9FC1, 0xDD9BA0C0F4EC6ECC, + 0xF1FF5EFADA450C8D, 0xA51627688695FD80, 0x582DADDE63E4EE97, 0x0CC4D44C3F341F9A, 0x308217980608D63C, + 0x646B6E0A5AD82731, 0x9950E4BCBFA93426, 0xCDB99D2EE379C52B, 0x90FB71CAD654A0F5, 0xC41208588A8451F8, + 0x392982EE6FF542EF, 0x6DC0FB7C3325B3E2, 0x518638A80A197A44, 0x056F413A56C98B49, 0xF854CB8CB3B8985E, + 0xACBDB21EEF686953, 0x80D94C24C1C10B12, 0xD43035B69D11FA1F, 0x290BBF007860E908, 0x7DE2C69224B01805, + 0x41A405461D8CD1A3, 0x154D7CD4415C20AE, 0xE876F662A42D33B9, 0xBC9F8FF0F8FDC2B4, 0xB0BF0A16F97FF73B, + 0xE4567384A5AF0636, 0x196DF93240DE1521, 0x4D8480A01C0EE42C, 0x71C2437425322D8A, 0x252B3AE679E2DC87, + 0xD810B0509C93CF90, 0x8CF9C9C2C0433E9D, 0xA09D37F8EEEA5CDC, 0xF4744E6AB23AADD1, 0x094FC4DC574BBEC6, + 0x5DA6BD4E0B9B4FCB, 0x61E07E9A32A7866D, 0x350907086E777760, 0xC8328DBE8B066477, 0x9CDBF42CD7D6957A, + 0xD073867288020F69, 0x849AFFE0D4D2FE64, 0x79A1755631A3ED73, 0x2D480CC46D731C7E, 0x110ECF10544FD5D8, + 0x45E7B682089F24D5, 0xB8DC3C34EDEE37C2, 0xEC3545A6B13EC6CF, 0xC051BB9C9F97A48E, 0x94B8C20EC3475583, + 0x698348B826364694, 0x3D6A312A7AE6B799, 0x012CF2FE43DA7E3F, 0x55C58B6C1F0A8F32, 0xA8FE01DAFA7B9C25, + 0xFC177848A6AB6D28, 0xF037FDAEA72958A7, 0xA4DE843CFBF9A9AA, 0x59E50E8A1E88BABD, 0x0D0C771842584BB0, + 0x314AB4CC7B648216, 0x65A3CD5E27B4731B, 0x989847E8C2C5600C, 0xCC713E7A9E159101, 0xE015C040B0BCF340, + 0xB4FCB9D2EC6C024D, 0x49C73364091D115A, 0x1D2E4AF655CDE057, 0x216889226CF129F1, 0x7581F0B03021D8FC, + 0x88BA7A06D550CBEB, 0xDC53039489803AE6, 0x11EA9EBA6AF9FFCD, 0x4503E72836290EC0, 0xB8386D9ED3581DD7, + 0xECD1140C8F88ECDA, 0xD097D7D8B6B4257C, 0x847EAE4AEA64D471, 0x794524FC0F15C766, 0x2DAC5D6E53C5366B, + 0x01C8A3547D6C542A, 0x5521DAC621BCA527, 0xA81A5070C4CDB630, 0xFCF329E2981D473D, 0xC0B5EA36A1218E9B, + 0x945C93A4FDF17F96, 0x6967191218806C81, 0x3D8E608044509D8C, 0x31AEE56645D2A803, 0x65479CF41902590E, + 0x987C1642FC734A19, 0xCC956FD0A0A3BB14, 0xF0D3AC04999F72B2, 0xA43AD596C54F83BF, 0x59015F20203E90A8, + 0x0DE826B27CEE61A5, 0x218CD888524703E4, 0x7565A11A0E97F2E9, 0x885E2BACEBE6E1FE, 0xDCB7523EB73610F3, + 0xE0F191EA8E0AD955, 0xB418E878D2DA2858, 0x492362CE37AB3B4F, 0x1DCA1B5C6B7BCA42, 0x5162690234AF5051, + 0x058B1090687FA15C, 0xF8B09A268D0EB24B, 0xAC59E3B4D1DE4346, 0x901F2060E8E28AE0, 0xC4F659F2B4327BED, + 0x39CDD344514368FA, 0x6D24AAD60D9399F7, 0x414054EC233AFBB6, 0x15A92D7E7FEA0ABB, 0xE892A7C89A9B19AC, + 0xBC7BDE5AC64BE8A1, 0x803D1D8EFF772107, 0xD4D4641CA3A7D00A, 0x29EFEEAA46D6C31D, 0x7D0697381A063210, + 0x712612DE1B84079F, 0x25CF6B4C4754F692, 0xD8F4E1FAA225E585, 0x8C1D9868FEF51488, 0xB05B5BBCC7C9DD2E, + 0xE4B2222E9B192C23, 0x1989A8987E683F34, 0x4D60D10A22B8CE39, 0x61042F300C11AC78, 0x35ED56A250C15D75, + 0xC8D6DC14B5B04E62, 0x9C3FA586E960BF6F, 0xA0796652D05C76C9, 0xF4901FC08C8C87C4, 0x09AB957669FD94D3, + 0x5D42ECE4352D65DE + ], + [ + 0x0000000000000000, 0x3F0BE14A916A6DCB, 0x7E17C29522D4DB96, 0x411C23DFB3BEB65D, 0xFC2F852A45A9B72C, + 0xC3246460D4C3DAE7, 0x823847BF677D6CBA, 0xBD33A6F5F6170171, 0x6A87A57F245D70DD, 0x558C4435B5371D16, + 0x149067EA0689AB4B, 0x2B9B86A097E3C680, 0x96A8205561F4C7F1, 0xA9A3C11FF09EAA3A, 0xE8BFE2C043201C67, + 0xD7B4038AD24A71AC, 0xD50F4AFE48BAE1BA, 0xEA04ABB4D9D08C71, 0xAB18886B6A6E3A2C, 0x94136921FB0457E7, + 0x2920CFD40D135696, 0x162B2E9E9C793B5D, 0x57370D412FC78D00, 0x683CEC0BBEADE0CB, 0xBF88EF816CE79167, + 0x80830ECBFD8DFCAC, 0xC19F2D144E334AF1, 0xFE94CC5EDF59273A, 0x43A76AAB294E264B, 0x7CAC8BE1B8244B80, + 0x3DB0A83E0B9AFDDD, 0x02BB49749AF09016, 0x38C63AD73E7BDDF1, 0x07CDDB9DAF11B03A, 0x46D1F8421CAF0667, + 0x79DA19088DC56BAC, 0xC4E9BFFD7BD26ADD, 0xFBE25EB7EAB80716, 0xBAFE7D685906B14B, 0x85F59C22C86CDC80, + 0x52419FA81A26AD2C, 0x6D4A7EE28B4CC0E7, 0x2C565D3D38F276BA, 0x135DBC77A9981B71, 0xAE6E1A825F8F1A00, + 0x9165FBC8CEE577CB, 0xD079D8177D5BC196, 0xEF72395DEC31AC5D, 0xEDC9702976C13C4B, 0xD2C29163E7AB5180, + 0x93DEB2BC5415E7DD, 0xACD553F6C57F8A16, 0x11E6F50333688B67, 0x2EED1449A202E6AC, 0x6FF1379611BC50F1, + 0x50FAD6DC80D63D3A, 0x874ED556529C4C96, 0xB845341CC3F6215D, 0xF95917C370489700, 0xC652F689E122FACB, + 0x7B61507C1735FBBA, 0x446AB136865F9671, 0x057692E935E1202C, 0x3A7D73A3A48B4DE7, 0x718C75AE7CF7BBE2, + 0x4E8794E4ED9DD629, 0x0F9BB73B5E236074, 0x30905671CF490DBF, 0x8DA3F084395E0CCE, 0xB2A811CEA8346105, + 0xF3B432111B8AD758, 0xCCBFD35B8AE0BA93, 0x1B0BD0D158AACB3F, 0x2400319BC9C0A6F4, 0x651C12447A7E10A9, + 0x5A17F30EEB147D62, 0xE72455FB1D037C13, 0xD82FB4B18C6911D8, 0x9933976E3FD7A785, 0xA6387624AEBDCA4E, + 0xA4833F50344D5A58, 0x9B88DE1AA5273793, 0xDA94FDC5169981CE, 0xE59F1C8F87F3EC05, 0x58ACBA7A71E4ED74, + 0x67A75B30E08E80BF, 0x26BB78EF533036E2, 0x19B099A5C25A5B29, 0xCE049A2F10102A85, 0xF10F7B65817A474E, + 0xB01358BA32C4F113, 0x8F18B9F0A3AE9CD8, 0x322B1F0555B99DA9, 0x0D20FE4FC4D3F062, 0x4C3CDD90776D463F, + 0x73373CDAE6072BF4, 0x494A4F79428C6613, 0x7641AE33D3E60BD8, 0x375D8DEC6058BD85, 0x08566CA6F132D04E, + 0xB565CA530725D13F, 0x8A6E2B19964FBCF4, 0xCB7208C625F10AA9, 0xF479E98CB49B6762, 0x23CDEA0666D116CE, + 0x1CC60B4CF7BB7B05, 0x5DDA28934405CD58, 0x62D1C9D9D56FA093, 0xDFE26F2C2378A1E2, 0xE0E98E66B212CC29, + 0xA1F5ADB901AC7A74, 0x9EFE4CF390C617BF, 0x9C4505870A3687A9, 0xA34EE4CD9B5CEA62, 0xE252C71228E25C3F, + 0xDD592658B98831F4, 0x606A80AD4F9F3085, 0x5F6161E7DEF55D4E, 0x1E7D42386D4BEB13, 0x2176A372FC2186D8, + 0xF6C2A0F82E6BF774, 0xC9C941B2BF019ABF, 0x88D5626D0CBF2CE2, 0xB7DE83279DD54129, 0x0AED25D26BC24058, + 0x35E6C498FAA82D93, 0x74FAE74749169BCE, 0x4BF1060DD87CF605, 0xE318EB5CF9EF77C4, 0xDC130A1668851A0F, + 0x9D0F29C9DB3BAC52, 0xA204C8834A51C199, 0x1F376E76BC46C0E8, 0x203C8F3C2D2CAD23, 0x6120ACE39E921B7E, + 0x5E2B4DA90FF876B5, 0x899F4E23DDB20719, 0xB694AF694CD86AD2, 0xF7888CB6FF66DC8F, 0xC8836DFC6E0CB144, + 0x75B0CB09981BB035, 0x4ABB2A430971DDFE, 0x0BA7099CBACF6BA3, 0x34ACE8D62BA50668, 0x3617A1A2B155967E, + 0x091C40E8203FFBB5, 0x4800633793814DE8, 0x770B827D02EB2023, 0xCA382488F4FC2152, 0xF533C5C265964C99, + 0xB42FE61DD628FAC4, 0x8B2407574742970F, 0x5C9004DD9508E6A3, 0x639BE59704628B68, 0x2287C648B7DC3D35, + 0x1D8C270226B650FE, 0xA0BF81F7D0A1518F, 0x9FB460BD41CB3C44, 0xDEA84362F2758A19, 0xE1A3A228631FE7D2, + 0xDBDED18BC794AA35, 0xE4D530C156FEC7FE, 0xA5C9131EE54071A3, 0x9AC2F254742A1C68, 0x27F154A1823D1D19, + 0x18FAB5EB135770D2, 0x59E69634A0E9C68F, 0x66ED777E3183AB44, 0xB15974F4E3C9DAE8, 0x8E5295BE72A3B723, + 0xCF4EB661C11D017E, 0xF045572B50776CB5, 0x4D76F1DEA6606DC4, 0x727D1094370A000F, 0x3361334B84B4B652, + 0x0C6AD20115DEDB99, 0x0ED19B758F2E4B8F, 0x31DA7A3F1E442644, 0x70C659E0ADFA9019, 0x4FCDB8AA3C90FDD2, + 0xF2FE1E5FCA87FCA3, 0xCDF5FF155BED9168, 0x8CE9DCCAE8532735, 0xB3E23D8079394AFE, 0x64563E0AAB733B52, + 0x5B5DDF403A195699, 0x1A41FC9F89A7E0C4, 0x254A1DD518CD8D0F, 0x9879BB20EEDA8C7E, 0xA7725A6A7FB0E1B5, + 0xE66E79B5CC0E57E8, 0xD96598FF5D643A23, 0x92949EF28518CC26, 0xAD9F7FB81472A1ED, 0xEC835C67A7CC17B0, + 0xD388BD2D36A67A7B, 0x6EBB1BD8C0B17B0A, 0x51B0FA9251DB16C1, 0x10ACD94DE265A09C, 0x2FA73807730FCD57, + 0xF8133B8DA145BCFB, 0xC718DAC7302FD130, 0x8604F9188391676D, 0xB90F185212FB0AA6, 0x043CBEA7E4EC0BD7, + 0x3B375FED7586661C, 0x7A2B7C32C638D041, 0x45209D785752BD8A, 0x479BD40CCDA22D9C, 0x789035465CC84057, + 0x398C1699EF76F60A, 0x0687F7D37E1C9BC1, 0xBBB45126880B9AB0, 0x84BFB06C1961F77B, 0xC5A393B3AADF4126, + 0xFAA872F93BB52CED, 0x2D1C7173E9FF5D41, 0x121790397895308A, 0x530BB3E6CB2B86D7, 0x6C0052AC5A41EB1C, + 0xD133F459AC56EA6D, 0xEE3815133D3C87A6, 0xAF2436CC8E8231FB, 0x902FD7861FE85C30, 0xAA52A425BB6311D7, + 0x9559456F2A097C1C, 0xD44566B099B7CA41, 0xEB4E87FA08DDA78A, 0x567D210FFECAA6FB, 0x6976C0456FA0CB30, + 0x286AE39ADC1E7D6D, 0x176102D04D7410A6, 0xC0D5015A9F3E610A, 0xFFDEE0100E540CC1, 0xBEC2C3CFBDEABA9C, + 0x81C922852C80D757, 0x3CFA8470DA97D626, 0x03F1653A4BFDBBED, 0x42ED46E5F8430DB0, 0x7DE6A7AF6929607B, + 0x7F5DEEDBF3D9F06D, 0x40560F9162B39DA6, 0x014A2C4ED10D2BFB, 0x3E41CD0440674630, 0x83726BF1B6704741, + 0xBC798ABB271A2A8A, 0xFD65A96494A49CD7, 0xC26E482E05CEF11C, 0x15DA4BA4D78480B0, 0x2AD1AAEE46EEED7B, + 0x6BCD8931F5505B26, 0x54C6687B643A36ED, 0xE9F5CE8E922D379C, 0xD6FE2FC403475A57, 0x97E20C1BB0F9EC0A, + 0xA8E9ED51219381C1 + ], + [ + 0x0000000000000000, 0x1DEE8A5E222CA1DC, 0x3BDD14BC445943B8, 0x26339EE26675E264, 0x77BA297888B28770, + 0x6A54A326AA9E26AC, 0x4C673DC4CCEBC4C8, 0x5189B79AEEC76514, 0xEF7452F111650EE0, 0xF29AD8AF3349AF3C, + 0xD4A9464D553C4D58, 0xC947CC137710EC84, 0x98CE7B8999D78990, 0x8520F1D7BBFB284C, 0xA3136F35DD8ECA28, + 0xBEFDE56BFFA26BF4, 0x4C300AC98DC40345, 0x51DE8097AFE8A299, 0x77ED1E75C99D40FD, 0x6A03942BEBB1E121, + 0x3B8A23B105768435, 0x2664A9EF275A25E9, 0x0057370D412FC78D, 0x1DB9BD5363036651, 0xA34458389CA10DA5, + 0xBEAAD266BE8DAC79, 0x98994C84D8F84E1D, 0x8577C6DAFAD4EFC1, 0xD4FE714014138AD5, 0xC910FB1E363F2B09, + 0xEF2365FC504AC96D, 0xF2CDEFA2726668B1, 0x986015931B88068A, 0x858E9FCD39A4A756, 0xA3BD012F5FD14532, + 0xBE538B717DFDE4EE, 0xEFDA3CEB933A81FA, 0xF234B6B5B1162026, 0xD4072857D763C242, 0xC9E9A209F54F639E, + 0x771447620AED086A, 0x6AFACD3C28C1A9B6, 0x4CC953DE4EB44BD2, 0x5127D9806C98EA0E, 0x00AE6E1A825F8F1A, + 0x1D40E444A0732EC6, 0x3B737AA6C606CCA2, 0x269DF0F8E42A6D7E, 0xD4501F5A964C05CF, 0xC9BE9504B460A413, + 0xEF8D0BE6D2154677, 0xF26381B8F039E7AB, 0xA3EA36221EFE82BF, 0xBE04BC7C3CD22363, 0x9837229E5AA7C107, + 0x85D9A8C0788B60DB, 0x3B244DAB87290B2F, 0x26CAC7F5A505AAF3, 0x00F95917C3704897, 0x1D17D349E15CE94B, + 0x4C9E64D30F9B8C5F, 0x5170EE8D2DB72D83, 0x7743706F4BC2CFE7, 0x6AADFA3169EE6E3B, 0xA218840D981E1391, + 0xBFF60E53BA32B24D, 0x99C590B1DC475029, 0x842B1AEFFE6BF1F5, 0xD5A2AD7510AC94E1, 0xC84C272B3280353D, + 0xEE7FB9C954F5D759, 0xF391339776D97685, 0x4D6CD6FC897B1D71, 0x50825CA2AB57BCAD, 0x76B1C240CD225EC9, + 0x6B5F481EEF0EFF15, 0x3AD6FF8401C99A01, 0x273875DA23E53BDD, 0x010BEB384590D9B9, 0x1CE5616667BC7865, + 0xEE288EC415DA10D4, 0xF3C6049A37F6B108, 0xD5F59A785183536C, 0xC81B102673AFF2B0, 0x9992A7BC9D6897A4, + 0x847C2DE2BF443678, 0xA24FB300D931D41C, 0xBFA1395EFB1D75C0, 0x015CDC3504BF1E34, 0x1CB2566B2693BFE8, + 0x3A81C88940E65D8C, 0x276F42D762CAFC50, 0x76E6F54D8C0D9944, 0x6B087F13AE213898, 0x4D3BE1F1C854DAFC, + 0x50D56BAFEA787B20, 0x3A78919E8396151B, 0x27961BC0A1BAB4C7, 0x01A58522C7CF56A3, 0x1C4B0F7CE5E3F77F, + 0x4DC2B8E60B24926B, 0x502C32B8290833B7, 0x761FAC5A4F7DD1D3, 0x6BF126046D51700F, 0xD50CC36F92F31BFB, + 0xC8E24931B0DFBA27, 0xEED1D7D3D6AA5843, 0xF33F5D8DF486F99F, 0xA2B6EA171A419C8B, 0xBF586049386D3D57, + 0x996BFEAB5E18DF33, 0x848574F57C347EEF, 0x76489B570E52165E, 0x6BA611092C7EB782, 0x4D958FEB4A0B55E6, + 0x507B05B56827F43A, 0x01F2B22F86E0912E, 0x1C1C3871A4CC30F2, 0x3A2FA693C2B9D296, 0x27C12CCDE095734A, + 0x993CC9A61F3718BE, 0x84D243F83D1BB962, 0xA2E1DD1A5B6E5B06, 0xBF0F57447942FADA, 0xEE86E0DE97859FCE, + 0xF3686A80B5A93E12, 0xD55BF462D3DCDC76, 0xC8B57E3CF1F07DAA, 0xD6E9A7309F3239A7, 0xCB072D6EBD1E987B, + 0xED34B38CDB6B7A1F, 0xF0DA39D2F947DBC3, 0xA1538E481780BED7, 0xBCBD041635AC1F0B, 0x9A8E9AF453D9FD6F, + 0x876010AA71F55CB3, 0x399DF5C18E573747, 0x24737F9FAC7B969B, 0x0240E17DCA0E74FF, 0x1FAE6B23E822D523, + 0x4E27DCB906E5B037, 0x53C956E724C911EB, 0x75FAC80542BCF38F, 0x6814425B60905253, 0x9AD9ADF912F63AE2, + 0x873727A730DA9B3E, 0xA104B94556AF795A, 0xBCEA331B7483D886, 0xED6384819A44BD92, 0xF08D0EDFB8681C4E, + 0xD6BE903DDE1DFE2A, 0xCB501A63FC315FF6, 0x75ADFF0803933402, 0x6843755621BF95DE, 0x4E70EBB447CA77BA, + 0x539E61EA65E6D666, 0x0217D6708B21B372, 0x1FF95C2EA90D12AE, 0x39CAC2CCCF78F0CA, 0x24244892ED545116, + 0x4E89B2A384BA3F2D, 0x536738FDA6969EF1, 0x7554A61FC0E37C95, 0x68BA2C41E2CFDD49, 0x39339BDB0C08B85D, + 0x24DD11852E241981, 0x02EE8F674851FBE5, 0x1F0005396A7D5A39, 0xA1FDE05295DF31CD, 0xBC136A0CB7F39011, + 0x9A20F4EED1867275, 0x87CE7EB0F3AAD3A9, 0xD647C92A1D6DB6BD, 0xCBA943743F411761, 0xED9ADD965934F505, + 0xF07457C87B1854D9, 0x02B9B86A097E3C68, 0x1F5732342B529DB4, 0x3964ACD64D277FD0, 0x248A26886F0BDE0C, + 0x7503911281CCBB18, 0x68ED1B4CA3E01AC4, 0x4EDE85AEC595F8A0, 0x53300FF0E7B9597C, 0xEDCDEA9B181B3288, + 0xF02360C53A379354, 0xD610FE275C427130, 0xCBFE74797E6ED0EC, 0x9A77C3E390A9B5F8, 0x879949BDB2851424, + 0xA1AAD75FD4F0F640, 0xBC445D01F6DC579C, 0x74F1233D072C2A36, 0x691FA96325008BEA, 0x4F2C37814375698E, + 0x52C2BDDF6159C852, 0x034B0A458F9EAD46, 0x1EA5801BADB20C9A, 0x38961EF9CBC7EEFE, 0x257894A7E9EB4F22, + 0x9B8571CC164924D6, 0x866BFB923465850A, 0xA05865705210676E, 0xBDB6EF2E703CC6B2, 0xEC3F58B49EFBA3A6, + 0xF1D1D2EABCD7027A, 0xD7E24C08DAA2E01E, 0xCA0CC656F88E41C2, 0x38C129F48AE82973, 0x252FA3AAA8C488AF, + 0x031C3D48CEB16ACB, 0x1EF2B716EC9DCB17, 0x4F7B008C025AAE03, 0x52958AD220760FDF, 0x74A614304603EDBB, + 0x69489E6E642F4C67, 0xD7B57B059B8D2793, 0xCA5BF15BB9A1864F, 0xEC686FB9DFD4642B, 0xF186E5E7FDF8C5F7, + 0xA00F527D133FA0E3, 0xBDE1D8233113013F, 0x9BD246C15766E35B, 0x863CCC9F754A4287, 0xEC9136AE1CA42CBC, + 0xF17FBCF03E888D60, 0xD74C221258FD6F04, 0xCAA2A84C7AD1CED8, 0x9B2B1FD69416ABCC, 0x86C59588B63A0A10, + 0xA0F60B6AD04FE874, 0xBD188134F26349A8, 0x03E5645F0DC1225C, 0x1E0BEE012FED8380, 0x383870E3499861E4, + 0x25D6FABD6BB4C038, 0x745F4D278573A52C, 0x69B1C779A75F04F0, 0x4F82599BC12AE694, 0x526CD3C5E3064748, + 0xA0A13C6791602FF9, 0xBD4FB639B34C8E25, 0x9B7C28DBD5396C41, 0x8692A285F715CD9D, 0xD71B151F19D2A889, + 0xCAF59F413BFE0955, 0xECC601A35D8BEB31, 0xF1288BFD7FA74AED, 0x4FD56E9680052119, 0x523BE4C8A22980C5, + 0x74087A2AC45C62A1, 0x69E6F074E670C37D, 0x386F47EE08B7A669, 0x2581CDB02A9B07B5, 0x03B253524CEEE5D1, + 0x1E5CD90C6EC2440D + ] + ]; + + readonly ulong _finalSeed; + readonly IntPtr _nativeContext; + readonly ulong[][] _table; + readonly bool _useEcma; + readonly bool _useNative; + ulong _hashInt; + + /// Initializes the CRC64 table and seed as CRC64-ECMA + public Crc64Context() + { + _hashInt = CRC64_ECMA_SEED; + _table = _ecmaCrc64Table; + _finalSeed = CRC64_ECMA_SEED; + _useEcma = true; + + if(!Native.IsSupported) return; + + _nativeContext = crc64_init(); + _useNative = _nativeContext != IntPtr.Zero; + } + + /// Initializes the CRC16 table with a custom polynomial and seed + public Crc64Context(ulong polynomial, ulong seed) + { + _hashInt = seed; + _finalSeed = seed; + _useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED; + + if(Native.IsSupported && _useEcma) + { + _nativeContext = crc64_init(); + _useNative = _nativeContext != IntPtr.Zero; + } + else + _table = GenerateTable(polynomial); + } + +#region IChecksum Members + + /// + public string Name => Localization.CRC64_ECMA_Name; + + /// + public Guid Id => new("D0C0D902-420A-45DA-A235-9D48BEE4B1CE"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) => + Step(ref _hashInt, _table, data, len, _useEcma, _useNative, _nativeContext); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + ulong crc = _hashInt ^ _finalSeed; + + if(!_useNative || !_useEcma) return BigEndianBitConverter.GetBytes(crc); + + crc64_final(_nativeContext, ref crc); + crc64_free(_nativeContext); + + return BigEndianBitConverter.GetBytes(crc); + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + ulong crc = _hashInt ^ _finalSeed; + + var crc64Output = new StringBuilder(); + + if(_useNative && _useEcma) + { + crc64_final(_nativeContext, ref crc); + crc64_free(_nativeContext); + } + + for(var i = 0; i < BigEndianBitConverter.GetBytes(crc).Length; i++) + crc64Output.Append(BigEndianBitConverter.GetBytes(crc)[i].ToString("x2")); + + return crc64Output.ToString(); + } + +#endregion + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial IntPtr crc64_init(); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int crc64_update(IntPtr ctx, byte[] data, uint len); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int crc64_final(IntPtr ctx, ref ulong crc); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial void crc64_free(IntPtr ctx); + + static ulong[][] GenerateTable(ulong polynomial) + { + var table = new ulong[8][]; + + for(var i = 0; i < 8; i++) table[i] = new ulong[256]; + + for(var i = 0; i < 256; i++) + { + var entry = (ulong)i; + + for(var j = 0; j < 8; j++) + { + if((entry & 1) == 1) + entry = entry >> 1 ^ polynomial; + else + entry >>= 1; + } + + table[0][i] = entry; + } + + for(var slice = 1; slice < 4; slice++) + { + for(var i = 0; i < 256; i++) + table[slice][i] = table[slice - 1][i] >> 8 ^ table[0][table[slice - 1][i] & 0xFF]; + } + + return table; + } + + static void Step(ref ulong previousCrc, ulong[][] table, byte[] data, uint len, bool useEcma, bool useNative, + IntPtr nativeContext) + { + if(useNative && useEcma) + { + crc64_update(nativeContext, data, len); + + return; + } + + var dataOff = 0; + + if(useEcma && Pclmulqdq.IsSupported && Sse41.IsSupported && Ssse3.IsSupported && Sse2.IsSupported) + { + // Only works in blocks of 32 bytes + uint blocks = len / 32; + + if(blocks > 0) + { + previousCrc = ~Clmul.Step(~previousCrc, data, blocks * 32); + + dataOff = (int)(blocks * 32); + len -= blocks * 32; + } + + if(len == 0) return; + } + + // Unroll according to Intel slicing by uint8_t + // http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf + // http://sourceforge.net/projects/slicing-by-8/ + + ulong crc = previousCrc; + + if(len > 4) + { + long limit = dataOff + (len & ~(uint)3); + len &= 3; + + while(dataOff < limit) + { + var tmp = (uint)(crc ^ BitConverter.ToUInt32(data, dataOff)); + dataOff += 4; + + crc = table[3][tmp & 0xFF] ^ + table[2][tmp >> 8 & 0xFF] ^ + crc >> 32 ^ + table[1][tmp >> 16 & 0xFF] ^ + table[0][tmp >> 24]; + } + } + + while(len-- != 0) crc = table[0][data[dataOff++] ^ crc & 0xFF] ^ crc >> 8; + + previousCrc = crc; + } + + /// Gets the hash of a file + /// File path. + + // ReSharper disable once ReturnTypeCanBeEnumerable.Global + public static byte[] File(string filename) + { + File(filename, out byte[] localHash); + + return localHash; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) => + File(filename, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED); + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + /// CRC polynomial + /// CRC seed + public static string File(string filename, out byte[] hash, ulong polynomial, ulong seed) + { + bool useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED; + bool useNative = Native.IsSupported; + IntPtr nativeContext = IntPtr.Zero; + + if(useNative && useEcma) + { + nativeContext = crc64_init(); + useNative = nativeContext != IntPtr.Zero; + } + + var fileStream = new FileStream(filename, FileMode.Open); + + ulong localHashInt = seed; + + ulong[][] localTable = GenerateTable(polynomial); + + var buffer = new byte[65536]; + int read = fileStream.EnsureRead(buffer, 0, 65536); + + while(read > 0) + { + Step(ref localHashInt, localTable, buffer, (uint)read, useEcma, useNative, nativeContext); + + read = fileStream.EnsureRead(buffer, 0, 65536); + } + + localHashInt ^= seed; + + if(useNative && useEcma) + { + crc64_final(nativeContext, ref localHashInt); + crc64_free(nativeContext); + } + + hash = BigEndianBitConverter.GetBytes(localHashInt); + + var crc64Output = new StringBuilder(); + + foreach(byte h in hash) crc64Output.Append(h.ToString("x2")); + + fileStream.Close(); + + return crc64Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) => + Data(data, len, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED); + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + /// CRC polynomial + /// CRC seed + public static string Data(byte[] data, uint len, out byte[] hash, ulong polynomial, ulong seed) + { + bool useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED; + bool useNative = Native.IsSupported; + IntPtr nativeContext = IntPtr.Zero; + + if(useNative && useEcma) + { + nativeContext = crc64_init(); + useNative = nativeContext != IntPtr.Zero; + } + + ulong localHashInt = seed; + + ulong[][] localTable = GenerateTable(polynomial); + + Step(ref localHashInt, localTable, data, len, useEcma, useNative, nativeContext); + + localHashInt ^= seed; + + if(useNative && useEcma) + { + crc64_final(nativeContext, ref localHashInt); + crc64_free(nativeContext); + } + + hash = BigEndianBitConverter.GetBytes(localHashInt); + + var crc64Output = new StringBuilder(); + + foreach(byte h in hash) crc64Output.Append(h.ToString("x2")); + + return crc64Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} \ No newline at end of file diff --git a/Aaru.Checksums/Fletcher32/neon.cs b/Aaru.Checksums/Fletcher32/neon.cs new file mode 100644 index 000000000..21e175818 --- /dev/null +++ b/Aaru.Checksums/Fletcher32/neon.cs @@ -0,0 +1,246 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : neon.cs +// Author(s) : Natalia Portillo +// The Chromium Authors +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Compute Fletcher32 checksum using NEON vectorization. +// +// --[ License ] -------------------------------------------------------------- +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright 2017 The Chromium Authors. All rights reserved. +// ****************************************************************************/ + +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace Aaru.Checksums.Fletcher32; + +static class Neon +{ + internal static void Step(ref ushort preSum1, ref ushort preSum2, byte[] buf, uint len) + { + /* + * Split Fletcher-32 into component sums. + */ + uint s1 = preSum1; + uint s2 = preSum2; + + var bufPos = 0; + + /* + * Process the data in blocks. + */ + const uint block_Size = 1 << 5; + uint blocks = len / block_Size; + len -= blocks * block_Size; + + while(blocks != 0) + { + uint n = Fletcher32Context.Nmax / block_Size; /* The NMAX constraint. */ + + if(n > blocks) n = blocks; + + blocks -= n; + /* + * Process n blocks of data. At most NMAX data bytes can be + * processed before s2 must be reduced modulo FLETCHER_MODULE. + */ + var v_S2 = Vector128.Create(s1 * n, 0, 0, 0); + var v_S1 = Vector128.Create(0u, 0, 0, 0); + Vector128 v_Column_Sum_1 = AdvSimd.DuplicateToVector128((ushort)0); + Vector128 v_Column_Sum_2 = AdvSimd.DuplicateToVector128((ushort)0); + Vector128 v_Column_Sum_3 = AdvSimd.DuplicateToVector128((ushort)0); + Vector128 v_Column_Sum_4 = AdvSimd.DuplicateToVector128((ushort)0); + + do + { + /* + * Load 32 input bytes. + */ + var bytes1 = Vector128.Create(buf[bufPos], + buf[bufPos + 1], + buf[bufPos + 2], + buf[bufPos + 3], + buf[bufPos + 4], + buf[bufPos + 5], + buf[bufPos + 6], + buf[bufPos + 7], + buf[bufPos + 8], + buf[bufPos + 9], + buf[bufPos + 10], + buf[bufPos + 11], + buf[bufPos + 12], + buf[bufPos + 13], + buf[bufPos + 14], + buf[bufPos + 15]); + + bufPos += 16; + + var bytes2 = Vector128.Create(buf[bufPos], + buf[bufPos + 1], + buf[bufPos + 2], + buf[bufPos + 3], + buf[bufPos + 4], + buf[bufPos + 5], + buf[bufPos + 6], + buf[bufPos + 7], + buf[bufPos + 8], + buf[bufPos + 9], + buf[bufPos + 10], + buf[bufPos + 11], + buf[bufPos + 12], + buf[bufPos + 13], + buf[bufPos + 14], + buf[bufPos + 15]); + + bufPos += 16; + /* + * Add previous block byte sum to v_s2. + */ + v_S2 = AdvSimd.Add(v_S2, v_S1); + + /* + * Horizontally add the bytes for s1. + */ + v_S1 = AdvSimd.AddPairwiseWideningAndAdd(v_S1, + AdvSimd + .AddPairwiseWideningAndAdd(AdvSimd + .AddPairwiseWidening(bytes1), + bytes2)); + + /* + * Vertically add the bytes for s2. + */ + v_Column_Sum_1 = AdvSimd.AddWideningLower(v_Column_Sum_1, bytes1.GetLower()); + v_Column_Sum_2 = AdvSimd.AddWideningLower(v_Column_Sum_2, bytes1.GetUpper()); + v_Column_Sum_3 = AdvSimd.AddWideningLower(v_Column_Sum_3, bytes2.GetLower()); + v_Column_Sum_4 = AdvSimd.AddWideningLower(v_Column_Sum_4, bytes2.GetUpper()); + } while(--n != 0); + + v_S2 = AdvSimd.ShiftLeftLogical(v_S2, 5); + + /* + * Multiply-add bytes by [ 32, 31, 30, ... ] for s2. + */ + v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, + v_Column_Sum_1.GetLower(), + Vector64.Create((ushort)32, 31, 30, 29)); + + v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, + v_Column_Sum_1.GetUpper(), + Vector64.Create((ushort)28, 27, 26, 25)); + + v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, + v_Column_Sum_2.GetLower(), + Vector64.Create((ushort)24, 23, 22, 21)); + + v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, + v_Column_Sum_2.GetUpper(), + Vector64.Create((ushort)20, 19, 18, 17)); + + v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, + v_Column_Sum_3.GetLower(), + Vector64.Create((ushort)16, 15, 14, 13)); + + v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, + v_Column_Sum_3.GetUpper(), + Vector64.Create((ushort)12, 11, 10, 9)); + + v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, + v_Column_Sum_4.GetLower(), + Vector64.Create((ushort)8, 7, 6, 5)); + + v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, + v_Column_Sum_4.GetUpper(), + Vector64.Create((ushort)4, 3, 2, 1)); + + /* + * Sum epi32 ints v_s1(s2) and accumulate in s1(s2). + */ + Vector64 sum1 = AdvSimd.AddPairwise(v_S1.GetLower(), v_S1.GetUpper()); + Vector64 sum2 = AdvSimd.AddPairwise(v_S2.GetLower(), v_S2.GetUpper()); + Vector64 s1S2 = AdvSimd.AddPairwise(sum1, sum2); + s1 += AdvSimd.Extract(s1S2, 0); + s2 += AdvSimd.Extract(s1S2, 1); + /* + * Reduce. + */ + s1 %= Fletcher32Context.FletcherModule; + s2 %= Fletcher32Context.FletcherModule; + } + + /* + * Handle leftover data. + */ + if(len != 0) + { + if(len >= 16) + { + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + len -= 16; + } + + while(len-- != 0) s2 += s1 += buf[bufPos++]; + + if(s1 >= Fletcher32Context.FletcherModule) s1 -= Fletcher32Context.FletcherModule; + + s2 %= Fletcher32Context.FletcherModule; + } + + /* + * Return the recombined sums. + */ + preSum1 = (ushort)(s1 & 0xFFFF); + preSum2 = (ushort)(s2 & 0xFFFF); + } +} \ No newline at end of file diff --git a/Aaru.Checksums/Fletcher32/ssse3.cs b/Aaru.Checksums/Fletcher32/ssse3.cs new file mode 100644 index 000000000..8787b08a4 --- /dev/null +++ b/Aaru.Checksums/Fletcher32/ssse3.cs @@ -0,0 +1,188 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ssse3.cs +// Author(s) : Natalia Portillo +// The Chromium Authors +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Compute Fletcher32 checksum using SSSE3 vectorization. +// +// --[ License ] -------------------------------------------------------------- +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright 2017 The Chromium Authors. All rights reserved. +// ****************************************************************************/ + +using System; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace Aaru.Checksums.Fletcher32; + +static class Ssse3 +{ + internal static void Step(ref ushort sum1, ref ushort sum2, byte[] buf, uint len) + { + uint s1 = sum1; + uint s2 = sum2; + var bufPos = 0; + + /* + * Process the data in blocks. + */ + const uint block_Size = 1 << 5; + uint blocks = len / block_Size; + len -= blocks * block_Size; + + while(blocks != 0) + { + uint n = Fletcher32Context.Nmax / block_Size; /* The NMAX constraint. */ + + if(n > blocks) n = blocks; + + blocks -= n; + + Vector128 tap1 = Vector128.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17) + .AsByte(); + + Vector128 tap2 = Vector128.Create(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1).AsByte(); + Vector128 zero = Vector128.Create(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).AsByte(); + var ones = Vector128.Create(1, 1, 1, 1, 1, 1, 1, 1); + /* + * Process n blocks of data. At most NMAX data bytes can be + * processed before s2 must be reduced modulo BASE. + */ + var v_Ps = Vector128.Create(s1 * n, 0, 0, 0); + var v_S2 = Vector128.Create(s2, 0, 0, 0); + var v_S1 = Vector128.Create(0u, 0, 0, 0); + + do + { + /* + * Load 32 input bytes. + */ + var bytes1 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos), + BitConverter.ToUInt32(buf, bufPos + 4), + BitConverter.ToUInt32(buf, bufPos + 8), + BitConverter.ToUInt32(buf, bufPos + 12)); + + bufPos += 16; + + var bytes2 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos), + BitConverter.ToUInt32(buf, bufPos + 4), + BitConverter.ToUInt32(buf, bufPos + 8), + BitConverter.ToUInt32(buf, bufPos + 12)); + + bufPos += 16; + + /* + * Add previous block byte sum to v_ps. + */ + v_Ps = Sse2.Add(v_Ps, v_S1); + /* + * Horizontally add the bytes for s1, multiply-adds the + * bytes by [ 32, 31, 30, ... ] for s2. + */ + v_S1 = Sse2.Add(v_S1, Sse2.SumAbsoluteDifferences(bytes1.AsByte(), zero).AsUInt32()); + + Vector128 mad1 = + System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes1.AsByte(), tap1.AsSByte()); + + v_S2 = Sse2.Add(v_S2, Sse2.MultiplyAddAdjacent(mad1.AsInt16(), ones.AsInt16()).AsUInt32()); + v_S1 = Sse2.Add(v_S1, Sse2.SumAbsoluteDifferences(bytes2.AsByte(), zero).AsUInt32()); + + Vector128 mad2 = + System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes2.AsByte(), tap2.AsSByte()); + + v_S2 = Sse2.Add(v_S2, Sse2.MultiplyAddAdjacent(mad2.AsInt16(), ones.AsInt16()).AsUInt32()); + } while(--n != 0); + + v_S2 = Sse2.Add(v_S2, Sse2.ShiftLeftLogical(v_Ps, 5)); + /* + * Sum epi32 ints v_s1(s2) and accumulate in s1(s2). + */ + v_S1 = Sse2.Add(v_S1, Sse2.Shuffle(v_S1, 177)); + v_S1 = Sse2.Add(v_S1, Sse2.Shuffle(v_S1, 78)); + s1 += (uint)Sse2.ConvertToInt32(v_S1.AsInt32()); + v_S2 = Sse2.Add(v_S2, Sse2.Shuffle(v_S2, 177)); + v_S2 = Sse2.Add(v_S2, Sse2.Shuffle(v_S2, 78)); + s2 = (uint)Sse2.ConvertToInt32(v_S2.AsInt32()); + /* + * Reduce. + */ + s1 %= Fletcher32Context.FletcherModule; + s2 %= Fletcher32Context.FletcherModule; + } + + /* + * Handle leftover data. + */ + if(len != 0) + { + if(len >= 16) + { + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + s2 += s1 += buf[bufPos++]; + len -= 16; + } + + while(len-- != 0) s2 += s1 += buf[bufPos++]; + + if(s1 >= Fletcher32Context.FletcherModule) s1 -= Fletcher32Context.FletcherModule; + + s2 %= Fletcher32Context.FletcherModule; + } + + /* + * Return the recombined sums. + */ + sum1 = (ushort)(s1 & 0xFFFF); + sum2 = (ushort)(s2 & 0xFFFF); + } +} \ No newline at end of file diff --git a/Aaru.Checksums/FletcherContext.cs b/Aaru.Checksums/FletcherContext.cs new file mode 100644 index 000000000..46c9696ab --- /dev/null +++ b/Aaru.Checksums/FletcherContext.cs @@ -0,0 +1,749 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : FletcherContext.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Implements Fletcher-32 and Fletcher-16 algorithms. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// Disabled because the speed is abnormally slow + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Arm; +using System.Text; +using Aaru.Checksums.Fletcher32; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Ssse3 = System.Runtime.Intrinsics.X86.Ssse3; + +namespace Aaru.Checksums; + +/// +/// Implements the Fletcher-32 algorithm +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public sealed partial class Fletcher32Context : IChecksum +{ + internal const ushort FletcherModule = 0xFFFF; + internal const uint Nmax = 5552; + readonly IntPtr _nativeContext; + readonly bool _useNative; + ushort _sum1, _sum2; + + /// Initializes the Fletcher-32 sums + public Fletcher32Context() + { + _sum1 = 0xFFFF; + _sum2 = 0xFFFF; + + if(!Native.IsSupported) return; + + _nativeContext = fletcher32_init(); + _useNative = _nativeContext != IntPtr.Zero; + } + +#region IChecksum Members + + /// + public string Name => Localization.Fletcher32_Name; + + /// + public Guid Id => new("0E51B39F-C5E6-4CED-9E59-BA5A42B3B2F4"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + var finalSum = (uint)(_sum2 << 16 | _sum1); + + if(!_useNative) return BigEndianBitConverter.GetBytes(finalSum); + + fletcher32_final(_nativeContext, ref finalSum); + fletcher32_free(_nativeContext); + + return BigEndianBitConverter.GetBytes(finalSum); + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + var finalSum = (uint)(_sum2 << 16 | _sum1); + + if(_useNative) + { + fletcher32_final(_nativeContext, ref finalSum); + fletcher32_free(_nativeContext); + } + + var fletcherOutput = new StringBuilder(); + + for(var i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++) + fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2")); + + return fletcherOutput.ToString(); + } + +#endregion + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial IntPtr fletcher32_init(); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int fletcher32_update(IntPtr ctx, byte[] data, uint len); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int fletcher32_final(IntPtr ctx, ref uint crc); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial void fletcher32_free(IntPtr ctx); + + static void Step(ref ushort previousSum1, ref ushort previousSum2, byte[] data, uint len, bool useNative, + IntPtr nativeContext) + { + if(useNative) + { + fletcher32_update(nativeContext, data, len); + + return; + } + + if(Ssse3.IsSupported) + { + Fletcher32.Ssse3.Step(ref previousSum1, ref previousSum2, data, len); + + return; + } + + if(AdvSimd.IsSupported) + { + Neon.Step(ref previousSum1, ref previousSum2, data, len); + + return; + } + + uint sum1 = previousSum1; + uint sum2 = previousSum2; + var dataOff = 0; + + switch(len) + { + /* in case user likes doing a byte at a time, keep it fast */ + case 1: + { + sum1 += data[dataOff]; + + if(sum1 >= FletcherModule) sum1 -= FletcherModule; + + sum2 += sum1; + + if(sum2 >= FletcherModule) sum2 -= FletcherModule; + + previousSum1 = (ushort)(sum1 & 0xFFFF); + previousSum2 = (ushort)(sum2 & 0xFFFF); + + return; + } + /* in case short lengths are provided, keep it somewhat fast */ + case < 16: + { + while(len-- > 0) + { + sum1 += data[dataOff++]; + sum2 += sum1; + } + + if(sum1 >= FletcherModule) sum1 -= FletcherModule; + + sum2 %= FletcherModule; /* only added so many FLETCHER_MODULE's */ + previousSum1 = (ushort)(sum1 & 0xFFFF); + previousSum2 = (ushort)(sum2 & 0xFFFF); + + return; + } + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while(len >= Nmax) + { + len -= Nmax; + uint n = Nmax / 16; + + do + { + sum1 += data[dataOff]; + sum2 += sum1; + sum1 += data[dataOff + 1]; + sum2 += sum1; + sum1 += data[dataOff + 2]; + sum2 += sum1; + sum1 += data[dataOff + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 2 + 1]; + sum2 += sum1; + + /* 16 sums unrolled */ + dataOff += 16; + } while(--n != 0); + + sum1 %= FletcherModule; + sum2 %= FletcherModule; + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if(len != 0) + { + /* avoid modulos if none remaining */ + while(len >= 16) + { + len -= 16; + sum1 += data[dataOff]; + sum2 += sum1; + sum1 += data[dataOff + 1]; + sum2 += sum1; + sum1 += data[dataOff + 2]; + sum2 += sum1; + sum1 += data[dataOff + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 4 + 2 + 1]; + sum2 += sum1; + + dataOff += 16; + } + + while(len-- != 0) + { + sum1 += data[dataOff++]; + sum2 += sum1; + } + + sum1 %= FletcherModule; + sum2 %= FletcherModule; + } + + previousSum1 = (ushort)(sum1 & 0xFFFF); + previousSum2 = (ushort)(sum2 & 0xFFFF); + } + + /// Gets the hash of a file + /// File path. + public static byte[] File(string filename) + { + File(filename, out byte[] hash); + + return hash; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + bool useNative = Native.IsSupported; + IntPtr nativeContext = IntPtr.Zero; + + if(useNative) + { + nativeContext = fletcher32_init(); + + if(nativeContext == IntPtr.Zero) useNative = false; + } + + var fileStream = new FileStream(filename, FileMode.Open); + + ushort localSum1 = 0xFFFF; + ushort localSum2 = 0xFFFF; + + var buffer = new byte[65536]; + int read = fileStream.EnsureRead(buffer, 0, 65536); + + while(read > 0) + { + Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext); + + read = fileStream.EnsureRead(buffer, 0, 65536); + } + + var finalSum = (uint)(localSum2 << 16 | localSum1); + + if(useNative) + { + fletcher32_final(nativeContext, ref finalSum); + fletcher32_free(nativeContext); + } + + hash = BigEndianBitConverter.GetBytes(finalSum); + + var fletcherOutput = new StringBuilder(); + + foreach(byte h in hash) fletcherOutput.Append(h.ToString("x2")); + + fileStream.Close(); + + return fletcherOutput.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + bool useNative = Native.IsSupported; + IntPtr nativeContext = IntPtr.Zero; + + if(useNative) + { + nativeContext = fletcher32_init(); + + if(nativeContext == IntPtr.Zero) useNative = false; + } + + ushort localSum1 = 0xFFFF; + ushort localSum2 = 0xFFFF; + + Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext); + + var finalSum = (uint)(localSum2 << 16 | localSum1); + + if(useNative) + { + fletcher32_final(nativeContext, ref finalSum); + fletcher32_free(nativeContext); + } + + hash = BigEndianBitConverter.GetBytes(finalSum); + + var adlerOutput = new StringBuilder(); + + foreach(byte h in hash) adlerOutput.Append(h.ToString("x2")); + + return adlerOutput.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} + +/// +/// Implements the Fletcher-16 algorithm +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +public sealed partial class Fletcher16Context : IChecksum +{ + const byte FLETCHER_MODULE = 0xFF; + const byte NMAX = 22; + + readonly IntPtr _nativeContext; + readonly bool _useNative; + byte _sum1, _sum2; + + /// Initializes the Fletcher-16 sums + public Fletcher16Context() + { + _sum1 = 0xFF; + _sum2 = 0xFF; + + if(!Native.IsSupported) return; + + _nativeContext = fletcher16_init(); + _useNative = _nativeContext != IntPtr.Zero; + } + +#region IChecksum Members + + /// + public string Name => Localization.Fletcher16_Name; + + /// + public Guid Id => new("80C51F1D-71F8-4741-A0CF-18FA8102EE4B"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + var finalSum = (ushort)(_sum2 << 8 | _sum1); + + if(!_useNative) return BigEndianBitConverter.GetBytes(finalSum); + + fletcher16_final(_nativeContext, ref finalSum); + fletcher16_free(_nativeContext); + + return BigEndianBitConverter.GetBytes(finalSum); + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + var finalSum = (ushort)(_sum2 << 8 | _sum1); + + if(_useNative) + { + fletcher16_final(_nativeContext, ref finalSum); + fletcher16_free(_nativeContext); + } + + var fletcherOutput = new StringBuilder(); + + for(var i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++) + fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2")); + + return fletcherOutput.ToString(); + } + +#endregion + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial IntPtr fletcher16_init(); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int fletcher16_update(IntPtr ctx, byte[] data, uint len); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial int fletcher16_final(IntPtr ctx, ref ushort checksum); + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial void fletcher16_free(IntPtr ctx); + + static void Step(ref byte previousSum1, ref byte previousSum2, byte[] data, uint len, bool useNative, + IntPtr nativeContext) + { + if(useNative) + { + fletcher16_update(nativeContext, data, len); + + return; + } + + uint sum1 = previousSum1; + uint sum2 = previousSum2; + var dataOff = 0; + + switch(len) + { + /* in case user likes doing a byte at a time, keep it fast */ + case 1: + { + sum1 += data[dataOff]; + + if(sum1 >= FLETCHER_MODULE) sum1 -= FLETCHER_MODULE; + + sum2 += sum1; + + if(sum2 >= FLETCHER_MODULE) sum2 -= FLETCHER_MODULE; + + previousSum1 = (byte)(sum1 & 0xFF); + previousSum2 = (byte)(sum2 & 0xFF); + + return; + } + /* in case short lengths are provided, keep it somewhat fast */ + case < 11: + { + while(len-- > 0) + { + sum1 += data[dataOff++]; + sum2 += sum1; + } + + if(sum1 >= FLETCHER_MODULE) sum1 -= FLETCHER_MODULE; + + sum2 %= FLETCHER_MODULE; /* only added so many FLETCHER_MODULE's */ + previousSum1 = (byte)(sum1 & 0xFF); + previousSum2 = (byte)(sum2 & 0xFF); + + return; + } + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while(len >= NMAX) + { + len -= NMAX; + uint n = NMAX / 11; + + do + { + sum1 += data[dataOff]; + sum2 += sum1; + sum1 += data[dataOff + 1]; + sum2 += sum1; + sum1 += data[dataOff + 2]; + sum2 += sum1; + sum1 += data[dataOff + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 2]; + sum2 += sum1; + + /* 11 sums unrolled */ + dataOff += 11; + } while(--n != 0); + + sum1 %= FLETCHER_MODULE; + sum2 %= FLETCHER_MODULE; + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if(len != 0) + { + /* avoid modulos if none remaining */ + while(len >= 11) + { + len -= 11; + sum1 += data[dataOff]; + sum2 += sum1; + sum1 += data[dataOff + 1]; + sum2 += sum1; + sum1 += data[dataOff + 2]; + sum2 += sum1; + sum1 += data[dataOff + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2]; + sum2 += sum1; + sum1 += data[dataOff + 4 + 2 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 1]; + sum2 += sum1; + sum1 += data[dataOff + 8 + 2]; + sum2 += sum1; + + dataOff += 11; + } + + while(len-- != 0) + { + sum1 += data[dataOff++]; + sum2 += sum1; + } + + sum1 %= FLETCHER_MODULE; + sum2 %= FLETCHER_MODULE; + } + + previousSum1 = (byte)(sum1 & 0xFF); + previousSum2 = (byte)(sum2 & 0xFF); + } + + /// Gets the hash of a file + /// File path. + public static byte[] File(string filename) + { + File(filename, out byte[] hash); + + return hash; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + bool useNative = Native.IsSupported; + IntPtr nativeContext = IntPtr.Zero; + + if(useNative) + { + nativeContext = fletcher16_init(); + + if(nativeContext == IntPtr.Zero) useNative = false; + } + + var fileStream = new FileStream(filename, FileMode.Open); + + byte localSum1 = 0xFF; + byte localSum2 = 0xFF; + + var buffer = new byte[65536]; + int read = fileStream.EnsureRead(buffer, 0, 65536); + + while(read > 0) + { + Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext); + + read = fileStream.EnsureRead(buffer, 0, 65536); + } + + var finalSum = (ushort)(localSum2 << 8 | localSum1); + + if(useNative) + { + fletcher16_final(nativeContext, ref finalSum); + fletcher16_free(nativeContext); + } + + hash = BigEndianBitConverter.GetBytes(finalSum); + + var fletcherOutput = new StringBuilder(); + + foreach(byte h in hash) fletcherOutput.Append(h.ToString("x2")); + + fileStream.Close(); + + return fletcherOutput.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + bool useNative = Native.IsSupported; + IntPtr nativeContext = IntPtr.Zero; + + if(useNative) + { + nativeContext = fletcher16_init(); + + if(nativeContext == IntPtr.Zero) useNative = false; + } + + byte localSum1 = 0xFF; + byte localSum2 = 0xFF; + + Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext); + + var finalSum = (ushort)(localSum2 << 8 | localSum1); + + if(useNative) + { + fletcher16_final(nativeContext, ref finalSum); + fletcher16_free(nativeContext); + } + + hash = BigEndianBitConverter.GetBytes(finalSum); + + var adlerOutput = new StringBuilder(); + + foreach(byte h in hash) adlerOutput.Append(h.ToString("x2")); + + return adlerOutput.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} \ No newline at end of file diff --git a/Aaru.Checksums/Localization/Localization.Designer.cs b/Aaru.Checksums/Localization/Localization.Designer.cs new file mode 100644 index 000000000..2a0b2bcce --- /dev/null +++ b/Aaru.Checksums/Localization/Localization.Designer.cs @@ -0,0 +1,420 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Aaru.Checksums { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Localization { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Localization() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aaru.Checksums.Localization.Localization", typeof(Localization).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Adler-32. + /// + internal static string Adler32_Name { + get { + return ResourceManager.GetString("Adler32_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assertion failed. + /// + internal static string Assertion_failed { + get { + return ResourceManager.GetString("Assertion_failed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text Pack 4 CRC 0x{0:X4}, expected 0x{1:X4}. + /// + internal static string CD_Text_Pack_four_CRC_0_expected_1 { + get { + return ResourceManager.GetString("CD_Text_Pack_four_CRC_0_expected_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text Pack 1 CRC 0x{0:X4}, expected 0x{1:X4}. + /// + internal static string CD_Text_Pack_one_CRC_0_expected_1 { + get { + return ResourceManager.GetString("CD_Text_Pack_one_CRC_0_expected_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text Pack 3 CRC 0x{0:X4}, expected 0x{1:X4}. + /// + internal static string CD_Text_Pack_three_CRC_0_expected_1 { + get { + return ResourceManager.GetString("CD_Text_Pack_three_CRC_0_expected_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text Pack 2 CRC 0x{0:X4}, expected 0x{1:X4}. + /// + internal static string CD_Text_Pack_two_CRC_0_expected_1 { + get { + return ResourceManager.GetString("CD_Text_Pack_two_CRC_0_expected_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CRC-16 (CCITT). + /// + internal static string CRC16_CCITT_Name { + get { + return ResourceManager.GetString("CRC16_CCITT_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CRC-16 (IBM). + /// + internal static string CRC16_IBM_Name { + get { + return ResourceManager.GetString("CRC16_IBM_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CRC-32. + /// + internal static string CRC32_Name { + get { + return ResourceManager.GetString("CRC32_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CRC-64 (ECMA). + /// + internal static string CRC64_ECMA_Name { + get { + return ResourceManager.GetString("CRC64_ECMA_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cyclic CDTP2 0x{0:X4}, Calc CDTP2 0x{1:X4}. + /// + internal static string Cyclic_CDTP2_0_Calc_CDTP2_1 { + get { + return ResourceManager.GetString("Cyclic_CDTP2_0_Calc_CDTP2_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cyclic CDTP3 0x{0:X4}, Calc CDTP3 0x{1:X4}. + /// + internal static string Cyclic_CDTP3_0_Calc_CDTP3_1 { + get { + return ResourceManager.GetString("Cyclic_CDTP3_0_Calc_CDTP3_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cyclic CDTP4 0x{0:X4}, Calc CDTP4 0x{1:X4}. + /// + internal static string Cyclic_CDTP4_0_Calc_CDTP4_1 { + get { + return ResourceManager.GetString("Cyclic_CDTP4_0_Calc_CDTP4_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Detected CD+EG Pack in subchannel. + /// + internal static string Detected_CD_EG_Pack_in_subchannel { + get { + return ResourceManager.GetString("Detected_CD_EG_Pack_in_subchannel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Detected CD+G Pack in subchannel. + /// + internal static string Detected_CD_G_Pack_in_subchannel { + get { + return ResourceManager.GetString("Detected_CD_G_Pack_in_subchannel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Detected CD+MIDI Pack in subchannel. + /// + internal static string Detected_CD_MIDI_Pack_in_subchannel { + get { + return ResourceManager.GetString("Detected_CD_MIDI_Pack_in_subchannel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Detected CD-TEXT Pack in subchannel. + /// + internal static string Detected_CD_TEXT_Pack_in_subchannel { + get { + return ResourceManager.GetString("Detected_CD_TEXT_Pack_in_subchannel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Detected Line Graphics Pack in subchannel. + /// + internal static string Detected_Line_Graphics_Pack_in_subchannel { + get { + return ResourceManager.GetString("Detected_Line_Graphics_Pack_in_subchannel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Detected unknown Pack type in subchannel: mode {0}, item {1}. + /// + internal static string Detected_unknown_Pack_type_in_subchannel_mode_0_item_1 { + get { + return ResourceManager.GetString("Detected_unknown_Pack_type_in_subchannel_mode_0_item_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Detected User Pack in subchannel. + /// + internal static string Detected_User_Pack_in_subchannel { + get { + return ResourceManager.GetString("Detected_User_Pack_in_subchannel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Detected Zero Pack in subchannel. + /// + internal static string Detected_Zero_Pack_in_subchannel { + get { + return ResourceManager.GetString("Detected_Zero_Pack_in_subchannel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to + /// Erasure positions as determined by roots of Eras Loc Poly: + ///. + /// + internal static string Erasure_positions_as_determined_by_roots_of_Eras_Loc_Poly { + get { + return ResourceManager.GetString("Erasure_positions_as_determined_by_roots_of_Eras_Loc_Poly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to + /// ERROR: denominator = 0 + ///. + /// + internal static string ERROR_denominator_equals_zero { + get { + return ResourceManager.GetString("ERROR_denominator_equals_zero", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to + /// Final error positions: . + /// + internal static string Final_error_positions { + get { + return ResourceManager.GetString("Final_error_positions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fletcher-16. + /// + internal static string Fletcher16_Name { + get { + return ResourceManager.GetString("Fletcher16_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fletcher-32. + /// + internal static string Fletcher32_Name { + get { + return ResourceManager.GetString("Fletcher32_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to + /// lambda(x) is WRONG + ///. + /// + internal static string lambda_is_wrong { + get { + return ResourceManager.GetString("lambda_is_wrong", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to m must be between 2 and 16 inclusive. + /// + internal static string m_must_be_between_2_and_16_inclusive { + get { + return ResourceManager.GetString("m_must_be_between_2_and_16_inclusive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MD5. + /// + internal static string MD5_Name { + get { + return ResourceManager.GetString("MD5_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not yet implemented.. + /// + internal static string Not_yet_implemented { + get { + return ResourceManager.GetString("Not_yet_implemented", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Q subchannel CRC 0x{0:X4}, expected 0x{1:X4}. + /// + internal static string Q_subchannel_CRC_0_expected_1 { + get { + return ResourceManager.GetString("Q_subchannel_CRC_0_expected_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SHA1. + /// + internal static string SHA1_Name { + get { + return ResourceManager.GetString("SHA1_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SHA256. + /// + internal static string SHA256_Name { + get { + return ResourceManager.GetString("SHA256_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SHA384. + /// + internal static string SHA384_Name { + get { + return ResourceManager.GetString("SHA384_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SHA512. + /// + internal static string SHA512_Name { + get { + return ResourceManager.GetString("SHA512_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SpamSum does not have a binary representation.. + /// + internal static string SpamSum_does_not_have_a_binary_representation { + get { + return ResourceManager.GetString("SpamSum_does_not_have_a_binary_representation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SpamSum. + /// + internal static string SpamSum_Name { + get { + return ResourceManager.GetString("SpamSum_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The input exceeds data types.. + /// + internal static string The_input_exceeds_data_types { + get { + return ResourceManager.GetString("The_input_exceeds_data_types", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trying to calculate RS without initializing!. + /// + internal static string Trying_to_calculate_RS_without_initializing { + get { + return ResourceManager.GetString("Trying_to_calculate_RS_without_initializing", resourceCulture); + } + } + } +} diff --git a/Aaru.Checksums/Localization/Localization.es.resx b/Aaru.Checksums/Localization/Localization.es.resx new file mode 100644 index 000000000..9f9a0e949 --- /dev/null +++ b/Aaru.Checksums/Localization/Localization.es.resx @@ -0,0 +1,136 @@ + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + Error de aserción + + + CRC del paquete 4 de CD-Text es 0x{0:X4} se esperaba 0x{1:X4} + + + CRC del paquete 1 de CD-Text es 0x{0:X4} se esperaba 0x{1:X4} + + + CRC del paquete 3 de CD-Text es 0x{0:X4} se esperaba 0x{1:X4} + + + CRC del paquete 4 de CD-Text es 0x{0:X4} se esperaba 0x{1:X4} + + + CDTP2 cíclico 0x{0:X4}, CDTP2 calculado 0x{1:X4} + + + CDTP3 cíclico 0x{0:X4}, CDTP3 calculado 0x{1:X4} + + + CDTP4 cíclico 0x{0:X4}, CDTP4 calculado 0x{1:X4} + + + Detectado paquete CD+EG en el subcanal + + + Detectado paquete CD+G en el subcanal + + + Detectado paquete CD+MIDI en el subcanal + + + Detectado paquete CD-TEXT en el subcanal + + + Detectado paquete de gráficos lineales en el subcanal + + + Detectado paquete de tipo desconocido en el subcanal: modo {0}, elemento {1} + + + Detectado paquete de usuario en el subcanal + + + Detectado paquete cero en el subcanal + + + Posiciones de borrado determinadas por el polinomio: + + + ERROR: denominador = 0 + + + Posiciones finales de error: + + + lambda(x) es INCORRECTO + + + m debe estar entre 2 y 16 inclusivos + + + Aún no implementado. + + + CRC del subcanal Q es 0x{0:X4}, se esperaba 0x{1:X4} + + + SpamSum no posee una representación binaria. + + + La entrada excede los tipos de datos + + + ¡Intentando calcular RS sin inicializar! + + + Adler-32 + + + CRC-16 (CCITT) + + + CRC-16 (IBM) + + + CRC-32 + + + CRC-64 (ECMA) + + + Fletcher-32 + + + Fletcher-16 + + + MD5 + + + SHA1 + + + SHA256 + + + SHA384 + + + SHA512 + + + SpamSum + + \ No newline at end of file diff --git a/Aaru.Checksums/Localization/Localization.resx b/Aaru.Checksums/Localization/Localization.resx new file mode 100644 index 000000000..4d624dda0 --- /dev/null +++ b/Aaru.Checksums/Localization/Localization.resx @@ -0,0 +1,150 @@ + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + Detected Zero Pack in subchannel + + + Detected Line Graphics Pack in subchannel + + + Detected CD+G Pack in subchannel + + + Detected CD+EG Pack in subchannel + + + Detected CD-TEXT Pack in subchannel + + + Detected CD+MIDI Pack in subchannel + + + Detected User Pack in subchannel + + + Detected unknown Pack type in subchannel: mode {0}, item {1} + + + Q subchannel CRC 0x{0:X4}, expected 0x{1:X4} + + + CD-Text Pack 1 CRC 0x{0:X4}, expected 0x{1:X4} + + + Cyclic CDTP2 0x{0:X4}, Calc CDTP2 0x{1:X4} + + + CD-Text Pack 2 CRC 0x{0:X4}, expected 0x{1:X4} + + + Cyclic CDTP3 0x{0:X4}, Calc CDTP3 0x{1:X4} + + + CD-Text Pack 3 CRC 0x{0:X4}, expected 0x{1:X4} + + + Cyclic CDTP4 0x{0:X4}, Calc CDTP4 0x{1:X4} + + + CD-Text Pack 4 CRC 0x{0:X4}, expected 0x{1:X4} + + + m must be between 2 and 16 inclusive + + + Trying to calculate RS without initializing! + + + + lambda(x) is WRONG + + + + + Erasure positions as determined by roots of Eras Loc Poly: + + + + + Final error positions: + + + + ERROR: denominator = 0 + + + + SpamSum does not have a binary representation. + + + Assertion failed + + + The input exceeds data types. + + + Not yet implemented. + + + Adler-32 + + + CRC-16 (CCITT) + + + CRC-16 (IBM) + + + CRC-32 + + + CRC-64 (ECMA) + + + Fletcher-32 + + + Fletcher-16 + + + MD5 + + + SHA1 + + + SHA256 + + + SHA384 + + + SHA512 + + + SpamSum + + \ No newline at end of file diff --git a/Aaru.Checksums/MD5Context.cs b/Aaru.Checksums/MD5Context.cs new file mode 100644 index 000000000..3061b6dd0 --- /dev/null +++ b/Aaru.Checksums/MD5Context.cs @@ -0,0 +1,145 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : MD5Context.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Wraps up .NET MD5 implementation to a Init(), Update(), Final() context. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Checksums; + +/// +/// Wraps up .NET MD5 implementation to a Init(), Update(), Final() context. +public sealed class Md5Context : IChecksum +{ + readonly MD5 _provider; + + /// Initializes the MD5 hash provider + public Md5Context() => _provider = MD5.Create(); + +#region IChecksum Members + + /// + public string Name => Localization.MD5_Name; + + /// + public Guid Id => new("C78674C4-F699-4FAB-A618-1661AF659A7C"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + _provider.TransformFinalBlock([], 0, 0); + + return _provider.Hash; + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + _provider.TransformFinalBlock([], 0, 0); + var md5Output = new StringBuilder(); + + if(_provider.Hash is null) return null; + + foreach(byte h in _provider.Hash) md5Output.Append(h.ToString("x2")); + + return md5Output.ToString(); + } + +#endregion + + /// Gets the hash of a file + /// File path. + public static byte[] File(string filename) + { + var localMd5Provider = MD5.Create(); + var fileStream = new FileStream(filename, FileMode.Open); + byte[] result = localMd5Provider.ComputeHash(fileStream); + fileStream.Close(); + + return result; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + var localMd5Provider = MD5.Create(); + var fileStream = new FileStream(filename, FileMode.Open); + hash = localMd5Provider.ComputeHash(fileStream); + var md5Output = new StringBuilder(); + + foreach(byte h in hash) md5Output.Append(h.ToString("x2")); + + fileStream.Close(); + + return md5Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + var localMd5Provider = MD5.Create(); + hash = localMd5Provider.ComputeHash(data, 0, (int)len); + var md5Output = new StringBuilder(); + + foreach(byte h in hash) md5Output.Append(h.ToString("x2")); + + return md5Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} \ No newline at end of file diff --git a/Aaru.Checksums/Native.cs b/Aaru.Checksums/Native.cs new file mode 100644 index 000000000..e2e48e033 --- /dev/null +++ b/Aaru.Checksums/Native.cs @@ -0,0 +1,81 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Native.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Checks that Aaru.Checksums.Native library is available and usable. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Checksums; + +/// Handles native implementations of compression algorithms +public static partial class Native +{ + static bool _checked; + static bool _supported; + + /// Set to return native as never supported + public static bool ForceManaged { get; set; } + + /// + /// If set to true the native library was found and loaded correctly and its reported version is + /// compatible. + /// + public static bool IsSupported + { + get + { + if(ForceManaged) return false; + + if(_checked) return _supported; + + ulong version; + _checked = true; + + try + { + version = get_acn_version(); + } + catch + { + _supported = false; + + return false; + } + + // TODO: Check version compatibility + _supported = version >= 0x06000000; + + return _supported; + } + } + + [LibraryImport("libAaru.Checksums.Native", SetLastError = true)] + private static partial ulong get_acn_version(); +} \ No newline at end of file diff --git a/Aaru.Checksums/ReedSolomon.cs b/Aaru.Checksums/ReedSolomon.cs new file mode 100644 index 000000000..8b4d811bf --- /dev/null +++ b/Aaru.Checksums/ReedSolomon.cs @@ -0,0 +1,632 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ReedSolomon.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Calculates a Reed-Solomon. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright (C) 1996 Phil Karn +// Copyright (C) 1995 Robert Morelos-Zaragoza +// Copyright (C) 1995 Hari Thirumoorthy +// ****************************************************************************/ + +/* + * Reed-Solomon coding and decoding + * Phil Karn (karn at ka9q.ampr.org) September 1996 + * + * This file is derived from the program "new_rs_erasures.c" by Robert + * Morelos-Zaragoza (robert at spectra.eng.hawaii.edu) and Hari Thirumoorthy + * (harit at spectra.eng.hawaii.edu), Aug 1995 + * + * I've made changes to improve performance, clean up the code and make it + * easier to follow. Data is now passed to the encoding and decoding functions + * through arguments rather than in global arrays. The decode function returns + * the number of corrected symbols, or -1 if the word is uncorrectable. + * + * This code supports a symbol size from 2 bits up to 16 bits, + * implying a block size of 3 2-bit symbols (6 bits) up to 65535 + * 16-bit symbols (1,048,560 bits). The code parameters are set in rs.h. + * + * Note that if symbols larger than 8 bits are used, the type of each + * data array element switches from unsigned char to unsigned int. The + * caller must ensure that elements larger than the symbol range are + * not passed to the encoder or decoder. + * + */ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.Console; + +namespace Aaru.Checksums; + +/// Implements the Reed-Solomon algorithm +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public class ReedSolomon +{ + /// Alpha exponent for the first root of the generator polynomial + const int B0 = 1; + const string MODULE_NAME = "Reed Solomon"; + /// No legal value in index form represents zero, so we need a special value for this purpose + int _a0; + /// index->polynomial form conversion table + int[] _alphaTo; + /// Generator polynomial g(x) Degree of g(x) = 2*TT has roots @**B0, @**(B0+1), ... ,@^(B0+2*TT-1) + int[] _gg; + /// Polynomial->index form conversion table + int[] _indexOf; + bool _initialized; + int _mm, _kk, _nn; + /// + /// Primitive polynomials - see Lin & Costello, Error Control Coding Appendix A, and Lee & Messerschmitt, Digital + /// Communication p. 453. + /// + int[] _pp; + + /// Initializes the Reed-Solomon with RS(n,k) with GF(2^m) + public void InitRs(int n, int k, int m) + { + _pp = m switch + { + 2 => [1, 1, 1], + 3 => [1, 1, 0, 1], + 4 => [1, 1, 0, 0, 1], + 5 => [1, 0, 1, 0, 0, 1], + 6 => [1, 1, 0, 0, 0, 0, 1], + 7 => [1, 0, 0, 1, 0, 0, 0, 1], + 8 => [1, 0, 1, 1, 1, 0, 0, 0, 1], + 9 => [1, 0, 0, 0, 1, 0, 0, 0, 0, 1], + 10 => [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1], + 11 => [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1], + 12 => [1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1], + 13 => [1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1], + 14 => [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1], + 15 => [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + 16 => [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1], + _ => throw new ArgumentOutOfRangeException(nameof(m), + Localization.m_must_be_between_2_and_16_inclusive) + }; + + _mm = m; + _kk = k; + _nn = n; + _a0 = n; + _alphaTo = new int[n + 1]; + _indexOf = new int[n + 1]; + + _gg = new int[_nn - _kk + 1]; + + generate_gf(); + gen_poly(); + + _initialized = true; + } + + int Modnn(int x) + { + while(x >= _nn) + { + x -= _nn; + x = (x >> _mm) + (x & _nn); + } + + return x; + } + + static int Min(int a, int b) => a < b ? a : b; + + static void Clear(ref int[] a, int n) + { + int ci; + + for(ci = n - 1; ci >= 0; ci--) a[ci] = 0; + } + + static void Copy(ref int[] a, ref int[] b, int n) + { + int ci; + + for(ci = n - 1; ci >= 0; ci--) a[ci] = b[ci]; + } + + static void Copydown(ref int[] a, ref int[] b, int n) + { + int ci; + + for(ci = n - 1; ci >= 0; ci--) a[ci] = b[ci]; + } + + /* generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] + lookup tables: index->polynomial form alpha_to[] contains j=alpha**i; + polynomial form -> index form index_of[j=alpha**i] = i + alpha=2 is the primitive element of GF(2**m) + HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows: + Let @ represent the primitive element commonly called "alpha" that + is the root of the primitive polynomial p(x). Then in GF(2^m), for any + 0 <= i <= 2^m-2, + @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) + where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation + of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for + example the polynomial representation of @^5 would be given by the binary + representation of the integer "alpha_to[5]". + Similarily, index_of[] can be used as follows: + As above, let @ represent the primitive element of GF(2^m) that is + the root of the primitive polynomial p(x). In order to find the power + of @ (alpha) that has the polynomial representation + a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) + we consider the integer "i" whose binary representation with a(0) being LSB + and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry + "index_of[i]". Now, @^index_of[i] is that element whose polynomial + representation is (a(0),a(1),a(2),...,a(m-1)). + NOTE: + The element alpha_to[2^m-1] = 0 always signifying that the + representation of "@^infinity" = 0 is (0,0,0,...,0). + Similarily, the element index_of[0] = A0 always signifying + that the power of alpha which has the polynomial representation + (0,0,...,0) is "infinity". + + */ + void generate_gf() + { + int i; + + var mask = 1; + _alphaTo[_mm] = 0; + + for(i = 0; i < _mm; i++) + { + _alphaTo[i] = mask; + _indexOf[_alphaTo[i]] = i; + + /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */ + if(_pp[i] != 0) _alphaTo[_mm] ^= mask; /* Bit-wise EXOR operation */ + + mask <<= 1; /* single left-shift */ + } + + _indexOf[_alphaTo[_mm]] = _mm; + /* + * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by + * poly-repr of @^i shifted left one-bit and accounting for any @^MM + * term that may occur when poly-repr of @^i is shifted. + */ + mask >>= 1; + + for(i = _mm + 1; i < _nn; i++) + { + if(_alphaTo[i - 1] >= mask) + _alphaTo[i] = _alphaTo[_mm] ^ (_alphaTo[i - 1] ^ mask) << 1; + else + _alphaTo[i] = _alphaTo[i - 1] << 1; + + _indexOf[_alphaTo[i]] = i; + } + + _indexOf[0] = _a0; + _alphaTo[_nn] = 0; + } + + /* + * Obtain the generator polynomial of the TT-error correcting, length + * NN=(2**MM -1) Reed Solomon code from the product of (X+@**(B0+i)), i = 0, + * ... ,(2*TT-1) + * + * Examples: + * + * If B0 = 1, TT = 1. deg(g(x)) = 2*TT = 2. + * g(x) = (x+@) (x+@**2) + * + * If B0 = 0, TT = 2. deg(g(x)) = 2*TT = 4. + * g(x) = (x+1) (x+@) (x+@**2) (x+@**3) + */ + void gen_poly() + { + int i; + + _gg[0] = _alphaTo[B0]; + _gg[1] = 1; /* g(x) = (X+@**B0) initially */ + + for(i = 2; i <= _nn - _kk; i++) + { + _gg[i] = 1; + + /* + * Below multiply (Gg[0]+Gg[1]*x + ... +Gg[i]x^i) by + * (@**(B0+i-1) + x) + */ + for(int j = i - 1; j > 0; j--) + { + if(_gg[j] != 0) + _gg[j] = _gg[j - 1] ^ _alphaTo[Modnn(_indexOf[_gg[j]] + B0 + i - 1)]; + else + _gg[j] = _gg[j - 1]; + } + + /* Gg[0] can never be zero */ + _gg[0] = _alphaTo[Modnn(_indexOf[_gg[0]] + B0 + i - 1)]; + } + + /* convert Gg[] to index form for quicker encoding */ + for(i = 0; i <= _nn - _kk; i++) _gg[i] = _indexOf[_gg[i]]; + } + + /* + * take the string of symbols in data[i], i=0..(k-1) and encode + * systematically to produce NN-KK parity symbols in bb[0]..bb[NN-KK-1] data[] + * is input and bb[] is output in polynomial form. Encoding is done by using + * a feedback shift register with appropriate connections specified by the + * elements of Gg[], which was generated above. Codeword is c(X) = + * data(X)*X**(NN-KK)+ b(X) + */ + /// Takes the symbols in data to output parity in bb. + /// Returns -1 if an illegal symbol is found. + /// Data symbols. + /// Outs parity symbols. + public int encode_rs(int[] data, out int[] bb) + { + if(!_initialized) + throw new UnauthorizedAccessException(Localization.Trying_to_calculate_RS_without_initializing); + + int i; + bb = new int[_nn - _kk]; + + Clear(ref bb, _nn - _kk); + + for(i = _kk - 1; i >= 0; i--) + { + if(_mm != 8) + if(data[i] > _nn) + return -1; /* Illegal symbol */ + + int feedback = _indexOf[data[i] ^ bb[_nn - _kk - 1]]; + + if(feedback != _a0) + { + /* feedback term is non-zero */ + for(int j = _nn - _kk - 1; j > 0; j--) + { + if(_gg[j] != _a0) + bb[j] = bb[j - 1] ^ _alphaTo[Modnn(_gg[j] + feedback)]; + else + bb[j] = bb[j - 1]; + } + + bb[0] = _alphaTo[Modnn(_gg[0] + feedback)]; + } + else + { + /* feedback term is zero. encoder becomes a + * single-byte shifter */ + for(int j = _nn - _kk - 1; j > 0; j--) bb[j] = bb[j - 1]; + + bb[0] = 0; + } + } + + return 0; + } + + /* + * Performs ERRORS+ERASURES decoding of RS codes. If decoding is successful, + * writes the codeword into data[] itself. Otherwise data[] is unaltered. + * + * Return number of symbols corrected, or -1 if codeword is illegal + * or uncorrectable. + * + * First "no_eras" erasures are declared by the calling program. Then, the + * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). + * If the number of channel errors is not greater than "t_after_eras" the + * transmitted codeword will be recovered. Details of algorithm can be found + * in R. Blahut's "Theory ... of Error-Correcting Codes". + */ + /// Decodes the RS. If decoding is successful outputs corrected data symbols. + /// Returns corrected symbols, -1 if illegal or uncorrectable + /// Data symbols. + /// Position of erasures. + /// Number of erasures. + public int eras_dec_rs(ref int[] data, out int[] erasPos, int noEras) + { + if(!_initialized) + throw new UnauthorizedAccessException(Localization.Trying_to_calculate_RS_without_initializing); + + erasPos = new int[_nn - _kk]; + int i, j; + int q, tmp; + var recd = new int[_nn]; + var lambda = new int[_nn - _kk + 1]; /* Err+Eras Locator poly */ + var s = new int[_nn - _kk + 1]; /* syndrome poly */ + var b = new int[_nn - _kk + 1]; + var t = new int[_nn - _kk + 1]; + var omega = new int[_nn - _kk + 1]; + var root = new int[_nn - _kk]; + var reg = new int[_nn - _kk + 1]; + var loc = new int[_nn - _kk]; + int count; + + /* data[] is in polynomial form, copy and convert to index form */ + for(i = _nn - 1; i >= 0; i--) + { + if(_mm != 8) + if(data[i] > _nn) + return -1; /* Illegal symbol */ + + recd[i] = _indexOf[data[i]]; + } + + /* first form the syndromes; i.e., evaluate recd(x) at roots of g(x) + * namely @**(B0+i), i = 0, ... ,(NN-KK-1) + */ + var synError = 0; + + for(i = 1; i <= _nn - _kk; i++) + { + tmp = 0; + + for(j = 0; j < _nn; j++) + if(recd[j] != _a0) /* recd[j] in index form */ + tmp ^= _alphaTo[Modnn(recd[j] + (B0 + i - 1) * j)]; + + synError |= tmp; /* set flag if non-zero syndrome => + * error */ + + /* store syndrome in index form */ + s[i] = _indexOf[tmp]; + } + + if(synError == 0) return 0; + + Clear(ref lambda, _nn - _kk); + lambda[0] = 1; + + if(noEras > 0) + { + /* Init lambda to be the erasure locator polynomial */ + lambda[1] = _alphaTo[erasPos[0]]; + + for(i = 1; i < noEras; i++) + { + int u = erasPos[i]; + + for(j = i + 1; j > 0; j--) + { + tmp = _indexOf[lambda[j - 1]]; + + if(tmp != _a0) lambda[j] ^= _alphaTo[Modnn(u + tmp)]; + } + } + +#if DEBUG + /* find roots of the erasure location polynomial */ + for(i = 1; i <= noEras; i++) reg[i] = _indexOf[lambda[i]]; + + count = 0; + + for(i = 1; i <= _nn; i++) + { + q = 1; + + for(j = 1; j <= noEras; j++) + { + if(reg[j] == _a0) continue; + + reg[j] = Modnn(reg[j] + j); + q ^= _alphaTo[reg[j]]; + } + + if(q != 0) continue; + + /* store root and error location + * number indices + */ + root[count] = i; + loc[count] = _nn - i; + count++; + } + + if(count != noEras) + { + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.lambda_is_wrong); + + return -1; + } + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Erasure_positions_as_determined_by_roots_of_Eras_Loc_Poly); + + for(i = 0; i < count; i++) AaruConsole.DebugWriteLine(MODULE_NAME, "{0} ", loc[i]); + + AaruConsole.DebugWriteLine(MODULE_NAME, "\n"); +#endif + } + + for(i = 0; i < _nn - _kk + 1; i++) b[i] = _indexOf[lambda[i]]; + + /* + * Begin Berlekamp-Massey algorithm to determine error+erasure + * locator polynomial + */ + int r = noEras; + int el = noEras; + + while(++r <= _nn - _kk) + { + /* r is the step number */ + /* Compute discrepancy at the r-th step in poly-form */ + var discrR = 0; + + for(i = 0; i < r; i++) + if(lambda[i] != 0 && s[r - i] != _a0) + discrR ^= _alphaTo[Modnn(_indexOf[lambda[i]] + s[r - i])]; + + discrR = _indexOf[discrR]; /* Index form */ + + if(discrR == _a0) + { + /* 2 lines below: B(x) <-- x*B(x) */ + Copydown(ref b, ref b, _nn - _kk); + b[0] = _a0; + } + else + { + /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */ + t[0] = lambda[0]; + + for(i = 0; i < _nn - _kk; i++) + { + if(b[i] != _a0) + t[i + 1] = lambda[i + 1] ^ _alphaTo[Modnn(discrR + b[i])]; + else + t[i + 1] = lambda[i + 1]; + } + + if(2 * el <= r + noEras - 1) + { + el = r + noEras - el; + + /* + * 2 lines below: B(x) <-- inv(discr_r) * + * lambda(x) + */ + for(i = 0; i <= _nn - _kk; i++) + b[i] = lambda[i] == 0 ? _a0 : Modnn(_indexOf[lambda[i]] - discrR + _nn); + } + else + { + /* 2 lines below: B(x) <-- x*B(x) */ + Copydown(ref b, ref b, _nn - _kk); + b[0] = _a0; + } + + Copy(ref lambda, ref t, _nn - _kk + 1); + } + } + + /* Convert lambda to index form and compute deg(lambda(x)) */ + var degLambda = 0; + + for(i = 0; i < _nn - _kk + 1; i++) + { + lambda[i] = _indexOf[lambda[i]]; + + if(lambda[i] != _a0) degLambda = i; + } + + /* + * Find roots of the error+erasure locator polynomial. By Chien + * Search + */ + int temp = reg[0]; + Copy(ref reg, ref lambda, _nn - _kk); + reg[0] = temp; + count = 0; /* Number of roots of lambda(x) */ + + for(i = 1; i <= _nn; i++) + { + q = 1; + + for(j = degLambda; j > 0; j--) + { + if(reg[j] == _a0) continue; + + reg[j] = Modnn(reg[j] + j); + q ^= _alphaTo[reg[j]]; + } + + if(q != 0) continue; + + /* store root (index-form) and error location number */ + root[count] = i; + loc[count] = _nn - i; + count++; + } + +#if DEBUG + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Final_error_positions); + + for(i = 0; i < count; i++) AaruConsole.DebugWriteLine(MODULE_NAME, "{0} ", loc[i]); + + AaruConsole.DebugWriteLine(MODULE_NAME, "\n"); +#endif + + if(degLambda != count) return -1; + + /* + * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo + * x**(NN-KK)). in index form. Also find deg(omega). + */ + var degOmega = 0; + + for(i = 0; i < _nn - _kk; i++) + { + tmp = 0; + j = degLambda < i ? degLambda : i; + + for(; j >= 0; j--) + if(s[i + 1 - j] != _a0 && lambda[j] != _a0) + tmp ^= _alphaTo[Modnn(s[i + 1 - j] + lambda[j])]; + + if(tmp != 0) degOmega = i; + + omega[i] = _indexOf[tmp]; + } + + omega[_nn - _kk] = _a0; + + /* + * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form + */ + for(j = count - 1; j >= 0; j--) + { + var num1 = 0; + + for(i = degOmega; i >= 0; i--) + if(omega[i] != _a0) + num1 ^= _alphaTo[Modnn(omega[i] + i * root[j])]; + + int num2 = _alphaTo[Modnn(root[j] * (B0 - 1) + _nn)]; + var den = 0; + + /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ + for(i = Min(degLambda, _nn - _kk - 1) & ~1; i >= 0; i -= 2) + if(lambda[i + 1] != _a0) + den ^= _alphaTo[Modnn(lambda[i + 1] + i * root[j])]; + + if(den == 0) + { + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.ERROR_denominator_equals_zero); + + return -1; + } + + /* Apply error to data */ + if(num1 != 0) data[loc[j]] ^= _alphaTo[Modnn(_indexOf[num1] + _indexOf[num2] + _nn - _indexOf[den])]; + } + + return count; + } +} \ No newline at end of file diff --git a/Aaru.Checksums/Register.cs b/Aaru.Checksums/Register.cs new file mode 100644 index 000000000..3c909dddb --- /dev/null +++ b/Aaru.Checksums/Register.cs @@ -0,0 +1,46 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Register.cs +// Author(s) : Natalia Portillo +// +// Component : Core algorithms. +// +// --[ Description ] ---------------------------------------------------------- +// +// Registers all plugins in this assembly. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Checksums; + +// Needs to have the interface here so the source generator knows THIS IS the class +// ReSharper disable once RedundantExtendsListEntry +/// +public sealed partial class Register : IPluginRegister; \ No newline at end of file diff --git a/Aaru.Checksums/SHA1Context.cs b/Aaru.Checksums/SHA1Context.cs new file mode 100644 index 000000000..e58096b61 --- /dev/null +++ b/Aaru.Checksums/SHA1Context.cs @@ -0,0 +1,151 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SHA1Context.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Wraps up .NET SHA1 implementation to a Init(), Update(), Final() context. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Checksums; + +/// +/// Wraps up .NET SHA1 implementation to a Init(), Update(), Final() context. +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public sealed class Sha1Context : IChecksum +{ + readonly SHA1 _provider; + + /// Initializes the SHA1 hash provider + public Sha1Context() => _provider = SHA1.Create(); + +#region IChecksum Members + + /// + public string Name => Localization.SHA1_Name; + + /// + public Guid Id => new("5C28939D-DCBB-4C6E-8498-C509ABD99FC2"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + _provider.TransformFinalBlock([], 0, 0); + + return _provider.Hash; + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + _provider.TransformFinalBlock([], 0, 0); + var sha1Output = new StringBuilder(); + + if(_provider.Hash is null) return null; + + foreach(byte h in _provider.Hash) sha1Output.Append(h.ToString("x2")); + + return sha1Output.ToString(); + } + +#endregion + + /// Gets the hash of a file + /// File path. + + // ReSharper disable once ReturnTypeCanBeEnumerable.Global + public static byte[] File(string filename) + { + var localSha1Provider = SHA1.Create(); + var fileStream = new FileStream(filename, FileMode.Open); + byte[] result = localSha1Provider.ComputeHash(fileStream); + fileStream.Close(); + + return result; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + var localSha1Provider = SHA1.Create(); + var fileStream = new FileStream(filename, FileMode.Open); + hash = localSha1Provider.ComputeHash(fileStream); + var sha1Output = new StringBuilder(); + + foreach(byte h in hash) sha1Output.Append(h.ToString("x2")); + + fileStream.Close(); + + return sha1Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + var localSha1Provider = SHA1.Create(); + hash = localSha1Provider.ComputeHash(data, 0, (int)len); + var sha1Output = new StringBuilder(); + + foreach(byte h in hash) sha1Output.Append(h.ToString("x2")); + + return sha1Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} \ No newline at end of file diff --git a/Aaru.Checksums/SHA256Context.cs b/Aaru.Checksums/SHA256Context.cs new file mode 100644 index 000000000..ca66320d5 --- /dev/null +++ b/Aaru.Checksums/SHA256Context.cs @@ -0,0 +1,151 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SHA256Context.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Wraps up .NET SHA256 implementation to a Init(), Update(), Final() context. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Checksums; + +/// +/// Wraps up .NET SHA256 implementation to a Init(), Update(), Final() context. +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public sealed class Sha256Context : IChecksum +{ + readonly SHA256 _provider; + + /// Initializes the SHA256 hash provider + public Sha256Context() => _provider = SHA256.Create(); + +#region IChecksum Members + + /// + public string Name => Localization.SHA256_Name; + + /// + public Guid Id => new("A6F0EF52-064D-41D1-8619-240481749B70"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + _provider.TransformFinalBlock([], 0, 0); + + return _provider.Hash; + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + _provider.TransformFinalBlock([], 0, 0); + var sha256Output = new StringBuilder(); + + if(_provider.Hash is null) return null; + + foreach(byte h in _provider.Hash) sha256Output.Append(h.ToString("x2")); + + return sha256Output.ToString(); + } + +#endregion + + /// Gets the hash of a file + /// File path. + + // ReSharper disable once ReturnTypeCanBeEnumerable.Global + public static byte[] File(string filename) + { + var localSha256Provider = SHA256.Create(); + var fileStream = new FileStream(filename, FileMode.Open); + byte[] result = localSha256Provider.ComputeHash(fileStream); + fileStream.Close(); + + return result; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + var localSha256Provider = SHA256.Create(); + var fileStream = new FileStream(filename, FileMode.Open); + hash = localSha256Provider.ComputeHash(fileStream); + var sha256Output = new StringBuilder(); + + foreach(byte h in hash) sha256Output.Append(h.ToString("x2")); + + fileStream.Close(); + + return sha256Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + var localSha256Provider = SHA256.Create(); + hash = localSha256Provider.ComputeHash(data, 0, (int)len); + var sha256Output = new StringBuilder(); + + foreach(byte h in hash) sha256Output.Append(h.ToString("x2")); + + return sha256Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} \ No newline at end of file diff --git a/Aaru.Checksums/SHA384Context.cs b/Aaru.Checksums/SHA384Context.cs new file mode 100644 index 000000000..9d52ae6a2 --- /dev/null +++ b/Aaru.Checksums/SHA384Context.cs @@ -0,0 +1,152 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SHA384Context.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Wraps up .NET SHA384 implementation to a Init(), Update(), Final() context. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Checksums; + +/// +/// Wraps up .NET SHA384 implementation to a Init(), Update(), Final() context. +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public sealed class Sha384Context : IChecksum +{ + readonly SHA384 _provider; + + /// Initializes the SHA384 hash provider + public Sha384Context() => _provider = SHA384.Create(); + +#region IChecksum Members + + /// + public string Name => Localization.SHA384_Name; + + /// + public Guid Id => new("4A2A1820-E157-4842-B1E2-0E629FA60DDD"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + _provider.TransformFinalBlock([], 0, 0); + + return _provider.Hash; + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + _provider.TransformFinalBlock([], 0, 0); + var sha384Output = new StringBuilder(); + + if(_provider.Hash is null) return null; + + foreach(byte h in _provider.Hash) sha384Output.Append(h.ToString("x2")); + + return sha384Output.ToString(); + } + +#endregion + + /// Gets the hash of a file + /// File path. + + // ReSharper disable once ReturnTypeCanBeEnumerable.Global + public static byte[] File(string filename) + { + var localSha384Provider = SHA384.Create(); + var fileStream = new FileStream(filename, FileMode.Open); + byte[] result = localSha384Provider.ComputeHash(fileStream); + fileStream.Close(); + + return result; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + var localSha384Provider = SHA384.Create(); + var fileStream = new FileStream(filename, FileMode.Open); + hash = localSha384Provider.ComputeHash(fileStream); + var sha384Output = new StringBuilder(); + + foreach(byte h in hash) sha384Output.Append(h.ToString("x2")); + + fileStream.Close(); + + return sha384Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + var localSha384Provider = SHA384.Create(); + hash = localSha384Provider.ComputeHash(data, 0, (int)len); + var sha384Output = new StringBuilder(); + + foreach(byte h in hash) sha384Output.Append(h.ToString("x2")); + + return sha384Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} \ No newline at end of file diff --git a/Aaru.Checksums/SHA512Context.cs b/Aaru.Checksums/SHA512Context.cs new file mode 100644 index 000000000..e0e7ab337 --- /dev/null +++ b/Aaru.Checksums/SHA512Context.cs @@ -0,0 +1,150 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SHA512Context.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Wraps up .NET SHA512 implementation to a Init(), Update(), Final() context. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Checksums; + +/// +/// Wraps up .NET SHA512 implementation to a Init(), Update(), Final() context. +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public sealed class Sha512Context : IChecksum +{ + readonly SHA512 _provider; + + /// Initializes the SHA512 hash provider + public Sha512Context() => _provider = SHA512.Create(); + +#region IChecksum Members + + /// + public string Name => Localization.SHA512_Name; + + /// + public Guid Id => new("1E167BCB-2362-44DA-B5B0-B7ED3A22D5A6"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() + { + _provider.TransformFinalBlock([], 0, 0); + + return _provider.Hash; + } + + /// + /// Returns a hexadecimal representation of the hash value. + public string End() + { + _provider.TransformFinalBlock([], 0, 0); + var sha512Output = new StringBuilder(); + + if(_provider.Hash is null) return null; + + foreach(byte h in _provider.Hash) sha512Output.Append(h.ToString("x2")); + + return sha512Output.ToString(); + } + +#endregion + + /// Gets the hash of a file + /// File path. + public static byte[] File(string filename) + { + var localSha512Provider = SHA512.Create(); + var fileStream = new FileStream(filename, FileMode.Open); + byte[] result = localSha512Provider.ComputeHash(fileStream); + fileStream.Close(); + + return result; + } + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + var localSha512Provider = SHA512.Create(); + var fileStream = new FileStream(filename, FileMode.Open); + hash = localSha512Provider.ComputeHash(fileStream); + var sha512Output = new StringBuilder(); + + foreach(byte h in hash) sha512Output.Append(h.ToString("x2")); + + fileStream.Close(); + + return sha512Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + var localSha512Provider = SHA512.Create(); + hash = localSha512Provider.ComputeHash(data, 0, (int)len); + var sha512Output = new StringBuilder(); + + foreach(byte h in hash) sha512Output.Append(h.ToString("x2")); + + return sha512Output.ToString(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); +} \ No newline at end of file diff --git a/Aaru.Checksums/SpamSumContext.cs b/Aaru.Checksums/SpamSumContext.cs new file mode 100644 index 000000000..e93b28c9f --- /dev/null +++ b/Aaru.Checksums/SpamSumContext.cs @@ -0,0 +1,531 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SpamSumContext.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Implements the SpamSum fuzzy hashing algorithm. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// Based on ssdeep +// Copyright (C) 2002 Andrew Tridgell +// Copyright (C) 2006 ManTech International Corporation +// Copyright (C) 2013 Helmut Grohne +// +// Earlier versions of this code were named fuzzy.c and can be found at: +// http://www.samba.org/ftp/unpacked/junkcode/spamsum/ +// http://ssdeep.sf.net/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Checksums; + +/// +/// Implements the SpamSum fuzzy hashing algorithm. +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedParameter.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "OutParameterValueIsAlwaysDiscarded.Global")] +public sealed class SpamSumContext : IChecksum +{ + const uint ROLLING_WINDOW = 7; + const uint MIN_BLOCKSIZE = 3; + const uint HASH_PRIME = 0x01000193; + const uint HASH_INIT = 0x28021967; + const uint NUM_BLOCKHASHES = 31; + const uint SPAMSUM_LENGTH = 64; + const uint FUZZY_MAX_RESULT = 2 * SPAMSUM_LENGTH + 20; + + //"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + readonly byte[] _b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"u8.ToArray(); + FuzzyState _self; + + /// Initializes the SpamSum structures + public SpamSumContext() + { + _self = new FuzzyState + { + Bh = new BlockhashContext[NUM_BLOCKHASHES] + }; + + for(var i = 0; i < NUM_BLOCKHASHES; i++) _self.Bh[i].Digest = new byte[SPAMSUM_LENGTH]; + + _self.Bhstart = 0; + _self.Bhend = 1; + _self.Bh[0].H = HASH_INIT; + _self.Bh[0].Halfh = HASH_INIT; + _self.Bh[0].Digest[0] = 0; + _self.Bh[0].Halfdigest = 0; + _self.Bh[0].Dlen = 0; + _self.TotalSize = 0; + roll_init(); + } + +#region IChecksum Members + + /// + public string Name => Localization.SpamSum_Name; + + /// + public Guid Id => new("DA692981-3291-47D8-B8B9-A87F0605F6E9"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) + { + _self.TotalSize += len; + + for(var i = 0; i < len; i++) fuzzy_engine_step(data[i]); + } + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() => + throw new NotImplementedException(Localization.SpamSum_does_not_have_a_binary_representation); + + /// + /// Returns a base64 representation of the hash value. + public string End() + { + FuzzyDigest(out byte[] result); + + return CToString(result); + } + +#endregion + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void roll_init() => _self.Roll = new RollState + { + Window = new byte[ROLLING_WINDOW] + }; + + /* + * a rolling hash, based on the Adler checksum. By using a rolling hash + * we can perform auto resynchronisation after inserts/deletes + + * internally, h1 is the sum of the bytes in the window and h2 + * is the sum of the bytes times the index + + * h3 is a shift/xor based rolling hash, and is mostly needed to ensure that + * we can cope with large blocksize values + */ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void roll_hash(byte c) + { + _self.Roll.H2 -= _self.Roll.H1; + _self.Roll.H2 += ROLLING_WINDOW * c; + + _self.Roll.H1 += c; + _self.Roll.H1 -= _self.Roll.Window[_self.Roll.N % ROLLING_WINDOW]; + + _self.Roll.Window[_self.Roll.N % ROLLING_WINDOW] = c; + _self.Roll.N++; + + /* The original spamsum AND'ed this value with 0xFFFFFFFF which + * in theory should have no effect. This AND has been removed + * for performance (jk) */ + _self.Roll.H3 <<= 5; + _self.Roll.H3 ^= c; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + uint roll_sum() => _self.Roll.H1 + _self.Roll.H2 + _self.Roll.H3; + + /* A simple non-rolling hash, based on the FNV hash. */ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static uint sum_hash(byte c, uint h) => h * HASH_PRIME ^ c; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static uint SSDEEP_BS(uint index) => MIN_BLOCKSIZE << (int)index; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void fuzzy_try_fork_blockhash() + { + switch(_self.Bhend) + { + case >= NUM_BLOCKHASHES: + return; + + // assert + case 0: + throw new Exception(Localization.Assertion_failed); + } + + uint obh = _self.Bhend - 1; + uint nbh = _self.Bhend; + _self.Bh[nbh].H = _self.Bh[obh].H; + _self.Bh[nbh].Halfh = _self.Bh[obh].Halfh; + _self.Bh[nbh].Digest[0] = 0; + _self.Bh[nbh].Halfdigest = 0; + _self.Bh[nbh].Dlen = 0; + ++_self.Bhend; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void fuzzy_try_reduce_blockhash() + { + if(_self.Bhstart >= _self.Bhend) throw new Exception(Localization.Assertion_failed); + + if(_self.Bhend - _self.Bhstart < 2) + /* Need at least two working hashes. */ + return; + + if((ulong)SSDEEP_BS(_self.Bhstart) * SPAMSUM_LENGTH >= _self.TotalSize) + /* Initial blocksize estimate would select this or a smaller + * blocksize. */ + return; + + if(_self.Bh[_self.Bhstart + 1].Dlen < SPAMSUM_LENGTH / 2) + /* Estimate adjustment would select this blocksize. */ + return; + + /* At this point we are clearly no longer interested in the + * start_blocksize. Get rid of it. */ + ++_self.Bhstart; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void fuzzy_engine_step(byte c) + { + uint i; + /* At each character we update the rolling hash and the normal hashes. + * When the rolling hash hits a reset value then we emit a normal hash + * as a element of the signature and reset the normal hash. */ + roll_hash(c); + ulong h = roll_sum(); + + for(i = _self.Bhstart; i < _self.Bhend; ++i) + { + _self.Bh[i].H = sum_hash(c, _self.Bh[i].H); + _self.Bh[i].Halfh = sum_hash(c, _self.Bh[i].Halfh); + } + + for(i = _self.Bhstart; i < _self.Bhend; ++i) + { + /* With growing blocksize almost no runs fail the next test. */ + if(h % SSDEEP_BS(i) != SSDEEP_BS(i) - 1) + /* Once this condition is false for one bs, it is + * automatically false for all further bs. I.e. if + * h === -1 (mod 2*bs) then h === -1 (mod bs). */ + break; + + /* We have hit a reset point. We now emit hashes which are + * based on all characters in the piece of the message between + * the last reset point and this one */ + if(0 == _self.Bh[i].Dlen) fuzzy_try_fork_blockhash(); + + _self.Bh[i].Digest[_self.Bh[i].Dlen] = _b64[_self.Bh[i].H % 64]; + _self.Bh[i].Halfdigest = _b64[_self.Bh[i].Halfh % 64]; + + if(_self.Bh[i].Dlen < SPAMSUM_LENGTH - 1) + { + /* We can have a problem with the tail overflowing. The + * easiest way to cope with this is to only reset the + * normal hash if we have room for more characters in + * our signature. This has the effect of combining the + * last few pieces of the message into a single piece + * */ + _self.Bh[i].Digest[++_self.Bh[i].Dlen] = 0; + _self.Bh[i].H = HASH_INIT; + + if(_self.Bh[i].Dlen >= SPAMSUM_LENGTH / 2) continue; + + _self.Bh[i].Halfh = HASH_INIT; + _self.Bh[i].Halfdigest = 0; + } + else + fuzzy_try_reduce_blockhash(); + } + } + + // CLAUNIA: Flags seems to never be used in ssdeep, so I just removed it for code simplicity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void FuzzyDigest(out byte[] result) + { + var sb = new StringBuilder(); + uint bi = _self.Bhstart; + uint h = roll_sum(); + var remain = (int)(FUZZY_MAX_RESULT - 1); /* Exclude terminating '\0'. */ + result = new byte[FUZZY_MAX_RESULT]; + + /* Verify that our elimination was not overeager. */ + if(!(bi == 0 || (ulong)SSDEEP_BS(bi) / 2 * SPAMSUM_LENGTH < _self.TotalSize)) + throw new Exception(Localization.Assertion_failed); + + /* Initial blocksize guess. */ + while((ulong)SSDEEP_BS(bi) * SPAMSUM_LENGTH < _self.TotalSize) + { + ++bi; + + if(bi >= NUM_BLOCKHASHES) throw new OverflowException(Localization.The_input_exceeds_data_types); + } + + /* Adapt blocksize guess to actual digest length. */ + while(bi >= _self.Bhend) --bi; + + while(bi > _self.Bhstart && _self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2) --bi; + + if(bi > 0 && _self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2) throw new Exception(Localization.Assertion_failed); + + sb.Append($"{SSDEEP_BS(bi)}:"); + int i = Encoding.ASCII.GetBytes(sb.ToString()).Length; + + if(i <= 0) + /* Maybe snprintf has set errno here? */ + throw new OverflowException(Localization.The_input_exceeds_data_types); + + if(i >= remain) throw new Exception(Localization.Assertion_failed); + + remain -= i; + + Array.Copy(Encoding.ASCII.GetBytes(sb.ToString()), 0, result, 0, i); + + int resultOff = i; + + i = (int)_self.Bh[bi].Dlen; + + if(i > remain) throw new Exception(Localization.Assertion_failed); + + Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i); + resultOff += i; + remain -= i; + + if(h != 0) + { + if(remain <= 0) throw new Exception(Localization.Assertion_failed); + + result[resultOff] = _b64[_self.Bh[bi].H % 64]; + + if(i < 3 || + result[resultOff] != result[resultOff - 1] || + result[resultOff] != result[resultOff - 2] || + result[resultOff] != result[resultOff - 3]) + { + ++resultOff; + --remain; + } + } + else if(_self.Bh[bi].Digest[i] != 0) + { + if(remain <= 0) throw new Exception(Localization.Assertion_failed); + + result[resultOff] = _self.Bh[bi].Digest[i]; + + if(i < 3 || + result[resultOff] != result[resultOff - 1] || + result[resultOff] != result[resultOff - 2] || + result[resultOff] != result[resultOff - 3]) + { + ++resultOff; + --remain; + } + } + + if(remain <= 0) throw new Exception(Localization.Assertion_failed); + + result[resultOff++] = 0x3A; // ':' + --remain; + + if(bi < _self.Bhend - 1) + { + ++bi; + i = (int)_self.Bh[bi].Dlen; + + if(i > remain) throw new Exception(Localization.Assertion_failed); + + Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i); + resultOff += i; + remain -= i; + + if(h != 0) + { + if(remain <= 0) throw new Exception(Localization.Assertion_failed); + + h = _self.Bh[bi].Halfh; + result[resultOff] = _b64[h % 64]; + + if(i < 3 || + result[resultOff] != result[resultOff - 1] || + result[resultOff] != result[resultOff - 2] || + result[resultOff] != result[resultOff - 3]) + { + ++resultOff; + --remain; + } + } + else + { + i = _self.Bh[bi].Halfdigest; + + if(i != 0) + { + if(remain <= 0) throw new Exception(Localization.Assertion_failed); + + result[resultOff] = (byte)i; + + if(i < 3 || + result[resultOff] != result[resultOff - 1] || + result[resultOff] != result[resultOff - 2] || + result[resultOff] != result[resultOff - 3]) + { + ++resultOff; + --remain; + } + } + } + } + else if(h != 0) + { + if(_self.Bh[bi].Dlen != 0) throw new Exception(Localization.Assertion_failed); + + if(remain <= 0) throw new Exception(Localization.Assertion_failed); + + result[resultOff++] = _b64[_self.Bh[bi].H % 64]; + /* No need to bother with FUZZY_FLAG_ELIMSEQ, because this + * digest has length 1. */ + --remain; + } + + result[resultOff] = 0; + } + + /// Gets the hash of a file + /// File path. + public static byte[] File(string filename) => + throw new NotImplementedException(Localization.SpamSum_does_not_have_a_binary_representation); + + /// Gets the hash of a file in hexadecimal and as a byte array. + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) => + throw new NotImplementedException(Localization.Not_yet_implemented); + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// Length of the data buffer to hash. + /// null + /// Base64 representation of SpamSum $blocksize:$hash:$hash + public static string Data(byte[] data, uint len, out byte[] hash) + { + var fuzzyContext = new SpamSumContext(); + + fuzzyContext.Update(data, len); + + hash = null; + + return fuzzyContext.End(); + } + + /// Gets the hash of the specified data buffer. + /// Data buffer. + /// null + /// Base64 representation of SpamSum $blocksize:$hash:$hash + public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); + + // Converts an ASCII null-terminated string to .NET string + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static string CToString(byte[] cString) + { + var count = 0; + + // ReSharper disable once LoopCanBeConvertedToQuery + // LINQ is six times slower + foreach(byte c in cString) + { + if(c == 0) break; + + count++; + } + + return Encoding.ASCII.GetString(cString, 0, count); + } + +#region Nested type: BlockhashContext + + /* A blockhash contains a signature state for a specific (implicit) blocksize. + * The blocksize is given by SSDEEP_BS(index). The h and halfh members are the + * FNV hashes, where halfh stops to be reset after digest is SPAMSUM_LENGTH/2 + * long. The halfh hash is needed be able to truncate digest for the second + * output hash to stay compatible with ssdeep output. */ + struct BlockhashContext + { + public uint H; + public uint Halfh; + public byte[] Digest; + + // SPAMSUM_LENGTH + public byte Halfdigest; + public uint Dlen; + } + +#endregion + +#region Nested type: FuzzyState + + struct FuzzyState + { + public uint Bhstart; + public uint Bhend; + public BlockhashContext[] Bh; + + //NUM_BLOCKHASHES + public ulong TotalSize; + public RollState Roll; + } + +#endregion + +#region Nested type: RollState + + struct RollState + { + public byte[] Window; + + // ROLLING_WINDOW + public uint H1; + public uint H2; + public uint H3; + public uint N; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.CommonTypes b/Aaru.CommonTypes deleted file mode 160000 index 2aa15f080..000000000 --- a/Aaru.CommonTypes +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2aa15f080b7fe2e0b2a00e5575b336202ddfe5fd diff --git a/Aaru.CommonTypes/.gitignore b/Aaru.CommonTypes/.gitignore new file mode 100644 index 000000000..05c540d38 --- /dev/null +++ b/Aaru.CommonTypes/.gitignore @@ -0,0 +1,595 @@ +### VisualStudio template +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ +### Linux template + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +### C++ template +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o + +# Precompiled Headers +*.gch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### MonoDevelop template +#User Specific +*.usertasks + +#Mono Project Files +*.resources +test-results/ +### GPG template +secring.* + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests +### CMake template +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +### C template +# Object files +*.ko +*.elf + +# Linker output +*.map +*.exp + +*.so.* + +# Executables +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# NuGet Packages Directory +packages/ +## TODO: If the tool you use requires repositories.config uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +# This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) +!packages/build/ + + +# Others +sql/ +*.Cache + +# Visual Studio 2017 +.vs + +workspace.xml +cmake-build-debug +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +pkg/**/pkg +pkg/**/src +pkg/**/*.asc +pkg/**/*.sig +pkg/**/*.tar.xz +pkg/**/*.zip +pkg/**/aaru + +.sonarqube \ No newline at end of file diff --git a/Aaru.CommonTypes/Aaru.CommonTypes.csproj b/Aaru.CommonTypes/Aaru.CommonTypes.csproj new file mode 100644 index 000000000..b3a682596 --- /dev/null +++ b/Aaru.CommonTypes/Aaru.CommonTypes.csproj @@ -0,0 +1,108 @@ + + + + 2.0 + {F2B84194-26EB-4227-B1C5-6602517E85AE} + Library + Aaru.CommonTypes + Aaru.CommonTypes + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.CommonTypes + $(Version) + net8.0 + 12 + Contains common types defined by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + MIT + https://github.com/aaru-dps/Aaru.CommonTypes + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + LICENSE.MIT + + + + + + + + + + ResXFileCodeGenerator + Localization.Designer.cs + + + diff --git a/Aaru.CommonTypes/Aaru.CommonTypes.csproj.DotSettings b/Aaru.CommonTypes/Aaru.CommonTypes.csproj.DotSettings new file mode 100644 index 000000000..c2586551b --- /dev/null +++ b/Aaru.CommonTypes/Aaru.CommonTypes.csproj.DotSettings @@ -0,0 +1,7 @@ + + True + True \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/ATA.cs b/Aaru.CommonTypes/AaruMetadata/ATA.cs new file mode 100644 index 000000000..bb8309592 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/ATA.cs @@ -0,0 +1,58 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ATA.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System; +using Schemas; + +namespace Aaru.CommonTypes.AaruMetadata; + +public class ATA +{ + public Dump Identify { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator ATA(ATAType cicm) => cicm is null + ? null + : new ATA + { + Identify = cicm.Identify + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/AaruMetadata.cs b/Aaru.CommonTypes/AaruMetadata/AaruMetadata.cs new file mode 100644 index 000000000..01fb8cb2c --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/AaruMetadata.cs @@ -0,0 +1,207 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : AaruMetadata.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] +[JsonSerializable(typeof(MetadataJson))] + +// ReSharper disable once PartialTypeWithSinglePart +public partial class MetadataJsonContext : JsonSerializerContext; + +public class MetadataJson +{ + public Metadata AaruMetadata { get; set; } +} + +public class Metadata +{ + public List Developers { get; set; } + public List Publishers { get; set; } + public List Authors { get; set; } + public List Performers { get; set; } + public string Name { get; set; } + public string Version { get; set; } + public ReleaseType? Release { get; set; } + public DateTime? ReleaseDate { get; set; } + public List Barcodes { get; set; } + public string PartNumber { get; set; } + public string SerialNumber { get; set; } + public List Keywords { get; set; } + public List Magazines { get; set; } + public List Books { get; set; } + public List Categories { get; set; } + public List Subcategories { get; set; } + public List Languages { get; set; } + public List Systems { get; set; } + public List Architectures { get; set; } + public List RequiredOperatingSystems { get; set; } + public List UserManuals { get; set; } + public List OpticalDiscs { get; set; } + public List Advertisements { get; set; } + public List LinearMedias { get; set; } + public List PciCards { get; set; } + public List BlockMedias { get; set; } + public List AudioMedias { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Metadata(CICMMetadataType cicm) + { + if(cicm is null) return null; + + var metadata = new Metadata + { + Developers = cicm.Developer is null ? null : [..cicm.Developer], + Publishers = cicm.Publisher is null ? null : [..cicm.Publisher], + Authors = cicm.Author is null ? null : [..cicm.Author], + Performers = cicm.Performer is null ? null : [..cicm.Performer], + Name = cicm.Name, + Version = cicm.Version, + Release = cicm.ReleaseTypeSpecified ? (ReleaseType)cicm.ReleaseType : null, + ReleaseDate = cicm.ReleaseDateSpecified ? cicm.ReleaseDate : null, + PartNumber = cicm.PartNumber, + SerialNumber = cicm.SerialNumber, + Keywords = cicm.Keywords is null ? null : [..cicm.Keywords], + Categories = cicm.Categories is null ? null : [..cicm.Categories], + Subcategories = cicm.Subcategories is null ? null : [..cicm.Subcategories], + Systems = cicm.Systems is null ? null : [..cicm.Systems] + }; + + if(cicm.Barcodes is not null) + { + metadata.Barcodes = []; + + foreach(Schemas.BarcodeType code in cicm.Barcodes) metadata.Barcodes.Add(code); + } + + if(cicm.Magazine is not null) + { + metadata.Magazines = []; + + foreach(MagazineType magazine in cicm.Magazine) metadata.Magazines.Add(magazine); + } + + if(cicm.Book is not null) + { + metadata.Books = []; + + foreach(BookType book in cicm.Book) metadata.Books.Add(book); + } + + if(cicm.Languages is not null) + { + metadata.Languages = []; + + foreach(LanguagesTypeLanguage lng in cicm.Languages) metadata.Languages.Add((Language)lng); + } + + if(cicm.Architectures is not null) + { + metadata.Architectures = []; + + foreach(ArchitecturesTypeArchitecture arch in cicm.Architectures) + metadata.Architectures.Add((Architecture)arch); + } + + if(cicm.RequiredOperatingSystems is not null) + { + metadata.RequiredOperatingSystems = []; + + foreach(RequiredOperatingSystemType os in cicm.RequiredOperatingSystems) + metadata.RequiredOperatingSystems.Add(os); + } + + if(cicm.UserManual is not null) + { + metadata.UserManuals = []; + + foreach(UserManualType manual in cicm.UserManual) metadata.UserManuals.Add(manual); + } + + if(cicm.OpticalDisc is not null) + { + metadata.OpticalDiscs = []; + + foreach(OpticalDiscType disc in cicm.OpticalDisc) metadata.OpticalDiscs.Add(disc); + } + + if(cicm.Advertisement is not null) + { + metadata.Advertisements = []; + + foreach(AdvertisementType adv in cicm.Advertisement) metadata.Advertisements.Add(adv); + } + + if(cicm.LinearMedia is not null) + { + metadata.LinearMedias = []; + + foreach(LinearMediaType media in cicm.LinearMedia) metadata.LinearMedias.Add(media); + } + + if(cicm.PCICard is not null) + { + metadata.PciCards = []; + + foreach(PCIType pci in cicm.PCICard) metadata.PciCards.Add(pci); + } + + if(cicm.BlockMedia is not null) + { + metadata.BlockMedias = []; + + foreach(BlockMediaType media in cicm.BlockMedia) metadata.BlockMedias.Add(media); + } + + if(cicm.AudioMedia is null) return metadata; + + metadata.AudioMedias = []; + + foreach(AudioMediaType media in cicm.AudioMedia) metadata.AudioMedias.Add(media); + + return metadata; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Advertisement.cs b/Aaru.CommonTypes/AaruMetadata/Advertisement.cs new file mode 100644 index 000000000..1bc5a41f1 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Advertisement.cs @@ -0,0 +1,111 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Advertisement.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Advertisement +{ + public string Manufacturer { get; set; } + public string Product { get; set; } + public File File { get; set; } + public ulong FileSize { get; set; } + public ulong? Frames { get; set; } + public double Duration { get; set; } + public float? MeanFrameRate { get; set; } + public List Checksums { get; set; } + public List AudioTracks { get; set; } + public List VideoTracks { get; set; } + public List SubtitleTracks { get; set; } + public Recording Recording { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Advertisement(AdvertisementType cicm) + { + if(cicm is null) return null; + + var adv = new Advertisement + { + Manufacturer = cicm.Manufacturer, + Product = cicm.Product, + File = cicm.File, + FileSize = cicm.FileSize, + Frames = cicm.FramesSpecified ? cicm.Frames : null, + Duration = cicm.Duration, + MeanFrameRate = cicm.MeanFrameRateSpecified ? cicm.MeanFrameRate : null, + Recording = cicm.Recording + }; + + if(cicm.Checksums is not null) + { + adv.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) adv.Checksums.Add(chk); + } + + if(cicm.AudioTrack is not null) + { + adv.AudioTracks = []; + + foreach(AudioTracksType trk in cicm.AudioTrack) adv.AudioTracks.Add(trk); + } + + if(cicm.VideoTrack is not null) + { + adv.VideoTracks = []; + + foreach(VideoTracksType trk in cicm.VideoTrack) adv.VideoTracks.Add(trk); + } + + if(cicm.SubtitleTrack is null) return adv; + + { + adv.SubtitleTracks = []; + + foreach(SubtitleTracksType trk in cicm.SubtitleTrack) adv.SubtitleTracks.Add(trk); + } + + return adv; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Architecture.cs b/Aaru.CommonTypes/AaruMetadata/Architecture.cs new file mode 100644 index 000000000..56aa22987 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Architecture.cs @@ -0,0 +1,129 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Architecture.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Text.Json.Serialization; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +public enum Architecture +{ + [JsonPropertyName("4004")] + _4004, + [JsonPropertyName("4040")] + _4040, + [JsonPropertyName("6502")] + _6502, + [JsonPropertyName("65816")] + _65816, + [JsonPropertyName("8008")] + _8008, + [JsonPropertyName("8051")] + _8051, + [JsonPropertyName("8080")] + _8080, + [JsonPropertyName("8085")] + _8085, + Aarch64, + Am29000, + Amd64, + Apx432, + Arm, + Avr, + Avr32, + Axp, + Clipper, + Cray, + Esa390, + Hobbit, + I86, + I860, + I960, + Ia32, + Ia64, + M56K, + M6800, + M6801, + M6805, + M6809, + M68K, + M88K, + Mcs41, + Mcs48, + Mips32, + Mips64, + Msp430, + Nios2, + Openrisc, + Parisc, + PDP1, + PDP10, + PDP11, + PDP7, + PDP8, + Pic, + Power, + Ppc, + Ppc64, + Prism, + Renesasrx, + Riscv, + S360, + S370, + Sh, + Sh1, + Sh2, + Sh3, + Sh4, + Sh5, + Sh64, + Sparc, + Sparc64, + Transputer, + Vax, + We32000, + X32, + Z80, + Z800, + Z8000, + Z80000, + Zarch +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/AudioMedia.cs b/Aaru.CommonTypes/AaruMetadata/AudioMedia.cs new file mode 100644 index 000000000..aaa8cc711 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/AudioMedia.cs @@ -0,0 +1,138 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : AudioMedia.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class AudioMedia +{ + public Image Image { get; set; } + public ulong Size { get; set; } + public List Checksums { get; set; } + public Sequence Sequence { get; set; } + public string PartNumber { get; set; } + public string SerialNumber { get; set; } + public string Manufacturer { get; set; } + public string Model { get; set; } + public string AccoustID { get; set; } + public List Blocks { get; set; } + public string CopyProtection { get; set; } + public Dimensions Dimensions { get; set; } + public Scans Scans { get; set; } + public List DumpHardware { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator AudioMedia(AudioMediaType cicm) + { + if(cicm is null) return null; + + var media = new AudioMedia + { + Image = cicm.Image, + Size = cicm.Size, + Sequence = cicm.Sequence, + PartNumber = cicm.PartNumber, + SerialNumber = cicm.SerialNumber, + Manufacturer = cicm.Manufacturer, + Model = cicm.Model, + AccoustID = cicm.AccoustID, + CopyProtection = cicm.CopyProtection, + Dimensions = cicm.Dimensions, + Scans = cicm.Scans + }; + + if(cicm.Checksums is not null) + { + media.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) media.Checksums.Add(chk); + } + + if(cicm.Block is not null) + { + media.Blocks = []; + + foreach(AudioBlockType blk in cicm.Block) media.Blocks.Add(blk); + } + + if(cicm.DumpHardwareArray is null) return media; + + media.DumpHardware = []; + + foreach(DumpHardwareType hw in cicm.DumpHardwareArray) media.DumpHardware.Add(hw); + + return media; + } +} + +public class AudioBlock +{ + public Image Image { get; set; } + public ulong Size { get; set; } + public string AccoustID { get; set; } + public List Checksums { get; set; } + public string Format { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator AudioBlock(AudioBlockType cicm) + { + if(cicm is null) return null; + + var blk = new AudioBlock + { + Image = cicm.Image, + Size = cicm.Size, + AccoustID = cicm.AccoustID, + Format = cicm.Format + }; + + if(cicm.Checksums is null) return blk; + + blk.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) blk.Checksums.Add(chk); + + return blk; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/AudioVideo.cs b/Aaru.CommonTypes/AaruMetadata/AudioVideo.cs new file mode 100644 index 000000000..fb1576b6f --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/AudioVideo.cs @@ -0,0 +1,321 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : AudioVideo.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class AudioTrack +{ + public List Languages { get; set; } + public uint Number { get; set; } + public string AccoustID { get; set; } + public string Codec { get; set; } + public uint Channels { get; set; } + public double SampleRate { get; set; } + public long MeanBitrate { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator AudioTrack(AudioTracksType cicm) + { + if(cicm is null) return null; + + var trk = new AudioTrack + { + Number = cicm.TrackNumber, + AccoustID = cicm.AccoustID, + Codec = cicm.Codec, + Channels = cicm.Channels, + SampleRate = cicm.SampleRate, + MeanBitrate = cicm.MeanBitrate + }; + + if(cicm.Languages is null) return trk; + + trk.Languages = []; + + foreach(LanguagesTypeLanguage lng in cicm.Languages) trk.Languages.Add((Language)lng); + + return trk; + } +} + +public class VideoTrack +{ + public List Languages { get; set; } + public uint Number { get; set; } + public string Codec { get; set; } + public uint Horizontal { get; set; } + public uint Vertical { get; set; } + public long MeanBitrate { get; set; } + + [JsonPropertyName("3D")] + public bool ThreeD { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator VideoTrack(VideoTracksType cicm) + { + if(cicm is null) return null; + + var trk = new VideoTrack + { + Number = cicm.TrackNumber, + Codec = cicm.Codec, + Horizontal = cicm.Horizontal, + Vertical = cicm.Vertical, + MeanBitrate = cicm.MeanBitrate, + ThreeD = cicm.ThreeD + }; + + if(cicm.Languages is null) return trk; + + trk.Languages = []; + + foreach(LanguagesTypeLanguage lng in cicm.Languages) trk.Languages.Add((Language)lng); + + return trk; + } +} + +public class SubtitleTrack +{ + public List Languages { get; set; } + public uint Number { get; set; } + public string Codec { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator SubtitleTrack(SubtitleTracksType cicm) + { + if(cicm is null) return null; + + var sub = new SubtitleTrack + { + Number = cicm.TrackNumber, + Codec = cicm.Codec + }; + + if(cicm.Languages is null) return sub; + + sub.Languages = []; + + foreach(LanguagesTypeLanguage lng in cicm.Languages) sub.Languages.Add((Language)lng); + + return sub; + } +} + +public class Recording +{ + public string Broadcaster { get; set; } + public string BroadcastPlatform { get; set; } + public SourceFormat SourceFormat { get; set; } + public DateTime Timestamp { get; set; } + public List Software { get; set; } + public Coordinates Coordinates { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Recording(RecordingType cicm) + { + if(cicm is null) return null; + + var recording = new Recording + { + Broadcaster = cicm.Broadcaster, + BroadcastPlatform = cicm.BroadcastPlatform, + SourceFormat = (SourceFormat)cicm.SourceFormat, + Timestamp = cicm.Timestamp, + Coordinates = cicm.Coordinates + }; + + if(cicm.Software is null) return recording; + + recording.Software = []; + + foreach(SoftwareType sw in cicm.Software) recording.Software.Add(sw); + + return recording; + } +} + +public class Coordinates +{ + public double Latitude { get; set; } + public double Longitude { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Coordinates(CoordinatesType cicm) => cicm is null + ? null + : new Coordinates + { + Latitude = cicm.Latitude, + Longitude = cicm.Longitude + }; +} + +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum SourceFormat +{ + [JsonPropertyName("ITU-A")] + ITUA, + [JsonPropertyName("ITU-B")] + ITUB, + [JsonPropertyName("ITU-C")] + ITUC, + [JsonPropertyName("ITU-D")] + ITUD, + [JsonPropertyName("ITU-E")] + ITUE, + [JsonPropertyName("ITU-F")] + ITUF, + [JsonPropertyName("ITU-G")] + ITUG, + [JsonPropertyName("ITU-H")] + ITUH, + [JsonPropertyName("ITU-I")] + ITUI, + [JsonPropertyName("ITU-J")] + ITUJ, + [JsonPropertyName("ITU-K")] + ITUK, + [JsonPropertyName("ITU-L")] + ITUL, + [JsonPropertyName("ITU-M")] + ITUM, + [JsonPropertyName("ITU-N")] + ITUN, + [JsonPropertyName("PAL-B")] + PALB, + [JsonPropertyName("SECAM-B")] + SECAMB, + [JsonPropertyName("PAL-D")] + PALD, + [JsonPropertyName("SECAM-D")] + SECAMD, + [JsonPropertyName("PAL-G")] + PALG, + [JsonPropertyName("SECAM-G")] + SECAMG, + [JsonPropertyName("PAL-H")] + PALH, + [JsonPropertyName("PAL-I")] + PALI, + [JsonPropertyName("PAL-K")] + PALK, + [JsonPropertyName("SECAM-K")] + SECAMK, + [JsonPropertyName("NTSC-M")] + NTSCM, + [JsonPropertyName("PAL-N")] + PALN, + [JsonPropertyName("PAL-M")] + PALM, + [JsonPropertyName("SECAM-M")] + SECAMM, + MUSE, + PALplus, + FM, + AM, + COFDM, + [JsonPropertyName("CAM-D")] + CAMD, + DAB, + [JsonPropertyName("DAB+")] + DAB1, + DRM, + [JsonPropertyName("DRM+")] + DRM1, + FMeXtra, + ATSC, + ATSC2, + ATSC3, + [JsonPropertyName("ATSC-M/H")] + ATSCMH, + [JsonPropertyName("DVB-T")] + DVBT, + [JsonPropertyName("DVB-T2")] + DVBT2, + [JsonPropertyName("DVB-S")] + DVBS, + [JsonPropertyName("DVB-S2")] + DVBS2, + [JsonPropertyName("DVB-S2X")] + DVBS2X, + [JsonPropertyName("DVB-C")] + DVBC, + [JsonPropertyName("DVB-C2")] + DVBC2, + [JsonPropertyName("DVB-H")] + DVBH, + [JsonPropertyName("DVB-NGH")] + DVBNGH, + [JsonPropertyName("DVB-SH")] + DVBSH, + [JsonPropertyName("ISDB-T")] + ISDBT, + [JsonPropertyName("ISDB-Tb")] + ISDBTb, + [JsonPropertyName("ISDB-S")] + ISDBS, + [JsonPropertyName("ISDB-C")] + ISDBC, + [JsonPropertyName("1seg")] + Item1seg, + DTMB, + CCMB, + [JsonPropertyName("T-DMB")] + TDMB, + [JsonPropertyName("S-DMB")] + SDMB, + IPTV, + [JsonPropertyName("DVB-MT")] + DVBMT, + [JsonPropertyName("DVB-MC")] + DVBMC, + [JsonPropertyName("DVB-MS")] + DVBMS, + ADR, + SDR +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Barcode.cs b/Aaru.CommonTypes/AaruMetadata/Barcode.cs new file mode 100644 index 000000000..29a473632 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Barcode.cs @@ -0,0 +1,95 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Barcode.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; + +namespace Aaru.CommonTypes.AaruMetadata; + +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum BarcodeType +{ + Aztec, + Codabar, + Code11, + Code128, + Code39, + Code93, + CPC_Binary, + EZcode, + FIM, + ITF, + ITF14, + EAN13, + EAN8, + MaxiCode, + ISBN, + ISRC, + MSI, + ShotCode, + RM4SCC, + QR, + EAN5, + EAN2, + POSTNET, + PostBar, + Plessey, + Pharmacode, + PDF417, + PatchCode +} + +public class Barcode +{ + public BarcodeType Type { get; set; } + public string Value { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Barcode(Schemas.BarcodeType cicm) => cicm is null + ? null + : new Barcode + { + Type = (BarcodeType)cicm.type, + Value = cicm.Value + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/BlockMedia.cs b/Aaru.CommonTypes/AaruMetadata/BlockMedia.cs new file mode 100644 index 000000000..e6ec10a76 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/BlockMedia.cs @@ -0,0 +1,210 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : BlockMedia.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class BlockMedia +{ + public Image Image { get; set; } + public ulong Size { get; set; } + public List Checksums { get; set; } + public List ContentChecksums { get; set; } + public Sequence Sequence { get; set; } + public string Manufacturer { get; set; } + public string Model { get; set; } + public string Serial { get; set; } + public string Firmware { get; set; } + public string PartNumber { get; set; } + public string SerialNumber { get; set; } + public uint PhysicalBlockSize { get; set; } + public uint LogicalBlockSize { get; set; } + public ulong LogicalBlocks { get; set; } + public List VariableBlockSize { get; set; } + public List TapeInformation { get; set; } + public Scans Scans { get; set; } + public ATA ATA { get; set; } + public Pci Pci { get; set; } + public Pcmcia Pcmcia { get; set; } + public SecureDigital SecureDigital { get; set; } + public MultiMediaCard MultiMediaCard { get; set; } + public SCSI SCSI { get; set; } + public Usb Usb { get; set; } + public Dump Mam { get; set; } + public ushort? Heads { get; set; } + public uint? Cylinders { get; set; } + public ulong? SectorsPerTrack { get; set; } + public List Track { get; set; } + public string CopyProtection { get; set; } + public Dimensions Dimensions { get; set; } + public List FileSystemInformation { get; set; } + public List DumpHardware { get; set; } + public string MediaType { get; set; } + public string MediaSubType { get; set; } + public string Interface { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator BlockMedia(BlockMediaType cicm) + { + if(cicm is null) return null; + + var media = new BlockMedia + { + Image = cicm.Image, + Size = cicm.Size, + Sequence = cicm.Sequence, + Manufacturer = cicm.Manufacturer, + Model = cicm.Model, + Serial = cicm.Serial, + Firmware = cicm.Firmware, + PartNumber = cicm.PartNumber, + SerialNumber = cicm.SerialNumber, + PhysicalBlockSize = cicm.PhysicalBlockSize, + LogicalBlockSize = cicm.LogicalBlockSize, + LogicalBlocks = cicm.LogicalBlocks, + Scans = cicm.Scans, + ATA = cicm.ATA, + Pci = cicm.PCI, + Pcmcia = cicm.PCMCIA, + SecureDigital = cicm.SecureDigital, + MultiMediaCard = cicm.MultiMediaCard, + SCSI = cicm.SCSI, + Usb = cicm.USB, + Mam = cicm.MAM, + Heads = cicm.HeadsSpecified ? cicm.Heads : null, + Cylinders = cicm.CylindersSpecified ? cicm.Cylinders : null, + SectorsPerTrack = cicm.SectorsPerTrackSpecified ? cicm.SectorsPerTrack : null, + CopyProtection = cicm.CopyProtection, + Dimensions = cicm.Dimensions, + MediaType = cicm.DiskType, + MediaSubType = cicm.DiskSubType, + Interface = cicm.Interface + }; + + if(cicm.Checksums is not null) + { + media.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) media.Checksums.Add(chk); + } + + if(cicm.ContentChecksums is not null) + { + media.ContentChecksums = []; + + foreach(Schemas.ChecksumType chk in cicm.ContentChecksums) media.ContentChecksums.Add(chk); + } + + if(cicm.VariableBlockSize is not null) + { + media.VariableBlockSize = []; + + foreach(BlockSizeType blkSize in cicm.VariableBlockSize) media.VariableBlockSize.Add(blkSize); + } + + if(cicm.TapeInformation is not null) + { + media.TapeInformation = []; + + foreach(TapePartitionType tapeInformation in cicm.TapeInformation) + media.TapeInformation.Add(tapeInformation); + } + + if(cicm.FileSystemInformation is not null) + { + media.FileSystemInformation = []; + + foreach(PartitionType fsInfo in cicm.FileSystemInformation) media.FileSystemInformation.Add(fsInfo); + } + + if(cicm.DumpHardwareArray is null) return media; + + media.DumpHardware = []; + + foreach(DumpHardwareType hw in cicm.DumpHardwareArray) media.DumpHardware.Add(hw); + + return media; + } +} + +public class BlockTrack +{ + public Image Image { get; set; } + public ulong Size { get; set; } + public ushort Head { get; set; } + public uint Cylinder { get; set; } + public ulong StartSector { get; set; } + public ulong EndSector { get; set; } + public ulong Sectors { get; set; } + public uint BytesPerSector { get; set; } + public List Checksums { get; set; } + public string Format { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator BlockTrack(BlockTrackType cicm) + { + if(cicm is null) return null; + + var trk = new BlockTrack + { + Image = cicm.Image, + Size = cicm.Size, + Head = cicm.Head, + Cylinder = cicm.Cylinder, + StartSector = cicm.StartSector, + EndSector = cicm.EndSector, + Sectors = cicm.Sectors, + BytesPerSector = cicm.BytesPerSector, + Format = cicm.Format + }; + + if(cicm.Checksums is null) return trk; + + trk.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) trk.Checksums.Add(chk); + + return trk; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Book.cs b/Aaru.CommonTypes/AaruMetadata/Book.cs new file mode 100644 index 000000000..61bdd452a --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Book.cs @@ -0,0 +1,93 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Book.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Book +{ + public List Barcodes { get; set; } + public Cover Cover { get; set; } + public string Name { get; set; } + public string Editorial { get; set; } + public string Author { get; set; } + public DateTime? PublicationDate { get; set; } + public List Languages { get; set; } + public uint? Pages { get; set; } + public string PageSize { get; set; } + public Scan Scan { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Book(BookType cicm) + { + if(cicm is null) return null; + + var book = new Book + { + Cover = cicm.Cover, + Name = cicm.Name, + Editorial = cicm.Editorial, + Author = cicm.Author, + PublicationDate = cicm.PublicationDateSpecified ? cicm.PublicationDate : null, + Pages = cicm.PagesSpecified ? cicm.Pages : null, + PageSize = cicm.PageSize, + Scan = cicm.Scan + }; + + if(cicm.Barcodes is not null) + { + book.Barcodes = []; + + foreach(Schemas.BarcodeType code in cicm.Barcodes) book.Barcodes.Add(code); + } + + if(cicm.Language is null) return book; + + book.Languages = []; + + foreach(LanguagesTypeLanguage lng in cicm.Language) book.Languages.Add((Language)lng); + + return book; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Checksum.cs b/Aaru.CommonTypes/AaruMetadata/Checksum.cs new file mode 100644 index 000000000..b2b48eda5 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Checksum.cs @@ -0,0 +1,91 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Checksum.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System; +using System.Text.Json.Serialization; + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Checksum +{ + public ChecksumType Type { get; set; } + public string Value { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Checksum(Schemas.ChecksumType cicm) => cicm is null + ? null + : new Checksum + { + Value = cicm.Value, + Type = (ChecksumType)cicm.type + }; +} + +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +public enum ChecksumType +{ + Fletcher16, + Fletcher32, + Adler32, + CRC16, + CRC16Ccitt, + CRC32, + CRC64, + Md4, + Md5, + Dm6, + Ripemd128, + Ripemd160, + Ripemed320, + Sha1, + Sha224, + Sha256, + Sha384, + Sha512, + Sha3, + Skein, + Snefru, + Blake256, + Blake512, + Tiger, + Whirlpool, + SpamSum +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Contents.cs b/Aaru.CommonTypes/AaruMetadata/Contents.cs new file mode 100644 index 000000000..ec36f530d --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Contents.cs @@ -0,0 +1,222 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Contents.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class FilesystemContents +{ + public List Files { get; set; } + public List Directories { get; set; } + public string Namespace { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator FilesystemContents(FilesystemContentsType cicm) + { + if(cicm is null) return null; + + var fs = new FilesystemContents + { + Namespace = cicm.@namespace + }; + + if(cicm.File is not null) + { + fs.Files = []; + + foreach(ContentsFileType file in cicm.File) fs.Files.Add(file); + } + + if(cicm.Directory is null) return fs; + + fs.Directories = []; + + foreach(DirectoryType dir in cicm.Directory) fs.Directories.Add(dir); + + return fs; + } +} + +public class ContentsFile +{ + public List Checksums { get; set; } + public List ExtendedAttributes { get; set; } + public string Name { get; set; } + public DateTime? CreationTime { get; set; } + public DateTime? AccessTime { get; set; } + public DateTime? StatusChangeTime { get; set; } + public DateTime? BackupTime { get; set; } + public DateTime? LastWriteTime { get; set; } + public ulong Attributes { get; set; } + public uint? PosixMode { get; set; } + public ulong? DeviceNumber { get; set; } + public ulong? PosixGroupId { get; set; } + public ulong Inode { get; set; } + public ulong Links { get; set; } + public ulong? PosixUserId { get; set; } + public ulong Length { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator ContentsFile(ContentsFileType cicm) + { + if(cicm is null) return null; + + var file = new ContentsFile + { + Name = cicm.name, + CreationTime = cicm.creationTimeSpecified ? cicm.creationTime : null, + AccessTime = cicm.accessTimeSpecified ? cicm.accessTime : null, + StatusChangeTime = cicm.statusChangeTimeSpecified ? cicm.statusChangeTime : null, + BackupTime = cicm.backupTimeSpecified ? cicm.backupTime : null, + LastWriteTime = cicm.lastWriteTimeSpecified ? cicm.lastWriteTime : null, + Attributes = cicm.attributes, + PosixMode = cicm.posixModeSpecified ? cicm.posixMode : null, + DeviceNumber = cicm.deviceNumberSpecified ? cicm.deviceNumber : null, + PosixGroupId = cicm.posixGroupIdSpecified ? cicm.posixGroupId : null, + Inode = cicm.inode, + Links = cicm.links, + PosixUserId = cicm.posixUserIdSpecified ? cicm.posixUserId : null, + Length = cicm.length + }; + + if(cicm.Checksums is not null) + { + file.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) file.Checksums.Add(chk); + } + + if(cicm.ExtendedAttributes is null) return file; + + file.ExtendedAttributes = []; + + foreach(ExtendedAttributeType xa in cicm.ExtendedAttributes) file.ExtendedAttributes.Add(xa); + + return file; + } +} + +public class ExtendedAttribute +{ + public List Checksums { get; set; } + public string Name { get; set; } + public ulong Length { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator ExtendedAttribute(ExtendedAttributeType cicm) + { + if(cicm is null) return null; + + var xa = new ExtendedAttribute + { + Name = cicm.name, + Length = cicm.length + }; + + if(cicm.Checksums is null) return xa; + + xa.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) xa.Checksums.Add(chk); + + return xa; + } +} + +public class Directory +{ + public List Files { get; set; } + public List Directories { get; set; } + public string Name { get; set; } + public DateTime? CreationTime { get; set; } + public DateTime? AccessTime { get; set; } + public DateTime? StatusChangeTime { get; set; } + public DateTime? BackupTime { get; set; } + public DateTime? LastWriteTime { get; set; } + public ulong Attributes { get; set; } + public uint? PosixMode { get; set; } + public ulong? DeviceNumber { get; set; } + public ulong? PosixGroupId { get; set; } + public ulong? Inode { get; set; } + public ulong? Links { get; set; } + public ulong? PosixUserId { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Directory(DirectoryType cicm) + { + if(cicm is null) return null; + + var dir = new Directory + { + Name = cicm.name, + CreationTime = cicm.creationTimeSpecified ? cicm.creationTime : null, + AccessTime = cicm.accessTimeSpecified ? cicm.accessTime : null, + StatusChangeTime = cicm.statusChangeTimeSpecified ? cicm.statusChangeTime : null, + BackupTime = cicm.backupTimeSpecified ? cicm.backupTime : null, + LastWriteTime = cicm.lastWriteTimeSpecified ? cicm.lastWriteTime : null, + Attributes = cicm.attributes, + PosixMode = cicm.posixModeSpecified ? cicm.posixMode : null, + DeviceNumber = cicm.deviceNumberSpecified ? cicm.deviceNumber : null, + PosixGroupId = cicm.posixGroupIdSpecified ? cicm.posixGroupId : null, + Inode = cicm.inodeSpecified ? cicm.inode : null, + Links = cicm.linksSpecified ? cicm.links : null, + PosixUserId = cicm.posixUserIdSpecified ? cicm.posixUserId : null + }; + + if(cicm.Directory is not null) + { + dir.Directories = []; + + foreach(DirectoryType d in cicm.Directory) dir.Directories.Add(d); + } + + if(cicm.File is null) return dir; + + dir.Files = []; + + foreach(ContentsFileType file in cicm.File) dir.Files.Add(file); + + return dir; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Dimensions.cs b/Aaru.CommonTypes/AaruMetadata/Dimensions.cs new file mode 100644 index 000000000..450b361bd --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Dimensions.cs @@ -0,0 +1,1160 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Dimensions.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System; +using Schemas; + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Dimensions +{ + public double? Diameter { get; set; } + public double? Height { get; set; } + public double? Width { get; set; } + public double Thickness { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Dimensions(DimensionsType cicm) => cicm is null + ? null + : new Dimensions + { + Diameter = + cicm.DiameterSpecified + ? cicm.Diameter + : null, + Height = cicm.HeightSpecified + ? cicm.Height + : null, + Width = cicm.WidthSpecified + ? cicm.Width + : null, + Thickness = cicm.Thickness + }; + + /// Gets the physical dimensions, in metadata expected format, for a given media type + /// Media type + /// Dimensions metadata + public static Dimensions FromMediaType(MediaType mediaType) + { + var dmns = new Dimensions(); + + switch(mediaType) + { +#region 5.25" floppy disk + + case MediaType.Apple32SS: + case MediaType.Apple32DS: + case MediaType.Apple33SS: + case MediaType.Apple33DS: + case MediaType.AppleFileWare: + case MediaType.DOS_525_SS_DD_8: + case MediaType.DOS_525_SS_DD_9: + case MediaType.DOS_525_DS_DD_8: + case MediaType.DOS_525_DS_DD_9: + case MediaType.DOS_525_HD: + case MediaType.XDF_525: + case MediaType.ACORN_525_SS_SD_40: + case MediaType.ACORN_525_SS_SD_80: + case MediaType.ACORN_525_SS_DD_40: + case MediaType.ACORN_525_SS_DD_80: + case MediaType.ACORN_525_DS_DD: + case MediaType.ATARI_525_SD: + case MediaType.ATARI_525_ED: + case MediaType.ATARI_525_DD: + case MediaType.CBM_1540: + case MediaType.CBM_1540_Ext: + case MediaType.CBM_1571: + case MediaType.ECMA_66: + case MediaType.ECMA_70: + case MediaType.NEC_525_HD: + case MediaType.ECMA_78: + case MediaType.ECMA_78_2: + case MediaType.ECMA_99_8: + case MediaType.ECMA_99_15: + case MediaType.ECMA_99_26: + case MediaType.FDFORMAT_525_DD: + case MediaType.FDFORMAT_525_HD: + case MediaType.MetaFloppy_Mod_I: + case MediaType.MetaFloppy_Mod_II: + // According to ECMA-99 et al + dmns.Height = 133.3; + + dmns.Width = 133.3; + + dmns.Thickness = 1.65; + + return dmns; + +#endregion 5.25" floppy disk + +#region 3.5" floppy disk + + case MediaType.AppleSonySS: + case MediaType.AppleSonyDS: + case MediaType.DOS_35_SS_DD_8: + case MediaType.DOS_35_SS_DD_9: + case MediaType.DOS_35_DS_DD_8: + case MediaType.DOS_35_DS_DD_9: + case MediaType.DOS_35_HD: + case MediaType.DOS_35_ED: + case MediaType.DMF: + case MediaType.DMF_82: + case MediaType.XDF_35: + case MediaType.ACORN_35_DS_DD: + case MediaType.CBM_35_DD: + case MediaType.CBM_AMIGA_35_DD: + case MediaType.CBM_AMIGA_35_HD: + case MediaType.FDFORMAT_35_DD: + case MediaType.FDFORMAT_35_HD: + case MediaType.NEC_35_HD_8: + case MediaType.NEC_35_HD_15: + case MediaType.Floptical: + case MediaType.HiFD: + case MediaType.UHD144: + case MediaType.Apricot_35: + case MediaType.FD32MB: + // According to ECMA-100 et al + dmns.Height = 94; + + dmns.Width = 90; + + dmns.Thickness = 3.3; + + return dmns; + +#endregion 3.5" floppy disk + +#region 8" floppy disk + + case MediaType.IBM23FD: + case MediaType.IBM33FD_128: + case MediaType.IBM33FD_256: + case MediaType.IBM33FD_512: + case MediaType.IBM43FD_128: + case MediaType.IBM43FD_256: + case MediaType.IBM53FD_256: + case MediaType.IBM53FD_512: + case MediaType.IBM53FD_1024: + case MediaType.RX01: + case MediaType.RX02: + case MediaType.NEC_8_SD: + case MediaType.NEC_8_DD: + case MediaType.ECMA_54: + case MediaType.ECMA_59: + case MediaType.ECMA_69_8: + case MediaType.ECMA_69_15: + case MediaType.ECMA_69_26: + // According to ECMA-59 et al + dmns.Height = 203.2; + + dmns.Width = 203.2; + + dmns.Thickness = 1.65; + + return dmns; + +#endregion 8" floppy disk + +#region 356mm magneto optical + + case MediaType.ECMA_260: + case MediaType.ECMA_260_Double: + // According to ECMA-260 et al + dmns.Height = 421.84; + + dmns.Width = 443.76; + + dmns.Thickness = 25.4; + + return dmns; + +#endregion 356mm magneto optical + +#region 300mm magneto optical + + case MediaType.ECMA_189: + case MediaType.ECMA_190: + case MediaType.ECMA_317: + // According to ECMA-317 et al + dmns.Height = 340; + + dmns.Width = 320; + + dmns.Thickness = 17; + + return dmns; + +#endregion 300mm magneto optical + +#region 5.25" magneto optical + + case MediaType.ECMA_153: + case MediaType.ECMA_153_512: + case MediaType.ECMA_183_512: + case MediaType.ECMA_183: + case MediaType.ECMA_184_512: + case MediaType.ECMA_184: + case MediaType.ECMA_195: + case MediaType.ECMA_195_512: + case MediaType.ECMA_238: + case MediaType.ECMA_280: + case MediaType.ECMA_322: + case MediaType.ECMA_322_2k: + case MediaType.UDO: + case MediaType.UDO2: + case MediaType.UDO2_WORM: + case MediaType.ISO_15286: + case MediaType.ISO_15286_1024: + case MediaType.ISO_15286_512: + case MediaType.ISO_10089: + case MediaType.ISO_10089_512: + case MediaType.ECMA_322_1k: + case MediaType.ECMA_322_512: + case MediaType.ISO_14517: + case MediaType.ISO_14517_512: + // According to ECMA-183 et al + dmns.Height = 153; + + dmns.Width = 135; + + dmns.Thickness = 11; + + return dmns; + +#endregion 5.25" magneto optical + +#region 3.5" magneto optical + + case MediaType.ECMA_154: + case MediaType.ECMA_201: + case MediaType.ECMA_201_ROM: + case MediaType.ECMA_223: + case MediaType.ECMA_223_512: + case MediaType.GigaMo: + case MediaType.GigaMo2: + case MediaType.ISO_15041_512: + // According to ECMA-154 et al + dmns.Height = 94; + + dmns.Width = 90; + + dmns.Thickness = 6; + + return dmns; + +#endregion 3.5" magneto optical + + case MediaType.PD650: + case MediaType.PD650_WORM: + dmns.Height = 135; + + dmns.Width = 124; + + dmns.Thickness = 7.8; + + return dmns; + case MediaType.ECMA_239: + dmns.Height = 97; + + dmns.Width = 92; + + dmns.Thickness = 5; + + return dmns; + case MediaType.MMCmicro: + dmns.Height = 14; + + dmns.Width = 12; + + dmns.Thickness = 1.1; + + return dmns; + case MediaType.MemoryStickMicro: + dmns.Height = 15; + + dmns.Width = 12.5; + + dmns.Thickness = 1.2; + + return dmns; + case MediaType.microSD: + dmns.Height = 11; + + dmns.Width = 15; + + dmns.Thickness = 1; + + return dmns; + case MediaType.miniSD: + dmns.Height = 21.5; + + dmns.Width = 20; + + dmns.Thickness = 1.4; + + return dmns; + case MediaType.QIC3010: + case MediaType.QIC3020: + case MediaType.QIC3080: + case MediaType.QIC3095: + case MediaType.QIC320: + case MediaType.QIC40: + case MediaType.QIC80: + dmns.Height = 20; + + dmns.Width = 21.5; + + dmns.Thickness = 1.6; + + return dmns; + case MediaType.RSMMC: + dmns.Height = 18; + + dmns.Width = 24; + + dmns.Thickness = 1.4; + + return dmns; + case MediaType.MMC: + dmns.Height = 32; + + dmns.Width = 24; + + dmns.Thickness = 1.4; + + return dmns; + case MediaType.SecureDigital: + dmns.Height = 32; + + dmns.Width = 24; + + dmns.Thickness = 2.1; + + return dmns; + case MediaType.xD: + dmns.Height = 20; + + dmns.Width = 25; + + dmns.Thickness = 1.78; + + return dmns; + case MediaType.XQD: + dmns.Height = 38.5; + + dmns.Width = 29.8; + + dmns.Thickness = 3.8; + + return dmns; + case MediaType.MemoryStickDuo: + case MediaType.MemoryStickProDuo: + dmns.Height = 20; + + dmns.Width = 31; + + dmns.Thickness = 1.6; + + return dmns; + case MediaType.Nintendo3DSGameCard: + case MediaType.NintendoDSGameCard: + case MediaType.NintendoDSiGameCard: + dmns.Height = 35; + + dmns.Width = 33; + + dmns.Thickness = 3.8; + + return dmns; + case MediaType.DataPlay: + dmns.Height = 42; + + dmns.Width = 33.5; + + dmns.Thickness = 3; + + return dmns; + case MediaType.Microdrive: + dmns.Height = 44; + + dmns.Width = 34; + + dmns.Thickness = 8; + + return dmns; + case MediaType.ExpressCard34: + dmns.Height = 75; + + dmns.Width = 34; + + dmns.Thickness = 5; + + return dmns; + case MediaType.SmartMedia: + dmns.Height = 45; + + dmns.Width = 37; + + dmns.Thickness = 0.76; + + return dmns; + case MediaType.MiniCard: + dmns.Height = 45; + + dmns.Width = 37; + + dmns.Thickness = 3.5; + + return dmns; + case MediaType.PlayStationMemoryCard: + case MediaType.PlayStationMemoryCard2: + dmns.Height = 55.7; + + dmns.Width = 41.5; + + dmns.Thickness = 7; + + return dmns; + case MediaType.CFast: + case MediaType.CompactFlash: + dmns.Height = 36; + + dmns.Width = 43; + + dmns.Thickness = 3.3; + + return dmns; + case MediaType.CompactFlashType2: + dmns.Height = 36; + + dmns.Width = 43; + + dmns.Thickness = 5; + + return dmns; + case MediaType.ZXMicrodrive: + dmns.Height = 36; + + dmns.Width = 43; + + dmns.Thickness = 5; + + return dmns; + case MediaType.MemoryStick: + case MediaType.MemoryStickPro: + dmns.Height = 21; + + dmns.Width = 50; + + dmns.Thickness = 2.6; + + return dmns; + case MediaType.PocketZip: + dmns.Height = 54.5; + + dmns.Width = 50; + + dmns.Thickness = 2; + + return dmns; + case MediaType.ExpressCard54: + dmns.Height = 75; + + dmns.Width = 54; + + dmns.Thickness = 5; + + return dmns; + case MediaType.PCCardTypeI: + dmns.Height = 85.6; + + dmns.Width = 54; + + dmns.Thickness = 3.3; + + return dmns; + case MediaType.PCCardTypeII: + dmns.Height = 85.6; + + dmns.Width = 54; + + dmns.Thickness = 5; + + return dmns; + case MediaType.PCCardTypeIII: + dmns.Height = 85.6; + + dmns.Width = 54; + + dmns.Thickness = 10.5; + + return dmns; + case MediaType.PCCardTypeIV: + dmns.Height = 85.6; + + dmns.Width = 54; + + dmns.Thickness = 16; + + return dmns; + case MediaType.DataStore: + dmns.Height = 86.5; + + dmns.Width = 54; + + dmns.Thickness = 2.5; + + return dmns; + case MediaType.VideoFloppy: + dmns.Height = 54; + + dmns.Width = 60; + + dmns.Thickness = 3.5; + + return dmns; + case MediaType.VXA1: + case MediaType.VXA2: + case MediaType.VXA3: + dmns.Height = 95; + + dmns.Width = 62.5; + + dmns.Thickness = 15; + + return dmns; + case MediaType.MiniDV: + dmns.Height = 47.5; + + dmns.Width = 66; + + dmns.Thickness = 12; + + return dmns; + case MediaType.Wafer: + dmns.Height = 46.8; + + dmns.Width = 67.1; + + dmns.Thickness = 7.9; + + return dmns; + case MediaType.NintendoDiskCard: + dmns.Height = 76.2; + + dmns.Width = 71.12; + + dmns.Thickness = 0; + + return dmns; + case MediaType.HiMD: + case MediaType.MD: + case MediaType.MDData: + case MediaType.MDData2: + case MediaType.MD60: + case MediaType.MD74: + case MediaType.MD80: + dmns.Height = 68; + + dmns.Width = 71.5; + + dmns.Thickness = 4.8; + + return dmns; + case MediaType.DAT160: + case MediaType.DAT320: + case MediaType.DAT72: + case MediaType.DDS1: + case MediaType.DDS2: + case MediaType.DDS3: + case MediaType.DDS4: + case MediaType.DigitalAudioTape: + dmns.Height = 54; + + dmns.Width = 73; + + dmns.Thickness = 10.5; + + return dmns; + case MediaType.CompactFloppy: + dmns.Height = 100; + + dmns.Width = 80; + + dmns.Thickness = 5; + + return dmns; + case MediaType.DECtapeII: + dmns.Height = 60; + + dmns.Width = 81; + + dmns.Thickness = 13; + + return dmns; + case MediaType.Ditto: + dmns.Height = 60; + + dmns.Width = 81; + + dmns.Thickness = 14; + + return dmns; + case MediaType.DittoMax: + dmns.Height = 126; + + dmns.Width = 81; + + dmns.Thickness = 14; + + return dmns; + case MediaType.RDX: + case MediaType.RDX320: + dmns.Height = 119; + + dmns.Width = 87; + + dmns.Thickness = 23; + + return dmns; + case MediaType.LS120: + case MediaType.LS240: + dmns.Height = 94; + + dmns.Width = 90; + + dmns.Thickness = 3.5; + + return dmns; + case MediaType.Travan: + case MediaType.Travan3: + case MediaType.Travan4: + case MediaType.Travan5: + case MediaType.Travan7: + dmns.Height = 72; + + dmns.Width = 92; + + dmns.Thickness = 15; + + return dmns; + case MediaType.Travan1Ex: + dmns.Height = 0; + + dmns.Width = 92; + + dmns.Thickness = 15; + + return dmns; + case MediaType.Travan3Ex: + dmns.Height = 0; + + dmns.Width = 92; + + dmns.Thickness = 15; + + return dmns; + case MediaType.ADR2120: + case MediaType.ADR260: + case MediaType.ADR30: + case MediaType.ADR50: + dmns.Height = 129; + + dmns.Width = 93; + + dmns.Thickness = 14.5; + + return dmns; + case MediaType.Data8: + case MediaType.AIT1: + case MediaType.AIT1Turbo: + case MediaType.AIT2: + case MediaType.AIT2Turbo: + case MediaType.AIT3: + case MediaType.AIT3Ex: + case MediaType.AIT3Turbo: + case MediaType.AIT4: + case MediaType.AIT5: + case MediaType.AITETurbo: + case MediaType.Exatape106m: + case MediaType.Exatape160mXL: + case MediaType.Exatape112m: + case MediaType.Exatape125m: + case MediaType.Exatape150m: + case MediaType.Exatape15m: + case MediaType.Exatape170m: + case MediaType.Exatape225m: + case MediaType.Exatape22m: + case MediaType.Exatape22mAME: + case MediaType.Exatape28m: + case MediaType.Exatape40m: + case MediaType.Exatape45m: + case MediaType.Exatape54m: + case MediaType.Exatape75m: + case MediaType.Exatape76m: + case MediaType.Exatape80m: + dmns.Height = 62.5; + + dmns.Width = 95; + + dmns.Thickness = 15; + + return dmns; + case MediaType.EZ135: + case MediaType.EZ230: + case MediaType.SQ327: + dmns.Height = 97; + + dmns.Width = 98; + + dmns.Thickness = 9.5; + + return dmns; + case MediaType.SQ400: + case MediaType.SQ800: + case MediaType.SQ2000: + dmns.Height = 137; + + dmns.Width = 137; + + dmns.Thickness = 12; + + return dmns; + case MediaType.ZIP100: + case MediaType.ZIP250: + case MediaType.ZIP750: + dmns.Height = 98.5; + + dmns.Width = 98; + + dmns.Thickness = 6.5; + + return dmns; + case MediaType.Jaz: + case MediaType.Jaz2: + dmns.Height = 102; + + dmns.Width = 98; + + dmns.Thickness = 12; + + return dmns; + case MediaType.Orb: + case MediaType.Orb5: + dmns.Height = 104; + + dmns.Width = 98; + + dmns.Thickness = 8; + + return dmns; + case MediaType.SparQ: + dmns.Height = 98; + + dmns.Width = 100; + + dmns.Thickness = 9.7; + + return dmns; + case MediaType.ProfessionalDisc: + case MediaType.ProfessionalDiscDual: + case MediaType.ProfessionalDiscTriple: + case MediaType.ProfessionalDiscQuad: + case MediaType.PDD: + case MediaType.PDD_WORM: + dmns.Height = 130; + + dmns.Width = 128.5; + + dmns.Thickness = 9; + + return dmns; + case MediaType.SLR1: + case MediaType.SLR2: + case MediaType.SLR3: + case MediaType.SLR32: + case MediaType.SLR32SL: + case MediaType.SLR4: + case MediaType.SLR5: + case MediaType.SLR5SL: + case MediaType.SLR6: + case MediaType.SLRtape100: + case MediaType.SLRtape140: + case MediaType.SLRtape24: + case MediaType.SLRtape24SL: + case MediaType.SLRtape40: + case MediaType.SLRtape50: + case MediaType.SLRtape60: + case MediaType.SLRtape7: + case MediaType.SLRtape75: + case MediaType.SLRtape7SL: + dmns.Height = 150; + + dmns.Width = 100; + + dmns.Thickness = 18; + + return dmns; + case MediaType.N64DD: + dmns.Height = 103.124; + + dmns.Width = 101.092; + + dmns.Thickness = 10.16; + + return dmns; + case MediaType.CompactTapeI: + case MediaType.CompactTapeII: + case MediaType.DLTtapeIII: + case MediaType.DLTtapeIIIxt: + case MediaType.DLTtapeIV: + case MediaType.DLTtapeS4: + case MediaType.SDLT1: + case MediaType.SDLT2: + case MediaType.VStapeI: + dmns.Height = 105; + + dmns.Width = 105; + + dmns.Thickness = 25; + + return dmns; + case MediaType.LTO: + case MediaType.LTO2: + case MediaType.LTO3: + case MediaType.LTO3WORM: + case MediaType.LTO4: + case MediaType.LTO4WORM: + case MediaType.LTO5: + case MediaType.LTO5WORM: + case MediaType.LTO6: + case MediaType.LTO6WORM: + case MediaType.LTO7: + case MediaType.LTO7WORM: + dmns.Height = 101.6; + + dmns.Width = 105.41; + + dmns.Thickness = 21.59; + + return dmns; + case MediaType.IBM3480: + case MediaType.IBM3490: + case MediaType.IBM3490E: + case MediaType.IBM3592: + dmns.Height = 125.73; + + dmns.Width = 107.95; + + dmns.Thickness = 25.4; + + return dmns; + case MediaType.T9840A: + case MediaType.T9840B: + case MediaType.T9840C: + case MediaType.T9840D: + case MediaType.T9940A: + case MediaType.T9940B: + dmns.Height = 124.46; + + dmns.Width = 109.22; + + dmns.Thickness = 25.4; + + return dmns; + case MediaType.CompactCassette: + case MediaType.Dcas25: + case MediaType.Dcas85: + case MediaType.Dcas103: + dmns.Height = 63.5; + + dmns.Width = 128; + + dmns.Thickness = 12; + + return dmns; + case MediaType.IBM3470: + dmns.Height = 58.42; + + dmns.Width = 137.16; + + dmns.Thickness = 16.51; + + return dmns; + case MediaType.MLR1: + case MediaType.MLR3: + case MediaType.MLR1SL: + dmns.Height = 101.6; + + dmns.Width = 152.4; + + dmns.Thickness = 15.24; + + return dmns; + case MediaType.QIC11: + case MediaType.QIC120: + case MediaType.QIC1350: + case MediaType.QIC150: + case MediaType.QIC24: + case MediaType.QIC525: + dmns.Height = 101.6; + + dmns.Width = 154.2; + + dmns.Thickness = 16.6; + + return dmns; +#pragma warning disable CS0612 // Type or member is obsolete + case MediaType.Bernoulli: +#pragma warning restore CS0612 // Type or member is obsolete + case MediaType.Bernoulli10: + case MediaType.Bernoulli20: + dmns.Height = 280; + + dmns.Width = 209; + + dmns.Thickness = 18; + + return dmns; +#pragma warning disable CS0612 // Type or member is obsolete + case MediaType.Bernoulli2: +#pragma warning restore CS0612 // Type or member is obsolete + case MediaType.BernoulliBox2_20: + case MediaType.Bernoulli35: + case MediaType.Bernoulli44: + case MediaType.Bernoulli65: + case MediaType.Bernoulli90: + case MediaType.Bernoulli105: + case MediaType.Bernoulli150: + case MediaType.Bernoulli230: + dmns.Height = 138; + + dmns.Width = 136; + + dmns.Thickness = 9; + + return dmns; + case MediaType.DTF: + case MediaType.DTF2: + dmns.Height = 144.78; + + dmns.Width = 254; + + dmns.Thickness = 25.4; + + return dmns; + case MediaType.LD: + case MediaType.LDROM: + case MediaType.LDROM2: + case MediaType.MegaLD: + case MediaType.LVROM: + dmns.Diameter = 300; + + dmns.Thickness = 2.5; + + return dmns; + case MediaType.CRVdisc: + dmns.Height = 344; + + dmns.Width = 325; + + dmns.Thickness = 15.6; + + return dmns; + case MediaType.REV35: + case MediaType.REV70: + case MediaType.REV120: + dmns.Height = 74.8; + + dmns.Width = 76.8; + + dmns.Thickness = 10; + + return dmns; + +#region CD/DVD/BD + + case MediaType.CDDA: + case MediaType.CDG: + case MediaType.CDEG: + case MediaType.CDI: + case MediaType.CDROM: + case MediaType.CDROMXA: + case MediaType.CDPLUS: + case MediaType.CDMO: + case MediaType.CDR: + case MediaType.CDRW: + case MediaType.CDMRW: + case MediaType.VCD: + case MediaType.SVCD: + case MediaType.PCD: + case MediaType.SACD: + case MediaType.DDCD: + case MediaType.DDCDR: + case MediaType.DDCDRW: + case MediaType.DTSCD: + case MediaType.CDMIDI: + case MediaType.CDV: + case MediaType.CD: + case MediaType.DVDROM: + case MediaType.DVDR: + case MediaType.DVDRW: + case MediaType.DVDPR: + case MediaType.DVDPRW: + case MediaType.DVDPRWDL: + case MediaType.DVDRDL: + case MediaType.DVDPRDL: + case MediaType.DVDRAM: + case MediaType.DVDRWDL: + case MediaType.DVDDownload: + case MediaType.HDDVDROM: + case MediaType.HDDVDRAM: + case MediaType.HDDVDR: + case MediaType.HDDVDRW: + case MediaType.HDDVDRDL: + case MediaType.HDDVDRWDL: + case MediaType.BDROM: + case MediaType.BDR: + case MediaType.BDRE: + case MediaType.BDRXL: + case MediaType.BDREXL: + case MediaType.PS1CD: + case MediaType.PS2CD: + case MediaType.PS2DVD: + case MediaType.PS3DVD: + case MediaType.PS3BD: + case MediaType.PS4BD: + case MediaType.PS5BD: + case MediaType.XGD: + case MediaType.XGD2: + case MediaType.XGD3: + case MediaType.XGD4: + case MediaType.MEGACD: + case MediaType.SATURNCD: + case MediaType.GDROM: + case MediaType.GDR: + case MediaType.SuperCDROM2: + case MediaType.JaguarCD: + case MediaType.ThreeDO: + case MediaType.WOD: + case MediaType.WUOD: + case MediaType.PCFX: + case MediaType.CDIREADY: + case MediaType.FMTOWNS: + case MediaType.CDTV: + case MediaType.CD32: + case MediaType.Nuon: + case MediaType.Playdia: + case MediaType.Pippin: + case MediaType.MilCD: + case MediaType.CVD: + case MediaType.UHDBD: + dmns.Diameter = 120; + + dmns.Thickness = 1.2; + + return dmns; + case MediaType.GOD: + dmns.Diameter = 80; + + dmns.Thickness = 1.2; + + return dmns; + case MediaType.VideoNow: + dmns.Diameter = 85; + + dmns.Thickness = 1.2; + + return dmns; + case MediaType.VideoNowColor: + case MediaType.VideoNowXp: + dmns.Diameter = 108; + + dmns.Thickness = 1.2; + + return dmns; + +#endregion CD/DVD/BD + +#region Apple Hard Disks + + // TODO: Find Apple Widget size + case MediaType.AppleProfile: + dmns.Height = 223.8; + + dmns.Width = 438.9; + + dmns.Thickness = 111.5; + + return dmns; + case MediaType.AppleHD20: + dmns.Height = 246.4; + + dmns.Width = 266.7; + + dmns.Thickness = 78.7; + + return dmns; + +#endregion Apple Hard Disks + + case MediaType.UMD: + dmns.Height = 64; + + dmns.Width = 63; + + dmns.Thickness = 4; + + return dmns; + case MediaType.HF12: + case MediaType.HF24: + dmns.Height = 137.5; + + dmns.Width = 135.9; + + dmns.Thickness = 5.64; + + return dmns; + default: + return null; + } + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Dump.cs b/Aaru.CommonTypes/AaruMetadata/Dump.cs new file mode 100644 index 000000000..449050fe7 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Dump.cs @@ -0,0 +1,149 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Dump.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Image +{ + public string Format { get; set; } + public ulong? Offset { get; set; } + public string Value { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Image(ImageType cicm) => cicm is null + ? null + : new Image + { + Format = cicm.format, + Offset = cicm.offsetSpecified ? cicm.offset : null, + Value = cicm.Value + }; +} + +public class Dump +{ + public string Image { get; set; } + public ulong Size { get; set; } + public List Checksums { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Dump(DumpType cicm) + { + if(cicm is null) return null; + + Dump dump = new() + { + Image = cicm.Image, + Size = cicm.Size + }; + + if(cicm.Checksums is null) return dump; + + dump.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) dump.Checksums.Add(chk); + + return dump; + } +} + +public class Border +{ + public string Image { get; set; } + public ulong Size { get; set; } + public List Checksums { get; set; } + public uint? Session { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Border(BorderType cicm) + { + if(cicm is null) return null; + + var border = new Border + { + Image = cicm.Image, + Size = cicm.Size, + Session = cicm.sessionSpecified ? cicm.session : null + }; + + if(cicm.Checksums is null) return border; + + border.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) border.Checksums.Add(chk); + + return border; + } +} + +public class File +{ + public string Format { get; set; } + public string Value { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator File(FileType cicm) => cicm is null + ? null + : new File + { + Format = cicm.format, + Value = cicm.Value + }; +} + +public class BlockSize +{ + public uint StartingBlock { get; set; } + public uint Value { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator BlockSize(BlockSizeType cicm) => cicm is null + ? null + : new BlockSize + { + StartingBlock = cicm.startingBlock, + Value = cicm.Value + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/DumpHardware.cs b/Aaru.CommonTypes/AaruMetadata/DumpHardware.cs new file mode 100644 index 000000000..628956220 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/DumpHardware.cs @@ -0,0 +1,113 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DumpHardware.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class DumpHardware +{ + public string Manufacturer { get; set; } + public string Model { get; set; } + public string Revision { get; set; } + public string Firmware { get; set; } + public string Serial { get; set; } + public List Extents { get; set; } + public Software Software { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator DumpHardware(DumpHardwareType cicm) + { + if(cicm is null) return null; + + var hw = new DumpHardware + { + Manufacturer = cicm.Manufacturer, + Model = cicm.Model, + Revision = cicm.Revision, + Firmware = cicm.Firmware, + Serial = cicm.Serial, + Software = cicm.Software + }; + + if(cicm.Extents is null) return hw; + + hw.Extents = []; + + foreach(ExtentType ext in cicm.Extents) hw.Extents.Add(ext); + + return hw; + } +} + +public class Extent +{ + public ulong Start { get; set; } + public ulong End { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Extent(ExtentType cicm) => cicm is null + ? null + : new Extent + { + Start = cicm.Start, + End = cicm.End + }; +} + +public class Software +{ + public string Name { get; set; } + public string Version { get; set; } + public string OperatingSystem { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Software(SoftwareType cicm) => cicm is null + ? null + : new Software + { + Name = cicm.Name, + Version = cicm.Version, + OperatingSystem = cicm.OperatingSystem + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/FileSystem.cs b/Aaru.CommonTypes/AaruMetadata/FileSystem.cs new file mode 100644 index 000000000..4bc5195ae --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/FileSystem.cs @@ -0,0 +1,121 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : FileSystem.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class FileSystem +{ + public string Type { get; set; } + public DateTime? CreationDate { get; set; } + public DateTime? ModificationDate { get; set; } + public DateTime? BackupDate { get; set; } + public uint ClusterSize { get; set; } + public ulong Clusters { get; set; } + public ulong? Files { get; set; } + public bool Bootable { get; set; } + public string VolumeSerial { get; set; } + public string VolumeName { get; set; } + public ulong? FreeClusters { get; set; } + public bool Dirty { get; set; } + public DateTime? ExpirationDate { get; set; } + public DateTime? EffectiveDate { get; set; } + public string SystemIdentifier { get; set; } + public string VolumeSetIdentifier { get; set; } + public string PublisherIdentifier { get; set; } + public string DataPreparerIdentifier { get; set; } + public string ApplicationIdentifier { get; set; } + public FilesystemContents Contents { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator FileSystem(FileSystemType cicm) => cicm is null + ? null + : new FileSystem + { + Type = cicm.Type, + CreationDate = + cicm.CreationDateSpecified + ? cicm.CreationDate + : null, + ModificationDate = + cicm.ModificationDateSpecified + ? cicm.ModificationDate + : null, + BackupDate = + cicm.BackupDateSpecified + ? cicm.BackupDate + : null, + ClusterSize = cicm.ClusterSize, + Clusters = cicm.Clusters, + Files = + cicm.FilesSpecified + ? cicm.Files + : null, + Bootable = cicm.Bootable, + VolumeSerial = cicm.VolumeSerial, + VolumeName = cicm.VolumeName, + FreeClusters = + cicm.FreeClustersSpecified + ? cicm.FreeClusters + : null, + Dirty = cicm.Dirty, + ExpirationDate = + cicm.ExpirationDateSpecified + ? cicm.ExpirationDate + : null, + EffectiveDate = + cicm.EffectiveDateSpecified + ? cicm.EffectiveDate + : null, + SystemIdentifier = cicm.SystemIdentifier, + VolumeSetIdentifier = + cicm.VolumeSetIdentifier, + PublisherIdentifier = + cicm.PublisherIdentifier, + DataPreparerIdentifier = + cicm.DataPreparerIdentifier, + ApplicationIdentifier = + cicm.ApplicationIdentifier, + Contents = cicm.Contents + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Language.cs b/Aaru.CommonTypes/AaruMetadata/Language.cs new file mode 100644 index 000000000..de72d894a --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Language.cs @@ -0,0 +1,538 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Language.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum Language +{ + aar, + abk, + ace, + ach, + ada, + ady, + afa, + afh, + afr, + ain, + aka, + akk, + alb, + ale, + alg, + alt, + amh, + ang, + anp, + apa, + ara, + arc, + arg, + arm, + arn, + arp, + art, + arw, + asm, + ast, + ath, + aus, + ava, + ave, + awa, + aym, + aze, + bad, + bai, + bak, + bal, + bam, + ban, + baq, + bas, + bat, + bej, + bel, + bem, + ben, + ber, + bho, + bih, + bik, + bin, + bis, + bla, + bnt, + bos, + bra, + bre, + btk, + bua, + bug, + bul, + bur, + byn, + cad, + cai, + car, + cat, + cau, + ceb, + cel, + cha, + chb, + che, + chg, + chi, + chk, + chm, + chn, + cho, + chp, + chr, + chu, + chv, + chy, + cmc, + cop, + cor, + cos, + cpe, + cpf, + cpp, + cre, + crh, + crp, + csb, + cus, + cze, + dak, + dan, + dar, + day, + del, + den, + dgr, + din, + div, + doi, + dra, + dsb, + dua, + dum, + dut, + dyu, + dzo, + efi, + egy, + eka, + elx, + eng, + enm, + epo, + est, + ewe, + ewo, + fan, + fao, + fat, + fij, + fil, + fin, + fiu, + fon, + fre, + frm, + fro, + frr, + frs, + fry, + ful, + fur, + gaa, + gay, + gba, + gem, + geo, + ger, + gez, + gil, + gla, + gle, + glg, + glv, + gmh, + goh, + gon, + gor, + got, + grb, + grc, + gre, + grn, + gsw, + guj, + gwi, + hai, + hat, + hau, + haw, + heb, + her, + hil, + him, + hin, + hit, + hmn, + hmo, + hrv, + hsb, + hun, + hup, + iba, + ibo, + ice, + ido, + iii, + ijo, + iku, + ile, + ilo, + ina, + inc, + ind, + ine, + inh, + ipk, + ira, + iro, + ita, + jav, + jbo, + jpn, + jpr, + jrb, + kaa, + kab, + kac, + kal, + kam, + kan, + kar, + kas, + kau, + kaw, + kaz, + kbd, + kha, + khi, + khm, + kho, + kik, + kin, + kir, + kmb, + kok, + kom, + kon, + kor, + kos, + kpe, + krc, + krl, + kro, + kru, + kua, + kum, + kur, + kut, + lad, + lah, + lam, + lao, + lat, + lav, + lez, + lim, + lin, + lit, + lol, + loz, + ltz, + lua, + lub, + lug, + lui, + lun, + luo, + lus, + mac, + mad, + mag, + mah, + mai, + mak, + mal, + man, + mao, + map, + mar, + mas, + may, + mdf, + mdr, + men, + mga, + mic, + min, + mis, + mkh, + mlg, + mlt, + mnc, + mni, + mno, + moh, + mon, + mos, + mul, + mun, + mus, + mwl, + mwr, + myn, + myv, + nah, + nai, + nap, + nau, + nav, + nbl, + nde, + ndo, + nds, + nep, + @new, + nia, + nic, + niu, + nno, + nob, + nog, + non, + nor, + nqo, + nso, + nub, + nwc, + nya, + nym, + nyn, + nyo, + nzi, + oci, + oji, + ori, + orm, + osa, + oss, + ota, + oto, + paa, + pag, + pal, + pam, + pan, + pap, + pau, + peo, + per, + phi, + phn, + pli, + pol, + pon, + por, + pra, + pro, + pus, + [JsonPropertyName("qaa-qtz")] + qaaqtz, + que, + raj, + rap, + rar, + roa, + roh, + rom, + rum, + run, + rup, + rus, + sad, + sag, + sah, + sai, + sal, + sam, + san, + sas, + sat, + scn, + sco, + sel, + sem, + sga, + sgn, + shn, + sid, + sin, + sio, + sit, + sla, + slo, + slv, + sma, + sme, + smi, + smj, + smn, + smo, + sms, + sna, + snd, + snk, + sog, + som, + son, + sot, + spa, + srd, + srn, + srp, + srr, + ssa, + ssw, + suk, + sun, + sus, + sux, + swa, + swe, + syc, + syr, + tah, + tai, + tam, + tat, + tel, + tem, + ter, + tet, + tgk, + tgl, + tha, + tib, + tig, + tir, + tiv, + tkl, + tlh, + tli, + tmh, + tog, + ton, + tpi, + tsi, + tsn, + tso, + tuk, + tum, + tup, + tur, + tut, + tvl, + twi, + tyv, + udm, + uga, + uig, + ukr, + umb, + und, + urd, + uzb, + vai, + ven, + vie, + vol, + vot, + wak, + wal, + war, + was, + wel, + wen, + wln, + wol, + xal, + xho, + yao, + yap, + yid, + yor, + ypk, + zap, + zbl, + zen, + zgh, + zha, + znd, + zul, + zun, + zxx, + zza +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Layers.cs b/Aaru.CommonTypes/AaruMetadata/Layers.cs new file mode 100644 index 000000000..ef0e4fe76 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Layers.cs @@ -0,0 +1,114 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Layers.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Layers +{ + public List Sectors { get; set; } + public LayerType? Type { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Layers(LayersType cicm) + { + if(cicm is null) return null; + + var layers = new Layers + { + Type = cicm.typeSpecified ? (LayerType)cicm.type : null + }; + + if(cicm.Sectors is null) return layers; + + layers.Sectors = []; + + foreach(SectorsType sec in cicm.Sectors) layers.Sectors.Add(sec); + + return layers; + } +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +public enum LayerType +{ + PTP, + OTP +} + +public class LayeredText +{ + public uint? Layer { get; set; } + public string Text { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator LayeredText(LayeredTextType cicm) => cicm is null + ? null + : new LayeredText + { + Layer = cicm.layerSpecified + ? cicm.layer + : null, + Text = cicm.Value + }; +} + +public class Sectors +{ + public uint? Layer { get; set; } + public ulong Value { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Sectors(SectorsType cicm) => cicm is null + ? null + : new Sectors + { + Layer = + cicm.layerSpecified ? cicm.layer : null, + Value = cicm.Value + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/LinearMedia.cs b/Aaru.CommonTypes/AaruMetadata/LinearMedia.cs new file mode 100644 index 000000000..68cacc6bc --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/LinearMedia.cs @@ -0,0 +1,117 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : LinearMedia.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class LinearMedia +{ + public Image Image { get; set; } + public ulong Size { get; set; } + public List ImageChecksums { get; set; } + public List Checksums { get; set; } + public string PartNumber { get; set; } + public string SerialNumber { get; set; } + public string Title { get; set; } + public uint? Sequence { get; set; } + public uint? ImageInterleave { get; set; } + public uint? Interleave { get; set; } + public string Manufacturer { get; set; } + public string Model { get; set; } + public string Package { get; set; } + public string Interface { get; set; } + public Dimensions Dimensions { get; set; } + public Scans Scans { get; set; } + public List DumpHardware { get; set; } + public Pcmcia Pcmcia { get; set; } + public string CopyProtection { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator LinearMedia(LinearMediaType cicm) + { + if(cicm is null) return null; + + var linearMedia = new LinearMedia + { + Image = cicm.Image, + Size = cicm.Size, + PartNumber = cicm.PartNumber, + SerialNumber = cicm.SerialNumber, + Title = cicm.Title, + Sequence = cicm.SequenceSpecified ? cicm.Sequence : null, + ImageInterleave = cicm.ImageInterleaveSpecified ? cicm.ImageInterleave : null, + Interleave = cicm.InterleaveSpecified ? cicm.Interleave : null, + Manufacturer = cicm.Manufacturer, + Model = cicm.Model, + Package = cicm.Package, + Interface = cicm.Interface, + Dimensions = cicm.Dimensions, + Scans = cicm.Scans, + Pcmcia = cicm.PCMCIA, + CopyProtection = cicm.CopyProtection + }; + + if(cicm.ImageChecksums is not null) + { + linearMedia.ImageChecksums = []; + + foreach(Schemas.ChecksumType chk in cicm.ImageChecksums) linearMedia.ImageChecksums.Add(chk); + } + + if(cicm.Checksums is not null) + { + linearMedia.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) linearMedia.Checksums.Add(chk); + } + + if(cicm.DumpHardwareArray is null) return linearMedia; + + linearMedia.DumpHardware = []; + + foreach(DumpHardwareType hw in cicm.DumpHardwareArray) linearMedia.DumpHardware.Add(hw); + + return linearMedia; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Magazine.cs b/Aaru.CommonTypes/AaruMetadata/Magazine.cs new file mode 100644 index 000000000..dc7c99bbd --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Magazine.cs @@ -0,0 +1,90 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Magazine.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Magazine +{ + public List Barcodes { get; set; } + public Cover Cover { get; set; } + public string Name { get; set; } + public string Editorial { get; set; } + public DateTime? PublicationDate { get; set; } + public uint? Number { get; set; } + public List Languages { get; set; } + public uint? Pages { get; set; } + public string PageSize { get; set; } + public Scan Scan { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Magazine(MagazineType cicm) + { + if(cicm is null) return null; + + var magazine = new Magazine + { + Cover = cicm.Cover, + Name = cicm.Name, + Editorial = cicm.Editorial, + PublicationDate = cicm.PublicationDateSpecified ? cicm.PublicationDate : null, + Number = cicm.NumberSpecified ? cicm.Number : null, + Pages = cicm.PagesSpecified ? cicm.Pages : null, + Scan = cicm.Scan + }; + + if(cicm.Barcodes is not null) + { + magazine.Barcodes = []; + + foreach(Schemas.BarcodeType code in cicm.Barcodes) magazine.Barcodes.Add(code); + } + + if(cicm.Language is null) return magazine; + + foreach(LanguagesTypeLanguage lng in cicm.Language) magazine.Languages.Add((Language)lng); + + return magazine; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/MultiMediaCard.cs b/Aaru.CommonTypes/AaruMetadata/MultiMediaCard.cs new file mode 100644 index 000000000..936d0ab08 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/MultiMediaCard.cs @@ -0,0 +1,64 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : MultiMediaCard.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System; +using Schemas; + +namespace Aaru.CommonTypes.AaruMetadata; + +public class MultiMediaCard +{ + public Dump CID { get; set; } + public Dump CSD { get; set; } + public Dump ExtendedCSD { get; set; } + public Dump OCR { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator MultiMediaCard(MultiMediaCardType cicm) => cicm is null + ? null + : new MultiMediaCard + { + CSD = cicm.CSD, + CID = cicm.CID, + ExtendedCSD = cicm.ExtendedCSD, + OCR = cicm.OCR + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/OpticalDisc.cs b/Aaru.CommonTypes/AaruMetadata/OpticalDisc.cs new file mode 100644 index 000000000..6afca5f5d --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/OpticalDisc.cs @@ -0,0 +1,377 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : OpticalDisc.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class OpticalDisc +{ + public Image Image { get; set; } + public ulong Size { get; set; } + public Sequence Sequence { get; set; } + public Layers Layers { get; set; } + public List Checksums { get; set; } + public string PartNumber { get; set; } + public string SerialNumber { get; set; } + public List RingCode { get; set; } + public List MasteringSid { get; set; } + public List Toolstamp { get; set; } + public List MouldSid { get; set; } + public List MouldText { get; set; } + public string DiscType { get; set; } + public string DiscSubType { get; set; } + public int? Offset { get; set; } + public uint[] Tracks { get; set; } + public uint Sessions { get; set; } + public string CopyProtection { get; set; } + public Dimensions Dimensions { get; set; } + public Case Case { get; set; } + public Scans Scans { get; set; } + public Dump Pfi { get; set; } + public Dump Dmi { get; set; } + public Dump Cmi { get; set; } + public Dump Bca { get; set; } + public Dump Atip { get; set; } + public Dump Adip { get; set; } + public Dump Pma { get; set; } + public Dump Dds { get; set; } + public Dump Sai { get; set; } + public Dump LastRmd { get; set; } + public Dump Pri { get; set; } + public Dump MediaID { get; set; } + public Dump Pfir { get; set; } + public Dump Dcb { get; set; } + public Dump Di { get; set; } + public Dump Pac { get; set; } + public Dump Toc { get; set; } + public Dump LeadInCdText { get; set; } + public List FirstTrackPregrap { get; set; } + public List LeadIn { get; set; } + public List LeadOut { get; set; } + public Xbox Xbox { get; set; } + public Ps3Encryption Ps3Encryption { get; set; } + public string MediaCatalogueNumber { get; set; } + public List Track { get; set; } + public List DumpHardware { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator OpticalDisc(OpticalDiscType cicm) + { + if(cicm is null) return null; + + var disc = new OpticalDisc + { + Image = cicm.Image, + Size = cicm.Size, + Sequence = cicm.Sequence, + Layers = cicm.Layers, + PartNumber = cicm.PartNumber, + SerialNumber = cicm.SerialNumber, + DiscType = cicm.DiscType, + DiscSubType = cicm.DiscSubType, + Offset = cicm.OffsetSpecified ? cicm.Offset : null, + Tracks = cicm.Tracks, + Sessions = cicm.Sessions, + CopyProtection = cicm.CopyProtection, + Dimensions = cicm.Dimensions, + Case = cicm.Case, + Scans = cicm.Scans, + Pfi = cicm.PFI, + Dmi = cicm.DMI, + Cmi = cicm.CMI, + Bca = cicm.BCA, + Atip = cicm.ATIP, + Adip = cicm.ADIP, + Pma = cicm.PMA, + Dds = cicm.DDS, + Sai = cicm.SAI, + LastRmd = cicm.LastRMD, + Pri = cicm.PRI, + MediaID = cicm.MediaID, + Pfir = cicm.PFIR, + Dcb = cicm.DCB, + Pac = cicm.PAC, + Toc = cicm.TOC, + LeadInCdText = cicm.LeadInCdText, + Xbox = cicm.Xbox, + Ps3Encryption = cicm.PS3Encryption, + MediaCatalogueNumber = cicm.MediaCatalogueNumber + }; + + if(cicm.Checksums is not null) + { + disc.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) disc.Checksums.Add(chk); + } + + if(cicm.RingCode is not null) + { + disc.RingCode = []; + + foreach(LayeredTextType lt in cicm.RingCode) disc.RingCode.Add(lt); + } + + if(cicm.MasteringSID is not null) + { + disc.MasteringSid = []; + + foreach(LayeredTextType lt in cicm.MasteringSID) disc.MasteringSid.Add(lt); + } + + if(cicm.Toolstamp is not null) + { + disc.Toolstamp = []; + + foreach(LayeredTextType lt in cicm.Toolstamp) disc.Toolstamp.Add(lt); + } + + if(cicm.MouldSID is not null) + { + disc.MouldSid = []; + + foreach(LayeredTextType lt in cicm.MouldSID) disc.MouldSid.Add(lt); + } + + if(cicm.MouldText is not null) + { + disc.MouldText = []; + + foreach(LayeredTextType lt in cicm.MouldText) disc.MouldText.Add(lt); + } + + if(cicm.FirstTrackPregrap is not null) + { + disc.FirstTrackPregrap = []; + + foreach(BorderType lt in cicm.FirstTrackPregrap) disc.FirstTrackPregrap.Add(lt); + } + + if(cicm.LeadIn is not null) + { + disc.LeadIn = []; + + foreach(BorderType lt in cicm.LeadIn) disc.LeadIn.Add(lt); + } + + if(cicm.LeadOut is not null) + { + disc.LeadOut = []; + + foreach(BorderType lt in cicm.LeadOut) disc.LeadOut.Add(lt); + } + + if(cicm.Track is not null) + { + disc.Track = []; + + foreach(Schemas.TrackType lt in cicm.Track) disc.Track.Add(lt); + } + + if(cicm.DumpHardwareArray is null) return disc; + + disc.DumpHardware = []; + + foreach(DumpHardwareType hw in cicm.DumpHardwareArray) disc.DumpHardware.Add(hw); + + return disc; + } +} + +public class Track +{ + public Image Image { get; set; } + public ulong Size { get; set; } + public TrackSequence Sequence { get; set; } + public string StartMsf { get; set; } + public string EndMsf { get; set; } + public ulong StartSector { get; set; } + public ulong EndSector { get; set; } + public List Indexes { get; set; } + public TrackFlags Flags { get; set; } + public string ISRC { get; set; } + public TrackType Type { get; set; } + public uint BytesPerSector { get; set; } + public string AccoustID { get; set; } + public List Checksums { get; set; } + public SubChannel SubChannel { get; set; } + public List FileSystemInformation { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Track(Schemas.TrackType cicm) + { + if(cicm is null) return null; + + var trk = new Track + { + Image = cicm.Image, + Size = cicm.Size, + Sequence = cicm.Sequence, + StartMsf = cicm.StartMSF, + EndMsf = cicm.EndMSF, + StartSector = cicm.StartSector, + EndSector = cicm.EndSector, + Flags = cicm.Flags, + ISRC = cicm.ISRC, + Type = (TrackType)cicm.TrackType1, + BytesPerSector = cicm.BytesPerSector, + AccoustID = cicm.AccoustID, + SubChannel = cicm.SubChannel + }; + + if(cicm.Indexes is not null) + { + trk.Indexes = []; + + foreach(TrackIndexType idx in cicm.Indexes) trk.Indexes.Add(idx); + } + + if(cicm.Checksums is not null) + { + trk.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) trk.Checksums.Add(chk); + } + + if(cicm.FileSystemInformation is null) return trk; + + trk.FileSystemInformation = []; + + foreach(PartitionType fs in cicm.FileSystemInformation) trk.FileSystemInformation.Add(fs); + + return trk; + } +} + +public class TrackSequence +{ + public uint Number { get; set; } + public uint Session { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator TrackSequence(TrackSequenceType cicm) => cicm is null + ? null + : new TrackSequence + { + Number = cicm.TrackNumber, + Session = cicm.Session + }; +} + +public class TrackIndex +{ + public ushort Index { get; set; } + public int Value { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator TrackIndex(TrackIndexType cicm) => cicm is null + ? null + : new TrackIndex + { + Index = cicm.index, + Value = cicm.Value + }; +} + +public class TrackFlags +{ + public bool Quadraphonic { get; set; } + public bool Data { get; set; } + public bool CopyPermitted { get; set; } + public bool PreEmphasis { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator TrackFlags(TrackFlagsType cicm) => cicm is null + ? null + : new TrackFlags + { + CopyPermitted = cicm.CopyPermitted, + Data = cicm.Data, + PreEmphasis = cicm.PreEmphasis, + Quadraphonic = cicm.Quadraphonic + }; +} + +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +public enum TrackType +{ + Audio, + Mode0, + Mode1, + Mode2, + Mode2Form1, + Mode2Form2, + Dvd, + HdDvd, + Bluray, + Ddcd +} + +public class SubChannel +{ + public Image Image { get; set; } + public ulong Size { get; set; } + public List Checksums { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator SubChannel(SubChannelType cicm) + { + if(cicm is null) return null; + + var subchannel = new SubChannel + { + Image = cicm.Image, + Size = cicm.Size + }; + + if(cicm.Checksums is null) return subchannel; + + subchannel.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) subchannel.Checksums.Add(chk); + + return subchannel; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/PCI.cs b/Aaru.CommonTypes/AaruMetadata/PCI.cs new file mode 100644 index 000000000..9e0e83edd --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/PCI.cs @@ -0,0 +1,67 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PCI.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System; +using Schemas; + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Pci +{ + public ushort VendorID { get; set; } + + public ushort DeviceID { get; set; } + + public Dump Configuration { get; set; } + + public LinearMedia ExpansionRom { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Pci(PCIType cicm) => cicm is null + ? null + : new Pci + { + VendorID = cicm.VendorID, + DeviceID = cicm.DeviceID, + Configuration = cicm.Configuration, + ExpansionRom = cicm.ExpansionROM + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/PCMCIA.cs b/Aaru.CommonTypes/AaruMetadata/PCMCIA.cs new file mode 100644 index 000000000..9dbdd7d18 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/PCMCIA.cs @@ -0,0 +1,80 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PCMCIA.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Pcmcia +{ + public Dump Cis { get; set; } + public string Compliance { get; set; } + public ushort? ManufacturerCode { get; set; } + public ushort? CardCode { get; set; } + public string Manufacturer { get; set; } + public string ProductName { get; set; } + public List AdditionalInformation { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Pcmcia(PCMCIAType cicm) => cicm is null + ? null + : new Pcmcia + { + Cis = cicm.CIS, + Compliance = cicm.Compliance, + ManufacturerCode = + cicm.ManufacturerCodeSpecified + ? cicm.ManufacturerCode + : null, + CardCode = + cicm.CardCodeSpecified + ? cicm.CardCode + : null, + Manufacturer = cicm.Manufacturer, + ProductName = cicm.ProductName, + AdditionalInformation = + cicm.AdditionalInformation is null + ? null + : [..cicm.AdditionalInformation] + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/PS3.cs b/Aaru.CommonTypes/AaruMetadata/PS3.cs new file mode 100644 index 000000000..c8c6f1e7a --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/PS3.cs @@ -0,0 +1,60 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PS3.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System; +using Schemas; + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Ps3Encryption +{ + public string Key { get; set; } + public string Serial { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Ps3Encryption(PS3EncryptionType cicm) => cicm is null + ? null + : new Ps3Encryption + { + Key = cicm.Key, + Serial = cicm.Serial + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Partition.cs b/Aaru.CommonTypes/AaruMetadata/Partition.cs new file mode 100644 index 000000000..b88c6c213 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Partition.cs @@ -0,0 +1,81 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Partition.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Partition +{ + public uint Sequence { get; set; } + public string Name { get; set; } + public string Type { get; set; } + public ulong StartSector { get; set; } + public ulong EndSector { get; set; } + public string Description { get; set; } + public List FileSystems { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Partition(PartitionType cicm) + { + if(cicm is null) return null; + + var part = new Partition + { + Sequence = cicm.Sequence, + Name = cicm.Name, + Type = cicm.Type, + StartSector = cicm.StartSector, + EndSector = cicm.EndSector, + Description = cicm.Description + }; + + if(cicm.FileSystems is null) return part; + + part.FileSystems = []; + + foreach(FileSystemType fs in cicm.FileSystems) part.FileSystems.Add(fs); + + return part; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/ReleaseType.cs b/Aaru.CommonTypes/AaruMetadata/ReleaseType.cs new file mode 100644 index 000000000..0066f670c --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/ReleaseType.cs @@ -0,0 +1,63 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ReleaseType.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; + +namespace Aaru.CommonTypes.AaruMetadata; + +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum ReleaseType +{ + Retail, + Bundle, + Coverdisc, + Subscription, + Demo, + OEM, + Shareware, + FOSS, + Adware, + Donationware, + DigitalDownload, + SaaS +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/RequiredOperatingSystem.cs b/Aaru.CommonTypes/AaruMetadata/RequiredOperatingSystem.cs new file mode 100644 index 000000000..444b949aa --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/RequiredOperatingSystem.cs @@ -0,0 +1,61 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : RequiredOperatingSystem.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class RequiredOperatingSystem +{ + public string Name { get; set; } + public List Versions { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator RequiredOperatingSystem(RequiredOperatingSystemType cicm) => cicm is null + ? null + : new RequiredOperatingSystem + { + Name = cicm.Name, + Versions = cicm.Version is null ? null : [..cicm.Version] + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/SCSI.cs b/Aaru.CommonTypes/AaruMetadata/SCSI.cs new file mode 100644 index 000000000..4a645704d --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/SCSI.cs @@ -0,0 +1,106 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SCSI.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class SCSI +{ + public Dump Inquiry { get; set; } + public List Evpds { get; set; } + public Dump ModeSense { get; set; } + public Dump ModeSense10 { get; set; } + public Dump LogSense { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator SCSI(SCSIType cicm) + { + if(cicm is null) return null; + + var scsi = new SCSI + { + Inquiry = cicm.Inquiry, + LogSense = cicm.LogSense, + ModeSense = cicm.ModeSense, + ModeSense10 = cicm.ModeSense10 + }; + + if(cicm.EVPD is null) return cicm; + + scsi.Evpds = []; + + foreach(EVPDType evpd in cicm.EVPD) scsi.Evpds.Add(evpd); + + return scsi; + } +} + +public class Evpd +{ + public string Image { get; set; } + public ulong Size { get; set; } + public List Checksums { get; set; } + public byte? Page { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Evpd(EVPDType cicm) + { + if(cicm is null) return null; + + var evpd = new Evpd + { + Image = cicm.Image, + Size = cicm.Size, + Page = cicm.pageSpecified ? cicm.page : null + }; + + if(cicm.Checksums is null) return evpd; + + evpd.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) evpd.Checksums.Add(chk); + + return evpd; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Scanning.cs b/Aaru.CommonTypes/AaruMetadata/Scanning.cs new file mode 100644 index 000000000..1c848dfbd --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Scanning.cs @@ -0,0 +1,312 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Scanning.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Scan +{ + public File File { get; set; } + public List Checksums { get; set; } + public List Scanner { get; set; } + public List ScanProcessing { get; set; } + public List OCR { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Scan(ScanType cicm) + { + if(cicm is null) return null; + + var scan = new Scan + { + File = cicm.File + }; + + if(cicm.Checksums is not null) + { + scan.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) scan.Checksums.Add(chk); + } + + if(cicm.Scanner is not null) + { + scan.Scanner = []; + + foreach(ScannerType scanner in cicm.Scanner) scan.Scanner.Add(scanner); + } + + if(cicm.ScanProcessing is not null) + { + scan.ScanProcessing = []; + + foreach(ScanProcessingType processing in cicm.ScanProcessing) scan.ScanProcessing.Add(processing); + } + + if(cicm.OCR is null) return scan; + + scan.OCR = []; + + foreach(OCRType ocr in cicm.OCR) scan.OCR.Add(ocr); + + return scan; + } +} + +public class Cover +{ + public File File { get; set; } + public List Checksums { get; set; } + public byte[] Thumbnail { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Cover(CoverType cicm) + { + if(cicm is null) return null; + + var cover = new Cover + { + File = cicm.File, + Thumbnail = cicm.Thumbnail + }; + + if(cicm.Checksums is null) return cover; + + cover.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) cover.Checksums.Add(chk); + + return cover; + } +} + +public class Case +{ + public CaseType Type { get; set; } + public Scans Scans { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Case(Schemas.CaseType cicm) => cicm is null + ? null + : new Case + { + Type = (CaseType)cicm.CaseType1, + Scans = cicm.Scans + }; +} + +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +public enum CaseType +{ + Jewel, + BigJewel, + SlimJewel, + Sleeve, + Qpack, + Digisleeve, + DiscboxSlider, + CompacPlus, + KeepCase, + SnapCase, + SoftCase, + EcoPack, + Liftlock, + Spindle, + Ps2Case, + Ps3Case, + BlurayKeepCase, + PsCase, + DcCase, + SaturnCase, + XboxCase, + Xbox360Case, + XboxOneCase, + SaturnBigCase, + GcCase, + WiiCase, + Unknown +} + +public class Scans +{ + public CaseScan Case { get; set; } + public MediaScan Media { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Scans(ScansType cicm) => cicm is null + ? null + : new Scans + { + Case = cicm.CaseScan, + Media = cicm.Scan + }; +} + +public class CaseScan +{ + public CaseScanElement Element { get; set; } + public Scan Scan { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator CaseScan(CaseScanType cicm) => cicm is null + ? null + : new CaseScan + { + Element = (CaseScanElement)cicm + .CaseScanElement, + Scan = cicm.Scan + }; +} + +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +public enum CaseScanElement +{ + Sleeve, + Inner, + Inlay, + FrontBack, + FrontFull, + BoxFront, + BoxBack, + BoxSpine, + External +} + +public class MediaScan +{ + public MediaScanElement Element { get; set; } + public Scan Scan { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator MediaScan(MediaScanType cicm) => cicm is null + ? null + : new MediaScan + { + Element = (MediaScanElement)cicm + .MediaScanElement, + Scan = cicm.Scan + }; +} + +[JsonConverter(typeof(JsonStringEnumMemberConverter))] +public enum MediaScanElement +{ + Up, + Down, + Front, + Back, + Left, + Right +} + +public class Scanner +{ + public string Author { get; set; } + public string Manufacturer { get; set; } + public string Model { get; set; } + public string Serial { get; set; } + public string Software { get; set; } + public string SoftwareVersion { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Scanner(ScannerType cicm) => cicm is null + ? null + : new Scanner + { + Author = cicm.Author, + Manufacturer = cicm.Manufacturer, + Model = cicm.Model, + Serial = cicm.Serial, + Software = cicm.Software, + SoftwareVersion = cicm.SoftwareVersion + }; +} + +public class ScanProcessing +{ + public string Author { get; set; } + public string Software { get; set; } + public string SoftwareVersion { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator ScanProcessing(ScanProcessingType cicm) => cicm is null + ? null + : new ScanProcessing + { + Author = cicm.Author, + Software = cicm.Software, + SoftwareVersion = + cicm.SoftwareVersion + }; +} + +public class OCR +{ + public string Author { get; set; } + public string Software { get; set; } + public string SoftwareVersion { get; set; } + public List Language { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator OCR(OCRType cicm) + { + if(cicm is null) return null; + + var ocr = new OCR + { + Author = cicm.Author, + Software = cicm.Software, + SoftwareVersion = cicm.SoftwareVersion + }; + + if(cicm.Language is null) return ocr; + + ocr.Language = []; + + foreach(Language lng in cicm.Language) ocr.Language.Add(lng); + + return ocr; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/SecureDigital.cs b/Aaru.CommonTypes/AaruMetadata/SecureDigital.cs new file mode 100644 index 000000000..e34896303 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/SecureDigital.cs @@ -0,0 +1,64 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SecureDigital.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System; +using Schemas; + +namespace Aaru.CommonTypes.AaruMetadata; + +public class SecureDigital +{ + public Dump CID { get; set; } + public Dump CSD { get; set; } + public Dump SCR { get; set; } + public Dump OCR { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator SecureDigital(SecureDigitalType cicm) => cicm is null + ? null + : new SecureDigital + { + CID = cicm.CID, + CSD = cicm.CSD, + SCR = cicm.SCR, + OCR = cicm.OCR + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Sequence.cs b/Aaru.CommonTypes/AaruMetadata/Sequence.cs new file mode 100644 index 000000000..ddd79af29 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Sequence.cs @@ -0,0 +1,68 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Sequence.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System; +using Schemas; + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Sequence +{ + public string Title { get; set; } + public uint MediaSequence { get; set; } + public uint TotalMedia { get; set; } + public byte? Side { get; set; } + public byte? Layer { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Sequence(SequenceType cicm) => cicm is null + ? null + : new Sequence + { + Title = cicm.MediaTitle, + MediaSequence = cicm.MediaSequence, + TotalMedia = cicm.TotalMedia, + Side = cicm.SideSpecified ? cicm.Side : null, + Layer = cicm.LayerSpecified + ? cicm.Layer + : null + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Tape.cs b/Aaru.CommonTypes/AaruMetadata/Tape.cs new file mode 100644 index 000000000..bb8778a13 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Tape.cs @@ -0,0 +1,122 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Tape.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class TapePartition +{ + public Image Image { get; set; } + public ulong Size { get; set; } + public ulong Sequence { get; set; } + public ulong StartBlock { get; set; } + public ulong EndBlock { get; set; } + public List Checksums { get; set; } + public List Files { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator TapePartition(TapePartitionType cicm) + { + if(cicm is null) return null; + + TapePartition partition = new() + { + Image = cicm.Image, + Size = cicm.Size, + Sequence = cicm.Sequence, + StartBlock = cicm.StartBlock, + EndBlock = cicm.EndBlock + }; + + if(cicm.Checksums is not null) + { + partition.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) partition.Checksums.Add(chk); + } + + if(cicm.File is null) return partition; + + partition.Files = []; + + foreach(TapeFileType file in cicm.File) partition.Files.Add(file); + + return partition; + } +} + +public class TapeFile +{ + public Image Image { get; set; } + public ulong Size { get; set; } + public ulong Sequence { get; set; } + public ulong BlockSize { get; set; } + public ulong StartBlock { get; set; } + public ulong EndBlock { get; set; } + public List Checksums { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator TapeFile(TapeFileType cicm) + { + if(cicm is null) return null; + + var file = new TapeFile + { + Image = cicm.Image, + Size = cicm.Size, + Sequence = cicm.Sequence, + BlockSize = cicm.BlockSize, + StartBlock = cicm.StartBlock, + EndBlock = cicm.EndBlock + }; + + if(cicm.Checksums is null) return file; + + file.Checksums = []; + + foreach(Schemas.ChecksumType chk in cicm.Checksums) file.Checksums.Add(chk); + + return file; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/USB.cs b/Aaru.CommonTypes/AaruMetadata/USB.cs new file mode 100644 index 000000000..ce1f2fef8 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/USB.cs @@ -0,0 +1,62 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : USB.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +using System; +using Schemas; + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Usb +{ + public ushort VendorID { get; set; } + public ushort ProductID { get; set; } + public Dump Descriptors { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Usb(USBType cicm) => cicm is null + ? null + : new Usb + { + VendorID = cicm.VendorID, + ProductID = cicm.ProductID, + Descriptors = cicm.Descriptors + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/UserManual.cs b/Aaru.CommonTypes/AaruMetadata/UserManual.cs new file mode 100644 index 000000000..52d588710 --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/UserManual.cs @@ -0,0 +1,75 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : UserManual.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class UserManual +{ + public List Language { get; set; } + public uint Pages { get; set; } + public string PageSize { get; set; } + public Scan Scan { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator UserManual(UserManualType cicm) + { + if(cicm is null) return null; + + var manual = new UserManual + { + Pages = cicm.Pages, + PageSize = cicm.PageSize, + Scan = cicm.Scan + }; + + if(cicm.Language is null) return manual; + + manual.Language = []; + + foreach(LanguagesTypeLanguage lng in cicm.Language) manual.Language.Add((Language)lng); + + return manual; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/AaruMetadata/Xbox.cs b/Aaru.CommonTypes/AaruMetadata/Xbox.cs new file mode 100644 index 000000000..e140e967c --- /dev/null +++ b/Aaru.CommonTypes/AaruMetadata/Xbox.cs @@ -0,0 +1,88 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Xbox.cs +// Author(s) : Natalia Portillo +// +// Component : Metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines format for metadata. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Schemas; + +// ReSharper disable UnusedMember.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace Aaru.CommonTypes.AaruMetadata; + +public class Xbox +{ + public Dump Pfi { get; set; } + public Dump Dmi { get; set; } + public List SecuritySectors { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator Xbox(XboxType cicm) + { + if(cicm is null) return null; + + Xbox xbox = new() + { + Pfi = cicm.PFI, + Dmi = cicm.DMI + }; + + if(cicm.SecuritySectors is null) return xbox; + + foreach(XboxSecuritySectorsType ss in cicm.SecuritySectors) xbox.SecuritySectors.Add(ss); + + return xbox; + } +} + +public class XboxSecuritySector +{ + public uint RequestVersion { get; set; } + public uint RequestNumber { get; set; } + public Dump SecuritySectors { get; set; } + + [Obsolete("Will be removed in Aaru 7")] + public static implicit operator XboxSecuritySector(XboxSecuritySectorsType cicm) => cicm is null + ? null + : new XboxSecuritySector + { + RequestNumber = cicm.RequestNumber, + RequestVersion = cicm.RequestVersion, + SecuritySectors = cicm.SecuritySectors + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Delegates.cs b/Aaru.CommonTypes/Delegates.cs new file mode 100644 index 000000000..32b37f5db --- /dev/null +++ b/Aaru.CommonTypes/Delegates.cs @@ -0,0 +1,91 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Delegates.cs +// Author(s) : Natalia Portillo +// +// Component : Common types. +// +// --[ Description ] ---------------------------------------------------------- +// +// Delegates to communicate with user interface. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedType.Global + +namespace Aaru.CommonTypes; + +/// Initializes a progress indicator (e.g. makes a progress bar visible) +public delegate void InitProgressHandler(); + +/// Updates a progress indicator with text +public delegate void UpdateProgressHandler(string text, long current, long maximum); + +/// Pulses a progress indicator with indeterminate boundaries +public delegate void PulseProgressHandler(string text); + +/// Uninitializes a progress indicator (e.g. adds a newline to the console) +public delegate void EndProgressHandler(); + +/// Initializes a secondary progress indicator (e.g. makes a progress bar visible) +public delegate void InitProgressHandler2(); + +/// Updates a secondary progress indicator with text +public delegate void UpdateProgressHandler2(string text, long current, long maximum); + +/// Pulses a secondary progress indicator with indeterminate boundaries +public delegate void PulseProgressHandler2(string text); + +/// Uninitializes a secondary progress indicator (e.g. adds a newline to the console) +public delegate void EndProgressHandler2(); + +/// Initializes two progress indicators (e.g. makes a progress bar visible) +public delegate void InitTwoProgressHandler(); + +/// Updates two progress indicators with text +public delegate void UpdateTwoProgressHandler(string text, long current, long maximum, string text2, long current2, + long maximum2); + +/// Pulses a progress indicator with indeterminate boundaries +public delegate void PulseTwoProgressHandler(string text, string text2); + +/// Uninitializes a progress indicator (e.g. adds a newline to the console) +public delegate void EndTwoProgressHandler(); + +/// Updates a status indicator +public delegate void UpdateStatusHandler(string text); + +/// Shows an error message +public delegate void ErrorMessageHandler(string text); + +/// Initializes a block map that's going to be filled with a media scan +public delegate void InitBlockMapHandler(ulong blocks, ulong blockSize, ulong blocksToRead, ushort currentProfile); + +/// Updates lists of time taken on scanning from the specified sector +/// Time in milliseconds +public delegate void ScanTimeHandler(ulong sector, double duration); + +/// Specified a number of blocks could not be read on scan +public delegate void ScanUnreadableHandler(ulong sector); + +/// Sends the speed of scanning a specific sector +public delegate void ScanSpeedHandler(ulong sector, double currentSpeed); \ No newline at end of file diff --git a/Aaru.CommonTypes/Enums/DeviceType.cs b/Aaru.CommonTypes/Enums/DeviceType.cs new file mode 100644 index 000000000..241ab7872 --- /dev/null +++ b/Aaru.CommonTypes/Enums/DeviceType.cs @@ -0,0 +1,58 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DeviceType.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines enumerations of device types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.CommonTypes.Enums; + +/// Device types +public enum DeviceType +{ + /// Unknown device type + Unknown = -1, + /// ATA device + ATA = 1, + /// ATA Packet device (aka SCSI over ATA) + ATAPI = 2, + /// SCSI device (or USB-MSC, SBP2, FC, UAS, etc) + SCSI = 3, + /// SecureDigital memory card + SecureDigital = 4, + /// MultiMediaCard memory card + MMC = 5, + /// NVMe device + NVMe = 6 +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Enums/ErrorNumber.cs b/Aaru.CommonTypes/Enums/ErrorNumber.cs new file mode 100644 index 000000000..aac605df5 --- /dev/null +++ b/Aaru.CommonTypes/Enums/ErrorNumber.cs @@ -0,0 +1,287 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ErrorNumber.cs +// Author(s) : Natalia Portillo +// +// Component : Common types. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines enumerations of error numbers. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.CommonTypes.Enums; + +/// Enumerates error codes. Negative for UNIX error number equivalents, positive for Aaru error numbers. +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "IdentifierTypo")] +public enum ErrorNumber +{ + /// Operation not permitted + NotPermitted = -1, + /// No such file or directory + NoSuchFile = -2, + /// No such process + NoSuchProcess = -3, + /// System call interrupted + InterruptedSyscall = -4, + /// I/O error + InOutError = -5, + /// No such device or address + NoSuchDeviceOrAddress = -6, + /// The argument list is too long + ArgumentListTooLong = -7, + /// Error loading the executable format + ExecutableFormatError = -8, + /// Bad file descriptor + BadFileNumber = -9, + /// No child process + NoChildProcess = -10, + /// Try again + TryAgain = -11, + /// Process ran out of memory + OutOfMemory = -12, + /// Access denied + AccessDenied = -13, + /// Bad address + BadAddress = -14, + /// File is not a block device + NotABlockDevice = -15, + /// Busy, cannot complete + Busy = -16, + /// File already exists + FileExists = -17, + /// Tried to create a link that crosses devices + CrossDeviceLink = -18, + /// No such device + NoSuchDevice = -19, + /// Is not a directory (e.g.: trying to ReadDir() a file) + NotDirectory = -20, + /// Is a directory (e.g.: trying to Read() a dir) + IsDirectory = -21, + /// Invalid argument + InvalidArgument = -22, + /// File table overflow + FileTableOverflow = -23, + /// Too many open files + TooManyOpenFiles = -24, + /// Destination is not a TTY + NotTypewriter = -25, + /// Text file busy + TextFileBusy = -26, + /// File is too large + FileTooLarge = -27, + /// No space left on volume + NoSpaceLeft = -28, + /// Illegal seek requested + IllegalSeek = -29, + /// Tried a write operation on a read-only device + ReadOnly = -30, + /// Too many links + TooManyLinks = -31, + /// Broken pipe + BrokenPipe = -32, + /// Out of domain + OutOfDomain = -33, + /// Out of range + OutOfRange = -34, + /// Operation would incur in a deadlock + DeadlockWouldOccur = -35, + /// Name is too long + NameTooLong = -36, + /// There are no available locks + NoLocksAvailable = -37, + /// Not implemented + NotImplemented = -38, + /// There is no data available + NoData = -61, + /// Link is severed + SeveredLink = -67, + /// There is no such attribute + NoSuchExtendedAttribute = NoData, + /// Not supported + NotSupported = -252, + /// Operation not permitted + EPERM = NotPermitted, + /// No such file or directory + ENOENT = NoSuchFile, + /// No such process + ESRCH = NoSuchProcess, + /// System call interrupted + EINTR = InterruptedSyscall, + /// I/O error + EIO = InOutError, + /// No such device or address + ENXIO = NoSuchDeviceOrAddress, + /// The argument list is too long + E2BIG = ArgumentListTooLong, + /// Error loading the executable format + ENOEXEC = ExecutableFormatError, + /// Bad file descriptor + EBADF = BadFileNumber, + /// No child process + ECHILD = NoChildProcess, + /// Try again + EAGAIN = TryAgain, + /// Process ran out of memory + ENOMEM = OutOfMemory, + /// Access denied + EACCES = AccessDenied, + /// Bad address + EFAULT = BadAddress, + /// File is not a block device + ENOTBLK = NotABlockDevice, + /// Busy, cannot complete + EBUSY = Busy, + /// File already exists + EEXIST = FileExists, + /// Tried to create a link that crosses devices + EXDEV = CrossDeviceLink, + /// No such device + ENODEV = NoSuchDevice, + /// Is not a directory (e.g.: trying to ReadDir() a file) + ENOTDIR = NotDirectory, + /// Is a directory (e.g.: trying to Read() a dir) + EISDIR = IsDirectory, + /// Invalid argument + EINVAL = InvalidArgument, + /// File table overflow + ENFILE = FileTableOverflow, + /// Too many open files + EMFILE = TooManyOpenFiles, + /// Destination is not a TTY + ENOTTY = NotTypewriter, + /// Text file busy + ETXTBSY = TextFileBusy, + /// File is too large + EFBIG = FileTooLarge, + /// No space left on volume + ENOSPC = NoSpaceLeft, + /// Illegal seek requested + ESPIPE = IllegalSeek, + /// Tried a write operation on a read-only device + EROFS = ReadOnly, + /// Too many links + EMLINK = TooManyLinks, + /// Broken pipe + EPIPE = BrokenPipe, + /// Out of domain + EDOM = OutOfDomain, + /// Out of range + ERANGE = OutOfRange, + /// Operation would incur in a deadlock + EDEADLK = DeadlockWouldOccur, + /// Name is too long + ENAMETOOLONG = NameTooLong, + /// There are no available locks + ENOLCK = NoLocksAvailable, + /// Not implemented + ENOSYS = NotImplemented, + /// Link is severed + ENOLINK = SeveredLink, + /// Not supported + ENOTSUP = NotSupported, + /// Directory is not empty + DirectoryNotEmpty = -39, + /// Too many symbolic links encountered + TooManySymbolicLinks = -40, + /// Directory is not empty + ENOTEMPTY = DirectoryNotEmpty, + /// Too many symbolic links encountered + ELOOP = TooManySymbolicLinks, + /// There is no such attribute + ENOATTR = NoSuchExtendedAttribute, + /// There is no data available + ENODATA = NoData, + /// No error + NoError = 0, + /// User requested help to be shown + HelpRequested = 1, + /// Command found nothing + NothingFound = 2, + /// Media has been already dumped completely + AlreadyDumped = 3, + /// Image and its sectors cannot be verified + NotVerifiable = 4, + /// There are bad sectors and image cannot be verified + BadSectorsImageNotVerified = 5, + /// All sectors are good and image cannot be verified + CorrectSectorsImageNotVerified = 6, + /// Image is bad and sectors cannot be verified + BadImageSectorsNotVerified = 7, + /// Image is bad and there are bad sectors + BadImageBadSectors = 8, + /// All sectors are good and image is bad + CorrectSectorsBadImage = 9, + /// Image is good and sectors cannot be verified + CorrectImageSectorsNotVerified = 10, + /// Image is good and there are bad sectors + CorrectImageBadSectors = 11, + /// Exception has been raised + UnexpectedException = 12, + /// The number of arguments is not as expected + UnexpectedArgumentCount = 13, + /// A required argument is not present + MissingArgument = 14, + /// The specified file cannot be opened + CannotOpenFile = 15, + /// The specified encoding cannot be found + EncodingUnknown = 16, + /// The image format has not been recognized + UnrecognizedFormat = 17, + /// The image format failed to open + CannotOpenFormat = 18, + /// The specified metadata sidecar does not have the correct format + InvalidSidecar = 19, + /// The specified resume map does not have the correct format + InvalidResume = 20, + /// The specified image format cannot be found + FormatNotFound = 21, + /// More than one format found for the specified search criteria + TooManyFormats = 22, + /// The specified format does not support the specified media + UnsupportedMedia = 23, + /// Data will be lost writing the specified format + DataWillBeLost = 24, + /// Cannot create destination format + CannotCreateFormat = 25, + /// Error writing data + WriteError = 26, + /// Cannot open device + CannotOpenDevice = 27, + /// Cannot remove the existing database + CannotRemoveDatabase = 28, + /// Specified sector could not be found + SectorNotFound = 29, + /// Image or device has not been opened + NotOpened = 30 +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Enums/Images.cs b/Aaru.CommonTypes/Enums/Images.cs new file mode 100644 index 000000000..bc1c56c7c --- /dev/null +++ b/Aaru.CommonTypes/Enums/Images.cs @@ -0,0 +1,436 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Images.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines enumerations to be used by disc image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright © 2020-2024 Rebecca Wallander +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.CommonTypes.Enums; + +/// Track (as partitioning element) types. +public enum TrackType : byte +{ + /// Audio track + Audio = 0, + /// Data track (not any of the below defined ones) + Data = 1, + /// Data track, compact disc mode 1 + CdMode1 = 2, + /// Data track, compact disc mode 2, formless + CdMode2Formless = 3, + /// Data track, compact disc mode 2, form 1 + CdMode2Form1 = 4, + /// Data track, compact disc mode 2, form 2 + CdMode2Form2 = 5 +} + +/// Type of subchannel in track +public enum TrackSubchannelType : byte +{ + /// Track does not has subchannel dumped, or it's not a CD + None = 0, + /// Subchannel is packed and error corrected + Packed = 1, + /// Subchannel is interleaved + Raw = 2, + /// Subchannel is packed and comes interleaved with main channel in same file + PackedInterleaved = 3, + /// Subchannel is interleaved and comes interleaved with main channel in same file + RawInterleaved = 4, + /// Only Q subchannel is stored as 16 bytes + Q16 = 5, + /// Only Q subchannel is stored as 16 bytes and comes interleaved with main channel in same file + Q16Interleaved = 6 +} + +/// Metadata present for each sector (aka, "tag"). +public enum SectorTagType +{ + /// Apple's GCR sector tags, 12 bytes + AppleSectorTag = 0, + /// Sync frame from CD sector, 12 bytes + CdSectorSync = 1, + /// CD sector header, 4 bytes + CdSectorHeader = 2, + /// CD mode 2 sector subheader + CdSectorSubHeader = 3, + /// CD sector EDC, 4 bytes + CdSectorEdc = 4, + /// CD sector ECC P, 172 bytes + CdSectorEccP = 5, + /// CD sector ECC Q, 104 bytes + CdSectorEccQ = 6, + /// CD sector ECC (P and Q), 276 bytes + CdSectorEcc = 7, + /// CD sector subchannel, 96 bytes + CdSectorSubchannel = 8, + /// CD track ISRC, string, 12 bytes + CdTrackIsrc = 9, + /// CD track text, string, 13 bytes + CdTrackText = 10, + /// CD track flags, 1 byte + CdTrackFlags = 11, + /// DVD sector copyright information + DvdSectorCmi = 12, + /// Floppy address mark (contents depend on underlying floppy format) + FloppyAddressMark = 13, + /// DVD sector title key, 5 bytes + DvdSectorTitleKey = 14, + /// Decrypted DVD sector title key, 5 bytes + DvdTitleKeyDecrypted = 15, + /// DVD sector information, 1 bytes + DvdSectorInformation = 16, + /// DVD sector number, 3 bytes + DvdSectorNumber = 17, + /// DVD sector ID error detection, 2 bytes + DvdSectorIed = 18, + /// DVD sector EDC, 4 bytes + DvdSectorEdc = 19 +} + +/// Metadata present for each media. +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum MediaTagType +{ + /// CD table of contents + CD_TOC = 0, + /// CD session information + CD_SessionInfo = 1, + /// CD full table of contents + CD_FullTOC = 2, + /// CD PMA + CD_PMA = 3, + /// CD Address-Time-In-Pregroove + CD_ATIP = 4, + /// CD-Text + CD_TEXT = 5, + /// CD Media Catalogue Number + CD_MCN = 6, + /// DVD/HD DVD Physical Format Information + DVD_PFI = 7, + /// DVD Lead-in Copyright Management Information + DVD_CMI = 8, + /// DVD disc key + DVD_DiscKey = 9, + /// DVD/HD DVD Burst Cutting Area + DVD_BCA = 10, + /// DVD/HD DVD Lead-in Disc Manufacturer Information + DVD_DMI = 11, + /// Media identifier + DVD_MediaIdentifier = 12, + /// Media key block + DVD_MKB = 13, + /// DVD-RAM/HD DVD-RAM DDS information + DVDRAM_DDS = 14, + /// DVD-RAM/HD DVD-RAM Medium status + DVDRAM_MediumStatus = 15, + /// DVD-RAM/HD DVD-RAM Spare area information + DVDRAM_SpareArea = 16, + /// DVD-R/-RW/HD DVD-R RMD in last border-out + DVDR_RMD = 17, + /// Pre-recorded information from DVD-R/-RW lead-in + DVDR_PreRecordedInfo = 18, + /// DVD-R/-RW/HD DVD-R media identifier + DVDR_MediaIdentifier = 19, + /// DVD-R/-RW/HD DVD-R physical format information + DVDR_PFI = 20, + /// ADIP information + DVD_ADIP = 21, + /// HD DVD Lead-in copyright protection information + HDDVD_CPI = 22, + /// HD DVD-R Medium Status + HDDVD_MediumStatus = 23, + /// DVD+/-R DL Layer capacity + DVDDL_LayerCapacity = 24, + /// DVD-R DL Middle Zone start address + DVDDL_MiddleZoneAddress = 25, + /// DVD-R DL Jump Interval Size + DVDDL_JumpIntervalSize = 26, + /// DVD-R DL Start LBA of the manual layer jump + DVDDL_ManualLayerJumpLBA = 27, + /// Blu-ray Disc Information + BD_DI = 28, + /// Blu-ray Burst Cutting Area + BD_BCA = 29, + /// Blu-ray Disc Definition Structure + BD_DDS = 30, + /// Blu-ray Cartridge Status + BD_CartridgeStatus = 31, + /// Blu-ray Status of Spare Area + BD_SpareArea = 32, + /// AACS volume identifier + AACS_VolumeIdentifier = 33, + /// AACS pre-recorded media serial number + AACS_SerialNumber = 34, + /// AACS media identifier + AACS_MediaIdentifier = 35, + /// Lead-in AACS media key block + AACS_MKB = 36, + /// AACS data keys + AACS_DataKeys = 37, + /// LBA extents flagged for bus encryption by AACS + AACS_LBAExtents = 38, + /// CPRM media key block in Lead-in + AACS_CPRM_MKB = 39, + /// Recognized layer formats in hybrid discs + Hybrid_RecognizedLayers = 40, + /// Disc write protection status + MMC_WriteProtection = 41, + /// Disc standard information + MMC_DiscInformation = 42, + /// Disc track resources information + MMC_TrackResourcesInformation = 43, + /// BD-R Pseudo-overwrite information + MMC_POWResourcesInformation = 44, + /// SCSI INQUIRY response + SCSI_INQUIRY = 45, + /// SCSI MODE PAGE 2Ah + SCSI_MODEPAGE_2A = 46, + /// ATA IDENTIFY DEVICE response + ATA_IDENTIFY = 47, + /// ATA IDENTIFY PACKET DEVICE response + ATAPI_IDENTIFY = 48, + /// PCMCIA/CardBus Card Information Structure + PCMCIA_CIS = 49, + /// SecureDigital CID + SD_CID = 50, + /// SecureDigital CSD + SD_CSD = 51, + /// SecureDigital SCR + SD_SCR = 52, + /// SecureDigital OCR + SD_OCR = 53, + /// MultiMediaCard CID + MMC_CID = 54, + /// MultiMediaCard CSD + MMC_CSD = 55, + /// MultiMediaCard OCR + MMC_OCR = 56, + /// MultiMediaCard Extended CSD + MMC_ExtendedCSD = 57, + /// Xbox Security Sector + Xbox_SecuritySector = 58, + /// + /// On floppy disks, data in last cylinder usually in a different format that contains duplication or + /// manufacturing information + /// + Floppy_LeadOut = 59, + /// DVD Disc Control Blocks + DCB = 60, + /// Compact Disc First Track Pregap + CD_FirstTrackPregap = 61, + /// Compact Disc Lead-out + CD_LeadOut = 62, + /// SCSI MODE SENSE (6) + SCSI_MODESENSE_6 = 63, + /// SCSI MODE SENSE (10) + SCSI_MODESENSE_10 = 64, + /// USB descriptors + USB_Descriptors = 65, + /// XGD unlocked DMI + Xbox_DMI = 66, + /// XDG unlocked PFI + Xbox_PFI = 67, + /// Compact Disc Lead-in + CD_LeadIn = 68, + /// 8 bytes response that seems to define type of MiniDisc + MiniDiscType = 69, + /// 4 bytes response to vendor command D5h + MiniDiscD5 = 70, + /// User TOC, contains fragments, track names, and can be from 1 to 3 sectors of 2336 bytes + MiniDiscUTOC = 71, + /// Not entirely clear kind of TOC that only appears on MD-DATA discs + MiniDiscDTOC = 72, + /// Decrypted DVD disc key + DVD_DiscKey_Decrypted = 73 +} + +/// Enumeration of media types defined in metadata +public enum MetadataMediaType : byte +{ + /// Purely optical discs + OpticalDisc = 0, + /// Media that is physically block-based or abstracted like that + BlockMedia = 1, + /// Media that can be accessed by-byte or by-bit, like chips + LinearMedia = 2, + /// Media that can only store data when it is modulated to audio + AudioMedia = 3 +} + +/// CD flags bitmask +[Flags] +public enum CdFlags : byte +{ + /// Track is quadraphonic. + FourChannel = 0x08, + /// Track is non-audio (data). + DataTrack = 0x04, + /// Track is copy protected. + CopyPermitted = 0x02, + /// Track has pre-emphasis. + PreEmphasis = 0x01 +} + +/// Status of a requested floppy sector +[Flags] +public enum FloppySectorStatus : byte +{ + /// Both address mark and data checksums are correct. + Correct = 0x01, + /// Data checksum is incorrect. + DataError = 0x02, + /// Address mark checksum is incorrect. + AddressMarkError = 0x04, + /// There is another sector in the same track/head with same sector id. + Duplicated = 0x08, + /// Sector data section is not magnetized. + Demagnetized = 0x10, + /// Sector data section has a physically visible hole. + Hole = 0x20, + /// There is no address mark containing the requested sector id in the track/head. + NotFound = 0x40 +} + +/// Types of floppy disks +public enum FloppyTypes : byte +{ + /// 8" floppy + Floppy, + /// 5.25" floppy + MiniFloppy, + /// 3.5" floppy + MicroFloppy, + /// 3" floppy + CompactFloppy, + /// 5.25" twiggy + FileWare, + /// 2.5" quickdisk + QuickDisk +} + +/// Enumeration of floppy densities +public enum FloppyDensities : byte +{ + /// Standard coercivity (about 300Oe as found in 8" and 5.25"-double-density disks). + Standard, + /// Double density coercivity (about 600Oe as found in 5.25" HD and 3.5" DD disks). + Double, + /// High density coercivity (about 700Oe as found in 3.5" HD disks). + High, + /// Extended density coercivity (about 750Oe as found in 3.5" ED disks). + Extended +} + +/// Capabilities for optical media image formats +[Flags] +public enum OpticalImageCapabilities : ulong +{ + /// Can store Red Book audio tracks? + CanStoreAudioTracks = 0x01, + /// Can store CD-V analogue video tracks? + CanStoreVideoTracks = 0x02, + /// Can store Yellow Book data tracks? + CanStoreDataTracks = 0x03, + /// Can store pregaps without needing to interpret the subchannel? + CanStorePregaps = 0x04, + /// Can store indexes without needing to interpret the subchannel? + CanStoreIndexes = 0x08, + /// Can store raw P to W subchannel data? + CanStoreSubchannelRw = 0x10, + /// Can store more than one session? + CanStoreSessions = 0x20, + /// Can store track ISRCs without needing to interpret the subchannel? + CanStoreIsrc = 0x40, + /// Can store Lead-In's CD-TEXT? + CanStoreCdText = 0x80, + /// Can store the MCN without needing to interpret the subchannel? + CanStoreMcn = 0x100, + /// Can store the whole 2352 bytes of a sector? + CanStoreRawData = 0x200, + /// Can store more than 1 session in media that is not CD based (DVD et al)? + CanStoreNotCdSessions = 0x2000, + /// Can store more than 1 track in media that is not CD based (DVD et al)? + CanStoreNotCdTracks = 0x4000, + /// Can store hidden tracks with a type different from track 1? + CanStoreHiddenTracks = 0x8000, + + // TODO: Implement + /// Can store scrambled data? + CanStoreScrambledData = 0x400, + /// Can store only the user area of a sector (2048, 2324, etc)? + CanStoreCookedData = 0x800, + /// Can store more than 1 track? + CanStoreMultipleTracks = 0x1000 +} + +/// Enumeration of linear memory device types +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum LinearMemoryType +{ + /// Unknown device type + Unknown = 0, + /// Read-only memory + ROM = 1, + /// Read-write memory, power-off persistent, used to save data + SaveRAM = 2, + /// Read-write volatile memory + WorkRAM = 3, + /// NOR flash memory + NOR = 4, + /// NAND flash memory + NAND = 5, + /// Memory mapper device + Mapper = 6, + /// Processor, CPU, DSP, etc + Processor = 7, + /// Programmable Array Logic + PAL = 8, + /// Generic Array Logic + GAL = 9, + /// Electronically Erasable Programmable Read Only Memory + EEPROM = 10, + /// Read-only memory, character + CharacterROM = 11, + /// Read-write volatile memory for character + CharacterRAM = 12, + /// Trainer, or hack + Trainer = 13 +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Enums/Nes.cs b/Aaru.CommonTypes/Enums/Nes.cs new file mode 100644 index 000000000..1f602b089 --- /dev/null +++ b/Aaru.CommonTypes/Enums/Nes.cs @@ -0,0 +1,127 @@ +// ReSharper disable InconsistentNaming + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.CommonTypes.Enums; + +public enum NesConsoleType : byte +{ + Nes = 0, + Vs = 1, + Playchoice = 2, + Extended = 3 +} + +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum NesTimingMode : byte +{ + RP2C02 = 0, + RP2C07 = 1, + Multiple = 2, + UMC6527P = 3 +} + +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum NesVsPpuType : byte +{ + RP2C03B = 0, + RP2C03G = 1, + RP2C04_0001 = 2, + RP2C04_0002 = 3, + RP2C04_0003 = 4, + RP2C04_0004 = 5, + RC2C03B = 6, + RC2C03C = 7, + RC2C05_01 = 8, + RC2C05_02 = 9, + RC2C05_03 = 10, + RC2C05_04 = 11, + RC2C05_05 = 12 +} + +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum NesVsHardwareType : byte +{ + Normal = 0, + RBI = 1, + TKO = 2, + SuperXevious = 3, + IceClimber = 4, + Dual = 5, + RaidOnBungeling = 6 +} + +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum NesExtendedConsoleType : byte +{ + Normal = 0, + Vs = 1, + Playchoice = 2, + DecimalMode = 3, + VT01_Monochrome = 4, + VT01 = 5, + VT02 = 6, + VT03 = 7, + VT09 = 8, + VT32 = 9, + VT369 = 10, + UM6578 = 11 +} + +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum NesDefaultExpansionDevice : byte +{ + Unspecified = 0, + Controller = 1, + FourScore = 2, + FourPlayersAdapter = 3, + Vs = 4, + VsSystem = 5, + VsPinball = 6, + VsZapper = 7, + Zapper = 8, + TwoZappers = 9, + HyperShotLightgun = 0xA, + PowerPadSideA = 0xB, + PowerPadSideB = 0xC, + FamilyTrainerSideA = 0xD, + FamilyTrainerSideB = 0xE, + ArkanoidVaus = 0xF, + ArkanoidVausFamicom = 0x10, + TwoVausDataRecorder = 0x11, + HyperShotController = 0x12, + CoconutsPachinko = 0x13, + ExcitingBoxing = 0x14, + JissenMahjong = 0x15, + PartyTap = 0x16, + OekaKidsTablet = 0x17, + SunsoftBarcodeBattler = 0x18, + PianoKeyboard = 0x19, + PokkunMoguraa = 0x1A, + TopRider = 0x1B, + DoubleFisted = 0x1C, + Famicom3DSystem = 0x1D, + DoremikkoKeyboard = 0x1E, + GyroSet = 0x1F, + DataRecorder = 0x20, + TurboFile = 0x21, + StorageBattleBox = 0x22, + FamilyBASICKeyboardDataRecorder = 0x23, + DongdaKeyboard = 0x24, + BitCorpKeyboard = 0x25, + SuborKeyboard = 0x26, + SuborKeyboardMouse = 0x27, + SuborKeyboardMouse24 = 0x28, + SNESMouse = 0x29, + Multicart = 0x2A, + SNESControllers = 0x2B, + RacerMateBicycle = 0x2C, + UForce = 0x2D, + StackUp = 0x2E, + PatrolmanLightgun = 0x2F, + C1CassetteInterface = 0x30, + SwappedController = 0x31, + SudokuPad = 0x32, + ABLPinball = 0x33, + GoldenNuggetCasino = 0x34 +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Extents/ExtentsByte.cs b/Aaru.CommonTypes/Extents/ExtentsByte.cs new file mode 100644 index 000000000..e706e6c31 --- /dev/null +++ b/Aaru.CommonTypes/Extents/ExtentsByte.cs @@ -0,0 +1,242 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ExtentsByte.cs +// Author(s) : Natalia Portillo +// +// Component : Extent helpers. +// +// --[ Description ] ---------------------------------------------------------- +// +// Provides extents for byte types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Aaru.CommonTypes.Extents; + +/// Implements extents for +[SuppressMessage("ReSharper", "UnusedType.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public sealed class ExtentsByte +{ + List> _backend; + + /// Initialize an empty list of extents + public ExtentsByte() => _backend = []; + + /// Initializes extents with an specific list + /// List of extents as tuples "start, end" + public ExtentsByte(IEnumerable> list) + { + _backend = []; + + // This ensure no overlapping extents are added on creation + foreach(Tuple t in list) Add(t.Item1, t.Item2); + } + + /// Gets a count of how many extents are stored + public int Count => _backend.Count; + + /// Adds the specified number to the corresponding extent, or creates a new one + /// + public void Add(byte item) + { + Tuple removeOne = null; + Tuple removeTwo = null; + Tuple itemToAdd = null; + + for(var i = 0; i < _backend.Count; i++) + { + // Already contained in an extent + if(item >= _backend[i].Item1 && item <= _backend[i].Item2) return; + + // Expands existing extent start + if(item == _backend[i].Item1 - 1) + { + removeOne = _backend[i]; + + if(i > 0 && item == _backend[i - 1].Item2 + 1) + { + removeTwo = _backend[i - 1]; + itemToAdd = new Tuple(_backend[i - 1].Item1, _backend[i].Item2); + } + else + itemToAdd = new Tuple(item, _backend[i].Item2); + + break; + } + + // Expands existing extent end + if(item != _backend[i].Item2 + 1) continue; + + removeOne = _backend[i]; + + if(i < _backend.Count - 1 && item == _backend[i + 1].Item1 - 1) + { + removeTwo = _backend[i + 1]; + itemToAdd = new Tuple(_backend[i].Item1, _backend[i + 1].Item2); + } + else + itemToAdd = new Tuple(_backend[i].Item1, item); + + break; + } + + if(itemToAdd != null) + { + _backend.Remove(removeOne); + _backend.Remove(removeTwo); + _backend.Add(itemToAdd); + } + else + _backend.Add(new Tuple(item, item)); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + } + + /// Adds a new extent + /// First element of the extent + /// + /// Last element of the extent or if is true how many elements the extent runs + /// for + /// + /// If set to true, indicates how many elements the extent runs for + public void Add(byte start, byte end, bool run = false) + { + byte realEnd; + + if(run) + realEnd = (byte)(start + end - 1); + else + realEnd = end; + + // TODO: Optimize this + for(byte t = start; t <= realEnd; t++) Add(t); + } + + /// Checks if the specified item is contained by an extent on this instance + /// Item to search for + /// true if any of the extents on this instance contains the item + public bool Contains(byte item) => _backend.Any(extent => item >= extent.Item1 && item <= extent.Item2); + + /// Removes all extents from this instance + public void Clear() => _backend.Clear(); + + /// Removes an item from the extents in this instance + /// Item to remove + /// true if the item was contained in a known extent and removed, false otherwise + public bool Remove(byte item) + { + Tuple toRemove = null; + Tuple toAddOne = null; + Tuple toAddTwo = null; + + foreach(Tuple extent in _backend) + { + // Extent is contained and not a border + if(item > extent.Item1 && item < extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, (byte)(item - 1)); + toAddTwo = new Tuple((byte)(item + 1), extent.Item2); + + break; + } + + // Extent is left border, but not only element + if(item == extent.Item1 && item != extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple((byte)(item + 1), extent.Item2); + + break; + } + + // Extent is right border, but not only element + if(item != extent.Item1 && item == extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, (byte)(item - 1)); + + break; + } + + // Extent is only element + if(item != extent.Item1 || item != extent.Item2) continue; + + toRemove = extent; + + break; + } + + // Item not found + if(toRemove == null) return false; + + _backend.Remove(toRemove); + + if(toAddOne != null) _backend.Add(toAddOne); + + if(toAddTwo != null) _backend.Add(toAddTwo); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + + return true; + } + + /// + /// Converts the list of extents to an array of where T1 is first element of the extent and + /// T2 is last element + /// + /// Array of + public Tuple[] ToArray() => _backend.ToArray(); + + /// Gets the first element of the extent that contains the specified item + /// Item + /// First element of extent + /// true if item was found in an extent, false otherwise + public bool GetStart(byte item, out byte start) + { + start = 0; + + foreach(Tuple extent in _backend.Where(extent => item >= extent.Item1 && item <= extent.Item2)) + { + start = extent.Item1; + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Extents/ExtentsConverter.cs b/Aaru.CommonTypes/Extents/ExtentsConverter.cs new file mode 100644 index 000000000..8726780b2 --- /dev/null +++ b/Aaru.CommonTypes/Extents/ExtentsConverter.cs @@ -0,0 +1,82 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ExtentsConverter.cs +// Author(s) : Natalia Portillo +// +// Component : XML metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Converts extents to/from XML. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using Aaru.CommonTypes.AaruMetadata; + +namespace Aaru.CommonTypes.Extents; + +/// Converts extents +public static class ExtentsConverter +{ + /// Converts unsigned long integer extents into XML based extents + /// Extents + /// XML based extents + public static List ToMetadata(ExtentsULong extents) + { + if(extents == null) return null; + + Tuple[] tuples = extents.ToArray(); + List list = []; + + for(ulong i = 0; i < (ulong)tuples.LongLength; i++) + { + list.Add(new Extent + { + Start = tuples[i].Item1, + End = tuples[i].Item2 + }); + } + + return list; + } + + /// Converts XML based extents into unsigned long integer extents + /// XML based extents + /// Extents + public static ExtentsULong FromMetadata(IEnumerable extents) + { + if(extents == null) return null; + + var tuples = extents.Select(extent => new Tuple(extent.Start, extent.End)).ToList(); + + return new ExtentsULong(tuples); + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Extents/ExtentsInt.cs b/Aaru.CommonTypes/Extents/ExtentsInt.cs new file mode 100644 index 000000000..644008b93 --- /dev/null +++ b/Aaru.CommonTypes/Extents/ExtentsInt.cs @@ -0,0 +1,242 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ExtentsInt.cs +// Author(s) : Natalia Portillo +// +// Component : Extent helpers. +// +// --[ Description ] ---------------------------------------------------------- +// +// Provides extents for int types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Aaru.CommonTypes.Extents; + +/// Implements extents for +[SuppressMessage("ReSharper", "UnusedType.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public sealed class ExtentsInt +{ + List> _backend; + + /// Initialize an empty list of extents + public ExtentsInt() => _backend = []; + + /// Initializes extents with an specific list + /// List of extents as tuples "start, end" + public ExtentsInt(IEnumerable> list) + { + _backend = []; + + // This ensure no overlapping extents are added on creation + foreach(Tuple t in list) Add(t.Item1, t.Item2); + } + + /// Gets a count of how many extents are stored + public int Count => _backend.Count; + + /// Adds the specified number to the corresponding extent, or creates a new one + /// + public void Add(int item) + { + Tuple removeOne = null; + Tuple removeTwo = null; + Tuple itemToAdd = null; + + for(var i = 0; i < _backend.Count; i++) + { + // Already contained in an extent + if(item >= _backend[i].Item1 && item <= _backend[i].Item2) return; + + // Expands existing extent start + if(item == _backend[i].Item1 - 1) + { + removeOne = _backend[i]; + + if(i > 0 && item == _backend[i - 1].Item2 + 1) + { + removeTwo = _backend[i - 1]; + itemToAdd = new Tuple(_backend[i - 1].Item1, _backend[i].Item2); + } + else + itemToAdd = new Tuple(item, _backend[i].Item2); + + break; + } + + // Expands existing extent end + if(item != _backend[i].Item2 + 1) continue; + + removeOne = _backend[i]; + + if(i < _backend.Count - 1 && item == _backend[i + 1].Item1 - 1) + { + removeTwo = _backend[i + 1]; + itemToAdd = new Tuple(_backend[i].Item1, _backend[i + 1].Item2); + } + else + itemToAdd = new Tuple(_backend[i].Item1, item); + + break; + } + + if(itemToAdd != null) + { + _backend.Remove(removeOne); + _backend.Remove(removeTwo); + _backend.Add(itemToAdd); + } + else + _backend.Add(new Tuple(item, item)); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + } + + /// Adds a new extent + /// First element of the extent + /// + /// Last element of the extent or if is true how many elements the extent runs + /// for + /// + /// If set to true, indicates how many elements the extent runs for + public void Add(int start, int end, bool run = false) + { + int realEnd; + + if(run) + realEnd = start + end - 1; + else + realEnd = end; + + // TODO: Optimize this + for(int t = start; t <= realEnd; t++) Add(t); + } + + /// Checks if the specified item is contained by an extent on this instance + /// Item to search for + /// true if any of the extents on this instance contains the item + public bool Contains(int item) => _backend.Any(extent => item >= extent.Item1 && item <= extent.Item2); + + /// Removes all extents from this instance + public void Clear() => _backend.Clear(); + + /// Removes an item from the extents in this instance + /// Item to remove + /// true if the item was contained in a known extent and removed, false otherwise + public bool Remove(int item) + { + Tuple toRemove = null; + Tuple toAddOne = null; + Tuple toAddTwo = null; + + foreach(Tuple extent in _backend) + { + // Extent is contained and not a border + if(item > extent.Item1 && item < extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, item - 1); + toAddTwo = new Tuple(item + 1, extent.Item2); + + break; + } + + // Extent is left border, but not only element + if(item == extent.Item1 && item != extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(item + 1, extent.Item2); + + break; + } + + // Extent is right border, but not only element + if(item != extent.Item1 && item == extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, item - 1); + + break; + } + + // Extent is only element + if(item != extent.Item1 || item != extent.Item2) continue; + + toRemove = extent; + + break; + } + + // Item not found + if(toRemove == null) return false; + + _backend.Remove(toRemove); + + if(toAddOne != null) _backend.Add(toAddOne); + + if(toAddTwo != null) _backend.Add(toAddTwo); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + + return true; + } + + /// + /// Converts the list of extents to an array of where T1 is first element of the extent and + /// T2 is last element + /// + /// Array of + public Tuple[] ToArray() => _backend.ToArray(); + + /// Gets the first element of the extent that contains the specified item + /// Item + /// First element of extent + /// true if item was found in an extent, false otherwise + public bool GetStart(int item, out int start) + { + start = 0; + + foreach(Tuple extent in _backend.Where(extent => item >= extent.Item1 && item <= extent.Item2)) + { + start = extent.Item1; + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Extents/ExtentsLong.cs b/Aaru.CommonTypes/Extents/ExtentsLong.cs new file mode 100644 index 000000000..5da734f46 --- /dev/null +++ b/Aaru.CommonTypes/Extents/ExtentsLong.cs @@ -0,0 +1,241 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ExtentsLong.cs +// Author(s) : Natalia Portillo +// +// Component : Extent helpers. +// +// --[ Description ] ---------------------------------------------------------- +// +// Provides extents for long types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Aaru.CommonTypes.Extents; + +/// Implements extents for +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public sealed class ExtentsLong +{ + List> _backend; + + /// Initialize an empty list of extents + public ExtentsLong() => _backend = []; + + /// Initializes extents with an specific list + /// List of extents as tuples "start, end" + public ExtentsLong(IEnumerable> list) + { + _backend = []; + + // This ensure no overlapping extents are added on creation + foreach(Tuple t in list) Add(t.Item1, t.Item2); + } + + /// Gets a count of how many extents are stored + public int Count => _backend.Count; + + /// Adds the specified number to the corresponding extent, or creates a new one + /// + public void Add(long item) + { + Tuple removeOne = null; + Tuple removeTwo = null; + Tuple itemToAdd = null; + + for(var i = 0; i < _backend.Count; i++) + { + // Already contained in an extent + if(item >= _backend[i].Item1 && item <= _backend[i].Item2) return; + + // Expands existing extent start + if(item == _backend[i].Item1 - 1) + { + removeOne = _backend[i]; + + if(i > 0 && item == _backend[i - 1].Item2 + 1) + { + removeTwo = _backend[i - 1]; + itemToAdd = new Tuple(_backend[i - 1].Item1, _backend[i].Item2); + } + else + itemToAdd = new Tuple(item, _backend[i].Item2); + + break; + } + + // Expands existing extent end + if(item != _backend[i].Item2 + 1) continue; + + removeOne = _backend[i]; + + if(i < _backend.Count - 1 && item == _backend[i + 1].Item1 - 1) + { + removeTwo = _backend[i + 1]; + itemToAdd = new Tuple(_backend[i].Item1, _backend[i + 1].Item2); + } + else + itemToAdd = new Tuple(_backend[i].Item1, item); + + break; + } + + if(itemToAdd != null) + { + _backend.Remove(removeOne); + _backend.Remove(removeTwo); + _backend.Add(itemToAdd); + } + else + _backend.Add(new Tuple(item, item)); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + } + + /// Adds a new extent + /// First element of the extent + /// + /// Last element of the extent or if is true how many elements the extent runs + /// for + /// + /// If set to true, indicates how many elements the extent runs for + public void Add(long start, long end, bool run = false) + { + long realEnd; + + if(run) + realEnd = start + end - 1; + else + realEnd = end; + + // TODO: Optimize this + for(long t = start; t <= realEnd; t++) Add(t); + } + + /// Checks if the specified item is contained by an extent on this instance + /// Item to search for + /// true if any of the extents on this instance contains the item + public bool Contains(long item) => _backend.Any(extent => item >= extent.Item1 && item <= extent.Item2); + + /// Removes all extents from this instance + public void Clear() => _backend.Clear(); + + /// Removes an item from the extents in this instance + /// Item to remove + /// true if the item was contained in a known extent and removed, false otherwise + public bool Remove(long item) + { + Tuple toRemove = null; + Tuple toAddOne = null; + Tuple toAddTwo = null; + + foreach(Tuple extent in _backend) + { + // Extent is contained and not a border + if(item > extent.Item1 && item < extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, item - 1); + toAddTwo = new Tuple(item + 1, extent.Item2); + + break; + } + + // Extent is left border, but not only element + if(item == extent.Item1 && item != extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(item + 1, extent.Item2); + + break; + } + + // Extent is right border, but not only element + if(item != extent.Item1 && item == extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, item - 1); + + break; + } + + // Extent is only element + if(item != extent.Item1 || item != extent.Item2) continue; + + toRemove = extent; + + break; + } + + // Item not found + if(toRemove == null) return false; + + _backend.Remove(toRemove); + + if(toAddOne != null) _backend.Add(toAddOne); + + if(toAddTwo != null) _backend.Add(toAddTwo); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + + return true; + } + + /// + /// Converts the list of extents to an array of where T1 is first element of the extent and + /// T2 is last element + /// + /// Array of + public Tuple[] ToArray() => _backend.ToArray(); + + /// Gets the first element of the extent that contains the specified item + /// Item + /// First element of extent + /// true if item was found in an extent, false otherwise + public bool GetStart(long item, out long start) + { + start = 0; + + foreach(Tuple extent in _backend.Where(extent => item >= extent.Item1 && item <= extent.Item2)) + { + start = extent.Item1; + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Extents/ExtentsSByte.cs b/Aaru.CommonTypes/Extents/ExtentsSByte.cs new file mode 100644 index 000000000..5e24dc70c --- /dev/null +++ b/Aaru.CommonTypes/Extents/ExtentsSByte.cs @@ -0,0 +1,242 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ExtentsSByte.cs +// Author(s) : Natalia Portillo +// +// Component : Extent helpers. +// +// --[ Description ] ---------------------------------------------------------- +// +// Provides extents for sbyte types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Aaru.CommonTypes.Extents; + +/// Implements extents for +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public sealed class ExtentsSByte +{ + List> _backend; + + /// Initialize an empty list of extents + public ExtentsSByte() => _backend = []; + + /// Initializes extents with an specific list + /// List of extents as tuples "start, end" + public ExtentsSByte(IEnumerable> list) + { + _backend = []; + + // This ensure no overlapping extents are added on creation + foreach(Tuple t in list) Add(t.Item1, t.Item2); + } + + /// Gets a count of how many extents are stored + public int Count => _backend.Count; + + /// Adds the specified number to the corresponding extent, or creates a new one + /// + public void Add(sbyte item) + { + Tuple removeOne = null; + Tuple removeTwo = null; + Tuple itemToAdd = null; + + for(var i = 0; i < _backend.Count; i++) + { + // Already contained in an extent + if(item >= _backend[i].Item1 && item <= _backend[i].Item2) return; + + // Expands existing extent start + if(item == _backend[i].Item1 - 1) + { + removeOne = _backend[i]; + + if(i > 0 && item == _backend[i - 1].Item2 + 1) + { + removeTwo = _backend[i - 1]; + itemToAdd = new Tuple(_backend[i - 1].Item1, _backend[i].Item2); + } + else + itemToAdd = new Tuple(item, _backend[i].Item2); + + break; + } + + // Expands existing extent end + if(item != _backend[i].Item2 + 1) continue; + + removeOne = _backend[i]; + + if(i < _backend.Count - 1 && item == _backend[i + 1].Item1 - 1) + { + removeTwo = _backend[i + 1]; + itemToAdd = new Tuple(_backend[i].Item1, _backend[i + 1].Item2); + } + else + itemToAdd = new Tuple(_backend[i].Item1, item); + + break; + } + + if(itemToAdd != null) + { + _backend.Remove(removeOne); + _backend.Remove(removeTwo); + _backend.Add(itemToAdd); + } + else + _backend.Add(new Tuple(item, item)); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + } + + /// Adds a new extent + /// First element of the extent + /// + /// Last element of the extent or if is true how many elements the extent runs + /// for + /// + /// If set to true, indicates how many elements the extent runs for + public void Add(sbyte start, sbyte end, bool run = false) + { + sbyte realEnd; + + if(run) + realEnd = (sbyte)(start + end - 1); + else + realEnd = end; + + // TODO: Optimize this + for(sbyte t = start; t <= realEnd; t++) Add(t); + } + + /// Checks if the specified item is contained by an extent on this instance + /// Item to search for + /// true if any of the extents on this instance contains the item + public bool Contains(sbyte item) => _backend.Any(extent => item >= extent.Item1 && item <= extent.Item2); + + /// Removes all extents from this instance + public void Clear() => _backend.Clear(); + + /// Removes an item from the extents in this instance + /// Item to remove + /// true if the item was contained in a known extent and removed, false otherwise + public bool Remove(sbyte item) + { + Tuple toRemove = null; + Tuple toAddOne = null; + Tuple toAddTwo = null; + + foreach(Tuple extent in _backend) + { + // Extent is contained and not a border + if(item > extent.Item1 && item < extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, (sbyte)(item - 1)); + toAddTwo = new Tuple((sbyte)(item + 1), extent.Item2); + + break; + } + + // Extent is left border, but not only element + if(item == extent.Item1 && item != extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple((sbyte)(item + 1), extent.Item2); + + break; + } + + // Extent is right border, but not only element + if(item != extent.Item1 && item == extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, (sbyte)(item - 1)); + + break; + } + + // Extent is only element + if(item != extent.Item1 || item != extent.Item2) continue; + + toRemove = extent; + + break; + } + + // Item not found + if(toRemove == null) return false; + + _backend.Remove(toRemove); + + if(toAddOne != null) _backend.Add(toAddOne); + + if(toAddTwo != null) _backend.Add(toAddTwo); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + + return true; + } + + /// + /// Converts the list of extents to an array of where T1 is first element of the extent and + /// T2 is last element + /// + /// Array of + public Tuple[] ToArray() => _backend.ToArray(); + + /// Gets the first element of the extent that contains the specified item + /// Item + /// First element of extent + /// true if item was found in an extent, false otherwise + public bool GetStart(sbyte item, out sbyte start) + { + start = 0; + + foreach(Tuple extent in _backend.Where(extent => item >= extent.Item1 && item <= extent.Item2)) + { + start = extent.Item1; + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Extents/ExtentsShort.cs b/Aaru.CommonTypes/Extents/ExtentsShort.cs new file mode 100644 index 000000000..9bcaff285 --- /dev/null +++ b/Aaru.CommonTypes/Extents/ExtentsShort.cs @@ -0,0 +1,242 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ExtentsShort.cs +// Author(s) : Natalia Portillo +// +// Component : Extent helpers. +// +// --[ Description ] ---------------------------------------------------------- +// +// Provides extents for short types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Aaru.CommonTypes.Extents; + +/// Implements extents for +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public sealed class ExtentsShort +{ + List> _backend; + + /// Initialize an empty list of extents + public ExtentsShort() => _backend = []; + + /// Initializes extents with an specific list + /// List of extents as tuples "start, end" + public ExtentsShort(IEnumerable> list) + { + _backend = []; + + // This ensure no overlapping extents are added on creation + foreach(Tuple t in list) Add(t.Item1, t.Item2); + } + + /// Gets a count of how many extents are stored + public int Count => _backend.Count; + + /// Adds the specified number to the corresponding extent, or creates a new one + /// + public void Add(short item) + { + Tuple removeOne = null; + Tuple removeTwo = null; + Tuple itemToAdd = null; + + for(var i = 0; i < _backend.Count; i++) + { + // Already contained in an extent + if(item >= _backend[i].Item1 && item <= _backend[i].Item2) return; + + // Expands existing extent start + if(item == _backend[i].Item1 - 1) + { + removeOne = _backend[i]; + + if(i > 0 && item == _backend[i - 1].Item2 + 1) + { + removeTwo = _backend[i - 1]; + itemToAdd = new Tuple(_backend[i - 1].Item1, _backend[i].Item2); + } + else + itemToAdd = new Tuple(item, _backend[i].Item2); + + break; + } + + // Expands existing extent end + if(item != _backend[i].Item2 + 1) continue; + + removeOne = _backend[i]; + + if(i < _backend.Count - 1 && item == _backend[i + 1].Item1 - 1) + { + removeTwo = _backend[i + 1]; + itemToAdd = new Tuple(_backend[i].Item1, _backend[i + 1].Item2); + } + else + itemToAdd = new Tuple(_backend[i].Item1, item); + + break; + } + + if(itemToAdd != null) + { + _backend.Remove(removeOne); + _backend.Remove(removeTwo); + _backend.Add(itemToAdd); + } + else + _backend.Add(new Tuple(item, item)); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + } + + /// Adds a new extent + /// First element of the extent + /// + /// Last element of the extent or if is true how many elements the extent runs + /// for + /// + /// If set to true, indicates how many elements the extent runs for + public void Add(short start, short end, bool run = false) + { + short realEnd; + + if(run) + realEnd = (short)(start + end - 1); + else + realEnd = end; + + // TODO: Optimize this + for(short t = start; t <= realEnd; t++) Add(t); + } + + /// Checks if the specified item is contained by an extent on this instance + /// Item to search for + /// true if any of the extents on this instance contains the item + public bool Contains(short item) => _backend.Any(extent => item >= extent.Item1 && item <= extent.Item2); + + /// Removes all extents from this instance + public void Clear() => _backend.Clear(); + + /// Removes an item from the extents in this instance + /// Item to remove + /// true if the item was contained in a known extent and removed, false otherwise + public bool Remove(short item) + { + Tuple toRemove = null; + Tuple toAddOne = null; + Tuple toAddTwo = null; + + foreach(Tuple extent in _backend) + { + // Extent is contained and not a border + if(item > extent.Item1 && item < extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, (short)(item - 1)); + toAddTwo = new Tuple((short)(item + 1), extent.Item2); + + break; + } + + // Extent is left border, but not only element + if(item == extent.Item1 && item != extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple((short)(item + 1), extent.Item2); + + break; + } + + // Extent is right border, but not only element + if(item != extent.Item1 && item == extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, (short)(item - 1)); + + break; + } + + // Extent is only element + if(item != extent.Item1 || item != extent.Item2) continue; + + toRemove = extent; + + break; + } + + // Item not found + if(toRemove == null) return false; + + _backend.Remove(toRemove); + + if(toAddOne != null) _backend.Add(toAddOne); + + if(toAddTwo != null) _backend.Add(toAddTwo); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + + return true; + } + + /// + /// Converts the list of extents to an array of where T1 is first element of the extent and + /// T2 is last element + /// + /// Array of + public Tuple[] ToArray() => _backend.ToArray(); + + /// Gets the first element of the extent that contains the specified item + /// Item + /// First element of extent + /// true if item was found in an extent, false otherwise + public bool GetStart(short item, out short start) + { + start = 0; + + foreach(Tuple extent in _backend.Where(extent => item >= extent.Item1 && item <= extent.Item2)) + { + start = extent.Item1; + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Extents/ExtentsUInt.cs b/Aaru.CommonTypes/Extents/ExtentsUInt.cs new file mode 100644 index 000000000..d9c94a9ba --- /dev/null +++ b/Aaru.CommonTypes/Extents/ExtentsUInt.cs @@ -0,0 +1,242 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ExtentsUInt.cs +// Author(s) : Natalia Portillo +// +// Component : Extent helpers. +// +// --[ Description ] ---------------------------------------------------------- +// +// Provides extents for uint types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Aaru.CommonTypes.Extents; + +/// Implements extents for +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public sealed class ExtentsUInt +{ + List> _backend; + + /// Initialize an empty list of extents + public ExtentsUInt() => _backend = []; + + /// Initializes extents with an specific list + /// List of extents as tuples "start, end" + public ExtentsUInt(IEnumerable> list) + { + _backend = []; + + // This ensure no overlapping extents are added on creation + foreach(Tuple t in list) Add(t.Item1, t.Item2); + } + + /// Gets a count of how many extents are stored + public int Count => _backend.Count; + + /// Adds the specified number to the corresponding extent, or creates a new one + /// + public void Add(uint item) + { + Tuple removeOne = null; + Tuple removeTwo = null; + Tuple itemToAdd = null; + + for(var i = 0; i < _backend.Count; i++) + { + // Already contained in an extent + if(item >= _backend[i].Item1 && item <= _backend[i].Item2) return; + + // Expands existing extent start + if(item == _backend[i].Item1 - 1) + { + removeOne = _backend[i]; + + if(i > 0 && item == _backend[i - 1].Item2 + 1) + { + removeTwo = _backend[i - 1]; + itemToAdd = new Tuple(_backend[i - 1].Item1, _backend[i].Item2); + } + else + itemToAdd = new Tuple(item, _backend[i].Item2); + + break; + } + + // Expands existing extent end + if(item != _backend[i].Item2 + 1) continue; + + removeOne = _backend[i]; + + if(i < _backend.Count - 1 && item == _backend[i + 1].Item1 - 1) + { + removeTwo = _backend[i + 1]; + itemToAdd = new Tuple(_backend[i].Item1, _backend[i + 1].Item2); + } + else + itemToAdd = new Tuple(_backend[i].Item1, item); + + break; + } + + if(itemToAdd != null) + { + _backend.Remove(removeOne); + _backend.Remove(removeTwo); + _backend.Add(itemToAdd); + } + else + _backend.Add(new Tuple(item, item)); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + } + + /// Adds a new extent + /// First element of the extent + /// + /// Last element of the extent or if is true how many elements the extent runs + /// for + /// + /// If set to true, indicates how many elements the extent runs for + public void Add(uint start, uint end, bool run = false) + { + uint realEnd; + + if(run) + realEnd = start + end - 1; + else + realEnd = end; + + // TODO: Optimize this + for(uint t = start; t <= realEnd; t++) Add(t); + } + + /// Checks if the specified item is contained by an extent on this instance + /// Item to search for + /// true if any of the extents on this instance contains the item + public bool Contains(uint item) => _backend.Any(extent => item >= extent.Item1 && item <= extent.Item2); + + /// Removes all extents from this instance + public void Clear() => _backend.Clear(); + + /// Removes an item from the extents in this instance + /// Item to remove + /// true if the item was contained in a known extent and removed, false otherwise + public bool Remove(uint item) + { + Tuple toRemove = null; + Tuple toAddOne = null; + Tuple toAddTwo = null; + + foreach(Tuple extent in _backend) + { + // Extent is contained and not a border + if(item > extent.Item1 && item < extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, item - 1); + toAddTwo = new Tuple(item + 1, extent.Item2); + + break; + } + + // Extent is left border, but not only element + if(item == extent.Item1 && item != extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(item + 1, extent.Item2); + + break; + } + + // Extent is right border, but not only element + if(item != extent.Item1 && item == extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, item - 1); + + break; + } + + // Extent is only element + if(item != extent.Item1 || item != extent.Item2) continue; + + toRemove = extent; + + break; + } + + // Item not found + if(toRemove == null) return false; + + _backend.Remove(toRemove); + + if(toAddOne != null) _backend.Add(toAddOne); + + if(toAddTwo != null) _backend.Add(toAddTwo); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + + return true; + } + + /// + /// Converts the list of extents to an array of where T1 is first element of the extent and + /// T2 is last element + /// + /// Array of + public Tuple[] ToArray() => _backend.ToArray(); + + /// Gets the first element of the extent that contains the specified item + /// Item + /// First element of extent + /// true if item was found in an extent, false otherwise + public bool GetStart(uint item, out uint start) + { + start = 0; + + foreach(Tuple extent in _backend.Where(extent => item >= extent.Item1 && item <= extent.Item2)) + { + start = extent.Item1; + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Extents/ExtentsULong.cs b/Aaru.CommonTypes/Extents/ExtentsULong.cs new file mode 100644 index 000000000..a6ef385dd --- /dev/null +++ b/Aaru.CommonTypes/Extents/ExtentsULong.cs @@ -0,0 +1,242 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ExtentsULong.cs +// Author(s) : Natalia Portillo +// +// Component : Extent helpers. +// +// --[ Description ] ---------------------------------------------------------- +// +// Provides extents for ulong types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Aaru.CommonTypes.Extents; + +/// Implements extents for +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +public sealed class ExtentsULong +{ + List> _backend; + + /// Initialize an empty list of extents + public ExtentsULong() => _backend = []; + + /// Initializes extents with an specific list + /// List of extents as tuples "start, end" + public ExtentsULong(IEnumerable> list) + { + _backend = []; + + // This ensure no overlapping extents are added on creation + foreach(Tuple t in list) Add(t.Item1, t.Item2); + } + + /// Gets a count of how many extents are stored + public int Count => _backend.Count; + + /// Adds the specified number to the corresponding extent, or creates a new one + /// + public void Add(ulong item) + { + Tuple removeOne = null; + Tuple removeTwo = null; + Tuple itemToAdd = null; + + for(var i = 0; i < _backend.Count; i++) + { + // Already contained in an extent + if(item >= _backend[i].Item1 && item <= _backend[i].Item2) return; + + // Expands existing extent start + if(item == _backend[i].Item1 - 1) + { + removeOne = _backend[i]; + + if(i > 0 && item == _backend[i - 1].Item2 + 1) + { + removeTwo = _backend[i - 1]; + itemToAdd = new Tuple(_backend[i - 1].Item1, _backend[i].Item2); + } + else + itemToAdd = new Tuple(item, _backend[i].Item2); + + break; + } + + // Expands existing extent end + if(item != _backend[i].Item2 + 1) continue; + + removeOne = _backend[i]; + + if(i < _backend.Count - 1 && item == _backend[i + 1].Item1 - 1) + { + removeTwo = _backend[i + 1]; + itemToAdd = new Tuple(_backend[i].Item1, _backend[i + 1].Item2); + } + else + itemToAdd = new Tuple(_backend[i].Item1, item); + + break; + } + + if(itemToAdd != null) + { + _backend.Remove(removeOne); + _backend.Remove(removeTwo); + _backend.Add(itemToAdd); + } + else + _backend.Add(new Tuple(item, item)); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + } + + /// Adds a new extent + /// First element of the extent + /// + /// Last element of the extent or if is true how many elements the extent runs + /// for + /// + /// If set to true, indicates how many elements the extent runs for + public void Add(ulong start, ulong end, bool run = false) + { + ulong realEnd; + + if(run) + realEnd = start + end - 1; + else + realEnd = end; + + // TODO: Optimize this + for(ulong t = start; t <= realEnd; t++) Add(t); + } + + /// Checks if the specified item is contained by an extent on this instance + /// Item to search for + /// true if any of the extents on this instance contains the item + public bool Contains(ulong item) => _backend.Any(extent => item >= extent.Item1 && item <= extent.Item2); + + /// Removes all extents from this instance + public void Clear() => _backend.Clear(); + + /// Removes an item from the extents in this instance + /// Item to remove + /// true if the item was contained in a known extent and removed, false otherwise + public bool Remove(ulong item) + { + Tuple toRemove = null; + Tuple toAddOne = null; + Tuple toAddTwo = null; + + foreach(Tuple extent in _backend) + { + // Extent is contained and not a border + if(item > extent.Item1 && item < extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, item - 1); + toAddTwo = new Tuple(item + 1, extent.Item2); + + break; + } + + // Extent is left border, but not only element + if(item == extent.Item1 && item != extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(item + 1, extent.Item2); + + break; + } + + // Extent is right border, but not only element + if(item != extent.Item1 && item == extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, item - 1); + + break; + } + + // Extent is only element + if(item != extent.Item1 || item != extent.Item2) continue; + + toRemove = extent; + + break; + } + + // Item not found + if(toRemove == null) return false; + + _backend.Remove(toRemove); + + if(toAddOne != null) _backend.Add(toAddOne); + + if(toAddTwo != null) _backend.Add(toAddTwo); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + + return true; + } + + /// + /// Converts the list of extents to an array of where T1 is first element of the extent and + /// T2 is last element + /// + /// Array of + public Tuple[] ToArray() => _backend.ToArray(); + + /// Gets the first element of the extent that contains the specified item + /// Item + /// First element of extent + /// true if item was found in an extent, false otherwise + public bool GetStart(ulong item, out ulong start) + { + start = 0; + + foreach(Tuple extent in _backend.Where(extent => item >= extent.Item1 && item <= extent.Item2)) + { + start = extent.Item1; + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Extents/ExtentsUShort.cs b/Aaru.CommonTypes/Extents/ExtentsUShort.cs new file mode 100644 index 000000000..20b979013 --- /dev/null +++ b/Aaru.CommonTypes/Extents/ExtentsUShort.cs @@ -0,0 +1,242 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ExtentsUShort.cs +// Author(s) : Natalia Portillo +// +// Component : Extent helpers. +// +// --[ Description ] ---------------------------------------------------------- +// +// Provides extents for ushort types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Aaru.CommonTypes.Extents; + +/// Implements extents for +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public sealed class ExtentsUShort +{ + List> _backend; + + /// Initialize an empty list of extents + public ExtentsUShort() => _backend = []; + + /// Initializes extents with an specific list + /// List of extents as tuples "start, end" + public ExtentsUShort(IEnumerable> list) + { + _backend = []; + + // This ensure no overlapping extents are added on creation + foreach(Tuple t in list) Add(t.Item1, t.Item2); + } + + /// Gets a count of how many extents are stored + public int Count => _backend.Count; + + /// Adds the specified number to the corresponding extent, or creates a new one + /// + public void Add(ushort item) + { + Tuple removeOne = null; + Tuple removeTwo = null; + Tuple itemToAdd = null; + + for(var i = 0; i < _backend.Count; i++) + { + // Already contained in an extent + if(item >= _backend[i].Item1 && item <= _backend[i].Item2) return; + + // Expands existing extent start + if(item == _backend[i].Item1 - 1) + { + removeOne = _backend[i]; + + if(i > 0 && item == _backend[i - 1].Item2 + 1) + { + removeTwo = _backend[i - 1]; + itemToAdd = new Tuple(_backend[i - 1].Item1, _backend[i].Item2); + } + else + itemToAdd = new Tuple(item, _backend[i].Item2); + + break; + } + + // Expands existing extent end + if(item != _backend[i].Item2 + 1) continue; + + removeOne = _backend[i]; + + if(i < _backend.Count - 1 && item == _backend[i + 1].Item1 - 1) + { + removeTwo = _backend[i + 1]; + itemToAdd = new Tuple(_backend[i].Item1, _backend[i + 1].Item2); + } + else + itemToAdd = new Tuple(_backend[i].Item1, item); + + break; + } + + if(itemToAdd != null) + { + _backend.Remove(removeOne); + _backend.Remove(removeTwo); + _backend.Add(itemToAdd); + } + else + _backend.Add(new Tuple(item, item)); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + } + + /// Adds a new extent + /// First element of the extent + /// + /// Last element of the extent or if is true how many elements the extent runs + /// for + /// + /// If set to true, indicates how many elements the extent runs for + public void Add(ushort start, ushort end, bool run = false) + { + ushort realEnd; + + if(run) + realEnd = (ushort)(start + end - 1); + else + realEnd = end; + + // TODO: Optimize this + for(ushort t = start; t <= realEnd; t++) Add(t); + } + + /// Checks if the specified item is contained by an extent on this instance + /// Item to search for + /// true if any of the extents on this instance contains the item + public bool Contains(ushort item) => _backend.Any(extent => item >= extent.Item1 && item <= extent.Item2); + + /// Removes all extents from this instance + public void Clear() => _backend.Clear(); + + /// Removes an item from the extents in this instance + /// Item to remove + /// true if the item was contained in a known extent and removed, false otherwise + public bool Remove(ushort item) + { + Tuple toRemove = null; + Tuple toAddOne = null; + Tuple toAddTwo = null; + + foreach(Tuple extent in _backend) + { + // Extent is contained and not a border + if(item > extent.Item1 && item < extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, (ushort)(item - 1)); + toAddTwo = new Tuple((ushort)(item + 1), extent.Item2); + + break; + } + + // Extent is left border, but not only element + if(item == extent.Item1 && item != extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple((ushort)(item + 1), extent.Item2); + + break; + } + + // Extent is right border, but not only element + if(item != extent.Item1 && item == extent.Item2) + { + toRemove = extent; + toAddOne = new Tuple(extent.Item1, (ushort)(item - 1)); + + break; + } + + // Extent is only element + if(item != extent.Item1 || item != extent.Item2) continue; + + toRemove = extent; + + break; + } + + // Item not found + if(toRemove == null) return false; + + _backend.Remove(toRemove); + + if(toAddOne != null) _backend.Add(toAddOne); + + if(toAddTwo != null) _backend.Add(toAddTwo); + + // Sort + _backend = _backend.OrderBy(t => t.Item1).ToList(); + + return true; + } + + /// + /// Converts the list of extents to an array of where T1 is first element of the extent and + /// T2 is last element + /// + /// Array of + public Tuple[] ToArray() => _backend.ToArray(); + + /// Gets the first element of the extent that contains the specified item + /// Item + /// First element of extent + /// true if item was found in an extent, false otherwise + public bool GetStart(ushort item, out ushort start) + { + start = 0; + + foreach(Tuple extent in _backend.Where(extent => item >= extent.Item1 && item <= extent.Item2)) + { + start = extent.Item1; + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Geometry.cs b/Aaru.CommonTypes/Geometry.cs new file mode 100644 index 000000000..c9f75b344 --- /dev/null +++ b/Aaru.CommonTypes/Geometry.cs @@ -0,0 +1,144 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Geometry.cs +// Author(s) : Natalia Portillo +// +// Component : CommonTypes. +// +// --[ Description ] ---------------------------------------------------------- +// +// Includes geometry for several medias. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Linq; + +namespace Aaru.CommonTypes; + +/// Handles CHS geometries +public static class Geometry +{ + /// List of known disk geometries + public static readonly (ushort cylinders, byte heads, ushort sectorsPerTrack, uint bytesPerSector, MediaEncoding + encoding, bool variableSectorsPerTrack, MediaType type)[] KnownGeometries = + [ + (32, 1, 8, 319, MediaEncoding.FM, false, MediaType.IBM23FD), + (35, 1, 9, 256, MediaEncoding.FM, false, MediaType.ECMA_66), + (35, 1, 13, 256, MediaEncoding.AppleGCR, false, MediaType.Apple32SS), + (35, 1, 16, 256, MediaEncoding.MFM, false, MediaType.MetaFloppy_Mod_I), + (35, 1, 16, 256, MediaEncoding.AppleGCR, false, MediaType.Apple33SS), + (35, 1, 19, 256, MediaEncoding.CommodoreGCR, false, MediaType.CBM_1540), + (35, 2, 13, 256, MediaEncoding.AppleGCR, false, MediaType.Apple32DS), + (35, 2, 16, 256, MediaEncoding.AppleGCR, false, MediaType.Apple33DS), + (35, 2, 19, 256, MediaEncoding.CommodoreGCR, false, MediaType.CBM_1571), + (40, 1, 8, 512, MediaEncoding.MFM, false, MediaType.DOS_525_SS_DD_8), + (40, 1, 9, 512, MediaEncoding.MFM, false, MediaType.DOS_525_SS_DD_9), + (40, 1, 10, 256, MediaEncoding.FM, false, MediaType.ACORN_525_SS_SD_40), + (40, 1, 16, 256, MediaEncoding.MFM, false, MediaType.ACORN_525_SS_DD_40), + (40, 1, 18, 128, MediaEncoding.FM, false, MediaType.ATARI_525_SD), + (40, 1, 18, 256, MediaEncoding.MFM, false, MediaType.ATARI_525_DD), + (40, 1, 19, 256, MediaEncoding.CommodoreGCR, false, MediaType.CBM_1540_Ext), + (40, 1, 26, 128, MediaEncoding.MFM, false, MediaType.ATARI_525_ED), + (40, 2, 8, 512, MediaEncoding.MFM, false, MediaType.DOS_525_DS_DD_8), + (40, 2, 9, 512, MediaEncoding.MFM, false, MediaType.DOS_525_DS_DD_9), + (40, 2, 16, 256, MediaEncoding.FM, false, MediaType.ECMA_70), + (70, 2, 9, 512, MediaEncoding.MFM, false, MediaType.Apricot_35), + (74, 1, 8, 512, MediaEncoding.FM, false, MediaType.IBM33FD_512), + (74, 1, 15, 256, MediaEncoding.FM, false, MediaType.IBM33FD_256), + (74, 1, 26, 128, MediaEncoding.FM, false, MediaType.IBM33FD_128), + (74, 2, 8, 1024, MediaEncoding.MFM, false, MediaType.IBM53FD_1024), + (74, 2, 15, 256, MediaEncoding.FM, false, MediaType.IBM43FD_256), + (74, 2, 15, 512, MediaEncoding.MFM, false, MediaType.IBM53FD_512), + (74, 2, 26, 128, MediaEncoding.FM, false, MediaType.IBM43FD_128), + (74, 2, 26, 256, MediaEncoding.MFM, false, MediaType.IBM53FD_256), + (77, 1, 16, 256, MediaEncoding.MFM, false, MediaType.MetaFloppy_Mod_II), + (77, 1, 26, 128, MediaEncoding.FM, false, MediaType.RX01), + (77, 1, 26, 256, MediaEncoding.MFM, false, MediaType.RX02), + (77, 2, 8, 1024, MediaEncoding.MFM, false, MediaType.NEC_525_HD), + (77, 2, 15, 512, MediaEncoding.MFM, false, MediaType.ECMA_99_15), + (77, 2, 26, 128, MediaEncoding.FM, false, MediaType.NEC_8_SD), + (77, 2, 26, 256, MediaEncoding.MFM, false, MediaType.RX03), + (80, 1, 8, 512, MediaEncoding.MFM, false, MediaType.DOS_35_SS_DD_8), + (80, 1, 9, 512, MediaEncoding.MFM, false, MediaType.DOS_35_SS_DD_9), + (80, 1, 10, 256, MediaEncoding.FM, false, MediaType.ACORN_525_SS_SD_80), + (80, 1, 10, 512, MediaEncoding.AppleGCR, true, MediaType.AppleSonySS), + (80, 1, 10, 512, MediaEncoding.MFM, false, MediaType.RX50), + (80, 1, 11, 512, MediaEncoding.MFM, false, MediaType.ATARI_35_SS_DD_11), + (80, 1, 16, 256, MediaEncoding.MFM, false, MediaType.ACORN_525_SS_DD_80), + (80, 2, 5, 1024, MediaEncoding.MFM, false, MediaType.ACORN_35_DS_DD), + (80, 2, 8, 512, MediaEncoding.MFM, false, MediaType.DOS_35_DS_DD_8), + (80, 2, 9, 512, MediaEncoding.MFM, false, MediaType.DOS_35_DS_DD_9), + (80, 2, 10, 512, MediaEncoding.AppleGCR, true, MediaType.AppleSonyDS), + (80, 2, 10, 512, MediaEncoding.MFM, false, MediaType.CBM_35_DD), + (80, 2, 10, 1024, MediaEncoding.MFM, false, MediaType.ACORN_35_DS_HD), + (80, 2, 11, 512, MediaEncoding.MFM, false, MediaType.CBM_AMIGA_35_DD), + (80, 2, 15, 512, MediaEncoding.MFM, false, MediaType.DOS_525_HD), + (80, 2, 16, 256, MediaEncoding.FM, false, MediaType.ECMA_78), + (80, 2, 16, 256, MediaEncoding.MFM, false, MediaType.ACORN_525_DS_DD), + (80, 2, 18, 512, MediaEncoding.MFM, false, MediaType.DOS_35_HD), + (80, 2, 19, 512, MediaEncoding.MFM, false, MediaType.XDF_525), + (80, 2, 21, 512, MediaEncoding.MFM, false, MediaType.DMF), + (80, 2, 22, 512, MediaEncoding.MFM, false, MediaType.CBM_AMIGA_35_HD), + (80, 2, 23, 512, MediaEncoding.MFM, false, MediaType.XDF_35), + (80, 2, 36, 512, MediaEncoding.MFM, false, MediaType.DOS_35_ED), + (82, 2, 10, 512, MediaEncoding.MFM, false, MediaType.FDFORMAT_35_DD), + (82, 2, 17, 512, MediaEncoding.MFM, false, MediaType.FDFORMAT_525_HD), + (82, 2, 21, 512, MediaEncoding.MFM, false, MediaType.FDFORMAT_35_HD), + (240, 2, 38, 512, MediaEncoding.MFM, false, MediaType.NEC_35_TD), + (753, 2, 27, 512, MediaEncoding.MFM, false, MediaType.Floptical), + + // Following ones are what the device itself report, not the physical geometry + (154, 16, 32, 512, MediaEncoding.MFM, false, MediaType.PocketZip), + (262, 32, 56, 512, MediaEncoding.MFM, false, MediaType.LS240), + (963, 8, 32, 512, MediaEncoding.MFM, false, MediaType.LS120), + (1021, 64, 32, 512, MediaEncoding.MFM, false, MediaType.Jaz), + (1024, 2, 32, 512, MediaEncoding.MFM, false, MediaType.FD32MB) + ]; + + /// Gets the media type for a given geometry + /// Geometry + /// Media type + public static MediaType GetMediaType( + (ushort cylinders, byte heads, ushort sectorsPerTrack, uint bytesPerSector, MediaEncoding encoding, bool + variableSectorsPerTrack) geometry) => (from geom in KnownGeometries + where geom.cylinders == geometry.cylinders && + geom.heads == geometry.heads && + geom.sectorsPerTrack == geometry.sectorsPerTrack && + geom.bytesPerSector == geometry.bytesPerSector && + geom.encoding == geometry.encoding && + geom.variableSectorsPerTrack == + geometry.variableSectorsPerTrack + select geom.type).FirstOrDefault(); + + /// Gets the geometry for a given media type + /// Media type + /// Geometry + public static (ushort cylinders, byte heads, ushort sectorsPerTrack, uint bytesPerSector, MediaEncoding encoding, + bool variableSectorsPerTrack, MediaType type) GetGeometry(MediaType mediaType) => + (from geom in KnownGeometries where geom.type == mediaType select geom).FirstOrDefault(); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IArchive.cs b/Aaru.CommonTypes/Interfaces/IArchive.cs new file mode 100644 index 000000000..5cdc82c81 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IArchive.cs @@ -0,0 +1,208 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IArchive.cs +// Author(s) : Michael Drüing +// +// Component : Archives. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface for implementing archive plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2018-2024 Michael Drüing +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global + +using System; +using System.Collections.Generic; +using System.Text; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; +using FileAttributes = System.IO.FileAttributes; + +namespace Aaru.CommonTypes.Interfaces; + +/// Supported archive features +[Flags] +public enum ArchiveSupportedFeature : uint +{ + /// The archive supports filenames for its entries. If this flag is not set, files can only be accessed by number. + SupportsFilenames = 1 << 0, + /// + /// The archive supports compression. If this flag is not set, compressed and uncompressed lengths are always the + /// same. + /// + SupportsCompression = 1 << 1, + /// + /// The archive supports subdirectories. If this flag is not set, all filenames are guaranteed to not contain any + /// "/" character. + /// + SupportsSubdirectories = 1 << 2, + /// + /// The archive supports explicit entries for directories (like Zip, for example). If this flag is not set, + /// directories are implicit by the relative name of the files. + /// + HasExplicitDirectories = 1 << 3, + /// The archive stores a timestamp with each entry if this flag is set. + HasEntryTimestamp = 1 << 4, + /// If this flag is set, individual files or the whole archive might be encrypted or password-protected. + SupportsProtection = 1 << 5, // TODO: not implemented yet + + /// If this flag is set, the archive supports returning extended attributes (Xattrs) for each entry. + SupportsXAttrs = 1 << 6 +} + +/// Defines the interface to handle an archive (e.g. ZIP, WAD, etc) +public interface IArchive +{ + /// Descriptive name of the plugin + string Name { get; } + + /// Unique UUID of the plugin + Guid Id { get; } + + /// Plugin author + string Author { get; } + + /// + /// Returns true if the archive has a file/stream/buffer currently opened and no + /// has been issued. + /// + /// true if the archive is opened, false otherwise. + bool Opened { get; } + + /// Return a bitfield indicating the features supported by this archive type. + /// The ArchiveSupportedFeature bitfield. + /// + /// If the archive is not opened, this returns the capabilities of the archive format, otherwise it returns the + /// capabilities in use by the currently opened archive. + /// + ArchiveSupportedFeature ArchiveFeatures { get; } + + /// Gets the number of entries (i.e. files) that are contained in this archive. + /// + /// Entries in this context can also mean directories or volume labels, for some types of archives that store + /// these explicitly. Do not rely on all entries being regular files! + /// + /// The number of files. + int NumberOfEntries { get; } + + /// Identifies if the specified filter contains data recognizable by this archive instance + /// Filter that contains the archive. This allows use to handle .tar.gz and similars. + bool Identify(IFilter filter); + + /// Opens the specified stream with this archive instance + /// Filter that contains the archive. This allows use to handle .tar.gz and similars. + /// The encoding codepage to use for this archive. + ErrorNumber Open(IFilter filter, Encoding encoding); + + /// Closes the archive. + void Close(); + + /// Gets the file name (and path) of the given entry in the archive. + /// + /// The path components are separated by a forward slash "/".
The path should not start with a leading + /// slash (i.e. it should be relative, not absolute). + ///
+ /// + /// The entry in the archive for which to return the file name. + /// The file name, with (relative) path + /// Error number. + ErrorNumber GetFilename(int entryNumber, out string fileName); + + /// + /// Gets the entry number for a particular file path in the archive. fileName is the relative path of the + /// file in the archive. If the file cannot be found, -1 is returned. + /// + /// + /// The path should be relative (no leading slash), using regular slashes as path separator, and be normalized, + /// i.e. no "foo//bar" or "foo/../bar" path components. + /// + /// The relative path for which to get the entry number. + /// If set, do a case insensitive matching and return the first file that matches. + /// The number of the entry corresponding to the given path, or -1 if the path does not exist. + /// Error number. + ErrorNumber GetEntryNumber(string fileName, bool caseInsensitiveMatch, out int entryNumber); + + /// Gets the (compressed) size of the given entry. + /// The entry for which to get the compressed size. + /// The compressed size of the entry, or 0 if the entry is not a regular file. + /// Error number. + /// The return value is equal to the return value of GetUncompressedSize() if the file is not compressed. + /// + ErrorNumber GetCompressedSize(int entryNumber, out long length); + + /// Gets the uncompressed size of the given entry. + /// The entry for which to get the uncompressed size. + /// The uncompressed size of the entry, or 0 if the entry is not a regular file. + /// Error number. + /// The return value is equal to the return value of GetCompressedSize() if the file is not compressed. + /// + ErrorNumber GetUncompressedSize(int entryNumber, out long length); + + /// Gets the attributes of a file or directory. + /// The entry in the archive for which to retrieve the attributes. + /// File attributes, or zero if the archive does not support attributes. + /// Error number. + /// + ErrorNumber GetAttributes(int entryNumber, out FileAttributes attributes); + + /// Lists all extended attributes, alternate data streams and forks of the given file. + /// The entry in the archive for which to retrieve the list of attributes. + /// List of extended attributes, alternate data streams and forks. + /// Error number. + ErrorNumber ListXAttr(int entryNumber, out List xattrs); + + /// Reads an extended attribute, alternate data stream or fork from the given file. + /// The entry in the archive for which to retrieve the XAttr. + /// Extended attribute, alternate data stream or fork name. + /// Buffer where the extended attribute data will be stored. + /// Error number. + ErrorNumber GetXattr(int entryNumber, string xattr, ref byte[] buffer); + + /// Gets information about an entry in the archive. + /// Note that some of the data might be incomplete or not available at all, depending on the type of archive. + /// The entry int he archive for which to get the information + /// The available information about the entry in the archive + /// Error number. + /// + /// + ErrorNumber Stat(int entryNumber, out FileEntryInfo stat); + + /// + /// Returns the Filter for the given entry. It will return null if the entry in question is not a regular + /// file (i.e. directory, volume label, etc.) + /// + /// The entry for which the Filter should be returned. + /// The Filter for the given entry. + /// Error number. + ErrorNumber GetEntry(int entryNumber, out IFilter filter); + + /// + /// Gets user readable information about the archive. The exact contents depend on the archive plugin implementation. + /// + /// Filter that handles the archive. + /// The encoding codepage to use with the archive. + /// Variable that holds the user readable information. + void GetInformation(IFilter filter, Encoding encoding, out string information); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IBaseImage.cs b/Aaru.CommonTypes/Interfaces/IBaseImage.cs new file mode 100644 index 000000000..ba72a17b1 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IBaseImage.cs @@ -0,0 +1,81 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IBaseImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; + +namespace Aaru.CommonTypes.Interfaces; + +/// Base interface for all images +public interface IBaseImage +{ + /// Plugin author + string Author { get; } + + /// Gets the Aaru Metadata for the image + AaruMetadata.Metadata AaruMetadata { get; } + + /// List of dump hardware used to create the image from real media + List DumpHardware { get; } + + /// Gets the image format. + /// The image format. + string Format { get; } + + /// Plugin UUID. + Guid Id { get; } + + /// Image information + ImageInfo Info { get; } + + /// Plugin name. + string Name { get; } + + /// Identifies the image. + /// true, if image was identified, false otherwise. + /// Image filter. + bool Identify(IFilter imageFilter); + + /// Opens the image. + /// true, if image was opened, false otherwise. + /// Image filter. + ErrorNumber Open(IFilter imageFilter); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IBaseWritableImage.cs b/Aaru.CommonTypes/Interfaces/IBaseWritableImage.cs new file mode 100644 index 000000000..623eb9bc6 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IBaseWritableImage.cs @@ -0,0 +1,98 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IBaseWritableImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the base interface to be implemented by writable image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Base interface for all writable images +public interface IBaseWritableImage : IBaseImage +{ + /// Contains a description of the last error + string ErrorMessage { get; } + + /// If set to true means the image is opened for writing + bool IsWriting { get; } + + /// Gets a list of known extensions for format auto-choosing + IEnumerable KnownExtensions { get; } + + /// Gets a list of that are supported by the media image format + IEnumerable SupportedMediaTags { get; } + + /// Gets a list of that are supported by the media image format + IEnumerable SupportedMediaTypes { get; } + + /// Retrieves a list of options supported by the filesystem, with name, type and description + IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions { get; } + + /// Gets a list of that are supported by the media image format + IEnumerable SupportedSectorTags { get; } + + /// + /// Creates a new image in the specified path, for the specified , with the specified + /// options to hold a media with the specified number of sectors + /// + /// Path to the new image, with extension + /// that will be written in the image + /// Options to be used when creating new image + /// How many sectors the media has. + /// + /// true if operating completed successfully, false otherwise + bool Create(string path, MediaType mediaType, Dictionary options, ulong sectors, uint sectorSize); + + /// Closes the image and flushes all data to disk + /// Error number + bool Close(); + + /// Sets the Aaru Metadata for the image + bool SetMetadata(AaruMetadata.Metadata metadata); + + /// Sets the list of dump hardware used to create the image from real media + bool SetDumpHardware(List dumpHardware); + + /// Sets image metadata + /// containing image metadata + /// true if operating completed successfully, false otherwise + bool SetImageInfo(ImageInfo imageInfo); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IByteAddressableImage.cs b/Aaru.CommonTypes/Interfaces/IByteAddressableImage.cs new file mode 100644 index 000000000..d33057400 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IByteAddressableImage.cs @@ -0,0 +1,141 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IByteAddressableImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by byte-addressable image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Interface defining linear media (chips, game carts, etc) images +[SuppressMessage("ReSharper", "UnusedParameter.Global")] +[SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "OutParameterValueIsAlwaysDiscarded.Global")] +public interface IByteAddressableImage : IBaseWritableImage +{ + /// Gets or sets the current position + long Position { get; set; } + + /// Creates a linear media image + /// Path where to create the media image + /// Media type + /// Image options + /// Maximum size in bytes + /// Error number + ErrorNumber Create(string path, MediaType mediaType, Dictionary options, long maximumSize); + + /// Gets the linear memory mappings, e.g. interleaving, starting address, etc. + /// Format still not decided + /// Error number + ErrorNumber GetMappings(out LinearMemoryMap mappings); + + /// Reads a byte from the image + /// The byte read + /// Set to true to advance position, false otherwise. + /// Error number + ErrorNumber ReadByte(out byte b, bool advance = true); + + /// Reads a byte from the image at the specified position + /// Position + /// The byte read + /// Set to true to advance position, false otherwise. + /// Error number + ErrorNumber ReadByteAt(long position, out byte b, bool advance = true); + + /// Reads several bytes from the image + /// Buffer to store the data in + /// Offset in buffer where to place the byte in + /// How many bytes to read from image + /// How many bytes were read + /// Set to true to advance position, false otherwise. + /// Error number + ErrorNumber ReadBytes(byte[] buffer, int offset, int bytesToRead, out int bytesRead, bool advance = true); + + /// Reads several bytes from the image at the specified position + /// Position + /// Buffer to store the data in + /// Offset in buffer where to place the byte in + /// How many bytes to read from image + /// How many bytes were read + /// Set to true to advance position, false otherwise. + /// Error number + ErrorNumber ReadBytesAt(long position, byte[] buffer, int offset, int bytesToRead, out int bytesRead, + bool advance = true); + + /// Sets the linear memory mappings, e.g. interleaving, starting address, etc. + /// Format still not decided + /// Error number + ErrorNumber SetMappings(LinearMemoryMap mappings); + + /// Writes a byte to the image + /// The byte to be written + /// Set to true to advance position, false otherwise. + /// Error number + ErrorNumber WriteByte(byte b, bool advance = true); + + /// Writes a byte to the image at the specified position + /// Position + /// The byte read + /// Set to true to advance position, false otherwise. + /// Error number + ErrorNumber WriteByteAt(long position, byte b, bool advance = true); + + /// Writes several bytes to the image + /// Buffer to store the data in + /// Offset in buffer where the bytes start in + /// How many bytes to write to image + /// How many bytes were written + /// Set to true to advance position, false otherwise. + /// Error number + ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten, bool advance = true); + + /// Writes several bytes to the image at the specified position + /// Position + /// Buffer to store the data in + /// Offset in buffer where the bytes start in + /// How many bytes to write to image + /// How many bytes were written + /// Set to true to advance position, false otherwise. + /// Error number + ErrorNumber WriteBytesAt(long position, byte[] buffer, int offset, int bytesToWrite, out int bytesWritten, + bool advance = true); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IChecksum.cs b/Aaru.CommonTypes/Interfaces/IChecksum.cs new file mode 100644 index 000000000..f9b322e9d --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IChecksum.cs @@ -0,0 +1,69 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IChecksum.cs +// Author(s) : Natalia Portillo +// +// Component : Checksums. +// +// --[ Description ] ---------------------------------------------------------- +// +// Provides an interface for implementing checksums and hashes. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; + +namespace Aaru.CommonTypes.Interfaces; + +/// Defines the interface to implement a checksum or hashing algorithm +public interface IChecksum +{ + /// Plugin author + string Author { get; } + + /// Plugin name. + string Name { get; } + + /// Plugin UUID. + Guid Id { get; } + + /// Updates the hash with data. + /// Data buffer. + /// Length of buffer to hash. + void Update(byte[] data, uint len); + + /// Updates the hash with data. + /// Data buffer. + void Update(byte[] data); + + /// Returns a byte array of the hash value. + byte[] Final(); + + /// Returns a hexadecimal representation of the hash value. + string End(); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IFilesystem.cs b/Aaru.CommonTypes/Interfaces/IFilesystem.cs new file mode 100644 index 000000000..6640f997a --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IFilesystem.cs @@ -0,0 +1,71 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IFilesystem.cs +// Author(s) : Natalia Portillo +// +// Component : Filesystem plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Interface for filesystem plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; + +namespace Aaru.CommonTypes.Interfaces; + +/// Interface to implement filesystem plugins. +public interface IFilesystem +{ + /// Plugin name (translatable). + string Name { get; } + + /// Plugin UUID. + Guid Id { get; } + + /// Plugin author + string Author { get; } + + /// Identifies the filesystem in the specified LBA + /// Disk image. + /// Partition. + /// true, if the filesystem is recognized, false otherwise. + bool Identify(IMediaImage imagePlugin, Partition partition); + + /// Gets information about the identified filesystem. + /// Disk image. + /// Partition. + /// Which encoding to use for this filesystem. + /// Filesystem information. + /// Information about the filesystem as expected by Aaru Metadata + void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IFilter.cs b/Aaru.CommonTypes/Interfaces/IFilter.cs new file mode 100644 index 000000000..bc2aa6d0a --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IFilter.cs @@ -0,0 +1,154 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IFilter.cs +// Author(s) : Natalia Portillo +// +// Component : Filters. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface for a Filter. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using Aaru.CommonTypes.Enums; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Defines a filter, that is, a transformation of the data from a file, like, for example, a compressor (e.g. +/// GZIP), or a container (e.g. AppleDouble) +/// +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] +public interface IFilter +{ + /// Descriptive name of the plugin + string Name { get; } + + /// Unique UUID of the plugin + Guid Id { get; } + + /// Plugin author + string Author { get; } + + /// + /// Gets the path used to open this filter.
UNIX: /path/to/archive.zip/path/to/file.bin => + /// /path/to/archive.zip/path/to/file.bin
Windows: C:\path\to\archive.zip\path\to\file.bin => + /// C:\path\to\archive.zip\path\to\file.bin + ///
+ /// Path used to open this filter. + string BasePath { get; } + + /// Gets creation time of file referenced by this filter. + /// The creation time. + DateTime CreationTime { get; } + + /// Gets length of this filter's data fork. + /// The data fork length. + long DataForkLength { get; } + + /// + /// Gets the filename for the file referenced by this filter.
UNIX: /path/to/archive.zip/path/to/file.bin = + /// > file.bin
Windows: C:\path\to\archive.zip\path\to\file.bin => file.bin + ///
+ /// The filename. + string Filename { get; } + + /// Gets last write time of file referenced by this filter. + /// The last write time. + DateTime LastWriteTime { get; } + + /// Gets length of file referenced by ths filter. + /// The length. + long Length { get; } + + /// + /// Gets full path to file referenced by this filter. If it's an archive, it's the path inside the archive.
+ /// UNIX: /path/to/archive.zip/path/to/file.bin => /path/to/file.bin
Windows: + /// C:\path\to\archive.zip\path\to\file.bin => \path\to\file.bin + ///
+ /// The path. + string Path { get; } + + /// + /// Gets path to parent folder to the file referenced by this filter. If it's an archive, it's the full path to + /// the archive itself.
UNIX: /path/to/archive.zip/path/to/file.bin => /path/to/archive.zip
Windows: + /// C:\path\to\archive.zip\path\to\file.bin = > C:\path\to\archive.zip + ///
+ /// The parent folder. + string ParentFolder { get; } + + /// Gets length of this filter's resource fork. + /// The resource fork length. + long ResourceForkLength { get; } + + /// Returns true if the file referenced by this filter has a resource fork + bool HasResourceFork { get; } + + /// Closes all opened streams. + void Close(); + + /// Gets a stream to access the data fork contents. + /// The data fork stream. + Stream GetDataForkStream(); + + /// Gets a stream to access the resource fork contents. + /// The resource fork stream. + Stream GetResourceForkStream(); + + /// Identifies if the specified path contains data recognizable by this filter instance + /// Path. + bool Identify(string path) => File.Exists(path) && Identify(new FileStream(path, FileMode.Open, FileAccess.Read)); + + /// Identifies if the specified stream contains data recognizable by this filter instance + /// Stream. + bool Identify(Stream stream); + + /// Identifies if the specified buffer contains data recognizable by this filter instance + /// Buffer. + bool Identify(byte[] buffer) => Identify(new MemoryStream(buffer)); + + /// Opens the specified path with this filter instance + /// Path. + ErrorNumber Open(string path) => !File.Exists(path) + ? ErrorNumber.NoSuchFile + : Open(new FileStream(path, FileMode.Open, FileAccess.Read)); + + /// Opens the specified stream with this filter instance + /// Stream. + ErrorNumber Open(Stream stream); + + /// Opens the specified buffer with this filter instance + /// Buffer. + ErrorNumber Open(byte[] buffer) => Open(new MemoryStream(buffer)); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IFloppyImage.cs b/Aaru.CommonTypes/Interfaces/IFloppyImage.cs new file mode 100644 index 000000000..563930d80 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IFloppyImage.cs @@ -0,0 +1,128 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IFloppyImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by floppy image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// +/// Abstract class to implement disk image reading plugins that can contain floppy images. This interface is +/// needed because floppy formatting characteristics are not necessarily compatible with the whole. LBA-oriented +/// interface is defined by . All data returned by these +/// methods is already decoded from its corresponding bitstream. +/// +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public interface IFloppyImage : IMediaImage +{ + /// + /// Floppy info, contains information about physical characteristics of floppy, like size, bitrate, track density, + /// etc... + /// + FloppyInfo FloppyInfo { get; } + + /// Reads a sector's user data. + /// + /// If is one of the duplicates is returned + /// randomly. If is or + /// random data is returned. If is + /// null is returned. Otherwise, whatever is in the sector is + /// returned. + /// + /// Physical track (position of the heads over the floppy media, 0-based). + /// Physical head (0-based). + /// Logical sector ID. + /// Status of request. + /// Buffer where the sector data will be stored. + ErrorNumber ReadSector(ushort track, byte head, ushort sector, out FloppySectorStatus status, out byte[] buffer); + + /// Reads a sector's tag. + /// + /// If is one of the duplicates is returned + /// randomly. If is or + /// random data is returned. If is + /// null is returned. Otherwise, whatever tag is in the sector is + /// returned. + /// + /// Physical track (position of the heads over the floppy media, 0-based). + /// Physical head (0-based). + /// Logical sector ID. + /// Status of request. + /// Sector tag + /// Buffer where the sector tag data will be stored. + ErrorNumber ReadSectorTag(ushort track, byte head, ushort sector, out FloppySectorStatus status, SectorTagType tag, + out byte[] buffer); + + /// Reads a whole track. It includes all gaps, address marks, sectors data, etc. + /// The track data. + /// Physical track (position of the heads over the floppy media, 0-based). + /// Physical head (0-based). + /// Buffer where the track data will be stored. + ErrorNumber ReadTrack(ushort track, byte head, out byte[] buffer); + + /// Reads a sector's data including all tags, address mark, and so, in a format dependent of represented media. + /// + /// If is one of the duplicates is returned + /// randomly. If is or + /// random data is returned. If is + /// null is returned. Otherwise, whatever is in the sector is + /// returned. + /// + /// Physical track (position of the heads over the floppy media, 0-based). + /// Physical head (0-based). + /// Logical sector ID. + /// Status of request. + /// Buffer where the sector data will be stored. + ErrorNumber ReadSectorLong(ushort track, byte head, ushort sector, out FloppySectorStatus status, + out byte[] buffer); + + /// Verifies a track. + /// True if correct, false if incorrect, null if uncheckable. + /// Physical track (position of the heads over the floppy media, 0-based). + /// Physical head (0-based). + bool? VerifyTrack(ushort track, byte head); + + /// Verifies a sector, relative to track. + /// True if correct, false if incorrect, null if uncheckable. + /// Physical track (position of the heads over the floppy media, 0-based). + /// Physical head (0-based). + /// Logical sector ID. + bool? VerifySector(ushort track, byte head, ushort sector); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IFluxImage.cs b/Aaru.CommonTypes/Interfaces/IFluxImage.cs new file mode 100644 index 000000000..594ccbfb1 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IFluxImage.cs @@ -0,0 +1,130 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IFluxImage.cs +// Author(s) : Rebecca Wallander +// +// Component : Flux image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by flux image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Rebecca Wallander +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Enums; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Abstract class to implement flux reading plugins. +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] +public interface IFluxImage : IBaseImage +{ + /// + /// An image may have more than one capture for a specific head/track/sub-track combination. This returns + /// the amount of captures in the image for the specified head/track/sub-track combination. + /// + /// Error number + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// Physical sub-step of track (e.g. half-track) + /// The number of captures + ErrorNumber CapturesLength(uint head, ushort track, byte subTrack, out uint length); + + /// Reads the resolution (sample rate) of a index signal capture in picoseconds. + /// Error number + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// Physical sub-step of track (e.g. half-track) + /// Which capture to read. See also + /// The resolution of the index capture in picoseconds + ErrorNumber ReadFluxIndexResolution(uint head, ushort track, byte subTrack, uint captureIndex, + out ulong resolution); + + /// Reads the resolution (sample rate) of a data signal capture in picoseconds. + /// Error number + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// Physical sub-step of track (e.g. half-track) + /// Which capture to read. See also + /// The resolution of the data capture in picoseconds + ErrorNumber ReadFluxDataResolution(uint head, ushort track, byte subTrack, uint captureIndex, out ulong resolution); + + /// Reads the resolution (sample rate) of a flux capture in picoseconds. + /// Error number + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// Physical sub-step of track (e.g. half-track) + /// Which capture to read. See also + /// The resolution of the index capture in picoseconds + /// The resolution of the data capture in picoseconds + ErrorNumber ReadFluxResolution(uint head, ushort track, byte subTrack, uint captureIndex, out ulong indexResolution, + out ulong dataResolution); + + /// Reads the entire flux capture with index and data streams, as well as its resolution. + /// Error number + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// Physical sub-step of track (e.g. half-track) + /// Which capture to read. See also + /// The resolution (sample rate) of the index capture in picoseconds + /// The resolution (sample rate) of the data capture in picoseconds + /// Buffer to store the index stream in + /// Buffer to store the data stream in + ErrorNumber ReadFluxCapture(uint head, ushort track, byte subTrack, uint captureIndex, out ulong indexResolution, + out ulong dataResolution, out byte[] indexBuffer, out byte[] dataBuffer); + + /// Reads a capture's index stream. + /// Error number + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// Physical sub-step of track (e.g. half-track) + /// Which capture to read. See also + /// Buffer to store the data in + ErrorNumber ReadFluxIndexCapture(uint head, ushort track, byte subTrack, uint captureIndex, out byte[] buffer); + + /// Reads a capture's data stream. + /// Error number + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// Physical sub-step of track (e.g. half-track) + /// Which capture to read. See also + /// Buffer to store the data in + ErrorNumber ReadFluxDataCapture(uint head, ushort track, byte subTrack, uint captureIndex, out byte[] buffer); + + /// + /// An image may have tracks split into sub-steps. This returns the highest sub-step index for the track. + /// + /// Error number + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// The number of captures + ErrorNumber SubTrackLength(uint head, ushort track, out byte length); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IMediaGraph.cs b/Aaru.CommonTypes/Interfaces/IMediaGraph.cs new file mode 100644 index 000000000..94f2e5cfe --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IMediaGraph.cs @@ -0,0 +1,133 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IMediaGraph.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace Aaru.CommonTypes.Interfaces; + +/// Defines the interface to draw the dump or verification status of a media in a picture. +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] +public interface IMediaGraph +{ + /// Paints the specified sector in green + /// Sector + public void PaintSectorGood(ulong sector); + + /// Paints the specified sector in red + /// Sector + public void PaintSectorBad(ulong sector); + + /// Paints the specified sector in yellow + /// Sector + public void PaintSectorUnknown(ulong sector); + + /// Paints the specified sector in gray + /// Sector + public void PaintSectorUndumped(ulong sector); + + /// Paints a sector with the specified color + /// Sector + /// Red from 0 to 255 + /// Green from 0 to 255 + /// Blue from 0 to 255 + /// Opacity from 0 to 255 + public void PaintSector(ulong sector, byte red, byte green, byte blue, byte opacity = 0xFF); + + /// Paints sectors, staring at in gray + /// First sector to paint + /// How many sectors to paint + public void PaintSectorsUndumped(ulong startingSector, uint length); + + /// Paints sectors, staring at in green + /// First sector to paint + /// How many sectors to paint + public void PaintSectorsGood(ulong startingSector, uint length); + + /// Paints sectors, staring at in red + /// First sector to paint + /// How many sectors to paint + public void PaintSectorsBad(ulong startingSector, uint length); + + /// Paints sectors, staring at in yellow + /// First sector to paint + /// How many sectors to paint + public void PaintSectorsUnknown(ulong startingSector, uint length); + + /// Paints sectors, staring at in the specified color + /// First sector to paint + /// How many sectors to paint + /// Red from 0 to 255 + /// Green from 0 to 255 + /// Blue from 0 to 255 + /// Opacity from 0 to 255 + public void PaintSectors(ulong startingSector, uint length, byte red, byte green, byte blue, byte opacity = 0xFF); + + /// Paints the specified sectors in gray + /// List of sectors to paint + public void PaintSectorsUndumped(IEnumerable sectors); + + /// Paints the specified sectors in green + /// List of sectors to paint + public void PaintSectorsGood(IEnumerable sectors); + + /// Paints the specified sectors in red + /// List of sectors to paint + public void PaintSectorsBad(IEnumerable sectors); + + /// Paints the specified sectors in yellow + /// List of sectors to paint + public void PaintSectorsUnknown(IEnumerable sectors); + + /// Paints the specified sectors in the specified color + /// List of sectors to paint + /// Red from 0 to 255 + /// Green from 0 to 255 + /// Blue from 0 to 255 + /// Opacity from 0 to 255 + public void PaintSectorsUnknown(IEnumerable sectors, byte red, byte green, byte blue, byte opacity = 0xFF); + + /// Paints the information specific to recordable discs in green + public void PaintRecordableInformationGood(); + + /// Writes the graph bitmap as a PNG into the specified stream + /// Stream that will receive the spiral bitmap + public void WriteTo(Stream stream); + + /// Writes the graph bitmap as a PNG into the specified stream + /// Path to the file to save the PNG to + public void WriteTo(string path); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IMediaImage.cs b/Aaru.CommonTypes/Interfaces/IMediaImage.cs new file mode 100644 index 000000000..e0d4a07bd --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IMediaImage.cs @@ -0,0 +1,94 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IMediaImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines interface to be implemented by block addressable disk image +// plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using Aaru.CommonTypes.Enums; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Abstract class to implement disk image reading plugins. +public interface IMediaImage : IBaseImage +{ + /// Reads a disk tag. + /// + /// Tag type to read. + /// Disk tag + ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer); + + /// Reads a sector's user data. + /// The sector's user data. + /// Sector address (LBA). + /// + ErrorNumber ReadSector(ulong sectorAddress, out byte[] buffer); + + /// Reads a complete sector (user data + all tags). + /// The complete sector. Format depends on disk type. + /// Sector address (LBA). + /// + ErrorNumber ReadSectorLong(ulong sectorAddress, out byte[] buffer); + + /// Reads user data from several sectors. + /// The sectors user data. + /// Starting sector address (LBA). + /// How many sectors to read. + /// + ErrorNumber ReadSectors(ulong sectorAddress, uint length, out byte[] buffer); + + /// Reads several complete sector (user data + all tags). + /// The complete sectors. Format depends on disk type. + /// Starting sector address (LBA). + /// How many sectors to read. + /// + ErrorNumber ReadSectorsLong(ulong sectorAddress, uint length, out byte[] buffer); + + /// Reads tag from several sectors. + /// The sectors tag. + /// Starting sector address (LBA). + /// How many sectors to read. + /// Tag type. + /// + ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag, out byte[] buffer); + + /// Reads a sector's tag. + /// The sector's tag. + /// Sector address (LBA). + /// Tag type. + /// + ErrorNumber ReadSectorTag(ulong sectorAddress, SectorTagType tag, out byte[] buffer); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IOpticalMediaImage.cs b/Aaru.CommonTypes/Interfaces/IOpticalMediaImage.cs new file mode 100644 index 000000000..dc433853d --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IOpticalMediaImage.cs @@ -0,0 +1,127 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IOpticalMediaImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by optical disc image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Abstract class to implement disk image reading plugins. +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +public interface IOpticalMediaImage : IMediaImage, IPartitionableMediaImage, IVerifiableSectorsImage +{ + /// Gets the disc track extents (start, length). + /// The track extents. + List Tracks { get; } + + /// Gets the sessions (optical discs only). + /// The sessions. + List Sessions { get; } + + /// Reads a sector's user data, relative to track. + /// The sector's user data. + /// Sector address (relative LBA). + /// Track. + /// + ErrorNumber ReadSector(ulong sectorAddress, uint track, out byte[] buffer); + + /// Reads a sector's tag, relative to track. + /// The sector's tag. + /// Sector address (relative LBA). + /// Track. + /// Tag type. + /// + ErrorNumber ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag, out byte[] buffer); + + /// Reads user data from several sectors, relative to track. + /// The sectors user data. + /// Starting sector address (relative LBA). + /// How many sectors to read. + /// Track. + /// + ErrorNumber ReadSectors(ulong sectorAddress, uint length, uint track, out byte[] buffer); + + /// Reads tag from several sectors, relative to track. + /// The sectors tag. + /// Starting sector address (relative LBA). + /// How many sectors to read. + /// Track. + /// Tag type. + /// + ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag, out byte[] buffer); + + /// Reads a complete sector (user data + all tags), relative to track. + /// The complete sector. Format depends on disk type. + /// Sector address (relative LBA). + /// Track. + /// + ErrorNumber ReadSectorLong(ulong sectorAddress, uint track, out byte[] buffer); + + /// Reads several complete sector (user data + all tags), relative to track. + /// The complete sectors. Format depends on disk type. + /// Starting sector address (relative LBA). + /// How many sectors to read. + /// Track. + /// + ErrorNumber ReadSectorsLong(ulong sectorAddress, uint length, uint track, out byte[] buffer); + + /// Gets the disc track extents for a specified session. + /// The track extents for that session. + /// Session. + List GetSessionTracks(Session session); + + /// Gets the disc track extents for a specified session. + /// The track extents for that session. + /// Session. + List GetSessionTracks(ushort session); + + /// Verifies several sectors, relative to track. + /// True if all are correct, false if any is incorrect, null if any is uncheckable. + /// Starting sector address (relative LBA). + /// How many sectors to read. + /// Track. + /// List of incorrect sectors + /// List of uncheckable sectors + bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List failingLbas, + out List unknownLbas); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IPartition.cs b/Aaru.CommonTypes/Interfaces/IPartition.cs new file mode 100644 index 000000000..173bf0048 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IPartition.cs @@ -0,0 +1,63 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IPartition.cs +// Author(s) : Natalia Portillo +// +// Component : Partitioning scheme plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines methods to be used by partitioning scheme plugins and several +// constants. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Aaru.CommonTypes.Interfaces; + +/// Abstract class to implement partitioning schemes interpreting plugins. +public interface IPartition +{ + /// Plugin name. + string Name { get; } + + /// Plugin UUID. + Guid Id { get; } + + /// Plugin author + string Author { get; } + + /// Interprets a partitioning scheme. + /// true, if partitioning scheme is recognized, false otherwise. + /// Disk image. + /// Returns list of partitions. + /// At which sector to start searching for the partition scheme. + bool GetInformation(IMediaImage imagePlugin, out List partitions, ulong sectorOffset); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IPartitionableMediaImage.cs b/Aaru.CommonTypes/Interfaces/IPartitionableMediaImage.cs new file mode 100644 index 000000000..45c680e27 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IPartitionableMediaImage.cs @@ -0,0 +1,53 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IPartitionableMediaImage.cs +// Author(s) : Natalia Portillo +// +// Component : Media image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by image plugins that can +// contain partitioned medias, usually optical discs and some newer tapes. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; + +namespace Aaru.CommonTypes.Interfaces; + +/// Defines an image that can contain partitions +public interface IPartitionableMediaImage +{ + /// + /// Gets an array partitions. Typically only useful for optical disc images where each track and index means a + /// different partition, as reads can be relative to them. + /// + /// The partitions. + List Partitions { get; } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IPluginRegister.cs b/Aaru.CommonTypes/Interfaces/IPluginRegister.cs new file mode 100644 index 000000000..f1f0b8e58 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IPluginRegister.cs @@ -0,0 +1,113 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IPluginsRegister.cs +// Author(s) : Natalia Portillo +// +// Component : Interfaces. +// +// --[ Description ] ---------------------------------------------------------- +// +// Interface that declares class and methods to call to register plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.DependencyInjection; + +namespace Aaru.CommonTypes.Interfaces; + +/// Defines a register of all known plugins +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public interface IPluginRegister +{ + /// + /// Registers all checksum plugins in the provided service collection + /// + /// Service collection + void RegisterChecksumPlugins(IServiceCollection services); + + /// + /// Registers all filesystem plugins in the provided service collection + /// + /// Service collection + void RegisterFilesystemPlugins(IServiceCollection services); + + /// + /// Registers all filter plugins in the provided service collection + /// + /// Service collection + void RegisterFilterPlugins(IServiceCollection services); + + /// + /// Registers all floppy image plugins in the provided service collection + /// + /// Service collection + void RegisterFloppyImagePlugins(IServiceCollection services); + + /// + /// Registers all media image plugins in the provided service collection + /// + /// Service collection + void RegisterMediaImagePlugins(IServiceCollection services); + + /// + /// Registers all partition plugins in the provided service collection + /// + /// Service collection + void RegisterPartitionPlugins(IServiceCollection services); + + /// + /// Registers all read-only filesystem plugins in the provided service collection + /// + /// Service collection + void RegisterReadOnlyFilesystemPlugins(IServiceCollection services); + + /// + /// Registers all writable floppy image plugins in the provided service collection + /// + /// Service collection + void RegisterWritableFloppyImagePlugins(IServiceCollection services); + + /// + /// Registers all writable media image plugins in the provided service collection + /// + /// Service collection + void RegisterWritableImagePlugins(IServiceCollection services); + + /// + /// Registers all archive plugins in the provided service collection + /// + /// Service collection + void RegisterArchivePlugins(IServiceCollection services); + + /// + /// Registers all byte addressable media image plugins in the provided service collection + /// + /// Service collection + void RegisterByteAddressablePlugins(IServiceCollection services); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IReadOnlyFilesystem.cs b/Aaru.CommonTypes/Interfaces/IReadOnlyFilesystem.cs new file mode 100644 index 000000000..48521de2c --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IReadOnlyFilesystem.cs @@ -0,0 +1,202 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IReadOnlyFilesystem.cs +// Author(s) : Natalia Portillo +// +// Component : Filesystem plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Interface for filesystem plugins that offer read-only support of their +// contents. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; +using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes; +using FileSystemInfo = Aaru.CommonTypes.Structs.FileSystemInfo; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Defines the interface to implement reading the contents of a filesystem +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] +public interface IReadOnlyFilesystem : IFilesystem +{ + /// Information about the filesystem as expected by Aaru Metadata + FileSystem Metadata { get; } + + /// Retrieves a list of options supported by the filesystem, with name, type and description + IEnumerable<(string name, Type type, string description)> SupportedOptions { get; } + + /// Supported namespaces + Dictionary Namespaces { get; } + + /// + /// Initializes whatever internal structures the filesystem plugin needs to be able to read files and directories + /// from the filesystem. + /// + /// + /// + /// Which encoding to use for this filesystem. + /// Dictionary of key=value pairs containing options to pass to the filesystem + /// Filename namespace + ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace); + + /// Frees all internal structures created by + ErrorNumber Unmount(); + + /// Gets the attributes of a file or directory + /// Error number. + /// File path. + /// File attributes. + ErrorNumber GetAttributes(string path, out FileAttributes attributes); + + /// Lists all extended attributes, alternate data streams and forks of the given file. + /// Error number. + /// Path. + /// List of extended attributes, alternate data streams and forks. + ErrorNumber ListXAttr(string path, out List xattrs); + + /// Reads an extended attribute, alternate data stream or fork from the given file. + /// Error number. + /// File path. + /// Extended attribute, alternate data stream or fork name. + /// Buffer. + ErrorNumber GetXattr(string path, string xattr, ref byte[] buf); + + /// Gets information about the mounted volume. + /// Information about the mounted volume. + ErrorNumber StatFs(out FileSystemInfo stat); + + /// Gets information about a file or directory. + /// File path. + /// File information. + ErrorNumber Stat(string path, out FileEntryInfo stat); + + /// Solves a symbolic link. + /// Link path. + /// Link destination. + ErrorNumber ReadLink(string path, out string dest); + + /// Opens a file for reading. + /// Path to the file. + /// Represents the opened file and is needed for other file-related operations. + /// Error number + ErrorNumber OpenFile(string path, out IFileNode node); + + /// Closes a file, freeing any private data allocated on opening. + /// The file node. + /// Error number. + ErrorNumber CloseFile(IFileNode node); + + /// Move the file node position pointer to the specified position with the specified origin + /// The file node. + /// Desired position. + /// From where in the file to move the position pointer to. + /// Error number. + ErrorNumber Seek(IFileNode node, long position, SeekOrigin origin) + { + if(node is null) return ErrorNumber.InvalidArgument; + + long desiredPosition = origin switch + { + SeekOrigin.Begin => position, + SeekOrigin.End => node.Length + position, + _ => node.Offset + position + }; + + if(desiredPosition < 0) return ErrorNumber.InvalidArgument; + + if(desiredPosition >= node.Length) return ErrorNumber.InvalidArgument; + + node.Offset = desiredPosition; + + return ErrorNumber.NoError; + } + + /// Reads data from a file (main/only data stream or data fork). + /// File node. + /// Bytes to read. + /// Buffer. Must exist and be of size equal or bigger than + /// How many bytes were read into the buffer + ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read); + + /// Opens a directory for listing. + /// Path to the directory. + /// Represents the opened directory and is needed for other directory-related operations. + /// Error number + ErrorNumber OpenDir(string path, out IDirNode node); + + /// Closes a directory, freeing any private data allocated on opening. + /// The directory node. + /// Error number. + ErrorNumber CloseDir(IDirNode node); + + /// Reads the next entry in the directory. + /// Represent an opened directory. + /// + /// The next entry name. + /// null + /// if there are no more entries. + /// + /// Error number. + ErrorNumber ReadDir(IDirNode node, out string filename); +} + +/// Represents an opened file from a filesystem +[SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] +public interface IFileNode +{ + /// Path to the file + string Path { get; } + + /// File length + long Length { get; } + + /// Current position in file + long Offset { get; set; } +} + +/// Represents an opened directory from a filesystem +[SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] +public interface IDirNode +{ + /// Path to the directory + string Path { get; } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/ITapeImage.cs b/Aaru.CommonTypes/Interfaces/ITapeImage.cs new file mode 100644 index 000000000..39f693a4c --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/ITapeImage.cs @@ -0,0 +1,57 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ITapeImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by block addressable sequential +// tape image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using Aaru.CommonTypes.Structs; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Defines an image that can store the information from streaming, digital, tapes +public interface ITapeImage : IMediaImage +{ + /// Gets a list of all the files registered in the image + List Files { get; } + + /// Gets a list of all the partitions registered in the image + List TapePartitions { get; } + + /// If the media is a really a tape, as some formats can store non-tapes + bool IsTape { get; } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IVerifiableImage.cs b/Aaru.CommonTypes/Interfaces/IVerifiableImage.cs new file mode 100644 index 000000000..bc00d298a --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IVerifiableImage.cs @@ -0,0 +1,48 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IVerifiableImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines interface to be implemented by image plugins that can verify the +// image itself. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.CommonTypes.Interfaces; + +/// Defines an image that can verify the integrity of the image itself, but not its contents +public interface IVerifiableImage +{ + /// Verifies media image internal checksum. + /// True if correct, false if incorrect, null if there is no internal checksum available + bool? VerifyMediaImage(); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IVerifiableSectorsImage.cs b/Aaru.CommonTypes/Interfaces/IVerifiableSectorsImage.cs new file mode 100644 index 000000000..78ea59897 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IVerifiableSectorsImage.cs @@ -0,0 +1,62 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IVerifiableSectorsImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines interface to be implemented by image plugins that can verify the +// sectors contained in the image. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.CommonTypes.Interfaces; + +/// Defines an image that can verify the integrity of the sectors it contains +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +public interface IVerifiableSectorsImage +{ + /// Verifies a sector. + /// True if correct, false if incorrect, null if uncheckable. + /// Sector address (LBA). + bool? VerifySector(ulong sectorAddress); + + /// Verifies several sectors. + /// True if all are correct, false if any is incorrect, null if any is uncheckable. + /// Starting sector address (LBA). + /// How many sectors to read. + /// List of incorrect sectors + /// List of uncheckable sectors + bool? VerifySectors(ulong sectorAddress, uint length, out List failingLbas, out List unknownLbas); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IWritableFloppyImage.cs b/Aaru.CommonTypes/Interfaces/IWritableFloppyImage.cs new file mode 100644 index 000000000..949ada66d --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IWritableFloppyImage.cs @@ -0,0 +1,98 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IFloppyImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by floppy image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// +/// Abstract class to implement disk image reading plugins that can contain floppy images. This interface is +/// needed because floppy formatting characteristics are not necessarily compatible with the whole LBA-oriented +/// interface defined by . All data expected by these methods +/// is already decoded from its corresponding bitstream. +/// +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public interface IWritableFloppyImage : IFloppyImage, IWritableImage +{ + /// + /// Indicates the image plugin the floppy physical characteristics and must be called before following methods are + /// called. Once this is called, LBA-based methods should not be used. + /// + /// + /// Floppy info, contains information about physical characteristics of floppy, like size, bitrate, + /// track density, etc... + /// + /// true if operating completed successfully, false otherwise + bool SetFloppyCharacteristics(FloppyInfo info); + + /// Writes a sector's user data. + /// + /// If is one of the duplicates. If + /// is , , + /// it will be ignored. Otherwise, whatever data should be in the sector. + /// + /// Physical track (position of the heads over the floppy media, 0-based). + /// Physical head (0-based). + /// Logical sector ID. + /// Status of sector. + /// true if operating completed successfully, false otherwise + bool WriteSector(byte[] data, ushort track, byte head, ushort sector, FloppySectorStatus status); + + /// Writes a whole track, including all gaps, address marks, sectors data, etc. + /// The track data. + /// Physical track (position of the heads over the floppy media, 0-based). + /// Physical head (0-based). + /// true if operating completed successfully, false otherwise + bool WriteTrack(byte[] data, ushort track, byte head); + + /// Writes a sector's data including all tags, address mark, and so, in a format dependent of represented media. + /// + /// If is one of the duplicates. If + /// is , , + /// it will be ignored. Otherwise, whatever data should be in the sector. + /// + /// Physical track (position of the heads over the floppy media, 0-based). + /// Physical head (0-based). + /// Logical sector ID. + /// Status of request. + /// true if operating completed successfully, false otherwise + bool WriteSectorLong(byte[] data, ushort track, byte head, ushort sector, out FloppySectorStatus status); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IWritableFluxImage.cs b/Aaru.CommonTypes/Interfaces/IWritableFluxImage.cs new file mode 100644 index 000000000..06e47138c --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IWritableFluxImage.cs @@ -0,0 +1,85 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IWritableFluxImage.cs +// Author(s) : Rebecca Wallander +// +// Component : Writable flux image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by writable flux image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Rebecca Wallander +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Enums; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Abstract class to implement flux writing plugins. +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedParameter.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +public interface IWritableFluxImage : IFluxImage, IWritableImage +{ + /// Writes a flux capture. + /// Error number + /// The index capture's resolution (sample rate) in picoseconds + /// The capture's resolution (sample rate) in picoseconds + /// Flux representation of the index signal + /// Flux representation of the data signal + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// Physical sub-step of track (e.g. half-track) + /// Which capture slot to write to. See also + ErrorNumber WriteFluxCapture(ulong indexResolution, ulong dataResolution, byte[] indexBuffer, byte[] dataBuffer, + uint head, ushort track, byte subTrack, uint captureIndex); + + /// Writes a capture's index stream. + /// Error number + /// The capture's resolution (sample rate) in picoseconds + /// Flux representation of the index signal + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// Physical sub-step of track (e.g. half-track) + /// Which capture to read. See also + ErrorNumber WriteFluxIndexCapture(ulong resolution, byte[] index, uint head, ushort track, byte subTrack, + uint captureIndex); + + /// Writes a capture's data stream. + /// Error number + /// The capture's resolution (sample rate) in picoseconds + /// Flux representation of the data signal + /// Physical head (0-based) + /// Physical track (position of the heads over the floppy media, 0-based) + /// Physical sub-step of track (e.g. half-track) + /// Which capture to read. See also + ErrorNumber WriteFluxDataCapture(ulong resolution, byte[] data, uint head, ushort track, byte subTrack, + uint captureIndex); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IWritableImage.cs b/Aaru.CommonTypes/Interfaces/IWritableImage.cs new file mode 100644 index 000000000..2c3ef0efe --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IWritableImage.cs @@ -0,0 +1,105 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IWritableImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by writable block addressable image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using Aaru.CommonTypes.Enums; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// +/// Abstract class to implement disk image writing plugins. TODO: This interface is subject to change until +/// notice. +/// +public interface IWritableImage : IMediaImage, IBaseWritableImage +{ + /// Sets media geometry + /// Cylinders + /// Heads + /// Sectors per track + /// true if operating completed successfully, false otherwise + bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack); + + /// Writes a media tag to the image + /// Media tag + /// + /// + /// + /// true if operating completed successfully, false otherwise + bool WriteMediaTag(byte[] data, MediaTagType tag); + + /// Writes a sector to the image + /// Sector data + /// Sector address + /// true if operating completed successfully, false otherwise + bool WriteSector(byte[] data, ulong sectorAddress); + + /// Writes a sector to the image with main channel tags attached + /// Sector data with its main channel tags attached + /// Sector address + /// true if operating completed successfully, false otherwise + bool WriteSectorLong(byte[] data, ulong sectorAddress); + + /// Writes several sectors to the image + /// Sectors data + /// Sector starting address + /// How many sectors to write + /// true if operating completed successfully, false otherwise + bool WriteSectors(byte[] data, ulong sectorAddress, uint length); + + /// Writes several sectors to the image + /// Sector data with their main channel tags attached + /// Sector starting address + /// How many sectors to write + /// true if operating completed successfully, false otherwise + bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length); + + /// Writes parallel or subchannel sector tag for several sector + /// Tag data to write + /// Starting sector address + /// How many sectors to write + /// Tag type + /// true if operating completed successfully, false otherwise + bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag); + + /// Writes parallel or subchannel sector tag for one sector + /// Tag data to write + /// Sector address + /// Tag type + /// true if operating completed successfully, false otherwise + bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IWritableOpticalImage.cs b/Aaru.CommonTypes/Interfaces/IWritableOpticalImage.cs new file mode 100644 index 000000000..21824fec1 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IWritableOpticalImage.cs @@ -0,0 +1,56 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IWritableOpticalImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by writable image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Defines an image that is writable and can store an optical disc (CD, DVD, etc) +public interface IWritableOpticalImage : IWritableImage, IOpticalMediaImage +{ + /// Image format capabilities + OpticalImageCapabilities OpticalCapabilities { get; } + + /// Sets tracks for optical media + /// List of tracks + /// true if operating completed successfully, false otherwise + bool SetTracks(List tracks); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interfaces/IWritableTapeImage.cs b/Aaru.CommonTypes/Interfaces/IWritableTapeImage.cs new file mode 100644 index 000000000..9b158e123 --- /dev/null +++ b/Aaru.CommonTypes/Interfaces/IWritableTapeImage.cs @@ -0,0 +1,66 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IWritableTapeImage.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines the interface to be implemented by writable block addressable +// sequential tape image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Structs; + +namespace Aaru.CommonTypes.Interfaces; + +/// +/// Defines an image that is writable and can store information about a streaming, digital, tape +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +public interface IWritableTapeImage : ITapeImage, IWritableImage +{ + /// Registers a new file in the image + /// Tape file descriptor + /// true if successful, false otherwise + bool AddFile(TapeFile file); + + /// Registers a new partition + /// Tape partition descriptor + /// true if successful, false otherwise + bool AddPartition(TapePartition partition); + + /// + /// Tells the image plugin to set the internal structures to expect a tape (e.g. unknown block count and size). + /// Must be called before + /// + /// true if successful, false otherwise + bool SetTape(); +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interop/DetectOS.cs b/Aaru.CommonTypes/Interop/DetectOS.cs new file mode 100644 index 000000000..516ffae2a --- /dev/null +++ b/Aaru.CommonTypes/Interop/DetectOS.cs @@ -0,0 +1,435 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DetectOS.cs +// Author(s) : Natalia Portillo +// +// Component : Interop services. +// +// --[ Description ] ---------------------------------------------------------- +// +// Detects underlying operating system. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using System.Security.Principal; + +namespace Aaru.CommonTypes.Interop; + +/// Detects the underlying execution framework and operating system +public static partial class DetectOS +{ + /// Are we running under Mono? + public static readonly bool IsMono = + RuntimeInformation.FrameworkDescription.StartsWith("Mono", StringComparison.Ordinal); + /// Are we running under .NET Core? + public static readonly bool IsNetCore = + RuntimeInformation.FrameworkDescription.StartsWith(".NET Core", StringComparison.Ordinal); + + /// Checks if the underlying runtime runs in 64-bit mode + public static readonly bool Is64Bit = IntPtr.Size == 8; + + /// Are we running under Windows? + public static bool IsWindows => GetRealPlatformID() == PlatformID.Win32NT || + GetRealPlatformID() == PlatformID.Win32S || + GetRealPlatformID() == PlatformID.Win32Windows || + GetRealPlatformID() == PlatformID.WinCE || + GetRealPlatformID() == PlatformID.WindowsPhone || + GetRealPlatformID() == PlatformID.Xbox; + + /// Are we running with administrative (root) privileges? + public static bool IsAdmin + { + get + { + if(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return Environment.UserName == "root"; + + bool isAdmin; + WindowsIdentity user = null; + + try + { + user = WindowsIdentity.GetCurrent(); + var principal = new WindowsPrincipal(user); + isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator); + } + catch(UnauthorizedAccessException) + { + isAdmin = false; + } + catch(Exception) + { + isAdmin = false; + } + finally + { + user?.Dispose(); + } + + return isAdmin; + } + } + + [DllImport("libc", SetLastError = true)] + static extern int uname(out UtsName name); + + [LibraryImport("libc", + EntryPoint = "sysctlbyname", + SetLastError = true, + StringMarshalling = StringMarshalling.Custom, + StringMarshallingCustomType = typeof(AnsiStringMarshaller))] + private static partial int OSX_sysctlbyname(string name, IntPtr oldp, IntPtr oldlenp, IntPtr newp, uint newlen); + + /// Gets the real platform ID, not the incomplete .NET framework one + /// Platform ID + /// Unhandled exception + public static PlatformID GetRealPlatformID() + { + if((int)Environment.OSVersion.Platform < 4 || (int)Environment.OSVersion.Platform == 5) + return (PlatformID)(int)Environment.OSVersion.Platform; + + int error = uname(out UtsName unixname); + + if(error != 0) + { + throw new Exception(string.Format(Localization.Unhandled_exception_calling_uname_0, + Marshal.GetLastWin32Error())); + } + + switch(unixname.sysname) + { + // TODO: Differentiate Linux, Android, Tizen + case "Linux": + { +#if __ANDROID__ + return PlatformID.Android; +#else + return PlatformID.Linux; +#endif + } + + case "Darwin": + { + IntPtr pLen = Marshal.AllocHGlobal(sizeof(int)); + int osxError = OSX_sysctlbyname("hw.machine", IntPtr.Zero, pLen, IntPtr.Zero, 0); + + if(osxError != 0) + { + Marshal.FreeHGlobal(pLen); + + throw new Exception(string.Format(Localization.Unhandled_exception_calling_uname_0, + Marshal.GetLastWin32Error())); + } + + int length = Marshal.ReadInt32(pLen); + IntPtr pStr = Marshal.AllocHGlobal(length); + osxError = OSX_sysctlbyname("hw.machine", pStr, pLen, IntPtr.Zero, 0); + + if(osxError != 0) + { + Marshal.FreeHGlobal(pStr); + Marshal.FreeHGlobal(pLen); + + throw new Exception(string.Format(Localization.Unhandled_exception_calling_uname_0, + Marshal.GetLastWin32Error())); + } + + string machine = Marshal.PtrToStringAnsi(pStr); + + Marshal.FreeHGlobal(pStr); + Marshal.FreeHGlobal(pLen); + + if(machine != null && + (machine.StartsWith("iPad", StringComparison.Ordinal) || + machine.StartsWith("iPod", StringComparison.Ordinal) || + machine.StartsWith("iPhone", StringComparison.Ordinal))) + return PlatformID.iOS; + + return PlatformID.MacOSX; + } + + case "GNU": + return PlatformID.Hurd; + case "FreeBSD": + case "GNU/kFreeBSD": + return PlatformID.FreeBSD; + case "DragonFly": + return PlatformID.DragonFly; + case "Haiku": + return PlatformID.Haiku; + case "HP-UX": + return PlatformID.HPUX; + case "AIX": + return PlatformID.AIX; + case "OS400": + return PlatformID.OS400; + case "IRIX": + case "IRIX64": + return PlatformID.IRIX; + case "Minix": + return PlatformID.Minix; + case "NetBSD": + return PlatformID.NetBSD; + case "NONSTOP_KERNEL": + return PlatformID.NonStop; + case "OpenBSD": + return PlatformID.OpenBSD; + case "QNX": + return PlatformID.QNX; + case "SINIX-Y": + return PlatformID.SINIX; + case "SunOS": + return PlatformID.Solaris; + case "OSF1": + return PlatformID.Tru64; + case "ULTRIX": + return PlatformID.Ultrix; + case "SCO_SV": + return PlatformID.OpenServer; + case "UnixWare": + return PlatformID.UnixWare; + case "Interix": + case "UWIN-W7": + return PlatformID.Win32NT; + default: + { + if(unixname.sysname.StartsWith("CYGWIN_NT", StringComparison.Ordinal) || + unixname.sysname.StartsWith("MINGW32_NT", StringComparison.Ordinal) || + unixname.sysname.StartsWith("MSYS_NT", StringComparison.Ordinal) || + unixname.sysname.StartsWith("UWIN", StringComparison.Ordinal)) + return PlatformID.Win32NT; + + return PlatformID.Unknown; + } + } + } + + /// Gets a string for the current operating system REAL version (handles Darwin 1.4 and Windows 10 falsifying) + /// Current operating system version + public static string GetVersion() + { + var environ = Environment.OSVersion.Version.ToString(); + + switch(GetRealPlatformID()) + { + case PlatformID.MacOSX: + if(Environment.OSVersion.Version.Major >= 11) return environ; + + if(Environment.OSVersion.Version.Major != 1) + return $"10.{Environment.OSVersion.Version.Major - 4}.{Environment.OSVersion.Version.Minor}"; + + switch(Environment.OSVersion.Version.Minor) + { + case 3: + return "10.0"; + case 4: + return "10.1"; + } + + goto default; + case PlatformID.Win32NT: + // From Windows 8.1 the reported version is simply falsified... + if(Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 2 || + Environment.OSVersion.Version.Major > 6) + { + return FileVersionInfo + .GetVersionInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), + "KERNEL32.DLL")) + .ProductVersion; + } + + return environ; + default: + return environ; + } + } + + /// From a platform ID and version returns a human-readable version + /// Platform ID + /// Version number + /// Operating system name + public static string GetPlatformName(PlatformID id, string version = null) + { + switch(id) + { + case PlatformID.AIX: + return "AIX"; + case PlatformID.Android: + return "Android"; + case PlatformID.DragonFly: + return "DragonFly BSD"; + case PlatformID.FreeBSD: + return "FreeBSD"; + case PlatformID.Haiku: + return "Haiku"; + case PlatformID.HPUX: + return "HP/UX"; + case PlatformID.Hurd: + return "Hurd"; + case PlatformID.iOS: + return "iOS"; + case PlatformID.IRIX: + return "IRIX"; + case PlatformID.Linux: + if(!File.Exists("/proc/version")) return "Linux"; + + string s = File.ReadAllText("/proc/version"); + + return s.Contains("Microsoft") || s.Contains("WSL") ? "Windows Subsystem for Linux" : "Linux"; + + case PlatformID.MacOSX: + if(string.IsNullOrEmpty(version)) return "macOS"; + + string[] pieces = version.Split('.'); + + if(pieces.Length < 2 || !int.TryParse(pieces[1], out int minor)) return "macOS"; + + int.TryParse(pieces[0], out int major); + + if(minor >= 12 || major >= 11) return "macOS"; + + return minor >= 8 ? "OS X" : "Mac OS X"; + + case PlatformID.Minix: + return "MINIX"; + case PlatformID.NetBSD: + return "NetBSD"; + case PlatformID.NonStop: + return "NonStop OS"; + case PlatformID.OpenBSD: + return "OpenBSD"; + case PlatformID.OpenServer: + return "SCO OpenServer"; + case PlatformID.OS400: + return "OS/400"; + case PlatformID.PlayStation3: + return "Sony CellOS"; + case PlatformID.PlayStation4: + return "Sony Orbis OS"; + case PlatformID.QNX: + return "QNX"; + case PlatformID.SINIX: + return "SINIX"; + case PlatformID.Solaris: + return "Sun Solaris"; + case PlatformID.Tizen: + return "Samsung Tizen"; + case PlatformID.Tru64: + return "Tru64 UNIX"; + case PlatformID.Ultrix: + return "Ultrix"; + case PlatformID.Unix: + return "UNIX"; + case PlatformID.UnixWare: + return "SCO UnixWare"; + case PlatformID.Wii: + return "Nintendo Wii"; + case PlatformID.WiiU: + return "Nintendo Wii U"; + case PlatformID.Win32NT: + if(string.IsNullOrEmpty(version)) return "Windows NT/2000/XP/Vista/7/10"; + + if(version.StartsWith("3.", StringComparison.Ordinal) || + version.StartsWith("4.", StringComparison.Ordinal)) + return "Windows NT"; + + if(version.StartsWith("5.0", StringComparison.Ordinal)) return "Windows 2000"; + + if(version.StartsWith("5.1", StringComparison.Ordinal)) return "Windows XP"; + + if(version.StartsWith("5.2", StringComparison.Ordinal)) return "Windows 2003"; + + if(version.StartsWith("6.0", StringComparison.Ordinal)) return "Windows Vista"; + + if(version.StartsWith("6.1", StringComparison.Ordinal)) return "Windows 7"; + + if(version.StartsWith("6.2", StringComparison.Ordinal)) return "Windows 8"; + + if(version.StartsWith("6.3", StringComparison.Ordinal)) return "Windows 8.1"; + + if(version.StartsWith("10.0", StringComparison.Ordinal)) return "Windows 10"; + + return version.StartsWith("11.0", StringComparison.Ordinal) + ? "Windows 11" + : "Windows NT/2000/XP/Vista/7/10/11"; + + case PlatformID.Win32S: + return "Windows 3.x with win32s"; + case PlatformID.Win32Windows: + if(string.IsNullOrEmpty(version)) return "Windows 9x/Me"; + + if(version.StartsWith("4.0", StringComparison.Ordinal)) return "Windows 95"; + + if(version.StartsWith("4.10.2222", StringComparison.Ordinal)) return "Windows 98 SE"; + + if(version.StartsWith("4.1", StringComparison.Ordinal)) return "Windows 98"; + + return version.StartsWith("4.9", StringComparison.Ordinal) ? "Windows Me" : "Windows 9x/Me"; + + case PlatformID.WinCE: + return "Windows CE/Mobile"; + case PlatformID.WindowsPhone: + return "Windows Phone"; + case PlatformID.Xbox: + return "Xbox OS"; + case PlatformID.zOS: + return "z/OS"; + default: + return id.ToString(); + } + } + +#region Nested type: UtsName + + /// POSIX uname structure, size from OSX, big enough to handle extra fields + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + struct UtsName + { + /// System name + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public readonly string sysname; + /// Node name + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public readonly string nodename; + /// Release level + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public readonly string release; + /// Version level + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public readonly string version; + /// Hardware level + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public readonly string machine; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interop/PlatformID.cs b/Aaru.CommonTypes/Interop/PlatformID.cs new file mode 100644 index 000000000..a4521e983 --- /dev/null +++ b/Aaru.CommonTypes/Interop/PlatformID.cs @@ -0,0 +1,121 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PlatformID.cs +// Author(s) : Natalia Portillo +// +// Component : Interop services. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains an enhanced PlatformID enumeration. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.CommonTypes.Interop; + +/// Contains an arbitrary list of OSes, even if .NET does not run on them +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum PlatformID +{ + /// Win32s + Win32S = 0, + /// Win32 (Windows 9x) + Win32Windows = 1, + /// Windows NT + Win32NT = 2, + /// Windows Mobile + WinCE = 3, + /// UNIX (do not use, too generic) + Unix = 4, + /// Xbox 360 + Xbox = 5, + /// OS X + MacOSX = 6, + /// iOS is not OS X + iOS = 7, + /// Linux + Linux = 8, + /// Sun Solaris + Solaris = 9, + /// NetBSD + NetBSD = 10, + /// OpenBSD + OpenBSD = 11, + /// FreeBSD + FreeBSD = 12, + /// DragonFly BSD + DragonFly = 13, + /// Nintendo Wii + Wii = 14, + /// Nintendo Wii U + WiiU = 15, + /// Sony PlayStation 3 + PlayStation3 = 16, + /// Sony Playstation 4 + PlayStation4 = 17, + /// Google Android + Android = 18, + /// Samsung Tizen + Tizen = 19, + /// Windows Phone + WindowsPhone = 20, + /// GNU/Hurd + Hurd = 21, + /// Haiku + Haiku = 22, + /// HP-UX + HPUX = 23, + /// AIX + AIX = 24, + /// OS/400 + OS400 = 25, + /// IRIX + IRIX = 26, + /// Minix + Minix = 27, + /// NonStop + NonStop = 28, + /// QNX + QNX = 29, + /// SINIX + SINIX = 30, + /// Tru64 UNIX + Tru64 = 31, + /// Ultrix + Ultrix = 32, + /// SCO OpenServer / SCO UNIX + OpenServer = 33, + /// SCO UnixWare + UnixWare = 34, + /// IBM z/OS + zOS = 35, + /// Unknown + Unknown = -1 +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Interop/Version.cs b/Aaru.CommonTypes/Interop/Version.cs new file mode 100644 index 000000000..467a3ecde --- /dev/null +++ b/Aaru.CommonTypes/Interop/Version.cs @@ -0,0 +1,86 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Version.cs +// Author(s) : Natalia Portillo +// +// Component : Interop services. +// +// --[ Description ] ---------------------------------------------------------- +// +// Returns Aaru version. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime; + +namespace Aaru.CommonTypes.Interop; + +/// Gets our own, or the runtime's version +public static class Version +{ + /// Gets version string + /// Version + public static string GetVersion() => typeof(Version).Assembly.GetName().Version?.ToString(); + + /// Gets .NET Core version + /// Version + public static string GetNetCoreVersion() + { + Assembly assembly = typeof(GCSettings).Assembly; + + string[] assemblyPath = assembly.CodeBase?.Split(new[] + { + '/', '\\' + }, + StringSplitOptions.RemoveEmptyEntries); + + if(assemblyPath is null) return null; + + int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App"); + + if(netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2) return assemblyPath[netCoreAppIndex + 1]; + + return null; + } + + /// Gets Mono version + /// Version + public static string GetMonoVersion() + { + if(!DetectOS.IsMono) return null; + + MethodInfo monoDisplayName = Type.GetType("Mono.Runtime") + ?.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); + + if(monoDisplayName != null) return (string)monoDisplayName.Invoke(null, null); + + return null; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Localization/Localization.Designer.cs b/Aaru.CommonTypes/Localization/Localization.Designer.cs new file mode 100644 index 000000000..f275e3257 --- /dev/null +++ b/Aaru.CommonTypes/Localization/Localization.Designer.cs @@ -0,0 +1,1886 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Aaru.CommonTypes { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Localization { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Localization() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aaru.CommonTypes.Localization.Localization", typeof(Localization).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is SyQuest, media has 1961069 blocks of 512 bytes, setting media type to SparQ.. + /// + internal static string Drive_manufacturer_is_SyQuest_media_has_1961069_blocks_of_512_bytes_setting_media_type_to_SparQ { + get { + return ResourceManager.GetString("Drive_manufacturer_is_SyQuest_media_has_1961069_blocks_of_512_bytes_setting_media" + + "_type_to_SparQ", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception {0}. + /// + internal static string Exception_0 { + get { + return ResourceManager.GetString("Exception_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IDENTIFY response is different than 512 bytes, not decoding.. + /// + internal static string IDENTIFY_response_is_different_than_512_bytes_not_decoding { + get { + return ResourceManager.GetString("IDENTIFY_response_is_different_than_512_bytes_not_decoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to INQUIRY response is {0} bytes, less than minimum of 36 bytes, decoded data can be incorrect, not decoding.. + /// + internal static string INQUIRY_response_is_0_bytes_less_than_minimum_of_36_bytes { + get { + return ResourceManager.GetString("INQUIRY_response_is_0_bytes_less_than_minimum_of_36_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to INQUIRY response length ({0} bytes) is different than specified in length field ({1} bytes), decoded data can be incorrect, not decoding.. + /// + internal static string INQUIRY_response_length_0_bytes_is_different_than_specified_in_length_field { + get { + return ResourceManager.GetString("INQUIRY_response_length_0_bytes_is_different_than_specified_in_length_field", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Acorn formatted 5¼" double density floppy.. + /// + internal static string SCSI_Media_Type_Description_Acorn_MD1DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Acorn_MD1DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Acorn formatted 5¼" double density floppy with 80 tracks.. + /// + internal static string SCSI_Media_Type_Description_Acorn_MD1DD_80 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Acorn_MD1DD_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Acorn formatted 5¼" single density floppy.. + /// + internal static string SCSI_Media_Type_Description_Acorn_MD1SD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Acorn_MD1SD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Acorn formatted 3½" double density floppy.. + /// + internal static string SCSI_Media_Type_Description_Acorn_MF2DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Acorn_MF2DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Acorn formatted 3½" high density floppy.. + /// + internal static string SCSI_Media_Type_Description_Acorn_MF2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Acorn_MF2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Amiga formatted 3½" double density floppy.. + /// + internal static string SCSI_Media_Type_Description_Amiga_MF2DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Amiga_MF2DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Amiga formatted 3½" high density floppy.. + /// + internal static string SCSI_Media_Type_Description_Amiga_MF2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Amiga_MF2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apple DOS 3.2 formatted 5¼" floppy.. + /// + internal static string SCSI_Media_Type_Description_Apple_DOS32 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Apple_DOS32", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apple DOS 3.2 formatted 5¼" double sided floppy.. + /// + internal static string SCSI_Media_Type_Description_Apple_DOS32_DS { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Apple_DOS32_DS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apple DOS 3.3 formatted 5¼" floppy.. + /// + internal static string SCSI_Media_Type_Description_Apple_DOS33 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Apple_DOS33", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apple DOS 3.3 formatted 5¼" double sided floppy.. + /// + internal static string SCSI_Media_Type_Description_Apple_DOS33_DS { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Apple_DOS33_DS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apple formatted 3½" double density single sided floppy.. + /// + internal static string SCSI_Media_Type_Description_Apple_MF1DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Apple_MF1DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apricot formatted 3½" floppy.. + /// + internal static string SCSI_Media_Type_Description_Apricot_MF2DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Apricot_MF2DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Atari formatted 5¼" double density floppy.. + /// + internal static string SCSI_Media_Type_Description_Atari_MD1DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Atari_MD1DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Atari formatted 5¼" single density floppy.. + /// + internal static string SCSI_Media_Type_Description_Atari_MD1SD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Atari_MD1SD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is IOMEGA, media has {0} blocks of 256 bytes, setting media type to 10Mb Bernoulli Box.. + /// + internal static string SCSI_Media_Type_Description_Bernoulli10 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Bernoulli10", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is IOMEGA, media has 294918 blocks of 512 bytes, setting media type to 150Mb Bernoulli Box II.. + /// + internal static string SCSI_Media_Type_Description_Bernoulli2_150 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Bernoulli2_150", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is IOMEGA, media has 87040 blocks of 512 bytes, setting media type to 44Mb Bernoulli Box II.. + /// + internal static string SCSI_Media_Type_Description_Bernoulli2_44 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Bernoulli2_44", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is IOMEGA, media has 175856 blocks of 512 bytes, setting media type to 90Mb Bernoulli Box II.. + /// + internal static string SCSI_Media_Type_Description_Bernoulli2_90 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Bernoulli2_90", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to CompactTape.. + /// + internal static string SCSI_Media_Type_Description_CompactTape { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_CompactTape", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to CompactTape II.. + /// + internal static string SCSI_Media_Type_Description_CompactTapeII { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_CompactTapeII", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dat" setting media type to DAT72.. + /// + internal static string SCSI_Media_Type_Description_DAT72_dat { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DAT72_dat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to DDS.. + /// + internal static string SCSI_Media_Type_Description_DDS { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DDS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to DDS-2.. + /// + internal static string SCSI_Media_Type_Description_DDS2 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DDS2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dat" setting media type to DDS-2.. + /// + internal static string SCSI_Media_Type_Description_DDS2_dat { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DDS2_dat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to DDS-3.. + /// + internal static string SCSI_Media_Type_Description_DDS3 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DDS3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dat" setting media type to DDS-3.. + /// + internal static string SCSI_Media_Type_Description_DDS3_dat { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DDS3_dat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to DDS-4.. + /// + internal static string SCSI_Media_Type_Description_DDS4 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DDS4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dat" setting media type to DDS-4.. + /// + internal static string SCSI_Media_Type_Description_DDS4_alt { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DDS4_alt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to DEC RX02 floppy.. + /// + internal static string SCSI_Media_Type_Description_DEC_RX02 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DEC_RX02", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to DLTtape III.. + /// + internal static string SCSI_Media_Type_Description_DLTtapeIII { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DLTtapeIII", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to DLTtape IIIxt.. + /// + internal static string SCSI_Media_Type_Description_DLTtapeIIIxt { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DLTtapeIIIxt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to DLTtape IV.. + /// + internal static string SCSI_Media_Type_Description_DLTtapeIV { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DLTtapeIV", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Microsoft DMF formatted 3½" high density floppy.. + /// + internal static string SCSI_Media_Type_Description_DMF_MF2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_DMF_MF2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-154 / ISO 10090 conforming 3½" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA154 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA154", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-183 / ISO 13481 conforming 5¼" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA183 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA183", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-184 / ISO 13549 conforming 5¼" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA184 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA184", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-195 / ISO 13842 conforming 5¼" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA195 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA195", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-201 / ISO 13963 conforming 3½" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA201 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA201", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-201 / ISO 13963 conforming 3½" embossed magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA201_embossed { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA201_embossed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-223 conforming 3½" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA223 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA223", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-238 / ISO 15486 conforming 5¼" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA238 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA238", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-239 / ISO 15498 conforming 3½" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA239 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA239", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-260 / ISO 15898 conforming 356mm magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA260 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA260", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-280 / ISO 18093 conforming 5¼" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA280 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA280", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-317 / ISO 20162 conforming 300mm magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA317 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA317", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-322 / ISO 22092 conforming 5¼" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ECMA322 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA322", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-54 formatted 8" floppy.. + /// + internal static string SCSI_Media_Type_Description_ECMA54 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA54", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-56 formatted 5¼" double density floppy.. + /// + internal static string SCSI_Media_Type_Description_ECMA56 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA56", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-59 formatted 8" floppy.. + /// + internal static string SCSI_Media_Type_Description_ECMA59 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA59", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-66 formatted 5¼" floppy.. + /// + internal static string SCSI_Media_Type_Description_ECMA66 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA66", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-69 formatted 8" floppy.. + /// + internal static string SCSI_Media_Type_Description_ECMA69 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA69", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-70 formatted 5¼" floppy.. + /// + internal static string SCSI_Media_Type_Description_ECMA70 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA70", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-78 formatted 5¼" floppy.. + /// + internal static string SCSI_Media_Type_Description_ECMA78 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA78", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-99 formatted 5¼" floppy.. + /// + internal static string SCSI_Media_Type_Description_ECMA99 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ECMA99", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 106m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_106m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_106m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 112m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_112m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_112m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 125m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_125m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_125m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 150m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_150m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_150m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 15m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_15m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_15m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 160m Exatape XL.. + /// + internal static string SCSI_Media_Type_Description_Exatape_160m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_160m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 170m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_170m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_170m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 225m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_225m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_225m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 22m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_22m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_22m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 22m Exatape AME.. + /// + internal static string SCSI_Media_Type_Description_Exatape_22m_AME { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_22m_AME", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 28m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_28m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_28m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 40m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_40m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_40m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 45m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_45m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_45m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 54m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_54m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_54m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 75m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_75m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_75m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 76m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_76m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_76m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 80m Exatape.. + /// + internal static string SCSI_Media_Type_Description_Exatape_80m { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Exatape_80m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is SyQuest, media has 262144 blocks of 512 bytes, setting media type to EZ135.. + /// + internal static string SCSI_Media_Type_Description_EZ135 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_EZ135", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is SyQuest, media has 450560 blocks of 512 bytes, setting media type to EZ230.. + /// + internal static string SCSI_Media_Type_Description_EZ230 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_EZ230", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive model is LS (SuperDisk), media has 65536 blocks of 512 bytes, setting media type to FD32MB.. + /// + internal static string SCSI_Media_Type_Description_FD32MB { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_FD32MB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to FDFORMAT formatted 5¼" high density floppy.. + /// + internal static string SCSI_Media_Type_Description_FDFORMAT_MD2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_FDFORMAT_MD2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to FDFORMAT formatted 3½" double density floppy.. + /// + internal static string SCSI_Media_Type_Description_FDFORMAT_MF2DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_FDFORMAT_MF2DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to FDFORMAT formatted 3½" high density floppy.. + /// + internal static string SCSI_Media_Type_Description_FDFORMAT_MF2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_FDFORMAT_MF2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Floptical.. + /// + internal static string SCSI_Media_Type_Description_Floptical { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Floptical", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to GigaMO 3½" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_GigaMO { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_GigaMO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to GigaMO 2 3½" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_GigaMO2 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_GigaMO2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media has 46956 blocks of 256 bytes, setting media type to 12Mb HyperFlex.. + /// + internal static string SCSI_Media_Type_Description_HF12 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_HF12", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media has 78936 blocks of 256 bytes, setting media type to 24Mb HyperFlex.. + /// + internal static string SCSI_Media_Type_Description_HF24 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_HF24", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive model is HiFD, media has 393380 blocks of 512 bytes, setting media type to HiFD.. + /// + internal static string SCSI_Media_Type_Description_HiFD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_HiFD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Sony HiMD.. + /// + internal static string SCSI_Media_Type_Description_HiMD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_HiMD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 8" (23FD) floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_23FD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_23FD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 8" (33FD) floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_33FD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_33FD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 8" (43FD) floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_43FD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_43FD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 8" (53FD) floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_53FD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_53FD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 5¼" double density single sided floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_MD1DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MD1DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 5¼" double density single sided floppy (8 sectors).. + /// + internal static string SCSI_Media_Type_Description_IBM_MD1DD_8 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MD1DD_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 5¼" double density floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_MD2DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MD2DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 5¼" double density floppy (8 sectors).. + /// + internal static string SCSI_Media_Type_Description_IBM_MD2DD_8 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MD2DD_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 5¼" high density floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_MD2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MD2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" double density single sided floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_MF1DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MF1DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" double density single sided floppy (8 sectors).. + /// + internal static string SCSI_Media_Type_Description_IBM_MF1DD_8 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MF1DD_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" double density floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_MF2DD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MF2DD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" double density floppy (8 sectors).. + /// + internal static string SCSI_Media_Type_Description_IBM_MF2DD_8 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MF2DD_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" extra density floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_MF2ED { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MF2ED", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" high density floppy.. + /// + internal static string SCSI_Media_Type_Description_IBM_MF2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM_MF2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to IBM 3490.. + /// + internal static string SCSI_Media_Type_Description_IBM3490 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM3490", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to IBM 3490E.. + /// + internal static string SCSI_Media_Type_Description_IBM3490E { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM3490E", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is IBM, setting media type to IBM 3592.. + /// + internal static string SCSI_Media_Type_Description_IBM3592 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_IBM3592", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ISO 10089 conforming 5¼" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ISO10089 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ISO10089", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ISO 14517 conforming 5¼" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ISO14517 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ISO14517", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ISO 15041 conforming 3½" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ISO15041 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ISO15041", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ISO 15286 conforming 5¼" magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_ISO15286 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ISO15286", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is IOMEGA, drive model is JAZ, media has 2091050 blocks of 512 bytes, setting media type to 1Gb JAZ.. + /// + internal static string SCSI_Media_Type_Description_JAZ { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_JAZ", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is IOMEGA, drive model is JAZ, media has 3915600 blocks of 512 bytes, setting media type to 2Gb JAZ.. + /// + internal static string SCSI_Media_Type_Description_JAZ2 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_JAZ2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive model is LS (SuperDisk), media has 2880 blocks of 512 bytes, setting media type to PC-98 formatted 3½" high density floppy.. + /// + internal static string SCSI_Media_Type_Description_LS_PC98_MF2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LS_PC98_MF2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive model is LS (SuperDisk), media has 246528 blocks of 512 bytes, setting media type to LS-120.. + /// + internal static string SCSI_Media_Type_Description_LS120 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LS120", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive model is LS (SuperDisk), media has 469504 blocks of 512 bytes, setting media type to LS-240.. + /// + internal static string SCSI_Media_Type_Description_LS240 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LS240", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to LTO.. + /// + internal static string SCSI_Media_Type_Description_LTO { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LTO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO.. + /// + internal static string SCSI_Media_Type_Description_LTO_ult { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LTO_ult", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to LTO-2.. + /// + internal static string SCSI_Media_Type_Description_LTO2 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LTO2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-2.. + /// + internal static string SCSI_Media_Type_Description_LTO2_ult { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LTO2_ult", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-3.. + /// + internal static string SCSI_Media_Type_Description_LTO3 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LTO3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-4.. + /// + internal static string SCSI_Media_Type_Description_LTO4 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LTO4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-5.. + /// + internal static string SCSI_Media_Type_Description_LTO5 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LTO5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-6.. + /// + internal static string SCSI_Media_Type_Description_LTO6_ult { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LTO6_ult", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-7.. + /// + internal static string SCSI_Media_Type_Description_LTO7_ult { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_LTO7_ult", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 60 minute MiniDisc.. + /// + internal static string SCSI_Media_Type_Description_MD60 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_MD60", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI peripheral type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 60 minute MiniDisc.. + /// + internal static string SCSI_Media_Type_Description_MD60_MDDATA { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_MD60_MDDATA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 74 minute MiniDisc.. + /// + internal static string SCSI_Media_Type_Description_MD74 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_MD74", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI peripheral type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 74 minute MiniDisc.. + /// + internal static string SCSI_Media_Type_Description_MD74_MDDATA { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_MD74_MDDATA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 80 minute MiniDisc.. + /// + internal static string SCSI_Media_Type_Description_MD80 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_MD80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI peripheral type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 80 minute MiniDisc.. + /// + internal static string SCSI_Media_Type_Description_MD80_MDDATA { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_MD80_MDDATA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI peripheral type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to MiniDisc for Data.. + /// + internal static string SCSI_Media_Type_Description_MDDATA { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_MDDATA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to MetaFloppy formatted 5¼" double density single sided floppy.. + /// + internal static string SCSI_Media_Type_Description_MetaFloppy { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_MetaFloppy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive model is Castlewood Orb, media has 4307184 blocks of 512 bytes, setting media type to Orb.. + /// + internal static string SCSI_Media_Type_Description_Orb { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Orb", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to PC-98 formatted 5¼" high density floppy.. + /// + internal static string SCSI_Media_Type_Description_PC98_MD2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_PC98_MD2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to PC-98 formatted 3½" high density floppy (15 sectors).. + /// + internal static string SCSI_Media_Type_Description_PC98_MF2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_PC98_MF2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is IOMEGA, media has 78882 blocks of 512 bytes, setting media type to PocketZIP.. + /// + internal static string SCSI_Media_Type_Description_PocketZIP { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_PocketZIP", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to QIC-11.. + /// + internal static string SCSI_Media_Type_Description_QIC11 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_QIC11", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to QIC-120.. + /// + internal static string SCSI_Media_Type_Description_QIC120 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_QIC120", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to QIC-150.. + /// + internal static string SCSI_Media_Type_Description_QIC150 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_QIC150", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to QIC-24.. + /// + internal static string SCSI_Media_Type_Description_QIC24 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_QIC24", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive model is RDX, media has {0} blocks of {1} bytes, setting media type to RDX320.. + /// + internal static string SCSI_Media_Type_Description_RDX320 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_RDX320", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 120Gb REV.. + /// + internal static string SCSI_Media_Type_Description_REV120 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_REV120", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 35Gb REV.. + /// + internal static string SCSI_Media_Type_Description_REV35 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_REV35", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 70Gb REV.. + /// + internal static string SCSI_Media_Type_Description_REV70 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_REV70", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "sdz" setting media type to Super AIT.. + /// + internal static string SCSI_Media_Type_Description_SAIT { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_SAIT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to SuperDLT.. + /// + internal static string SCSI_Media_Type_Description_SDLT { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_SDLT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to SuperDLT 2.. + /// + internal static string SCSI_Media_Type_Description_SDLT2 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_SDLT2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Sharp formatted 3½" high density floppy.. + /// + internal static string SCSI_Media_Type_Description_Sharp_MF2HD { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Sharp_MF2HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is SyQuest, media has 390696 blocks of 512 bytes, setting media type to SQ2000.. + /// + internal static string SCSI_Media_Type_Description_SQ2000 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_SQ2000", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is SyQuest, media has 215440 blocks of 512 bytes, setting media type to SQ310.. + /// + internal static string SCSI_Media_Type_Description_SQ310 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_SQ310", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is SyQuest, media has 524288 blocks of 512 bytes, setting media type to SQ327.. + /// + internal static string SCSI_Media_Type_Description_SQ327 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_SQ327", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is SyQuest, media has 86700 blocks of 512 bytes, setting media type to SQ400.. + /// + internal static string SCSI_Media_Type_Description_SQ400 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_SQ400", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is SyQuest, media has 173456 blocks of 512 bytes, setting media type to SQ800.. + /// + internal static string SCSI_Media_Type_Description_SQ800 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_SQ800", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is SyQuest, media has 2929800 blocks of 512 bytes, setting media type to SyJet.. + /// + internal static string SCSI_Media_Type_Description_SyJet { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_SyJet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T10000A.. + /// + internal static string SCSI_Media_Type_Description_T10000A { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_T10000A", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T10000B.. + /// + internal static string SCSI_Media_Type_Description_T10000B { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_T10000B", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T10000C.. + /// + internal static string SCSI_Media_Type_Description_T10000C { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_T10000C", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T10000D.. + /// + internal static string SCSI_Media_Type_Description_T10000D { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_T10000D", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T9840A.. + /// + internal static string SCSI_Media_Type_Description_T9840A { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_T9840A", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T9840D.. + /// + internal static string SCSI_Media_Type_Description_T9840D { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_T9840D", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T9940A.. + /// + internal static string SCSI_Media_Type_Description_T9940A { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_T9940A", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T9940B.. + /// + internal static string SCSI_Media_Type_Description_T9940B { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_T9940B", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T9840C.. + /// + internal static string SCSI_Media_Type_Description_T9940C { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_T9940C", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to Travan 4.. + /// + internal static string SCSI_Media_Type_Description_Travan4 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Travan4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to Travan 5.. + /// + internal static string SCSI_Media_Type_Description_Travan5 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Travan5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "stt" setting media type to Travan 5.. + /// + internal static string SCSI_Media_Type_Description_Travan5_stt { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Travan5_stt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "stt" setting media type to Travan 7.. + /// + internal static string SCSI_Media_Type_Description_Travan7 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Travan7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to UDO.. + /// + internal static string SCSI_Media_Type_Description_UDO { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_UDO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to UDO2.. + /// + internal static string SCSI_Media_Type_Description_UDO2 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_UDO2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to unknown.. + /// + internal static string SCSI_Media_Type_Description_Unknown { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Unknown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to unknown magneto-optical.. + /// + internal static string SCSI_Media_Type_Description_Unknown_MO { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_Unknown_MO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to VStape I.. + /// + internal static string SCSI_Media_Type_Description_VStape { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_VStape", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "vxa" setting media type to VXA.. + /// + internal static string SCSI_Media_Type_Description_VXA { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_VXA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "vxa" setting media type to VXA 2.. + /// + internal static string SCSI_Media_Type_Description_VXA2 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_VXA2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "vxa" setting media type to VXA 3.. + /// + internal static string SCSI_Media_Type_Description_VXA3 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_VXA3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to WORM LTO-3.. + /// + internal static string SCSI_Media_Type_Description_WORM_LTO3 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_WORM_LTO3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to WORM LTO-4.. + /// + internal static string SCSI_Media_Type_Description_WORM_LTO4 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_WORM_LTO4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to WORM LTO-5.. + /// + internal static string SCSI_Media_Type_Description_WORM_LTO5 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_WORM_LTO5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to WORM LTO-6.. + /// + internal static string SCSI_Media_Type_Description_WORM_LTO6_ult { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_WORM_LTO6_ult", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to WORM LTO-7.. + /// + internal static string SCSI_Media_Type_Description_WORM_LTO7_ult { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_WORM_LTO7_ult", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to WORM UDO2.. + /// + internal static string SCSI_Media_Type_Description_WORM_UDO2 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_WORM_UDO2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI peripheral type is {0:X2}h, setting media type to host managed zoned block device.. + /// + internal static string SCSI_Media_Type_Description_ZBC_Host_Managed { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ZBC_Host_Managed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is IOMEGA, drive model is ZIP, media has 196608 blocks of 512 bytes, setting media type to 100Mb ZIP.. + /// + internal static string SCSI_Media_Type_Description_ZIP100 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ZIP100", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive manufacturer is IOMEGA, drive model is ZIP, media has 489532 blocks of 512 bytes, setting media type to 250Mb ZIP.. + /// + internal static string SCSI_Media_Type_Description_ZIP250 { + get { + return ResourceManager.GetString("SCSI_Media_Type_Description_ZIP250", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h and device is USB, setting media type to Flash Drive.. + /// + internal static string SCSI_medium_type_is_0_and_device_is_USB_setting_media_type_to_Flash_Drive { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_and_device_is_USB_setting_media_type_to_Flash_Drive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive starts with "ult", setting media type to LTO-2.. + /// + internal static string SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_to_LTO2 { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_" + + "to_LTO2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive starts with "ult", setting media type to LTO-3.. + /// + internal static string SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_to_LTO3 { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_" + + "to_LTO3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive starts with "ult", setting media type to LTO-4.. + /// + internal static string SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_to_LTO4 { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_" + + "to_LTO4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, density code is {1:X2}h, drive starts with "ult", setting media type to LTO-5.. + /// + internal static string SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_to_LTO5 { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_" + + "to_LTO5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to PD-650.. + /// + internal static string SCSI_medium_type_is_0_media_has_1_blocks_of_2_bytes_setting_media_type_to_PD_650 { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_media_has_1_blocks_of_2_bytes_setting_media_type_to_PD_650", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to WORM PD-650.. + /// + internal static string SCSI_medium_type_is_0_media_has_1_blocks_of_2_bytes_setting_media_type_to_WORM_PD_650 { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_media_has_1_blocks_of_2_bytes_setting_media_type_to_WORM_PD" + + "_650", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, setting media type to CD+.. + /// + internal static string SCSI_medium_type_is_0_setting_media_type_to_CD_Plus { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_setting_media_type_to_CD_Plus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, setting media type to CD-ROM.. + /// + internal static string SCSI_medium_type_is_0_setting_media_type_to_CD_ROM { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_setting_media_type_to_CD_ROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, setting media type to CD-R.. + /// + internal static string SCSI_medium_type_is_0_setting_media_type_to_CDR { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_setting_media_type_to_CDR", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, setting media type to CD-RW.. + /// + internal static string SCSI_medium_type_is_0_setting_media_type_to_CDRW { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_setting_media_type_to_CDRW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, setting media type to Compact Disc.. + /// + internal static string SCSI_medium_type_is_0_setting_media_type_to_Compact_Disc { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_setting_media_type_to_Compact_Disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, setting media type to Compact Disc Digital Audio.. + /// + internal static string SCSI_medium_type_is_0_setting_media_type_to_Compact_Disc_Digital_Audio { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_setting_media_type_to_Compact_Disc_Digital_Audio", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, setting media type to Photo CD.. + /// + internal static string SCSI_medium_type_is_0_setting_media_type_to_Photo_CD { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_setting_media_type_to_Photo_CD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium type is {0:X2}h, setting media type to unknown magneto-optical.. + /// + internal static string SCSI_medium_type_is_0_setting_media_type_to_unknown_magneto_optical { + get { + return ResourceManager.GetString("SCSI_medium_type_is_0_setting_media_type_to_unknown_magneto_optical", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unhandled exception calling uname: {0}. + /// + internal static string Unhandled_exception_calling_uname_0 { + get { + return ResourceManager.GetString("Unhandled_exception_calling_uname_0", resourceCulture); + } + } + } +} diff --git a/Aaru.CommonTypes/Localization/Localization.es.resx b/Aaru.CommonTypes/Localization/Localization.es.resx new file mode 100644 index 000000000..1208ed515 --- /dev/null +++ b/Aaru.CommonTypes/Localization/Localization.es.resx @@ -0,0 +1,631 @@ + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + El fabricante es SyQuest, el medio tiene 1961069 bloques de 512 bytes, estableciendo tipo como SparQ. + + + Excepción {0} + + + La respuesta a IDENTIFY es diferente de 512, no se decodificará. + + + La respuesta a INQUIRY es de {0} bytes, menor del mínimo de 36 bytes, los datos decodificados podrían ser incorrect, no se decodificará. + + + El tamaño de la respuesta a INQUIRY ({0} bytes) es diferente a la especificada en el campo de longitud ({1} bytes), los datos decodificados podrían ser incorrectos, no se decodificará. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 5¼" en formato Acorn. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 5¼" y 80 pistas en formato Acorn. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de densidad sencilla de 5¼" en formato Acorn. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 3½" en formato Acorn. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de alta densidad de 3½" en formato Acorn. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 3½" en formato Amiga. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de alta densidad de 3½" en formato Amiga. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 5¼" en formato Apple DOS 3.2. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 5¼" de doble cara en formato Apple DOS 3.2 + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 5¼" en formato Apple DOS 3.3 + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 5¼" de doble cara en formato Apple DOS 3.3 + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad y una cara de 3½" en formato Apple. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 3½" en formato Apricot. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de densidad sencilla de 5¼" en formato Atari. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 5¼" en formato Acorn. + + + El fabricante es IOMEGA, el medio tiene {0} bloques de 256 bytes, estableciendo tipo como Bernoulli Box de 10Mb. + + + El fabricante es IOMEGA, el medio tiene 294918 bloques de 512 bytes, estableciendo tipo como Bernoulli Box II de 150Mb. + + + El fabricante es IOMEGA, el medio tiene 87040 bloques de 512 bytes, estableciendo tipo como Bernoulli Box II de 44Mb. + + + El fabricante es IOMEGA, el medio tiene 175856 bloques de 512 bytes, estableciendo tipo como Bernoulli Box II de 90Mb. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, el modelo de la unidad comienza con "dlt", estableciendo tipo como CompacTape. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, el modelo de la unidad comienza con "dlt", estableciendo tipo como CompacTape II. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, el modelo de la unidad comienza con "dlt", estableciendo tipo como DLTtapeIII. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, el modelo de la unidad comienza con "dlt", estableciendo tipo como DLTtape IIIxt. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, el modelo de la unidad comienza con "dlt", estableciendo tipo como DLTtape IV. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, el modelo de la unidad comienza con "dat", estableciendo tipo como DAT72. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, el modelo de la unidad comienza con "dat", estableciendo tipo como DDS-2. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, el modelo de la unidad comienza con "dat", estableciendo tipo como DDS-3. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, el modelo de la unidad comienza con "dat", estableciendo tipo como DDS-4. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como DDS. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como DDS-2. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como DDS-3. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como DDS-4. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete DEC RX02. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de alta densidad de 3½" en formato Microsoft DMF. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 3½" conforme con ECMA-154 / ISO 10090. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 3½" conforme con ECMA-201 / ISO 13963. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico estampado de 3½" conforme con ECMA-201 / ISO 13963. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 3½" conforme con ECMA-223. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 3½" conforme con ECMA-239 / ISO 15498. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 3½" en formato FDFORMAT. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de alta densidad de 3½" en formato FDFORMAT. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 3½" modelo GigaMO. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 3½" modelo GigaMO 2. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad y una cara de 3½" con formato IBM. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad y una cara de 3½" con formato IBM (8 sectores). + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 3½" con formato IBM. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 3½" con formato IBM (8 sectores). + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de densidad extra de 3½" con formato IBM. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de alta densidad de 3½" con formato IBM. + + + El modelo de la unidad es LS (SuperDisk), el medio tiene 2880 bloques de 512 bytes, estableciendo tipo como disquete de alta densidad de 3½" con formato PC-98. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de alta densidad de 3½" con formato PC-98. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 5¼" conforme con ECMA-183 / ISO 13481. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 5¼" conforme con ECMA-184 / ISO 13549. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 5¼" conforme con ECMA-195 / ISO 13482. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 5¼" conforme con ECMA-238 / ISO 15486. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 5¼" conforme con ECMA-280 / ISO 18093. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 5¼" conforme con ECMA-322 / ISO 22092. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 356mm conforme con ECMA-260 / ISO 15898. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 300mm conforme con ECMA-317 / ISO 20162. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 5¼" en formato ECMA-56. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 5¼" en formato ECMA-66. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 5¼" en formato ECMA-70. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 5¼" en formato ECMA-78. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 5¼" en formato ECMA-99. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 8" en formato ECMA-54. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 8" en formato ECMA-59. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 8" en formato ECMA-69. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de alta densidad de 5¼" en formato FDFORMAT. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad y una cara de 5¼" en formato IBM. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad y una cara de 5¼" en formato IBM (8 sectores). + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 5¼" en formato IBM. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad de 5¼" en formato IBM (8 sectores. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de alta densidad de 5¼" en formato IBM. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 5¼" conforme con ISO 10089. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 5¼" conforme con ISO 14517. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 3½" conforme con ISO 15041. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico de 5¼" conforme con ISO 15286. + + + El modelo de la unidad es LS (SuperDisk), el medio tiene 246528 bloques de 512 bytes, estableciendo tipo como LS-120. + + + El modelo de la unidad es LS (SuperDisk), el medio tiene 469504 bloques de 512 bytes, estableciendo tipo como LS-120. + + + El fabricante de la unidad es IOMEGA, el modelo es JAZ y el medio tiene 2091050 bloques de 512 bytes, estableciendo tipo como JAZ de 1Gb. + + + El fabricante de la unidad es IOMEGA, el modelo es JAZ y el medio tiene 3915600 bloques de 512 bytes, estableciendo tipo como JAZ de 2Gb. + + + El fabricante de la unidad es IOMEGA, el modelo es ZIP y el medio tiene 196608 bloques de 512 bytes, estableciendo tipo como ZIP de 100Mb. + + + El fabricante de la unidad es IOMEGA, el modelo es ZIP y el medio tiene 196608 bloques de 512 bytes, estableciendo tipo como ZIP de 250Mb. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como LTO. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como LTO-2. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como QIC-11. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como QIC-120. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como QIC-150. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como QIC-24. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como Travan 5. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como Travan 4. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el fabricante es StorageTek, estableciendo tipo como T10000A. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el fabricante es StorageTek, estableciendo tipo como T10000B. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el fabricante es StorageTek, estableciendo tipo como T10000C. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el fabricante es StorageTek, estableciendo tipo como T10000D. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el fabricante es StorageTek, estableciendo tipo como T9840A. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el fabricante es StorageTek, estableciendo tipo como T9840D. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el fabricante es StorageTek, estableciendo tipo como T9940A. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el fabricante es StorageTek, estableciendo tipo como T9940B. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el fabricante es StorageTek, estableciendo tipo como T9840C. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 106m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 112m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 125m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 150m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 15m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape XL de 160m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 170m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 225m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 22m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape AME de 22m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 28m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 40m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 45m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 54m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 75m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 76. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "exb", estableciendo tipo como Exatape de 80m. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO-2. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO-3. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO-4. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO-5. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO-6. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO-7. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "sdz", estableciendo tipo como Super AIT. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "dlt", estableciendo tipo como SuperDLT. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "dlt", estableciendo tipo como SuperDLT 2. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "stt", estableciendo tipo como Travan 5. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "stt", estableciendo tipo como Travan 7. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "dlt", estableciendo tipo como VStape I. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "vxa", estableciendo tipo como VXA. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "vxa", estableciendo tipo como VXA 2. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "vxa", estableciendo tipo como VXA 3. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como WORM LTO-3. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como WORM LTO-4. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como WORM LTO-5. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como WORM LTO-6. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "uly", estableciendo tipo como WORM LTO-7. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO-2. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO-3. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO-4. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el modelo de la unidad comienza por "ult", estableciendo tipo como LTO-5. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como Floptical. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como Sony HiMD. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como MiniDisc de 60 minutos. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como MiniDisc de 74 minutos. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como MiniDisc de 80 minutos. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como REV de 120Gb. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como REV de 35Gb. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como REV de 70Gb. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como UDO. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como UDO2. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como desconocido. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como magneto-óptico desconocido. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como WORM UDO 2. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como PD-650. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como WORM PD-650. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 8" en formato IBM 23FD. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 8" en formato IBM 33FD. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 8" en formato IBM 43FD. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de 8" en formato IBM 53FD. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de alta densidad de 5¼" en formato PC-98. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de alta densidad de 3½" con formato Sharp. + + + El medio tiene 46956 bloques de 256 bytes, estableciendo tipo como HyperFlex de 12Mb. + + + El medio tiene 46956 bloques de 256 bytes, estableciendo tipo como HyperFlex de 24Mb. + + + El modelo de la unidad es Castlewood Orb, el medio tiene 4307184 bloques de 512 bytes, estableciendo tipo como Orb. + + + El modelo de la unidad es RDX, el medio tiene {0} bloques de {1} bytes, estableciendo tipo como RDX320. + + + El fabricante de la unidad es SyQuest, el medio tiene 390696 bloques de 512 bytes, estableciendo tipo como SQ2000. + + + El fabricante de la unidad es SyQuest, el medio tiene 215440 bloques de 512 bytes, estableciendo tipo como SQ310. + + + El fabricante de la unidad es SyQuest, el medio tiene 524288 bloques de 512 bytes, estableciendo tipo como SQ327. + + + El fabricante de la unidad es SyQuest, el medio tiene 87600 bloques de 512 bytes, estableciendo tipo como SQ400. + + + El fabricante de la unidad es SyQuest, el medio tiene 173456 bloques de 512 bytes, estableciendo tipo como SQ800. + + + El fabricante de la unidad es SyQuest, el medio tiene 2929800 bloques de 512 bytes, estableciendo tipo como SyJet. + + + El fabricante de la unidad es IOMEGA, el medio tiene 78882 bloques de 512 bytes, estableciendo tipo como PocketZIP. + + + El modelo de la unidad es HiFD, el medio tiene 393380 bloques de 512 bytes, estableciendo tipo como HiFD. + + + El modelo de la unidad es LS (SuperDisk), el medio tiene 65536 bloques de 512 bytes, estableciendo tipo como FD32MB. + + + El fabricante es SyQuest, el medio tiene 262144 bloques de 512 bytes, estableciendo tipo como EZ135. + + + El fabricante es SyQuest, el medio tiene 450560 bloques de 512 bytes, estableciendo tipo como EZ230. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como IBM 3490. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h, estableciendo tipo como IBM 3490E. + + + El tipo de medio SCSI es {0:X2}h, el código de densidad es {1:X2}h y el fabricante de la unidad es IBM, estableciendo tipo como IBM 3592. + + + El tipo de periférico SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como MiniDisc de 60 minutos. + + + El tipo de periférico SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como MiniDisc de 74 minutos. + + + El tipo de periférico SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como MiniDisc de 80 minutos. + + + El tipo de periférico SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como MiniDisc for Data. + + + El tipo de medio SCSI es {0:X2}h, el medio tiene {1} bloques de {2} bytes, estableciendo tipo como disquete de doble densidad y una cara de 5¼" en formato MetaFloppy. + + + El tipo de periférico SCSI es {0:X2}h, estableciendo tipo como dispositivo de zonas de bloques gestionado. + + + El tipo de medio SCSI es {0:X2}h y el dispositivo es USB, estableciendo tipo como unidad Flash. + + + El tipo de medio SCSI es {0:X2}h, estableciendo tipo como CD-R. + + + El tipo de medio SCSI es {0:X2}h, estableciendo tipo como CD-RW. + + + El tipo de medio SCSI es {0:X2}h, estableciendo tipo como CD+. + + + El tipo de medio SCSI es {0:X2}h, estableciendo tipo como CD-ROM. + + + El tipo de medio SCSI es {0:X2}h, estableciendo tipo como Compact Disc. + + + El tipo de medio SCSI es {0:X2}h, estableciendo tipo como Compact Disc Digital Audio. + + + El tipo de medio SCSI es {0:X2}h, estableciendo tipo como Photo CD. + + + El tipo de medio SCSI es {0:X2}h, estableciendo tipo como magneto-óptico desconocido. + + + Excepción no manejada llamando a uname: {0} + + \ No newline at end of file diff --git a/Aaru.CommonTypes/Localization/Localization.resx b/Aaru.CommonTypes/Localization/Localization.resx new file mode 100644 index 000000000..5bbf14e20 --- /dev/null +++ b/Aaru.CommonTypes/Localization/Localization.resx @@ -0,0 +1,638 @@ + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + Unhandled exception calling uname: {0} + + + Drive manufacturer is SyQuest, media has 1961069 blocks of 512 bytes, setting media type to SparQ. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to WORM PD-650. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to PD-650. + + + SCSI medium type is {0:X2}h, setting media type to Compact Disc. + + + SCSI medium type is {0:X2}h, setting media type to CD-ROM. + + + SCSI medium type is {0:X2}h, setting media type to Compact Disc Digital Audio. + + + SCSI medium type is {0:X2}h, setting media type to CD+. + + + SCSI medium type is {0:X2}h, setting media type to Photo CD. + + + SCSI medium type is {0:X2}h, setting media type to CD-R. + + + SCSI medium type is {0:X2}h, setting media type to CD-RW. + + + SCSI medium type is {0:X2}h and device is USB, setting media type to Flash Drive. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive starts with "ult", setting media type to LTO-2. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive starts with "ult", setting media type to LTO-3. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive starts with "ult", setting media type to LTO-4. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive starts with "ult", setting media type to LTO-5. + + + SCSI medium type is {0:X2}h, setting media type to unknown magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-154 / ISO 10090 conforming 3½" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-201 / ISO 13963 conforming 3½" embossed magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-201 / ISO 13963 conforming 3½" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-223 conforming 3½" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-183 / ISO 13481 conforming 5¼" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ISO 15041 conforming 3½" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-184 / ISO 13549 conforming 5¼" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-195 / ISO 13842 conforming 5¼" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ISO 14517 conforming 5¼" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to unknown magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ISO 10089 conforming 5¼" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-238 / ISO 15486 conforming 5¼" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ISO 15286 conforming 5¼" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-322 / ISO 22092 conforming 5¼" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-260 / ISO 15898 conforming 356mm magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-239 / ISO 15498 conforming 3½" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to GigaMO 3½" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to GigaMO 2 3½" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-280 / ISO 18093 conforming 5¼" magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-317 / ISO 20162 conforming 300mm magneto-optical. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to UDO. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to WORM UDO2. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to UDO2. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-54 formatted 8" floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-59 formatted 8" floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-69 formatted 8" floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to unknown. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-66 formatted 5¼" floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-70 formatted 5¼" floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-78 formatted 5¼" floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-99 formatted 5¼" floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" double density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 120Gb REV. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 70Gb REV. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 35Gb REV. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to PC-98 formatted 3½" high density floppy (15 sectors). + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" high density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Atari formatted 5¼" single density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Atari formatted 5¼" double density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 8" (33FD) floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 8" (43FD) floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to ECMA-56 formatted 5¼" double density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Acorn formatted 5¼" single density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apple DOS 3.2 formatted 5¼" floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apple DOS 3.3 formatted 5¼" floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Acorn formatted 5¼" double density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apple DOS 3.2 formatted 5¼" double sided floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apple DOS 3.3 formatted 5¼" double sided floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to MetaFloppy formatted 5¼" double density single sided floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Acorn formatted 5¼" double density floppy with 80 tracks. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to DEC RX02 floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 8" (53FD) floppy. + + + Drive manufacturer is IOMEGA, media has {0} blocks of 256 bytes, setting media type to 10Mb Bernoulli Box. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 8" (23FD) floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 5¼" double density single sided floppy (8 sectors). + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 5¼" double density single sided floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apricot formatted 3½" floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" double density single sided floppy (8 sectors). + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 5¼" double density floppy (8 sectors). + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" double density single sided floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 5¼" double density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Apple formatted 3½" double density single sided floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" double density floppy (8 sectors). + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to FDFORMAT formatted 3½" double density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Amiga formatted 3½" double density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 5¼" high density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to FDFORMAT formatted 5¼" high density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Microsoft DMF formatted 3½" high density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to FDFORMAT formatted 3½" high density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Amiga formatted 3½" high density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to IBM formatted 3½" extra density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Floptical. + + + Drive model is LS (SuperDisk), media has 65536 blocks of 512 bytes, setting media type to FD32MB. + + + Drive manufacturer is IOMEGA, media has 78882 blocks of 512 bytes, setting media type to PocketZIP. + + + Drive manufacturer is SyQuest, media has 86700 blocks of 512 bytes, setting media type to SQ400. + + + Drive manufacturer is IOMEGA, media has 87040 blocks of 512 bytes, setting media type to 44Mb Bernoulli Box II. + + + Drive manufacturer is SyQuest, media has 173456 blocks of 512 bytes, setting media type to SQ800. + + + Drive manufacturer is IOMEGA, media has 175856 blocks of 512 bytes, setting media type to 90Mb Bernoulli Box II. + + + Drive manufacturer is IOMEGA, drive model is ZIP, media has 196608 blocks of 512 bytes, setting media type to 100Mb ZIP. + + + Drive manufacturer is SyQuest, media has 215440 blocks of 512 bytes, setting media type to SQ310. + + + Drive model is LS (SuperDisk), media has 246528 blocks of 512 bytes, setting media type to LS-120. + + + Drive manufacturer is SyQuest, media has 262144 blocks of 512 bytes, setting media type to EZ135. + + + Drive manufacturer is IOMEGA, media has 294918 blocks of 512 bytes, setting media type to 150Mb Bernoulli Box II. + + + Drive manufacturer is SyQuest, media has 390696 blocks of 512 bytes, setting media type to SQ2000. + + + Drive model is HiFD, media has 393380 blocks of 512 bytes, setting media type to HiFD. + + + Drive manufacturer is SyQuest, media has 450560 blocks of 512 bytes, setting media type to EZ230. + + + Drive model is LS (SuperDisk), media has 469504 blocks of 512 bytes, setting media type to LS-240. + + + Drive manufacturer is IOMEGA, drive model is ZIP, media has 489532 blocks of 512 bytes, setting media type to 250Mb ZIP. + + + Drive manufacturer is SyQuest, media has 524288 blocks of 512 bytes, setting media type to SQ327. + + + Drive manufacturer is IOMEGA, drive model is JAZ, media has 2091050 blocks of 512 bytes, setting media type to 1Gb JAZ. + + + Drive manufacturer is SyQuest, media has 2929800 blocks of 512 bytes, setting media type to SyJet. + + + Drive manufacturer is IOMEGA, drive model is JAZ, media has 3915600 blocks of 512 bytes, setting media type to 2Gb JAZ. + + + Drive model is Castlewood Orb, media has 4307184 blocks of 512 bytes, setting media type to Orb. + + + Drive model is RDX, media has {0} blocks of {1} bytes, setting media type to RDX320. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Acorn formatted 3½" double density floppy. + + + Drive model is LS (SuperDisk), media has 2880 blocks of 512 bytes, setting media type to PC-98 formatted 3½" high density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Sharp formatted 3½" high density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to PC-98 formatted 5¼" high density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Acorn formatted 3½" high density floppy. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 60 minute MiniDisc. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 74 minute MiniDisc. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 80 minute MiniDisc. + + + SCSI medium type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to Sony HiMD. + + + SCSI peripheral type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to MiniDisc for Data. + + + SCSI peripheral type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 60 minute MiniDisc. + + + SCSI peripheral type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 74 minute MiniDisc. + + + SCSI peripheral type is {0:X2}h, media has {1} blocks of {2} bytes, setting media type to 80 minute MiniDisc. + + + SCSI peripheral type is {0:X2}h, setting media type to host managed zoned block device. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to QIC-11. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to QIC-24. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to IBM 3490. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to QIC-120. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to QIC-150. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to DDS. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to DDS-2. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to DDS-3. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to DDS-4. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to IBM 3490E. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "sdz" setting media type to Super AIT. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-2. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T9840A. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T9940A. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-3. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T9940B. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T9840C. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-4. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T9840D. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T10000A. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T10000B. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T10000C. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is StorageTek, setting media type to T10000D. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-5. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to WORM LTO-3. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to WORM LTO-4. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to WORM LTO-5. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to LTO. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to LTO-2. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dat" setting media type to DDS-3. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dat" setting media type to DDS-4. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dat" setting media type to DAT72. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dat" setting media type to DDS-2. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-6. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to WORM LTO-6. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to LTO-7. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "ult" setting media type to WORM LTO-7. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 15m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive manufacturer is IBM, setting media type to IBM 3592. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "vxa" setting media type to VXA. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 28m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to CompactTape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to CompactTape II. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "vxa" setting media type to VXA 2. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "vxa" setting media type to VXA 3. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 54m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to DLTtape III. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to DLTtape IIIxt. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 106m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to DLTtape IV. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "stt" setting media type to Travan 5. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 160m Exatape XL. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to SuperDLT. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to SuperDLT 2. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "dlt" setting media type to VStape I. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "stt" setting media type to Travan 7. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to Travan 4. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, setting media type to Travan 5. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 22m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 40m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 76m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 112m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 22m Exatape AME. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 170m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 125m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 45m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 225m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 150m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 75m Exatape. + + + SCSI medium type is {0:X2}h, density code is {1:X2}h, drive model starts with "exb" setting media type to 80m Exatape. + + + IDENTIFY response is different than 512 bytes, not decoding. + + + INQUIRY response is {0} bytes, less than minimum of 36 bytes, decoded data can be incorrect, not decoding. + + + INQUIRY response length ({0} bytes) is different than specified in length field ({1} bytes), decoded data can be incorrect, not decoding. + + + Exception {0} + + + Media has 46956 blocks of 256 bytes, setting media type to 12Mb HyperFlex. + + + Media has 78936 blocks of 256 bytes, setting media type to 24Mb HyperFlex. + + \ No newline at end of file diff --git a/Aaru.CommonTypes/MediaType.cs b/Aaru.CommonTypes/MediaType.cs new file mode 100644 index 000000000..6b01ed61e --- /dev/null +++ b/Aaru.CommonTypes/MediaType.cs @@ -0,0 +1,1323 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : MediaType.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru common types. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains common media types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable InconsistentNaming +// TODO: Rename contents + +using System; + +#pragma warning disable 1591 + +// ReSharper disable UnusedMember.Global +// ReSharper disable IdentifierTypo + +namespace Aaru.CommonTypes; + +public enum MediaEncoding +{ + Unknown, + FM, + MFM, + M2FM, + AppleGCR, + CommodoreGCR +} + +/// Contains an enumeration of all known types of media. +public enum MediaType : uint +{ +#region Generics, types 0 to 9 + + /// Unknown disk type + Unknown = 0, + /// Unknown magneto-optical + UnknownMO = 1, + /// Generic hard disk + GENERIC_HDD = 2, + /// Microdrive type hard disk + Microdrive = 3, + /// Zoned hard disk + Zone_HDD = 4, + /// USB flash drives + FlashDrive = 5, + /// Unknown data tape + UnknownTape = 6, + +#endregion Generics, types 0 to 9 + +#region Somewhat standard Compact Disc formats, types 10 to 39 + + /// Any unknown or standard violating CD + CD = 10, + /// CD Digital Audio (Red Book) + CDDA = 11, + /// CD+G (Red Book) + CDG = 12, + /// CD+EG (Red Book) + CDEG = 13, + /// CD-i (Green Book) + CDI = 14, + /// CD-ROM (Yellow Book) + CDROM = 15, + /// CD-ROM XA (Yellow Book) + CDROMXA = 16, + /// CD+ (Blue Book) + CDPLUS = 17, + /// CD-MO (Orange Book) + CDMO = 18, + /// CD-Recordable (Orange Book) + CDR = 19, + /// CD-ReWritable (Orange Book) + CDRW = 20, + /// Mount-Rainier CD-RW + CDMRW = 21, + /// Video CD (White Book) + VCD = 22, + /// Super Video CD (White Book) + SVCD = 23, + /// Photo CD (Beige Book) + PCD = 24, + /// Super Audio CD (Scarlet Book) + SACD = 25, + /// Double-Density CD-ROM (Purple Book) + DDCD = 26, + /// DD CD-R (Purple Book) + DDCDR = 27, + /// DD CD-RW (Purple Book) + DDCDRW = 28, + /// DTS audio CD (non-standard) + DTSCD = 29, + /// CD-MIDI (Red Book) + CDMIDI = 30, + /// CD-Video (ISO/IEC 61104) + CDV = 31, + /// 120mm, Phase-Change, 1298496 sectors, 512 bytes/sector, PD650, ECMA-240, ISO 15485 + PD650 = 32, + /// 120mm, Write-Once, 1281856 sectors, 512 bytes/sector, PD650, ECMA-240, ISO 15485 + PD650_WORM = 33, + /// + /// CD-i Ready, contains a track before the first TOC track, in mode 2, and all TOC tracks are Audio. Subchannel + /// marks track as audio pause. + /// + CDIREADY = 34, + FMTOWNS = 35, + +#endregion Somewhat standard Compact Disc formats, types 10 to 39 + +#region Standard DVD formats, types 40 to 50 + + /// DVD-ROM (applies to DVD Video and DVD Audio) + DVDROM = 40, + /// DVD-R + DVDR = 41, + /// DVD-RW + DVDRW = 42, + /// DVD+R + DVDPR = 43, + /// DVD+RW + DVDPRW = 44, + /// DVD+RW DL + DVDPRWDL = 45, + /// DVD-R DL + DVDRDL = 46, + /// DVD+R DL + DVDPRDL = 47, + /// DVD-RAM + DVDRAM = 48, + /// DVD-RW DL + DVDRWDL = 49, + /// DVD-Download + DVDDownload = 50, + +#endregion Standard DVD formats, types 40 to 50 + +#region Standard HD-DVD formats, types 51 to 59 + + /// HD DVD-ROM (applies to HD DVD Video) + HDDVDROM = 51, + /// HD DVD-RAM + HDDVDRAM = 52, + /// HD DVD-R + HDDVDR = 53, + /// HD DVD-RW + HDDVDRW = 54, + /// HD DVD-R DL + HDDVDRDL = 55, + /// HD DVD-RW DL + HDDVDRWDL = 56, + +#endregion Standard HD-DVD formats, types 51 to 59 + +#region Standard Blu-ray formats, types 60 to 69 + + /// BD-ROM (and BD Video) + BDROM = 60, + /// BD-R + BDR = 61, + /// BD-RE + BDRE = 62, + /// BD-R XL + BDRXL = 63, + /// BD-RE XL + BDREXL = 64, + /// Ultra HD Blu-ray + UHDBD = 65, + +#endregion Standard Blu-ray formats, types 60 to 69 + +#region Rare or uncommon optical standards, types 70 to 79 + + /// Enhanced Versatile Disc + EVD = 70, + /// Forward Versatile Disc + FVD = 71, + /// Holographic Versatile Disc + HVD = 72, + /// China Blue High Definition + CBHD = 73, + /// High Definition Versatile Multilayer Disc + HDVMD = 74, + /// Versatile Compact Disc High Density + VCDHD = 75, + /// Stacked Volumetric Optical Disc + SVOD = 76, + /// Five Dimensional disc + FDDVD = 77, + /// China Video Disc + CVD = 78, + +#endregion Rare or uncommon optical standards, types 70 to 79 + +#region LaserDisc based, types 80 to 89 + + /// Pioneer LaserDisc + LD = 80, + /// Pioneer LaserDisc data + LDROM = 81, + LDROM2 = 82, + LVROM = 83, + MegaLD = 84, + /// Writable LaserDisc with support for component video + CRVdisc = 85, + +#endregion LaserDisc based, types 80 to 89 + +#region MiniDisc based, types 90 to 99 + + /// Sony Hi-MD + HiMD = 90, + /// Sony MiniDisc + MD = 91, + /// Sony MD-Data + MDData = 92, + /// Sony MD-Data2 + MDData2 = 93, + /// Sony MiniDisc, 60 minutes, formatted with Hi-MD format + MD60 = 94, + /// Sony MiniDisc, 74 minutes, formatted with Hi-MD format + MD74 = 95, + /// Sony MiniDisc, 80 minutes, formatted with Hi-MD format + MD80 = 96, + +#endregion MiniDisc based, types 90 to 99 + +#region Plasmon UDO, types 100 to 109 + + /// 5.25", Phase-Change, 1834348 sectors, 8192 bytes/sector, Ultra Density Optical, ECMA-350, ISO 17345 + UDO = 100, + /// 5.25", Phase-Change, 3669724 sectors, 8192 bytes/sector, Ultra Density Optical 2, ECMA-380, ISO 11976 + UDO2 = 101, + /// 5.25", Write-Once, 3668759 sectors, 8192 bytes/sector, Ultra Density Optical 2, ECMA-380, ISO 11976 + UDO2_WORM = 102, + +#endregion Plasmon UDO, types 100 to 109 + +#region Sony game media, types 110 to 129 + + PlayStationMemoryCard = 110, + PlayStationMemoryCard2 = 111, + /// Sony PlayStation game CD + PS1CD = 112, + /// Sony PlayStation 2 game CD + PS2CD = 113, + /// Sony PlayStation 2 game DVD + PS2DVD = 114, + /// Sony PlayStation 3 game DVD + PS3DVD = 115, + /// Sony PlayStation 3 game Blu-ray + PS3BD = 116, + /// Sony PlayStation 4 game Blu-ray + PS4BD = 117, + /// Sony PlayStation Portable Universal Media Disc (ECMA-365) + UMD = 118, + PlayStationVitaGameCard = 119, + /// Sony PlayStation 5 game Ultra HD Blu-ray + PS5BD = 120, + +#endregion Sony game media, types 110 to 129 + +#region Microsoft game media, types 130 to 149 + + /// Microsoft X-box Game Disc + XGD = 130, + /// Microsoft X-box 360 Game Disc + XGD2 = 131, + /// Microsoft X-box 360 Game Disc + XGD3 = 132, + /// Microsoft X-box One Game Disc + XGD4 = 133, + +#endregion Microsoft game media, types 130 to 149 + +#region Sega game media, types 150 to 169 + + /// Sega MegaCD + MEGACD = 150, + /// Sega Saturn disc + SATURNCD = 151, + /// Sega/Yamaha Gigabyte Disc + GDROM = 152, + /// Sega/Yamaha recordable Gigabyte Disc + GDR = 153, + SegaCard = 154, + MilCD = 155, + MegaDriveCartridge = 156, + _32XCartridge = 157, + SegaPicoCartridge = 158, + MasterSystemCartridge = 159, + GameGearCartridge = 160, + SegaSaturnCartridge = 161, + +#endregion Sega game media, types 150 to 169 + +#region Other game media, types 170 to 179 + + /// PC-Engine / TurboGrafx cartridge + HuCard = 170, + /// PC-Engine / TurboGrafx CD + SuperCDROM2 = 171, + /// Atari Jaguar CD + JaguarCD = 172, + /// 3DO CD + ThreeDO = 173, + /// NEC PC-FX + PCFX = 174, + /// NEO-GEO CD + NeoGeoCD = 175, + /// Commodore CDTV + CDTV = 176, + /// Amiga CD32 + CD32 = 177, + /// Nuon (DVD based videogame console) + Nuon = 178, + /// Bandai Playdia + Playdia = 179, + +#endregion Other game media, types 170 to 179 + +#region Apple standard floppy format, types 180 to 189 + + /// 5.25", SS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR + Apple32SS = 180, + /// 5.25", DS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR + Apple32DS = 181, + /// 5.25", SS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR + Apple33SS = 182, + /// 5.25", DS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR + Apple33DS = 183, + /// 3.5", SS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR + AppleSonySS = 184, + /// 3.5", DS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR + AppleSonyDS = 185, + /// 5.25", DS, ?D, ?? tracks, ?? spt, 512 bytes/sector, GCR, opposite side heads, aka Twiggy + AppleFileWare = 186, + +#endregion Apple standard floppy format + +#region IBM/Microsoft PC floppy formats, types 190 to 209 + + /// 5.25", SS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM + DOS_525_SS_DD_8 = 190, + /// 5.25", SS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM + DOS_525_SS_DD_9 = 191, + /// 5.25", DS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM + DOS_525_DS_DD_8 = 192, + /// 5.25", DS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM + DOS_525_DS_DD_9 = 193, + /// 5.25", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM + DOS_525_HD = 194, + /// 3.5", SS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM + DOS_35_SS_DD_8 = 195, + /// 3.5", SS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM + DOS_35_SS_DD_9 = 196, + /// 3.5", DS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM + DOS_35_DS_DD_8 = 197, + /// 3.5", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM + DOS_35_DS_DD_9 = 198, + /// 3.5", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM + DOS_35_HD = 199, + /// 3.5", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM + DOS_35_ED = 200, + /// 3.5", DS, HD, 80 tracks, 21 spt, 512 bytes/sector, MFM + DMF = 201, + /// 3.5", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM + DMF_82 = 202, + /// + /// 5.25", DS, HD, 80 tracks, ? spt, ??? + ??? + ??? bytes/sector, MFM track 0 = ??15 sectors, 512 bytes/sector, + /// falsified to DOS as 19 spt, 512 bps + /// + XDF_525 = 203, + /// + /// 3.5", DS, HD, 80 tracks, 4 spt, 8192 + 2048 + 1024 + 512 bytes/sector, MFM track 0 = 19 sectors, 512 + /// bytes/sector, falsified to DOS as 23 spt, 512 bps + /// + XDF_35 = 204, + +#endregion IBM/Microsoft PC standard floppy formats, types 190 to 209 + +#region IBM standard floppy formats, types 210 to 219 + + /// 8", SS, SD, 32 tracks, 8 spt, 319 bytes/sector, FM + IBM23FD = 210, + /// 8", SS, SD, 73 tracks, 26 spt, 128 bytes/sector, FM + IBM33FD_128 = 211, + /// 8", SS, SD, 74 tracks, 15 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM33FD_256 = 212, + /// 8", SS, SD, 74 tracks, 8 spt, 512 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM33FD_512 = 213, + /// 8", DS, SD, 74 tracks, 26 spt, 128 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM43FD_128 = 214, + /// 8", DS, SD, 74 tracks, 26 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM43FD_256 = 215, + /// + /// 8", DS, DD, 74 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + IBM53FD_256 = 216, + /// + /// 8", DS, DD, 74 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + IBM53FD_512 = 217, + /// + /// 8", DS, DD, 74 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + IBM53FD_1024 = 218, + +#endregion IBM standard floppy formats, types 210 to 219 + +#region DEC standard floppy formats, types 220 to 229 + + /// 8", SS, DD, 77 tracks, 26 spt, 128 bytes/sector, FM + RX01 = 220, + /// 8", SS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM + RX02 = 221, + /// 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM + RX03 = 222, + /// 5.25", SS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM + RX50 = 223, + +#endregion DEC standard floppy formats, types 220 to 229 + +#region Acorn standard floppy formats, types 230 to 239 + + /// 5,25", SS, SD, 40 tracks, 10 spt, 256 bytes/sector, FM + ACORN_525_SS_SD_40 = 230, + /// 5,25", SS, SD, 80 tracks, 10 spt, 256 bytes/sector, FM + ACORN_525_SS_SD_80 = 231, + /// 5,25", SS, DD, 40 tracks, 16 spt, 256 bytes/sector, MFM + ACORN_525_SS_DD_40 = 232, + /// 5,25", SS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM + ACORN_525_SS_DD_80 = 233, + /// 5,25", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM + ACORN_525_DS_DD = 234, + /// 3,5", DS, DD, 80 tracks, 5 spt, 1024 bytes/sector, MFM + ACORN_35_DS_DD = 235, + /// 3,5", DS, HD, 80 tracks, 10 spt, 1024 bytes/sector, MFM + ACORN_35_DS_HD = 236, + +#endregion Acorn standard floppy formats, types 230 to 239 + +#region Atari standard floppy formats, types 240 to 249 + + /// 5,25", SS, SD, 40 tracks, 18 spt, 128 bytes/sector, FM + ATARI_525_SD = 240, + /// 5,25", SS, ED, 40 tracks, 26 spt, 128 bytes/sector, MFM + ATARI_525_ED = 241, + /// 5,25", SS, DD, 40 tracks, 18 spt, 256 bytes/sector, MFM + ATARI_525_DD = 242, + /// 3,5", SS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM + ATARI_35_SS_DD = 243, + /// 3,5", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM + ATARI_35_DS_DD = 244, + /// 3,5", SS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM + ATARI_35_SS_DD_11 = 245, + /// 3,5", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM + ATARI_35_DS_DD_11 = 246, + +#endregion Atari standard floppy formats, types 240 to 249 + +#region Commodore standard floppy formats, types 250 to 259 + + /// 3,5", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM (1581) + CBM_35_DD = 250, + /// 3,5", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM (Amiga) + CBM_AMIGA_35_DD = 251, + /// 3,5", DS, HD, 80 tracks, 22 spt, 512 bytes/sector, MFM (Amiga) + CBM_AMIGA_35_HD = 252, + /// 5,25", SS, DD, 35 tracks, GCR + CBM_1540 = 253, + /// 5,25", SS, DD, 40 tracks, GCR + CBM_1540_Ext = 254, + /// 5,25", DS, DD, 35 tracks, GCR + CBM_1571 = 255, + +#endregion Commodore standard floppy formats, types 250 to 259 + +#region NEC/SHARP standard floppy formats, types 260 to 269 + + /// 8", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM + NEC_8_SD = 260, + /// 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM + NEC_8_DD = 261, + /// 5.25", SS, SD, 80 tracks, 16 spt, 256 bytes/sector, FM + NEC_525_SS = 262, + /// 5.25", DS, SD, 80 tracks, 16 spt, 256 bytes/sector, MFM + NEC_525_DS = 263, + /// 5,25", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM + NEC_525_HD = 264, + /// 3,5", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM, aka mode 3 + NEC_35_HD_8 = 265, + /// 3,5", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM + NEC_35_HD_15 = 266, + /// 3,5", DS, TD, 240 tracks, 38 spt, 512 bytes/sector, MFM + NEC_35_TD = 267, + /// 5,25", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM + SHARP_525 = NEC_525_HD, + /// 3,5", DS, HD, 80 tracks, 9 spt, 1024 bytes/sector, MFM + SHARP_525_9 = 268, + /// 3,5", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM + SHARP_35 = NEC_35_HD_8, + /// 3,5", DS, HD, 80 tracks, 9 spt, 1024 bytes/sector, MFM + SHARP_35_9 = 269, + +#endregion NEC/SHARP standard floppy formats, types 260 to 269 + +#region ECMA floppy standards, types 270 to 289 + + /// + /// 5,25", DS, DD, 80 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track + /// 0 side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_99_8 = 270, + /// + /// 5,25", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track + /// 0 side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_99_15 = 271, + /// + /// 5,25", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track + /// 0 side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_99_26 = 272, + /// 3,5", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM + ECMA_100 = DOS_35_DS_DD_9, + /// 3,5", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM + ECMA_125 = DOS_35_HD, + /// 3,5", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM + ECMA_147 = DOS_35_ED, + /// 8", SS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM + ECMA_54 = 273, + /// 8", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM + ECMA_59 = 274, + /// 5,25", SS, DD, 35 tracks, 9 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector + ECMA_66 = 275, + /// + /// 8", DS, DD, 77 tracks, 8 spt, 1024 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_69_8 = 276, + /// + /// 8", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_69_15 = 277, + /// + /// 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_69_26 = 278, + /// + /// 5,25", DS, DD, 40 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector, track 0 + /// side 1 = 16 sectors, 256 bytes/sector + /// + ECMA_70 = 279, + /// + /// 5,25", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector, track 0 + /// side 1 = 16 sectors, 256 bytes/sector + /// + ECMA_78 = 280, + /// 5,25", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, FM + ECMA_78_2 = 281, + +#endregion ECMA floppy standards, types 270 to 289 + +#region Non-standard PC formats (FDFORMAT, 2M, etc), types 290 to 308 + + /// 5,25", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM + FDFORMAT_525_DD = 290, + /// 5,25", DS, HD, 82 tracks, 17 spt, 512 bytes/sector, MFM + FDFORMAT_525_HD = 291, + /// 3,5", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM + FDFORMAT_35_DD = 292, + /// 3,5", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM + FDFORMAT_35_HD = 293, + +#endregion Non-standard PC formats (FDFORMAT, 2M, etc), types 290 to 308 + +#region Apricot ACT standard floppy formats, type 309 + + /// 3.5", DS, DD, 70 tracks, 9 spt, 512 bytes/sector, MFM + Apricot_35 = 309, + +#endregion Apricot ACT standard floppy formats, type 309 + +#region OnStream ADR, types 310 to 319 + + ADR2120 = 310, + ADR260 = 311, + ADR30 = 312, + ADR50 = 313, + +#endregion OnStream ADR, types 310 to 319 + +#region Advanced Intelligent Tape, types 320 to 339 + + AIT1 = 320, + AIT1Turbo = 321, + AIT2 = 322, + AIT2Turbo = 323, + AIT3 = 324, + AIT3Ex = 325, + AIT3Turbo = 326, + AIT4 = 327, + AIT5 = 328, + AITETurbo = 329, + SAIT1 = 330, + SAIT2 = 331, + +#endregion Advanced Intelligent Tape, types 320 to 339 + +#region Iomega, types 340 to 359 + + /// Obsolete type for 8"x11" Bernoulli Box disk + [Obsolete] + Bernoulli = 340, + /// Obsolete type for 5⅓" Bernoulli Box II disks + [Obsolete] + Bernoulli2 = 341, + Ditto = 342, + DittoMax = 343, + Jaz = 344, + Jaz2 = 345, + PocketZip = 346, + REV120 = 347, + REV35 = 348, + REV70 = 349, + ZIP100 = 350, + ZIP250 = 351, + ZIP750 = 352, + /// 5⅓" Bernoulli Box II disk with 35Mb capacity + Bernoulli35 = 353, + /// 5⅓" Bernoulli Box II disk with 44Mb capacity + Bernoulli44 = 354, + /// 5⅓" Bernoulli Box II disk with 65Mb capacity + Bernoulli65 = 355, + /// 5⅓" Bernoulli Box II disk with 90Mb capacity + Bernoulli90 = 356, + /// 5⅓" Bernoulli Box II disk with 105Mb capacity + Bernoulli105 = 357, + /// 5⅓" Bernoulli Box II disk with 150Mb capacity + Bernoulli150 = 358, + /// 5⅓" Bernoulli Box II disk with 230Mb capacity + Bernoulli230 = 359, + +#endregion Iomega, types 340 to 359 + +#region Audio or video media, types 360 to 369 + + CompactCassette = 360, + Data8 = 361, + MiniDV = 362, + /// D/CAS-25: Digital data on Compact Cassette form factor, special magnetic media, 9-track + Dcas25 = 363, + /// D/CAS-85: Digital data on Compact Cassette form factor, special magnetic media, 17-track + Dcas85 = 364, + /// D/CAS-103: Digital data on Compact Cassette form factor, special magnetic media, 21-track + Dcas103 = 365, + +#endregion Audio media, types 360 to 369 + +#region CompactFlash Association, types 370 to 379 + + CFast = 370, + CompactFlash = 371, + CompactFlashType2 = 372, + +#endregion CompactFlash Association, types 370 to 379 + +#region Digital Audio Tape / Digital Data Storage, types 380 to 389 + + DigitalAudioTape = 380, + DAT160 = 381, + DAT320 = 382, + DAT72 = 383, + DDS1 = 384, + DDS2 = 385, + DDS3 = 386, + DDS4 = 387, + +#endregion Digital Audio Tape / Digital Data Storage, types 380 to 389 + +#region DEC, types 390 to 399 + + CompactTapeI = 390, + CompactTapeII = 391, + DECtapeII = 392, + DLTtapeIII = 393, + DLTtapeIIIxt = 394, + DLTtapeIV = 395, + DLTtapeS4 = 396, + SDLT1 = 397, + SDLT2 = 398, + VStapeI = 399, + +#endregion DEC, types 390 to 399 + +#region Exatape, types 400 to 419 + + Exatape15m = 400, + Exatape22m = 401, + Exatape22mAME = 402, + Exatape28m = 403, + Exatape40m = 404, + Exatape45m = 405, + Exatape54m = 406, + Exatape75m = 407, + Exatape76m = 408, + Exatape80m = 409, + Exatape106m = 410, + Exatape160mXL = 411, + Exatape112m = 412, + Exatape125m = 413, + Exatape150m = 414, + Exatape170m = 415, + Exatape225m = 416, + +#endregion Exatape, types 400 to 419 + +#region PCMCIA / ExpressCard, types 420 to 429 + + ExpressCard34 = 420, + ExpressCard54 = 421, + PCCardTypeI = 422, + PCCardTypeII = 423, + PCCardTypeIII = 424, + PCCardTypeIV = 425, + +#endregion PCMCIA / ExpressCard, types 420 to 429 + +#region SyQuest, types 430 to 449 + + /// SyQuest 135Mb cartridge for use in EZ135 and EZFlyer drives + EZ135 = 430, + /// SyQuest EZFlyer 230Mb cartridge for use in EZFlyer drive + EZ230 = 431, + /// SyQuest 4.7Gb for use in Quest drive + Quest = 432, + /// SyQuest SparQ 1Gb cartridge + SparQ = 433, + /// SyQuest 5Mb cartridge for SQ306RD drive + SQ100 = 434, + /// SyQuest 10Mb cartridge for SQ312RD drive + SQ200 = 435, + /// SyQuest 15Mb cartridge for SQ319RD drive + SQ300 = 436, + /// SyQuest 105Mb cartridge for SQ3105 and SQ3270 drives + SQ310 = 437, + /// SyQuest 270Mb cartridge for SQ3270 drive + SQ327 = 438, + /// SyQuest 44Mb cartridge for SQ555, SQ5110 and SQ5200C/SQ200 drives + SQ400 = 439, + /// SyQuest 88Mb cartridge for SQ5110 and SQ5200C/SQ200 drives + SQ800 = 440, + /// SyQuest 1.5Gb cartridge for SyJet drive + [Obsolete] + SQ1500 = 441, + /// SyQuest 200Mb cartridge for use in SQ5200C drive + SQ2000 = 442, + /// SyQuest 1.5Gb cartridge for SyJet drive + SyJet = 443, + +#endregion SyQuest, types 430 to 449 + +#region Nintendo, types 450 to 469 + + FamicomGamePak = 450, + GameBoyAdvanceGamePak = 451, + GameBoyGamePak = 452, + /// Nintendo GameCube Optical Disc + GOD = 453, + N64DD = 454, + N64GamePak = 455, + NESGamePak = 456, + Nintendo3DSGameCard = 457, + NintendoDiskCard = 458, + NintendoDSGameCard = 459, + NintendoDSiGameCard = 460, + SNESGamePak = 461, + SNESGamePakUS = 462, + /// Nintendo Wii Optical Disc + WOD = 463, + /// Nintendo Wii U Optical Disc + WUOD = 464, + SwitchGameCard = 465, + +#endregion Nintendo, types 450 to 469 + +#region IBM Tapes, types 470 to 479 + + IBM3470 = 470, + IBM3480 = 471, + IBM3490 = 472, + IBM3490E = 473, + IBM3592 = 474, + +#endregion IBM Tapes, types 470 to 479 + +#region LTO Ultrium, types 480 to 509 + + LTO = 480, + LTO2 = 481, + LTO3 = 482, + LTO3WORM = 483, + LTO4 = 484, + LTO4WORM = 485, + LTO5 = 486, + LTO5WORM = 487, + LTO6 = 488, + LTO6WORM = 489, + LTO7 = 490, + LTO7WORM = 491, + +#endregion LTO Ultrium, types 480 to 509 + +#region MemoryStick, types 510 to 519 + + MemoryStick = 510, + MemoryStickDuo = 511, + MemoryStickMicro = 512, + MemoryStickPro = 513, + MemoryStickProDuo = 514, + +#endregion MemoryStick, types 510 to 519 + +#region SecureDigital, types 520 to 529 + + microSD = 520, + miniSD = 521, + SecureDigital = 522, + +#endregion SecureDigital, types 520 to 529 + +#region MultiMediaCard, types 530 to 539 + + MMC = 530, + MMCmicro = 531, + RSMMC = 532, + MMCplus = 533, + MMCmobile = 534, + +#endregion MultiMediaCard, types 530 to 539 + +#region SLR, types 540 to 569 + + MLR1 = 540, + MLR1SL = 541, + MLR3 = 542, + SLR1 = 543, + SLR2 = 544, + SLR3 = 545, + SLR32 = 546, + SLR32SL = 547, + SLR4 = 548, + SLR5 = 549, + SLR5SL = 550, + SLR6 = 551, + SLRtape7 = 552, + SLRtape7SL = 553, + SLRtape24 = 554, + SLRtape24SL = 555, + SLRtape40 = 556, + SLRtape50 = 557, + SLRtape60 = 558, + SLRtape75 = 559, + SLRtape100 = 560, + SLRtape140 = 561, + +#endregion SLR, types 540 to 569 + +#region QIC, types 570 to 589 + + QIC11 = 570, + QIC120 = 571, + QIC1350 = 572, + QIC150 = 573, + QIC24 = 574, + QIC3010 = 575, + QIC3020 = 576, + QIC3080 = 577, + QIC3095 = 578, + QIC320 = 579, + QIC40 = 580, + QIC525 = 581, + QIC80 = 582, + +#endregion QIC, types 570 to 589 + +#region StorageTek tapes, types 590 to 609 + + STK4480 = 590, + STK4490 = 591, + STK9490 = 592, + T9840A = 593, + T9840B = 594, + T9840C = 595, + T9840D = 596, + T9940A = 597, + T9940B = 598, + T10000A = 599, + T10000B = 600, + T10000C = 601, + T10000D = 602, + +#endregion StorageTek tapes, types 590 to 609 + +#region Travan, types 610 to 619 + + Travan = 610, + Travan1Ex = 611, + Travan3 = 612, + Travan3Ex = 613, + Travan4 = 614, + Travan5 = 615, + Travan7 = 616, + +#endregion Travan, types 610 to 619 + +#region VXA, types 620 to 629 + + VXA1 = 620, + VXA2 = 621, + VXA3 = 622, + +#endregion VXA, types 620 to 629 + +#region Magneto-optical, types 630 to 659 + + /// 5,25", M.O., WORM, 650Mb, 318750 sectors, 1024 bytes/sector, ECMA-153, ISO 11560 + ECMA_153 = 630, + /// 5,25", M.O., WORM, 600Mb, 581250 sectors, 512 bytes/sector, ECMA-153, ISO 11560 + ECMA_153_512 = 631, + /// 3,5", M.O., RW, 128Mb, 248826 sectors, 512 bytes/sector, ECMA-154, ISO 10090 + ECMA_154 = 632, + /// 5,25", M.O., RW/WORM, 1Gb, 904995 sectors, 512 bytes/sector, ECMA-183, ISO 13481 + ECMA_183_512 = 633, + /// 5,25", M.O., RW/WORM, 1Gb, 498526 sectors, 1024 bytes/sector, ECMA-183, ISO 13481 + ECMA_183 = 634, + /// 5,25", M.O., RW/WORM, 1.2Gb, 1165600 sectors, 512 bytes/sector, ECMA-184, ISO 13549 + ECMA_184_512 = 635, + /// 5,25", M.O., RW/WORM, 1.3Gb, 639200 sectors, 1024 bytes/sector, ECMA-184, ISO 13549 + ECMA_184 = 636, + /// 300mm, M.O., WORM, ??? sectors, 1024 bytes/sector, ECMA-189, ISO 13614 + ECMA_189 = 637, + /// 300mm, M.O., WORM, ??? sectors, 1024 bytes/sector, ECMA-190, ISO 13403 + ECMA_190 = 638, + /// 5,25", M.O., RW/WORM, 936921 or 948770 sectors, 1024 bytes/sector, ECMA-195, ISO 13842 + ECMA_195 = 639, + /// 5,25", M.O., RW/WORM, 1644581 or 1647371 sectors, 512 bytes/sector, ECMA-195, ISO 13842 + ECMA_195_512 = 640, + /// 3,5", M.O., 446325 sectors, 512 bytes/sector, ECMA-201, ISO 13963 + ECMA_201 = 641, + /// 3,5", M.O., 429975 sectors, 512 bytes/sector, embossed, ISO 13963 + ECMA_201_ROM = 642, + /// 3,5", M.O., 371371 sectors, 1024 bytes/sector, ECMA-223 + ECMA_223 = 643, + /// 3,5", M.O., 694929 sectors, 512 bytes/sector, ECMA-223 + ECMA_223_512 = 644, + /// 5,25", M.O., 1244621 sectors, 1024 bytes/sector, ECMA-238, ISO 15486 + ECMA_238 = 645, + /// 3,5", M.O., 310352, 320332 or 321100 sectors, 2048 bytes/sector, ECMA-239, ISO 15498 + ECMA_239 = 646, + /// 356mm, M.O., 14476734 sectors, 1024 bytes/sector, ECMA-260, ISO 15898 + ECMA_260 = 647, + /// 356mm, M.O., 24445990 sectors, 1024 bytes/sector, ECMA-260, ISO 15898 + ECMA_260_Double = 648, + /// 5,25", M.O., 1128134 sectors, 2048 bytes/sector, ECMA-280, ISO 18093 + ECMA_280 = 649, + /// 300mm, M.O., 7355716 sectors, 2048 bytes/sector, ECMA-317, ISO 20162 + ECMA_317 = 650, + /// 5,25", M.O., 1095840 sectors, 4096 bytes/sector, ECMA-322, ISO 22092, 9.1Gb/cart + ECMA_322 = 651, + /// 5,25", M.O., 2043664 sectors, 2048 bytes/sector, ECMA-322, ISO 22092, 8.6Gb/cart + ECMA_322_2k = 652, + /// 3,5", M.O., 605846 sectors, 2048 bytes/sector, Cherry Book, GigaMo, ECMA-351, ISO 17346 + GigaMo = 653, + /// 3,5", M.O., 1063146 sectors, 2048 bytes/sector, Cherry Book 2, GigaMo 2, ECMA-353, ISO 22533 + GigaMo2 = 654, + /// 5,25", M.O., 1263472 sectors, 2048 bytes/sector, ISO 15286, 5.2Gb/cart + ISO_15286 = 655, + /// 5,25", M.O., 2319786 sectors, 1024 bytes/sector, ISO 15286, 4.8Gb/cart + ISO_15286_1024 = 656, + /// 5,25", M.O., ??????? sectors, 512 bytes/sector, ISO 15286, 4.1Gb/cart + ISO_15286_512 = 657, + /// 5,25", M.O., 314569 sectors, 1024 bytes/sector, ISO 10089, 650Mb/cart + ISO_10089 = 658, + /// 5,25", M.O., ?????? sectors, 512 bytes/sector, ISO 10089, 594Mb/cart + ISO_10089_512 = 659, + +#endregion Magneto-optical, types 630 to 659 + +#region Other floppy standards, types 660 to 689 + + CompactFloppy = 660, + DemiDiskette = 661, + /// 3.5", 652 tracks, 2 sides, 512 bytes/sector, Floptical, ECMA-207, ISO 14169 + Floptical = 662, + HiFD = 663, + QuickDisk = 664, + UHD144 = 665, + VideoFloppy = 666, + Wafer = 667, + ZXMicrodrive = 668, + /// 5.25", SS, DD, 77 tracks, 16 spt, 256 bytes/sector, MFM, 100 tpi, 300rpm + MetaFloppy_Mod_II = 669, + +#endregion Other floppy standards, types 660 to 669 + +#region Miscellaneous, types 670 to 689 + + BeeCard = 670, + Borsu = 671, + DataStore = 672, + DIR = 673, + DST = 674, + DTF = 675, + DTF2 = 676, + Flextra3020 = 677, + Flextra3225 = 678, + HiTC1 = 679, + HiTC2 = 680, + LT1 = 681, + MiniCard = 872, + Orb = 683, + Orb5 = 684, + SmartMedia = 685, + xD = 686, + XQD = 687, + DataPlay = 688, + +#endregion Miscellaneous, types 670 to 689 + +#region Apple specific media, types 690 to 699 + + AppleProfile = 690, + AppleWidget = 691, + AppleHD20 = 692, + PriamDataTower = 693, + Pippin = 694, + +#endregion Apple specific media, types 690 to 699 + +#region DEC hard disks, types 700 to 729 + + /// + /// 2382 cylinders, 4 tracks/cylinder, 42 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 204890112 bytes + /// + RA60 = 700, + /// + /// 546 cylinders, 14 tracks/cylinder, 31 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 121325568 bytes + /// + RA80 = 701, + /// + /// 1248 cylinders, 14 tracks/cylinder, 51 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 456228864 bytes + /// + RA81 = 702, + /// + /// 302 cylinders, 4 tracks/cylinder, 42 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 25976832 + /// bytes + /// + RC25 = 703, + /// + /// 615 cylinders, 4 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 21411840 + /// bytes + /// + RD31 = 704, + /// + /// 820 cylinders, 6 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 42823680 + /// bytes + /// + RD32 = 705, + /// + /// 306 cylinders, 4 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 10653696 + /// bytes + /// + RD51 = 706, + /// + /// 480 cylinders, 7 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 30965760 + /// bytes + /// + RD52 = 707, + /// + /// 1024 cylinders, 7 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 75497472 bytes + /// + RD53 = 708, + /// + /// 1225 cylinders, 8 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 159936000 bytes + /// + RD54 = 709, + /// + /// 411 cylinders, 3 tracks/cylinder, 22 sectors/track, 256 words/sector, 16 bits/word, 512 bytes/sector, 13888512 + /// bytes + /// + RK06 = 710, + /// + /// 411 cylinders, 3 tracks/cylinder, 20 sectors/track, 256 words/sector, 18 bits/word, 576 bytes/sector, 14204160 + /// bytes + /// + RK06_18 = 711, + /// + /// 815 cylinders, 3 tracks/cylinder, 22 sectors/track, 256 words/sector, 16 bits/word, 512 bytes/sector, 27540480 + /// bytes + /// + RK07 = 712, + /// + /// 815 cylinders, 3 tracks/cylinder, 20 sectors/track, 256 words/sector, 18 bits/word, 576 bytes/sector, 28166400 + /// bytes + /// + RK07_18 = 713, + /// + /// 823 cylinders, 5 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 67420160 + /// bytes + /// + RM02 = 714, + /// + /// 823 cylinders, 5 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 67420160 + /// bytes + /// + RM03 = 715, + /// + /// 823 cylinders, 19 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 256196608 bytes + /// + RM05 = 716, + /// + /// 203 cylinders, 10 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 22865920 bytes + /// + RP02 = 717, + /// + /// 203 cylinders, 10 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, + /// 23385600 bytes + /// + RP02_18 = 718, + /// + /// 400 cylinders, 10 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 45056000 bytes + /// + RP03 = 719, + /// + /// 400 cylinders, 10 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, + /// 46080000 bytes + /// + RP03_18 = 720, + /// + /// 411 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 87960576 bytes + /// + RP04 = 721, + /// + /// 411 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, + /// 89959680 bytes + /// + RP04_18 = 722, + /// + /// 411 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 87960576 bytes + /// + RP05 = 723, + /// + /// 411 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, + /// 89959680 bytes + /// + RP05_18 = 724, + /// + /// 815 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 174423040 bytes + /// + RP06 = 725, + /// + /// 815 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, + /// 178387200 bytes + /// + RP06_18 = 726, + +#endregion DEC hard disks, types 700 to 729 + +#region Imation, types 730 to 739 + + LS120 = 730, + LS240 = 731, + FD32MB = 732, + RDX = 733, + /// Imation 320Gb RDX + RDX320 = 734, + +#endregion Imation, types 730 to 739 + +#region VideoNow, types 740 to 749 + + VideoNow = 740, + VideoNowColor = 741, + VideoNowXp = 742, + +#endregion + +#region Iomega, types 750 to 759 + + /// 8"x11" Bernoulli Box disk with 10Mb capacity + Bernoulli10 = 750, + /// 8"x11" Bernoulli Box disk with 20Mb capacity + Bernoulli20 = 751, + /// 5⅓" Bernoulli Box II disk with 20Mb capacity + BernoulliBox2_20 = 752, + +#endregion Iomega, types 750 to 759 + +#region Kodak, types 760 to 769 + + KodakVerbatim3 = 760, + KodakVerbatim6 = 761, + KodakVerbatim12 = 762, + +#endregion Kodak, types 760 to 769 + +#region Sony and Panasonic Blu-ray derived, types 770 to 799 + + /// Professional Disc for video, single layer, rewritable, 23Gb + ProfessionalDisc = 770, + /// Professional Disc for video, dual layer, rewritable, 50Gb + ProfessionalDiscDual = 771, + /// Professional Disc for video, triple layer, rewritable, 100Gb + ProfessionalDiscTriple = 772, + /// Professional Disc for video, quad layer, write once, 128Gb + ProfessionalDiscQuad = 773, + /// Professional Disc for DATA, single layer, rewritable, 23Gb + PDD = 774, + /// Professional Disc for DATA, single layer, write once, 23Gb + PDD_WORM = 775, + /// Archival Disc, 1st gen., 300Gb + ArchivalDisc = 776, + /// Archival Disc, 2nd gen., 500Gb + ArchivalDisc2 = 777, + /// Archival Disc, 3rd gen., 1Tb + ArchivalDisc3 = 778, + /// Optical Disc archive, 1st gen., write once, 300Gb + ODC300R = 779, + /// Optical Disc archive, 1st gen., rewritable, 300Gb + ODC300RE = 780, + /// Optical Disc archive, 2nd gen., write once, 600Gb + ODC600R = 781, + /// Optical Disc archive, 2nd gen., rewritable, 600Gb + ODC600RE = 782, + /// Optical Disc archive, 3rd gen., rewritable, 1200Gb + ODC1200RE = 783, + /// Optical Disc archive, 3rd gen., write once, 1500Gb + ODC1500R = 784, + /// Optical Disc archive, 4th gen., write once, 3300Gb + ODC3300R = 785, + /// Optical Disc archive, 5th gen., write once, 5500Gb + ODC5500R = 786, + +#endregion Sony and Panasonic Blu-ray derived, types 770 to 799 + +#region Magneto-optical, types 800 to 819 + + /// 5,25", M.O., 4383356 sectors, 1024 bytes/sector, ECMA-322, ISO 22092, 9.1Gb/cart + ECMA_322_1k = 800, + /// 5,25", M.O., ??????? sectors, 512 bytes/sector, ECMA-322, ISO 22092, 9.1Gb/cart + ECMA_322_512 = 801, + /// 5,25", M.O., 1273011 sectors, 1024 bytes/sector, ISO 14517, 2.6Gb/cart + ISO_14517 = 802, + /// 5,25", M.O., 2244958 sectors, 512 bytes/sector, ISO 14517, 2.3Gb/cart + ISO_14517_512 = 803, + /// 3,5", M.O., 1041500 sectors, 512 bytes/sector, ISO 15041, 540Mb/cart + ISO_15041_512 = 804, + +#endregion Magneto-optical, types 800 to 819 + +#region More floppy formats, types 820 to deprecated + + /// 5.25", SS, DD, 35 tracks, 16 spt, 256 bytes/sector, MFM, 48 tpi, ???rpm + MetaFloppy_Mod_I = 820, + /// HyperFlex (12Mb), 5.25", DS, 301 tracks, 78 spt, 256 bytes/sector, MFM, 333 tpi, 600rpm + HF12 = 823, + /// HyperFlex (24Mb), 5.25", DS, 506 tracks, 78 spt, 256 bytes/sector, MFM, 666 tpi, 720rpm + HF24 = 824, + +#endregion + + AtariLynxCard = 821, + AtariJaguarCartridge = 822 +} \ No newline at end of file diff --git a/Aaru.CommonTypes/MediaType.csv b/Aaru.CommonTypes/MediaType.csv new file mode 100644 index 000000000..154aa40ee --- /dev/null +++ b/Aaru.CommonTypes/MediaType.csv @@ -0,0 +1,542 @@ +Enum,Value,Summary +"Unknown",0,"Unknown disk type" +"UnknownMO",1,"Unknown magneto-optical" +"GENERIC_HDD",2,"Generic hard disk" +"Microdrive",3,"Microdrive type hard disk" +"Zone_HDD",4,"Zoned hard disk" +"FlashDrive",5,"USB flash drives" +"UnknownTape",6,"Unknown data tape" +"CD",10,"Any unknown or standard violating CD" +"CDDA",11,"CD Digital Audio (Red Book)" +"CDG",12,"CD+G (Red Book)" +"CDEG",13,"CD+EG (Red Book)" +"CDI",14,"CD-i (Green Book)" +"CDROM",15,"CD-ROM (Yellow Book)" +"CDROMXA",16,"CD-ROM XA (Yellow Book)" +"CDPLUS",17,"CD+ (Blue Book)" +"CDMO",18,"CD-MO (Orange Book)" +"CDR",19,"CD-Recordable (Orange Book)" +"CDRW",20,"CD-ReWritable (Orange Book)" +"CDMRW",21,"Mount-Rainier CD-RW" +"VCD",22,"Video CD (White Book)" +"SVCD",23,"Super Video CD (White Book)" +"PCD",24,"Photo CD (Beige Book)" +"SACD",25,"Super Audio CD (Scarlet Book)" +"DDCD",26,"Double-Density CD-ROM (Purple Book)" +"DDCDR",27,"DD CD-R (Purple Book)" +"DDCDRW",28,"DD CD-RW (Purple Book)" +"DTSCD",29,"DTS audio CD (non-standard)" +"CDMIDI",30,"CD-MIDI (Red Book)" +"CDV",31,"CD-Video (ISO/IEC 61104)" +"PD650",32,"120mm, Phase-Change, 1298496 sectors, 512 bytes/sector, PD650, ECMA-240, ISO 15485" +"PD650_WORM",33,"120mm, Write-Once, 1281856 sectors, 512 bytes/sector, PD650, ECMA-240, ISO 15485" +"CDIREADY",34,"CD-i Ready, contains a track before the first TOC track, in mode 2, and all TOC tracks are Audio. Subchannel marks track as audio pause." +"FMTOWNS",35, +"DVDROM",40,"DVD-ROM (applies to DVD Video and DVD Audio)" +"DVDR",41,"DVD-R" +"DVDRW",42,"DVD-RW" +"DVDPR",43,"DVD+R" +"DVDPRW",44,"DVD+RW" +"DVDPRWDL",45,"DVD+RW DL" +"DVDRDL",46,"DVD-R DL" +"DVDPRDL",47,"DVD+R DL" +"DVDRAM",48,"DVD-RAM" +"DVDRWDL",49,"DVD-RW DL" +"DVDDownload",50,"DVD-Download" +"HDDVDROM",51,"HD DVD-ROM (applies to HD DVD Video)" +"HDDVDRAM",52,"HD DVD-RAM" +"HDDVDR",53,"HD DVD-R" +"HDDVDRW",54,"HD DVD-RW" +"HDDVDRDL",55,"HD DVD-R DL" +"HDDVDRWDL",56,"HD DVD-RW DL" +"BDROM",60,"BD-ROM (and BD Video)" +"BDR",61,"BD-R" +"BDRE",62,"BD-RE" +"BDRXL",63,"BD-R XL" +"BDREXL",64,"BD-RE XL" +"UHDBD",65,"Ultra HD Blu-ray" +"EVD",70,"Enhanced Versatile Disc" +"FVD",71,"Forward Versatile Disc" +"HVD",72,"Holographic Versatile Disc" +"CBHD",73,"China Blue High Definition" +"HDVMD",74,"High Definition Versatile Multilayer Disc" +"VCDHD",75,"Versatile Compact Disc High Density" +"SVOD",76,"Stacked Volumetric Optical Disc" +"FDDVD",77,"Five Dimensional disc" +"CVD",78,"China Video Disc" +"LD",80,"Pioneer LaserDisc" +"LDROM",81,"Pioneer LaserDisc data" +"LDROM2",82, +"LVROM",83, +"MegaLD",84, +"CRVdisc",85,"Writable LaserDisc with support for component video" +"HiMD",90,"Sony Hi-MD" +"MD",91,"Sony MiniDisc" +"MDData",92,"Sony MD-Data" +"MDData2",93,"Sony MD-Data2" +"MD60",94,"Sony MiniDisc, 60 minutes, formatted with Hi-MD format" +"MD74",95,"Sony MiniDisc, 74 minutes, formatted with Hi-MD format" +"MD80",96,"Sony MiniDisc, 80 minutes, formatted with Hi-MD format" +"UDO",100,"5.25"", Phase-Change, 1834348 sectors, 8192 bytes/sector, Ultra Density Optical, ECMA-350, ISO 17345" +"UDO2",101,"5.25"", Phase-Change, 3669724 sectors, 8192 bytes/sector, Ultra Density Optical 2, ECMA-380, ISO 11976" +"UDO2_WORM",102,"5.25"", Write-Once, 3668759 sectors, 8192 bytes/sector, Ultra Density Optical 2, ECMA-380, ISO 11976" +"PlayStationMemoryCard",110, +"PlayStationMemoryCard2",111, +"PS1CD",112,"Sony PlayStation game CD" +"PS2CD",113,"Sony PlayStation 2 game CD" +"PS2DVD",114,"Sony PlayStation 2 game DVD" +"PS3DVD",115,"Sony PlayStation 3 game DVD" +"PS3BD",116,"Sony PlayStation 3 game Blu-ray" +"PS4BD",117,"Sony PlayStation 4 game Blu-ray" +"UMD",118,"Sony PlayStation Portable Universal Media Disc (ECMA-365)" +"PlayStationVitaGameCard",119, +"PS5BD",120,"Sony PlayStation 5 game Ultra HD Blu-ray" +"XGD",130,"Microsoft X-box Game Disc" +"XGD2",131,"Microsoft X-box 360 Game Disc" +"XGD3",132,"Microsoft X-box 360 Game Disc" +"XGD4",133,"Microsoft X-box One Game Disc" +"MEGACD",150,"Sega MegaCD" +"SATURNCD",151,"Sega Saturn disc" +"GDROM",152,"Sega/Yamaha Gigabyte Disc" +"GDR",153,"Sega/Yamaha recordable Gigabyte Disc" +"SegaCard",154, +"MilCD",155, +"MegaDriveCartridge",156, +"_32XCartridge",157, +"SegaPicoCartridge",158, +"MasterSystemCartridge",159, +"GameGearCartridge",160, +"SegaSaturnCartridge",161, +"HuCard",170,"PC-Engine / TurboGrafx cartridge" +"SuperCDROM2",171,"PC-Engine / TurboGrafx CD" +"JaguarCD",172,"Atari Jaguar CD" +"ThreeDO",173,"3DO CD" +"PCFX",174,"NEC PC-FX" +"NeoGeoCD",175,"NEO-GEO CD" +"CDTV",176,"Commodore CDTV" +"CD32",177,"Amiga CD32" +"Nuon",178,"Nuon (DVD based videogame console)" +"Playdia",179,"Bandai Playdia" +"Apple32SS",180,"5.25"", SS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR" +"Apple32DS",181,"5.25"", DS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR" +"Apple33SS",182,"5.25"", SS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR" +"Apple33DS",183,"5.25"", DS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR" +"AppleSonySS",184,"3.5"", SS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR" +"AppleSonyDS",185,"3.5"", DS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR" +"AppleFileWare",186,"5.25"", DS, ?D, ?? tracks, ?? spt, 512 bytes/sector, GCR, opposite side heads, aka Twiggy" +"DOS_525_SS_DD_8",190,"5.25"", SS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM" +"DOS_525_SS_DD_9",191,"5.25"", SS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM" +"DOS_525_DS_DD_8",192,"5.25"", DS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM" +"DOS_525_DS_DD_9",193,"5.25"", DS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM" +"DOS_525_HD",194,"5.25"", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM" +"DOS_35_SS_DD_8",195,"3.5"", SS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM" +"DOS_35_SS_DD_9",196,"3.5"", SS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM" +"DOS_35_DS_DD_8",197,"3.5"", DS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM" +"DOS_35_DS_DD_9",198,"3.5"", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM" +"DOS_35_HD",199,"3.5"", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM" +"DOS_35_ED",200,"3.5"", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM" +"DMF",201,"3.5"", DS, HD, 80 tracks, 21 spt, 512 bytes/sector, MFM" +"DMF_82",202,"3.5"", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM" +"XDF_525",203,"5.25"", DS, HD, 80 tracks, ? spt, ??? + ??? + ??? bytes/sector, MFM track 0 = ??15 sectors, 512 bytes/sector, falsified to DOS as 19 spt, 512 bps" +"XDF_35",204,"3.5"", DS, HD, 80 tracks, 4 spt, 8192 + 2048 + 1024 + 512 bytes/sector, MFM track 0 = 19 sectors, 512 bytes/sector, falsified to DOS as 23 spt, 512 bps" +"IBM23FD",210,"8"", SS, SD, 32 tracks, 8 spt, 319 bytes/sector, FM" +"IBM33FD_128",211,"8"", SS, SD, 73 tracks, 26 spt, 128 bytes/sector, FM" +"IBM33FD_256",212,"8"", SS, SD, 74 tracks, 15 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector" +"IBM33FD_512",213,"8"", SS, SD, 74 tracks, 8 spt, 512 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector" +"IBM43FD_128",214,"8"", DS, SD, 74 tracks, 26 spt, 128 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector" +"IBM43FD_256",215,"8"", DS, SD, 74 tracks, 26 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector" +"IBM53FD_256",216,"8"", DS, DD, 74 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector" +"IBM53FD_512",217,"8"", DS, DD, 74 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector" +"IBM53FD_1024",218,"8"", DS, DD, 74 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector" +"RX01",220,"8"", SS, DD, 77 tracks, 26 spt, 128 bytes/sector, FM" +"RX02",221,"8"", SS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM" +"RX03",222,"8"", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM" +"RX50",223,"5.25"", SS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM" +"ACORN_525_SS_SD_40",230,"5,25"", SS, SD, 40 tracks, 10 spt, 256 bytes/sector, FM" +"ACORN_525_SS_SD_80",231,"5,25"", SS, SD, 80 tracks, 10 spt, 256 bytes/sector, FM" +"ACORN_525_SS_DD_40",232,"5,25"", SS, DD, 40 tracks, 16 spt, 256 bytes/sector, MFM" +"ACORN_525_SS_DD_80",233,"5,25"", SS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM" +"ACORN_525_DS_DD",234,"5,25"", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM" +"ACORN_35_DS_DD",235,"3,5"", DS, DD, 80 tracks, 5 spt, 1024 bytes/sector, MFM" +"ACORN_35_DS_HD",236,"3,5"", DS, HD, 80 tracks, 10 spt, 1024 bytes/sector, MFM" +"ATARI_525_SD",240,"5,25"", SS, SD, 40 tracks, 18 spt, 128 bytes/sector, FM" +"ATARI_525_ED",241,"5,25"", SS, ED, 40 tracks, 26 spt, 128 bytes/sector, MFM" +"ATARI_525_DD",242,"5,25"", SS, DD, 40 tracks, 18 spt, 256 bytes/sector, MFM" +"ATARI_35_SS_DD",243,"3,5"", SS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM" +"ATARI_35_DS_DD",244,"3,5"", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM" +"ATARI_35_SS_DD_11",245,"3,5"", SS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM" +"ATARI_35_DS_DD_11",246,"3,5"", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM" +"CBM_35_DD",250,"3,5"", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM (1581)" +"CBM_AMIGA_35_DD",251,"3,5"", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM (Amiga)" +"CBM_AMIGA_35_HD",252,"3,5"", DS, HD, 80 tracks, 22 spt, 512 bytes/sector, MFM (Amiga)" +"CBM_1540",253,"5,25"", SS, DD, 35 tracks, GCR" +"CBM_1540_Ext",254,"5,25"", SS, DD, 40 tracks, GCR" +"CBM_1571",255,"5,25"", DS, DD, 35 tracks, GCR" +"NEC_8_SD",260,"8"", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM" +"NEC_8_DD",261,"8"", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM" +"NEC_525_SS",262,"5.25"", SS, SD, 80 tracks, 16 spt, 256 bytes/sector, FM" +"NEC_525_DS",263,"5.25"", DS, SD, 80 tracks, 16 spt, 256 bytes/sector, MFM" +"NEC_525_HD",264,"5,25"", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM" +"NEC_35_HD_8",265,"3,5"", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM, aka mode 3" +"NEC_35_HD_15",266,"3,5"", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM" +"NEC_35_TD",267,"3,5"", DS, TD, 240 tracks, 38 spt, 512 bytes/sector, MFM" +"SHARP_525",NEC_525_HD,"5,25"", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM" +"SHARP_525_9",268,"3,5"", DS, HD, 80 tracks, 9 spt, 1024 bytes/sector, MFM" +"SHARP_35",NEC_35_HD_8,"3,5"", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM" +"SHARP_35_9",269,"3,5"", DS, HD, 80 tracks, 9 spt, 1024 bytes/sector, MFM" +"ECMA_99_8",270,"5,25"", DS, DD, 80 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector" +"ECMA_99_15",271,"5,25"", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector" +"ECMA_99_26",272,"5,25"", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector" +"ECMA_100",DOS_35_DS_DD_9,"3,5"", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM" +"ECMA_125",DOS_35_HD,"3,5"", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM" +"ECMA_147",DOS_35_ED,"3,5"", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM" +"ECMA_54",273,"8"", SS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM" +"ECMA_59",274,"8"", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM" +"ECMA_66",275,"5,25"", SS, DD, 35 tracks, 9 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector" +"ECMA_69_8",276,"8"", DS, DD, 77 tracks, 8 spt, 1024 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector" +"ECMA_69_15",277,"8"", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector" +"ECMA_69_26",278,"8"", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector" +"ECMA_70",279,"5,25"", DS, DD, 40 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector, track 0 side 1 = 16 sectors, 256 bytes/sector" +"ECMA_78",280,"5,25"", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector, track 0 side 1 = 16 sectors, 256 bytes/sector" +"ECMA_78_2",281,"5,25"", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, FM" +"FDFORMAT_525_DD",290,"5,25"", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM" +"FDFORMAT_525_HD",291,"5,25"", DS, HD, 82 tracks, 17 spt, 512 bytes/sector, MFM" +"FDFORMAT_35_DD",292,"3,5"", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM" +"FDFORMAT_35_HD",293,"3,5"", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM" +"Apricot_35",309,"3.5"", DS, DD, 70 tracks, 9 spt, 512 bytes/sector, MFM" +"ADR2120",310, +"ADR260",311, +"ADR30",312, +"ADR50",313, +"AIT1",320, +"AIT1Turbo",321, +"AIT2",322, +"AIT2Turbo",323, +"AIT3",324, +"AIT3Ex",325, +"AIT3Turbo",326, +"AIT4",327, +"AIT5",328, +"AITETurbo",329, +"SAIT1",330, +"SAIT2",331, +"Bernoulli",340,"Obsolete type for 8""x11"" Bernoulli Box disk" +"Bernoulli2",341,"Obsolete type for 5⅓"" Bernoulli Box II disks" +"Ditto",342, +"DittoMax",343, +"Jaz",344, +"Jaz2",345, +"PocketZip",346, +"REV120",347, +"REV35",348, +"REV70",349, +"ZIP100",350, +"ZIP250",351, +"ZIP750",352, +"Bernoulli35",353,"5⅓"" Bernoulli Box II disk with 35Mb capacity" +"Bernoulli44",354,"5⅓"" Bernoulli Box II disk with 44Mb capacity" +"Bernoulli65",355,"5⅓"" Bernoulli Box II disk with 65Mb capacity" +"Bernoulli90",356,"5⅓"" Bernoulli Box II disk with 90Mb capacity" +"Bernoulli105",357,"5⅓"" Bernoulli Box II disk with 105Mb capacity" +"Bernoulli150",358,"5⅓"" Bernoulli Box II disk with 150Mb capacity" +"Bernoulli230",359,"5⅓"" Bernoulli Box II disk with 230Mb capacity" +"CompactCassette",360, +"Data8",361, +"MiniDV",362, +"Dcas25",363,"D/CAS-25: Digital data on Compact Cassette form factor, special magnetic media, 9-track" +"Dcas85",364,"D/CAS-85: Digital data on Compact Cassette form factor, special magnetic media, 17-track" +"Dcas103",365,"D/CAS-103: Digital data on Compact Cassette form factor, special magnetic media, 21-track" +"CFast",370, +"CompactFlash",371, +"CompactFlashType2",372, +"DigitalAudioTape",380, +"DAT160",381, +"DAT320",382, +"DAT72",383, +"DDS1",384, +"DDS2",385, +"DDS3",386, +"DDS4",387, +"CompactTapeI",390, +"CompactTapeII",391, +"DECtapeII",392, +"DLTtapeIII",393, +"DLTtapeIIIxt",394, +"DLTtapeIV",395, +"DLTtapeS4",396, +"SDLT1",397, +"SDLT2",398, +"VStapeI",399, +"Exatape15m",400, +"Exatape22m",401, +"Exatape22mAME",402, +"Exatape28m",403, +"Exatape40m",404, +"Exatape45m",405, +"Exatape54m",406, +"Exatape75m",407, +"Exatape76m",408, +"Exatape80m",409, +"Exatape106m",410, +"Exatape160mXL",411, +"Exatape112m",412, +"Exatape125m",413, +"Exatape150m",414, +"Exatape170m",415, +"Exatape225m",416, +"ExpressCard34",420, +"ExpressCard54",421, +"PCCardTypeI",422, +"PCCardTypeII",423, +"PCCardTypeIII",424, +"PCCardTypeIV",425, +"EZ135",430,"SyQuest 135Mb cartridge for use in EZ135 and EZFlyer drives" +"EZ230",431,"SyQuest EZFlyer 230Mb cartridge for use in EZFlyer drive" +"Quest",432,"SyQuest 4.7Gb for use in Quest drive" +"SparQ",433,"SyQuest SparQ 1Gb cartridge" +"SQ100",434,"SyQuest 5Mb cartridge for SQ306RD drive" +"SQ200",435,"SyQuest 10Mb cartridge for SQ312RD drive" +"SQ300",436,"SyQuest 15Mb cartridge for SQ319RD drive" +"SQ310",437,"SyQuest 105Mb cartridge for SQ3105 and SQ3270 drives" +"SQ327",438,"SyQuest 270Mb cartridge for SQ3270 drive" +"SQ400",439,"SyQuest 44Mb cartridge for SQ555, SQ5110 and SQ5200C/SQ200 drives" +"SQ800",440,"SyQuest 88Mb cartridge for SQ5110 and SQ5200C/SQ200 drives" +"SQ1500",441,"SyQuest 1.5Gb cartridge for SyJet drive" +"SQ2000",442,"SyQuest 200Mb cartridge for use in SQ5200C drive" +"SyJet",443,"SyQuest 1.5Gb cartridge for SyJet drive" +"FamicomGamePak",450, +"GameBoyAdvanceGamePak",451, +"GameBoyGamePak",452, +"GOD",453,"Nintendo GameCube Optical Disc" +"N64DD",454, +"N64GamePak",455, +"NESGamePak",456, +"Nintendo3DSGameCard",457, +"NintendoDiskCard",458, +"NintendoDSGameCard",459, +"NintendoDSiGameCard",460, +"SNESGamePak",461, +"SNESGamePakUS",462, +"WOD",463,"Nintendo Wii Optical Disc" +"WUOD",464,"Nintendo Wii U Optical Disc" +"SwitchGameCard",465, +"IBM3470",470, +"IBM3480",471, +"IBM3490",472, +"IBM3490E",473, +"IBM3592",474, +"LTO",480, +"LTO2",481, +"LTO3",482, +"LTO3WORM",483, +"LTO4",484, +"LTO4WORM",485, +"LTO5",486, +"LTO5WORM",487, +"LTO6",488, +"LTO6WORM",489, +"LTO7",490, +"LTO7WORM",491, +"MemoryStick",510, +"MemoryStickDuo",511, +"MemoryStickMicro",512, +"MemoryStickPro",513, +"MemoryStickProDuo",514, +"microSD",520, +"miniSD",521, +"SecureDigital",522, +"MMC",530, +"MMCmicro",531, +"RSMMC",532, +"MMCplus",533, +"MMCmobile",534, +"MLR1",540, +"MLR1SL",541, +"MLR3",542, +"SLR1",543, +"SLR2",544, +"SLR3",545, +"SLR32",546, +"SLR32SL",547, +"SLR4",548, +"SLR5",549, +"SLR5SL",550, +"SLR6",551, +"SLRtape7",552, +"SLRtape7SL",553, +"SLRtape24",554, +"SLRtape24SL",555, +"SLRtape40",556, +"SLRtape50",557, +"SLRtape60",558, +"SLRtape75",559, +"SLRtape100",560, +"SLRtape140",561, +"QIC11",570, +"QIC120",571, +"QIC1350",572, +"QIC150",573, +"QIC24",574, +"QIC3010",575, +"QIC3020",576, +"QIC3080",577, +"QIC3095",578, +"QIC320",579, +"QIC40",580, +"QIC525",581, +"QIC80",582, +"STK4480",590, +"STK4490",591, +"STK9490",592, +"T9840A",593, +"T9840B",594, +"T9840C",595, +"T9840D",596, +"T9940A",597, +"T9940B",598, +"T10000A",599, +"T10000B",600, +"T10000C",601, +"T10000D",602, +"Travan",610, +"Travan1Ex",611, +"Travan3",612, +"Travan3Ex",613, +"Travan4",614, +"Travan5",615, +"Travan7",616, +"VXA1",620, +"VXA2",621, +"VXA3",622, +"ECMA_153",630,"5,25"", M.O., WORM, 650Mb, 318750 sectors, 1024 bytes/sector, ECMA-153, ISO 11560" +"ECMA_153_512",631,"5,25"", M.O., WORM, 600Mb, 581250 sectors, 512 bytes/sector, ECMA-153, ISO 11560" +"ECMA_154",632,"3,5"", M.O., RW, 128Mb, 248826 sectors, 512 bytes/sector, ECMA-154, ISO 10090" +"ECMA_183_512",633,"5,25"", M.O., RW/WORM, 1Gb, 904995 sectors, 512 bytes/sector, ECMA-183, ISO 13481" +"ECMA_183",634,"5,25"", M.O., RW/WORM, 1Gb, 498526 sectors, 1024 bytes/sector, ECMA-183, ISO 13481" +"ECMA_184_512",635,"5,25"", M.O., RW/WORM, 1.2Gb, 1165600 sectors, 512 bytes/sector, ECMA-184, ISO 13549" +"ECMA_184",636,"5,25"", M.O., RW/WORM, 1.3Gb, 639200 sectors, 1024 bytes/sector, ECMA-184, ISO 13549" +"ECMA_189",637,"300mm, M.O., WORM, ??? sectors, 1024 bytes/sector, ECMA-189, ISO 13614" +"ECMA_190",638,"300mm, M.O., WORM, ??? sectors, 1024 bytes/sector, ECMA-190, ISO 13403" +"ECMA_195",639,"5,25"", M.O., RW/WORM, 936921 or 948770 sectors, 1024 bytes/sector, ECMA-195, ISO 13842" +"ECMA_195_512",640,"5,25"", M.O., RW/WORM, 1644581 or 1647371 sectors, 512 bytes/sector, ECMA-195, ISO 13842" +"ECMA_201",641,"3,5"", M.O., 446325 sectors, 512 bytes/sector, ECMA-201, ISO 13963" +"ECMA_201_ROM",642,"3,5"", M.O., 429975 sectors, 512 bytes/sector, embossed, ISO 13963" +"ECMA_223",643,"3,5"", M.O., 371371 sectors, 1024 bytes/sector, ECMA-223" +"ECMA_223_512",644,"3,5"", M.O., 694929 sectors, 512 bytes/sector, ECMA-223" +"ECMA_238",645,"5,25"", M.O., 1244621 sectors, 1024 bytes/sector, ECMA-238, ISO 15486" +"ECMA_239",646,"3,5"", M.O., 310352, 320332 or 321100 sectors, 2048 bytes/sector, ECMA-239, ISO 15498" +"ECMA_260",647,"356mm, M.O., 14476734 sectors, 1024 bytes/sector, ECMA-260, ISO 15898" +"ECMA_260_Double",648,"356mm, M.O., 24445990 sectors, 1024 bytes/sector, ECMA-260, ISO 15898" +"ECMA_280",649,"5,25"", M.O., 1128134 sectors, 2048 bytes/sector, ECMA-280, ISO 18093" +"ECMA_317",650,"300mm, M.O., 7355716 sectors, 2048 bytes/sector, ECMA-317, ISO 20162" +"ECMA_322",651,"5,25"", M.O., 1095840 sectors, 4096 bytes/sector, ECMA-322, ISO 22092, 9.1Gb/cart" +"ECMA_322_2k",652,"5,25"", M.O., 2043664 sectors, 2048 bytes/sector, ECMA-322, ISO 22092, 8.6Gb/cart" +"GigaMo",653,"3,5"", M.O., 605846 sectors, 2048 bytes/sector, Cherry Book, GigaMo, ECMA-351, ISO 17346" +"GigaMo2",654,"3,5"", M.O., 1063146 sectors, 2048 bytes/sector, Cherry Book 2, GigaMo 2, ECMA-353, ISO 22533" +"ISO_15286",655,"5,25"", M.O., 1263472 sectors, 2048 bytes/sector, ISO 15286, 5.2Gb/cart" +"ISO_15286_1024",656,"5,25"", M.O., 2319786 sectors, 1024 bytes/sector, ISO 15286, 4.8Gb/cart" +"ISO_15286_512",657,"5,25"", M.O., ??????? sectors, 512 bytes/sector, ISO 15286, 4.1Gb/cart" +"ISO_10089",658,"5,25"", M.O., 314569 sectors, 1024 bytes/sector, ISO 10089, 650Mb/cart" +"ISO_10089_512",659,"5,25"", M.O., ?????? sectors, 512 bytes/sector, ISO 10089, 594Mb/cart" +"CompactFloppy",660, +"DemiDiskette",661, +"Floptical",662,"3.5"", 652 tracks, 2 sides, 512 bytes/sector, Floptical, ECMA-207, ISO 14169" +"HiFD",663, +"QuickDisk",664, +"UHD144",665, +"VideoFloppy",666, +"Wafer",667, +"ZXMicrodrive",668, +"MetaFloppy_Mod_II",669,"5.25"", SS, DD, 77 tracks, 16 spt, 256 bytes/sector, MFM, 100 tpi, 300rpm" +"BeeCard",670, +"Borsu",671, +"DataStore",672, +"DIR",673, +"DST",674, +"DTF",675, +"DTF2",676, +"Flextra3020",677, +"Flextra3225",678, +"HiTC1",679, +"HiTC2",680, +"LT1",681, +"MiniCard",872, +"Orb",683, +"Orb5",684, +"SmartMedia",685, +"xD",686, +"XQD",687, +"DataPlay",688, +"AppleProfile",690, +"AppleWidget",691, +"AppleHD20",692, +"PriamDataTower",693, +"Pippin",694, +"RA60",700,"2382 cylinders, 4 tracks/cylinder, 42 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 204890112 bytes" +"RA80",701,"546 cylinders, 14 tracks/cylinder, 31 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 121325568 bytes" +"RA81",702,"1248 cylinders, 14 tracks/cylinder, 51 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 456228864 bytes" +"RC25",703,"302 cylinders, 4 tracks/cylinder, 42 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 25976832 bytes" +"RD31",704,"615 cylinders, 4 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 21411840 bytes" +"RD32",705,"820 cylinders, 6 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 42823680 bytes" +"RD51",706,"306 cylinders, 4 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 10653696 bytes" +"RD52",707,"480 cylinders, 7 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 30965760 bytes" +"RD53",708,"1024 cylinders, 7 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 75497472 bytes" +"RD54",709,"1225 cylinders, 8 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 159936000 bytes" +"RK06",710,"411 cylinders, 3 tracks/cylinder, 22 sectors/track, 256 words/sector, 16 bits/word, 512 bytes/sector, 13888512 bytes" +"RK06_18",711,"411 cylinders, 3 tracks/cylinder, 20 sectors/track, 256 words/sector, 18 bits/word, 576 bytes/sector, 14204160 bytes" +"RK07",712,"815 cylinders, 3 tracks/cylinder, 22 sectors/track, 256 words/sector, 16 bits/word, 512 bytes/sector, 27540480 bytes" +"RK07_18",713,"815 cylinders, 3 tracks/cylinder, 20 sectors/track, 256 words/sector, 18 bits/word, 576 bytes/sector, 28166400 bytes" +"RM02",714,"823 cylinders, 5 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 67420160 bytes" +"RM03",715,"823 cylinders, 5 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 67420160 bytes" +"RM05",716,"823 cylinders, 19 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 256196608 bytes" +"RP02",717,"203 cylinders, 10 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 22865920 bytes" +"RP02_18",718,"203 cylinders, 10 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, 23385600 bytes" +"RP03",719,"400 cylinders, 10 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 45056000 bytes" +"RP03_18",720,"400 cylinders, 10 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, 46080000 bytes" +"RP04",721,"411 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 87960576 bytes" +"RP04_18",722,"411 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, 89959680 bytes" +"RP05",723,"411 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 87960576 bytes" +"RP05_18",724,"411 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, 89959680 bytes" +"RP06",725,"815 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 174423040 bytes" +"RP06_18",726,"815 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, 178387200 bytes" +"LS120",730, +"LS240",731, +"FD32MB",732, +"RDX",733, +"RDX320",734,"Imation 320Gb RDX" +"VideoNow",740, +"VideoNowColor",741, +"VideoNowXp",742, +"Bernoulli10",750,"8""x11"" Bernoulli Box disk with 10Mb capacity" +"Bernoulli20",751,"8""x11"" Bernoulli Box disk with 20Mb capacity" +"BernoulliBox2_20",752,"5⅓"" Bernoulli Box II disk with 20Mb capacity" +"KodakVerbatim3",760, +"KodakVerbatim6",761, +"KodakVerbatim12",762, +"ProfessionalDisc",770,"Professional Disc for video, single layer, rewritable, 23Gb" +"ProfessionalDiscDual",771,"Professional Disc for video, dual layer, rewritable, 50Gb" +"ProfessionalDiscTriple",772,"Professional Disc for video, triple layer, rewritable, 100Gb" +"ProfessionalDiscQuad",773,"Professional Disc for video, quad layer, write once, 128Gb" +"PDD",774,"Professional Disc for DATA, single layer, rewritable, 23Gb" +"PDD_WORM",775,"Professional Disc for DATA, single layer, write once, 23Gb" +"ArchivalDisc",776,"Archival Disc, 1st gen., 300Gb" +"ArchivalDisc2",777,"Archival Disc, 2nd gen., 500Gb" +"ArchivalDisc3",778,"Archival Disc, 3rd gen., 1Tb" +"ODC300R",779,"Optical Disc archive, 1st gen., write once, 300Gb" +"ODC300RE",780,"Optical Disc archive, 1st gen., rewritable, 300Gb" +"ODC600R",781,"Optical Disc archive, 2nd gen., write once, 600Gb" +"ODC600RE",782,"Optical Disc archive, 2nd gen., rewritable, 600Gb" +"ODC1200RE",783,"Optical Disc archive, 3rd gen., rewritable, 1200Gb" +"ODC1500R",784,"Optical Disc archive, 3rd gen., write once, 1500Gb" +"ODC3300R",785,"Optical Disc archive, 4th gen., write once, 3300Gb" +"ODC5500R",786,"Optical Disc archive, 5th gen., write once, 5500Gb" +"ECMA_322_1k",800,"5,25"", M.O., 4383356 sectors, 1024 bytes/sector, ECMA-322, ISO 22092, 9.1Gb/cart" +"ECMA_322_512",801,"5,25"", M.O., ??????? sectors, 512 bytes/sector, ECMA-322, ISO 22092, 9.1Gb/cart" +"ISO_14517",802,"5,25"", M.O., 1273011 sectors, 1024 bytes/sector, ISO 14517, 2.6Gb/cart" +"ISO_14517_512",803,"5,25"", M.O., 2244958 sectors, 512 bytes/sector, ISO 14517, 2.3Gb/cart" +"ISO_15041_512",804,"3,5"", M.O., 1041500 sectors, 512 bytes/sector, ISO 15041, 540Mb/cart" +"MetaFloppy_Mod_I",820,"5.25"", SS, DD, 35 tracks, 16 spt, 256 bytes/sector, MFM, 48 tpi, ???rpm" +"AtariLynxCard",821, +"AtariJaguarCartridge",822, +"HF12",823,"HyperFlex (12Mb), 5.25"", DS, 301 tracks, 78 spt, 256 bytes/sector, MFM, 333 tpi, 600rpm", +"HF24",824,"HyperFlex (24Mb), 5.25"", DS, 506 tracks, 78 spt, 256 bytes/sector, MFM, 666 tpi, 720rpm", \ No newline at end of file diff --git a/Aaru.CommonTypes/MediaTypeFromDevice/FromAta.cs b/Aaru.CommonTypes/MediaTypeFromDevice/FromAta.cs new file mode 100644 index 000000000..3574af278 --- /dev/null +++ b/Aaru.CommonTypes/MediaTypeFromDevice/FromAta.cs @@ -0,0 +1,71 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : FromAta.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru common types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.Console; + +namespace Aaru.CommonTypes; + +public static partial class MediaTypeFromDevice +{ + /// Gets the media type from an ATA (not ATAPI) device + /// Manufacturer string + /// Model string + /// Is the device removable? + /// Does the device self-identify as CompactFlash? + /// Is the device attached thru PCMCIA or CardBus? + /// Number of blocks in device + /// The media type + public static MediaType GetFromAta(string manufacturer, string model, bool removable, bool compactFlash, + bool pcmcia, ulong blocks) + { + if(!removable) + { + if(compactFlash) return MediaType.CompactFlash; + + return pcmcia ? MediaType.PCCardTypeI : MediaType.GENERIC_HDD; + } + + if(!manufacturer.Equals("syquest", StringComparison.InvariantCultureIgnoreCase) || + !model.Equals("sparq", StringComparison.InvariantCultureIgnoreCase) || + blocks != 1961069) + return MediaType.Unknown; + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Drive_manufacturer_is_SyQuest_media_has_1961069_blocks_of_512_bytes_setting_media_type_to_SparQ); + + return MediaType.SparQ; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/MediaTypeFromDevice/FromMmc.cs b/Aaru.CommonTypes/MediaTypeFromDevice/FromMmc.cs new file mode 100644 index 000000000..6621fd044 --- /dev/null +++ b/Aaru.CommonTypes/MediaTypeFromDevice/FromMmc.cs @@ -0,0 +1,197 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : FromMmc.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru common types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.Console; + +namespace Aaru.CommonTypes; + +/// Gets the media type from a real device +public static partial class MediaTypeFromDevice +{ + /// Gets the media type from an SCSI MultiMedia Commands compliant device + /// Model string + /// Medium type from MODE SENSE + /// Density code from MODE SENSE + /// Number of blocks in media + /// Size of a block in bytes + /// Is the device USB attached + /// Is the media an optical disc + /// Media type + static MediaType GetFromMmc(string model, byte mediumType, byte densityCode, ulong blocks, uint blockSize, + bool isUsb, bool opticalDisc) + { + switch(mediumType) + { + case 0x00: + if(blockSize == 512) + { + if(blocks == 1281856) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_media_has_1_blocks_of_2_bytes_setting_media_type_to_WORM_PD_650, + mediumType, + blocks, + blockSize); + + return MediaType.PD650_WORM; + } + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_media_has_1_blocks_of_2_bytes_setting_media_type_to_PD_650, + mediumType, + blocks, + blockSize); + + return MediaType.PD650; + } + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_medium_type_is_0_setting_media_type_to_Compact_Disc, + mediumType); + + return MediaType.CD; + case 0x01: + case 0x05: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_medium_type_is_0_setting_media_type_to_CD_ROM, + mediumType); + + return MediaType.CDROM; + case 0x02: + case 0x06: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_setting_media_type_to_Compact_Disc_Digital_Audio, + mediumType); + + return MediaType.CDDA; + case 0x03: + case 0x07: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_medium_type_is_0_setting_media_type_to_CD_Plus, + mediumType); + + return MediaType.CDPLUS; + case 0x04: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_medium_type_is_0_setting_media_type_to_Photo_CD, + mediumType); + + return MediaType.PCD; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_medium_type_is_0_setting_media_type_to_CDR, + mediumType); + + return MediaType.CDR; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_medium_type_is_0_setting_media_type_to_CDRW, + mediumType); + + return MediaType.CDRW; + case 0x40 when isUsb && !opticalDisc: + case 0x41 when isUsb && !opticalDisc: + case 0x42 when isUsb && !opticalDisc: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_and_device_is_USB_setting_media_type_to_Flash_Drive, + mediumType); + + return MediaType.FlashDrive; + case 0x80: + if(model.ToLowerInvariant().StartsWith("ult", StringComparison.Ordinal)) + { + switch(densityCode) + { + case 0x42: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_to_LTO2, + mediumType, + densityCode); + + return MediaType.LTO2; + case 0x44: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_to_LTO3, + mediumType, + densityCode); + + return MediaType.LTO3; + case 0x46: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_to_LTO4, + mediumType, + densityCode); + + return MediaType.LTO4; + case 0x58: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_density_code_is_1_drive_starts_with_ult_setting_media_type_to_LTO5, + mediumType, + densityCode); + + return MediaType.LTO5; + } + } + + break; + } + + return MediaType.Unknown; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/MediaTypeFromDevice/FromOdc.cs b/Aaru.CommonTypes/MediaTypeFromDevice/FromOdc.cs new file mode 100644 index 000000000..394e20b8e --- /dev/null +++ b/Aaru.CommonTypes/MediaTypeFromDevice/FromOdc.cs @@ -0,0 +1,417 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : FromOdc.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru common types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using Aaru.Console; + +namespace Aaru.CommonTypes; + +public static partial class MediaTypeFromDevice +{ + /// Gets the device type from a SCSI Optical Device + /// Medium type from MODE SENSE + /// Number of blocks in device + /// Size in bytes of a block + /// Media type + static MediaType GetFromOdc(byte mediumType, ulong blocks, uint blockSize) + { + if(mediumType != 0x01 && mediumType != 0x02 && mediumType != 0x03 && mediumType != 0x05 && mediumType != 0x07) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_medium_type_is_0_setting_media_type_to_unknown_magneto_optical, + mediumType); + + return MediaType.UnknownMO; + } + + switch(blockSize) + { + case 512: + { + switch(blocks) + { + case 248826: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA154, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_154; + case 429975: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA201_embossed, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_201_ROM; + case 446325: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA201, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_201; + case 694929: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA223, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_223_512; + case 904995: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA183, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_183_512; + case 1041500: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO15041, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_15041_512; + case 1128772: + case 1163337: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA184, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_184_512; + case 1281856: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_media_has_1_blocks_of_2_bytes_setting_media_type_to_WORM_PD_650, + mediumType, + blocks, + blockSize); + + return MediaType.PD650_WORM; + case 1298496: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_media_has_1_blocks_of_2_bytes_setting_media_type_to_PD_650, + mediumType, + blocks, + blockSize); + + return MediaType.PD650; + case 1644581: + case 1647371: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA195, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_195_512; + case 2244958: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO14517, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_14517_512; + default: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Unknown_MO, + mediumType, + blocks, + blockSize); + + return MediaType.UnknownMO; + } + } + + case 1024: + { + switch(blocks) + { + case 314569: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO10089, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_10089; + case 371371: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA223, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_223; + case 498526: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA184, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_183; + case 603466: + case 637041: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA184, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_184; + case 936921: + case 948770: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA195, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_195; + case 1244621: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA238, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_238; + case 1273011: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO14517, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_14517; + case 2319786: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO15286, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_15286_1024; + case 4383356: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA322, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_322_1k; + case 14476734: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA260, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_260; + case 24445990: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA260, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_260_Double; + default: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Unknown_MO, + mediumType, + blocks, + blockSize); + + return MediaType.UnknownMO; + } + } + + case 2048: + { + switch(blocks) + { + case 310352: // Found in real media + case 318988: + case 320332: + case 321100: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA239, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_239; + case 605846: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_GigaMO, + mediumType, + blocks, + blockSize); + + return MediaType.GigaMo; + case 1063146: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_GigaMO2, + mediumType, + blocks, + blockSize); + + return MediaType.GigaMo2; + case 1128134: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA280, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_280; + case 1263472: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO15286, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_15286; + case 2043664: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA322, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_322_2k; + case 7355716: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA317, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_317; + default: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Unknown_MO, + mediumType, + blocks, + blockSize); + + return MediaType.UnknownMO; + } + } + + case 4096: + { + switch(blocks) + { + case 1095840: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA322, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_322; + default: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Unknown_MO, + mediumType, + blocks, + blockSize); + + return MediaType.UnknownMO; + } + } + + case 8192: + { + switch(blocks) + { + case 1834348: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_UDO, + mediumType, + blocks, + blockSize); + + return MediaType.UDO; + case 3668759: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_WORM_UDO2, + mediumType, + blocks, + blockSize); + + return MediaType.UDO2_WORM; + case 3669724: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_UDO2, + mediumType, + blocks, + blockSize); + + return MediaType.UDO2; + default: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Unknown_MO, + mediumType, + blocks, + blockSize); + + return MediaType.UnknownMO; + } + } + + default: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Unknown_MO, + mediumType, + blocks, + blockSize); + + return MediaType.UnknownMO; + } + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/MediaTypeFromDevice/FromSbc.cs b/Aaru.CommonTypes/MediaTypeFromDevice/FromSbc.cs new file mode 100644 index 000000000..0faead035 --- /dev/null +++ b/Aaru.CommonTypes/MediaTypeFromDevice/FromSbc.cs @@ -0,0 +1,1165 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : FromSbc.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru common types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.Console; + +namespace Aaru.CommonTypes; + +public static partial class MediaTypeFromDevice +{ + /// Gets the media type from a SCSI Block Commands compliant device + /// Vendor string + /// Model string + /// Medium type from MODE SENSE + /// Number of blocks in device + /// Size of a block in bytes + /// Media type + static MediaType GetFromSbc(string vendor, string model, byte mediumType, ulong blocks, uint blockSize) + { + switch(mediumType) + { + case 0x09: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA54, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_54; + case 0x0A: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA59, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_59; + case 0x0B: + switch(blockSize) + { + case 256: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA69, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_69_26; + case 512: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA69, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_69_15; + case 1024: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA69, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_69_8; + } + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Unknown, + mediumType, + blocks, + blockSize); + + return MediaType.Unknown; + case 0x0E: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA66, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_66; + case 0x12: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA70, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_70; + case 0x16: + switch(blockSize) + { + case 256: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA78, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_78; + case 512: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA78, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_78_2; + } + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Unknown, + mediumType, + blocks, + blockSize); + + return MediaType.Unknown; + case 0x1A: + switch(blockSize) + { + case 256: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA99, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_99_26; + case 512: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA99, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_99_15; + case 1024: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA99, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_99_8; + } + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Unknown, + mediumType, + blocks, + blockSize); + + return MediaType.Unknown; + case 0x1E: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MF2DD, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_35_DS_DD_9; + case 0x41: + switch(blocks) + { + case 58620544: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_REV120, + mediumType, + blocks, + blockSize); + + return MediaType.REV120; + case 34185728: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_REV70, + mediumType, + blocks, + blockSize); + + return MediaType.REV70; + case 17090880: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_REV35, + mediumType, + blocks, + blockSize); + + return MediaType.REV35; + } + + break; + case 0x93: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_PC98_MF2HD, + mediumType, + blocks, + blockSize); + + return MediaType.NEC_35_HD_15; + case 0x94: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MF2HD, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_35_HD; + } + + switch(blockSize) + { + case 128: + switch(blocks) + { + case 720: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Atari_MD1SD, + mediumType, + blocks, + blockSize); + + return MediaType.ATARI_525_SD; + case 1040: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Atari_MD1DD, + mediumType, + blocks, + blockSize); + + return MediaType.ATARI_525_DD; + case 1898: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_33FD, + mediumType, + blocks, + blockSize); + + return MediaType.IBM33FD_128; + case 2002: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA54, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_54; + case 3848: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_43FD, + mediumType, + blocks, + blockSize); + + return MediaType.IBM43FD_128; + case 4004: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA59, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_59; + } + + break; + case 256: + switch(blocks) + { + case 322: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA56, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_66; + case 400: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Acorn_MD1SD, + mediumType, + blocks, + blockSize); + + return MediaType.ACORN_525_SS_SD_40; + case 455: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Apple_DOS32, + mediumType, + blocks, + blockSize); + + return MediaType.Apple32SS; + case 560: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Apple_DOS33, + mediumType, + blocks, + blockSize); + + return MediaType.Apple33SS; + case 640: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Acorn_MD1DD, + mediumType, + blocks, + blockSize); + + return MediaType.ACORN_525_SS_DD_40; + case 720: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Atari_MD1DD, + mediumType, + blocks, + blockSize); + + return MediaType.ATARI_525_DD; + case 800: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Acorn_MD1DD_80, + mediumType, + blocks, + blockSize); + + return MediaType.ACORN_525_SS_SD_80; + case 910: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Apple_DOS32_DS, + mediumType, + blocks, + blockSize); + + return MediaType.Apple32DS; + case 1120: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Apple_DOS33_DS, + mediumType, + blocks, + blockSize); + + return MediaType.Apple33DS; + case 1121: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_33FD, + mediumType, + blocks, + blockSize); + + return MediaType.IBM33FD_256; + case 1232: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_MetaFloppy, + mediumType, + blocks, + blockSize); + + return MediaType.MetaFloppy_Mod_II; + case 1280 when mediumType == 0x01: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Acorn_MD1DD_80, + mediumType, + blocks, + blockSize); + + return MediaType.ACORN_525_SS_DD_80; + case 1280: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA70, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_70; + case 2002: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DEC_RX02, + mediumType, + blocks, + blockSize); + + return MediaType.RX02; + case 2560: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA78, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_78; + case 3848: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_53FD, + mediumType, + blocks, + blockSize); + + return MediaType.IBM53FD_256; + case 4004: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA99, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_99_26; + case 39168 when vendor.StartsWith("iomega", StringComparison.OrdinalIgnoreCase): + case 41004 when vendor.StartsWith("iomega", StringComparison.OrdinalIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Bernoulli10, + blocks); + + return MediaType.Bernoulli10; + case 46956: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_HF12); + + return MediaType.HF12; + case 78936: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_HF24); + + return MediaType.HF12; + } + + break; + case 319: + switch(blocks) + { + case 256: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_23FD, + mediumType, + blocks, + blockSize); + + return MediaType.IBM23FD; + } + + break; + case 512: + switch(blocks) + { + case 320: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MD1DD_8, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_525_SS_DD_8; + case 360: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MD1DD, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_525_SS_DD_9; + case 610: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_33FD, + mediumType, + blocks, + blockSize); + + return MediaType.IBM33FD_512; + case 630 when mediumType == 0x01: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Apricot_MF2DD, + mediumType, + blocks, + blockSize); + + return MediaType.Apricot_35; + case 640 when mediumType == 0x01: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MF1DD_8, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_35_SS_DD_8; + case 640: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MD2DD_8, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_525_DS_DD_8; + case 720 when mediumType == 0x01: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MF1DD, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_35_SS_DD_9; + case 720: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MD2DD, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_525_DS_DD_9; + case 800: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Apple_MF1DD, + mediumType, + blocks, + blockSize); + + return MediaType.AppleSonySS; + case 1280: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MF2DD_8, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_35_DS_DD_8; + case 1440: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MF2DD, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_35_DS_DD_9; + case 1640: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_FDFORMAT_MF2DD, + mediumType, + blocks, + blockSize); + + return MediaType.FDFORMAT_35_DD; + case 1760: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Amiga_MF2DD, + mediumType, + blocks, + blockSize); + + return MediaType.CBM_AMIGA_35_DD; + case 2242: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_53FD, + mediumType, + blocks, + blockSize); + + return MediaType.IBM53FD_512; + case 2332: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA99, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_99_15; + case 2400: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MD2HD, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_525_HD; + case 2788: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_FDFORMAT_MD2HD, + mediumType, + blocks, + blockSize); + + return MediaType.FDFORMAT_525_HD; + case 2880: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MF2HD, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_35_HD; + case 3360: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DMF_MF2HD, + mediumType, + blocks, + blockSize); + + return MediaType.DMF; + case 3444: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_FDFORMAT_MF2HD, + mediumType, + blocks, + blockSize); + + return MediaType.FDFORMAT_35_HD; + case 3520: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Amiga_MF2HD, + mediumType, + blocks, + blockSize); + + return MediaType.CBM_AMIGA_35_HD; + case 5760: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_MF2ED, + mediumType, + blocks, + blockSize); + + return MediaType.DOS_35_ED; + case 40662 when mediumType == 0x20: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Floptical, + mediumType, + blocks, + blockSize); + + return MediaType.Floptical; + case 65536 when model.ToLowerInvariant().StartsWith("ls-", StringComparison.Ordinal): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_FD32MB); + + return MediaType.FD32MB; + case 78882 when vendor.StartsWith("iomega", StringComparison.OrdinalIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_PocketZIP); + + return MediaType.PocketZip; + case 86700 when vendor.Equals("syquest", StringComparison.InvariantCultureIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_SQ400); + + return MediaType.SQ400; + case 87040 when vendor.StartsWith("iomega", StringComparison.OrdinalIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_Bernoulli2_44); + + return MediaType.Bernoulli44; + case 173456 when vendor.Equals("syquest", StringComparison.InvariantCultureIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_SQ800); + + return MediaType.SQ800; + case 175856 when vendor.StartsWith("iomega", StringComparison.OrdinalIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_Bernoulli2_90); + + return MediaType.Bernoulli90; + case 196608 when model.ToLowerInvariant().StartsWith("zip", StringComparison.OrdinalIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_ZIP100); + + return MediaType.ZIP100; + + case 215440 when vendor.Equals("syquest", StringComparison.InvariantCultureIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_SQ310); + + return MediaType.SQ310; + case 246528 when model.ToLowerInvariant().StartsWith("ls-", StringComparison.Ordinal): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_LS120); + + return MediaType.LS120; + case 248826 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA154, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_154; + case 262144 when vendor.Equals("syquest", StringComparison.InvariantCultureIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_EZ135); + + return MediaType.EZ135; + case 294918 when vendor.StartsWith("iomega", StringComparison.OrdinalIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Bernoulli2_150); + + return MediaType.Bernoulli150; + case 390696 when vendor.Equals("syquest", StringComparison.InvariantCultureIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_SQ2000); + + return MediaType.SQ2000; + case 393380 when model.ToLowerInvariant().StartsWith("hifd", StringComparison.Ordinal): + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_HiFD, + blocks, + blockSize); + + return MediaType.HiFD; + case 429975 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA201_embossed, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_201_ROM; + case 446325 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA201, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_201; + case 450560 when vendor.Equals("syquest", StringComparison.InvariantCultureIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_EZ230); + + return MediaType.EZ230; + case 469504 when model.ToLowerInvariant().StartsWith("ls-", StringComparison.Ordinal): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_LS240); + + return MediaType.LS240; + case 489532 when model.ToLowerInvariant().StartsWith("zip", StringComparison.OrdinalIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_ZIP250); + + return MediaType.ZIP250; + case 524288 when vendor.Equals("syquest", StringComparison.InvariantCultureIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_SQ327); + + return MediaType.SQ327; + case 694929 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA223, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_223_512; + case 904995 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA183, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_183_512; + case 1041500 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO15041, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_15041_512; + case 1128772 when mediumType is 0x01 or 0x02: + case 1163337 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA184, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_184_512; + case 1281856 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_media_has_1_blocks_of_2_bytes_setting_media_type_to_WORM_PD_650, + mediumType, + blocks, + blockSize); + + return MediaType.PD650_WORM; + case 1298496 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .SCSI_medium_type_is_0_media_has_1_blocks_of_2_bytes_setting_media_type_to_PD_650, + mediumType, + blocks, + blockSize); + + return MediaType.PD650; + case 1470500 when model.ToLowerInvariant().StartsWith("zip", StringComparison.OrdinalIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_ZIP250); + + return MediaType.ZIP750; + case 1644581 when mediumType is 0x01 or 0x02: + case 1647371 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA195, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_195_512; + case 1961069 when vendor.Equals("syquest", StringComparison.InvariantCultureIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Drive_manufacturer_is_SyQuest_media_has_1961069_blocks_of_512_bytes_setting_media_type_to_SparQ); + + return MediaType.SparQ; + case 2091050 when model.ToLowerInvariant().StartsWith("jaz", StringComparison.Ordinal): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_JAZ); + + return MediaType.Jaz; + case 2244958 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO14517, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_14517_512; + case 2929800 when vendor.Equals("syquest", StringComparison.InvariantCultureIgnoreCase): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_SyJet); + + return MediaType.SyJet; + case 3915600 when model.ToLowerInvariant().StartsWith("jaz", StringComparison.Ordinal): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_JAZ2); + + return MediaType.Jaz2; + case 4307184 when vendor.ToLowerInvariant().StartsWith("cws orb", StringComparison.Ordinal): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_Orb); + + return MediaType.Orb; + case 625134256 when model.ToLowerInvariant().StartsWith("rdx", StringComparison.Ordinal): + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_RDX320, + blocks, + blockSize); + + return MediaType.RDX320; + } + + break; + case 1024: + { + switch(blocks) + { + case 800 when mediumType == 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Acorn_MF2DD, + mediumType, + blocks, + blockSize); + + return MediaType.ACORN_35_DS_DD; + case 1220: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM_53FD, + mediumType, + blocks, + blockSize); + + return MediaType.IBM53FD_1024; + case 1232 when model.ToLowerInvariant().StartsWith("ls-", StringComparison.Ordinal): + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.SCSI_Media_Type_Description_LS_PC98_MF2HD); + + return MediaType.NEC_35_HD_8; + case 1232: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Sharp_MF2HD, + mediumType, + blocks, + blockSize); + + return MediaType.SHARP_35; + case 1268: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA69, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_69_8; + case 1280: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_PC98_MD2HD, + mediumType, + blocks, + blockSize); + + return MediaType.NEC_525_HD; + case 1316: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA99, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_99_8; + case 1600 when mediumType == 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Acorn_MF2HD, + mediumType, + blocks, + blockSize); + + return MediaType.ACORN_35_DS_HD; + case 314569 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO10089, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_10089; + case 371371 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA223, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_223; + case 498526 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA183, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_183; + case 603466 when mediumType is 0x01 or 0x02: + case 637041 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA184, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_184; + case 936921 when mediumType is 0x01 or 0x02: + case 948770 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA195, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_195; + case 1244621 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA238, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_238; + case 1273011 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO14517, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_14517; + case 2319786 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO15286, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_15286_1024; + case 4383356 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA322, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_322_1k; + case 14476734 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA260, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_260; + case 24445990 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA260, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_260_Double; + } + } + + break; + case 2048: + { + switch(blocks) + { + case 112311: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_MD60, + mediumType, + blocks, + blockSize); + + return MediaType.MD60; + case 138363: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_MD74, + mediumType, + blocks, + blockSize); + + return MediaType.MD74; + case 149373: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_MD80, + mediumType, + blocks, + blockSize); + + return MediaType.MD80; + case 310352 when mediumType is 0x01 or 0x02: // Found in real media + case 318988 when mediumType is 0x01 or 0x02: + case 320332 when mediumType is 0x01 or 0x02: + case 321100 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA239, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_239; + case 494023: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_HiMD, + mediumType, + blocks, + blockSize); + + return MediaType.HiMD; + case 605846 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_GigaMO, + mediumType, + blocks, + blockSize); + + return MediaType.GigaMo; + case 1063146 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_GigaMO2, + mediumType, + blocks, + blockSize); + + return MediaType.GigaMo2; + case 1128134 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA280, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_280; + case 1263472 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ISO15286, + mediumType, + blocks, + blockSize); + + return MediaType.ISO_15286; + case 2043664 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA322, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_322_2k; + case 7355716 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA317, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_317; + } + } + + break; + case 4096: + { + switch(blocks) + { + case 1095840 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ECMA322, + mediumType, + blocks, + blockSize); + + return MediaType.ECMA_322; + } + } + + break; + case 8192: + { + switch(blocks) + { + case 1834348 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_UDO, + mediumType, + blocks, + blockSize); + + return MediaType.UDO; + case 3668759 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_WORM_UDO2, + mediumType, + blocks, + blockSize); + + return MediaType.UDO2_WORM; + case 3669724 when mediumType is 0x01 or 0x02: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_UDO2, + mediumType, + blocks, + blockSize); + + return MediaType.UDO2; + } + } + + break; + } + + return MediaType.Unknown; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/MediaTypeFromDevice/FromScsi.cs b/Aaru.CommonTypes/MediaTypeFromDevice/FromScsi.cs new file mode 100644 index 000000000..fe961d557 --- /dev/null +++ b/Aaru.CommonTypes/MediaTypeFromDevice/FromScsi.cs @@ -0,0 +1,145 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : FromScsi.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru common types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.Console; + +namespace Aaru.CommonTypes; + +public static partial class MediaTypeFromDevice +{ + const string MODULE_NAME = "Media detection"; + + /// Tries to guess, from SCSI information, the media type of a device and/or its inserted media + /// The SCSI Peripheral Type as indicated in the INQUIRY response + /// The vendor string of the device + /// The model string of the device + /// The medium type byte from MODE SENSE + /// The density type byte from MODE SENSE + /// How many blocks are on the media + /// Size in bytes of each block + /// Device is USB + /// Is media an optical disc? + /// The media type + public static MediaType GetFromScsi(byte scsiPeripheralType, string vendor, string model, byte mediumType, + byte densityCode, ulong blocks, uint blockSize, bool isUsb, bool opticalDisc) + { + switch(scsiPeripheralType) + { + // Direct access device + case 0x00: + // Simplified access device + case 0x0E: + if(mediumType is 0x03 or 0x05 or 0x07) goto case 0x07; + + return GetFromSbc(vendor, model, mediumType, blocks, blockSize); + + // Sequential access device + case 0x01: + return GetFromSsc(vendor, model, mediumType, densityCode); + + // Write-once device + case 0x04: + // Optical device + case 0x07: + return GetFromOdc(mediumType, blocks, blockSize); + + // MultiMedia Device + case 0x05: + return GetFromMmc(model, mediumType, densityCode, blocks, blockSize, isUsb, opticalDisc); + + // MD DATA drives + case 0x10 when model.StartsWith("MDM", StringComparison.Ordinal) || + model.StartsWith("MDH", StringComparison.Ordinal): + if(blockSize == 2048) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_MDDATA, + scsiPeripheralType, + blocks, + blockSize); + + return MediaType.MDData; + } + + switch(blocks) + { + case 57312: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_MD60_MDDATA, + scsiPeripheralType, + blocks, + blockSize); + + return MediaType.MD60; + case 70464: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_MD74_MDDATA, + scsiPeripheralType, + blocks, + blockSize); + + return MediaType.MD74; + case 76096: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_MD80_MDDATA, + scsiPeripheralType, + blocks, + blockSize); + + return MediaType.MD80; + } + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_MD60_MDDATA, + scsiPeripheralType, + blocks, + blockSize); + + return MediaType.MD; + + // Host managed zoned block device + case 0x14: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_ZBC_Host_Managed, + scsiPeripheralType, + blocks, + blockSize); + + return MediaType.Zone_HDD; + } + + return MediaType.Unknown; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/MediaTypeFromDevice/FromSsc.cs b/Aaru.CommonTypes/MediaTypeFromDevice/FromSsc.cs new file mode 100644 index 000000000..6af4ed8e5 --- /dev/null +++ b/Aaru.CommonTypes/MediaTypeFromDevice/FromSsc.cs @@ -0,0 +1,1702 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : FromSsc.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru common types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.Console; + +namespace Aaru.CommonTypes; + +public static partial class MediaTypeFromDevice +{ + /// Gets the media type from an SCSI Streaming Commands compliant device + /// Vendor string + /// Model string + /// Medium type from MODE SENSE + /// Density code from MODE SENSE + /// Media type + public static MediaType GetFromSsc(string vendor, string model, byte mediumType, byte densityCode) + { + switch(mediumType) + { + case 0x00: + switch(densityCode) + { + case 0x04: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_QIC11, + mediumType, + densityCode); + + return MediaType.QIC11; + case 0x05: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_QIC24, + mediumType, + densityCode); + + return MediaType.QIC24; + case 0x09: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM3490, + mediumType, + densityCode); + + return MediaType.IBM3490; + case 0x0F: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_QIC120, + mediumType, + densityCode); + + return MediaType.QIC120; + case 0x10: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_QIC150, + mediumType, + densityCode); + + return MediaType.QIC150; + case 0x13: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DDS, + mediumType, + densityCode); + + return MediaType.DDS1; + case 0x24: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DDS2, + mediumType, + densityCode); + + return MediaType.DDS2; + case 0x25: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DDS3, + mediumType, + densityCode); + + return MediaType.DDS3; + case 0x26: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DDS4, + mediumType, + densityCode); + + return MediaType.DDS4; + case 0x28: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM3490E, + mediumType, + densityCode); + + return MediaType.IBM3490E; + case 0x40: + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO_ult, + mediumType, + densityCode); + + return MediaType.LTO; + } + + if(model.StartsWith("sdz", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_SAIT, + mediumType, + densityCode); + + return MediaType.SAIT1; + } + + break; + + case 0x41: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO2_ult, + mediumType, + densityCode); + + return MediaType.LTO2; + } + + break; + } + + case 0x42: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO2_ult, + mediumType, + densityCode); + + return MediaType.LTO2; + } + + if(vendor.Equals("stk", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_T9840A, + mediumType, + densityCode); + + return MediaType.T9840A; + } + + break; + } + + case 0x43: + { + if(vendor.Equals("stk", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_T9940A, + mediumType, + densityCode); + + return MediaType.T9940A; + } + + break; + } + + case 0x44: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO3, + mediumType, + densityCode); + + return MediaType.LTO3; + } + + if(vendor.Equals("stk", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_T9940B, + mediumType, + densityCode); + + return MediaType.T9940B; + } + + break; + } + + case 0x45: + { + if(vendor.Equals("stk", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_T9940C, + mediumType, + densityCode); + + return MediaType.T9840C; + } + + break; + } + + case 0x46: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO4, + mediumType, + densityCode); + + return MediaType.LTO4; + } + + if(vendor.Equals("stk", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_T9840D, + mediumType, + densityCode); + + return MediaType.T9840D; + } + + break; + } + + case 0x4A: + { + if(vendor.Equals("stk", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_T10000A, + mediumType, + densityCode); + + return MediaType.T10000A; + } + + break; + } + + case 0x4B: + { + if(vendor.Equals("stk", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_T10000B, + mediumType, + densityCode); + + return MediaType.T10000B; + } + + break; + } + + case 0x4C: + { + if(vendor.Equals("stk", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_T10000C, + mediumType, + densityCode); + + return MediaType.T10000C; + } + + break; + } + + case 0x4D: + { + if(vendor.Equals("stk", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_T10000D, + mediumType, + densityCode); + + return MediaType.T10000D; + } + + break; + } + + case 0x58: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO5, + mediumType, + densityCode); + + return MediaType.LTO5; + } + + break; + } + + // Used by some HP drives for all generations + case 0x8C: + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DDS, + mediumType, + densityCode); + + return MediaType.DDS1; + } + } + + break; + case 0x01: + { + switch(densityCode) + { + case 0x44: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_WORM_LTO3, + mediumType, + densityCode); + + return MediaType.LTO3WORM; + } + + break; + } + + case 0x46: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_WORM_LTO4, + mediumType, + densityCode); + + return MediaType.LTO4WORM; + } + + break; + } + + case 0x58: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_WORM_LTO5, + mediumType, + densityCode); + + return MediaType.LTO5WORM; + } + + break; + } + } + } + + break; + case 0x18: + { + switch(densityCode) + { + case 0x00: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO_ult, + mediumType, + densityCode); + + return MediaType.LTO; + } + + break; + } + + case 0x40: + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO, + mediumType, + densityCode); + + return MediaType.LTO; + } + } + } + + break; + case 0x28: + { + switch(densityCode) + { + case 0x00: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO2_ult, + mediumType, + densityCode); + + return MediaType.LTO2; + } + + break; + } + + case 0x42: + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO2, + mediumType, + densityCode); + + return MediaType.LTO2; + } + } + } + + break; + case 0x33: + { + switch(densityCode) + { + case 0x00: + case 0x25: + { + if(model.StartsWith("dat", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DDS3_dat, + mediumType, + densityCode); + + return MediaType.DDS3; + } + + break; + } + } + } + + break; + case 0x34: + { + switch(densityCode) + { + case 0x00: + case 0x26: + { + if(model.StartsWith("dat", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DDS4_alt, + mediumType, + densityCode); + + return MediaType.DDS4; + } + + break; + } + } + } + + break; + case 0x35: + { + switch(densityCode) + { + case 0x00: + case 0x47: + { + if(model.StartsWith("dat", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DAT72_dat, + mediumType, + densityCode); + + return MediaType.DAT72; + } + + break; + } + } + } + + break; + case 0x38: + { + switch(densityCode) + { + case 0x00: + case 0x44: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO3, + mediumType, + densityCode); + + return MediaType.LTO3; + } + + break; + } + } + } + + break; + case 0x3C: + { + switch(densityCode) + { + case 0x00: + case 0x44: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_WORM_LTO3, + mediumType, + densityCode); + + return MediaType.LTO3WORM; + } + + break; + } + } + } + + break; + case 0x48: + { + switch(densityCode) + { + case 0x00: + case 0x46: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO4, + mediumType, + densityCode); + + return MediaType.LTO4; + } + + break; + } + } + } + + break; + case 0x4C: + { + switch(densityCode) + { + case 0x00: + case 0x46: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_WORM_LTO4, + mediumType, + densityCode); + + return MediaType.LTO4WORM; + } + + break; + } + } + } + + break; + case 0x50: + { + switch(densityCode) + { + case 0x00: + case 0x24: + { + if(model.StartsWith("dat", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DDS2_dat, + mediumType, + densityCode); + + return MediaType.DDS2; + } + + break; + } + } + } + + break; + case 0x58: + { + switch(densityCode) + { + case 0x00: + case 0x58: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO5, + mediumType, + densityCode); + + return MediaType.LTO5; + } + + break; + } + } + } + + break; + case 0x5C: + { + switch(densityCode) + { + case 0x00: + case 0x58: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_WORM_LTO5, + mediumType, + densityCode); + + return MediaType.LTO5WORM; + } + + break; + } + } + } + + break; + case 0x68: + { + switch(densityCode) + { + case 0x00: + case 0x5A: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO6_ult, + mediumType, + densityCode); + + return MediaType.LTO6; + } + + break; + } + } + } + + break; + case 0x6C: + { + switch(densityCode) + { + case 0x00: + case 0x5A: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_WORM_LTO6_ult, + mediumType, + densityCode); + + return MediaType.LTO6WORM; + } + + break; + } + } + } + + break; + case 0x78: + { + switch(densityCode) + { + case 0x00: + case 0x5C: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_LTO7_ult, + mediumType, + densityCode); + + return MediaType.LTO7; + } + + break; + } + } + } + + break; + case 0x7C: + { + switch(densityCode) + { + case 0x00: + case 0x5C: + { + if(model.StartsWith("ult", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_WORM_LTO7_ult, + mediumType, + densityCode); + + return MediaType.LTO7WORM; + } + + break; + } + } + } + + break; + case 0x81: + { + switch(densityCode) + { + case 0x00: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_15m, + mediumType, + densityCode); + + return MediaType.Exatape15m; + } + + if(vendor.Equals("ibm", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM3592, + mediumType, + densityCode); + + return MediaType.IBM3592; + } + + if(model.StartsWith("vxa", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_VXA, + mediumType, + densityCode); + + return MediaType.VXA1; + } + + break; + } + + case 0x14: + case 0x15: + case 0x27: + case 0x8C: + case 0x90: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_15m, + mediumType, + densityCode); + + return MediaType.Exatape15m; + } + + break; + } + + case 0x29: + case 0x2A: + { + if(vendor.Equals("ibm", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM3592, + mediumType, + densityCode); + + return MediaType.IBM3592; + } + + break; + } + + case 0x80: + { + if(model.StartsWith("vxa", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_VXA, + mediumType, + densityCode); + + return MediaType.VXA1; + } + + break; + } + } + } + + break; + case 0x82: + { + switch(densityCode) + { + case 0x00: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_28m, + mediumType, + densityCode); + + return MediaType.Exatape28m; + } + + if(vendor.Equals("ibm", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM3592, + mediumType, + densityCode); + + return MediaType.IBM3592; + } + + break; + } + + case 0x0A: + { + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_CompactTape, + mediumType, + densityCode); + + return MediaType.CompactTapeI; + } + + break; + } + + case 0x14: + case 0x15: + case 0x27: + case 0x8C: + case 0x90: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_28m, + mediumType, + densityCode); + + return MediaType.Exatape28m; + } + + break; + } + + case 0x16: + { + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_CompactTapeII, + mediumType, + densityCode); + + return MediaType.CompactTapeII; + } + + break; + } + + case 0x29: + case 0x2A: + { + if(vendor.Equals("ibm", StringComparison.InvariantCultureIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_IBM3592, + mediumType, + densityCode); + + return MediaType.IBM3592; + } + + break; + } + + case 0x81: + { + if(model.StartsWith("vxa", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_VXA2, + mediumType, + densityCode); + + return MediaType.VXA2; + } + + break; + } + + case 0x82: + { + if(model.StartsWith("vxa", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_VXA3, + mediumType, + densityCode); + + return MediaType.VXA3; + } + + break; + } + } + } + + break; + case 0x83: + { + switch(densityCode) + { + case 0x00: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_54m, + mediumType, + densityCode); + + return MediaType.Exatape54m; + } + + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DLTtapeIII, + mediumType, + densityCode); + + return MediaType.DLTtapeIII; + } + + break; + } + + case 0x14: + case 0x15: + case 0x27: + case 0x8C: + case 0x90: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_54m, + mediumType, + densityCode); + + return MediaType.Exatape54m; + } + + break; + } + + case 0x17: + case 0x18: + case 0x19: + case 0x80: + case 0x81: + { + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DLTtapeIII, + mediumType, + densityCode); + + return MediaType.DLTtapeIII; + } + + break; + } + } + } + + break; + case 0x84: + { + switch(densityCode) + { + case 0x00: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_80m, + mediumType, + densityCode); + + return MediaType.Exatape80m; + } + + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DLTtapeIIIxt, + mediumType, + densityCode); + + return MediaType.DLTtapeIIIxt; + } + + break; + } + + case 0x14: + case 0x15: + case 0x27: + case 0x8C: + case 0x90: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_80m, + mediumType, + densityCode); + + return MediaType.Exatape80m; + } + + break; + } + + case 0x19: + case 0x80: + case 0x81: + { + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DLTtapeIIIxt, + mediumType, + densityCode); + + return MediaType.DLTtapeIIIxt; + } + + break; + } + } + } + + break; + case 0x85: + { + switch(densityCode) + { + case 0x00: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_106m, + mediumType, + densityCode); + + return MediaType.Exatape106m; + } + + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("sdlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("superdlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DLTtapeIV, + mediumType, + densityCode); + + return MediaType.DLTtapeIV; + } + + if(model.StartsWith("stt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Travan5_stt, + mediumType, + densityCode); + + return MediaType.Travan5; + } + + break; + } + + case 0x14: + case 0x15: + case 0x27: + case 0x8C: + case 0x90: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_106m, + mediumType, + densityCode); + + return MediaType.Exatape106m; + } + + break; + } + + case 0x1A: + case 0x1B: + case 0x40: + case 0x41: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + { + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("sdlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("superdlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_DLTtapeIV, + mediumType, + densityCode); + + return MediaType.DLTtapeIV; + } + + break; + } + + case 0x46: + { + if(model.StartsWith("stt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Travan5_stt, + mediumType, + densityCode); + + return MediaType.Travan5; + } + + break; + } + } + } + + break; + case 0x86: + { + switch(densityCode) + { + case 0x00: + case 0x90: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_160m, + mediumType, + densityCode); + + return MediaType.Exatape160mXL; + } + + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("sdlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("superdlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_SDLT, + mediumType, + densityCode); + + return MediaType.SDLT1; + } + + break; + } + + case 0x8C: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_160m, + mediumType, + densityCode); + + return MediaType.Exatape160mXL; + } + + break; + } + + case 0x91: + case 0x92: + case 0x93: + { + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("sdlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("superdlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_SDLT, + mediumType, + densityCode); + + return MediaType.SDLT1; + } + + break; + } + } + } + + break; + case 0x87: + { + switch(densityCode) + { + case 0x00: + case 0x4A: + { + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("sdlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("superdlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_SDLT2, + mediumType, + densityCode); + + return MediaType.SDLT2; + } + + break; + } + } + } + + break; + case 0x90: + { + switch(densityCode) + { + case 0x00: + case 0x50: + case 0x98: + case 0x99: + { + if(model.StartsWith("dlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("sdlt", StringComparison.OrdinalIgnoreCase) || + model.StartsWith("superdlt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_VStape, + mediumType, + densityCode); + + return MediaType.VStapeI; + } + + break; + } + } + } + + break; + case 0x95: + { + if(model.StartsWith("stt", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Travan7, + mediumType, + densityCode); + + return MediaType.Travan7; + } + } + + break; + case 0xB6: + { + switch(densityCode) + { + case 0x45: + // HP Colorado tapes have a different capacity but return same density code at least in Seagate drives + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Travan4, + mediumType, + densityCode); + + return MediaType.Travan4; + } + } + + break; + case 0xB7: + { + switch(densityCode) + { + case 0x47: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Travan5, + mediumType, + densityCode); + + return MediaType.Travan5; + } + } + + break; + case 0xC1: + { + switch(densityCode) + { + case 0x00: + case 0x14: + case 0x15: + case 0x8C: + case 0x90: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_22m, + mediumType, + densityCode); + + return MediaType.Exatape22m; + } + + break; + } + } + } + + break; + case 0xC2: + { + switch(densityCode) + { + case 0x00: + case 0x14: + case 0x15: + case 0x27: + case 0x8C: + case 0x90: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_40m, + mediumType, + densityCode); + + return MediaType.Exatape40m; + } + + break; + } + } + } + + break; + case 0xC3: + { + switch(densityCode) + { + case 0x00: + case 0x14: + case 0x15: + case 0x27: + case 0x8C: + case 0x90: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_76m, + mediumType, + densityCode); + + return MediaType.Exatape76m; + } + + break; + } + } + } + + break; + case 0xC4: + { + switch(densityCode) + { + case 0x00: + case 0x14: + case 0x15: + case 0x27: + case 0x8C: + case 0x90: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_112m, + mediumType, + densityCode); + + return MediaType.Exatape112m; + } + + break; + } + } + } + + break; + case 0xD1: + { + switch(densityCode) + { + case 0x00: + case 0x27: + case 0x28: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_22m_AME, + mediumType, + densityCode); + + return MediaType.Exatape22mAME; + } + + break; + } + } + } + + break; + case 0xD2: + { + switch(densityCode) + { + case 0x00: + case 0x27: + case 0x28: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_170m, + mediumType, + densityCode); + + return MediaType.Exatape170m; + } + + break; + } + } + } + + break; + case 0xD3: + { + switch(densityCode) + { + case 0x00: + case 0x27: + case 0x28: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_125m, + mediumType, + densityCode); + + return MediaType.Exatape125m; + } + + break; + } + } + } + + break; + case 0xD4: + { + switch(densityCode) + { + case 0x00: + case 0x27: + case 0x28: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_45m, + mediumType, + densityCode); + + return MediaType.Exatape45m; + } + + break; + } + } + } + + break; + case 0xD5: + { + switch(densityCode) + { + case 0x00: + case 0x27: + case 0x28: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_225m, + mediumType, + densityCode); + + return MediaType.Exatape225m; + } + + break; + } + } + } + + break; + case 0xD6: + { + switch(densityCode) + { + case 0x00: + case 0x27: + case 0x28: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_150m, + mediumType, + densityCode); + + return MediaType.Exatape150m; + } + + break; + } + } + } + + break; + case 0xD7: + { + switch(densityCode) + { + case 0x00: + case 0x27: + case 0x28: + { + if(model.StartsWith("exb", StringComparison.OrdinalIgnoreCase)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SCSI_Media_Type_Description_Exatape_75m, + mediumType, + densityCode); + + return MediaType.Exatape75m; + } + + break; + } + } + } + + break; + } + + return MediaType.Unknown; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Metadata/CdOffset.cs b/Aaru.CommonTypes/Metadata/CdOffset.cs new file mode 100644 index 000000000..f2f663bb6 --- /dev/null +++ b/Aaru.CommonTypes/Metadata/CdOffset.cs @@ -0,0 +1,61 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CdOffset.cs +// Author(s) : Natalia Portillo +// +// Component : Device database. +// +// --[ Description ] ---------------------------------------------------------- +// +// Models Compact Disc read offset entries from AccurateRip database. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.ComponentModel.DataAnnotations; + +namespace Aaru.CommonTypes.Metadata; + +/// Describes CD reading offset +public class CdOffset +{ + /// Drive manufacturer + public string Manufacturer { get; set; } + + /// Drive model + public string Model { get; set; } + + /// Reading offset + public short Offset { get; set; } + + /// Number of times this offset has been submitted + public int Submissions { get; set; } + + /// Percentage of submissions in agreement with this offset + [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:P0}")] + public float Agreement { get; set; } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Metadata/DeviceReport.cs b/Aaru.CommonTypes/Metadata/DeviceReport.cs new file mode 100644 index 000000000..11fce0fe6 --- /dev/null +++ b/Aaru.CommonTypes/Metadata/DeviceReport.cs @@ -0,0 +1,1536 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DeviceReport.cs +// Author(s) : Natalia Portillo +// +// Component : JSON metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains classes for a JSON device report. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// TODO: Re-enable CS1591 in this file + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs.Devices.ATA; +using Aaru.CommonTypes.Structs.Devices.SCSI; +using Aaru.CommonTypes.Structs.Devices.SCSI.Modes; + +#pragma warning disable 1591 + +// ReSharper disable VirtualMemberNeverOverridden.Global +// ReSharper disable VirtualMemberCallInConstructor +// ReSharper disable UnusedMember.Global +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedAutoPropertyAccessor.Global + +namespace Aaru.CommonTypes.Metadata; + +// ReSharper disable once PartialTypeWithSinglePart +[JsonSourceGenerationOptions(WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + IncludeFields = true)] +[JsonSerializable(typeof(DeviceReport))] +public partial class DeviceReportContext : JsonSerializerContext; + +public class DeviceReport +{ + [JsonIgnore] + public int Id { get; set; } + + public virtual Usb USB { get; set; } + public virtual FireWire FireWire { get; set; } + public virtual Pcmcia PCMCIA { get; set; } + public bool CompactFlash { get; set; } + public virtual Ata ATA { get; set; } + public virtual Ata ATAPI { get; set; } + public virtual Scsi SCSI { get; set; } + public virtual MmcSd MultiMediaCard { get; set; } + public virtual MmcSd SecureDigital { get; set; } + public virtual GdRomSwapDiscCapabilities GdRomSwapDiscCapabilities { get; set; } + + public string Manufacturer { get; set; } + public string Model { get; set; } + public string Revision { get; set; } + public DeviceType Type { get; set; } +} + +public class Usb +{ + [JsonIgnore] + public int Id { get; set; } + + [DisplayName("Vendor ID")] + [DisplayFormat(DataFormatString = "0x{0:X4}")] + public ushort VendorID { get; set; } + + [DisplayName("Product ID")] + [DisplayFormat(DataFormatString = "0x{0:X4}")] + public ushort ProductID { get; set; } + + public string Manufacturer { get; set; } + public string Product { get; set; } + + [DisplayName("Removable media")] + public bool RemovableMedia { get; set; } + + public byte[] Descriptors { get; set; } +} + +public class FireWire +{ + [JsonIgnore] + public int Id { get; set; } + + [DisplayName("Vendor ID")] + [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "0x{0:X8}")] + public uint VendorID { get; set; } + + [DisplayName("Product ID")] + [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "0x{0:X8}")] + public uint ProductID { get; set; } + + [DisplayFormat(NullDisplayText = "Unknown")] + public string Manufacturer { get; set; } + + [DisplayFormat(NullDisplayText = "Unknown")] + public string Product { get; set; } + + [DisplayName("Is media removable?")] + public bool RemovableMedia { get; set; } +} + +public class Ata +{ + public Identify.IdentifyDevice? IdentifyDevice => Structs.Devices.ATA.Identify.Decode(Identify); + + [JsonIgnore] + public int Id { get; set; } + + public byte[] Identify { get; set; } + public virtual TestedMedia ReadCapabilities { get; set; } + public virtual List RemovableMedias { get; set; } +} + +public class Chs +{ + [JsonIgnore] + public int Id { get; set; } + + public ushort Cylinders { get; set; } + public ushort Heads { get; set; } + public ushort Sectors { get; set; } +} + +public class Scsi +{ + public Inquiry? Inquiry => Structs.Devices.SCSI.Inquiry.Decode(InquiryData); + + [JsonIgnore] + public int Id { get; set; } + + [DisplayName("Data from INQUIRY command")] + public byte[] InquiryData { get; set; } + + public virtual List EVPDPages { get; set; } + + [DisplayName("Supports MODE SENSE(6)")] + public bool SupportsModeSense6 { get; set; } + + [DisplayName("Supports MODE SENSE(10)")] + public bool SupportsModeSense10 { get; set; } + + [DisplayName("Supports MODE SENSE with subpages")] + public bool SupportsModeSubpages { get; set; } + + public virtual ScsiMode ModeSense { get; set; } + public virtual Mmc MultiMediaDevice { get; set; } + public virtual TestedMedia ReadCapabilities { get; set; } + public virtual List RemovableMedias { get; set; } + public virtual Ssc SequentialDevice { get; set; } + + [DisplayName("Data from MODE SENSE(6) command")] + public byte[] ModeSense6Data { get; set; } + + [DisplayName("Data from MODE SENSE(10) command")] + public byte[] ModeSense10Data { get; set; } + + [DisplayName("Data from MODE SENSE(6) command (current)")] + public byte[] ModeSense6CurrentData { get; set; } + + [DisplayName("Data from MODE SENSE(10) command (current)")] + public byte[] ModeSense10CurrentData { get; set; } + + [DisplayName("Data from MODE SENSE(6) command (changeable)")] + public byte[] ModeSense6ChangeableData { get; set; } + + [DisplayName("Data from MODE SENSE(10) command (changeable)")] + public byte[] ModeSense10ChangeableData { get; set; } + + [JsonIgnore] + public int? SequentialDeviceId { get; set; } +} + +public class ScsiMode +{ + [JsonIgnore] + public int Id { get; set; } + + [DisplayName("Medium type code")] + public byte? MediumType { get; set; } + + [DisplayName("Write protected")] + public bool WriteProtected { get; set; } + + public virtual List BlockDescriptors { get; set; } + public byte? Speed { get; set; } + + [DisplayName("Buffered mode")] + public byte? BufferedMode { get; set; } + + [DisplayName("Blank check enabled")] + public bool BlankCheckEnabled { get; set; } + + [DisplayName("DPO and FUA")] + public bool DPOandFUA { get; set; } + + public virtual List ModePages { get; set; } +} + +public class BlockDescriptor +{ + [JsonIgnore] + public int Id { get; set; } + + public byte Density { get; set; } + public ulong? Blocks { get; set; } + + [DisplayName("Block length (bytes)")] + public uint? BlockLength { get; set; } +} + +public class ScsiPage +{ + [JsonIgnore] + public int Id { get; set; } + + public byte page { get; set; } + public byte? subpage { get; set; } + public byte[] value { get; set; } +} + +public class Mmc +{ + [JsonIgnore] + public int Id { get; set; } + + public virtual ModePage_2A ModeSense2A => ModePage_2A.Decode(ModeSense2AData); + public virtual MmcFeatures Features { get; set; } + public virtual List TestedMedia { get; set; } + public byte[] ModeSense2AData { get; set; } + + [JsonIgnore] + public int? FeaturesId { get; set; } +} + +public class MmcFeatures +{ + [JsonIgnore] + public int Id { get; set; } + + [DisplayName("AACS version")] + public byte? AACSVersion { get; set; } + + [DisplayName("AGIDs")] + public byte? AGIDs { get; set; } + + [DisplayName("Binding nonce blocks")] + public byte? BindingNonceBlocks { get; set; } + + [DisplayName("Blocks per readable unit")] + public ushort? BlocksPerReadableUnit { get; set; } + + [DisplayName("Buffer under-run free in DVD writing")] + public bool BufferUnderrunFreeInDVD { get; set; } + + [DisplayName("Buffer under-run free in SAO writing")] + public bool BufferUnderrunFreeInSAO { get; set; } + + [DisplayName("Buffer under-run free in TAO writing")] + public bool BufferUnderrunFreeInTAO { get; set; } + + [DisplayName("Can audio scan")] + public bool CanAudioScan { get; set; } + + [DisplayName("Can eject")] + public bool CanEject { get; set; } + + [DisplayName("Can erase sectors")] + public bool CanEraseSector { get; set; } + + [DisplayName("Can expand BD-RE spare area")] + public bool CanExpandBDRESpareArea { get; set; } + + [DisplayName("Can format media")] + public bool CanFormat { get; set; } + + [DisplayName("Can format BD-RE without spare area")] + public bool CanFormatBDREWithoutSpare { get; set; } + + [DisplayName("Can do a fully certified format")] + public bool CanFormatCert { get; set; } + + [DisplayName("Can do a FRF format")] + public bool CanFormatFRF { get; set; } + + [DisplayName("Can do a quick certified format")] + public bool CanFormatQCert { get; set; } + + [DisplayName("Can do a RRM format")] + public bool CanFormatRRM { get; set; } + + [DisplayName("Can generate binding nonce")] + public bool CanGenerateBindingNonce { get; set; } + + [DisplayName("Can load")] + public bool CanLoad { get; set; } + + [DisplayName("Can mute separate channels")] + public bool CanMuteSeparateChannels { get; set; } + + [DisplayName("Can overwrite track in SAO")] + public bool CanOverwriteSAOTrack { get; set; } + + [DisplayName("Can overwrite track in TAO")] + public bool CanOverwriteTAOTrack { get; set; } + + [DisplayName("Can play CD-DA")] + public bool CanPlayCDAudio { get; set; } + + [DisplayName("Can pseudo-overwrite BD-R")] + public bool CanPseudoOverwriteBDR { get; set; } + + [DisplayName("Can read all dual-layer recordables")] + public bool CanReadAllDualR { get; set; } + + [DisplayName("Can read all dual-layer rewritables")] + public bool CanReadAllDualRW { get; set; } + + [DisplayName("Can read Blu-ray")] + public bool CanReadBD { get; set; } + + [DisplayName("Can read BD-R")] + public bool CanReadBDR { get; set; } + + [DisplayName("Can read BD-RE v1")] + public bool CanReadBDRE1 { get; set; } + + [DisplayName("Can read BD-RE v2")] + public bool CanReadBDRE2 { get; set; } + + [DisplayName("Can read BD-ROM")] + public bool CanReadBDROM { get; set; } + + [DisplayName("Can read BCA from Blu-ray")] + public bool CanReadBluBCA { get; set; } + + [DisplayName("Can read CD")] + public bool CanReadCD { get; set; } + + [DisplayName("Can read CD-MRW")] + public bool CanReadCDMRW { get; set; } + + [DisplayName("Can read CPRM's MKB")] + public bool CanReadCPRM_MKB { get; set; } + + [DisplayName("Can read DDCD")] + public bool CanReadDDCD { get; set; } + + [DisplayName("Can read DVD")] + public bool CanReadDVD { get; set; } + + [DisplayName("Can read DVD+MRW")] + public bool CanReadDVDPlusMRW { get; set; } + + [DisplayName("Can read DVD+R")] + public bool CanReadDVDPlusR { get; set; } + + [DisplayName("Can read DVD+R DL")] + public bool CanReadDVDPlusRDL { get; set; } + + [DisplayName("Can read DVD+RW")] + public bool CanReadDVDPlusRW { get; set; } + + [DisplayName("Can read DVD+RW DL")] + public bool CanReadDVDPlusRWDL { get; set; } + + [DisplayName("Can read drive's AACS certificate")] + public bool CanReadDriveAACSCertificate { get; set; } + + [DisplayName("Can read HD DVD")] + public bool CanReadHDDVD { get; set; } + + [DisplayName("Can read HD DVD-R")] + public bool CanReadHDDVDR { get; set; } + + [DisplayName("Can read HD DVD-RAM")] + public bool CanReadHDDVDRAM { get; set; } + + [DisplayName("Can read Lead-In's CD-TEXT")] + public bool CanReadLeadInCDText { get; set; } + + [DisplayName("Can read old generation BD-R")] + public bool CanReadOldBDR { get; set; } + + [DisplayName("Can read old generation BD-RE")] + public bool CanReadOldBDRE { get; set; } + + [DisplayName("Can read old generation BD-ROM")] + public bool CanReadOldBDROM { get; set; } + + [DisplayName("Can read spare area information")] + public bool CanReadSpareAreaInformation { get; set; } + + [DisplayName("Can report drive serial number")] + public bool CanReportDriveSerial { get; set; } + + [DisplayName("Can report media serial number")] + public bool CanReportMediaSerial { get; set; } + + [DisplayName("Can test write DDCD-R")] + public bool CanTestWriteDDCDR { get; set; } + + [DisplayName("Can test write DVD")] + public bool CanTestWriteDVD { get; set; } + + [DisplayName("Can test write in SAO mode")] + public bool CanTestWriteInSAO { get; set; } + + [DisplayName("Can test write in TAO mode")] + public bool CanTestWriteInTAO { get; set; } + + [DisplayName("Can upgrade firmware")] + public bool CanUpgradeFirmware { get; set; } + + [DisplayName("Can write Blu-ray")] + public bool CanWriteBD { get; set; } + + [DisplayName("Can write BD-R")] + public bool CanWriteBDR { get; set; } + + [DisplayName("Can write BD-RE v1")] + public bool CanWriteBDRE1 { get; set; } + + [DisplayName("Can write BD-RE v2")] + public bool CanWriteBDRE2 { get; set; } + + [DisplayName("Can write bus encrypted blocks")] + public bool CanWriteBusEncryptedBlocks { get; set; } + + [DisplayName("Can write CD-MRW")] + public bool CanWriteCDMRW { get; set; } + + [DisplayName("Can write CD-RW")] + public bool CanWriteCDRW { get; set; } + + [DisplayName("Can write CD-RW CAV")] + public bool CanWriteCDRWCAV { get; set; } + + [DisplayName("Can write CD in SAO mode")] + public bool CanWriteCDSAO { get; set; } + + [DisplayName("Can write CD in TAO mode")] + public bool CanWriteCDTAO { get; set; } + + [DisplayName("Can write CSS managed DVD")] + public bool CanWriteCSSManagedDVD { get; set; } + + [DisplayName("Can write DDCD-R")] + public bool CanWriteDDCDR { get; set; } + + [DisplayName("Can write DDCD-RW")] + public bool CanWriteDDCDRW { get; set; } + + [DisplayName("Can write DVD+MRW")] + public bool CanWriteDVDPlusMRW { get; set; } + + [DisplayName("Can write DVD+R")] + public bool CanWriteDVDPlusR { get; set; } + + [DisplayName("Can write DVD+R DL")] + public bool CanWriteDVDPlusRDL { get; set; } + + [DisplayName("Can write DVD+RW")] + public bool CanWriteDVDPlusRW { get; set; } + + [DisplayName("Can write DVD+RW DL")] + public bool CanWriteDVDPlusRWDL { get; set; } + + [DisplayName("Can write DVD-R")] + public bool CanWriteDVDR { get; set; } + + [DisplayName("Can write DVD-R DL")] + public bool CanWriteDVDRDL { get; set; } + + [DisplayName("Can write DVD-RW")] + public bool CanWriteDVDRW { get; set; } + + [DisplayName("Can write HD DVD-R")] + public bool CanWriteHDDVDR { get; set; } + + [DisplayName("Can write HD DVD-RAM")] + public bool CanWriteHDDVDRAM { get; set; } + + [DisplayName("Can write old generation BD-R")] + public bool CanWriteOldBDR { get; set; } + + [DisplayName("Can write old generation BD-RE")] + public bool CanWriteOldBDRE { get; set; } + + [DisplayName("Can write packet subchannel in TAO")] + public bool CanWritePackedSubchannelInTAO { get; set; } + + [DisplayName("Can write RW subchannel in SAO")] + public bool CanWriteRWSubchannelInSAO { get; set; } + + [DisplayName("Can write RW subchannel in TAO")] + public bool CanWriteRWSubchannelInTAO { get; set; } + + [DisplayName("Can write RAW-96 sectors")] + public bool CanWriteRaw { get; set; } + + [DisplayName("Can write RAW-96 sectors in multisession")] + public bool CanWriteRawMultiSession { get; set; } + + [DisplayName("Can write RAW-96 sectors in TAO")] + public bool CanWriteRawSubchannelInTAO { get; set; } + + [DisplayName("Changer is side change capable")] + public bool ChangerIsSideChangeCapable { get; set; } + + [DisplayName("Changer slots")] + public byte ChangerSlots { get; set; } + + [DisplayName("Changer supports disc present")] + public bool ChangerSupportsDiscPresent { get; set; } + + [DisplayName("CPRM version")] + public byte? CPRMVersion { get; set; } + + [DisplayName("CSS version")] + public byte? CSSVersion { get; set; } + + [DisplayName("DBML")] + public bool DBML { get; set; } + + [DisplayName("DVD Multi-Read Specification")] + public bool DVDMultiRead { get; set; } + + [DisplayName("Has an embedded changer")] + public bool EmbeddedChanger { get; set; } + + [DisplayName("Has error recovery page")] + public bool ErrorRecoveryPage { get; set; } + + [DisplayName("Firmware date")] + public DateTime? FirmwareDate { get; set; } + + [DisplayName("Loading mechanism type")] + public byte? LoadingMechanismType { get; set; } + + [DisplayName("Locked")] + public bool Locked { get; set; } + + [DisplayName("Logical block size")] + public uint? LogicalBlockSize { get; set; } + + [DisplayName("Multi-Read Specification")] + public bool MultiRead { get; set; } + + [DisplayName("Physical interface standard")] + public PhysicalInterfaces? PhysicalInterfaceStandard => (PhysicalInterfaces?)PhysicalInterfaceStandardNumber; + + [DisplayName("Physical interface standard number")] + public uint? PhysicalInterfaceStandardNumber { get; set; } + + [DisplayName("Prevent eject jumper")] + public bool PreventJumper { get; set; } + + [DisplayName("Supports AACS")] + public bool SupportsAACS { get; set; } + + [DisplayName("Supports bus encryption")] + public bool SupportsBusEncryption { get; set; } + + [DisplayName("Supports C2 pointers")] + public bool SupportsC2 { get; set; } + + [DisplayName("Supports CPRM")] + public bool SupportsCPRM { get; set; } + + [DisplayName("Supports CSS")] + public bool SupportsCSS { get; set; } + + [DisplayName("Supports DAP")] + public bool SupportsDAP { get; set; } + + [DisplayName("Supports device busy event")] + public bool SupportsDeviceBusyEvent { get; set; } + + [DisplayName("Supports hybrid discs")] + public bool SupportsHybridDiscs { get; set; } + + [DisplayName("Supports MODE PAGE 1Ch")] + public bool SupportsModePage1Ch { get; set; } + + [DisplayName("Supports OSSC")] + public bool SupportsOSSC { get; set; } + + [DisplayName("Supports PWP")] + public bool SupportsPWP { get; set; } + + [DisplayName("Supports SWPP")] + public bool SupportsSWPP { get; set; } + + [DisplayName("Supports SecurDisc")] + public bool SupportsSecurDisc { get; set; } + + [DisplayName("Support separate volume levels")] + public bool SupportsSeparateVolume { get; set; } + + [DisplayName("Supports VCPS")] + public bool SupportsVCPS { get; set; } + + [DisplayName("Supports write inhibit DCB")] + public bool SupportsWriteInhibitDCB { get; set; } + + [DisplayName("Supports write protect PAC")] + public bool SupportsWriteProtectPAC { get; set; } + + [DisplayName("Volume levels")] + public ushort? VolumeLevels { get; set; } + + [DisplayName("MMC FEATURES binary data")] + public byte[] BinaryData { get; set; } +} + +public class TestedMedia +{ + public Identify.IdentifyDevice? IdentifyDevice; + + [JsonIgnore] + public int Id { get; set; } + + [DisplayName("IDENTIFY DEVICE data")] + public byte[] IdentifyData { get; set; } + + [DisplayName("Blocks")] + public ulong? Blocks { get; set; } + + [DisplayName("Bytes per block")] + public uint? BlockSize { get; set; } + + [DisplayName("Can read AACS")] + public bool? CanReadAACS { get; set; } + + [DisplayName("Can read ADIP")] + public bool? CanReadADIP { get; set; } + + [DisplayName("Can read ATIP")] + public bool? CanReadATIP { get; set; } + + [DisplayName("Can read BCA")] + public bool? CanReadBCA { get; set; } + + [DisplayName("Can read C2 pointers")] + public bool? CanReadC2Pointers { get; set; } + + [DisplayName("Can read Copyright Management Information")] + public bool? CanReadCMI { get; set; } + + [DisplayName("Can read corrected subchannel")] + public bool? CanReadCorrectedSubchannel { get; set; } + + [DisplayName("Can read corrected subchannel with C2 pointers")] + public bool? CanReadCorrectedSubchannelWithC2 { get; set; } + + [DisplayName("Can read DCBs")] + public bool? CanReadDCB { get; set; } + + [DisplayName("Can read DDS")] + public bool? CanReadDDS { get; set; } + + [DisplayName("Can read DMI")] + public bool? CanReadDMI { get; set; } + + [DisplayName("Can read disc information")] + public bool? CanReadDiscInformation { get; set; } + + [DisplayName("Can read full TOC")] + public bool? CanReadFullTOC { get; set; } + + [DisplayName("Can read HD-DVD Copyright Management Information")] + public bool? CanReadHDCMI { get; set; } + + [DisplayName("Can read layer capacity")] + public bool? CanReadLayerCapacity { get; set; } + + [DisplayName("Can read into first track pregap")] + public bool? CanReadFirstTrackPreGap { get; set; } + + [DisplayName("Can read into Lead-In")] + public bool? CanReadLeadIn { get; set; } + + [DisplayName("Can read into Lead-Out")] + public bool? CanReadLeadOut { get; set; } + + [DisplayName("Can read media ID")] + public bool? CanReadMediaID { get; set; } + + [DisplayName("Can read media serial number")] + public bool? CanReadMediaSerial { get; set; } + + [DisplayName("Can read PAC")] + public bool? CanReadPAC { get; set; } + + [DisplayName("Can read PFI")] + public bool? CanReadPFI { get; set; } + + [DisplayName("Can read PMA")] + public bool? CanReadPMA { get; set; } + + [DisplayName("Can read PQ subchannel")] + public bool? CanReadPQSubchannel { get; set; } + + [DisplayName("Can read PQ subchannel with C2 pointers")] + public bool? CanReadPQSubchannelWithC2 { get; set; } + + [DisplayName("Can read pre-recorded information")] + public bool? CanReadPRI { get; set; } + + [DisplayName("Can read RW subchannel")] + public bool? CanReadRWSubchannel { get; set; } + + [DisplayName("Can read RW subchannel with C2 pointers")] + public bool? CanReadRWSubchannelWithC2 { get; set; } + + [DisplayName("Can read recordable PFI")] + public bool? CanReadRecordablePFI { get; set; } + + [DisplayName("Can read spare area information")] + public bool? CanReadSpareAreaInformation { get; set; } + + [DisplayName("Can read TOC")] + public bool? CanReadTOC { get; set; } + + [DisplayName("Density code")] + public byte? Density { get; set; } + + [DisplayName("Bytes per block in READ LONG commands")] + public uint? LongBlockSize { get; set; } + + [DisplayName("Media manufacturer")] + public string Manufacturer { get; set; } + + [DisplayName("Media recognized by drive?")] + public bool MediaIsRecognized { get; set; } + + [DisplayName("Medium type code")] + public byte? MediumType { get; set; } + + [DisplayName("Media type")] + public string MediumTypeName { get; set; } + + [DisplayName("Media model")] + public string Model { get; set; } + + [DisplayName("Can read scrambled DVD sectors using HL-DT-ST cache trick")] + public bool? SupportsHLDTSTReadRawDVD { get; set; } + + [DisplayName("Supports NEC READ CD-DA command")] + public bool? SupportsNECReadCDDA { get; set; } + + [DisplayName("Supports Pioneer READ CD-DA command")] + public bool? SupportsPioneerReadCDDA { get; set; } + + [DisplayName("Supports Pioneer READ CD-DA MSF command")] + public bool? SupportsPioneerReadCDDAMSF { get; set; } + + [DisplayName("Supports Plextor READ CD-DA command")] + public bool? SupportsPlextorReadCDDA { get; set; } + + [DisplayName("Can read scrambled DVD sectors using Plextor vendor command")] + public bool? SupportsPlextorReadRawDVD { get; set; } + + [DisplayName("Supports READ(10) command")] + public bool? SupportsRead10 { get; set; } + + [DisplayName("Supports READ(12) command")] + public bool? SupportsRead12 { get; set; } + + [DisplayName("Supports READ(16) command")] + public bool? SupportsRead16 { get; set; } + + [DisplayName("Supports READ(6) command")] + public bool? SupportsRead6 { get; set; } + + [DisplayName("Supports READ CAPACITY(16) command")] + public bool? SupportsReadCapacity16 { get; set; } + + [DisplayName("Supports READ CAPACITY command")] + public bool? SupportsReadCapacity { get; set; } + + [DisplayName("Supports READ CD command")] + public bool? SupportsReadCd { get; set; } + + [DisplayName("Supports READ CD MSF command")] + public bool? SupportsReadCdMsf { get; set; } + + [DisplayName("Supports full sector in READ CD command")] + public bool? SupportsReadCdRaw { get; set; } + + [DisplayName("Supports full sector in READ CD MSF command")] + public bool? SupportsReadCdMsfRaw { get; set; } + + [DisplayName("Supports READ LONG(16) command")] + public bool? SupportsReadLong16 { get; set; } + + [DisplayName("Supports READ LONG command")] + public bool? SupportsReadLong { get; set; } + + [DisplayName("Data from MODE SENSE(6) command")] + public byte[] ModeSense6Data { get; set; } + + [DisplayName("Data from MODE SENSE(10) command")] + public byte[] ModeSense10Data { get; set; } + + public virtual Chs CHS { get; set; } + public virtual Chs CurrentCHS { get; set; } + + [DisplayName("Sectors in 28-bit LBA mode")] + public uint? LBASectors { get; set; } + + [DisplayName("Sectors in 48-bit LBA mode")] + public ulong? LBA48Sectors { get; set; } + + [DisplayName("Logical alignment")] + public ushort? LogicalAlignment { get; set; } + + [DisplayName("Nominal rotation rate")] + public ushort? NominalRotationRate { get; set; } + + [DisplayName("Bytes per block, physical")] + public uint? PhysicalBlockSize { get; set; } + + [DisplayName("Is it a SSD?")] + public bool? SolidStateDevice { get; set; } + + [DisplayName("Bytes per unformatted track")] + public ushort? UnformattedBPT { get; set; } + + [DisplayName("Bytes per unformatted sector")] + public ushort? UnformattedBPS { get; set; } + + [DisplayName("Supports READ DMA (LBA) command")] + public bool? SupportsReadDmaLba { get; set; } + + [DisplayName("Supports READ DMA RETRY (LBA) command")] + public bool? SupportsReadDmaRetryLba { get; set; } + + [DisplayName("Supports READ SECTORS (LBA) command")] + public bool? SupportsReadLba { get; set; } + + [DisplayName("Supports READ SECTORS RETRY (LBA) command")] + public bool? SupportsReadRetryLba { get; set; } + + [DisplayName("Supports READ SECTORS LONG (LBA) command")] + public bool? SupportsReadLongLba { get; set; } + + [DisplayName("Supports READ SECTORS LONG RETRY (LBA) command")] + public bool? SupportsReadLongRetryLba { get; set; } + + [DisplayName("Supports SEEK (LBA) command")] + public bool? SupportsSeekLba { get; set; } + + [DisplayName("Supports READ DMA EXT command")] + public bool? SupportsReadDmaLba48 { get; set; } + + [DisplayName("Supports READ SECTORS EXT command")] + public bool? SupportsReadLba48 { get; set; } + + [DisplayName("Supports READ DMA command")] + public bool? SupportsReadDma { get; set; } + + [DisplayName("Supports READ DMA RETRY command")] + public bool? SupportsReadDmaRetry { get; set; } + + [DisplayName("Supports READ SECTORS RETRY command")] + public bool? SupportsReadRetry { get; set; } + + [DisplayName("Supports READ SECTORS command")] + public bool? SupportsReadSectors { get; set; } + + [DisplayName("Supports READ SECTORS LONG RETRY command")] + public bool? SupportsReadLongRetry { get; set; } + + [DisplayName("Supports SEEK command")] + public bool? SupportsSeek { get; set; } + + [DisplayName("Can read into inter-session Lead-In")] + public bool? CanReadingIntersessionLeadIn { get; set; } + + [DisplayName("Can read into inter-session Lead-Out")] + public bool? CanReadingIntersessionLeadOut { get; set; } + + [DisplayName("Data from inter-session Lead-In")] + public byte[] IntersessionLeadInData { get; set; } + + [DisplayName("Data from inter-session Lead-Out")] + public byte[] IntersessionLeadOutData { get; set; } + + [DisplayName("Can read scrambled data using READ CD command")] + public bool? CanReadCdScrambled { get; set; } + + [DisplayName("Data from scrambled READ CD command")] + public byte[] ReadCdScrambledData { get; set; } + + [DisplayName("Can read from cache using F1h command subcommand 06h")] + public bool? CanReadF1_06 { get; set; } + + [DisplayName("Can read from cache using F1h command subcommand 06h")] + public byte[] ReadF1_06Data { get; set; } + + [DisplayName("Can read from cache using F1h command subcommand 06h targeting Lead-Out")] + public bool? CanReadF1_06LeadOut { get; set; } + + [DisplayName("Can read from cache using F1h command subcommand 06h targeting Lead-Out")] + public byte[] ReadF1_06LeadOutData { get; set; } + + [JsonIgnore] + public int? AtaId { get; set; } + + [JsonIgnore] + public int? ScsiId { get; set; } + + [JsonIgnore] + public int? MmcId { get; set; } + +#region SCSI data + + [DisplayName("Data from READ(6) command")] + public byte[] Read6Data { get; set; } + + [DisplayName("Data from READ(10) command")] + public byte[] Read10Data { get; set; } + + [DisplayName("Data from READ(12) command")] + public byte[] Read12Data { get; set; } + + [DisplayName("Data from READ(16) command")] + public byte[] Read16Data { get; set; } + + [DisplayName("Data from READ LONG(10) command")] + public byte[] ReadLong10Data { get; set; } + + [DisplayName("Data from READ LONG(16) command")] + public byte[] ReadLong16Data { get; set; } + +#endregion + +#region ATA data + + [DisplayName("Data from READ SECTORS command")] + public byte[] ReadSectorsData { get; set; } + + [DisplayName("Data from READ SECTORS RETRY command")] + public byte[] ReadSectorsRetryData { get; set; } + + [DisplayName("Data from READ DMA command")] + public byte[] ReadDmaData { get; set; } + + [DisplayName("Data from READ DMA RETRY command")] + public byte[] ReadDmaRetryData { get; set; } + + [DisplayName("Data from READ SECTORS (LBA) command")] + public byte[] ReadLbaData { get; set; } + + [DisplayName("Data from READ SECTORS RETRY (LBA) command")] + public byte[] ReadRetryLbaData { get; set; } + + [DisplayName("Data from READ DMA (LBA) command")] + public byte[] ReadDmaLbaData { get; set; } + + [DisplayName("Data from READ DMA RETRY (LBA) command")] + public byte[] ReadDmaRetryLbaData { get; set; } + + [DisplayName("Data from READ SECTORS EXT command")] + public byte[] ReadLba48Data { get; set; } + + [DisplayName("Data from READ DMA EXT command")] + public byte[] ReadDmaLba48Data { get; set; } + + [DisplayName("Data from READ SECTORS LONG command")] + public byte[] ReadLongData { get; set; } + + [DisplayName("Data from READ SECTORS LONG RETRY command")] + public byte[] ReadLongRetryData { get; set; } + + [DisplayName("Data from READ SECTORS LONG (LBA) command")] + public byte[] ReadLongLbaData { get; set; } + + [DisplayName("Data from READ SECTORS LONG RETRY (LBA) command")] + public byte[] ReadLongRetryLbaData { get; set; } + +#endregion + +#region CompactDisc data + + [DisplayName("Data from READ TOC command")] + public byte[] TocData { get; set; } + + [DisplayName("Data from READ FULL TOC command")] + public byte[] FullTocData { get; set; } + + [DisplayName("Data from READ ATIP command")] + public byte[] AtipData { get; set; } + + [DisplayName("Data from READ PMA command")] + public byte[] PmaData { get; set; } + + [DisplayName("Data from READ CD command")] + public byte[] ReadCdData { get; set; } + + [DisplayName("Data from READ CD MSF command")] + public byte[] ReadCdMsfData { get; set; } + + [DisplayName("Data from READ CD (full sector) command")] + public byte[] ReadCdFullData { get; set; } + + [DisplayName("Data from READ CD MSF (full sector) command")] + public byte[] ReadCdMsfFullData { get; set; } + + [DisplayName("Data from track 1 pregap")] + public byte[] Track1PregapData { get; set; } + + [DisplayName("Data from Lead-In")] + public byte[] LeadInData { get; set; } + + [DisplayName("Data from Lead-Out")] + public byte[] LeadOutData { get; set; } + + [DisplayName("Data from reading C2 pointers")] + public byte[] C2PointersData { get; set; } + + [DisplayName("Data from reading with PQ subchannels")] + public byte[] PQSubchannelData { get; set; } + + [DisplayName("Data from reading with RW subchannels")] + public byte[] RWSubchannelData { get; set; } + + [DisplayName("Data from reading with corrected subchannels")] + public byte[] CorrectedSubchannelData { get; set; } + + [DisplayName("Data from reading with PQ subchannels and C2 pointers")] + public byte[] PQSubchannelWithC2Data { get; set; } + + [DisplayName("Data from reading with RW subchannels and C2 pointers")] + public byte[] RWSubchannelWithC2Data { get; set; } + + [DisplayName("Data from reading with corrected subchannels and C2 pointers")] + public byte[] CorrectedSubchannelWithC2Data { get; set; } + +#endregion + +#region DVD data + + [DisplayName("Data from PFI")] + public byte[] PfiData { get; set; } + + [DisplayName("Data from DMI")] + public byte[] DmiData { get; set; } + + [DisplayName("Data from DVD's Copyright Management Information")] + public byte[] CmiData { get; set; } + + [DisplayName("Data from DVD's BCA")] + public byte[] DvdBcaData { get; set; } + + [DisplayName("Data from DVD's AACS")] + public byte[] DvdAacsData { get; set; } + + [DisplayName("Data from DVD's DDS")] + public byte[] DvdDdsData { get; set; } + + [DisplayName("Data from DVD's Spare Area Information")] + public byte[] DvdSaiData { get; set; } + + [DisplayName("Data from DVD's pre-recorded information")] + public byte[] PriData { get; set; } + + [DisplayName("Data from embossed PFI")] + public byte[] EmbossedPfiData { get; set; } + + [DisplayName("Data from ADIP")] + public byte[] AdipData { get; set; } + + [DisplayName("Data from DCBs")] + public byte[] DcbData { get; set; } + + [DisplayName("Data from HD-DVD's Copyright Management Information")] + public byte[] HdCmiData { get; set; } + + [DisplayName("Data from DVD's layer information")] + public byte[] DvdLayerData { get; set; } + +#endregion + +#region Blu-ray data + + [DisplayName("Data from Blu-ray's BCA")] + public byte[] BluBcaData { get; set; } + + [DisplayName("Data from Blu-ray's DDS")] + public byte[] BluDdsData { get; set; } + + [DisplayName("Data from Blu-ray's Spare Area Information")] + public byte[] BluSaiData { get; set; } + + [DisplayName("Data from Blu-ray's Disc Information")] + public byte[] BluDiData { get; set; } + + [DisplayName("Data from Blu-ray's PAC")] + public byte[] BluPacData { get; set; } + +#endregion + +#region Vendor data + + [DisplayName("Data from Plextor's READ CD-DA command")] + public byte[] PlextorReadCddaData { get; set; } + + [DisplayName("Data from Pioneer's READ CD-DA command")] + public byte[] PioneerReadCddaData { get; set; } + + [DisplayName("Data from Pioneer's READ CD-DA MSF command")] + public byte[] PioneerReadCddaMsfData { get; set; } + + [DisplayName("Data from NEC's READ CD-DA command")] + public byte[] NecReadCddaData { get; set; } + + [DisplayName("Data from Plextor's scrambled DVD reading command")] + public byte[] PlextorReadRawDVDData { get; set; } + + [DisplayName("Data from HL-DT-ST's scrambled DVD reading trick")] + public byte[] HLDTSTReadRawDVDData { get; set; } + +#endregion +} + +public class Ssc +{ + [JsonIgnore] + public int Id { get; set; } + + [DisplayName("Block size granularity")] + public byte? BlockSizeGranularity { get; set; } + + [DisplayName("Maximum block length")] + public uint? MaxBlockLength { get; set; } + + [DisplayName("Minimum block length")] + public uint? MinBlockLength { get; set; } + + public virtual List SupportedDensities { get; set; } + public virtual List SupportedMediaTypes { get; set; } + public virtual List TestedMedia { get; set; } +} + +public class TestedSequentialMedia +{ + [JsonIgnore] + public int Id { get; set; } + + [DisplayName("Can read media serial?")] + public bool? CanReadMediaSerial { get; set; } + + [DisplayName("Density code")] + public byte? Density { get; set; } + + public string Manufacturer { get; set; } + + [DisplayName("Media recognized by drive?")] + public bool MediaIsRecognized { get; set; } + + [DisplayName("Medium type code")] + public byte? MediumType { get; set; } + + [DisplayName("Medium type")] + public string MediumTypeName { get; set; } + + public string Model { get; set; } + public virtual List SupportedDensities { get; set; } + public virtual List SupportedMediaTypes { get; set; } + + public byte[] ModeSense6Data { get; set; } + public byte[] ModeSense10Data { get; set; } + + [JsonIgnore] + public int? SscId { get; set; } +} + +public class Pcmcia +{ + public string[] AdditionalInformation; + + [JsonIgnore] + public int Id { get; set; } + + public byte[] CIS { get; set; } + public string Compliance { get; set; } + + [DisplayName("Manufacturer code")] + public ushort? ManufacturerCode { get; set; } + + [DisplayName("Card code")] + public ushort? CardCode { get; set; } + + public string Manufacturer { get; set; } + + [DisplayName("Product name")] + public string ProductName { get; set; } +} + +public class MmcSd +{ + [JsonIgnore] + public int Id { get; set; } + + public byte[] CID { get; set; } + public byte[] CSD { get; set; } + public byte[] OCR { get; set; } + public byte[] SCR { get; set; } + public byte[] ExtendedCSD { get; set; } +} + +public class SscSupportedMedia +{ + [JsonIgnore] + public int Id { get; set; } + + public byte MediumType { get; set; } + public virtual List DensityCodes { get; set; } + public ushort Width { get; set; } + public ushort Length { get; set; } + public string Organization { get; set; } + public string Name { get; set; } + public string Description { get; set; } + + [JsonIgnore] + public int? SscId { get; set; } +} + +public class DensityCode : IEquatable +{ + [JsonIgnore] + [Key] + public int Id { get; set; } + + public int Code { get; set; } + +#region IEquatable Members + + public bool Equals(DensityCode other) + { + if(ReferenceEquals(null, other)) return false; + + if(ReferenceEquals(this, other)) return true; + + return Code == other.Code; + } + +#endregion + + public override bool Equals(object obj) + { + if(ReferenceEquals(null, obj)) return false; + + if(ReferenceEquals(this, obj)) return true; + + return obj.GetType() == GetType() && Equals((DensityCode)obj); + } + + // ReSharper disable once NonReadonlyMemberInGetHashCode + public override int GetHashCode() => Code; +} + +public class GdRomSwapDiscCapabilities +{ + [JsonIgnore] + [Key] + public int Id { get; set; } + + public bool RecognizedSwapDisc { get; set; } + public bool TestCrashed { get; set; } + public byte SwapDiscLeadOutPMIN { get; set; } + public byte SwapDiscLeadOutPSEC { get; set; } + public byte SwapDiscLeadOutPFRAM { get; set; } + public int SwapDiscLeadOutStart { get; set; } + public bool Lba0Readable { get; set; } + public byte[] Lba0Data { get; set; } + public byte[] Lba0Sense { get; set; } + public string Lba0DecodedSense { get; set; } + public bool Lba0ScrambledReadable { get; set; } + public byte[] Lba0ScrambledData { get; set; } + public byte[] Lba0ScrambledSense { get; set; } + public string Lba0ScrambledDecodedSense { get; set; } + public bool Lba44990Readable { get; set; } + public byte[] Lba44990Data { get; set; } + public byte[] Lba44990Sense { get; set; } + public string Lba44990DecodedSense { get; set; } + public int Lba44990ReadableCluster { get; set; } + public bool Lba45000Readable { get; set; } + public byte[] Lba45000Data { get; set; } + public byte[] Lba45000Sense { get; set; } + public string Lba45000DecodedSense { get; set; } + public int Lba45000ReadableCluster { get; set; } + public bool Lba50000Readable { get; set; } + public byte[] Lba50000Data { get; set; } + public byte[] Lba50000Sense { get; set; } + public string Lba50000DecodedSense { get; set; } + public int Lba50000ReadableCluster { get; set; } + public bool Lba100000Readable { get; set; } + public byte[] Lba100000Data { get; set; } + public byte[] Lba100000Sense { get; set; } + public string Lba100000DecodedSense { get; set; } + public int Lba100000ReadableCluster { get; set; } + public bool Lba400000Readable { get; set; } + public byte[] Lba400000Data { get; set; } + public byte[] Lba400000Sense { get; set; } + public string Lba400000DecodedSense { get; set; } + public int Lba400000ReadableCluster { get; set; } + public bool Lba450000Readable { get; set; } + public byte[] Lba450000Data { get; set; } + public byte[] Lba450000Sense { get; set; } + public string Lba450000DecodedSense { get; set; } + public int Lba450000ReadableCluster { get; set; } + public bool Lba44990PqReadable { get; set; } + public byte[] Lba44990PqData { get; set; } + public byte[] Lba44990PqSense { get; set; } + public string Lba44990PqDecodedSense { get; set; } + public int Lba44990PqReadableCluster { get; set; } + public bool Lba45000PqReadable { get; set; } + public byte[] Lba45000PqData { get; set; } + public byte[] Lba45000PqSense { get; set; } + public string Lba45000PqDecodedSense { get; set; } + public int Lba45000PqReadableCluster { get; set; } + public bool Lba50000PqReadable { get; set; } + public byte[] Lba50000PqData { get; set; } + public byte[] Lba50000PqSense { get; set; } + public string Lba50000PqDecodedSense { get; set; } + public int Lba50000PqReadableCluster { get; set; } + public bool Lba100000PqReadable { get; set; } + public byte[] Lba100000PqData { get; set; } + public byte[] Lba100000PqSense { get; set; } + public string Lba100000PqDecodedSense { get; set; } + public int Lba100000PqReadableCluster { get; set; } + public bool Lba400000PqReadable { get; set; } + public byte[] Lba400000PqData { get; set; } + public byte[] Lba400000PqSense { get; set; } + public string Lba400000PqDecodedSense { get; set; } + public int Lba400000PqReadableCluster { get; set; } + public bool Lba450000PqReadable { get; set; } + public byte[] Lba450000PqData { get; set; } + public byte[] Lba450000PqSense { get; set; } + public string Lba450000PqDecodedSense { get; set; } + public int Lba450000PqReadableCluster { get; set; } + public bool Lba44990RwReadable { get; set; } + public byte[] Lba44990RwData { get; set; } + public byte[] Lba44990RwSense { get; set; } + public string Lba44990RwDecodedSense { get; set; } + public int Lba44990RwReadableCluster { get; set; } + public bool Lba45000RwReadable { get; set; } + public byte[] Lba45000RwData { get; set; } + public byte[] Lba45000RwSense { get; set; } + public string Lba45000RwDecodedSense { get; set; } + public int Lba45000RwReadableCluster { get; set; } + public bool Lba50000RwReadable { get; set; } + public byte[] Lba50000RwData { get; set; } + public byte[] Lba50000RwSense { get; set; } + public string Lba50000RwDecodedSense { get; set; } + public int Lba50000RwReadableCluster { get; set; } + public bool Lba100000RwReadable { get; set; } + public byte[] Lba100000RwData { get; set; } + public byte[] Lba100000RwSense { get; set; } + public string Lba100000RwDecodedSense { get; set; } + public int Lba100000RwReadableCluster { get; set; } + public bool Lba400000RwReadable { get; set; } + public byte[] Lba400000RwData { get; set; } + public byte[] Lba400000RwSense { get; set; } + public string Lba400000RwDecodedSense { get; set; } + public int Lba400000RwReadableCluster { get; set; } + public bool Lba450000RwReadable { get; set; } + public byte[] Lba450000RwData { get; set; } + public byte[] Lba450000RwSense { get; set; } + public string Lba450000RwDecodedSense { get; set; } + public int Lba450000RwReadableCluster { get; set; } + public bool Lba44990AudioReadable { get; set; } + public byte[] Lba44990AudioData { get; set; } + public byte[] Lba44990AudioSense { get; set; } + public string Lba44990AudioDecodedSense { get; set; } + public int Lba44990AudioReadableCluster { get; set; } + public bool Lba45000AudioReadable { get; set; } + public byte[] Lba45000AudioData { get; set; } + public byte[] Lba45000AudioSense { get; set; } + public string Lba45000AudioDecodedSense { get; set; } + public int Lba45000AudioReadableCluster { get; set; } + public bool Lba50000AudioReadable { get; set; } + public byte[] Lba50000AudioData { get; set; } + public byte[] Lba50000AudioSense { get; set; } + public string Lba50000AudioDecodedSense { get; set; } + public int Lba50000AudioReadableCluster { get; set; } + public bool Lba100000AudioReadable { get; set; } + public byte[] Lba100000AudioData { get; set; } + public byte[] Lba100000AudioSense { get; set; } + public string Lba100000AudioDecodedSense { get; set; } + public int Lba100000AudioReadableCluster { get; set; } + public bool Lba400000AudioReadable { get; set; } + public byte[] Lba400000AudioData { get; set; } + public byte[] Lba400000AudioSense { get; set; } + public string Lba400000AudioDecodedSense { get; set; } + public int Lba400000AudioReadableCluster { get; set; } + public bool Lba450000AudioReadable { get; set; } + public byte[] Lba450000AudioData { get; set; } + public byte[] Lba450000AudioSense { get; set; } + public string Lba450000AudioDecodedSense { get; set; } + public int Lba450000AudioReadableCluster { get; set; } + public bool Lba44990AudioPqReadable { get; set; } + public byte[] Lba44990AudioPqData { get; set; } + public byte[] Lba44990AudioPqSense { get; set; } + public string Lba44990AudioPqDecodedSense { get; set; } + public int Lba44990AudioPqReadableCluster { get; set; } + public bool Lba45000AudioPqReadable { get; set; } + public byte[] Lba45000AudioPqData { get; set; } + public byte[] Lba45000AudioPqSense { get; set; } + public string Lba45000AudioPqDecodedSense { get; set; } + public int Lba45000AudioPqReadableCluster { get; set; } + public bool Lba50000AudioPqReadable { get; set; } + public byte[] Lba50000AudioPqData { get; set; } + public byte[] Lba50000AudioPqSense { get; set; } + public string Lba50000AudioPqDecodedSense { get; set; } + public int Lba50000AudioPqReadableCluster { get; set; } + public bool Lba100000AudioPqReadable { get; set; } + public byte[] Lba100000AudioPqData { get; set; } + public byte[] Lba100000AudioPqSense { get; set; } + public string Lba100000AudioPqDecodedSense { get; set; } + public int Lba100000AudioPqReadableCluster { get; set; } + public bool Lba400000AudioPqReadable { get; set; } + public byte[] Lba400000AudioPqData { get; set; } + public byte[] Lba400000AudioPqSense { get; set; } + public string Lba400000AudioPqDecodedSense { get; set; } + public int Lba400000AudioPqReadableCluster { get; set; } + public bool Lba450000AudioPqReadable { get; set; } + public byte[] Lba450000AudioPqData { get; set; } + public byte[] Lba450000AudioPqSense { get; set; } + public string Lba450000AudioPqDecodedSense { get; set; } + public int Lba450000AudioPqReadableCluster { get; set; } + public bool Lba44990AudioRwReadable { get; set; } + public byte[] Lba44990AudioRwData { get; set; } + public byte[] Lba44990AudioRwSense { get; set; } + public string Lba44990AudioRwDecodedSense { get; set; } + public int Lba44990AudioRwReadableCluster { get; set; } + public bool Lba45000AudioRwReadable { get; set; } + public byte[] Lba45000AudioRwData { get; set; } + public byte[] Lba45000AudioRwSense { get; set; } + public string Lba45000AudioRwDecodedSense { get; set; } + public int Lba45000AudioRwReadableCluster { get; set; } + public bool Lba50000AudioRwReadable { get; set; } + public byte[] Lba50000AudioRwData { get; set; } + public byte[] Lba50000AudioRwSense { get; set; } + public string Lba50000AudioRwDecodedSense { get; set; } + public int Lba50000AudioRwReadableCluster { get; set; } + public bool Lba100000AudioRwReadable { get; set; } + public byte[] Lba100000AudioRwData { get; set; } + public byte[] Lba100000AudioRwSense { get; set; } + public string Lba100000AudioRwDecodedSense { get; set; } + public int Lba100000AudioRwReadableCluster { get; set; } + public bool Lba400000AudioRwReadable { get; set; } + public byte[] Lba400000AudioRwData { get; set; } + public byte[] Lba400000AudioRwSense { get; set; } + public string Lba400000AudioRwDecodedSense { get; set; } + public int Lba400000AudioRwReadableCluster { get; set; } + public bool Lba450000AudioRwReadable { get; set; } + public byte[] Lba450000AudioRwData { get; set; } + public byte[] Lba450000AudioRwSense { get; set; } + public string Lba450000AudioRwDecodedSense { get; set; } + public int Lba450000AudioRwReadableCluster { get; set; } + public uint MinimumReadableSectorInHdArea { get; set; } + public uint MaximumReadableSectorInHdArea { get; set; } + public byte[] MaximumReadablePqInHdArea { get; set; } + public byte[] MaximumReadableRwInHdArea { get; set; } +} + +public class SupportedDensity +{ + [JsonIgnore] + public int Id { get; set; } + + [DisplayName("Primary density code")] + public byte PrimaryCode { get; set; } + + [DisplayName("Secondary density code")] + public byte SecondaryCode { get; set; } + + public bool Writable { get; set; } + public bool Duplicate { get; set; } + + [DisplayName("Default density code")] + public bool DefaultDensity { get; set; } + + [DisplayName("Bits per mm")] + public uint BitsPerMm { get; set; } + + public ushort Width { get; set; } + public ushort Tracks { get; set; } + + [DisplayName("Nominal capacity (MiB)")] + public uint Capacity { get; set; } + + public string Organization { get; set; } + public string Name { get; set; } + public string Description { get; set; } + + [JsonIgnore] + public int? SscId { get; set; } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Metadata/MediaType.cs b/Aaru.CommonTypes/Metadata/MediaType.cs new file mode 100644 index 000000000..be46c7271 --- /dev/null +++ b/Aaru.CommonTypes/Metadata/MediaType.cs @@ -0,0 +1,2568 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : MediaType.cs +// Author(s) : Natalia Portillo +// +// Component : XML metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Converts a common media type to the XML equivalent. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +#pragma warning disable 612 +namespace Aaru.CommonTypes.Metadata; + +/// Handles media type for metadata +public static class MediaType +{ + /// Converts a media type of a pair of type and subtype strings to use in metadata + /// Media type + /// Media type and subtype for metadata + public static (string type, string subType) MediaTypeToString(CommonTypes.MediaType dskType) + { + string discType; + string discSubType; + + switch(dskType) + { + case CommonTypes.MediaType.BDR: + discType = "Blu-ray"; + discSubType = "BD-R"; + + break; + case CommonTypes.MediaType.BDRE: + discType = "Blu-ray"; + discSubType = "BD-RE"; + + break; + case CommonTypes.MediaType.BDREXL: + discType = "Blu-ray"; + discSubType = "BD-RE XL"; + + break; + case CommonTypes.MediaType.BDROM: + discType = "Blu-ray"; + discSubType = "BD-ROM"; + + break; + case CommonTypes.MediaType.BDRXL: + discType = "Blu-ray"; + discSubType = "BD-R XL"; + + break; + case CommonTypes.MediaType.UHDBD: + discType = "Blu-ray"; + discSubType = "Ultra HD Blu-ray"; + + break; + case CommonTypes.MediaType.CBHD: + discType = "Blu-ray"; + discSubType = "CBHD"; + + break; + case CommonTypes.MediaType.CD: + discType = "Compact Disc"; + discSubType = "CD"; + + break; + case CommonTypes.MediaType.CDDA: + discType = "Compact Disc"; + discSubType = "CD Digital Audio"; + + break; + case CommonTypes.MediaType.CDEG: + discType = "Compact Disc"; + discSubType = "CD+EG"; + + break; + case CommonTypes.MediaType.CDG: + discType = "Compact Disc"; + discSubType = "CD+G"; + + break; + case CommonTypes.MediaType.CDI: + discType = "Compact Disc"; + discSubType = "CD-i"; + + break; + case CommonTypes.MediaType.CDIREADY: + discType = "Compact Disc"; + discSubType = "CD-i Ready"; + + break; + case CommonTypes.MediaType.CDMIDI: + discType = "Compact Disc"; + discSubType = "CD+MIDI"; + + break; + case CommonTypes.MediaType.CDMO: + discType = "Compact Disc"; + discSubType = "CD-MO"; + + break; + case CommonTypes.MediaType.CDMRW: + discType = "Compact Disc"; + discSubType = "CD-MRW"; + + break; + case CommonTypes.MediaType.CDPLUS: + discType = "Compact Disc"; + discSubType = "CD+"; + + break; + case CommonTypes.MediaType.CDR: + discType = "Compact Disc"; + discSubType = "CD-R"; + + break; + case CommonTypes.MediaType.CDROM: + discType = "Compact Disc"; + discSubType = "CD-ROM"; + + break; + case CommonTypes.MediaType.CDROMXA: + discType = "Compact Disc"; + discSubType = "CD-ROM XA"; + + break; + case CommonTypes.MediaType.CDRW: + discType = "Compact Disc"; + discSubType = "CD-RW"; + + break; + case CommonTypes.MediaType.CDV: + discType = "Compact Disc"; + discSubType = "CD-Video"; + + break; + case CommonTypes.MediaType.DDCD: + discType = "DDCD"; + discSubType = "DDCD"; + + break; + case CommonTypes.MediaType.DDCDR: + discType = "DDCD"; + discSubType = "DDCD-R"; + + break; + case CommonTypes.MediaType.DDCDRW: + discType = "DDCD"; + discSubType = "DDCD-RW"; + + break; + case CommonTypes.MediaType.DTSCD: + discType = "Compact Disc"; + discSubType = "DTS CD"; + + break; + case CommonTypes.MediaType.DVDDownload: + discType = "DVD"; + discSubType = "DVD-Download"; + + break; + case CommonTypes.MediaType.DVDPR: + discType = "DVD"; + discSubType = "DVD+R"; + + break; + case CommonTypes.MediaType.DVDPRDL: + discType = "DVD"; + discSubType = "DVD+R DL"; + + break; + case CommonTypes.MediaType.DVDPRW: + discType = "DVD"; + discSubType = "DVD+RW"; + + break; + case CommonTypes.MediaType.DVDPRWDL: + discType = "DVD"; + discSubType = "DVD+RW DL"; + + break; + case CommonTypes.MediaType.DVDR: + discType = "DVD"; + discSubType = "DVD-R"; + + break; + case CommonTypes.MediaType.DVDRAM: + discType = "DVD"; + discSubType = "DVD-RAM"; + + break; + case CommonTypes.MediaType.DVDRDL: + discType = "DVD"; + discSubType = "DVD-R DL"; + + break; + case CommonTypes.MediaType.DVDROM: + discType = "DVD"; + discSubType = "DVD-ROM"; + + break; + case CommonTypes.MediaType.DVDRW: + discType = "DVD"; + discSubType = "DVD-RW"; + + break; + case CommonTypes.MediaType.DVDRWDL: + discType = "DVD"; + discSubType = "DVD-RW DL"; + + break; + case CommonTypes.MediaType.EVD: + discType = "EVD"; + discSubType = "EVD"; + + break; + case CommonTypes.MediaType.FDDVD: + discType = "FDDVD"; + discSubType = "FDDVD"; + + break; + case CommonTypes.MediaType.FVD: + discType = "FVD"; + discSubType = "FVD"; + + break; + case CommonTypes.MediaType.GDR: + discType = "GD"; + discSubType = "GD-R"; + + break; + case CommonTypes.MediaType.GDROM: + discType = "GD"; + discSubType = "GD-ROM"; + + break; + case CommonTypes.MediaType.GOD: + discType = "DVD"; + discSubType = "GameCube Game Disc"; + + break; + case CommonTypes.MediaType.WOD: + discType = "DVD"; + discSubType = "Wii Optical Disc"; + + break; + case CommonTypes.MediaType.WUOD: + discType = "Blu-ray"; + discSubType = "Wii U Optical Disc"; + + break; + case CommonTypes.MediaType.HDDVDR: + discType = "HD DVD"; + discSubType = "HD DVD-R"; + + break; + case CommonTypes.MediaType.HDDVDRAM: + discType = "HD DVD"; + discSubType = "HD DVD-RAM"; + + break; + case CommonTypes.MediaType.HDDVDRDL: + discType = "HD DVD"; + discSubType = "HD DVD-R DL"; + + break; + case CommonTypes.MediaType.HDDVDROM: + discType = "HD DVD"; + discSubType = "HD DVD-ROM"; + + break; + case CommonTypes.MediaType.HDDVDRW: + discType = "HD DVD"; + discSubType = "HD DVD-RW"; + + break; + case CommonTypes.MediaType.HDDVDRWDL: + discType = "HD DVD"; + discSubType = "HD DVD-RW DL"; + + break; + case CommonTypes.MediaType.HDVMD: + discType = "HD VMD"; + discSubType = "HD VMD"; + + break; + case CommonTypes.MediaType.HiMD: + discType = "MiniDisc"; + discSubType = "Hi-MD"; + + break; + case CommonTypes.MediaType.HVD: + discType = "HVD"; + discSubType = "HVD"; + + break; + case CommonTypes.MediaType.LD: + discType = "LaserDisc"; + discSubType = "LaserDisc"; + + break; + case CommonTypes.MediaType.CRVdisc: + discType = "CRVdisc"; + discSubType = "CRVdisc"; + + break; + case CommonTypes.MediaType.LDROM: + discType = "LaserDisc"; + discSubType = "LD-ROM"; + + break; + case CommonTypes.MediaType.LVROM: + discType = "LaserDisc"; + discSubType = "LV-ROM"; + + break; + case CommonTypes.MediaType.MegaLD: + discType = "LaserDisc"; + discSubType = "MegaLD"; + + break; + case CommonTypes.MediaType.MD: + discType = "MiniDisc"; + discSubType = "MiniDisc"; + + break; + case CommonTypes.MediaType.MD60: + discType = "MiniDisc"; + discSubType = "MiniDisc (60 minute)"; + + break; + case CommonTypes.MediaType.MD74: + discType = "MiniDisc"; + discSubType = "MiniDisc (74 minute)"; + + break; + case CommonTypes.MediaType.MD80: + discType = "MiniDisc"; + discSubType = "MiniDisc (80 minute)"; + + break; + case CommonTypes.MediaType.MEGACD: + discType = "Compact Disc"; + discSubType = "Sega Mega CD"; + + break; + case CommonTypes.MediaType.PCD: + discType = "Compact Disc"; + discSubType = "Photo CD"; + + break; + case CommonTypes.MediaType.PlayStationMemoryCard: + discType = "PlayStation Memory Card"; + discSubType = "PlayStation Memory Card"; + + break; + case CommonTypes.MediaType.PlayStationMemoryCard2: + discType = "PlayStation Memory Card"; + discSubType = "PlayStation 2 Memory Card"; + + break; + case CommonTypes.MediaType.PS1CD: + discType = "Compact Disc"; + discSubType = "PlayStation Game Disc"; + + break; + case CommonTypes.MediaType.PS2CD: + discType = "Compact Disc"; + discSubType = "PlayStation 2 Game Disc"; + + break; + case CommonTypes.MediaType.PS2DVD: + discType = "DVD"; + discSubType = "PlayStation 2 Game Disc"; + + break; + case CommonTypes.MediaType.PS3BD: + discType = "Blu-ray"; + discSubType = "PlayStation 3 Game Disc"; + + break; + case CommonTypes.MediaType.PS3DVD: + discType = "DVD"; + discSubType = "PlayStation 3 Game Disc"; + + break; + case CommonTypes.MediaType.PS4BD: + discType = "Blu-ray"; + discSubType = "PlayStation 4 Game Disc"; + + break; + case CommonTypes.MediaType.PS5BD: + discType = "Blu-ray"; + discSubType = "PlayStation 5 Game Disc"; + + break; + case CommonTypes.MediaType.SACD: + discType = "SACD"; + discSubType = "Super Audio CD"; + + break; + case CommonTypes.MediaType.SegaCard: + discType = "Sega Card"; + discSubType = "Sega Card"; + + break; + case CommonTypes.MediaType.SATURNCD: + discType = "Compact Disc"; + discSubType = "Sega Saturn CD"; + + break; + case CommonTypes.MediaType.SVCD: + discType = "Compact Disc"; + discSubType = "Super Video CD"; + + break; + case CommonTypes.MediaType.CVD: + discType = "Compact Disc"; + discSubType = "China Video Disc"; + + break; + case CommonTypes.MediaType.SVOD: + discType = "SVOD"; + discSubType = "SVOD"; + + break; + case CommonTypes.MediaType.UDO: + discType = "UDO"; + discSubType = "UDO"; + + break; + case CommonTypes.MediaType.UMD: + discType = "UMD"; + discSubType = "Universal Media Disc"; + + break; + case CommonTypes.MediaType.VCD: + discType = "Compact Disc"; + discSubType = "Video CD"; + + break; + case CommonTypes.MediaType.Nuon: + discType = "DVD"; + discSubType = "Nuon"; + + break; + case CommonTypes.MediaType.XGD: + discType = "DVD"; + discSubType = "Xbox Game Disc (XGD)"; + + break; + case CommonTypes.MediaType.XGD2: + discType = "DVD"; + discSubType = "Xbox 360 Game Disc (XGD2)"; + + break; + case CommonTypes.MediaType.XGD3: + discType = "DVD"; + discSubType = "Xbox 360 Game Disc (XGD3)"; + + break; + case CommonTypes.MediaType.XGD4: + discType = "Blu-ray"; + discSubType = "Xbox One Game Disc (XGD4)"; + + break; + case CommonTypes.MediaType.FMTOWNS: + discType = "Compact Disc"; + discSubType = "FM-Towns"; + + break; + case CommonTypes.MediaType.Apple32SS: + discType = "5.25\" floppy"; + discSubType = "Apple DOS 3.2"; + + break; + case CommonTypes.MediaType.Apple32DS: + discType = "5.25\" floppy"; + discSubType = "Apple DOS 3.2 (double-sided)"; + + break; + case CommonTypes.MediaType.Apple33SS: + discType = "5.25\" floppy"; + discSubType = "Apple DOS 3.3"; + + break; + case CommonTypes.MediaType.Apple33DS: + discType = "5.25\" floppy"; + discSubType = "Apple DOS 3.3 (double-sided)"; + + break; + case CommonTypes.MediaType.AppleSonySS: + discType = "3.5\" floppy"; + discSubType = "Apple 400K"; + + break; + case CommonTypes.MediaType.AppleSonyDS: + discType = "3.5\" floppy"; + discSubType = "Apple 800K"; + + break; + case CommonTypes.MediaType.AppleFileWare: + discType = "5.25\" floppy"; + discSubType = "Apple FileWare"; + + break; + case CommonTypes.MediaType.RX50: + discType = "5.25\" floppy"; + discSubType = "DEC RX50"; + + break; + case CommonTypes.MediaType.DOS_525_SS_DD_8: + discType = "5.25\" floppy"; + discSubType = "IBM double-density, single-sided, 8 sectors"; + + break; + case CommonTypes.MediaType.DOS_525_SS_DD_9: + discType = "5.25\" floppy"; + discSubType = "IBM double-density, single-sided, 9 sectors"; + + break; + case CommonTypes.MediaType.DOS_525_DS_DD_8: + discType = "5.25\" floppy"; + discSubType = "IBM double-density, double-sided, 8 sectors"; + + break; + case CommonTypes.MediaType.DOS_525_DS_DD_9: + discType = "5.25\" floppy"; + discSubType = "IBM double-density, double-sided, 9 sectors"; + + break; + case CommonTypes.MediaType.DOS_525_HD: + discType = "5.25\" floppy"; + discSubType = "IBM high-density"; + + break; + case CommonTypes.MediaType.DOS_35_SS_DD_8: + discType = "3.5\" floppy"; + discSubType = "IBM double-density, single-sided, 8 sectors"; + + break; + case CommonTypes.MediaType.DOS_35_SS_DD_9: + discType = "3.5\" floppy"; + discSubType = "IBM double-density, single-sided, 9 sectors"; + + break; + case CommonTypes.MediaType.DOS_35_DS_DD_8: + discType = "3.5\" floppy"; + discSubType = "IBM double-density, double-sided, 8 sectors"; + + break; + case CommonTypes.MediaType.DOS_35_DS_DD_9: + discType = "3.5\" floppy"; + discSubType = "IBM double-density, double-sided, 9 sectors"; + + break; + case CommonTypes.MediaType.DOS_35_HD: + discType = "3.5\" floppy"; + discSubType = "IBM high-density"; + + break; + case CommonTypes.MediaType.DOS_35_ED: + discType = "3.5\" floppy"; + discSubType = "IBM extra-density"; + + break; + case CommonTypes.MediaType.Apricot_35: + discType = "3.5\" floppy"; + discSubType = "Apricot double-density, single-sided, 70 tracks"; + + break; + case CommonTypes.MediaType.DMF: + discType = "3.5\" floppy"; + discSubType = "Microsoft DMF"; + + break; + case CommonTypes.MediaType.DMF_82: + discType = "3.5\" floppy"; + discSubType = "Microsoft DMF (82-track)"; + + break; + case CommonTypes.MediaType.XDF_35: + discType = "3.5\" floppy"; + discSubType = "IBM XDF"; + + break; + case CommonTypes.MediaType.XDF_525: + discType = "5.25\" floppy"; + discSubType = "IBM XDF"; + + break; + case CommonTypes.MediaType.IBM23FD: + discType = "8\" floppy"; + discSubType = "IBM 23FD"; + + break; + case CommonTypes.MediaType.IBM33FD_128: + discType = "8\" floppy"; + discSubType = "IBM 33FD (128 bytes/sector)"; + + break; + case CommonTypes.MediaType.IBM33FD_256: + discType = "8\" floppy"; + discSubType = "IBM 33FD (256 bytes/sector)"; + + break; + case CommonTypes.MediaType.IBM33FD_512: + discType = "8\" floppy"; + discSubType = "IBM 33FD (512 bytes/sector)"; + + break; + case CommonTypes.MediaType.IBM43FD_128: + discType = "8\" floppy"; + discSubType = "IBM 43FD (128 bytes/sector)"; + + break; + case CommonTypes.MediaType.IBM43FD_256: + discType = "8\" floppy"; + discSubType = "IBM 43FD (256 bytes/sector)"; + + break; + case CommonTypes.MediaType.IBM53FD_256: + discType = "8\" floppy"; + discSubType = "IBM 53FD (256 bytes/sector)"; + + break; + case CommonTypes.MediaType.IBM53FD_512: + discType = "8\" floppy"; + discSubType = "IBM 53FD (512 bytes/sector)"; + + break; + case CommonTypes.MediaType.IBM53FD_1024: + discType = "8\" floppy"; + discSubType = "IBM 53FD (1024 bytes/sector)"; + + break; + case CommonTypes.MediaType.RX01: + discType = "8\" floppy"; + discSubType = "DEC RX-01"; + + break; + case CommonTypes.MediaType.RX02: + discType = "8\" floppy"; + discSubType = "DEC RX-02"; + + break; + case CommonTypes.MediaType.RX03: + discType = "8\" floppy"; + discSubType = "DEC RX-03"; + + break; + case CommonTypes.MediaType.ACORN_525_SS_SD_40: + discType = "5.25\" floppy"; + discSubType = "BBC Micro 100K"; + + break; + case CommonTypes.MediaType.ACORN_525_SS_SD_80: + discType = "5.25\" floppy"; + discSubType = "BBC Micro 200K"; + + break; + case CommonTypes.MediaType.ACORN_525_SS_DD_40: + discType = "5.25\" floppy"; + discSubType = "Acorn S"; + + break; + case CommonTypes.MediaType.ACORN_525_SS_DD_80: + discType = "5.25\" floppy"; + discSubType = "Acorn M"; + + break; + case CommonTypes.MediaType.ACORN_525_DS_DD: + discType = "5.25\" floppy"; + discSubType = "Acorn L"; + + break; + case CommonTypes.MediaType.ACORN_35_DS_DD: + discType = "3.5\" floppy"; + discSubType = "Acorn Archimedes"; + + break; + case CommonTypes.MediaType.ACORN_35_DS_HD: + discType = "3.5\" floppy"; + discSubType = "Acorn Archimedes high-density"; + + break; + case CommonTypes.MediaType.ATARI_525_SD: + discType = "5.25\" floppy"; + discSubType = "Atari single-density"; + + break; + case CommonTypes.MediaType.ATARI_525_ED: + discType = "5.25\" floppy"; + discSubType = "Atari enhanced-density"; + + break; + case CommonTypes.MediaType.ATARI_525_DD: + discType = "5.25\" floppy"; + discSubType = "Atari double-density"; + + break; + case CommonTypes.MediaType.ATARI_35_SS_DD: + discType = "3.5\" floppy"; + discSubType = "Atari ST double-density, single-sided, 10 sectors"; + + break; + case CommonTypes.MediaType.ATARI_35_DS_DD: + discType = "3.5\" floppy"; + discSubType = "Atari ST double-density, double-sided, 10 sectors"; + + break; + case CommonTypes.MediaType.ATARI_35_SS_DD_11: + discType = "3.5\" floppy"; + discSubType = "Atari ST double-density, single-sided, 11 sectors"; + + break; + case CommonTypes.MediaType.ATARI_35_DS_DD_11: + discType = "3.5\" floppy"; + discSubType = "Atari ST double-density, double-sided, 11 sectors"; + + break; + case CommonTypes.MediaType.CBM_1540: + case CommonTypes.MediaType.CBM_1540_Ext: + discType = "5.25\" floppy"; + discSubType = "Commodore 1540/1541"; + + break; + case CommonTypes.MediaType.CBM_1571: + discType = "5.25\" floppy"; + discSubType = "Commodore 1571"; + + break; + case CommonTypes.MediaType.CBM_35_DD: + discType = "3.5\" floppy"; + discSubType = "Commodore 1581"; + + break; + case CommonTypes.MediaType.CBM_AMIGA_35_DD: + discType = "3.5\" floppy"; + discSubType = "Amiga double-density"; + + break; + case CommonTypes.MediaType.CBM_AMIGA_35_HD: + discType = "3.5\" floppy"; + discSubType = "Amiga high-density"; + + break; + case CommonTypes.MediaType.NEC_8_SD: + discType = "8\" floppy"; + discSubType = "NEC single-sided"; + + break; + case CommonTypes.MediaType.NEC_8_DD: + discType = "8\" floppy"; + discSubType = "NEC double-sided"; + + break; + case CommonTypes.MediaType.NEC_525_SS: + discType = "5.25\" floppy"; + discSubType = "NEC single-sided"; + + break; + case CommonTypes.MediaType.NEC_525_HD: + discType = "5.25\" floppy"; + discSubType = "NEC high-density"; + + break; + case CommonTypes.MediaType.NEC_35_HD_8: + discType = "3.5\" floppy"; + discSubType = "NEC high-density"; + + break; + case CommonTypes.MediaType.NEC_35_HD_15: + discType = "3.5\" floppy"; + discSubType = "NEC high-density"; + + break; + case CommonTypes.MediaType.NEC_35_TD: + discType = "3.5\" floppy"; + discSubType = "NEC triple-density"; + + break; + case CommonTypes.MediaType.SHARP_525_9: + discType = "5.25\" floppy"; + discSubType = "Sharp (9 sectors per track)"; + + break; + case CommonTypes.MediaType.SHARP_35_9: + discType = "3.5\" floppy"; + discSubType = "Sharp (9 sectors per track)"; + + break; + case CommonTypes.MediaType.ECMA_54: + discType = "8\" floppy"; + discSubType = "ECMA-54"; + + break; + case CommonTypes.MediaType.ECMA_59: + discType = "8\" floppy"; + discSubType = "ECMA-59"; + + break; + case CommonTypes.MediaType.ECMA_69_8: + case CommonTypes.MediaType.ECMA_69_15: + case CommonTypes.MediaType.ECMA_69_26: + discType = "8\" floppy"; + discSubType = "ECMA-69"; + + break; + case CommonTypes.MediaType.ECMA_66: + discType = "5.25\" floppy"; + discSubType = "ECMA-66"; + + break; + case CommonTypes.MediaType.ECMA_70: + discType = "5.25\" floppy"; + discSubType = "ECMA-70"; + + break; + case CommonTypes.MediaType.ECMA_78: + case CommonTypes.MediaType.ECMA_78_2: + discType = "5.25\" floppy"; + discSubType = "ECMA-78"; + + break; + case CommonTypes.MediaType.ECMA_99_8: + case CommonTypes.MediaType.ECMA_99_15: + case CommonTypes.MediaType.ECMA_99_26: + discType = "5.25\" floppy"; + discSubType = "ECMA-99"; + + break; + case CommonTypes.MediaType.FDFORMAT_525_DD: + discType = "5.25\" floppy"; + discSubType = "FDFORMAT double-density"; + + break; + case CommonTypes.MediaType.FDFORMAT_525_HD: + discType = "5.25\" floppy"; + discSubType = "FDFORMAT high-density"; + + break; + case CommonTypes.MediaType.FDFORMAT_35_DD: + discType = "3.5\" floppy"; + discSubType = "FDFORMAT double-density"; + + break; + case CommonTypes.MediaType.FDFORMAT_35_HD: + discType = "3.5\" floppy"; + discSubType = "FDFORMAT high-density"; + + break; + case CommonTypes.MediaType.ECMA_260: + case CommonTypes.MediaType.ECMA_260_Double: + discType = "356mm magneto-optical"; + discSubType = "ECMA-260 / ISO 15898"; + + break; + case CommonTypes.MediaType.ECMA_183_512: + case CommonTypes.MediaType.ECMA_183: + discType = "5.25\" magneto-optical"; + discSubType = "ECMA-183"; + + break; + case CommonTypes.MediaType.ISO_10089: + case CommonTypes.MediaType.ISO_10089_512: + discType = "5.25\" magneto-optical"; + discSubType = "ISO 10089"; + + break; + case CommonTypes.MediaType.ECMA_184_512: + case CommonTypes.MediaType.ECMA_184: + discType = "5.25\" magneto-optical"; + discSubType = "ECMA-184"; + + break; + case CommonTypes.MediaType.ECMA_154: + discType = "3.5\" magneto-optical"; + discSubType = "ECMA-154"; + + break; + case CommonTypes.MediaType.ECMA_201: + case CommonTypes.MediaType.ECMA_201_ROM: + discType = "3.5\" magneto-optical"; + discSubType = "ECMA-201"; + + break; + case CommonTypes.MediaType.ISO_15041_512: + discType = "3.5\" magneto-optical"; + discSubType = "ISO 15041"; + + break; + case CommonTypes.MediaType.FlashDrive: + discType = "USB flash drive"; + discSubType = "USB flash drive"; + + break; + case CommonTypes.MediaType.SuperCDROM2: + discType = "Compact Disc"; + discSubType = "Super CD-ROM²"; + + break; + case CommonTypes.MediaType.LDROM2: + discType = "LaserDisc"; + discSubType = "LD-ROM²"; + + break; + case CommonTypes.MediaType.JaguarCD: + discType = "Compact Disc"; + discSubType = "Atari Jaguar CD"; + + break; + case CommonTypes.MediaType.MilCD: + discType = "Compact Disc"; + discSubType = "Sega MilCD"; + + break; + case CommonTypes.MediaType.ThreeDO: + discType = "Compact Disc"; + discSubType = "3DO"; + + break; + case CommonTypes.MediaType.PCFX: + discType = "Compact Disc"; + discSubType = "PC-FX"; + + break; + case CommonTypes.MediaType.NeoGeoCD: + discType = "Compact Disc"; + discSubType = "NEO-GEO CD"; + + break; + case CommonTypes.MediaType.CDTV: + discType = "Compact Disc"; + discSubType = "Commodore CDTV"; + + break; + case CommonTypes.MediaType.CD32: + discType = "Compact Disc"; + discSubType = "Amiga CD32"; + + break; + case CommonTypes.MediaType.Playdia: + discType = "Compact Disc"; + discSubType = "Bandai Playdia"; + + break; + case CommonTypes.MediaType.Pippin: + discType = "Compact Disc"; + discSubType = "Apple Pippin"; + + break; + case CommonTypes.MediaType.ZIP100: + discType = "Iomega ZIP"; + discSubType = "Iomega ZIP100"; + + break; + case CommonTypes.MediaType.ZIP250: + discType = "Iomega ZIP"; + discSubType = "Iomega ZIP250"; + + break; + case CommonTypes.MediaType.ZIP750: + discType = "Iomega ZIP"; + discSubType = "Iomega ZIP750"; + + break; + case CommonTypes.MediaType.AppleProfile: + discType = "Hard Disk Drive"; + discSubType = "Apple Profile"; + + break; + case CommonTypes.MediaType.AppleWidget: + discType = "Hard Disk Drive"; + discSubType = "Apple Widget"; + + break; + case CommonTypes.MediaType.AppleHD20: + discType = "Hard Disk Drive"; + discSubType = "Apple HD20"; + + break; + case CommonTypes.MediaType.PriamDataTower: + discType = "Hard Disk Drive"; + discSubType = "Priam DataTower"; + + break; + case CommonTypes.MediaType.DDS1: + discType = "Digital Data Storage"; + discSubType = "DDS"; + + break; + case CommonTypes.MediaType.DDS2: + discType = "Digital Data Storage"; + discSubType = "DDS-2"; + + break; + case CommonTypes.MediaType.DDS3: + discType = "Digital Data Storage"; + discSubType = "DDS-3"; + + break; + case CommonTypes.MediaType.DDS4: + discType = "Digital Data Storage"; + discSubType = "DDS-4"; + + break; + case CommonTypes.MediaType.PocketZip: + discType = "Iomega PocketZip"; + discSubType = "Iomega PocketZip"; + + break; + case CommonTypes.MediaType.CompactFloppy: + discType = "3\" floppy"; + discSubType = "Compact Floppy"; + + break; + case CommonTypes.MediaType.GENERIC_HDD: + discType = "Hard Disk Drive"; + discSubType = "Unknown"; + + break; + case CommonTypes.MediaType.MDData: + discType = "MiniDisc"; + discSubType = "MD-DATA"; + + break; + case CommonTypes.MediaType.MDData2: + discType = "MiniDisc"; + discSubType = "MD-DATA2"; + + break; + case CommonTypes.MediaType.UDO2: + discType = "UDO"; + discSubType = "UDO2"; + + break; + case CommonTypes.MediaType.UDO2_WORM: + discType = "UDO"; + discSubType = "UDO2 (WORM)"; + + break; + case CommonTypes.MediaType.ADR30: + discType = "Advanced Digital Recording"; + discSubType = "ADR 30"; + + break; + case CommonTypes.MediaType.ADR50: + discType = "Advanced Digital Recording"; + discSubType = "ADR 50"; + + break; + case CommonTypes.MediaType.ADR260: + discType = "Advanced Digital Recording"; + discSubType = "ADR 2.60"; + + break; + case CommonTypes.MediaType.ADR2120: + discType = "Advanced Digital Recording"; + discSubType = "ADR 2.120"; + + break; + case CommonTypes.MediaType.AIT1: + discType = "Advanced Intelligent Tape"; + discSubType = "AIT-1"; + + break; + case CommonTypes.MediaType.AIT1Turbo: + discType = "Advanced Intelligent Tape"; + discSubType = "AIT-1 Turbo"; + + break; + case CommonTypes.MediaType.AIT2: + discType = "Advanced Intelligent Tape"; + discSubType = "AIT-2"; + + break; + case CommonTypes.MediaType.AIT2Turbo: + discType = "Advanced Intelligent Tape"; + discSubType = "AIT-2 Turbo"; + + break; + case CommonTypes.MediaType.AIT3: + discType = "Advanced Intelligent Tape"; + discSubType = "AIT-3"; + + break; + case CommonTypes.MediaType.AIT3Ex: + discType = "Advanced Intelligent Tape"; + discSubType = "AIT-3Ex"; + + break; + case CommonTypes.MediaType.AIT3Turbo: + discType = "Advanced Intelligent Tape"; + discSubType = "AIT-3 Turbo"; + + break; + case CommonTypes.MediaType.AIT4: + discType = "Advanced Intelligent Tape"; + discSubType = "AIT-4"; + + break; + case CommonTypes.MediaType.AIT5: + discType = "Advanced Intelligent Tape"; + discSubType = "AIT-5"; + + break; + case CommonTypes.MediaType.AITETurbo: + discType = "Advanced Intelligent Tape"; + discSubType = "AIT-E Turbo"; + + break; + case CommonTypes.MediaType.SAIT1: + discType = "Super Advanced Intelligent Tape"; + discSubType = "SAIT-1"; + + break; + case CommonTypes.MediaType.SAIT2: + discType = "Super Advanced Intelligent Tape"; + discSubType = "SAIT-2"; + + break; + case CommonTypes.MediaType.Bernoulli: + case CommonTypes.MediaType.Bernoulli10: + discType = "Iomega Bernoulli Box"; + discSubType = "Iomega Bernoulli Box 10Mb"; + + break; + case CommonTypes.MediaType.Bernoulli20: + discType = "Iomega Bernoulli Box"; + discSubType = "Iomega Bernoulli Box 20Mb"; + + break; + case CommonTypes.MediaType.BernoulliBox2_20: + case CommonTypes.MediaType.Bernoulli2: + discType = "Iomega Bernoulli Box II"; + discSubType = "Iomega Bernoulli Box II 20Mb"; + + break; + case CommonTypes.MediaType.Bernoulli35: + discType = "Iomega Bernoulli Box II"; + discSubType = "Iomega Bernoulli Box II 35Mb"; + + break; + case CommonTypes.MediaType.Bernoulli44: + discType = "Iomega Bernoulli Box II"; + discSubType = "Iomega Bernoulli Box II 44Mb"; + + break; + case CommonTypes.MediaType.Bernoulli65: + discType = "Iomega Bernoulli Box II"; + discSubType = "Iomega Bernoulli Box II 65Mb"; + + break; + case CommonTypes.MediaType.Bernoulli90: + discType = "Iomega Bernoulli Box II"; + discSubType = "Iomega Bernoulli Box II 90Mb"; + + break; + case CommonTypes.MediaType.Bernoulli105: + discType = "Iomega Bernoulli Box II"; + discSubType = "Iomega Bernoulli Box II 105Mb"; + + break; + case CommonTypes.MediaType.Bernoulli150: + discType = "Iomega Bernoulli Box II"; + discSubType = "Iomega Bernoulli Box II 150Mb"; + + break; + case CommonTypes.MediaType.Bernoulli230: + discType = "Iomega Bernoulli Box II"; + discSubType = "Iomega Bernoulli Box II 230Mb"; + + break; + case CommonTypes.MediaType.Ditto: + discType = "Iomega Ditto"; + discSubType = "Iomega Ditto"; + + break; + case CommonTypes.MediaType.DittoMax: + discType = "Iomega Ditto"; + discSubType = "Iomega Ditto Max"; + + break; + case CommonTypes.MediaType.Jaz: + discType = "Iomega Jaz"; + discSubType = "Iomega Jaz 1GB"; + + break; + case CommonTypes.MediaType.Jaz2: + discType = "Iomega Jaz"; + discSubType = "Iomega Jaz 2GB"; + + break; + case CommonTypes.MediaType.REV35: + discType = "Iomega REV"; + discSubType = "Iomega REV-35"; + + break; + case CommonTypes.MediaType.REV70: + discType = "Iomega REV"; + discSubType = "Iomega REV-70"; + + break; + case CommonTypes.MediaType.REV120: + discType = "Iomega REV"; + discSubType = "Iomega REV-120"; + + break; + case CommonTypes.MediaType.CompactFlash: + discType = "Compact Flash"; + discSubType = "Compact Flash"; + + break; + case CommonTypes.MediaType.CompactFlashType2: + discType = "Compact Flash"; + discSubType = "Compact Flash Type 2"; + + break; + case CommonTypes.MediaType.CFast: + discType = "Compact Flash"; + discSubType = "CFast"; + + break; + case CommonTypes.MediaType.DigitalAudioTape: + discType = "Digital Audio Tape"; + discSubType = "Digital Audio Tape"; + + break; + case CommonTypes.MediaType.DAT72: + discType = "Digital Data Storage"; + discSubType = "DAT-72"; + + break; + case CommonTypes.MediaType.DAT160: + discType = "Digital Data Storage"; + discSubType = "DAT-160"; + + break; + case CommonTypes.MediaType.DAT320: + discType = "Digital Data Storage"; + discSubType = "DAT-320"; + + break; + case CommonTypes.MediaType.DECtapeII: + discType = "DECtape"; + discSubType = "DECtape II"; + + break; + case CommonTypes.MediaType.CompactTapeI: + discType = "CompacTape"; + discSubType = "CompacTape"; + + break; + case CommonTypes.MediaType.CompactTapeII: + discType = "CompacTape"; + discSubType = "CompacTape II"; + + break; + case CommonTypes.MediaType.DLTtapeIII: + discType = "Digital Linear Tape"; + discSubType = "DLTtape III"; + + break; + case CommonTypes.MediaType.DLTtapeIIIxt: + discType = "Digital Linear Tape"; + discSubType = "DLTtape IIIXT"; + + break; + case CommonTypes.MediaType.DLTtapeIV: + discType = "Digital Linear Tape"; + discSubType = "DLTtape IV"; + + break; + case CommonTypes.MediaType.DLTtapeS4: + discType = "Digital Linear Tape"; + discSubType = "DLTtape S4"; + + break; + case CommonTypes.MediaType.SDLT1: + discType = "Super Digital Linear Tape"; + discSubType = "SDLTtape I"; + + break; + case CommonTypes.MediaType.SDLT2: + discType = "Super Digital Linear Tape"; + discSubType = "SDLTtape II"; + + break; + case CommonTypes.MediaType.VStapeI: + discType = "Digital Linear Tape"; + discSubType = "DLTtape VS1"; + + break; + case CommonTypes.MediaType.Data8: + discType = "Data8"; + discSubType = "Data8"; + + break; + case CommonTypes.MediaType.MiniDV: + discType = "DV tape"; + discSubType = "MiniDV"; + + break; + case CommonTypes.MediaType.Exatape15m: + discType = "Exatape"; + discSubType = "Exatape (15m)"; + + break; + case CommonTypes.MediaType.Exatape22m: + discType = "Exatape"; + discSubType = "Exatape (22m)"; + + break; + case CommonTypes.MediaType.Exatape22mAME: + discType = "Exatape"; + discSubType = "Exatape (22m AME)"; + + break; + case CommonTypes.MediaType.Exatape28m: + discType = "Exatape"; + discSubType = "Exatape (28m)"; + + break; + case CommonTypes.MediaType.Exatape40m: + discType = "Exatape"; + discSubType = "Exatape (40m)"; + + break; + case CommonTypes.MediaType.Exatape45m: + discType = "Exatape"; + discSubType = "Exatape (45m)"; + + break; + case CommonTypes.MediaType.Exatape54m: + discType = "Exatape"; + discSubType = "Exatape (54m)"; + + break; + case CommonTypes.MediaType.Exatape75m: + discType = "Exatape"; + discSubType = "Exatape (75m)"; + + break; + case CommonTypes.MediaType.Exatape76m: + discType = "Exatape"; + discSubType = "Exatape (76m)"; + + break; + case CommonTypes.MediaType.Exatape80m: + discType = "Exatape"; + discSubType = "Exatape (80m)"; + + break; + case CommonTypes.MediaType.Exatape106m: + discType = "Exatape"; + discSubType = "Exatape (106m)"; + + break; + case CommonTypes.MediaType.Exatape112m: + discType = "Exatape"; + discSubType = "Exatape (112m)"; + + break; + case CommonTypes.MediaType.Exatape125m: + discType = "Exatape"; + discSubType = "Exatape (125m)"; + + break; + case CommonTypes.MediaType.Exatape150m: + discType = "Exatape"; + discSubType = "Exatape (150m)"; + + break; + case CommonTypes.MediaType.Exatape160mXL: + discType = "Exatape"; + discSubType = "Exatape XL (160m)"; + + break; + case CommonTypes.MediaType.Exatape170m: + discType = "Exatape"; + discSubType = "Exatape (170m)"; + + break; + case CommonTypes.MediaType.Exatape225m: + discType = "Exatape"; + discSubType = "Exatape (225m)"; + + break; + case CommonTypes.MediaType.EZ135: + discType = "3.5\" SyQuest cartridge"; + discSubType = "EZ135"; + + break; + case CommonTypes.MediaType.EZ230: + discType = "3.5\" SyQuest cartridge"; + discSubType = "EZ230"; + + break; + case CommonTypes.MediaType.Quest: + discType = "3.5\" SyQuest cartridge"; + discSubType = "Quest"; + + break; + case CommonTypes.MediaType.SparQ: + discType = "3.5\" SyQuest cartridge"; + discSubType = "SparQ"; + + break; + case CommonTypes.MediaType.SQ100: + discType = "3.9\" SyQuest cartridge"; + discSubType = "SQ100"; + + break; + case CommonTypes.MediaType.SQ200: + discType = "3.9\" SyQuest cartridge"; + discSubType = "SQ200"; + + break; + case CommonTypes.MediaType.SQ300: + discType = "3.9\" SyQuest cartridge"; + discSubType = "SQ300"; + + break; + case CommonTypes.MediaType.SQ310: + discType = "3.5\" SyQuest cartridge"; + discSubType = "SQ310"; + + break; + case CommonTypes.MediaType.SQ327: + discType = "3.5\" SyQuest cartridge"; + discSubType = "SQ327"; + + break; + case CommonTypes.MediaType.SQ400: + discType = "5.25\" SyQuest cartridge"; + discSubType = "SQ400"; + + break; + case CommonTypes.MediaType.SQ800: + discType = "5.25\" SyQuest cartridge"; + discSubType = "SQ800"; + + break; + case CommonTypes.MediaType.SQ1500: + discType = "3.5\" SyQuest cartridge"; + discSubType = "SQ1500"; + + break; + case CommonTypes.MediaType.SQ2000: + discType = "5.25\" SyQuest cartridge"; + discSubType = "SQ2000"; + + break; + case CommonTypes.MediaType.SyJet: + discType = "3.5\" SyQuest cartridge"; + discSubType = "SyJet"; + + break; + case CommonTypes.MediaType.LTO: + discType = "Linear Tape-Open"; + discSubType = "LTO"; + + break; + case CommonTypes.MediaType.LTO2: + discType = "Linear Tape-Open"; + discSubType = "LTO-2"; + + break; + case CommonTypes.MediaType.LTO3: + discType = "Linear Tape-Open"; + discSubType = "LTO-3"; + + break; + case CommonTypes.MediaType.LTO3WORM: + discType = "Linear Tape-Open"; + discSubType = "LTO-3 (WORM)"; + + break; + case CommonTypes.MediaType.LTO4: + discType = "Linear Tape-Open"; + discSubType = "LTO-4"; + + break; + case CommonTypes.MediaType.LTO4WORM: + discType = "Linear Tape-Open"; + discSubType = "LTO-4 (WORM)"; + + break; + case CommonTypes.MediaType.LTO5: + discType = "Linear Tape-Open"; + discSubType = "LTO-5"; + + break; + case CommonTypes.MediaType.LTO5WORM: + discType = "Linear Tape-Open"; + discSubType = "LTO-5 (WORM)"; + + break; + case CommonTypes.MediaType.LTO6: + discType = "Linear Tape-Open"; + discSubType = "LTO-6"; + + break; + case CommonTypes.MediaType.LTO6WORM: + discType = "Linear Tape-Open"; + discSubType = "LTO-6 (WORM)"; + + break; + case CommonTypes.MediaType.LTO7: + discType = "Linear Tape-Open"; + discSubType = "LTO-7"; + + break; + case CommonTypes.MediaType.LTO7WORM: + discType = "Linear Tape-Open"; + discSubType = "LTO-7 (WORM)"; + + break; + case CommonTypes.MediaType.MemoryStick: + discType = "Memory Stick"; + discSubType = "Memory Stick"; + + break; + case CommonTypes.MediaType.MemoryStickDuo: + discType = "Memory Stick"; + discSubType = "Memory Stick Duo"; + + break; + case CommonTypes.MediaType.MemoryStickMicro: + discType = "Memory Stick"; + discSubType = "Memory Stick Micro"; + + break; + case CommonTypes.MediaType.MemoryStickPro: + discType = "Memory Stick"; + discSubType = "Memory Stick Pro"; + + break; + case CommonTypes.MediaType.MemoryStickProDuo: + discType = "Memory Stick"; + discSubType = "Memory Stick PRO Duo"; + + break; + case CommonTypes.MediaType.SecureDigital: + discType = "Secure Digital"; + discSubType = "Secure Digital"; + + break; + case CommonTypes.MediaType.miniSD: + discType = "Secure Digital"; + discSubType = "miniSD"; + + break; + case CommonTypes.MediaType.microSD: + discType = "Secure Digital"; + discSubType = "microSD"; + + break; + case CommonTypes.MediaType.MMC: + discType = "MultiMediaCard"; + discSubType = "MultiMediaCard"; + + break; + case CommonTypes.MediaType.MMCmicro: + discType = "MultiMediaCard"; + discSubType = "MMCmicro"; + + break; + case CommonTypes.MediaType.RSMMC: + discType = "MultiMediaCard"; + discSubType = "Reduced-Size MultiMediaCard"; + + break; + case CommonTypes.MediaType.MMCplus: + discType = "MultiMediaCard"; + discSubType = "MMCplus"; + + break; + case CommonTypes.MediaType.MMCmobile: + discType = "MultiMediaCard"; + discSubType = "MMCmobile"; + + break; + case CommonTypes.MediaType.MLR1: + discType = "Scalable Linear Recording"; + discSubType = "MLR1"; + + break; + case CommonTypes.MediaType.MLR1SL: + discType = "Scalable Linear Recording"; + discSubType = "MLR1 SL"; + + break; + case CommonTypes.MediaType.MLR3: + discType = "Scalable Linear Recording"; + discSubType = "MLR3"; + + break; + case CommonTypes.MediaType.SLR1: + discType = "Scalable Linear Recording"; + discSubType = "SLR1"; + + break; + case CommonTypes.MediaType.SLR2: + discType = "Scalable Linear Recording"; + discSubType = "SLR2"; + + break; + case CommonTypes.MediaType.SLR3: + discType = "Scalable Linear Recording"; + discSubType = "SLR3"; + + break; + case CommonTypes.MediaType.SLR32: + discType = "Scalable Linear Recording"; + discSubType = "SLR32"; + + break; + case CommonTypes.MediaType.SLR32SL: + discType = "Scalable Linear Recording"; + discSubType = "SLR32 SL"; + + break; + case CommonTypes.MediaType.SLR4: + discType = "Scalable Linear Recording"; + discSubType = "SLR4"; + + break; + case CommonTypes.MediaType.SLR5: + discType = "Scalable Linear Recording"; + discSubType = "SLR5"; + + break; + case CommonTypes.MediaType.SLR5SL: + discType = "Scalable Linear Recording"; + discSubType = "SLR5 SL"; + + break; + case CommonTypes.MediaType.SLR6: + discType = "Scalable Linear Recording"; + discSubType = "SLR6"; + + break; + case CommonTypes.MediaType.SLRtape7: + discType = "Scalable Linear Recording"; + discSubType = "SLRtape7"; + + break; + case CommonTypes.MediaType.SLRtape7SL: + discType = "Scalable Linear Recording"; + discSubType = "SLRtape7 SL"; + + break; + case CommonTypes.MediaType.SLRtape24: + discType = "Scalable Linear Recording"; + discSubType = "SLRtape24"; + + break; + case CommonTypes.MediaType.SLRtape24SL: + discType = "Scalable Linear Recording"; + discSubType = "SLRtape24 SL"; + + break; + case CommonTypes.MediaType.SLRtape40: + discType = "Scalable Linear Recording"; + discSubType = "SLRtape40"; + + break; + case CommonTypes.MediaType.SLRtape50: + discType = "Scalable Linear Recording"; + discSubType = "SLRtape50"; + + break; + case CommonTypes.MediaType.SLRtape60: + discType = "Scalable Linear Recording"; + discSubType = "SLRtape60"; + + break; + case CommonTypes.MediaType.SLRtape75: + discType = "Scalable Linear Recording"; + discSubType = "SLRtape75"; + + break; + case CommonTypes.MediaType.SLRtape100: + discType = "Scalable Linear Recording"; + discSubType = "SLRtape100"; + + break; + case CommonTypes.MediaType.SLRtape140: + discType = "Scalable Linear Recording"; + discSubType = "SLRtape140"; + + break; + case CommonTypes.MediaType.QIC11: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-11"; + + break; + case CommonTypes.MediaType.QIC24: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-24"; + + break; + case CommonTypes.MediaType.QIC40: + discType = "Quarter-inch mini cartridge"; + discSubType = "QIC-40"; + + break; + case CommonTypes.MediaType.QIC80: + discType = "Quarter-inch mini cartridge"; + discSubType = "QIC-80"; + + break; + case CommonTypes.MediaType.QIC120: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-120"; + + break; + case CommonTypes.MediaType.QIC150: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-150"; + + break; + case CommonTypes.MediaType.QIC320: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-320"; + + break; + case CommonTypes.MediaType.QIC525: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-525"; + + break; + case CommonTypes.MediaType.QIC1350: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-1350"; + + break; + case CommonTypes.MediaType.QIC3010: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-3010"; + + break; + case CommonTypes.MediaType.QIC3020: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-3020"; + + break; + case CommonTypes.MediaType.QIC3080: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-3080"; + + break; + case CommonTypes.MediaType.QIC3095: + discType = "Quarter-inch cartridge"; + discSubType = "QIC-3095"; + + break; + case CommonTypes.MediaType.Travan: + discType = "Travan"; + discSubType = "TR-1"; + + break; + case CommonTypes.MediaType.Travan1Ex: + discType = "Travan"; + discSubType = "TR-1 Ex"; + + break; + case CommonTypes.MediaType.Travan3: + discType = "Travan"; + discSubType = "TR-3"; + + break; + case CommonTypes.MediaType.Travan3Ex: + discType = "Travan"; + discSubType = "TR-3 Ex"; + + break; + case CommonTypes.MediaType.Travan4: + discType = "Travan"; + discSubType = "TR-4"; + + break; + case CommonTypes.MediaType.Travan5: + discType = "Travan"; + discSubType = "TR-5"; + + break; + case CommonTypes.MediaType.Travan7: + discType = "Travan"; + discSubType = "TR-7"; + + break; + case CommonTypes.MediaType.VXA1: + discType = "VXA"; + discSubType = "VXA-1"; + + break; + case CommonTypes.MediaType.VXA2: + discType = "VXA"; + discSubType = "VXA-2"; + + break; + case CommonTypes.MediaType.VXA3: + discType = "VXA"; + discSubType = "VXA-3"; + + break; + case CommonTypes.MediaType.ECMA_153: + case CommonTypes.MediaType.ECMA_153_512: + discType = "5.25\" magneto-optical"; + discSubType = "ECMA-153"; + + break; + case CommonTypes.MediaType.ECMA_189: + discType = "300mm magneto optical"; + discSubType = "ECMA-189"; + + break; + case CommonTypes.MediaType.ECMA_190: + discType = "300mm magneto optical"; + discSubType = "ECMA-190"; + + break; + case CommonTypes.MediaType.ECMA_195: + case CommonTypes.MediaType.ECMA_195_512: + discType = "5.25\" magneto-optical"; + discSubType = "ECMA-195"; + + break; + case CommonTypes.MediaType.ECMA_223: + case CommonTypes.MediaType.ECMA_223_512: + discType = "3.5\" magneto-optical"; + discSubType = "ECMA-223"; + + break; + case CommonTypes.MediaType.ECMA_238: + discType = "5.25\" magneto-optical"; + discSubType = "ECMA-238"; + + break; + case CommonTypes.MediaType.ECMA_239: + discType = "3.5\" magneto-optical"; + discSubType = "ECMA-239"; + + break; + case CommonTypes.MediaType.ECMA_280: + discType = "5.25\" magneto-optical"; + discSubType = "ECMA-280"; + + break; + case CommonTypes.MediaType.ECMA_317: + discType = "300mm magneto optical"; + discSubType = "ECMA-317"; + + break; + case CommonTypes.MediaType.ECMA_322: + case CommonTypes.MediaType.ECMA_322_512: + case CommonTypes.MediaType.ECMA_322_1k: + case CommonTypes.MediaType.ECMA_322_2k: + discType = "5.25\" magneto-optical"; + discSubType = "ECMA-322 / ISO 22092"; + + break; + case CommonTypes.MediaType.ISO_15286: + case CommonTypes.MediaType.ISO_15286_1024: + case CommonTypes.MediaType.ISO_15286_512: + discType = "5.25\" magneto-optical"; + discSubType = "ISO-15286"; + + break; + case CommonTypes.MediaType.ISO_14517: + case CommonTypes.MediaType.ISO_14517_512: + discType = "5.25\" magneto-optical"; + discSubType = "ISO-14517"; + + break; + case CommonTypes.MediaType.GigaMo: + discType = "3.5\" magneto-optical"; + discSubType = "GIGAMO"; + + break; + case CommonTypes.MediaType.GigaMo2: + discType = "3.5\" magneto-optical"; + discSubType = "2.3GB GIGAMO"; + + break; + case CommonTypes.MediaType.UnknownMO: + discType = "Magneto-optical"; + discSubType = "Unknown"; + + break; + case CommonTypes.MediaType.Floptical: + discType = "Floptical"; + discSubType = "Floptical"; + + break; + case CommonTypes.MediaType.HiFD: + discType = "HiFD"; + discSubType = "HiFD"; + + break; + case CommonTypes.MediaType.LS120: + discType = "SuperDisk"; + discSubType = "LS-120"; + + break; + case CommonTypes.MediaType.LS240: + discType = "SuperDisk"; + discSubType = "LS-240"; + + break; + case CommonTypes.MediaType.FD32MB: + discType = "3.5\" floppy"; + discSubType = "FD32MB"; + + break; + case CommonTypes.MediaType.UHD144: + discType = "UHD144"; + discSubType = "UHD144"; + + break; + case CommonTypes.MediaType.VCDHD: + discType = "VCDHD"; + discSubType = "VCDHD"; + + break; + case CommonTypes.MediaType.HuCard: + discType = "HuCard"; + discSubType = "HuCard"; + + break; + case CommonTypes.MediaType.CompactCassette: + discType = "Compact Cassette"; + discSubType = "Compact Cassette"; + + break; + case CommonTypes.MediaType.Dcas25: + discType = "Compact Cassette"; + discSubType = "D/CAS-25"; + + break; + case CommonTypes.MediaType.Dcas85: + discType = "Compact Cassette"; + discSubType = "D/CAS-85"; + + break; + case CommonTypes.MediaType.Dcas103: + discType = "Compact Cassette"; + discSubType = "D/CAS-103"; + + break; + case CommonTypes.MediaType.PCCardTypeI: + discType = "PCMCIA Card"; + discSubType = "PC-Card Type I"; + + break; + case CommonTypes.MediaType.PCCardTypeII: + discType = "PCMCIA Card"; + discSubType = "PC-Card Type II"; + + break; + case CommonTypes.MediaType.PCCardTypeIII: + discType = "PCMCIA Card"; + discSubType = "PC-Card Type III"; + + break; + case CommonTypes.MediaType.PCCardTypeIV: + discType = "PCMCIA Card"; + discSubType = "PC-Card Type IV"; + + break; + case CommonTypes.MediaType.ExpressCard34: + discType = "Express Card"; + discSubType = "Express Card (34mm)"; + + break; + case CommonTypes.MediaType.ExpressCard54: + discType = "Express Card"; + discSubType = "Express Card (54mm)"; + + break; + case CommonTypes.MediaType.FamicomGamePak: + discType = "Nintendo Famicom Game Pak"; + discSubType = "Nintendo Famicom Game Pak"; + + break; + case CommonTypes.MediaType.GameBoyAdvanceGamePak: + discType = "Nintendo Game Boy Advance Game Pak"; + discSubType = "Nintendo Game Boy Advance Game Pak"; + + break; + case CommonTypes.MediaType.GameBoyGamePak: + discType = "Nintendo Game Boy Game Pak"; + discSubType = "Nintendo Game Boy Game Pak"; + + break; + case CommonTypes.MediaType.N64DD: + discType = "Nintendo 64 Disk"; + discSubType = "Nintendo 64 Disk"; + + break; + case CommonTypes.MediaType.N64GamePak: + discType = "Nintendo 64 Game Pak"; + discSubType = "Nintendo 64 Game Pak"; + + break; + case CommonTypes.MediaType.NESGamePak: + discType = "Nintendo Entertainment System Game Pak"; + discSubType = "Nintendo Entertainment System Game Pak"; + + break; + case CommonTypes.MediaType.Nintendo3DSGameCard: + discType = "Nintendo 3DS Game Card"; + discSubType = "Nintendo 3DS Game Card"; + + break; + case CommonTypes.MediaType.NintendoDiskCard: + discType = "Nintendo Disk Card"; + discSubType = "Nintendo Disk Card"; + + break; + case CommonTypes.MediaType.NintendoDSGameCard: + discType = "Nintendo DS Game Card"; + discSubType = "Nintendo DS Game Card"; + + break; + case CommonTypes.MediaType.NintendoDSiGameCard: + discType = "Nintendo DSi Game Card"; + discSubType = "Nintendo DSi Game Card"; + + break; + case CommonTypes.MediaType.SNESGamePak: + discType = "Super Nintendo Game Pak"; + discSubType = "Super Nintendo Game Pak"; + + break; + case CommonTypes.MediaType.SNESGamePakUS: + discType = "Super Nintendo Game Pak (US)"; + discSubType = "Super Nintendo Game Pak (US)"; + + break; + case CommonTypes.MediaType.SwitchGameCard: + discType = "Nintendo Switch Game Card"; + discSubType = "Nintendo Switch Game Card"; + + break; + case CommonTypes.MediaType.IBM3470: + discType = "IBM 3470"; + discSubType = "IBM 3470"; + + break; + case CommonTypes.MediaType.IBM3480: + discType = "IBM 3480"; + discSubType = "IBM 3480"; + + break; + case CommonTypes.MediaType.IBM3490: + discType = "IBM 3490"; + discSubType = "IBM 3490"; + + break; + case CommonTypes.MediaType.IBM3490E: + discType = "IBM 3490E"; + discSubType = "IBM 3490E"; + + break; + case CommonTypes.MediaType.IBM3592: + discType = "IBM 3592"; + discSubType = "IBM 3592"; + + break; + case CommonTypes.MediaType.STK4480: + discType = "STK 4480"; + discSubType = "STK 4480"; + + break; + case CommonTypes.MediaType.STK4490: + discType = "STK 4490"; + discSubType = "STK 4490"; + + break; + case CommonTypes.MediaType.STK9490: + discType = "STK 9490"; + discSubType = "STK 9490"; + + break; + case CommonTypes.MediaType.T9840A: + discType = "STK T-9840"; + discSubType = "STK T-9840A"; + + break; + case CommonTypes.MediaType.T9840B: + discType = "STK T-9840"; + discSubType = "STK T-9840B"; + + break; + case CommonTypes.MediaType.T9840C: + discType = "STK T-9840"; + discSubType = "STK T-9840C"; + + break; + case CommonTypes.MediaType.T9840D: + discType = "STK T-9840"; + discSubType = "STK T-9840D"; + + break; + case CommonTypes.MediaType.T9940A: + discType = "STK T-9940"; + discSubType = "STK T-9940A"; + + break; + case CommonTypes.MediaType.T9940B: + discType = "STK T-9840"; + discSubType = "STK T-9840B"; + + break; + case CommonTypes.MediaType.T10000A: + discType = "STK T-10000"; + discSubType = "STK T-10000A"; + + break; + case CommonTypes.MediaType.T10000B: + discType = "STK T-10000"; + discSubType = "STK T-10000B"; + + break; + case CommonTypes.MediaType.T10000C: + discType = "STK T-10000"; + discSubType = "STK T-10000C"; + + break; + case CommonTypes.MediaType.T10000D: + discType = "STK T-10000"; + discSubType = "STK T-10000D"; + + break; + case CommonTypes.MediaType.DemiDiskette: + discType = "DemiDiskette"; + discSubType = "DemiDiskette"; + + break; + case CommonTypes.MediaType.QuickDisk: + discType = "QuickDisk"; + discSubType = "QuickDisk"; + + break; + case CommonTypes.MediaType.VideoFloppy: + discType = "VideoFloppy"; + discSubType = "VideoFloppy"; + + break; + case CommonTypes.MediaType.Wafer: + discType = "Wafer"; + discSubType = "Wafer"; + + break; + case CommonTypes.MediaType.ZXMicrodrive: + discType = "ZX Microdrive"; + discSubType = "ZX Microdrive"; + + break; + case CommonTypes.MediaType.BeeCard: + discType = "BeeCard"; + discSubType = "BeeCard"; + + break; + case CommonTypes.MediaType.Borsu: + discType = "Borsu"; + discSubType = "Borsu"; + + break; + case CommonTypes.MediaType.DataStore: + discType = "DataStore"; + discSubType = "DataStore"; + + break; + case CommonTypes.MediaType.DIR: + discType = "DIR"; + discSubType = "DIR"; + + break; + case CommonTypes.MediaType.DST: + discType = "DST"; + discSubType = "DST"; + + break; + case CommonTypes.MediaType.DTF: + discType = "DTF"; + discSubType = "DTF"; + + break; + case CommonTypes.MediaType.DTF2: + discType = "DTF2"; + discSubType = "DTF2"; + + break; + case CommonTypes.MediaType.Flextra3020: + discType = "Flextra"; + discSubType = "Flextra 3020"; + + break; + case CommonTypes.MediaType.Flextra3225: + discType = "Flextra"; + discSubType = "Flextra 3225"; + + break; + case CommonTypes.MediaType.HiTC1: + discType = "HiTC"; + discSubType = "HiTC1"; + + break; + case CommonTypes.MediaType.HiTC2: + discType = "HiTC"; + discSubType = "HiTC2"; + + break; + case CommonTypes.MediaType.LT1: + discType = "LT1"; + discSubType = "LT1"; + + break; + case CommonTypes.MediaType.MiniCard: + discType = "MiniCard"; + discSubType = "MiniCard"; + + break; + case CommonTypes.MediaType.Orb: + discType = "Orb"; + discSubType = "Orb"; + + break; + case CommonTypes.MediaType.Orb5: + discType = "Orb"; + discSubType = "Orb5"; + + break; + case CommonTypes.MediaType.SmartMedia: + discType = "SmartMedia"; + discSubType = "SmartMedia"; + + break; + case CommonTypes.MediaType.xD: + discType = "xD"; + discSubType = "xD"; + + break; + case CommonTypes.MediaType.XQD: + discType = "XQD"; + discSubType = "XQD"; + + break; + case CommonTypes.MediaType.DataPlay: + discType = "DataPlay"; + discSubType = "DataPlay"; + + break; + case CommonTypes.MediaType.PD650: + discType = "PD650"; + discSubType = "PD650"; + + break; + case CommonTypes.MediaType.PD650_WORM: + discType = "PD650"; + discSubType = "PD650 (WORM)"; + + break; + case CommonTypes.MediaType.RA60: + discType = "Hard Disk Drive"; + discSubType = "DEC RA-60"; + + break; + case CommonTypes.MediaType.RA80: + discType = "Hard Disk Drive"; + discSubType = "DEC RA-80"; + + break; + case CommonTypes.MediaType.RA81: + discType = "Hard Disk Drive"; + discSubType = "DEC RA-81"; + + break; + case CommonTypes.MediaType.RC25: + discType = "Hard Disk Drive"; + discSubType = "DEC RC-25"; + + break; + case CommonTypes.MediaType.RD31: + discType = "Hard Disk Drive"; + discSubType = "DEC RD-31"; + + break; + case CommonTypes.MediaType.RD32: + discType = "Hard Disk Drive"; + discSubType = "DEC RD-32"; + + break; + case CommonTypes.MediaType.RD51: + discType = "Hard Disk Drive"; + discSubType = "DEC RD-51"; + + break; + case CommonTypes.MediaType.RD52: + discType = "Hard Disk Drive"; + discSubType = "DEC RD-52"; + + break; + case CommonTypes.MediaType.RD53: + discType = "Hard Disk Drive"; + discSubType = "DEC RD-53"; + + break; + case CommonTypes.MediaType.RD54: + discType = "Hard Disk Drive"; + discSubType = "DEC RD-54"; + + break; + case CommonTypes.MediaType.RK06: + case CommonTypes.MediaType.RK06_18: + discType = "Hard Disk Drive"; + discSubType = "DEC RK-06"; + + break; + case CommonTypes.MediaType.RK07: + case CommonTypes.MediaType.RK07_18: + discType = "Hard Disk Drive"; + discSubType = "DEC RK-07"; + + break; + case CommonTypes.MediaType.RM02: + discType = "Hard Disk Drive"; + discSubType = "DEC RM-02"; + + break; + case CommonTypes.MediaType.RM03: + discType = "Hard Disk Drive"; + discSubType = "DEC RM-03"; + + break; + case CommonTypes.MediaType.RM05: + discType = "Hard Disk Drive"; + discSubType = "DEC RM-05"; + + break; + case CommonTypes.MediaType.RP02: + case CommonTypes.MediaType.RP02_18: + discType = "Hard Disk Drive"; + discSubType = "DEC RP-02"; + + break; + case CommonTypes.MediaType.RP03: + case CommonTypes.MediaType.RP03_18: + discType = "Hard Disk Drive"; + discSubType = "DEC RP-03"; + + break; + case CommonTypes.MediaType.RP04: + case CommonTypes.MediaType.RP04_18: + discType = "Hard Disk Drive"; + discSubType = "DEC RP-04"; + + break; + case CommonTypes.MediaType.RP05: + case CommonTypes.MediaType.RP05_18: + discType = "Hard Disk Drive"; + discSubType = "DEC RP-05"; + + break; + case CommonTypes.MediaType.RP06: + case CommonTypes.MediaType.RP06_18: + discType = "Hard Disk Drive"; + discSubType = "DEC RP-06"; + + break; + case CommonTypes.MediaType.RDX: + discType = "RDX"; + discSubType = "RDX"; + + break; + case CommonTypes.MediaType.RDX320: + discType = "RDX"; + discSubType = "RDX 320"; + + break; + case CommonTypes.MediaType.Zone_HDD: + discType = "Zoned Hard Disk Drive"; + discSubType = "Unknown"; + + break; + case CommonTypes.MediaType.Microdrive: + discType = "Hard Disk Drive"; + discSubType = "Microdrive"; + + break; + case CommonTypes.MediaType.VideoNow: + discType = "VideoNow"; + discSubType = "VideoNow"; + + break; + case CommonTypes.MediaType.VideoNowColor: + discType = "VideoNow"; + discSubType = "VideoNow Color"; + + break; + case CommonTypes.MediaType.VideoNowXp: + discType = "VideoNow"; + discSubType = "VideoNow XP"; + + break; + case CommonTypes.MediaType.KodakVerbatim3: + discType = "Kodak Verbatim"; + discSubType = "Kodak Verbatim (3 Mb)"; + + break; + case CommonTypes.MediaType.KodakVerbatim6: + discType = "Kodak Verbatim"; + discSubType = "Kodak Verbatim (6 Mb)"; + + break; + case CommonTypes.MediaType.KodakVerbatim12: + discType = "Kodak Verbatim"; + discSubType = "Kodak Verbatim (12 Mb)"; + + break; + case CommonTypes.MediaType.ProfessionalDisc: + discType = "Sony Professional Disc"; + discSubType = "Sony Professional Disc (single layer)"; + + break; + case CommonTypes.MediaType.ProfessionalDiscDual: + discType = "Sony Professional Disc"; + discSubType = "Sony Professional Disc (double layer)"; + + break; + case CommonTypes.MediaType.ProfessionalDiscTriple: + discType = "Sony Professional Disc"; + discSubType = "Sony Professional Disc (triple layer)"; + + break; + case CommonTypes.MediaType.ProfessionalDiscQuad: + discType = "Sony Professional Disc"; + discSubType = "Sony Professional Disc (quad layer)"; + + break; + case CommonTypes.MediaType.PDD: + discType = "Sony Professional Disc for DATA"; + discSubType = "Sony Professional Disc for DATA"; + + break; + case CommonTypes.MediaType.PDD_WORM: + discType = "Sony Professional Disc for DATA"; + discSubType = "Sony Professional Disc for DATA (write-once)"; + + break; + case CommonTypes.MediaType.ArchivalDisc: + discType = "Archival Disc"; + discSubType = "Archival Disc"; + + break; + case CommonTypes.MediaType.ArchivalDisc2: + discType = "Archival Disc"; + discSubType = "Archival Disc (2nd generation)"; + + break; + case CommonTypes.MediaType.ArchivalDisc3: + discType = "Archival Disc"; + discSubType = "Archival Disc (3rd generation)"; + + break; + case CommonTypes.MediaType.ODC300R: + discType = "Optical Disc Archive"; + discSubType = "ODC300R"; + + break; + case CommonTypes.MediaType.ODC300RE: + discType = "Optical Disc Archive"; + discSubType = "ODC300RE"; + + break; + case CommonTypes.MediaType.ODC600R: + discType = "Optical Disc Archive"; + discSubType = "ODC600R"; + + break; + case CommonTypes.MediaType.ODC600RE: + discType = "Optical Disc Archive"; + discSubType = "ODC600RE"; + + break; + case CommonTypes.MediaType.ODC1200RE: + discType = "Optical Disc Archive"; + discSubType = "ODC1200RE"; + + break; + case CommonTypes.MediaType.ODC1500R: + discType = "Optical Disc Archive"; + discSubType = "ODC1500R"; + + break; + case CommonTypes.MediaType.ODC3300R: + discType = "Optical Disc Archive"; + discSubType = "ODC3300R"; + + break; + case CommonTypes.MediaType.ODC5500R: + discType = "Optical Disc Archive"; + discSubType = "ODC5500R"; + + break; + case CommonTypes.MediaType.MetaFloppy_Mod_I: + discType = "5.25\" floppy"; + discSubType = "Micropolis MetaFloppy Mod I"; + + break; + case CommonTypes.MediaType.MetaFloppy_Mod_II: + discType = "5.25\" floppy"; + discSubType = "Micropolis MetaFloppy Mod II"; + + break; + case CommonTypes.MediaType.HF12: + discType = "HyperFlex"; + discSubType = "HyperFlex (12Mb)"; + + break; + case CommonTypes.MediaType.HF24: + discType = "HyperFlex"; + discSubType = "HyperFlex (24Mb)"; + + break; + default: + discType = "Unknown"; + discSubType = "Unknown"; + + break; + } + + return (discType, discSubType); + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Metadata/Resume.cs b/Aaru.CommonTypes/Metadata/Resume.cs new file mode 100644 index 000000000..82ec7b472 --- /dev/null +++ b/Aaru.CommonTypes/Metadata/Resume.cs @@ -0,0 +1,95 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Resume.cs +// Author(s) : Natalia Portillo +// +// Component : XML metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines XML format of a dump resume file. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; +using System.Xml.Serialization; +using Aaru.CommonTypes.AaruMetadata; + +namespace Aaru.CommonTypes.Metadata; + +[JsonSourceGenerationOptions(WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + IncludeFields = true)] +[JsonSerializable(typeof(ResumeJson))] + +// ReSharper disable once PartialTypeWithSinglePart +public partial class ResumeJsonContext : JsonSerializerContext; + +public class ResumeJson +{ + [JsonPropertyName("AaruResume")] + public Resume Resume { get; set; } +} + +/// Information that allows to resume a dump +[Serializable] +[XmlRoot("DicResume", Namespace = "", IsNullable = false)] +public class Resume +{ + /// List of blocks that returned an error on reading + [XmlArrayItem("Block")] + public List BadBlocks; + /// List of CD subchannels that did not read correctly + [XmlArrayItem("Block")] + public List BadSubchannels; + /// Extents of BLANK sectors for magneto-opticals + [XmlArrayItem("Extent")] + public Extent[] BlankExtents; + /// Date/time this resume file was created + [XmlElement(DataType = "dateTime")] + public DateTime CreationDate; + /// Last block on media + public ulong LastBlock; + /// Date/time this resume file was last written to + [XmlElement(DataType = "dateTime")] + public DateTime LastWriteDate; + /// Title keys that has not been read + [XmlArrayItem("Block")] + public List MissingTitleKeys; + /// Next block to read + public ulong NextBlock; + /// Is media removable? + public bool Removable; + /// Is media a tape? + public bool Tape; + /// List of dump tries + [XmlArrayItem("DumpTry")] + public List Tries; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Metadata/Statistics.cs b/Aaru.CommonTypes/Metadata/Statistics.cs new file mode 100644 index 000000000..012e0d5a4 --- /dev/null +++ b/Aaru.CommonTypes/Metadata/Statistics.cs @@ -0,0 +1,347 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Statistics.cs +// Author(s) : Natalia Portillo +// +// Component : XML metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Define XML for statistics. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable UnusedMember.Global + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using System.Xml.Serialization; + +namespace Aaru.CommonTypes.Metadata; + +/// Statistics +[XmlRoot("DicStats", Namespace = "", IsNullable = false)] +public class Stats +{ + /// Executed commands + public CommandsStats Commands; + + /// Operating systems Aaru has run from + [XmlArrayItem("OperatingSystem")] + public List OperatingSystems { get; set; } + + /// Aaru versions + [XmlArrayItem("Version")] + public List Versions { get; set; } + + /// Detected filesystems + [XmlArrayItem("Filesystem")] + public List Filesystems { get; set; } + + /// Detected partitioning schemes + [XmlArrayItem("Scheme")] + public List Partitions { get; set; } + + /// Media image formats + [XmlArrayItem("Format")] + public List MediaImages { get; set; } + + /// Used filters + [XmlArrayItem("Filter", IsNullable = true)] + public List Filters { get; set; } + + /// Found devices + [XmlArrayItem("Device", IsNullable = true)] + public List Devices { get; set; } + + /// Found media types, real, and in image + [XmlArrayItem("Media")] + public List Medias { get; set; } + + /// Benchmark statistics + public BenchmarkStats Benchmark { get; set; } + + /// Media scanning statistics + public MediaScanStats MediaScan { get; set; } + + /// Image verification statistics + public VerifyStats Verify { get; set; } +} + +[JsonSourceGenerationOptions(WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + IncludeFields = true)] +[JsonSerializable(typeof(StatsDto))] + +// ReSharper disable once PartialTypeWithSinglePart +public partial class StatsDtoContext : JsonSerializerContext; + +/// DTO for statistics +[SuppressMessage("ReSharper", "CollectionNeverQueried.Global")] +public class StatsDto +{ + /// Executed commands + public List Commands { get; set; } + + /// Operating systems Aaru has run from + public List OperatingSystems { get; set; } + + /// Aaru versions + public List Versions { get; set; } + + /// Detected filesystems + public List Filesystems { get; set; } + + /// Detected partitioning schemes + public List Partitions { get; set; } + + /// Media image formats + public List MediaFormats { get; set; } + + /// Used filters + public List Filters { get; set; } + + /// Found devices + public List Devices { get; set; } + + /// Found media types, real, and in image + public List Medias { get; set; } + + /// Remote applications + public List RemoteApplications { get; set; } + + /// Remote application architectures + public List RemoteArchitectures { get; set; } + + /// Operating systems where a remote application has been running + public List RemoteOperatingSystems { get; set; } +} + +/// Command execution statistics +[SuppressMessage("ReSharper", "UnassignedField.Global")] +public class CommandsStats +{ + /// Number of times the filesystem info command has been used + public long Analyze; + /// Number of times the benchmark command has been used + public long Benchmark; + /// Number of times the image checksum command has been used + public long Checksum; + /// Number of times the image compare command has been used + public long Compare; + /// Number of times the image convert command has been used + public long ConvertImage; + /// Number of times the image create-sidecar command has been used + public long CreateSidecar; + /// Number of times the image decode command has been used + public long Decode; + /// Number of times the device info command has been used + public long DeviceInfo; + /// Number of times the device report command has been used + public long DeviceReport; + /// Number of times the media dump command has been used + public long DumpMedia; + /// Number of times the image entropy command has been used + public long Entropy; + /// Number of times the filesystem extract command has been used + public long ExtractFiles; + /// Number of times the list formats command has been used + public long Formats; + /// Number of times the image info command has been used + public long ImageInfo; + /// Number of times the device list command has been used + public long ListDevices; + /// Number of times the list encodings command has been used + public long ListEncodings; + /// Number of times the filesystem ls command has been used + public long Ls; + /// Number of times the media info command has been used + public long MediaInfo; + /// Number of times the media scan command has been used + public long MediaScan; + /// Number of times the image printhex command has been used + public long PrintHex; + /// Number of times the image verify command has been used + public long Verify; +} + +/// Statistics of verified media +public class VerifiedItems +{ + /// Number of correct images + public long Correct; + /// Number of failed images + public long Failed; +} + +/// Verification statistics +public class VerifyStats +{ + /// Image verification statistics + public VerifiedItems MediaImages; + /// Image contents verification statistics + public ScannedSectors Sectors; +} + +/// Image contents verification statistics +public class ScannedSectors +{ + /// Sectors found to be correct + public long Correct; + /// Sectors found to be incorrect + public long Error; + /// Total number of verified sectors + public long Total; + /// Total number of sectors that could not be verified + public long Unverifiable; +} + +/// Media scanning time statistics +[SuppressMessage("ReSharper", "InconsistentNaming")] +public class TimeStats +{ + /// Number of sectors that took more than 3ms but less than 100ms to read + public long LessThan10ms; + /// Number of sectors that took more than 50ms but less than 150ms to read + public long LessThan150ms; + /// Number of sectors that took less than 3ms to read + public long LessThan3ms; + /// Number of sectors that took more than 150ms but less than 500ms to read + public long LessThan500ms; + /// Number of sectors that took more than 10ms but less than 50ms to read + public long LessThan50ms; + /// Number of sectors that took more than 500ms to read + public long MoreThan500ms; +} + +/// Media scanning statistics +public class MediaScanStats +{ + /// Statistics of scanned sectors + public ScannedSectors Sectors; + /// Scan time statistics + public TimeStats Times; +} + +/// Checksum type statistics +[SuppressMessage("ReSharper", "InconsistentNaming")] +public class ChecksumStats +{ + /// Checksum algorithm + [XmlAttribute] + public string algorithm; + /// Time taken to execute algorithm + [XmlText] + public double Value; +} + +/// Benchmark statistics +public class BenchmarkStats +{ + /// Total time taken to run the checksum algorithms in parallel + public double All; + /// List of time taken by each checksum algorithm + [XmlElement("Checksum")] + public List Checksum; + /// Time taken to benchmark entropy calculation + public double Entropy; + /// Maximum amount of memory used while running the benchmark + public long MaxMemory; + /// Minimum amount of memory used while running the benchmark + public long MinMemory; + /// Total time taken to run the checksum algorithms sequentially + public double Sequential; +} + +/// Media statistics +[SuppressMessage("ReSharper", "InconsistentNaming")] +public class MediaStats +{ + /// Media type + [XmlAttribute(AttributeName = "type")] + [JsonPropertyName("type")] + public string MediaType; + /// Found in a real device? + [XmlAttribute] + public bool real; + /// Number of times it has been found + [XmlText] + public long Value; +} + +/// Device statistics +public class DeviceStats +{ + /// Is manufacturer null? + [XmlIgnore] + public bool ManufacturerSpecified; + + /// Manufacturer string + public string Manufacturer { get; set; } + + /// Model string + public string Model { get; set; } + + /// Revision or firmware version + public string Revision { get; set; } + + /// Bus the device was attached to + public string Bus { get; set; } +} + +/// Name=value pair statistics +[SuppressMessage("ReSharper", "InconsistentNaming")] +public class NameValueStats +{ + /// Name + [XmlAttribute] + public string name { get; set; } + + /// Number of times it has been used/found + [XmlText] + public long Value { get; set; } +} + +/// Operating system statistics +[SuppressMessage("ReSharper", "InconsistentNaming")] +public class OsStats +{ + /// Operating system name + [XmlAttribute] + public string name { get; set; } + + /// Operating system version + [XmlAttribute] + public string version { get; set; } + + /// Number of times Aaru run on it + [XmlText] + public long Value { get; set; } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Metadata/Version.cs b/Aaru.CommonTypes/Metadata/Version.cs new file mode 100644 index 000000000..75be3ca44 --- /dev/null +++ b/Aaru.CommonTypes/Metadata/Version.cs @@ -0,0 +1,55 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Statistics.cs +// Author(s) : Natalia Portillo +// +// Component : XML metadata. +// +// --[ Description ] ---------------------------------------------------------- +// +// Returns Aaru version in XML software type format. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Interop; + +namespace Aaru.CommonTypes.Metadata; + +/// Manages Aaru's version for metadata +public static class Version +{ + /// Gets XML software type for the running version + /// XML software type + public static Software GetSoftware() => new() + { + Name = "Aaru", + OperatingSystem = DetectOS.GetRealPlatformID().ToString(), + Version = typeof(Version).Assembly.GetName().Version?.ToString() + }; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Metadata/cicm.cs b/Aaru.CommonTypes/Metadata/cicm.cs new file mode 100644 index 000000000..18063588b --- /dev/null +++ b/Aaru.CommonTypes/Metadata/cicm.cs @@ -0,0 +1,7390 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +// +//This source code was auto-generated by MonoXSD +// + +using System; +using System.CodeDom.Compiler; +using System.ComponentModel; +using System.Diagnostics; +using System.Xml.Serialization; + +namespace Schemas; + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code"), + XmlRoot("CICMMetadata", Namespace = "", IsNullable = false), Obsolete("Will be removed in Aaru 7")] +public class CICMMetadataType +{ + string[] developerField; + + string[] publisherField; + + string[] authorField; + + string[] performerField; + + string nameField; + + string versionField; + + CICMMetadataTypeReleaseType releaseTypeField; + + bool releaseTypeFieldSpecified; + + DateTime releaseDateField; + + bool releaseDateFieldSpecified; + + BarcodeType[] barcodesField; + + string partNumberField; + + string serialNumberField; + + string[] keywordsField; + + MagazineType[] magazineField; + + BookType[] bookField; + + string[] categoriesField; + + string[] subcategoriesField; + + LanguagesTypeLanguage[] languagesField; + + string[] systemsField; + + ArchitecturesTypeArchitecture[] architecturesField; + + RequiredOperatingSystemType[] requiredOperatingSystemsField; + + UserManualType[] userManualField; + + OpticalDiscType[] opticalDiscField; + + AdvertisementType[] advertisementField; + + LinearMediaType[] linearMediaField; + + PCIType[] pCICardField; + + BlockMediaType[] blockMediaField; + + AudioMediaType[] audioMediaField; + + /// + [XmlElement("Developer")] + public string[] Developer + { + get => developerField; + set => developerField = value; + } + + /// + [XmlElement("Publisher")] + public string[] Publisher + { + get => publisherField; + set => publisherField = value; + } + + /// + [XmlElement("Author")] + public string[] Author + { + get => authorField; + set => authorField = value; + } + + /// + [XmlElement("Performer")] + public string[] Performer + { + get => performerField; + set => performerField = value; + } + + /// + public string Name + { + get => nameField; + set => nameField = value; + } + + /// + public string Version + { + get => versionField; + set => versionField = value; + } + + /// + public CICMMetadataTypeReleaseType ReleaseType + { + get => releaseTypeField; + set => releaseTypeField = value; + } + + /// + [XmlIgnore] + public bool ReleaseTypeSpecified + { + get => releaseTypeFieldSpecified; + set => releaseTypeFieldSpecified = value; + } + + /// + [XmlElement(DataType = "date")] + public DateTime ReleaseDate + { + get => releaseDateField; + set => releaseDateField = value; + } + + /// + [XmlIgnore] + public bool ReleaseDateSpecified + { + get => releaseDateFieldSpecified; + set => releaseDateFieldSpecified = value; + } + + /// + [XmlArrayItem("Barcode", IsNullable = false)] + public BarcodeType[] Barcodes + { + get => barcodesField; + set => barcodesField = value; + } + + /// + public string PartNumber + { + get => partNumberField; + set => partNumberField = value; + } + + /// + public string SerialNumber + { + get => serialNumberField; + set => serialNumberField = value; + } + + /// + [XmlArrayItem("Keyword", IsNullable = false)] + public string[] Keywords + { + get => keywordsField; + set => keywordsField = value; + } + + /// + [XmlElement("Magazine")] + public MagazineType[] Magazine + { + get => magazineField; + set => magazineField = value; + } + + /// + [XmlElement("Book")] + public BookType[] Book + { + get => bookField; + set => bookField = value; + } + + /// + [XmlArrayItem("Category", IsNullable = false)] + public string[] Categories + { + get => categoriesField; + set => categoriesField = value; + } + + /// + [XmlArrayItem("Subcategory", IsNullable = false)] + public string[] Subcategories + { + get => subcategoriesField; + set => subcategoriesField = value; + } + + /// + [XmlArrayItem("Language", IsNullable = false)] + public LanguagesTypeLanguage[] Languages + { + get => languagesField; + set => languagesField = value; + } + + /// + [XmlArrayItem("System", IsNullable = false)] + public string[] Systems + { + get => systemsField; + set => systemsField = value; + } + + /// + [XmlArrayItem("Architecture", IsNullable = false)] + public ArchitecturesTypeArchitecture[] Architectures + { + get => architecturesField; + set => architecturesField = value; + } + + /// + [XmlArrayItem("RequiredOperatingSystem", IsNullable = false)] + public RequiredOperatingSystemType[] RequiredOperatingSystems + { + get => requiredOperatingSystemsField; + set => requiredOperatingSystemsField = value; + } + + /// + [XmlElement("UserManual")] + public UserManualType[] UserManual + { + get => userManualField; + set => userManualField = value; + } + + /// + [XmlElement("OpticalDisc")] + public OpticalDiscType[] OpticalDisc + { + get => opticalDiscField; + set => opticalDiscField = value; + } + + /// + [XmlElement("Advertisement")] + public AdvertisementType[] Advertisement + { + get => advertisementField; + set => advertisementField = value; + } + + /// + [XmlElement("LinearMedia")] + public LinearMediaType[] LinearMedia + { + get => linearMediaField; + set => linearMediaField = value; + } + + /// + [XmlElement("PCICard")] + public PCIType[] PCICard + { + get => pCICardField; + set => pCICardField = value; + } + + /// + [XmlElement("BlockMedia")] + public BlockMediaType[] BlockMedia + { + get => blockMediaField; + set => blockMediaField = value; + } + + /// + [XmlElement("AudioMedia")] + public AudioMediaType[] AudioMedia + { + get => audioMediaField; + set => audioMediaField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum CICMMetadataTypeReleaseType +{ + /// + Retail, + + /// + Bundle, + + /// + Coverdisc, + + /// + Subscription, + + /// + Demo, + + /// + OEM, + + /// + Shareware, + + /// + FOSS, + + /// + Adware, + + /// + Donationware, + + /// + [XmlEnum("Digital download")] + Digitaldownload, + + /// + SaaS +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class BarcodeType +{ + BarcodeTypeType typeField; + + string valueField; + + /// + [XmlAttribute] + public BarcodeTypeType type + { + get => typeField; + set => typeField = value; + } + + /// + [XmlText] + public string Value + { + get => valueField; + set => valueField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum BarcodeTypeType +{ + /// + aztec, + + /// + codabar, + + /// + code11, + + /// + code128, + + /// + code39, + + /// + code93, + + /// + cpcbinary, + + /// + ezcode, + + /// + fim, + + /// + itf, + + /// + itf14, + + /// + ean13, + + /// + ean8, + + /// + maxicode, + + /// + isbn, + + /// + isrc, + + /// + msi, + + /// + tof, + + /// + shotcode, + + /// + rm4scc, + + /// + qr, + + /// + ean5, + + /// + ean2, + + /// + [XmlEnum("qr")] + qr1, + + /// + postnet, + + /// + postbar, + + /// + plessey, + + /// + pharmacode, + + /// + pdf417, + + /// + patchcode +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class AudioBlockType +{ + ImageType imageField; + + ulong sizeField; + + string accoustIDField; + + ChecksumType[] checksumsField; + + string formatField; + + /// + public ImageType Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + public string AccoustID + { + get => accoustIDField; + set => accoustIDField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + public string Format + { + get => formatField; + set => formatField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class ImageType +{ + string formatField; + + ulong offsetField; + + bool offsetFieldSpecified; + + string valueField; + + /// + [XmlAttribute] + public string format + { + get => formatField; + set => formatField = value; + } + + /// + [XmlAttribute] + public ulong offset + { + get => offsetField; + set => offsetField = value; + } + + /// + [XmlIgnore] + public bool offsetSpecified + { + get => offsetFieldSpecified; + set => offsetFieldSpecified = value; + } + + /// + [XmlText] + public string Value + { + get => valueField; + set => valueField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class ChecksumType +{ + ChecksumTypeType typeField; + + string valueField; + + /// + [XmlAttribute] + public ChecksumTypeType type + { + get => typeField; + set => typeField = value; + } + + /// + [XmlText] + public string Value + { + get => valueField; + set => valueField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum ChecksumTypeType +{ + /// + fletcher16, + + /// + fletcher32, + + /// + adler32, + + /// + crc16, + + /// + crc16ccitt, + + /// + crc32, + + /// + crc64, + + /// + md4, + + /// + md5, + + /// + dm6, + + /// + ripemd128, + + /// + ripemd160, + + /// + ripemed320, + + /// + sha1, + + /// + sha224, + + /// + sha256, + + /// + sha384, + + /// + sha512, + + /// + sha3, + + /// + skein, + + /// + snefru, + + /// + blake256, + + /// + blake512, + + /// + tiger, + + /// + whirlpool, + + /// + spamsum +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class AudioMediaType +{ + ImageType imageField; + + ulong sizeField; + + ChecksumType[] checksumsField; + + SequenceType sequenceField; + + string partNumberField; + + string serialNumberField; + + string manufacturerField; + + string modelField; + + string accoustIDField; + + AudioBlockType[] blockField; + + string copyProtectionField; + + DimensionsType dimensionsField; + + ScansType scansField; + + DumpHardwareType[] dumpHardwareArrayField; + + /// + public ImageType Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + public SequenceType Sequence + { + get => sequenceField; + set => sequenceField = value; + } + + /// + public string PartNumber + { + get => partNumberField; + set => partNumberField = value; + } + + /// + public string SerialNumber + { + get => serialNumberField; + set => serialNumberField = value; + } + + /// + public string Manufacturer + { + get => manufacturerField; + set => manufacturerField = value; + } + + /// + public string Model + { + get => modelField; + set => modelField = value; + } + + /// + public string AccoustID + { + get => accoustIDField; + set => accoustIDField = value; + } + + /// + [XmlElement("Block")] + public AudioBlockType[] Block + { + get => blockField; + set => blockField = value; + } + + /// + public string CopyProtection + { + get => copyProtectionField; + set => copyProtectionField = value; + } + + /// + public DimensionsType Dimensions + { + get => dimensionsField; + set => dimensionsField = value; + } + + /// + public ScansType Scans + { + get => scansField; + set => scansField = value; + } + + /// + [XmlArrayItem("DumpHardware", IsNullable = false)] + public DumpHardwareType[] DumpHardwareArray + { + get => dumpHardwareArrayField; + set => dumpHardwareArrayField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class SequenceType +{ + string mediaTitleField; + + uint mediaSequenceField; + + uint totalMediaField; + + byte sideField; + + bool sideFieldSpecified; + + byte layerField; + + bool layerFieldSpecified; + + /// + public string MediaTitle + { + get => mediaTitleField; + set => mediaTitleField = value; + } + + /// + public uint MediaSequence + { + get => mediaSequenceField; + set => mediaSequenceField = value; + } + + /// + public uint TotalMedia + { + get => totalMediaField; + set => totalMediaField = value; + } + + /// + public byte Side + { + get => sideField; + set => sideField = value; + } + + /// + [XmlIgnore] + public bool SideSpecified + { + get => sideFieldSpecified; + set => sideFieldSpecified = value; + } + + /// + public byte Layer + { + get => layerField; + set => layerField = value; + } + + /// + [XmlIgnore] + public bool LayerSpecified + { + get => layerFieldSpecified; + set => layerFieldSpecified = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class DimensionsType +{ + double diameterField; + + bool diameterFieldSpecified; + + double heightField; + + bool heightFieldSpecified; + + double widthField; + + bool widthFieldSpecified; + + double thicknessField; + + /// + public double Diameter + { + get => diameterField; + set => diameterField = value; + } + + /// + [XmlIgnore] + public bool DiameterSpecified + { + get => diameterFieldSpecified; + set => diameterFieldSpecified = value; + } + + /// + public double Height + { + get => heightField; + set => heightField = value; + } + + /// + [XmlIgnore] + public bool HeightSpecified + { + get => heightFieldSpecified; + set => heightFieldSpecified = value; + } + + /// + public double Width + { + get => widthField; + set => widthField = value; + } + + /// + [XmlIgnore] + public bool WidthSpecified + { + get => widthFieldSpecified; + set => widthFieldSpecified = value; + } + + /// + public double Thickness + { + get => thicknessField; + set => thicknessField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class ScansType +{ + CaseScanType caseScanField; + + MediaScanType scanField; + + /// + public CaseScanType CaseScan + { + get => caseScanField; + set => caseScanField = value; + } + + /// + public MediaScanType Scan + { + get => scanField; + set => scanField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class CaseScanType +{ + CaseScanTypeCaseScanElement caseScanElementField; + + ScanType scanField; + + /// + public CaseScanTypeCaseScanElement CaseScanElement + { + get => caseScanElementField; + set => caseScanElementField = value; + } + + /// + public ScanType Scan + { + get => scanField; + set => scanField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum CaseScanTypeCaseScanElement +{ + /// + sleeve, + + /// + inner, + + /// + inlay, + + /// + frontback, + + /// + frontfull, + + /// + boxfront, + + /// + boxback, + + /// + boxspine, + + /// + external +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class ScanType +{ + FileType fileField; + + ChecksumType[] checksumsField; + + ScannerType[] scannerField; + + ScanProcessingType[] scanProcessingField; + + OCRType[] oCRField; + + /// + public FileType File + { + get => fileField; + set => fileField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + [XmlElement("Scanner")] + public ScannerType[] Scanner + { + get => scannerField; + set => scannerField = value; + } + + /// + [XmlElement("ScanProcessing")] + public ScanProcessingType[] ScanProcessing + { + get => scanProcessingField; + set => scanProcessingField = value; + } + + /// + [XmlElement("OCR")] + public OCRType[] OCR + { + get => oCRField; + set => oCRField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class FileType +{ + string formatField; + + string valueField; + + /// + [XmlAttribute] + public string format + { + get => formatField; + set => formatField = value; + } + + /// + [XmlText] + public string Value + { + get => valueField; + set => valueField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class ScannerType +{ + string authorField; + + string manufacturerField; + + string modelField; + + string serialField; + + string softwareField; + + string softwareVersionField; + + /// + public string Author + { + get => authorField; + set => authorField = value; + } + + /// + public string Manufacturer + { + get => manufacturerField; + set => manufacturerField = value; + } + + /// + public string Model + { + get => modelField; + set => modelField = value; + } + + /// + public string Serial + { + get => serialField; + set => serialField = value; + } + + /// + public string Software + { + get => softwareField; + set => softwareField = value; + } + + /// + public string SoftwareVersion + { + get => softwareVersionField; + set => softwareVersionField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class ScanProcessingType +{ + string authorField; + + string softwareField; + + string softwareVersionField; + + /// + public string Author + { + get => authorField; + set => authorField = value; + } + + /// + public string Software + { + get => softwareField; + set => softwareField = value; + } + + /// + public string SoftwareVersion + { + get => softwareVersionField; + set => softwareVersionField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class OCRType +{ + string authorField; + + string softwareField; + + string softwareVersionField; + + LanguagesTypeLanguage[] languageField; + + /// + public string Author + { + get => authorField; + set => authorField = value; + } + + /// + public string Software + { + get => softwareField; + set => softwareField = value; + } + + /// + public string SoftwareVersion + { + get => softwareVersionField; + set => softwareVersionField = value; + } + + /// + [XmlArrayItem("Language", IsNullable = false)] + public LanguagesTypeLanguage[] Language + { + get => languageField; + set => languageField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum LanguagesTypeLanguage +{ + /// + aar, + + /// + abk, + + /// + ace, + + /// + ach, + + /// + ada, + + /// + ady, + + /// + afa, + + /// + afh, + + /// + afr, + + /// + ain, + + /// + aka, + + /// + akk, + + /// + alb, + + /// + ale, + + /// + alg, + + /// + alt, + + /// + amh, + + /// + ang, + + /// + anp, + + /// + apa, + + /// + ara, + + /// + arc, + + /// + arg, + + /// + arm, + + /// + arn, + + /// + arp, + + /// + art, + + /// + arw, + + /// + asm, + + /// + ast, + + /// + ath, + + /// + aus, + + /// + ava, + + /// + ave, + + /// + awa, + + /// + aym, + + /// + aze, + + /// + bad, + + /// + bai, + + /// + bak, + + /// + bal, + + /// + bam, + + /// + ban, + + /// + baq, + + /// + bas, + + /// + bat, + + /// + bej, + + /// + bel, + + /// + bem, + + /// + ben, + + /// + ber, + + /// + bho, + + /// + bih, + + /// + bik, + + /// + bin, + + /// + bis, + + /// + bla, + + /// + bnt, + + /// + bos, + + /// + bra, + + /// + bre, + + /// + btk, + + /// + bua, + + /// + bug, + + /// + bul, + + /// + bur, + + /// + byn, + + /// + cad, + + /// + cai, + + /// + car, + + /// + cat, + + /// + cau, + + /// + ceb, + + /// + cel, + + /// + cha, + + /// + chb, + + /// + che, + + /// + chg, + + /// + chi, + + /// + chk, + + /// + chm, + + /// + chn, + + /// + cho, + + /// + chp, + + /// + chr, + + /// + chu, + + /// + chv, + + /// + chy, + + /// + cmc, + + /// + cop, + + /// + cor, + + /// + cos, + + /// + cpe, + + /// + cpf, + + /// + cpp, + + /// + cre, + + /// + crh, + + /// + crp, + + /// + csb, + + /// + cus, + + /// + cze, + + /// + dak, + + /// + dan, + + /// + dar, + + /// + day, + + /// + del, + + /// + den, + + /// + dgr, + + /// + din, + + /// + div, + + /// + doi, + + /// + dra, + + /// + dsb, + + /// + dua, + + /// + dum, + + /// + dut, + + /// + dyu, + + /// + dzo, + + /// + efi, + + /// + egy, + + /// + eka, + + /// + elx, + + /// + eng, + + /// + enm, + + /// + epo, + + /// + est, + + /// + ewe, + + /// + ewo, + + /// + fan, + + /// + fao, + + /// + fat, + + /// + fij, + + /// + fil, + + /// + fin, + + /// + fiu, + + /// + fon, + + /// + fre, + + /// + frm, + + /// + fro, + + /// + frr, + + /// + frs, + + /// + fry, + + /// + ful, + + /// + fur, + + /// + gaa, + + /// + gay, + + /// + gba, + + /// + gem, + + /// + geo, + + /// + ger, + + /// + gez, + + /// + gil, + + /// + gla, + + /// + gle, + + /// + glg, + + /// + glv, + + /// + gmh, + + /// + goh, + + /// + gon, + + /// + gor, + + /// + got, + + /// + grb, + + /// + grc, + + /// + gre, + + /// + grn, + + /// + gsw, + + /// + guj, + + /// + gwi, + + /// + hai, + + /// + hat, + + /// + hau, + + /// + haw, + + /// + heb, + + /// + her, + + /// + hil, + + /// + him, + + /// + hin, + + /// + hit, + + /// + hmn, + + /// + hmo, + + /// + hrv, + + /// + hsb, + + /// + hun, + + /// + hup, + + /// + iba, + + /// + ibo, + + /// + ice, + + /// + ido, + + /// + iii, + + /// + ijo, + + /// + iku, + + /// + ile, + + /// + ilo, + + /// + ina, + + /// + inc, + + /// + ind, + + /// + ine, + + /// + inh, + + /// + ipk, + + /// + ira, + + /// + iro, + + /// + ita, + + /// + jav, + + /// + jbo, + + /// + jpn, + + /// + jpr, + + /// + jrb, + + /// + kaa, + + /// + kab, + + /// + kac, + + /// + kal, + + /// + kam, + + /// + kan, + + /// + kar, + + /// + kas, + + /// + kau, + + /// + kaw, + + /// + kaz, + + /// + kbd, + + /// + kha, + + /// + khi, + + /// + khm, + + /// + kho, + + /// + kik, + + /// + kin, + + /// + kir, + + /// + kmb, + + /// + kok, + + /// + kom, + + /// + kon, + + /// + kor, + + /// + kos, + + /// + kpe, + + /// + krc, + + /// + krl, + + /// + kro, + + /// + kru, + + /// + kua, + + /// + kum, + + /// + kur, + + /// + kut, + + /// + lad, + + /// + lah, + + /// + lam, + + /// + lao, + + /// + lat, + + /// + lav, + + /// + lez, + + /// + lim, + + /// + lin, + + /// + lit, + + /// + lol, + + /// + loz, + + /// + ltz, + + /// + lua, + + /// + lub, + + /// + lug, + + /// + lui, + + /// + lun, + + /// + luo, + + /// + lus, + + /// + mac, + + /// + mad, + + /// + mag, + + /// + mah, + + /// + mai, + + /// + mak, + + /// + mal, + + /// + man, + + /// + mao, + + /// + map, + + /// + mar, + + /// + mas, + + /// + may, + + /// + mdf, + + /// + mdr, + + /// + men, + + /// + mga, + + /// + mic, + + /// + min, + + /// + mis, + + /// + mkh, + + /// + mlg, + + /// + mlt, + + /// + mnc, + + /// + mni, + + /// + mno, + + /// + moh, + + /// + mon, + + /// + mos, + + /// + mul, + + /// + mun, + + /// + mus, + + /// + mwl, + + /// + mwr, + + /// + myn, + + /// + myv, + + /// + nah, + + /// + nai, + + /// + nap, + + /// + nau, + + /// + nav, + + /// + nbl, + + /// + nde, + + /// + ndo, + + /// + nds, + + /// + nep, + + /// + @new, + + /// + nia, + + /// + nic, + + /// + niu, + + /// + nno, + + /// + nob, + + /// + nog, + + /// + non, + + /// + nor, + + /// + nqo, + + /// + nso, + + /// + nub, + + /// + nwc, + + /// + nya, + + /// + nym, + + /// + nyn, + + /// + nyo, + + /// + nzi, + + /// + oci, + + /// + oji, + + /// + ori, + + /// + orm, + + /// + osa, + + /// + oss, + + /// + ota, + + /// + oto, + + /// + paa, + + /// + pag, + + /// + pal, + + /// + pam, + + /// + pan, + + /// + pap, + + /// + pau, + + /// + peo, + + /// + per, + + /// + phi, + + /// + phn, + + /// + pli, + + /// + pol, + + /// + pon, + + /// + por, + + /// + pra, + + /// + pro, + + /// + pus, + + /// + [XmlEnum("qaa-qtz")] + qaaqtz, + + /// + que, + + /// + raj, + + /// + rap, + + /// + rar, + + /// + roa, + + /// + roh, + + /// + rom, + + /// + rum, + + /// + run, + + /// + rup, + + /// + rus, + + /// + sad, + + /// + sag, + + /// + sah, + + /// + sai, + + /// + sal, + + /// + sam, + + /// + san, + + /// + sas, + + /// + sat, + + /// + scn, + + /// + sco, + + /// + sel, + + /// + sem, + + /// + sga, + + /// + sgn, + + /// + shn, + + /// + sid, + + /// + sin, + + /// + sio, + + /// + sit, + + /// + sla, + + /// + slo, + + /// + slv, + + /// + sma, + + /// + sme, + + /// + smi, + + /// + smj, + + /// + smn, + + /// + smo, + + /// + sms, + + /// + sna, + + /// + snd, + + /// + snk, + + /// + sog, + + /// + som, + + /// + son, + + /// + sot, + + /// + spa, + + /// + srd, + + /// + srn, + + /// + srp, + + /// + srr, + + /// + ssa, + + /// + ssw, + + /// + suk, + + /// + sun, + + /// + sus, + + /// + sux, + + /// + swa, + + /// + swe, + + /// + syc, + + /// + syr, + + /// + tah, + + /// + tai, + + /// + tam, + + /// + tat, + + /// + tel, + + /// + tem, + + /// + ter, + + /// + tet, + + /// + tgk, + + /// + tgl, + + /// + tha, + + /// + tib, + + /// + tig, + + /// + tir, + + /// + tiv, + + /// + tkl, + + /// + tlh, + + /// + tli, + + /// + tmh, + + /// + tog, + + /// + ton, + + /// + tpi, + + /// + tsi, + + /// + tsn, + + /// + tso, + + /// + tuk, + + /// + tum, + + /// + tup, + + /// + tur, + + /// + tut, + + /// + tvl, + + /// + twi, + + /// + tyv, + + /// + udm, + + /// + uga, + + /// + uig, + + /// + ukr, + + /// + umb, + + /// + und, + + /// + urd, + + /// + uzb, + + /// + vai, + + /// + ven, + + /// + vie, + + /// + vol, + + /// + vot, + + /// + wak, + + /// + wal, + + /// + war, + + /// + was, + + /// + wel, + + /// + wen, + + /// + wln, + + /// + wol, + + /// + xal, + + /// + xho, + + /// + yao, + + /// + yap, + + /// + yid, + + /// + yor, + + /// + ypk, + + /// + zap, + + /// + zbl, + + /// + zen, + + /// + zgh, + + /// + zha, + + /// + znd, + + /// + zul, + + /// + zun, + + /// + zxx, + + /// + zza +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class MediaScanType +{ + MediaScanTypeMediaScanElement mediaScanElementField; + + ScanType scanField; + + /// + public MediaScanTypeMediaScanElement MediaScanElement + { + get => mediaScanElementField; + set => mediaScanElementField = value; + } + + /// + public ScanType Scan + { + get => scanField; + set => scanField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum MediaScanTypeMediaScanElement +{ + /// + up, + + /// + down, + + /// + front, + + /// + back, + + /// + left, + + /// + right +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class DumpHardwareType +{ + string manufacturerField; + + string modelField; + + string revisionField; + + string firmwareField; + + string serialField; + + ExtentType[] extentsField; + + SoftwareType softwareField; + + /// + public string Manufacturer + { + get => manufacturerField; + set => manufacturerField = value; + } + + /// + public string Model + { + get => modelField; + set => modelField = value; + } + + /// + public string Revision + { + get => revisionField; + set => revisionField = value; + } + + /// + public string Firmware + { + get => firmwareField; + set => firmwareField = value; + } + + /// + public string Serial + { + get => serialField; + set => serialField = value; + } + + /// + [XmlArrayItem("Extent", IsNullable = false)] + public ExtentType[] Extents + { + get => extentsField; + set => extentsField = value; + } + + /// + public SoftwareType Software + { + get => softwareField; + set => softwareField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class ExtentType +{ + ulong startField; + + ulong endField; + + /// + public ulong Start + { + get => startField; + set => startField = value; + } + + /// + public ulong End + { + get => endField; + set => endField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class SoftwareType +{ + string nameField; + + string versionField; + + string operatingSystemField; + + /// + public string Name + { + get => nameField; + set => nameField = value; + } + + /// + public string Version + { + get => versionField; + set => versionField = value; + } + + /// + public string OperatingSystem + { + get => operatingSystemField; + set => operatingSystemField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class BlockTrackType +{ + ImageType imageField; + + ulong sizeField; + + ushort headField; + + uint cylinderField; + + ulong startSectorField; + + ulong endSectorField; + + ulong sectorsField; + + uint bytesPerSectorField; + + ChecksumType[] checksumsField; + + string formatField; + + /// + public ImageType Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + public ushort Head + { + get => headField; + set => headField = value; + } + + /// + public uint Cylinder + { + get => cylinderField; + set => cylinderField = value; + } + + /// + public ulong StartSector + { + get => startSectorField; + set => startSectorField = value; + } + + /// + public ulong EndSector + { + get => endSectorField; + set => endSectorField = value; + } + + /// + public ulong Sectors + { + get => sectorsField; + set => sectorsField = value; + } + + /// + public uint BytesPerSector + { + get => bytesPerSectorField; + set => bytesPerSectorField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + public string Format + { + get => formatField; + set => formatField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class USBType +{ + ushort vendorIDField; + + ushort productIDField; + + DumpType descriptorsField; + + /// + public ushort VendorID + { + get => vendorIDField; + set => vendorIDField = value; + } + + /// + public ushort ProductID + { + get => productIDField; + set => productIDField = value; + } + + /// + public DumpType Descriptors + { + get => descriptorsField; + set => descriptorsField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class DumpType +{ + string imageField; + + ulong sizeField; + + ChecksumType[] checksumsField; + + /// + public string Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class EVPDType +{ + string imageField; + + ulong sizeField; + + ChecksumType[] checksumsField; + + byte pageField; + + bool pageFieldSpecified; + + /// + public string Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + [XmlAttribute] + public byte page + { + get => pageField; + set => pageField = value; + } + + /// + [XmlIgnore] + public bool pageSpecified + { + get => pageFieldSpecified; + set => pageFieldSpecified = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class SCSIType +{ + DumpType inquiryField; + + EVPDType[] eVPDField; + + DumpType modeSenseField; + + DumpType modeSense10Field; + + DumpType logSenseField; + + /// + public DumpType Inquiry + { + get => inquiryField; + set => inquiryField = value; + } + + /// + [XmlElement("EVPD")] + public EVPDType[] EVPD + { + get => eVPDField; + set => eVPDField = value; + } + + /// + public DumpType ModeSense + { + get => modeSenseField; + set => modeSenseField = value; + } + + /// + public DumpType ModeSense10 + { + get => modeSense10Field; + set => modeSense10Field = value; + } + + /// + public DumpType LogSense + { + get => logSenseField; + set => logSenseField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class MultiMediaCardType +{ + DumpType cIDField; + + DumpType cSDField; + + DumpType extendedCSDField; + + DumpType oCRField; + + /// + public DumpType CID + { + get => cIDField; + set => cIDField = value; + } + + /// + public DumpType CSD + { + get => cSDField; + set => cSDField = value; + } + + /// + public DumpType ExtendedCSD + { + get => extendedCSDField; + set => extendedCSDField = value; + } + + /// + public DumpType OCR + { + get => oCRField; + set => oCRField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class SecureDigitalType +{ + DumpType cIDField; + + DumpType cSDField; + + DumpType sCRField; + + DumpType oCRField; + + /// + public DumpType CID + { + get => cIDField; + set => cIDField = value; + } + + /// + public DumpType CSD + { + get => cSDField; + set => cSDField = value; + } + + /// + public DumpType SCR + { + get => sCRField; + set => sCRField = value; + } + + /// + public DumpType OCR + { + get => oCRField; + set => oCRField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class ATAType +{ + DumpType identifyField; + + /// + public DumpType Identify + { + get => identifyField; + set => identifyField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class TapeFileType +{ + ImageType imageField; + + ulong sizeField; + + ulong sequenceField; + + ulong blockSizeField; + + ulong startBlockField; + + ulong endBlockField; + + ChecksumType[] checksumsField; + + /// + public ImageType Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + public ulong Sequence + { + get => sequenceField; + set => sequenceField = value; + } + + /// + public ulong BlockSize + { + get => blockSizeField; + set => blockSizeField = value; + } + + /// + public ulong StartBlock + { + get => startBlockField; + set => startBlockField = value; + } + + /// + public ulong EndBlock + { + get => endBlockField; + set => endBlockField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class TapePartitionType +{ + ImageType imageField; + + ulong sizeField; + + ulong sequenceField; + + ulong startBlockField; + + ulong endBlockField; + + ChecksumType[] checksumsField; + + TapeFileType[] fileField; + + /// + public ImageType Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + public ulong Sequence + { + get => sequenceField; + set => sequenceField = value; + } + + /// + public ulong StartBlock + { + get => startBlockField; + set => startBlockField = value; + } + + /// + public ulong EndBlock + { + get => endBlockField; + set => endBlockField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + [XmlElement("File")] + public TapeFileType[] File + { + get => fileField; + set => fileField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class BlockSizeType +{ + uint startingBlockField; + + uint valueField; + + /// + [XmlAttribute] + public uint startingBlock + { + get => startingBlockField; + set => startingBlockField = value; + } + + /// + [XmlText] + public uint Value + { + get => valueField; + set => valueField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class BlockMediaType +{ + ImageType imageField; + + ulong sizeField; + + ChecksumType[] checksumsField; + + ChecksumType[] contentChecksumsField; + + SequenceType sequenceField; + + string manufacturerField; + + string modelField; + + string serialField; + + string firmwareField; + + string interfaceField; + + string partNumberField; + + string serialNumberField; + + uint physicalBlockSizeField; + + uint logicalBlockSizeField; + + ulong logicalBlocksField; + + BlockSizeType[] variableBlockSizeField; + + TapePartitionType[] tapeInformationField; + + ScansType scansField; + + ATAType aTAField; + + PCIType pCIField; + + PCMCIAType pCMCIAField; + + SecureDigitalType secureDigitalField; + + MultiMediaCardType multiMediaCardField; + + SCSIType sCSIField; + + USBType uSBField; + + DumpType mAMField; + + ushort headsField; + + bool headsFieldSpecified; + + uint cylindersField; + + bool cylindersFieldSpecified; + + ulong sectorsPerTrackField; + + bool sectorsPerTrackFieldSpecified; + + BlockTrackType[] trackField; + + string copyProtectionField; + + DimensionsType dimensionsField; + + PartitionType[] fileSystemInformationField; + + DumpHardwareType[] dumpHardwareArrayField; + + string diskTypeField; + + string diskSubTypeField; + + /// + public ImageType Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] ContentChecksums + { + get => contentChecksumsField; + set => contentChecksumsField = value; + } + + /// + public SequenceType Sequence + { + get => sequenceField; + set => sequenceField = value; + } + + /// + public string Manufacturer + { + get => manufacturerField; + set => manufacturerField = value; + } + + /// + public string Model + { + get => modelField; + set => modelField = value; + } + + /// + public string Serial + { + get => serialField; + set => serialField = value; + } + + /// + public string Firmware + { + get => firmwareField; + set => firmwareField = value; + } + + /// + public string Interface + { + get => interfaceField; + set => interfaceField = value; + } + + /// + public string PartNumber + { + get => partNumberField; + set => partNumberField = value; + } + + /// + public string SerialNumber + { + get => serialNumberField; + set => serialNumberField = value; + } + + /// + public uint PhysicalBlockSize + { + get => physicalBlockSizeField; + set => physicalBlockSizeField = value; + } + + /// + public uint LogicalBlockSize + { + get => logicalBlockSizeField; + set => logicalBlockSizeField = value; + } + + /// + public ulong LogicalBlocks + { + get => logicalBlocksField; + set => logicalBlocksField = value; + } + + /// + [XmlArrayItem("BlockSize", IsNullable = false)] + public BlockSizeType[] VariableBlockSize + { + get => variableBlockSizeField; + set => variableBlockSizeField = value; + } + + /// + [XmlArrayItem("Partition", IsNullable = false)] + public TapePartitionType[] TapeInformation + { + get => tapeInformationField; + set => tapeInformationField = value; + } + + /// + public ScansType Scans + { + get => scansField; + set => scansField = value; + } + + /// + public ATAType ATA + { + get => aTAField; + set => aTAField = value; + } + + /// + public PCIType PCI + { + get => pCIField; + set => pCIField = value; + } + + /// + public PCMCIAType PCMCIA + { + get => pCMCIAField; + set => pCMCIAField = value; + } + + /// + public SecureDigitalType SecureDigital + { + get => secureDigitalField; + set => secureDigitalField = value; + } + + /// + public MultiMediaCardType MultiMediaCard + { + get => multiMediaCardField; + set => multiMediaCardField = value; + } + + /// + public SCSIType SCSI + { + get => sCSIField; + set => sCSIField = value; + } + + /// + public USBType USB + { + get => uSBField; + set => uSBField = value; + } + + /// + public DumpType MAM + { + get => mAMField; + set => mAMField = value; + } + + /// + public ushort Heads + { + get => headsField; + set => headsField = value; + } + + /// + [XmlIgnore] + public bool HeadsSpecified + { + get => headsFieldSpecified; + set => headsFieldSpecified = value; + } + + /// + public uint Cylinders + { + get => cylindersField; + set => cylindersField = value; + } + + /// + [XmlIgnore] + public bool CylindersSpecified + { + get => cylindersFieldSpecified; + set => cylindersFieldSpecified = value; + } + + /// + public ulong SectorsPerTrack + { + get => sectorsPerTrackField; + set => sectorsPerTrackField = value; + } + + /// + [XmlIgnore] + public bool SectorsPerTrackSpecified + { + get => sectorsPerTrackFieldSpecified; + set => sectorsPerTrackFieldSpecified = value; + } + + /// + [XmlElement("Track")] + public BlockTrackType[] Track + { + get => trackField; + set => trackField = value; + } + + /// + public string CopyProtection + { + get => copyProtectionField; + set => copyProtectionField = value; + } + + /// + public DimensionsType Dimensions + { + get => dimensionsField; + set => dimensionsField = value; + } + + /// + [XmlArrayItem("Partition", IsNullable = false)] + public PartitionType[] FileSystemInformation + { + get => fileSystemInformationField; + set => fileSystemInformationField = value; + } + + /// + [XmlArrayItem("DumpHardware", IsNullable = false)] + public DumpHardwareType[] DumpHardwareArray + { + get => dumpHardwareArrayField; + set => dumpHardwareArrayField = value; + } + + /// + public string DiskType + { + get => diskTypeField; + set => diskTypeField = value; + } + + /// + public string DiskSubType + { + get => diskSubTypeField; + set => diskSubTypeField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class PCIType +{ + ushort vendorIDField; + + ushort deviceIDField; + + DumpType configurationField; + + LinearMediaType expansionROMField; + + /// + public ushort VendorID + { + get => vendorIDField; + set => vendorIDField = value; + } + + /// + public ushort DeviceID + { + get => deviceIDField; + set => deviceIDField = value; + } + + /// + public DumpType Configuration + { + get => configurationField; + set => configurationField = value; + } + + /// + public LinearMediaType ExpansionROM + { + get => expansionROMField; + set => expansionROMField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class LinearMediaType +{ + ImageType imageField; + + ulong sizeField; + + ChecksumType[] imageChecksumsField; + + ChecksumType[] checksumsField; + + string partNumberField; + + string serialNumberField; + + string titleField; + + uint sequenceField; + + bool sequenceFieldSpecified; + + uint imageInterleaveField; + + bool imageInterleaveFieldSpecified; + + uint interleaveField; + + bool interleaveFieldSpecified; + + string manufacturerField; + + string modelField; + + string packageField; + + string interfaceField; + + DimensionsType dimensionsField; + + ScansType scansField; + + DumpHardwareType[] dumpHardwareArrayField; + + PCMCIAType pCMCIAField; + + string copyProtectionField; + + /// + public ImageType Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] ImageChecksums + { + get => imageChecksumsField; + set => imageChecksumsField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + public string PartNumber + { + get => partNumberField; + set => partNumberField = value; + } + + /// + public string SerialNumber + { + get => serialNumberField; + set => serialNumberField = value; + } + + /// + public string Title + { + get => titleField; + set => titleField = value; + } + + /// + public uint Sequence + { + get => sequenceField; + set => sequenceField = value; + } + + /// + [XmlIgnore] + public bool SequenceSpecified + { + get => sequenceFieldSpecified; + set => sequenceFieldSpecified = value; + } + + /// + public uint ImageInterleave + { + get => imageInterleaveField; + set => imageInterleaveField = value; + } + + /// + [XmlIgnore] + public bool ImageInterleaveSpecified + { + get => imageInterleaveFieldSpecified; + set => imageInterleaveFieldSpecified = value; + } + + /// + public uint Interleave + { + get => interleaveField; + set => interleaveField = value; + } + + /// + [XmlIgnore] + public bool InterleaveSpecified + { + get => interleaveFieldSpecified; + set => interleaveFieldSpecified = value; + } + + /// + public string Manufacturer + { + get => manufacturerField; + set => manufacturerField = value; + } + + /// + public string Model + { + get => modelField; + set => modelField = value; + } + + /// + public string Package + { + get => packageField; + set => packageField = value; + } + + /// + public string Interface + { + get => interfaceField; + set => interfaceField = value; + } + + /// + public DimensionsType Dimensions + { + get => dimensionsField; + set => dimensionsField = value; + } + + /// + public ScansType Scans + { + get => scansField; + set => scansField = value; + } + + /// + [XmlArrayItem("DumpHardware", IsNullable = false)] + public DumpHardwareType[] DumpHardwareArray + { + get => dumpHardwareArrayField; + set => dumpHardwareArrayField = value; + } + + /// + public PCMCIAType PCMCIA + { + get => pCMCIAField; + set => pCMCIAField = value; + } + + /// + public string CopyProtection + { + get => copyProtectionField; + set => copyProtectionField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class PCMCIAType +{ + DumpType cISField; + + string complianceField; + + ushort manufacturerCodeField; + + bool manufacturerCodeFieldSpecified; + + ushort cardCodeField; + + bool cardCodeFieldSpecified; + + string manufacturerField; + + string productNameField; + + string[] additionalInformationField; + + /// + public DumpType CIS + { + get => cISField; + set => cISField = value; + } + + /// + public string Compliance + { + get => complianceField; + set => complianceField = value; + } + + /// + public ushort ManufacturerCode + { + get => manufacturerCodeField; + set => manufacturerCodeField = value; + } + + /// + [XmlIgnore] + public bool ManufacturerCodeSpecified + { + get => manufacturerCodeFieldSpecified; + set => manufacturerCodeFieldSpecified = value; + } + + /// + public ushort CardCode + { + get => cardCodeField; + set => cardCodeField = value; + } + + /// + [XmlIgnore] + public bool CardCodeSpecified + { + get => cardCodeFieldSpecified; + set => cardCodeFieldSpecified = value; + } + + /// + public string Manufacturer + { + get => manufacturerField; + set => manufacturerField = value; + } + + /// + public string ProductName + { + get => productNameField; + set => productNameField = value; + } + + /// + [XmlElement("AdditionalInformation")] + public string[] AdditionalInformation + { + get => additionalInformationField; + set => additionalInformationField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class PartitionType +{ + uint sequenceField; + + string nameField; + + string typeField; + + ulong startSectorField; + + ulong endSectorField; + + string descriptionField; + + FileSystemType[] fileSystemsField; + + /// + public uint Sequence + { + get => sequenceField; + set => sequenceField = value; + } + + /// + public string Name + { + get => nameField; + set => nameField = value; + } + + /// + public string Type + { + get => typeField; + set => typeField = value; + } + + /// + public ulong StartSector + { + get => startSectorField; + set => startSectorField = value; + } + + /// + public ulong EndSector + { + get => endSectorField; + set => endSectorField = value; + } + + /// + public string Description + { + get => descriptionField; + set => descriptionField = value; + } + + /// + [XmlArrayItem("FileSystem", IsNullable = false)] + public FileSystemType[] FileSystems + { + get => fileSystemsField; + set => fileSystemsField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class FileSystemType +{ + string typeField; + + DateTime creationDateField; + + bool creationDateFieldSpecified; + + DateTime modificationDateField; + + bool modificationDateFieldSpecified; + + DateTime backupDateField; + + bool backupDateFieldSpecified; + + uint clusterSizeField; + + ulong clustersField; + + ulong filesField; + + bool filesFieldSpecified; + + bool bootableField; + + string volumeSerialField; + + string volumeNameField; + + ulong freeClustersField; + + bool freeClustersFieldSpecified; + + bool dirtyField; + + DateTime expirationDateField; + + bool expirationDateFieldSpecified; + + DateTime effectiveDateField; + + bool effectiveDateFieldSpecified; + + string systemIdentifierField; + + string volumeSetIdentifierField; + + string publisherIdentifierField; + + string dataPreparerIdentifierField; + + string applicationIdentifierField; + + FilesystemContentsType contentsField; + + /// + public string Type + { + get => typeField; + set => typeField = value; + } + + /// + public DateTime CreationDate + { + get => creationDateField; + set => creationDateField = value; + } + + /// + [XmlIgnore] + public bool CreationDateSpecified + { + get => creationDateFieldSpecified; + set => creationDateFieldSpecified = value; + } + + /// + public DateTime ModificationDate + { + get => modificationDateField; + set => modificationDateField = value; + } + + /// + [XmlIgnore] + public bool ModificationDateSpecified + { + get => modificationDateFieldSpecified; + set => modificationDateFieldSpecified = value; + } + + /// + public DateTime BackupDate + { + get => backupDateField; + set => backupDateField = value; + } + + /// + [XmlIgnore] + public bool BackupDateSpecified + { + get => backupDateFieldSpecified; + set => backupDateFieldSpecified = value; + } + + /// + public uint ClusterSize + { + get => clusterSizeField; + set => clusterSizeField = value; + } + + /// + public ulong Clusters + { + get => clustersField; + set => clustersField = value; + } + + /// + public ulong Files + { + get => filesField; + set => filesField = value; + } + + /// + [XmlIgnore] + public bool FilesSpecified + { + get => filesFieldSpecified; + set => filesFieldSpecified = value; + } + + /// + public bool Bootable + { + get => bootableField; + set => bootableField = value; + } + + /// + public string VolumeSerial + { + get => volumeSerialField; + set => volumeSerialField = value; + } + + /// + public string VolumeName + { + get => volumeNameField; + set => volumeNameField = value; + } + + /// + public ulong FreeClusters + { + get => freeClustersField; + set => freeClustersField = value; + } + + /// + [XmlIgnore] + public bool FreeClustersSpecified + { + get => freeClustersFieldSpecified; + set => freeClustersFieldSpecified = value; + } + + /// + public bool Dirty + { + get => dirtyField; + set => dirtyField = value; + } + + /// + public DateTime ExpirationDate + { + get => expirationDateField; + set => expirationDateField = value; + } + + /// + [XmlIgnore] + public bool ExpirationDateSpecified + { + get => expirationDateFieldSpecified; + set => expirationDateFieldSpecified = value; + } + + /// + public DateTime EffectiveDate + { + get => effectiveDateField; + set => effectiveDateField = value; + } + + /// + [XmlIgnore] + public bool EffectiveDateSpecified + { + get => effectiveDateFieldSpecified; + set => effectiveDateFieldSpecified = value; + } + + /// + public string SystemIdentifier + { + get => systemIdentifierField; + set => systemIdentifierField = value; + } + + /// + public string VolumeSetIdentifier + { + get => volumeSetIdentifierField; + set => volumeSetIdentifierField = value; + } + + /// + public string PublisherIdentifier + { + get => publisherIdentifierField; + set => publisherIdentifierField = value; + } + + /// + public string DataPreparerIdentifier + { + get => dataPreparerIdentifierField; + set => dataPreparerIdentifierField = value; + } + + /// + public string ApplicationIdentifier + { + get => applicationIdentifierField; + set => applicationIdentifierField = value; + } + + /// + public FilesystemContentsType Contents + { + get => contentsField; + set => contentsField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class FilesystemContentsType +{ + ContentsFileType[] fileField; + + DirectoryType[] directoryField; + + string namespaceField; + + /// + [XmlElement("File")] + public ContentsFileType[] File + { + get => fileField; + set => fileField = value; + } + + /// + [XmlElement("Directory")] + public DirectoryType[] Directory + { + get => directoryField; + set => directoryField = value; + } + + /// + [XmlAttribute] + public string @namespace + { + get => namespaceField; + set => namespaceField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class ContentsFileType +{ + ChecksumType[] checksumsField; + + ExtendedAttributeType[] extendedAttributesField; + + string nameField; + + DateTime creationTimeField; + + bool creationTimeFieldSpecified; + + DateTime accessTimeField; + + bool accessTimeFieldSpecified; + + DateTime statusChangeTimeField; + + bool statusChangeTimeFieldSpecified; + + DateTime backupTimeField; + + bool backupTimeFieldSpecified; + + DateTime lastWriteTimeField; + + bool lastWriteTimeFieldSpecified; + + ulong attributesField; + + uint posixModeField; + + bool posixModeFieldSpecified; + + ulong deviceNumberField; + + bool deviceNumberFieldSpecified; + + ulong posixGroupIdField; + + bool posixGroupIdFieldSpecified; + + ulong inodeField; + + ulong linksField; + + ulong posixUserIdField; + + bool posixUserIdFieldSpecified; + + ulong lengthField; + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + [XmlArrayItem("ExtendedAttribute", IsNullable = false)] + public ExtendedAttributeType[] ExtendedAttributes + { + get => extendedAttributesField; + set => extendedAttributesField = value; + } + + /// + [XmlAttribute] + public string name + { + get => nameField; + set => nameField = value; + } + + /// + [XmlAttribute] + public DateTime creationTime + { + get => creationTimeField; + set => creationTimeField = value; + } + + /// + [XmlIgnore] + public bool creationTimeSpecified + { + get => creationTimeFieldSpecified; + set => creationTimeFieldSpecified = value; + } + + /// + [XmlAttribute] + public DateTime accessTime + { + get => accessTimeField; + set => accessTimeField = value; + } + + /// + [XmlIgnore] + public bool accessTimeSpecified + { + get => accessTimeFieldSpecified; + set => accessTimeFieldSpecified = value; + } + + /// + [XmlAttribute] + public DateTime statusChangeTime + { + get => statusChangeTimeField; + set => statusChangeTimeField = value; + } + + /// + [XmlIgnore] + public bool statusChangeTimeSpecified + { + get => statusChangeTimeFieldSpecified; + set => statusChangeTimeFieldSpecified = value; + } + + /// + [XmlAttribute] + public DateTime backupTime + { + get => backupTimeField; + set => backupTimeField = value; + } + + /// + [XmlIgnore] + public bool backupTimeSpecified + { + get => backupTimeFieldSpecified; + set => backupTimeFieldSpecified = value; + } + + /// + [XmlAttribute] + public DateTime lastWriteTime + { + get => lastWriteTimeField; + set => lastWriteTimeField = value; + } + + /// + [XmlIgnore] + public bool lastWriteTimeSpecified + { + get => lastWriteTimeFieldSpecified; + set => lastWriteTimeFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong attributes + { + get => attributesField; + set => attributesField = value; + } + + /// + [XmlAttribute] + public uint posixMode + { + get => posixModeField; + set => posixModeField = value; + } + + /// + [XmlIgnore] + public bool posixModeSpecified + { + get => posixModeFieldSpecified; + set => posixModeFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong deviceNumber + { + get => deviceNumberField; + set => deviceNumberField = value; + } + + /// + [XmlIgnore] + public bool deviceNumberSpecified + { + get => deviceNumberFieldSpecified; + set => deviceNumberFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong posixGroupId + { + get => posixGroupIdField; + set => posixGroupIdField = value; + } + + /// + [XmlIgnore] + public bool posixGroupIdSpecified + { + get => posixGroupIdFieldSpecified; + set => posixGroupIdFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong inode + { + get => inodeField; + set => inodeField = value; + } + + /// + [XmlAttribute] + public ulong links + { + get => linksField; + set => linksField = value; + } + + /// + [XmlAttribute] + public ulong posixUserId + { + get => posixUserIdField; + set => posixUserIdField = value; + } + + /// + [XmlIgnore] + public bool posixUserIdSpecified + { + get => posixUserIdFieldSpecified; + set => posixUserIdFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong length + { + get => lengthField; + set => lengthField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class ExtendedAttributeType +{ + ChecksumType[] checksumsField; + + string nameField; + + ulong lengthField; + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + [XmlAttribute] + public string name + { + get => nameField; + set => nameField = value; + } + + /// + [XmlAttribute] + public ulong length + { + get => lengthField; + set => lengthField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class DirectoryType +{ + ContentsFileType[] fileField; + + DirectoryType[] directoryField; + + string nameField; + + DateTime creationTimeField; + + bool creationTimeFieldSpecified; + + DateTime accessTimeField; + + bool accessTimeFieldSpecified; + + DateTime statusChangeTimeField; + + bool statusChangeTimeFieldSpecified; + + DateTime backupTimeField; + + bool backupTimeFieldSpecified; + + DateTime lastWriteTimeField; + + bool lastWriteTimeFieldSpecified; + + ulong attributesField; + + uint posixModeField; + + bool posixModeFieldSpecified; + + ulong deviceNumberField; + + bool deviceNumberFieldSpecified; + + ulong posixGroupIdField; + + bool posixGroupIdFieldSpecified; + + ulong inodeField; + + bool inodeFieldSpecified; + + ulong linksField; + + bool linksFieldSpecified; + + ulong posixUserIdField; + + bool posixUserIdFieldSpecified; + + /// + [XmlElement("File")] + public ContentsFileType[] File + { + get => fileField; + set => fileField = value; + } + + /// + [XmlElement("Directory")] + public DirectoryType[] Directory + { + get => directoryField; + set => directoryField = value; + } + + /// + [XmlAttribute] + public string name + { + get => nameField; + set => nameField = value; + } + + /// + [XmlAttribute] + public DateTime creationTime + { + get => creationTimeField; + set => creationTimeField = value; + } + + /// + [XmlIgnore] + public bool creationTimeSpecified + { + get => creationTimeFieldSpecified; + set => creationTimeFieldSpecified = value; + } + + /// + [XmlAttribute] + public DateTime accessTime + { + get => accessTimeField; + set => accessTimeField = value; + } + + /// + [XmlIgnore] + public bool accessTimeSpecified + { + get => accessTimeFieldSpecified; + set => accessTimeFieldSpecified = value; + } + + /// + [XmlAttribute] + public DateTime statusChangeTime + { + get => statusChangeTimeField; + set => statusChangeTimeField = value; + } + + /// + [XmlIgnore] + public bool statusChangeTimeSpecified + { + get => statusChangeTimeFieldSpecified; + set => statusChangeTimeFieldSpecified = value; + } + + /// + [XmlAttribute] + public DateTime backupTime + { + get => backupTimeField; + set => backupTimeField = value; + } + + /// + [XmlIgnore] + public bool backupTimeSpecified + { + get => backupTimeFieldSpecified; + set => backupTimeFieldSpecified = value; + } + + /// + [XmlAttribute] + public DateTime lastWriteTime + { + get => lastWriteTimeField; + set => lastWriteTimeField = value; + } + + /// + [XmlIgnore] + public bool lastWriteTimeSpecified + { + get => lastWriteTimeFieldSpecified; + set => lastWriteTimeFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong attributes + { + get => attributesField; + set => attributesField = value; + } + + /// + [XmlAttribute] + public uint posixMode + { + get => posixModeField; + set => posixModeField = value; + } + + /// + [XmlIgnore] + public bool posixModeSpecified + { + get => posixModeFieldSpecified; + set => posixModeFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong deviceNumber + { + get => deviceNumberField; + set => deviceNumberField = value; + } + + /// + [XmlIgnore] + public bool deviceNumberSpecified + { + get => deviceNumberFieldSpecified; + set => deviceNumberFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong posixGroupId + { + get => posixGroupIdField; + set => posixGroupIdField = value; + } + + /// + [XmlIgnore] + public bool posixGroupIdSpecified + { + get => posixGroupIdFieldSpecified; + set => posixGroupIdFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong inode + { + get => inodeField; + set => inodeField = value; + } + + /// + [XmlIgnore] + public bool inodeSpecified + { + get => inodeFieldSpecified; + set => inodeFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong links + { + get => linksField; + set => linksField = value; + } + + /// + [XmlIgnore] + public bool linksSpecified + { + get => linksFieldSpecified; + set => linksFieldSpecified = value; + } + + /// + [XmlAttribute] + public ulong posixUserId + { + get => posixUserIdField; + set => posixUserIdField = value; + } + + /// + [XmlIgnore] + public bool posixUserIdSpecified + { + get => posixUserIdFieldSpecified; + set => posixUserIdFieldSpecified = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class CoordinatesType +{ + double latitudeField; + + double longitudeField; + + /// + public double Latitude + { + get => latitudeField; + set => latitudeField = value; + } + + /// + public double Longitude + { + get => longitudeField; + set => longitudeField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class RecordingType +{ + string broadcasterField; + + string broadcastPlatformField; + + RecordingTypeSourceFormat sourceFormatField; + + DateTime timestampField; + + SoftwareType[] softwareField; + + CoordinatesType coordinatesField; + + /// + public string Broadcaster + { + get => broadcasterField; + set => broadcasterField = value; + } + + /// + public string BroadcastPlatform + { + get => broadcastPlatformField; + set => broadcastPlatformField = value; + } + + /// + public RecordingTypeSourceFormat SourceFormat + { + get => sourceFormatField; + set => sourceFormatField = value; + } + + /// + public DateTime Timestamp + { + get => timestampField; + set => timestampField = value; + } + + /// + [XmlElement("Software")] + public SoftwareType[] Software + { + get => softwareField; + set => softwareField = value; + } + + /// + public CoordinatesType Coordinates + { + get => coordinatesField; + set => coordinatesField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum RecordingTypeSourceFormat +{ + /// + [XmlEnum("ITU-A")] + ITUA, + + /// + [XmlEnum("ITU-B")] + ITUB, + + /// + [XmlEnum("ITU-C")] + ITUC, + + /// + [XmlEnum("ITU-D")] + ITUD, + + /// + [XmlEnum("ITU-E")] + ITUE, + + /// + [XmlEnum("ITU-F")] + ITUF, + + /// + [XmlEnum("ITU-G")] + ITUG, + + /// + [XmlEnum("ITU-H")] + ITUH, + + /// + [XmlEnum("ITU-I")] + ITUI, + + /// + [XmlEnum("ITU-J")] + ITUJ, + + /// + [XmlEnum("ITU-K")] + ITUK, + + /// + [XmlEnum("ITU-L")] + ITUL, + + /// + [XmlEnum("ITU-M")] + ITUM, + + /// + [XmlEnum("ITU-N")] + ITUN, + + /// + [XmlEnum("PAL-B")] + PALB, + + /// + [XmlEnum("SECAM-B")] + SECAMB, + + /// + [XmlEnum("PAL-D")] + PALD, + + /// + [XmlEnum("SECAM-D")] + SECAMD, + + /// + [XmlEnum("PAL-G")] + PALG, + + /// + [XmlEnum("SECAM-G")] + SECAMG, + + /// + [XmlEnum("PAL-H")] + PALH, + + /// + [XmlEnum("PAL-I")] + PALI, + + /// + [XmlEnum("PAL-K")] + PALK, + + /// + [XmlEnum("SECAM-K")] + SECAMK, + + /// + [XmlEnum("NTSC-M")] + NTSCM, + + /// + [XmlEnum("PAL-N")] + PALN, + + /// + [XmlEnum("PAL-M")] + PALM, + + /// + [XmlEnum("SECAM-M")] + SECAMM, + + /// + MUSE, + + /// + PALplus, + + /// + FM, + + /// + AM, + + /// + COFDM, + + /// + [XmlEnum("CAM-D")] + CAMD, + + /// + DAB, + + /// + [XmlEnum("DAB+")] + DAB1, + + /// + DRM, + + /// + [XmlEnum("DRM+")] + DRM1, + + /// + FMeXtra, + + /// + ATSC, + + /// + ATSC2, + + /// + ATSC3, + + /// + [XmlEnum("ATSC-M/H")] + ATSCMH, + + /// + [XmlEnum("DVB-T")] + DVBT, + + /// + [XmlEnum("DVB-T2")] + DVBT2, + + /// + [XmlEnum("DVB-S")] + DVBS, + + /// + [XmlEnum("DVB-S2")] + DVBS2, + + /// + [XmlEnum("DVB-S2X")] + DVBS2X, + + /// + [XmlEnum("DVB-C")] + DVBC, + + /// + [XmlEnum("DVB-C2")] + DVBC2, + + /// + [XmlEnum("DVB-H")] + DVBH, + + /// + [XmlEnum("DVB-NGH")] + DVBNGH, + + /// + [XmlEnum("DVB-SH")] + DVBSH, + + /// + [XmlEnum("ISDB-T")] + ISDBT, + + /// + [XmlEnum("ISDB-Tb")] + ISDBTb, + + /// + [XmlEnum("ISDB-S")] + ISDBS, + + /// + [XmlEnum("ISDB-C")] + ISDBC, + + /// + [XmlEnum("1seg")] + Item1seg, + + /// + DTMB, + + /// + CCMB, + + /// + [XmlEnum("T-DMB")] + TDMB, + + /// + [XmlEnum("S-DMB")] + SDMB, + + /// + IPTV, + + /// + [XmlEnum("DVB-MT")] + DVBMT, + + /// + [XmlEnum("DVB-MC")] + DVBMC, + + /// + [XmlEnum("DVB-MS")] + DVBMS, + + /// + ADR, + + /// + SDR +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class SubtitleTracksType +{ + LanguagesTypeLanguage[] languagesField; + + uint trackNumberField; + + string codecField; + + /// + [XmlArrayItem("Language", IsNullable = false)] + public LanguagesTypeLanguage[] Languages + { + get => languagesField; + set => languagesField = value; + } + + /// + [XmlAttribute] + public uint TrackNumber + { + get => trackNumberField; + set => trackNumberField = value; + } + + /// + [XmlAttribute] + public string Codec + { + get => codecField; + set => codecField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class VideoTracksType +{ + LanguagesTypeLanguage[] languagesField; + + uint trackNumberField; + + string codecField; + + uint horizontalField; + + uint verticalField; + + long meanBitrateField; + + bool threeDField; + + /// + [XmlArrayItem("Language", IsNullable = false)] + public LanguagesTypeLanguage[] Languages + { + get => languagesField; + set => languagesField = value; + } + + /// + [XmlAttribute] + public uint TrackNumber + { + get => trackNumberField; + set => trackNumberField = value; + } + + /// + [XmlAttribute] + public string Codec + { + get => codecField; + set => codecField = value; + } + + /// + [XmlAttribute] + public uint Horizontal + { + get => horizontalField; + set => horizontalField = value; + } + + /// + [XmlAttribute] + public uint Vertical + { + get => verticalField; + set => verticalField = value; + } + + /// + [XmlAttribute] + public long MeanBitrate + { + get => meanBitrateField; + set => meanBitrateField = value; + } + + /// + [XmlAttribute] + public bool ThreeD + { + get => threeDField; + set => threeDField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class AudioTracksType +{ + LanguagesTypeLanguage[] languagesField; + + uint trackNumberField; + + string accoustIDField; + + string codecField; + + uint channelsField; + + double sampleRateField; + + long meanBitrateField; + + /// + [XmlArrayItem("Language", IsNullable = false)] + public LanguagesTypeLanguage[] Languages + { + get => languagesField; + set => languagesField = value; + } + + /// + [XmlAttribute] + public uint TrackNumber + { + get => trackNumberField; + set => trackNumberField = value; + } + + /// + [XmlAttribute] + public string AccoustID + { + get => accoustIDField; + set => accoustIDField = value; + } + + /// + [XmlAttribute] + public string Codec + { + get => codecField; + set => codecField = value; + } + + /// + [XmlAttribute] + public uint Channels + { + get => channelsField; + set => channelsField = value; + } + + /// + [XmlAttribute] + public double SampleRate + { + get => sampleRateField; + set => sampleRateField = value; + } + + /// + [XmlAttribute] + public long MeanBitrate + { + get => meanBitrateField; + set => meanBitrateField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class AdvertisementType +{ + string manufacturerField; + + string productField; + + FileType fileField; + + ulong fileSizeField; + + ulong framesField; + + bool framesFieldSpecified; + + double durationField; + + float meanFrameRateField; + + bool meanFrameRateFieldSpecified; + + ChecksumType[] checksumsField; + + AudioTracksType[] audioTrackField; + + VideoTracksType[] videoTrackField; + + SubtitleTracksType[] subtitleTrackField; + + RecordingType recordingField; + + /// + public string Manufacturer + { + get => manufacturerField; + set => manufacturerField = value; + } + + /// + public string Product + { + get => productField; + set => productField = value; + } + + /// + public FileType File + { + get => fileField; + set => fileField = value; + } + + /// + public ulong FileSize + { + get => fileSizeField; + set => fileSizeField = value; + } + + /// + public ulong Frames + { + get => framesField; + set => framesField = value; + } + + /// + [XmlIgnore] + public bool FramesSpecified + { + get => framesFieldSpecified; + set => framesFieldSpecified = value; + } + + /// + public double Duration + { + get => durationField; + set => durationField = value; + } + + /// + public float MeanFrameRate + { + get => meanFrameRateField; + set => meanFrameRateField = value; + } + + /// + [XmlIgnore] + public bool MeanFrameRateSpecified + { + get => meanFrameRateFieldSpecified; + set => meanFrameRateFieldSpecified = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + [XmlElement("AudioTrack")] + public AudioTracksType[] AudioTrack + { + get => audioTrackField; + set => audioTrackField = value; + } + + /// + [XmlElement("VideoTrack")] + public VideoTracksType[] VideoTrack + { + get => videoTrackField; + set => videoTrackField = value; + } + + /// + [XmlElement("SubtitleTrack")] + public SubtitleTracksType[] SubtitleTrack + { + get => subtitleTrackField; + set => subtitleTrackField = value; + } + + /// + public RecordingType Recording + { + get => recordingField; + set => recordingField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class SubChannelType +{ + ImageType imageField; + + ulong sizeField; + + ChecksumType[] checksumsField; + + /// + public ImageType Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class TrackFlagsType +{ + bool quadraphonicField; + + bool dataField; + + bool copyPermittedField; + + bool preEmphasisField; + + /// + public bool Quadraphonic + { + get => quadraphonicField; + set => quadraphonicField = value; + } + + /// + public bool Data + { + get => dataField; + set => dataField = value; + } + + /// + public bool CopyPermitted + { + get => copyPermittedField; + set => copyPermittedField = value; + } + + /// + public bool PreEmphasis + { + get => preEmphasisField; + set => preEmphasisField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class TrackIndexType +{ + ushort indexField; + + int valueField; + + /// + [XmlAttribute] + public ushort index + { + get => indexField; + set => indexField = value; + } + + /// + [XmlText] + public int Value + { + get => valueField; + set => valueField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class TrackSequenceType +{ + uint trackNumberField; + + uint sessionField; + + /// + public uint TrackNumber + { + get => trackNumberField; + set => trackNumberField = value; + } + + /// + public uint Session + { + get => sessionField; + set => sessionField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class TrackType +{ + ImageType imageField; + + ulong sizeField; + + TrackSequenceType sequenceField; + + string startMSFField; + + string endMSFField; + + ulong startSectorField; + + ulong endSectorField; + + TrackIndexType[] indexesField; + + TrackFlagsType flagsField; + + string iSRCField; + + TrackTypeTrackType trackType1Field; + + uint bytesPerSectorField; + + string accoustIDField; + + ChecksumType[] checksumsField; + + SubChannelType subChannelField; + + PartitionType[] fileSystemInformationField; + + /// + public ImageType Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + public TrackSequenceType Sequence + { + get => sequenceField; + set => sequenceField = value; + } + + /// + public string StartMSF + { + get => startMSFField; + set => startMSFField = value; + } + + /// + public string EndMSF + { + get => endMSFField; + set => endMSFField = value; + } + + /// + public ulong StartSector + { + get => startSectorField; + set => startSectorField = value; + } + + /// + public ulong EndSector + { + get => endSectorField; + set => endSectorField = value; + } + + /// + [XmlArrayItem("Index", IsNullable = false)] + public TrackIndexType[] Indexes + { + get => indexesField; + set => indexesField = value; + } + + /// + public TrackFlagsType Flags + { + get => flagsField; + set => flagsField = value; + } + + /// + public string ISRC + { + get => iSRCField; + set => iSRCField = value; + } + + /// + [XmlElement("TrackType")] + public TrackTypeTrackType TrackType1 + { + get => trackType1Field; + set => trackType1Field = value; + } + + /// + public uint BytesPerSector + { + get => bytesPerSectorField; + set => bytesPerSectorField = value; + } + + /// + public string AccoustID + { + get => accoustIDField; + set => accoustIDField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + public SubChannelType SubChannel + { + get => subChannelField; + set => subChannelField = value; + } + + /// + [XmlArrayItem("Partition", IsNullable = false)] + public PartitionType[] FileSystemInformation + { + get => fileSystemInformationField; + set => fileSystemInformationField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum TrackTypeTrackType +{ + /// + audio, + + /// + mode0, + + /// + mode1, + + /// + mode2, + + /// + m2f1, + + /// + m2f2, + + /// + dvd, + + /// + hddvd, + + /// + bluray, + + /// + ddcd +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class PS3EncryptionType +{ + string keyField; + + string serialField; + + /// + public string Key + { + get => keyField; + set => keyField = value; + } + + /// + public string Serial + { + get => serialField; + set => serialField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class XboxSecuritySectorsType +{ + uint requestVersionField; + + uint requestNumberField; + + DumpType securitySectorsField; + + /// + public uint RequestVersion + { + get => requestVersionField; + set => requestVersionField = value; + } + + /// + public uint RequestNumber + { + get => requestNumberField; + set => requestNumberField = value; + } + + /// + public DumpType SecuritySectors + { + get => securitySectorsField; + set => securitySectorsField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class XboxType +{ + DumpType pFIField; + + DumpType dMIField; + + XboxSecuritySectorsType[] securitySectorsField; + + /// + public DumpType PFI + { + get => pFIField; + set => pFIField = value; + } + + /// + public DumpType DMI + { + get => dMIField; + set => dMIField = value; + } + + /// + [XmlElement("SecuritySectors")] + public XboxSecuritySectorsType[] SecuritySectors + { + get => securitySectorsField; + set => securitySectorsField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class BorderType +{ + string imageField; + + ulong sizeField; + + ChecksumType[] checksumsField; + + uint sessionField; + + bool sessionFieldSpecified; + + /// + public string Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + [XmlAttribute] + public uint session + { + get => sessionField; + set => sessionField = value; + } + + /// + [XmlIgnore] + public bool sessionSpecified + { + get => sessionFieldSpecified; + set => sessionFieldSpecified = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class CaseType +{ + CaseTypeCaseType caseType1Field; + + ScansType scansField; + + /// + [XmlElement("CaseType")] + public CaseTypeCaseType CaseType1 + { + get => caseType1Field; + set => caseType1Field = value; + } + + /// + public ScansType Scans + { + get => scansField; + set => scansField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum CaseTypeCaseType +{ + /// + jewel, + + /// + bigjewel, + + /// + slimjewel, + + /// + sleeve, + + /// + qpack, + + /// + digisleeve, + + /// + discboxslider, + + /// + compacplus, + + /// + keepcase, + + /// + snapcase, + + /// + softcase, + + /// + ecopack, + + /// + liftlock, + + /// + spindle, + + /// + ps2case, + + /// + ps3case, + + /// + bluraykeepcase, + + /// + pscase, + + /// + dccase, + + /// + saturncase, + + /// + xboxcase, + + /// + xbox360case, + + /// + xboxonecase, + + /// + saturnbigcase, + + /// + gccase, + + /// + wiicase, + + /// + unknown +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class LayeredTextType +{ + uint layerField; + + bool layerFieldSpecified; + + string valueField; + + /// + [XmlAttribute] + public uint layer + { + get => layerField; + set => layerField = value; + } + + /// + [XmlIgnore] + public bool layerSpecified + { + get => layerFieldSpecified; + set => layerFieldSpecified = value; + } + + /// + [XmlText] + public string Value + { + get => valueField; + set => valueField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class SectorsType +{ + uint layerField; + + bool layerFieldSpecified; + + ulong valueField; + + /// + [XmlAttribute] + public uint layer + { + get => layerField; + set => layerField = value; + } + + /// + [XmlIgnore] + public bool layerSpecified + { + get => layerFieldSpecified; + set => layerFieldSpecified = value; + } + + /// + [XmlText] + public ulong Value + { + get => valueField; + set => valueField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class LayersType +{ + SectorsType[] sectorsField; + + LayersTypeType typeField; + + bool typeFieldSpecified; + + /// + [XmlElement("Sectors")] + public SectorsType[] Sectors + { + get => sectorsField; + set => sectorsField = value; + } + + /// + [XmlAttribute] + public LayersTypeType type + { + get => typeField; + set => typeField = value; + } + + /// + [XmlIgnore] + public bool typeSpecified + { + get => typeFieldSpecified; + set => typeFieldSpecified = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum LayersTypeType +{ + /// + PTP, + + /// + OTP +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class OpticalDiscType +{ + ImageType imageField; + + ulong sizeField; + + SequenceType sequenceField; + + LayersType layersField; + + ChecksumType[] checksumsField; + + string partNumberField; + + string serialNumberField; + + LayeredTextType[] ringCodeField; + + LayeredTextType[] masteringSIDField; + + LayeredTextType[] toolstampField; + + LayeredTextType[] mouldSIDField; + + LayeredTextType[] mouldTextField; + + string discTypeField; + + string discSubTypeField; + + int offsetField; + + bool offsetFieldSpecified; + + uint[] tracksField; + + uint sessionsField; + + string copyProtectionField; + + DimensionsType dimensionsField; + + CaseType caseField; + + ScansType scansField; + + DumpType pFIField; + + DumpType dMIField; + + DumpType cMIField; + + DumpType bCAField; + + DumpType aTIPField; + + DumpType aDIPField; + + DumpType pMAField; + + DumpType dDSField; + + DumpType sAIField; + + DumpType lastRMDField; + + DumpType pRIField; + + DumpType mediaIDField; + + DumpType pFIRField; + + DumpType dCBField; + + DumpType diField; + + DumpType pACField; + + DumpType tOCField; + + DumpType leadInCdTextField; + + BorderType[] firstTrackPregrapField; + + BorderType[] leadInField; + + BorderType[] leadOutField; + + XboxType xboxField; + + PS3EncryptionType pS3EncryptionField; + + string mediaCatalogueNumberField; + + TrackType[] trackField; + + DumpHardwareType[] dumpHardwareArrayField; + + /// + public ImageType Image + { + get => imageField; + set => imageField = value; + } + + /// + public ulong Size + { + get => sizeField; + set => sizeField = value; + } + + /// + public SequenceType Sequence + { + get => sequenceField; + set => sequenceField = value; + } + + /// + public LayersType Layers + { + get => layersField; + set => layersField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + public string PartNumber + { + get => partNumberField; + set => partNumberField = value; + } + + /// + public string SerialNumber + { + get => serialNumberField; + set => serialNumberField = value; + } + + /// + [XmlElement("RingCode")] + public LayeredTextType[] RingCode + { + get => ringCodeField; + set => ringCodeField = value; + } + + /// + [XmlElement("MasteringSID")] + public LayeredTextType[] MasteringSID + { + get => masteringSIDField; + set => masteringSIDField = value; + } + + /// + [XmlElement("Toolstamp")] + public LayeredTextType[] Toolstamp + { + get => toolstampField; + set => toolstampField = value; + } + + /// + [XmlElement("MouldSID")] + public LayeredTextType[] MouldSID + { + get => mouldSIDField; + set => mouldSIDField = value; + } + + /// + [XmlElement("MouldText")] + public LayeredTextType[] MouldText + { + get => mouldTextField; + set => mouldTextField = value; + } + + /// + public string DiscType + { + get => discTypeField; + set => discTypeField = value; + } + + /// + public string DiscSubType + { + get => discSubTypeField; + set => discSubTypeField = value; + } + + /// + public int Offset + { + get => offsetField; + set => offsetField = value; + } + + /// + [XmlIgnore] + public bool OffsetSpecified + { + get => offsetFieldSpecified; + set => offsetFieldSpecified = value; + } + + /// + [XmlElement("Tracks")] + public uint[] Tracks + { + get => tracksField; + set => tracksField = value; + } + + /// + public uint Sessions + { + get => sessionsField; + set => sessionsField = value; + } + + /// + public string CopyProtection + { + get => copyProtectionField; + set => copyProtectionField = value; + } + + /// + public DimensionsType Dimensions + { + get => dimensionsField; + set => dimensionsField = value; + } + + /// + public CaseType Case + { + get => caseField; + set => caseField = value; + } + + /// + public ScansType Scans + { + get => scansField; + set => scansField = value; + } + + /// + public DumpType PFI + { + get => pFIField; + set => pFIField = value; + } + + /// + public DumpType DMI + { + get => dMIField; + set => dMIField = value; + } + + /// + public DumpType CMI + { + get => cMIField; + set => cMIField = value; + } + + /// + public DumpType BCA + { + get => bCAField; + set => bCAField = value; + } + + /// + public DumpType ATIP + { + get => aTIPField; + set => aTIPField = value; + } + + /// + public DumpType ADIP + { + get => aDIPField; + set => aDIPField = value; + } + + /// + public DumpType PMA + { + get => pMAField; + set => pMAField = value; + } + + /// + public DumpType DDS + { + get => dDSField; + set => dDSField = value; + } + + /// + public DumpType SAI + { + get => sAIField; + set => sAIField = value; + } + + /// + public DumpType LastRMD + { + get => lastRMDField; + set => lastRMDField = value; + } + + /// + public DumpType PRI + { + get => pRIField; + set => pRIField = value; + } + + /// + public DumpType MediaID + { + get => mediaIDField; + set => mediaIDField = value; + } + + /// + public DumpType PFIR + { + get => pFIRField; + set => pFIRField = value; + } + + /// + public DumpType DCB + { + get => dCBField; + set => dCBField = value; + } + + /// + public DumpType DI + { + get => diField; + set => diField = value; + } + + /// + public DumpType PAC + { + get => pACField; + set => pACField = value; + } + + /// + public DumpType TOC + { + get => tOCField; + set => tOCField = value; + } + + /// + public DumpType LeadInCdText + { + get => leadInCdTextField; + set => leadInCdTextField = value; + } + + /// + [XmlElement("FirstTrackPregrap")] + public BorderType[] FirstTrackPregrap + { + get => firstTrackPregrapField; + set => firstTrackPregrapField = value; + } + + /// + [XmlElement("LeadIn")] + public BorderType[] LeadIn + { + get => leadInField; + set => leadInField = value; + } + + /// + [XmlElement("LeadOut")] + public BorderType[] LeadOut + { + get => leadOutField; + set => leadOutField = value; + } + + /// + public XboxType Xbox + { + get => xboxField; + set => xboxField = value; + } + + /// + public PS3EncryptionType PS3Encryption + { + get => pS3EncryptionField; + set => pS3EncryptionField = value; + } + + /// + public string MediaCatalogueNumber + { + get => mediaCatalogueNumberField; + set => mediaCatalogueNumberField = value; + } + + /// + [XmlElement("Track")] + public TrackType[] Track + { + get => trackField; + set => trackField = value; + } + + /// + [XmlArrayItem("DumpHardware", IsNullable = false)] + public DumpHardwareType[] DumpHardwareArray + { + get => dumpHardwareArrayField; + set => dumpHardwareArrayField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class UserManualType +{ + LanguagesTypeLanguage[] languageField; + + uint pagesField; + + string pageSizeField; + + ScanType scanField; + + /// + [XmlArrayItem("Language", IsNullable = false)] + public LanguagesTypeLanguage[] Language + { + get => languageField; + set => languageField = value; + } + + /// + public uint Pages + { + get => pagesField; + set => pagesField = value; + } + + /// + public string PageSize + { + get => pageSizeField; + set => pageSizeField = value; + } + + /// + public ScanType Scan + { + get => scanField; + set => scanField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class RequiredOperatingSystemType +{ + string nameField; + + string[] versionField; + + /// + public string Name + { + get => nameField; + set => nameField = value; + } + + /// + [XmlElement("Version")] + public string[] Version + { + get => versionField; + set => versionField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class BookType +{ + BarcodeType[] barcodesField; + + CoverType coverField; + + string nameField; + + string editorialField; + + string authorField; + + DateTime publicationDateField; + + bool publicationDateFieldSpecified; + + LanguagesTypeLanguage[] languageField; + + uint pagesField; + + bool pagesFieldSpecified; + + string pageSizeField; + + ScanType scanField; + + /// + [XmlArrayItem("Barcode", IsNullable = false)] + public BarcodeType[] Barcodes + { + get => barcodesField; + set => barcodesField = value; + } + + /// + public CoverType Cover + { + get => coverField; + set => coverField = value; + } + + /// + public string Name + { + get => nameField; + set => nameField = value; + } + + /// + public string Editorial + { + get => editorialField; + set => editorialField = value; + } + + /// + public string Author + { + get => authorField; + set => authorField = value; + } + + /// + [XmlElement(DataType = "date")] + public DateTime PublicationDate + { + get => publicationDateField; + set => publicationDateField = value; + } + + /// + [XmlIgnore] + public bool PublicationDateSpecified + { + get => publicationDateFieldSpecified; + set => publicationDateFieldSpecified = value; + } + + /// + [XmlArrayItem("Language", IsNullable = false)] + public LanguagesTypeLanguage[] Language + { + get => languageField; + set => languageField = value; + } + + /// + public uint Pages + { + get => pagesField; + set => pagesField = value; + } + + /// + [XmlIgnore] + public bool PagesSpecified + { + get => pagesFieldSpecified; + set => pagesFieldSpecified = value; + } + + /// + public string PageSize + { + get => pageSizeField; + set => pageSizeField = value; + } + + /// + public ScanType Scan + { + get => scanField; + set => scanField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class CoverType +{ + FileType fileField; + + ChecksumType[] checksumsField; + + byte[] thumbnailField; + + /// + public FileType File + { + get => fileField; + set => fileField = value; + } + + /// + [XmlArrayItem("Checksum", IsNullable = false)] + public ChecksumType[] Checksums + { + get => checksumsField; + set => checksumsField = value; + } + + /// + [XmlElement(DataType = "base64Binary")] + public byte[] Thumbnail + { + get => thumbnailField; + set => thumbnailField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, DebuggerStepThrough, DesignerCategory("code")] +public class MagazineType +{ + BarcodeType[] barcodesField; + + CoverType coverField; + + string nameField; + + string editorialField; + + DateTime publicationDateField; + + bool publicationDateFieldSpecified; + + uint numberField; + + bool numberFieldSpecified; + + LanguagesTypeLanguage[] languageField; + + uint pagesField; + + bool pagesFieldSpecified; + + string pageSizeField; + + ScanType scanField; + + /// + [XmlArrayItem("Barcode", IsNullable = false)] + public BarcodeType[] Barcodes + { + get => barcodesField; + set => barcodesField = value; + } + + /// + public CoverType Cover + { + get => coverField; + set => coverField = value; + } + + /// + public string Name + { + get => nameField; + set => nameField = value; + } + + /// + public string Editorial + { + get => editorialField; + set => editorialField = value; + } + + /// + [XmlElement(DataType = "date")] + public DateTime PublicationDate + { + get => publicationDateField; + set => publicationDateField = value; + } + + /// + [XmlIgnore] + public bool PublicationDateSpecified + { + get => publicationDateFieldSpecified; + set => publicationDateFieldSpecified = value; + } + + /// + public uint Number + { + get => numberField; + set => numberField = value; + } + + /// + [XmlIgnore] + public bool NumberSpecified + { + get => numberFieldSpecified; + set => numberFieldSpecified = value; + } + + /// + [XmlArrayItem("Language", IsNullable = false)] + public LanguagesTypeLanguage[] Language + { + get => languageField; + set => languageField = value; + } + + /// + public uint Pages + { + get => pagesField; + set => pagesField = value; + } + + /// + [XmlIgnore] + public bool PagesSpecified + { + get => pagesFieldSpecified; + set => pagesFieldSpecified = value; + } + + /// + public string PageSize + { + get => pageSizeField; + set => pageSizeField = value; + } + + /// + public ScanType Scan + { + get => scanField; + set => scanField = value; + } +} + +/// +[GeneratedCode("xsd", "0.0.0.0"), SerializableAttribute, XmlType(AnonymousType = true)] +public enum ArchitecturesTypeArchitecture +{ + /// + [XmlEnum("4004")] + Item4004, + + /// + [XmlEnum("4040")] + Item4040, + + /// + [XmlEnum("6502")] + Item6502, + + /// + [XmlEnum("65816")] + Item65816, + + /// + [XmlEnum("8008")] + Item8008, + + /// + [XmlEnum("8051")] + Item8051, + + /// + [XmlEnum("8080")] + Item8080, + + /// + [XmlEnum("8085")] + Item8085, + + /// + aarch64, + + /// + am29000, + + /// + amd64, + + /// + apx432, + + /// + arm, + + /// + avr, + + /// + avr32, + + /// + axp, + + /// + clipper, + + /// + cray, + + /// + esa390, + + /// + hobbit, + + /// + i86, + + /// + i860, + + /// + i960, + + /// + ia32, + + /// + ia64, + + /// + m56k, + + /// + m6800, + + /// + m6801, + + /// + m6805, + + /// + m6809, + + /// + m68k, + + /// + m88k, + + /// + mcs41, + + /// + mcs48, + + /// + mips32, + + /// + mips64, + + /// + msp430, + + /// + nios2, + + /// + openrisc, + + /// + parisc, + + /// + pdp1, + + /// + pdp10, + + /// + pdp11, + + /// + pdp7, + + /// + pdp8, + + /// + pic, + + /// + power, + + /// + ppc, + + /// + ppc64, + + /// + prism, + + /// + renesasrx, + + /// + riscv, + + /// + s360, + + /// + s370, + + /// + sh, + + /// + sh1, + + /// + sh2, + + /// + sh3, + + /// + sh4, + + /// + sh5, + + /// + sh64, + + /// + sparc, + + /// + sparc64, + + /// + transputer, + + /// + vax, + + /// + we32000, + + /// + x32, + + /// + z80, + + /// + z800, + + /// + z8000, + + /// + z80000, + + /// + zarch +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Partition.cs b/Aaru.CommonTypes/Partition.cs new file mode 100644 index 000000000..6b9e313e5 --- /dev/null +++ b/Aaru.CommonTypes/Partition.cs @@ -0,0 +1,118 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Partition.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru common types. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains common partition types. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; + +#pragma warning disable CS1591 +namespace Aaru.CommonTypes; + +/// +/// Partition structure. +public struct Partition : IEquatable, IComparable +{ + /// Partition number, 0-started + public ulong Sequence; + /// Partition type + public string Type; + /// Partition name (if the scheme supports it) + public string Name; + /// Start of the partition, in bytes + public ulong Offset; + /// LBA of partition start + public ulong Start; + /// Length in bytes of the partition + public ulong Size; + /// Length in sectors of the partition + public ulong Length; + /// Information that does not find space in this struct + public string Description; + + /// LBA of last partition sector + public readonly ulong End => Start + Length - 1; + + /// Name of partition scheme that contains this partition + public string Scheme; + + /// + /// Compares two partitions + /// Partition to compare with + /// 0 if both partitions start and end at the same sector + public bool Equals(Partition other) => Start == other.Start && Length == other.Length; + + /// + public override bool Equals(object obj) => obj is Partition partition && Equals(partition); + + /// + + // ReSharper disable once NonReadonlyMemberInGetHashCode + public readonly override int GetHashCode() => Start.GetHashCode() + End.GetHashCode(); + + /// + /// Compares this partition with another and returns an integer that indicates whether the current partition + /// precedes, follows, or is in the same place as the other partition. + /// + /// Partition to compare with + /// A value that indicates the relative equality of the partitions being compared. + /// + public int CompareTo(Partition other) + { + if(Start == other.Start && End == other.End) return 0; + + if(Start > other.Start || End > other.End) return 1; + + return -1; + } + + // Define the equality operator. + public static bool operator ==(Partition operand1, Partition operand2) => operand1.Equals(operand2); + + // Define the inequality operator. + public static bool operator !=(Partition operand1, Partition operand2) => !operand1.Equals(operand2); + + // Define the is greater than operator. + public static bool operator >(Partition operand1, Partition operand2) => operand1.CompareTo(operand2) == 1; + + // Define the is less than operator. + public static bool operator <(Partition operand1, Partition operand2) => operand1.CompareTo(operand2) == -1; + + // Define the is greater than or equal to operator. + public static bool operator >=(Partition operand1, Partition operand2) => operand1.CompareTo(operand2) >= 0; + + // Define the is less than or equal to operator. + public static bool operator <=(Partition operand1, Partition operand2) => operand1.CompareTo(operand2) <= 0; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/PluginRegister.cs b/Aaru.CommonTypes/PluginRegister.cs new file mode 100644 index 000000000..af03e8665 --- /dev/null +++ b/Aaru.CommonTypes/PluginRegister.cs @@ -0,0 +1,288 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PluginRegister.cs +// Author(s) : Natalia Portillo +// +// Component : Common types. +// +// --[ Description ] ---------------------------------------------------------- +// +// Gets lists of all known plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Microsoft.Extensions.DependencyInjection; + +namespace Aaru.CommonTypes; + +public class PluginRegister +{ + static PluginRegister _instance; + + + IServiceProvider _serviceProvider; + IServiceCollection _services; + + PluginRegister() {} + + /// List of byte addressable image plugins + public SortedDictionary ByteAddressableImages + { + get + { + SortedDictionary byteAddressableImages = new(); + + foreach(IByteAddressableImage plugin in _serviceProvider.GetServices()) + byteAddressableImages[plugin.Name.ToLower()] = plugin; + + return byteAddressableImages; + } + } + + /// List of writable media image plugins + public SortedDictionary WritableImages + { + get + { + SortedDictionary mediaImages = new(); + + foreach(IBaseWritableImage plugin in _serviceProvider.GetServices()) + mediaImages[plugin.Name.ToLower()] = plugin; + + return mediaImages; + } + } + + /// List of writable floppy image plugins + public SortedDictionary WritableFloppyImages + { + get + { + SortedDictionary floppyImages = new(); + + foreach(IWritableFloppyImage plugin in _serviceProvider.GetServices()) + floppyImages[plugin.Name.ToLower()] = plugin; + + return floppyImages; + } + } + + /// List of floppy image plugins + public SortedDictionary FloppyImages + { + get + { + SortedDictionary floppyImages = new(); + + foreach(IFloppyImage plugin in _serviceProvider.GetServices()) + floppyImages[plugin.Name.ToLower()] = plugin; + + return floppyImages; + } + } + + /// List of all media image plugins + public SortedDictionary MediaImages + { + get + { + SortedDictionary mediaImages = new(); + + foreach(IMediaImage plugin in _serviceProvider.GetServices()) + mediaImages[plugin.Name.ToLower()] = plugin; + + return mediaImages; + } + } + + /// List of read-only filesystem plugins + public SortedDictionary ReadOnlyFilesystems + { + get + { + SortedDictionary readOnlyFilesystems = new(); + + foreach(IReadOnlyFilesystem plugin in _serviceProvider.GetServices()) + readOnlyFilesystems[plugin.Name.ToLower()] = plugin; + + return readOnlyFilesystems; + } + } + + /// List of all filesystem plugins + public SortedDictionary Filesystems + { + get + { + SortedDictionary filesystems = new(); + + foreach(IFilesystem plugin in _serviceProvider.GetServices()) + filesystems[plugin.Name.ToLower()] = plugin; + + return filesystems; + } + } + + /// List of all archive formats + public SortedDictionary Archives + { + get + { + SortedDictionary archives = new(); + + foreach(IArchive plugin in _serviceProvider.GetServices()) + archives[plugin.Name.ToLower()] = plugin; + + return archives; + } + } + + /// List of all partition plugins + public SortedDictionary Partitions + { + get + { + SortedDictionary partitions = new(); + + foreach(IPartition plugin in _serviceProvider.GetServices()) + partitions[plugin.Name.ToLower()] = plugin; + + return partitions; + } + } + + /// List of filter plugins + public SortedDictionary Filters + { + get + { + SortedDictionary filters = new(); + + foreach(IFilter plugin in _serviceProvider.GetServices()) filters[plugin.Name.ToLower()] = plugin; + + return filters; + } + } + + /// List of checksum plugins + public SortedDictionary Checksums + { + get + { + SortedDictionary checksums = new(); + + foreach(IChecksum plugin in _serviceProvider.GetServices()) + checksums[plugin.Name.ToLower()] = plugin; + + return checksums; + } + } + + /// Gets a singleton with all the known plugins + public static PluginRegister Singleton + { + get + { + if(_instance != null) return _instance; + + _instance = new PluginRegister + { + _services = new ServiceCollection() + }; + + _instance._serviceProvider = _instance._services.BuildServiceProvider(); + + return _instance; + } + } + + + /// + /// Replaces registered plugins list of this instance with the new ones provided by the providen registrators. + /// + /// List of plugin registrators as obtained from the assemblies that implement them. + public void InitPlugins(IEnumerable registrators) + { + _services = new ServiceCollection(); + + foreach(IPluginRegister registrator in registrators) AddPlugins(registrator); + + _instance._serviceProvider = _instance._services.BuildServiceProvider(); + } + + /// Adds plugins to the central plugin register + /// Plugin register + void AddPlugins(IPluginRegister pluginRegister) + { + pluginRegister.RegisterChecksumPlugins(_services); + pluginRegister.RegisterFilesystemPlugins(_services); + pluginRegister.RegisterFilterPlugins(_services); + pluginRegister.RegisterReadOnlyFilesystemPlugins(_services); + pluginRegister.RegisterFloppyImagePlugins(_services); + pluginRegister.RegisterMediaImagePlugins(_services); + pluginRegister.RegisterPartitionPlugins(_services); + pluginRegister.RegisterWritableFloppyImagePlugins(_services); + pluginRegister.RegisterWritableImagePlugins(_services); + pluginRegister.RegisterArchivePlugins(_services); + pluginRegister.RegisterByteAddressablePlugins(_services); + } + + /// Gets the filter that allows to read the specified path + /// Path + /// The filter that allows reading the specified path + public IFilter GetFilter(string path) + { + IFilter noFilter = null; + + foreach(IFilter filter in Filters.Values) + { + try + { + if(filter.Id != new Guid("12345678-AAAA-BBBB-CCCC-123456789000")) + { + if(!filter.Identify(path)) continue; + + var foundFilter = (IFilter)filter.GetType().GetConstructor(Type.EmptyTypes)?.Invoke([]); + + if(foundFilter?.Open(path) == ErrorNumber.NoError) return foundFilter; + } + else + noFilter = filter; + } + catch(IOException) + { + // Ignore and continue + } + } + + if(!noFilter?.Identify(path) == true) return null; + + noFilter?.Open(path); + + return noFilter; + } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Structs/Devices/ATA/Identify.cs b/Aaru.CommonTypes/Structs/Devices/ATA/Identify.cs new file mode 100644 index 000000000..11341bfa6 --- /dev/null +++ b/Aaru.CommonTypes/Structs/Devices/ATA/Identify.cs @@ -0,0 +1,1272 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Identify.cs +// Author(s) : Natalia Portillo +// +// Component : Common structures for ATA devices. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines a high level interpretation of the ATA IDENTIFY response. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Global + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; +using Marshal = Aaru.Helpers.Marshal; + +namespace Aaru.CommonTypes.Structs.Devices.ATA; + +/// +/// Information from following standards: T10-791D rev. 4c (ATA) T10-948D rev. 4c (ATA-2) T13-1153D rev. 18 +/// (ATA/ATAPI-4) T13-1321D rev. 3 (ATA/ATAPI-5) T13-1410D rev. 3b (ATA/ATAPI-6) T13-1532D rev. 4b (ATA/ATAPI-7) +/// T13-1699D rev. 3f (ATA8-ACS) T13-1699D rev. 4a (ATA8-ACS) T13-2015D rev. 2 (ACS-2) T13-2161D rev. 5 (ACS-3) CF+ +/// & CF Specification rev. 1.4 (CFA) +/// +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Identify +{ +#region CapabilitiesBit enum + + /// Capabilities flag bits. + [Flags] + public enum CapabilitiesBit : ushort + { + /// ATAPI: Interleaved DMA supported + InterleavedDMA = 0x8000, + /// ATAPI: Command queueing supported + CommandQueue = 0x4000, + /// Standby timer values are standard + StandardStandbyTimer = 0x2000, + /// ATAPI: Overlap operation supported + OverlapOperation = 0x2000, + /// ATAPI: ATA software reset required Obsoleted in ATA/ATAPI-4 + RequiresATASoftReset = 0x1000, + /// IORDY is supported + IORDY = 0x0800, + /// IORDY can be disabled + CanDisableIORDY = 0x0400, + /// LBA is supported + LBASupport = 0x0200, + /// DMA is supported + DMASupport = 0x0100, + /// Vendor unique Obsoleted in ATA/ATAPI-4 + VendorBit7 = 0x0080, + /// Vendor unique Obsoleted in ATA/ATAPI-4 + VendorBit6 = 0x0040, + /// Vendor unique Obsoleted in ATA/ATAPI-4 + VendorBit5 = 0x0020, + /// Vendor unique Obsoleted in ATA/ATAPI-4 + VendorBit4 = 0x0010, + /// Vendor unique Obsoleted in ATA/ATAPI-4 + VendorBit3 = 0x0008, + /// Vendor unique Obsoleted in ATA/ATAPI-4 + VendorBit2 = 0x0004, + /// Long Physical Alignment setting bit 1 + PhysicalAlignment1 = 0x0002, + /// Long Physical Alignment setting bit 0 + PhysicalAlignment0 = 0x0001 + } + +#endregion + +#region CapabilitiesBit2 enum + + /// More capabilities flag bits. + [Flags] + public enum CapabilitiesBit2 : ushort + { + /// MUST NOT be set + MustBeClear = 0x8000, + /// MUST be set + MustBeSet = 0x4000, +#pragma warning disable 1591 + Reserved13 = 0x2000, + Reserved12 = 0x1000, + Reserved11 = 0x0800, + Reserved10 = 0x0400, + Reserved09 = 0x0200, + Reserved08 = 0x0100, + Reserved07 = 0x0080, + Reserved06 = 0x0040, + Reserved05 = 0x0020, + Reserved04 = 0x0010, + Reserved03 = 0x0008, + Reserved02 = 0x0004, + Reserved01 = 0x0002, +#pragma warning restore 1591 + /// Indicates a device specific minimum standby timer value + SpecificStandbyTimer = 0x0001 + } + +#endregion + +#region CapabilitiesBit3 enum + + /// Even more capabilities flag bits. + [Flags] + public enum CapabilitiesBit3 : byte + { + /// BLOCK ERASE EXT supported + BlockErase = 0x0080, + /// OVERWRITE EXT supported + Overwrite = 0x0040, + /// CRYPTO SCRAMBLE EXT supported + CryptoScramble = 0x0020, + /// Sanitize feature set is supported + Sanitize = 0x0010, + /// If unset, sanitize commands are specified by ACS-2 + SanitizeCommands = 0x0008, + /// SANITIZE ANTIFREEZE LOCK EXT is supported + SanitizeAntifreeze = 0x0004, +#pragma warning disable 1591 + Reserved01 = 0x0002, +#pragma warning restore 1591 + /// Multiple logical sector setting is valid + MultipleValid = 0x0001 + } + +#endregion + +#region CommandSetBit enum + + /// Command set flag bits. + [Flags] + public enum CommandSetBit : ushort + { + /// Already obsolete in ATA/ATAPI-4, reserved in ATA3 + Obsolete15 = 0x8000, + /// NOP is supported + Nop = 0x4000, + /// READ BUFFER is supported + ReadBuffer = 0x2000, + /// WRITE BUFFER is supported + WriteBuffer = 0x1000, + /// Already obsolete in ATA/ATAPI-4, reserved in ATA3 + Obsolete11 = 0x0800, + /// Host Protected Area is supported + HPA = 0x0400, + /// DEVICE RESET is supported + DeviceReset = 0x0200, + /// SERVICE interrupt is supported + Service = 0x0100, + /// Release is supported + Release = 0x0080, + /// Look-ahead is supported + LookAhead = 0x0040, + /// Write cache is supported + WriteCache = 0x0020, + /// PACKET command set is supported + Packet = 0x0010, + /// Power Management feature set is supported + PowerManagement = 0x0008, + /// Removable Media feature set is supported + RemovableMedia = 0x0004, + /// Security Mode feature set is supported + SecurityMode = 0x0002, + /// SMART feature set is supported + SMART = 0x0001 + } + +#endregion + +#region CommandSetBit2 enum + + /// More command set flag bits. + [Flags] + public enum CommandSetBit2 : ushort + { + /// MUST NOT be set + MustBeClear = 0x8000, + /// MUST BE SET + MustBeSet = 0x4000, + /// FLUSH CACHE EXT supported + FlushCacheExt = 0x2000, + /// FLUSH CACHE supported + FlushCache = 0x1000, + /// Device Configuration Overlay feature set supported + DCO = 0x0800, + /// 48-bit LBA supported + LBA48 = 0x0400, + /// Automatic Acoustic Management supported + AAM = 0x0200, + /// SET MAX security extension supported + SetMax = 0x0100, + /// Address Offset Reserved Area Boot NCITS TR27:2001 + AddressOffsetReservedAreaBoot = 0x0080, + /// SET FEATURES required to spin-up + SetFeaturesRequired = 0x0040, + /// Power-Up in standby feature set supported + PowerUpInStandby = 0x0020, + /// Removable Media Status Notification feature set is supported + RemovableNotification = 0x0010, + /// Advanced Power Management feature set is supported + APM = 0x0008, + /// Compact Flash feature set is supported + CompactFlash = 0x0004, + /// READ DMA QUEUED and WRITE DMA QUEUED are supported + RWQueuedDMA = 0x0002, + /// DOWNLOAD MICROCODE is supported + DownloadMicrocode = 0x0001 + } + +#endregion + +#region CommandSetBit3 enum + + /// Even more command set flag bits. + [Flags] + public enum CommandSetBit3 : ushort + { + /// MUST NOT be set + MustBeClear = 0x8000, + /// MUST BE SET + MustBeSet = 0x4000, + /// IDLE IMMEDIATE with UNLOAD FEATURE is supported + IdleImmediate = 0x2000, + /// Reserved for INCITS TR-37/2004 + Reserved12 = 0x1000, + /// Reserved for INCITS TR-37/2004 + Reserved11 = 0x0800, + /// URG bit is supported in WRITE STREAM DMA EXT and WRITE STREAM EXT + WriteURG = 0x0400, + /// URG bit is supported in READ STREAM DMA EXT and READ STREAM EXT + ReadURG = 0x0200, + /// 64-bit World Wide Name is supported + WWN = 0x0100, + /// WRITE DMA QUEUED FUA EXT is supported + FUAWriteQ = 0x0080, + /// WRITE DMA FUA EXT and WRITE MULTIPLE FUA EXT are supported + FUAWrite = 0x0040, + /// General Purpose Logging feature supported + GPL = 0x0020, + /// Streaming feature set is supported + Streaming = 0x0010, + /// Media Card Pass Through command set supported + MCPT = 0x0008, + /// Media serial number supported + MediaSerial = 0x0004, + /// SMART self-test supported + SMARTSelfTest = 0x0002, + /// SMART error logging supported + SMARTLog = 0x0001 + } + +#endregion + +#region CommandSetBit4 enum + + /// Yet more command set flag bits. + [Flags] + public enum CommandSetBit4 : ushort + { + /// MUST NOT be set + MustBeClear = 0x8000, + /// MUST be set + MustBeSet = 0x4000, +#pragma warning disable 1591 + Reserved13 = 0x2000, + Reserved12 = 0x1000, + Reserved11 = 0x0800, + Reserved10 = 0x0400, +#pragma warning restore 1591 + /// DSN feature set is supported + DSN = 0x0200, + /// Accessible Max Address Configuration is supported + AMAC = 0x0100, + /// Extended Power Conditions is supported + ExtPowerCond = 0x0080, + /// Extended Status Reporting is supported + ExtStatusReport = 0x0040, + /// Free-fall Control feature set is supported + FreeFallControl = 0x0020, + /// Supports segmented feature in DOWNLOAD MICROCODE + SegmentedDownloadMicrocode = 0x0010, + /// READ/WRITE DMA EXT GPL are supported + RWDMAExtGpl = 0x0008, + /// WRITE UNCORRECTABLE is supported + WriteUnc = 0x0004, + /// Write/Read/Verify is supported + WRV = 0x0002, + /// Reserved for DT1825 + DT1825 = 0x0001 + } + +#endregion + +#region CommandSetBit5 enum + + /// Yet again more command set flag bits. + [Flags] + public enum CommandSetBit5 : ushort + { + /// Supports CFast Specification + CFast = 0x8000, + /// Deterministic read after TRIM is supported + DeterministicTrim = 0x4000, + /// Long physical sector alignment error reporting control is supported + LongPhysSectorAligError = 0x2000, + /// DEVICE CONFIGURATION IDENTIFY DMA and DEVICE CONFIGURATION SET DMA are supported + DeviceConfDMA = 0x1000, + /// READ BUFFER DMA is supported + ReadBufferDMA = 0x0800, + /// WRITE BUFFER DMA is supported + WriteBufferDMA = 0x0400, + /// SET PASSWORD DMA and SET UNLOCK DMA are supported + SetMaxDMA = 0x0200, + /// DOWNLOAD MICROCODE DMA is supported + DownloadMicroCodeDMA = 0x0100, + /// Reserved for IEEE-1667 + IEEE1667 = 0x0080, + /// Optional ATA 28-bit commands are supported + Ata28 = 0x0040, + /// Read zero after TRIM is supported + ReadZeroTrim = 0x0020, + /// Device encrypts all user data + Encrypted = 0x0010, + /// Extended number of user addressable sectors is supported + ExtSectors = 0x0008, + /// All write cache is non-volatile + AllCacheNV = 0x0004, + /// Zoned capabilities bit 1 + ZonedBit1 = 0x0002, + /// Zoned capabilities bit 0 + ZonedBit0 = 0x0001 + } + +#endregion + +#region DataSetMgmtBit enum + + /// Data set management flag bits. + [Flags] + public enum DataSetMgmtBit : ushort + { +#pragma warning disable 1591 + Reserved15 = 0x8000, + Reserved14 = 0x4000, + Reserved13 = 0x2000, + Reserved12 = 0x1000, + Reserved11 = 0x0800, + Reserved10 = 0x0400, + Reserved09 = 0x0200, + Reserved08 = 0x0100, + Reserved07 = 0x0080, + Reserved06 = 0x0040, + Reserved05 = 0x0020, + Reserved04 = 0x0010, + Reserved03 = 0x0008, + Reserved02 = 0x0004, + Reserved01 = 0x0002, +#pragma warning restore 1591 + /// TRIM is supported + Trim = 0x0001 + } + +#endregion + +#region DeviceFormFactorEnum enum + + /// Device form factor + public enum DeviceFormFactorEnum : ushort + { + /// Size not reported + NotReported = 0, + /// 5.25" + FiveAndQuarter = 1, + /// 3.5" + ThreeAndHalf = 2, + /// 2.5" + TwoAndHalf = 3, + /// 1.8" + OnePointEight = 4, + /// Less than 1.8" + LessThanOnePointEight = 5 + } + +#endregion + +#region ExtendedIdentifyBit enum + + /// Extended identify flag bits. + [Flags] + public enum ExtendedIdentifyBit : byte + { + /// Reserved + Reserved07 = 0x80, + /// Reserved + Reserved06 = 0x40, + /// Reserved + Reserved05 = 0x20, + /// Reserved + Reserved04 = 0x10, + /// Reserved + Reserved03 = 0x08, + /// Identify word 88 is valid + Word88Valid = 0x04, + /// Identify words 64 to 70 are valid + Words64to70Valid = 0x02, + /// Identify words 54 to 58 are valid + Words54to58Valid = 0x01 + } + +#endregion + +#region GeneralConfigurationBit enum + + /// General configuration flag bits. + [Flags] + public enum GeneralConfigurationBit : ushort + { + /// Set on ATAPI + NonMagnetic = 0x8000, + /// Format speed tolerance gap is required Obsoleted in ATA-2 + FormatGapReq = 0x4000, + /// Track offset option is available Obsoleted in ATA-2 + TrackOffset = 0x2000, + /// Data strobe offset option is available Obsoleted in ATA-2 + DataStrobeOffset = 0x1000, + /// Rotational speed tolerance is higher than 0,5% Obsoleted in ATA-2 + RotationalSpeedTolerance = 0x0800, + /// Disk transfer rate is > 10 Mb/s Obsoleted in ATA-2 + UltraFastIDE = 0x0400, + /// Disk transfer rate is > 5 Mb/s but <= 10 Mb/s Obsoleted in ATA-2 + FastIDE = 0x0200, + /// Disk transfer rate is <= 5 Mb/s Obsoleted in ATA-2 + SlowIDE = 0x0100, + /// Drive uses removable media + Removable = 0x0080, + /// Drive is fixed Obsoleted in ATA/ATAPI-6 + Fixed = 0x0040, + /// Spindle motor control is implemented Obsoleted in ATA-2 + SpindleControl = 0x0020, + /// Head switch time is bigger than 15 µsec. Obsoleted in ATA-2 + HighHeadSwitch = 0x0010, + /// Drive is not MFM encoded Obsoleted in ATA-2 + NotMFM = 0x0008, + /// Drive is soft sectored Obsoleted in ATA-2 + SoftSector = 0x0004, + /// Response incomplete Since ATA/ATAPI-5 + IncompleteResponse = 0x0004, + /// Drive is hard sectored Obsoleted in ATA-2 + HardSector = 0x0002, + /// Reserved + Reserved = 0x0001 + } + +#endregion + +#region MajorVersionBit enum + + /// Word 80 Major version + [Flags] + public enum MajorVersionBit : ushort + { +#pragma warning disable 1591 + Reserved15 = 0x8000, + Reserved14 = 0x4000, + Reserved13 = 0x2000, + Reserved12 = 0x1000, +#pragma warning restore 1591 + /// ACS-4 + ACS4 = 0x0800, + /// ACS-3 + ACS3 = 0x0400, + /// ACS-2 + ACS2 = 0x0200, + /// ATA8-ACS + Ata8ACS = 0x0100, + /// ATA/ATAPI-7 + AtaAtapi7 = 0x0080, + /// ATA/ATAPI-6 + AtaAtapi6 = 0x0040, + /// ATA/ATAPI-5 + AtaAtapi5 = 0x0020, + /// ATA/ATAPI-4 + AtaAtapi4 = 0x0010, + /// ATA-3 + Ata3 = 0x0008, + /// ATA-2 + Ata2 = 0x0004, + /// ATA-1 + Ata1 = 0x0002, +#pragma warning disable 1591 + Reserved00 = 0x0001 +#pragma warning restore 1591 + } + +#endregion + +#region SATACapabilitiesBit enum + + /// SATA capabilities flags + [Flags] + public enum SATACapabilitiesBit : ushort + { + /// Supports READ LOG DMA EXT + ReadLogDMAExt = 0x8000, + /// Supports device automatic partial to slumber transitions + DevSlumbTrans = 0x4000, + /// Supports host automatic partial to slumber transitions + HostSlumbTrans = 0x2000, + /// Supports NCQ priority + NCQPriority = 0x1000, + /// Supports unload while NCQ commands are outstanding + UnloadNCQ = 0x0800, + /// Supports PHY Event Counters + PHYEventCounter = 0x0400, + /// Supports receipt of host initiated power management requests + PowerReceipt = 0x0200, + /// Supports NCQ + NCQ = 0x0100, +#pragma warning disable 1591 + Reserved07 = 0x0080, + Reserved06 = 0x0040, + Reserved05 = 0x0020, + Reserved04 = 0x0010, +#pragma warning restore 1591 + /// Supports SATA Gen. 3 Signaling Speed (6.0Gb/s) + Gen3Speed = 0x0008, + /// Supports SATA Gen. 2 Signaling Speed (3.0Gb/s) + Gen2Speed = 0x0004, + /// Supports SATA Gen. 1 Signaling Speed (1.5Gb/s) + Gen1Speed = 0x0002, + /// MUST NOT be set + Clear = 0x0001 + } + +#endregion + +#region SATACapabilitiesBit2 enum + + /// More SATA capabilities flags + [Flags] + public enum SATACapabilitiesBit2 : ushort + { +#pragma warning disable 1591 + Reserved15 = 0x8000, + Reserved14 = 0x4000, + Reserved13 = 0x2000, + Reserved12 = 0x1000, + Reserved11 = 0x0800, + Reserved10 = 0x0400, + Reserved09 = 0x0200, + Reserved08 = 0x0100, + Reserved07 = 0x0080, +#pragma warning restore 1591 + /// Supports RECEIVE FPDMA QUEUED and SEND FPDMA QUEUED + FPDMAQ = 0x0040, + /// Supports NCQ Queue Management + NCQMgmt = 0x0020, + /// ATAPI: Supports host environment detect + HostEnvDetect = 0x0020, + /// Supports NCQ streaming + NCQStream = 0x0010, + /// ATAPI: Supports device attention on slimline connected devices + DevAttSlimline = 0x0010, + /// Coded value indicating current negotiated Serial ATA signal speed + CurrentSpeedBit2 = 0x0008, + /// Coded value indicating current negotiated Serial ATA signal speed + CurrentSpeedBit1 = 0x0004, + /// Coded value indicating current negotiated Serial ATA signal speed + CurrentSpeedBit0 = 0x0002, + /// MUST NOT be set + Clear = 0x0001 + } + +#endregion + +#region SATAFeaturesBit enum + + /// SATA features flags + [Flags] + public enum SATAFeaturesBit : ushort + { +#pragma warning disable 1591 + Reserved15 = 0x8000, + Reserved14 = 0x4000, + Reserved13 = 0x2000, + Reserved12 = 0x1000, + Reserved11 = 0x0800, + Reserved10 = 0x0400, + Reserved09 = 0x0200, + Reserved08 = 0x0100, +#pragma warning restore 1591 + /// Supports NCQ autosense + NCQAutoSense = 0x0080, + /// Automatic Partial to Slumber transitions are enabled + EnabledSlumber = 0x0080, + /// Supports Software Settings Preservation + SettingsPreserve = 0x0040, + /// Supports hardware feature control + HardwareFeatureControl = 0x0020, + /// ATAPI: Asynchronous notification + AsyncNotification = 0x0020, + /// Supports in-order data delivery + InOrderData = 0x0010, + /// Supports initiating power management + InitPowerMgmt = 0x0008, + /// Supports DMA Setup auto-activation + DMASetup = 0x0004, + /// Supports non-zero buffer offsets + NonZeroBufferOffset = 0x0002, + /// MUST NOT be set + Clear = 0x0001 + } + +#endregion + +#region SCTCommandTransportBit enum + + /// SCT Command Transport flags + [Flags] + public enum SCTCommandTransportBit : ushort + { +#pragma warning disable 1591 + Vendor15 = 0x8000, + Vendor14 = 0x4000, + Vendor13 = 0x2000, + Vendor12 = 0x1000, + Reserved11 = 0x0800, + Reserved10 = 0x0400, + Reserved09 = 0x0200, + Reserved08 = 0x0100, + Reserved07 = 0x0080, + Reserved06 = 0x0040, +#pragma warning restore 1591 + /// SCT Command Transport Data Tables supported + DataTables = 0x0020, + /// SCT Command Transport Features Control supported + FeaturesControl = 0x0010, + /// SCT Command Transport Error Recovery Control supported + ErrorRecoveryControl = 0x0008, + /// SCT Command Transport Write Same supported + WriteSame = 0x0004, + /// SCT Command Transport Long Sector Address supported + LongSectorAccess = 0x0002, + /// SCT Command Transport supported + Supported = 0x0001 + } + +#endregion + +#region SecurityStatusBit enum + + /// Security status flag bits. + [Flags] + public enum SecurityStatusBit : ushort + { +#pragma warning disable 1591 + Reserved15 = 0x8000, + Reserved14 = 0x4000, + Reserved13 = 0x2000, + Reserved12 = 0x1000, + Reserved11 = 0x0800, + Reserved10 = 0x0400, + Reserved09 = 0x0200, +#pragma warning restore 1591 + /// Maximum security level + Maximum = 0x0100, +#pragma warning disable 1591 + Reserved07 = 0x0080, + Reserved06 = 0x0040, +#pragma warning restore 1591 + /// Supports enhanced security erase + Enhanced = 0x0020, + /// Security count expired + Expired = 0x0010, + /// Security frozen + Frozen = 0x0008, + /// Security locked + Locked = 0x0004, + /// Security enabled + Enabled = 0x0002, + /// Security supported + Supported = 0x0001 + } + +#endregion + +#region SpecificConfigurationEnum enum + + /// Specific configuration flags + public enum SpecificConfigurationEnum : ushort + { + /// Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete + RequiresSetIncompleteResponse = 0x37C8, + /// Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is complete + RequiresSetCompleteResponse = 0x738C, + /// Device does not requires SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete + NotRequiresSetIncompleteResponse = 0x8C73, + /// Device does not requires SET FEATURES to spin up and IDENTIFY DEVICE response is complete + NotRequiresSetCompleteResponse = 0xC837 + } + +#endregion + +#region TransferMode enum + + /// Transfer mode flags + [Flags] + public enum TransferMode : byte + { +#pragma warning disable 1591 + Mode7 = 0x80, + Mode6 = 0x40, + Mode5 = 0x20, + Mode4 = 0x10, + Mode3 = 0x08, + Mode2 = 0x04, + Mode1 = 0x02, + Mode0 = 0x01 +#pragma warning restore 1591 + } + +#endregion + +#region TrustedComputingBit enum + + /// Trusted Computing flags + [Flags] + public enum TrustedComputingBit : ushort + { + /// MUST NOT be set + Clear = 0x8000, + /// MUST be set + Set = 0x4000, +#pragma warning disable 1591 + Reserved13 = 0x2000, + Reserved12 = 0x1000, + Reserved11 = 0x0800, + Reserved10 = 0x0400, + Reserved09 = 0x0200, + Reserved08 = 0x0100, + Reserved07 = 0x0080, + Reserved06 = 0x0040, + Reserved05 = 0x0020, + Reserved04 = 0x0010, + Reserved03 = 0x0008, + Reserved02 = 0x0004, + Reserved01 = 0x0002, +#pragma warning restore 1591 + /// Trusted Computing feature set is supported + TrustedComputing = 0x0001 + } + +#endregion + + const string MODULE_NAME = "ATA/ATAPI IDENTIFY decoder"; + + /// Decodes a raw IDENTIFY DEVICE response + /// Raw IDENTIFY DEVICE response + /// Decoded IDENTIFY DEVICE + public static IdentifyDevice? Decode(byte[] IdentifyDeviceResponse) + { + if(IdentifyDeviceResponse == null) return null; + + if(IdentifyDeviceResponse.Length != 512) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.IDENTIFY_response_is_different_than_512_bytes_not_decoding); + + return null; + } + + IdentifyDevice ATAID = Marshal.ByteArrayToStructureLittleEndian(IdentifyDeviceResponse); + + ATAID.WWN = DescrambleWWN(ATAID.WWN); + ATAID.WWNExtension = DescrambleWWN(ATAID.WWNExtension); + + ATAID.SerialNumber = DescrambleATAString(IdentifyDeviceResponse, 10 * 2, 20); + ATAID.FirmwareRevision = DescrambleATAString(IdentifyDeviceResponse, 23 * 2, 8); + ATAID.Model = DescrambleATAString(IdentifyDeviceResponse, 27 * 2, 40); + ATAID.AdditionalPID = DescrambleATAString(IdentifyDeviceResponse, 170 * 2, 8); + ATAID.MediaSerial = DescrambleATAString(IdentifyDeviceResponse, 176 * 2, 40); + ATAID.MediaManufacturer = DescrambleATAString(IdentifyDeviceResponse, 196 * 2, 20); + + return ATAID; + } + + /// Encodes a raw IDENTIFY DEVICE response + /// Decoded IDENTIFY DEVICE + /// Raw IDENTIFY DEVICE response + public static byte[] Encode(IdentifyDevice? identify) + { + if(identify is null) return null; + + IdentifyDevice ataId = identify.Value; + + ataId.WWN = DescrambleWWN(ataId.WWN); + ataId.WWNExtension = DescrambleWWN(ataId.WWNExtension); + + var buf = new byte[512]; + nint ptr = System.Runtime.InteropServices.Marshal.AllocHGlobal(512); + System.Runtime.InteropServices.Marshal.StructureToPtr(ataId, ptr, false); + System.Runtime.InteropServices.Marshal.Copy(ptr, buf, 0, 512); + System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr); + + byte[] str = ScrambleATAString(ataId.SerialNumber, 20); + Array.Copy(str, 0, buf, 10 * 2, 20); + str = ScrambleATAString(ataId.FirmwareRevision, 8); + Array.Copy(str, 0, buf, 23 * 2, 8); + str = ScrambleATAString(ataId.Model, 40); + Array.Copy(str, 0, buf, 27 * 2, 40); + str = ScrambleATAString(ataId.AdditionalPID, 8); + Array.Copy(str, 0, buf, 170 * 2, 8); + str = ScrambleATAString(ataId.MediaSerial, 40); + Array.Copy(str, 0, buf, 176 * 2, 40); + str = ScrambleATAString(ataId.MediaManufacturer, 20); + Array.Copy(str, 0, buf, 196 * 2, 20); + + return buf; + } + + static ulong DescrambleWWN(ulong WWN) + { + byte[] qwb = BitConverter.GetBytes(WWN); + var qword = new byte[8]; + + qword[7] = qwb[1]; + qword[6] = qwb[0]; + qword[5] = qwb[3]; + qword[4] = qwb[2]; + qword[3] = qwb[5]; + qword[2] = qwb[4]; + qword[1] = qwb[7]; + qword[0] = qwb[6]; + + return BitConverter.ToUInt64(qword, 0); + } + + static string DescrambleATAString(IList buffer, int offset, int length) + { + byte[] outbuf = buffer[offset + length - 1] != 0x00 ? new byte[length + 1] : new byte[length]; + + for(var i = 0; i < length; i += 2) + { + outbuf[i] = buffer[offset + i + 1]; + outbuf[i + 1] = buffer[offset + i]; + } + + string outStr = StringHandlers.CToString(outbuf); + + return outStr.Trim(); + } + + static byte[] ScrambleATAString(string str, int length) + { + var buf = new byte[length]; + + for(var i = 0; i < length; i++) buf[i] = 0x20; + + if(str is null) return buf; + + byte[] bytes = Encoding.ASCII.GetBytes(str); + + if(bytes.Length % 2 != 0) + { + var tmp = new byte[bytes.Length + 1]; + tmp[^1] = 0x20; + Array.Copy(bytes, 0, tmp, 0, bytes.Length); + bytes = tmp; + } + + for(var i = 0; i < bytes.Length; i += 2) + { + buf[i] = bytes[i + 1]; + buf[i + 1] = bytes[i]; + } + + return buf; + } + +#region Nested type: IdentifyDevice + + /// IDENTIFY DEVICE decoded response + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 2)] + public struct IdentifyDevice + { + /// + /// Word 0 General device configuration On ATAPI devices: Bits 12 to 8 indicate device type as SCSI defined Bits 6 + /// to 5: 0 = Device shall set DRQ within 3 ms of receiving PACKET 1 = Device shall assert INTRQ when DRQ is set to one + /// 2 = Device shall set DRQ within 50 µs of receiving PACKET Bits 1 to 0: 0 = 12 byte command packet 1 = 16 byte + /// command packet CompactFlash is 0x848A (non magnetic, removable, not MFM, hardsector, and UltraFAST) + /// + public GeneralConfigurationBit GeneralConfiguration; + /// Word 1 Cylinders in default translation mode Obsoleted in ATA/ATAPI-6 + public ushort Cylinders; + /// Word 2 Specific configuration + public SpecificConfigurationEnum SpecificConfiguration; + /// Word 3 Heads in default translation mode Obsoleted in ATA/ATAPI-6 + public ushort Heads; + /// Word 4 Unformatted bytes per track in default translation mode Obsoleted in ATA-2 + public ushort UnformattedBPT; + /// Word 5 Unformatted bytes per sector in default translation mode Obsoleted in ATA-2 + public ushort UnformattedBPS; + /// Word 6 Sectors per track in default translation mode Obsoleted in ATA/ATAPI-6 + public ushort SectorsPerTrack; + /// Words 7 to 8 CFA: Number of sectors per card + public uint SectorsPerCard; + /// Word 9 Vendor unique Obsoleted in ATA/ATAPI-4 + public ushort VendorWord9; + /// Words 10 to 19 Device serial number, right justified, padded with spaces + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] + public string SerialNumber; + /// + /// Word 20 Manufacturer defined Obsoleted in ATA-2 0x0001 = single ported single sector buffer 0x0002 = dual + /// ported multi sector buffer 0x0003 = dual ported multi sector buffer with reading + /// + public ushort BufferType; + /// Word 21 Size of buffer in 512 byte increments Obsoleted in ATA-2 + public ushort BufferSize; + /// Word 22 Bytes of ECC available in READ/WRITE LONG commands Obsoleted in ATA/ATAPI-4 + public ushort EccBytes; + /// Words 23 to 26 Firmware revision, left justified, padded with spaces + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] + public string FirmwareRevision; + /// Words 27 to 46 Model number, left justified, padded with spaces + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)] + public string Model; + /// + /// Word 47 bits 7 to 0 Maximum number of sectors that can be transferred per interrupt on read and write multiple + /// commands + /// + public byte MultipleMaxSectors; + /// Word 47 bits 15 to 8 Vendor unique ATA/ATAPI-4 says it must be 0x80 + public byte VendorWord47; + /// + /// Word 48 ATA-1: Set to 1 if it can perform doubleword I/O ATA-2 to ATA/ATAPI-7: Reserved ATA8-ACS: Trusted + /// Computing feature set + /// + public TrustedComputingBit TrustedComputing; + /// Word 49 Capabilities + public CapabilitiesBit Capabilities; + /// Word 50 Capabilities + public CapabilitiesBit2 Capabilities2; + /// Word 51 bits 7 to 0 Vendor unique Obsoleted in ATA/ATAPI-4 + public byte VendorWord51; + /// Word 51 bits 15 to 8 Transfer timing mode in PIO Obsoleted in ATA/ATAPI-4 + public byte PIOTransferTimingMode; + /// Word 52 bits 7 to 0 Vendor unique Obsoleted in ATA/ATAPI-4 + public byte VendorWord52; + /// Word 52 bits 15 to 8 Transfer timing mode in DMA Obsoleted in ATA/ATAPI-4 + public byte DMATransferTimingMode; + /// Word 53 bits 7 to 0 Reports if words 54 to 58 are valid + public ExtendedIdentifyBit ExtendedIdentify; + /// Word 53 bits 15 to 8 Free-fall Control Sensitivity + public byte FreeFallSensitivity; + /// Word 54 Cylinders in current translation mode Obsoleted in ATA/ATAPI-6 + public ushort CurrentCylinders; + /// Word 55 Heads in current translation mode Obsoleted in ATA/ATAPI-6 + public ushort CurrentHeads; + /// Word 56 Sectors per track in current translation mode Obsoleted in ATA/ATAPI-6 + public ushort CurrentSectorsPerTrack; + /// Words 57 to 58 Total sectors currently user-addressable Obsoleted in ATA/ATAPI-6 + public uint CurrentSectors; + /// Word 59 bits 7 to 0 Number of sectors currently set to transfer on a READ/WRITE MULTIPLE command + public byte MultipleSectorNumber; + /// Word 59 bits 15 to 8 Indicates if is valid + public CapabilitiesBit3 Capabilities3; + /// Words 60 to 61 If drive supports LBA, how many sectors are addressable using LBA + public uint LBASectors; + /// + /// Word 62 bits 7 to 0 Single word DMA modes available Obsoleted in ATA/ATAPI-4 In ATAPI it's not obsolete, + /// indicates UDMA mode (UDMA7 is instead MDMA0) + /// + public TransferMode DMASupported; + /// + /// Word 62 bits 15 to 8 Single word DMA mode currently active Obsoleted in ATA/ATAPI-4 In ATAPI it's not + /// obsolete, bits 0 and 1 indicate MDMA mode+1, bit 10 indicates DMA is supported and bit 15 indicates DMADIR bit in + /// PACKET is required for DMA transfers + /// + public TransferMode DMAActive; + /// Word 63 bits 7 to 0 Multiword DMA modes available + public TransferMode MDMASupported; + /// Word 63 bits 15 to 8 Multiword DMA mode currently active + public TransferMode MDMAActive; + + /// Word 64 bits 7 to 0 Supported Advanced PIO transfer modes + public TransferMode APIOSupported; + /// Word 64 bits 15 to 8 Reserved + public byte ReservedWord64; + /// Word 65 Minimum MDMA transfer cycle time per word in nanoseconds + public ushort MinMDMACycleTime; + /// Word 66 Recommended MDMA transfer cycle time per word in nanoseconds + public ushort RecMDMACycleTime; + /// Word 67 Minimum PIO transfer cycle time without flow control in nanoseconds + public ushort MinPIOCycleTimeNoFlow; + /// Word 68 Minimum PIO transfer cycle time with IORDY flow control in nanoseconds + public ushort MinPIOCycleTimeFlow; + + /// Word 69 Additional supported + public CommandSetBit5 CommandSet5; + /// Word 70 Reserved + public ushort ReservedWord70; + /// Word 71 ATAPI: Typical time in ns from receipt of PACKET to release bus + public ushort PacketBusRelease; + /// Word 72 ATAPI: Typical time in ns from receipt of SERVICE to clear BSY + public ushort ServiceBusyClear; + /// Word 73 Reserved + public ushort ReservedWord73; + /// Word 74 Reserved + public ushort ReservedWord74; + + /// Word 75 Maximum Queue depth + public ushort MaxQueueDepth; + + /// Word 76 Serial ATA Capabilities + public SATACapabilitiesBit SATACapabilities; + /// Word 77 Serial ATA Additional Capabilities + public SATACapabilitiesBit2 SATACapabilities2; + + /// Word 78 Supported Serial ATA features + public SATAFeaturesBit SATAFeatures; + /// Word 79 Enabled Serial ATA features + public SATAFeaturesBit EnabledSATAFeatures; + + /// Word 80 Major version of ATA/ATAPI standard supported + public MajorVersionBit MajorVersion; + /// Word 81 Minimum version of ATA/ATAPI standard supported + public ushort MinorVersion; + + /// Word 82 Supported command/feature sets + public CommandSetBit CommandSet; + /// Word 83 Supported command/feature sets + public CommandSetBit2 CommandSet2; + /// Word 84 Supported command/feature sets + public CommandSetBit3 CommandSet3; + + /// Word 85 Enabled command/feature sets + public CommandSetBit EnabledCommandSet; + /// Word 86 Enabled command/feature sets + public CommandSetBit2 EnabledCommandSet2; + /// Word 87 Enabled command/feature sets + public CommandSetBit3 EnabledCommandSet3; + + /// Word 88 bits 7 to 0 Supported Ultra DMA transfer modes + public TransferMode UDMASupported; + /// Word 88 bits 15 to 8 Selected Ultra DMA transfer modes + public TransferMode UDMAActive; + + /// Word 89 Time required for security erase completion + public ushort SecurityEraseTime; + /// Word 90 Time required for enhanced security erase completion + public ushort EnhancedSecurityEraseTime; + /// Word 91 Current advanced power management value + public ushort CurrentAPM; + + /// Word 92 Master password revision code + public ushort MasterPasswordRevisionCode; + /// Word 93 Hardware reset result + public ushort HardwareResetResult; + + /// Word 94 bits 7 to 0 Current AAM value + public byte CurrentAAM; + /// Word 94 bits 15 to 8 Vendor's recommended AAM value + public byte RecommendedAAM; + + /// Word 95 Stream minimum request size + public ushort StreamMinReqSize; + /// Word 96 Streaming transfer time in DMA + public ushort StreamTransferTimeDMA; + /// Word 97 Streaming access latency in DMA and PIO + public ushort StreamAccessLatency; + /// Words 98 to 99 Streaming performance granularity + public uint StreamPerformanceGranularity; + + /// Words 100 to 103 48-bit LBA addressable sectors + public ulong LBA48Sectors; + + /// Word 104 Streaming transfer time in PIO + public ushort StreamTransferTimePIO; + + /// Word 105 Maximum number of 512-byte block per DATA SET MANAGEMENT command + public ushort DataSetMgmtSize; + + /// + /// Word 106 Bit 15 should be zero Bit 14 should be one Bit 13 set indicates device has multiple logical sectors + /// per physical sector Bit 12 set indicates logical sector has more than 256 words (512 bytes) Bits 11 to 4 are + /// reserved Bits 3 to 0 indicate power of two of logical sectors per physical sector + /// + public ushort PhysLogSectorSize; + + /// Word 107 Interseek delay for ISO-7779 acoustic testing, in microseconds + public ushort InterseekDelay; + + /// Words 108 to 111 World Wide Name + public ulong WWN; + + /// Words 112 to 115 Reserved for WWN extension to 128 bit + public ulong WWNExtension; + + /// Word 116 Reserved for technical report + public ushort ReservedWord116; + + /// Words 117 to 118 Words per logical sector + public uint LogicalSectorWords; + + /// Word 119 Supported command/feature sets + public CommandSetBit4 CommandSet4; + /// Word 120 Supported command/feature sets + public CommandSetBit4 EnabledCommandSet4; + + /// Words 121 to 125 Reserved + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public ushort[] ReservedWords121; + + /// Word 126 ATAPI byte count limit + public ushort ATAPIByteCount; + + /// + /// Word 127 Removable Media Status Notification feature set support Bits 15 to 2 are reserved Bits 1 to 0 must be + /// 0 for not supported or 1 for supported. 2 and 3 are reserved. Obsoleted in ATA8-ACS + /// + public ushort RemovableStatusSet; + + /// Word 128 Security status + public SecurityStatusBit SecurityStatus; + + /// Words 129 to 159 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)] + public ushort[] ReservedWords129; + + /// + /// Word 160 CFA power mode Bit 15 must be set Bit 13 indicates mode 1 is required for one or more commands Bit 12 + /// indicates mode 1 is disabled Bits 11 to 0 indicates maximum current in mA + /// + public ushort CFAPowerMode; + + /// Words 161 to 167 Reserved for CFA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public ushort[] ReservedCFA; + + /// Word 168 Bits 15 to 4, reserved Bits 3 to 0, device nominal form factor + public DeviceFormFactorEnum DeviceFormFactor; + /// Word 169 DATA SET MANAGEMENT support + public DataSetMgmtBit DataSetMgmt; + /// Words 170 to 173 Additional product identifier + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] + public string AdditionalPID; + + /// Word 174 Reserved + public ushort ReservedWord174; + /// Word 175 Reserved + public ushort ReservedWord175; + + /// Words 176 to 195 Current media serial number + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)] + public string MediaSerial; + /// Words 196 to 205 Current media manufacturer + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] + public string MediaManufacturer; + + /// Word 206 SCT Command Transport features + public SCTCommandTransportBit SCTCommandTransport; + + /// Word 207 Reserved for CE-ATA + public ushort ReservedCEATAWord207; + /// Word 208 Reserved for CE-ATA + public ushort ReservedCEATAWord208; + + /// + /// Word 209 Alignment of logical block within a larger physical block Bit 15 shall be cleared to zero Bit 14 + /// shall be set to one Bits 13 to 0 indicate logical sector offset within the first physical sector + /// + public ushort LogicalAlignment; + + /// Words 210 to 211 Write/Read/Verify sector count mode 3 only + public uint WRVSectorCountMode3; + /// Words 212 to 213 Write/Read/Verify sector count mode 2 only + public uint WRVSectorCountMode2; + + /// + /// Word 214 NV Cache capabilities Bits 15 to 12 feature set version Bits 11 to 18 power mode feature set version + /// Bits 7 to 5 reserved Bit 4 feature set enabled Bits 3 to 2 reserved Bit 1 power mode feature set enabled Bit 0 + /// power mode feature set supported + /// + public ushort NVCacheCaps; + /// Words 215 to 216 NV Cache Size in Logical BLocks + public uint NVCacheSize; + /// Word 217 Nominal media rotation rate In ACS-1 meant NV Cache read speed in MB/s + public ushort NominalRotationRate; + /// Word 218 NV Cache write speed in MB/s Reserved since ACS-2 + public ushort NVCacheWriteSpeed; + /// Word 219 bits 7 to 0 Estimated device spin up in seconds + public byte NVEstimatedSpinUp; + /// Word 219 bits 15 to 8 NV Cache reserved + public byte NVReserved; + + /// Word 220 bits 7 to 0 Write/Read/Verify feature set current mode + public byte WRVMode; + /// Word 220 bits 15 to 8 Reserved + public byte WRVReserved; + + /// Word 221 Reserved + public ushort ReservedWord221; + + /// + /// Word 222 Transport major revision number Bits 15 to 12 indicate transport type. 0 parallel, 1 serial, 0xE + /// PCIe. Bits 11 to 0 indicate revision + /// + public ushort TransportMajorVersion; + /// Word 223 Transport minor revision number + public ushort TransportMinorVersion; + + /// Words 224 to 229 Reserved for CE-ATA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public ushort[] ReservedCEATA224; + + /// Words 230 to 233 48-bit LBA if Word 69 bit 3 is set + public ulong ExtendedUserSectors; + + /// Word 234 Minimum number of 512 byte units per DOWNLOAD MICROCODE mode 3 + public ushort MinDownloadMicroMode3; + /// Word 235 Maximum number of 512 byte units per DOWNLOAD MICROCODE mode 3 + public ushort MaxDownloadMicroMode3; + + /// Words 236 to 254 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)] + public ushort[] ReservedWords; + + /// Word 255 bits 7 to 0 Should be 0xA5 + public byte Signature; + /// Word 255 bits 15 to 8 Checksum + public byte Checksum; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Structs/Devices/SCSI/Enums.cs b/Aaru.CommonTypes/Structs/Devices/SCSI/Enums.cs new file mode 100644 index 000000000..35a810bab --- /dev/null +++ b/Aaru.CommonTypes/Structs/Devices/SCSI/Enums.cs @@ -0,0 +1,245 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Common structures for SCSI devices. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains various SCSI enumerations. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.CommonTypes.Structs.Devices.SCSI; + +/// List of known SCSI peripheral qualifiers +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum PeripheralQualifiers : byte +{ + /// Peripheral qualifier: Device is connected and supported + Supported = 0x00, + /// Peripheral qualifier: Device is supported but not connected + Unconnected = 0x01, + /// Peripheral qualifier: Reserved value + Reserved = 0x02, + /// Peripheral qualifier: Device is connected but unsupported + Unsupported = 0x03, + /// Peripheral qualifier: Vendor values: 0x04, 0x05, 0x06 and 0x07 + VendorMask = 0x04 +} + +/// List of known peripheral device types +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum PeripheralDeviceTypes : byte +{ + /// Direct-access device + DirectAccess = 0x00, + /// Sequential-access device + SequentialAccess = 0x01, + /// Printer device + PrinterDevice = 0x02, + /// Processor device + ProcessorDevice = 0x03, + /// Write-once device + WriteOnceDevice = 0x04, + /// CD-ROM/DVD/etc device + MultiMediaDevice = 0x05, + /// Scanner device + ScannerDevice = 0x06, + /// Optical memory device + OpticalDevice = 0x07, + /// Medium change device + MediumChangerDevice = 0x08, + /// Communications device + CommsDevice = 0x09, + /// Graphics arts pre-press device (defined in ASC IT8) + PrePressDevice1 = 0x0A, + /// Graphics arts pre-press device (defined in ASC IT8) + PrePressDevice2 = 0x0B, + /// Array controller device + ArrayControllerDevice = 0x0C, + /// Enclosure services device + EnclosureServiceDevice = 0x0D, + /// Simplified direct-access device + SimplifiedDevice = 0x0E, + /// Optical card reader/writer device + OCRWDevice = 0x0F, + /// Bridging Expanders + BridgingExpander = 0x10, + /// Object-based Storage Device + ObjectDevice = 0x11, + /// Automation/Drive Interface + ADCDevice = 0x12, + /// Security Manager Device + SCSISecurityManagerDevice = 0x13, + /// Host managed zoned block device + SCSIZonedBlockDevice = 0x14, + /// Well known logical unit + WellKnownDevice = 0x1E, + /// Unknown or no device type + UnknownDevice = 0x1F +} + +/// List of known ANSI SCSI standards +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum ANSIVersions : byte +{ + /// Device does not claim conformance to any ANSI version + ANSINoVersion = 0x00, + /// Device complies with ANSI X3.131:1986 + ANSI1986Version = 0x01, + /// Device complies with ANSI X3.131:1994 + ANSI1994Version = 0x02, + /// Device complies with ANSI X3.301:1997 + ANSI1997Version = 0x03, + /// Device complies with ANSI X3.351:2001 + ANSI2001Version = 0x04, + /// Device complies with ANSI X3.408:2005. + ANSI2005Version = 0x05, + /// Device complies with SPC-4 + ANSI2008Version = 0x06 +} + +/// List of known ECMA SCSI standards +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum ECMAVersions : byte +{ + /// Device does not claim conformance to any ECMA version + ECMANoVersion = 0x00, + /// Device complies with a ECMA-111 standard + ECMA111 = 0x01 +} + +/// List of known ISO SCSI standards +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum ISOVersions : byte +{ + /// Device does not claim conformance to any ISO/IEC version + ISONoVersion = 0x00, + /// Device complies with ISO/IEC 9316:1995 + ISO1995Version = 0x02 +} + +/// List of known SCSI Parallel Interface clocking types +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum SPIClocking : byte +{ + /// Supports only ST + ST = 0x00, + /// Supports only DT + DT = 0x01, + /// Reserved value + Reserved = 0x02, + /// Supports ST and DT + STandDT = 0x03 +} + +/// List of known TGPS values +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum TGPSValues : byte +{ + /// Asymmetrical access not supported + NotSupported = 0x00, + /// Only implicit asymmetrical access is supported + OnlyImplicit = 0x01, + /// Only explicit asymmetrical access is supported + OnlyExplicit = 0x02, + /// Both implicit and explicit asymmetrical access are supported + Both = 0x03 +} + +/// List of known SCSI protocols +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum ProtocolIdentifiers : byte +{ + /// Fibre Channel + FibreChannel = 0, + /// Parallel SCSI + SCSI = 1, + /// SSA + SSA = 2, + /// IEEE-1394 + Firewire = 3, + /// SCSI Remote Direct Memory Access Protocol + RDMAP = 4, + /// Internet SCSI + iSCSI = 5, + /// Serial SCSI + SAS = 6, + /// Automation/Drive Interface Transport Protocol + ADT = 7, + /// AT Attachment Interface (ATA/ATAPI) + ATA = 8, + /// USB Attached SCSI + UAS = 9, + /// SCSI over PCI Express + SCSIe = 10, + /// PCI Express + PCIe = 11, + /// No specific protocol + NoProtocol = 15 +} + +/// List of known SCSI definitions +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum ScsiDefinitions : byte +{ + /// Unknown + Current = 0, + /// SCSI-1 + SCSI1 = 1, + /// Unknown + CCS = 2, + /// SCSI-2 + SCSI2 = 3, + /// SCSI-3 + SCSI3 = 4 +} + +/// List of known SCSI physical interfaces +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum PhysicalInterfaces : uint +{ + /// Unspecified physical interface + Unspecified = 0, + /// SCSI + SCSI = 1, + /// ATAPI + ATAPI = 2, + /// IEEE-1394/1995 + IEEE1394 = 3, + /// IEEE-1394A + IEEE1394A = 4, + /// Fibre Channel + FC = 5, + /// IEEE-1394B + IEEE1394B = 6, + /// Serial ATAPI + SerialATAPI = 7, + /// USB + USB = 8, + /// Vendor unique + Vendor = 0xFFFF +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Structs/Devices/SCSI/Inquiry.cs b/Aaru.CommonTypes/Structs/Devices/SCSI/Inquiry.cs new file mode 100644 index 000000000..b5ce7a279 --- /dev/null +++ b/Aaru.CommonTypes/Structs/Devices/SCSI/Inquiry.cs @@ -0,0 +1,768 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Inquiry.cs +// Author(s) : Natalia Portillo +// +// Component : Common structures for SCSI devices. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines a high level interpretation of the SCSI INQUIRY response. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Aaru.Console; + +namespace Aaru.CommonTypes.Structs.Devices.SCSI; + +/// +/// Information from the following standards: T9/375-D revision 10l T10/995-D revision 10 T10/1236-D revision 20 +/// T10/1416-D revision 23 T10/1731-D revision 16 T10/502 revision 05 RFC 7144 ECMA-111 +/// +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public struct Inquiry +{ + const string MODULE_NAME = "SCSI INQUIRY decoder"; + /// Peripheral qualifier Byte 0, bits 7 to 5 + public byte PeripheralQualifier; + /// Peripheral device type Byte 0, bits 4 to 0 + public byte PeripheralDeviceType; + /// Removable device Byte 1, bit 7 + public bool RMB; + /// SCSI-1 vendor-specific qualification codes Byte 1, bits 6 to 0 + public byte DeviceTypeModifier; + /// ISO/IEC SCSI Standard Version Byte 2, bits 7 to 6, mask = 0xC0, >> 6 + public byte ISOVersion; + /// ECMA SCSI Standard Version Byte 2, bits 5 to 3, mask = 0x38, >> 3 + public byte ECMAVersion; + /// ANSI SCSI Standard Version Byte 2, bits 2 to 0, mask = 0x07 + public byte ANSIVersion; + /// Asynchronous Event Reporting Capability supported Byte 3, bit 7 + public bool AERC; + /// Device supports TERMINATE TASK command Byte 3, bit 6 + public bool TrmTsk; + /// Supports setting Normal ACA Byte 3, bit 5 + public bool NormACA; + /// Supports LUN hierarchical addressing Byte 3, bit 4 + public bool HiSup; + /// Responde data format Byte 3, bit 3 to 0 + public byte ResponseDataFormat; + /// Lenght of total INQUIRY response minus 4 Byte 4 + public byte AdditionalLength; + /// Device contains an embedded storage array controller Byte 5, bit 7 + public bool SCCS; + /// Device contains an Access Control Coordinator Byte 5, bit 6 + public bool ACC; + /// Supports asymetrical logical unit access Byte 5, bits 5 to 4 + public byte TPGS; + /// Supports third-party copy commands Byte 5, bit 3 + public bool ThreePC; + /// Reserved Byte 5, bits 2 to 1 + public byte Reserved2; + /// Supports protection information Byte 5, bit 0 + public bool Protect; + /// Supports basic queueing Byte 6, bit 7 + public bool BQue; + /// Device contains an embedded enclosure services component Byte 6, bit 6 + public bool EncServ; + /// Vendor-specific Byte 6, bit 5 + public bool VS1; + /// Multi-port device Byte 6, bit 4 + public bool MultiP; + /// Device contains or is attached to a medium changer Byte 6, bit 3 + public bool MChngr; + /// Device supports request and acknowledge handshakes Byte 6, bit 2 + public bool ACKREQQ; + /// Supports 32-bit wide SCSI addresses Byte 6, bit 1 + public bool Addr32; + /// Supports 16-bit wide SCSI addresses Byte 6, bit 0 + public bool Addr16; + /// Device supports relative addressing Byte 7, bit 7 + public bool RelAddr; + /// Supports 32-bit wide data transfers Byte 7, bit 6 + public bool WBus32; + /// Supports 16-bit wide data transfers Byte 7, bit 5 + public bool WBus16; + /// Supports synchronous data transfer Byte 7, bit 4 + public bool Sync; + /// Supports linked commands Byte 7, bit 3 + public bool Linked; + /// Supports CONTINUE TASK and TARGET TRANSFER DISABLE commands Byte 7, bit 2 + public bool TranDis; + /// Supports TCQ queue Byte 7, bit 1 + public bool CmdQue; + /// Indicates that the devices responds to RESET with soft reset Byte 7, bit 0 + public bool SftRe; + /// Vendor identification Bytes 8 to 15 + public byte[] VendorIdentification; + /// Product identification Bytes 16 to 31 + public byte[] ProductIdentification; + /// Product revision level Bytes 32 to 35 + public byte[] ProductRevisionLevel; + /// Vendor-specific data Bytes 36 to 55 + public byte[] VendorSpecific; + /// Byte 56, bits 7 to 4 + public byte Reserved3; + /// Supported SPI clocking Byte 56, bits 3 to 2 + public byte Clocking; + /// Device supports Quick Arbitration and Selection Byte 56, bit 1 + public bool QAS; + /// Supports information unit transfers Byte 56, bit 0 + public bool IUS; + /// Reserved Byte 57 + public byte Reserved4; + /// Array of version descriptors Bytes 58 to 73 + public ushort[] VersionDescriptors; + /// Reserved Bytes 74 to 95 + public byte[] Reserved5; + /// Reserved Bytes 96 to end + public byte[] VendorSpecific2; + + // Per DLT4000/DLT4500/DLT4700 Cartridge Tape Subsystem Product Manual + +#region Quantum vendor unique inquiry data structure + + /// Means that the INQUIRY response contains 56 bytes or more, so this data has been filled + public bool QuantumPresent; + /// The product family. Byte 36, bits 7 to 5 + public byte Qt_ProductFamily; + /// The released firmware. Byte 36, bits 4 to 0 + public byte Qt_ReleasedFirmware; + /// The firmware major version. Byte 37 + public byte Qt_FirmwareMajorVersion; + /// The firmware minor version. Byte 38 + public byte Qt_FirmwareMinorVersion; + /// The EEPROM format major version. Byte 39 + public byte Qt_EEPROMFormatMajorVersion; + /// The EEPROM format minor version. Byte 40 + public byte Qt_EEPROMFormatMinorVersion; + /// The firmware personality. Byte 41 + public byte Qt_FirmwarePersonality; + /// The firmware sub personality. Byte 42 + public byte Qt_FirmwareSubPersonality; + /// The tape directory format version. Byte 43 + public byte Qt_TapeDirectoryFormatVersion; + /// The controller hardware version. Byte 44 + public byte Qt_ControllerHardwareVersion; + /// The drive EEPROM version. Byte 45 + public byte Qt_DriveEEPROMVersion; + /// The drive hardware version. Byte 46 + public byte Qt_DriveHardwareVersion; + /// The media loader firmware version. Byte 47 + public byte Qt_MediaLoaderFirmwareVersion; + /// The media loader hardware version. Byte 48 + public byte Qt_MediaLoaderHardwareVersion; + /// The media loader mechanical version. Byte 49 + public byte Qt_MediaLoaderMechanicalVersion; + /// Is a media loader present? Byte 50 + public bool Qt_MediaLoaderPresent; + /// Is a library present? Byte 51 + public bool Qt_LibraryPresent; + /// The module revision. Bytes 52 to 55 + public byte[] Qt_ModuleRevision; + +#endregion Quantum vendor unique inquiry data structure + +#region IBM vendor unique inquiry data structure + + /// Means that the INQUIRY response contains 56 bytes or more, so this data has been filled + public bool IBMPresent; + /// Drive is not capable of automation Byte 36 bit 0 + public bool IBM_AutDis; + /// If not zero, limit in MB/s = Max * (this / 256) Byte 37 + public byte IBM_PerformanceLimit; + /// Byte 41 + public byte IBM_OEMSpecific; + +#endregion IBM vendor unique inquiry data structure + +#region HP vendor unique inquiry data structure + + /// Means that the INQUIRY response contains 49 bytes or more, so this data has been filled + public bool HPPresent; + /// WORM version Byte 40 bits 7 to 1 + public byte HP_WORMVersion; + /// WORM supported Byte 40 bit 0 + public bool HP_WORM; + /// Bytes 43 to 48 + public byte[] HP_OBDR; + +#endregion HP vendor unique inquiry data structure + +#region Seagate vendor unique inquiry data structure + + /// Means that bytes 36 to 43 are filled + public bool SeagatePresent; + /// Drive Serial Number Bytes 36 to 43 + public byte[] Seagate_DriveSerialNumber; + /// Means that bytes 96 to 143 are filled + public bool Seagate2Present; + /// Contains Seagate copyright notice Bytes 96 to 143 + public byte[] Seagate_Copyright; + /// Means that bytes 144 to 147 are filled + public bool Seagate3Present; + /// Reserved Seagate field Bytes 144 to 147 + public byte[] Seagate_ServoPROMPartNo; + +#endregion Seagate vendor unique inquiry data structure + +#region Kreon vendor unique inquiry data structure + + /// Means that firmware is Kreon + public bool KreonPresent; + /// Kreon identifier Bytes 36 to 40 + public byte[] KreonIdentifier; + /// Kreon just a 0x20 Bytes 41 + public byte KreonSpace; + /// Kreon version string Bytes 42 to 46 + public byte[] KreonVersion; + +#endregion Kreon vendor unique inquiry data structure + +#region Sony Hi-MD data + + /// Set if Hi-MD signature is present + public bool IsHiMD; + /// Hi-MD signature, bytes 36 to 44 + public byte[] HiMDSignature; + /// Unknown data, bytes 44 to 55 + public byte[] HiMDSpecific; + +#endregion Sony Hi-MD data + + static readonly byte[] HiMDSignatureContents = "Hi-MD "u8.ToArray(); + + /// Decodes a SCSI INQUIRY response + /// INQUIRY raw response data + /// Decoded SCSI INQUIRY + +#region Public methods + + public static Inquiry? Decode(byte[] SCSIInquiryResponse) + { + if(SCSIInquiryResponse == null) return null; + + if(SCSIInquiryResponse.Length < 36 && SCSIInquiryResponse.Length != 5) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.INQUIRY_response_is_0_bytes_less_than_minimum_of_36_bytes, + SCSIInquiryResponse.Length); + + return null; + } + + if(SCSIInquiryResponse.Length < SCSIInquiryResponse[4] + 4 && + SCSIInquiryResponse.Length != SCSIInquiryResponse[4]) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .INQUIRY_response_length_0_bytes_is_different_than_specified_in_length_field, + SCSIInquiryResponse.Length, + SCSIInquiryResponse[4] + 4); + + return null; + } + + var decoded = new Inquiry(); + + if(SCSIInquiryResponse.Length >= 1) + { + decoded.PeripheralQualifier = (byte)((SCSIInquiryResponse[0] & 0xE0) >> 5); + decoded.PeripheralDeviceType = (byte)(SCSIInquiryResponse[0] & 0x1F); + } + + if(SCSIInquiryResponse.Length >= 2) + { + decoded.RMB = Convert.ToBoolean(SCSIInquiryResponse[1] & 0x80); + decoded.DeviceTypeModifier = (byte)(SCSIInquiryResponse[1] & 0x7F); + } + + if(SCSIInquiryResponse.Length >= 3) + { + decoded.ISOVersion = (byte)((SCSIInquiryResponse[2] & 0xC0) >> 6); + decoded.ECMAVersion = (byte)((SCSIInquiryResponse[2] & 0x38) >> 3); + decoded.ANSIVersion = (byte)(SCSIInquiryResponse[2] & 0x07); + } + + if(SCSIInquiryResponse.Length >= 4) + { + decoded.AERC = Convert.ToBoolean(SCSIInquiryResponse[3] & 0x80); + decoded.TrmTsk = Convert.ToBoolean(SCSIInquiryResponse[3] & 0x40); + decoded.NormACA = Convert.ToBoolean(SCSIInquiryResponse[3] & 0x20); + decoded.HiSup = Convert.ToBoolean(SCSIInquiryResponse[3] & 0x10); + decoded.ResponseDataFormat = (byte)(SCSIInquiryResponse[3] & 0x07); + } + + if(SCSIInquiryResponse.Length >= 5) decoded.AdditionalLength = SCSIInquiryResponse[4]; + + if(SCSIInquiryResponse.Length >= 6) + { + decoded.SCCS = Convert.ToBoolean(SCSIInquiryResponse[5] & 0x80); + decoded.ACC = Convert.ToBoolean(SCSIInquiryResponse[5] & 0x40); + decoded.TPGS = (byte)((SCSIInquiryResponse[5] & 0x30) >> 4); + decoded.ThreePC = Convert.ToBoolean(SCSIInquiryResponse[5] & 0x08); + decoded.Reserved2 = (byte)((SCSIInquiryResponse[5] & 0x06) >> 1); + decoded.Protect = Convert.ToBoolean(SCSIInquiryResponse[5] & 0x01); + } + + if(SCSIInquiryResponse.Length >= 7) + { + decoded.BQue = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x80); + decoded.EncServ = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x40); + decoded.VS1 = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x20); + decoded.MultiP = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x10); + decoded.MChngr = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x08); + decoded.ACKREQQ = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x04); + decoded.Addr32 = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x02); + decoded.Addr16 = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x01); + } + + if(SCSIInquiryResponse.Length >= 8) + { + decoded.RelAddr = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x80); + decoded.WBus32 = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x40); + decoded.WBus16 = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x20); + decoded.Sync = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x10); + decoded.Linked = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x08); + decoded.TranDis = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x04); + decoded.CmdQue = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x02); + decoded.SftRe = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x01); + } + + if(SCSIInquiryResponse.Length >= 16) + { + decoded.VendorIdentification = new byte[8]; + Array.Copy(SCSIInquiryResponse, 8, decoded.VendorIdentification, 0, 8); + } + + if(SCSIInquiryResponse.Length >= 32) + { + decoded.ProductIdentification = new byte[16]; + Array.Copy(SCSIInquiryResponse, 16, decoded.ProductIdentification, 0, 16); + } + + if(SCSIInquiryResponse.Length >= 36) + { + decoded.ProductRevisionLevel = new byte[4]; + Array.Copy(SCSIInquiryResponse, 32, decoded.ProductRevisionLevel, 0, 4); + } + + if(SCSIInquiryResponse.Length >= 44) + { + // Seagate 1 + decoded.SeagatePresent = true; + decoded.Seagate_DriveSerialNumber = new byte[8]; + Array.Copy(SCSIInquiryResponse, 36, decoded.Seagate_DriveSerialNumber, 0, 8); + + // Hi-MD + decoded.HiMDSignature = new byte[8]; + Array.Copy(SCSIInquiryResponse, 36, decoded.HiMDSignature, 0, 8); + decoded.IsHiMD = HiMDSignatureContents.SequenceEqual(decoded.HiMDSignature); + } + + if(SCSIInquiryResponse.Length >= 46) + { + // Kreon + decoded.KreonIdentifier = new byte[5]; + Array.Copy(SCSIInquiryResponse, 36, decoded.KreonIdentifier, 0, 5); + decoded.KreonSpace = SCSIInquiryResponse[41]; + decoded.KreonVersion = new byte[5]; + Array.Copy(SCSIInquiryResponse, 42, decoded.KreonVersion, 0, 5); + + if(decoded.KreonSpace == 0x20 && decoded.KreonIdentifier.SequenceEqual("KREON"u8.ToArray())) + decoded.KreonPresent = true; + } + + if(SCSIInquiryResponse.Length >= 49) + { + // HP + decoded.HPPresent = true; + decoded.HP_WORM |= (SCSIInquiryResponse[40] & 0x01) == 0x01; + decoded.HP_WORMVersion = (byte)((SCSIInquiryResponse[40] & 0x7F) >> 1); + decoded.HP_OBDR = new byte[6]; + Array.Copy(SCSIInquiryResponse, 43, decoded.HP_OBDR, 0, 6); + } + + if(SCSIInquiryResponse.Length >= 56) + { + if(decoded.IsHiMD) + { + decoded.HiMDSpecific = new byte[12]; + Array.Copy(SCSIInquiryResponse, 44, decoded.HiMDSpecific, 0, 12); + } + else + { + decoded.VendorSpecific = new byte[20]; + Array.Copy(SCSIInquiryResponse, 36, decoded.VendorSpecific, 0, 20); + } + + // Quantum + decoded.QuantumPresent = true; + decoded.Qt_ProductFamily = (byte)((SCSIInquiryResponse[36] & 0xF0) >> 4); + decoded.Qt_ReleasedFirmware = (byte)(SCSIInquiryResponse[36] & 0x0F); + decoded.Qt_FirmwareMajorVersion = SCSIInquiryResponse[37]; + decoded.Qt_FirmwareMinorVersion = SCSIInquiryResponse[38]; + decoded.Qt_EEPROMFormatMajorVersion = SCSIInquiryResponse[39]; + decoded.Qt_EEPROMFormatMinorVersion = SCSIInquiryResponse[40]; + decoded.Qt_FirmwarePersonality = SCSIInquiryResponse[41]; + decoded.Qt_FirmwareSubPersonality = SCSIInquiryResponse[42]; + decoded.Qt_TapeDirectoryFormatVersion = SCSIInquiryResponse[43]; + decoded.Qt_ControllerHardwareVersion = SCSIInquiryResponse[44]; + decoded.Qt_DriveEEPROMVersion = SCSIInquiryResponse[45]; + decoded.Qt_DriveHardwareVersion = SCSIInquiryResponse[46]; + decoded.Qt_MediaLoaderFirmwareVersion = SCSIInquiryResponse[47]; + decoded.Qt_MediaLoaderHardwareVersion = SCSIInquiryResponse[48]; + decoded.Qt_MediaLoaderMechanicalVersion = SCSIInquiryResponse[49]; + decoded.Qt_MediaLoaderPresent = SCSIInquiryResponse[50] > 0; + decoded.Qt_LibraryPresent = SCSIInquiryResponse[51] > 0; + decoded.Qt_ModuleRevision = new byte[4]; + Array.Copy(SCSIInquiryResponse, 52, decoded.Qt_ModuleRevision, 0, 4); + + // IBM + decoded.IBMPresent = true; + decoded.IBM_AutDis |= (SCSIInquiryResponse[36] & 0x01) == 0x01; + decoded.IBM_PerformanceLimit = SCSIInquiryResponse[37]; + decoded.IBM_OEMSpecific = SCSIInquiryResponse[41]; + } + + if(SCSIInquiryResponse.Length >= 57) + { + decoded.Reserved3 = (byte)((SCSIInquiryResponse[56] & 0xF0) >> 4); + decoded.Clocking = (byte)((SCSIInquiryResponse[56] & 0x0C) >> 2); + decoded.QAS = Convert.ToBoolean(SCSIInquiryResponse[56] & 0x02); + decoded.IUS = Convert.ToBoolean(SCSIInquiryResponse[56] & 0x01); + } + + if(SCSIInquiryResponse.Length >= 58) decoded.Reserved4 = SCSIInquiryResponse[57]; + + if(SCSIInquiryResponse.Length >= 60) + { + int descriptorsNo; + + if(SCSIInquiryResponse.Length >= 74) + descriptorsNo = 8; + else + descriptorsNo = (SCSIInquiryResponse.Length - 58) / 2; + + decoded.VersionDescriptors = new ushort[descriptorsNo]; + + for(var i = 0; i < descriptorsNo; i++) + decoded.VersionDescriptors[i] = BitConverter.ToUInt16(SCSIInquiryResponse, 58 + i * 2); + } + + switch(SCSIInquiryResponse.Length) + { + case >= 75 and < 96: + decoded.Reserved5 = new byte[SCSIInquiryResponse.Length - 74]; + Array.Copy(SCSIInquiryResponse, 74, decoded.Reserved5, 0, SCSIInquiryResponse.Length - 74); + + break; + case >= 96: + decoded.Reserved5 = new byte[22]; + Array.Copy(SCSIInquiryResponse, 74, decoded.Reserved5, 0, 22); + + break; + } + + if(SCSIInquiryResponse.Length > 96) + { + decoded.VendorSpecific2 = new byte[SCSIInquiryResponse.Length - 96]; + Array.Copy(SCSIInquiryResponse, 96, decoded.VendorSpecific2, 0, SCSIInquiryResponse.Length - 96); + } + + if(SCSIInquiryResponse.Length >= 144) + { + // Seagate 2 + decoded.Seagate2Present = true; + decoded.Seagate_Copyright = new byte[48]; + Array.Copy(SCSIInquiryResponse, 96, decoded.Seagate_Copyright, 0, 48); + } + + if(SCSIInquiryResponse.Length < 148) return decoded; + + // Seagate 2 + decoded.Seagate3Present = true; + decoded.Seagate_ServoPROMPartNo = new byte[4]; + Array.Copy(SCSIInquiryResponse, 144, decoded.Seagate_ServoPROMPartNo, 0, 4); + + return decoded; + } + + /// Encodes a SCSI INQUIRY response + /// Decoded SCSI INQUIRY + /// Raw SCSI INQUIRY response + public static byte[] Encode(Inquiry? inq) + { + if(inq is null) return null; + + Inquiry decoded = inq.Value; + + var buffer = new byte[512]; + byte length = 0; + + buffer[0] = (byte)(decoded.PeripheralQualifier << 5); + buffer[0] += decoded.PeripheralDeviceType; + + if(decoded.RMB) buffer[1] = 0x80; + + buffer[1] += decoded.DeviceTypeModifier; + + buffer[2] = (byte)(decoded.ISOVersion << 6); + buffer[2] += (byte)(decoded.ECMAVersion << 3); + buffer[2] += decoded.ANSIVersion; + + if(decoded.AERC) buffer[3] = 0x80; + + if(decoded.TrmTsk) buffer[3] += 0x40; + + if(decoded.NormACA) buffer[3] += 0x20; + + if(decoded.HiSup) buffer[3] += 0x10; + + buffer[3] += decoded.ResponseDataFormat; + + if(decoded.AdditionalLength > 0) + { + length = 5; + buffer[4] = decoded.AdditionalLength; + } + + if(decoded.SCCS || + decoded.ACC || + decoded.TPGS > 0 || + decoded.ThreePC || + decoded.Reserved2 > 0 || + decoded.Protect) + { + length = 6; + + if(decoded.SCCS) buffer[5] = 0x80; + + if(decoded.ACC) buffer[5] += 0x40; + + buffer[5] += (byte)(decoded.TPGS << 4); + + if(decoded.ThreePC) buffer[5] += 0x08; + + buffer[5] += (byte)(decoded.Reserved2 << 1); + + if(decoded.Protect) buffer[5] += 0x01; + } + + if(decoded.BQue || + decoded.EncServ || + decoded.VS1 || + decoded.MultiP || + decoded.MChngr || + decoded.ACKREQQ || + decoded.Addr32 || + decoded.Addr16) + { + length = 7; + + if(decoded.BQue) buffer[6] = 0x80; + + if(decoded.EncServ) buffer[6] += 0x40; + + if(decoded.VS1) buffer[6] += 0x20; + + if(decoded.MultiP) buffer[6] += 0x10; + + if(decoded.MChngr) buffer[6] += 0x08; + + if(decoded.ACKREQQ) buffer[6] += 0x04; + + if(decoded.Addr32) buffer[6] += 0x02; + + if(decoded.Addr16) buffer[6] += 0x01; + } + + if(decoded.RelAddr || + decoded.WBus32 || + decoded.WBus16 || + decoded.Sync || + decoded.Linked || + decoded.TranDis || + decoded.CmdQue || + decoded.SftRe) + + { + length = 8; + + if(decoded.RelAddr) buffer[7] = 0x80; + + if(decoded.WBus32) buffer[7] += 0x40; + + if(decoded.WBus16) buffer[7] += 0x20; + + if(decoded.Sync) buffer[7] += 0x10; + + if(decoded.Linked) buffer[7] += 0x08; + + if(decoded.TranDis) buffer[7] += 0x04; + + if(decoded.CmdQue) buffer[7] += 0x02; + + if(decoded.SftRe) buffer[7] += 0x01; + } + + if(decoded.VendorIdentification != null) + { + length = 16; + + Array.Copy(decoded.VendorIdentification, + 0, + buffer, + 8, + decoded.VendorIdentification.Length >= 8 ? 8 : decoded.VendorIdentification.Length); + } + + if(decoded.ProductIdentification != null) + { + length = 32; + + Array.Copy(decoded.ProductIdentification, + 0, + buffer, + 16, + decoded.ProductIdentification.Length >= 16 ? 16 : decoded.ProductIdentification.Length); + } + + if(decoded.ProductRevisionLevel != null) + { + length = 36; + + Array.Copy(decoded.ProductRevisionLevel, + 0, + buffer, + 32, + decoded.ProductRevisionLevel.Length >= 4 ? 4 : decoded.ProductRevisionLevel.Length); + } + + if(decoded.Seagate_DriveSerialNumber != null) + { + length = 44; + Array.Copy(decoded.Seagate_DriveSerialNumber, 0, buffer, 36, 8); + } + + if(decoded is { KreonIdentifier: not null, KreonVersion: not null }) + { + length = 46; + Array.Copy(decoded.KreonIdentifier, 0, buffer, 36, 5); + buffer[41] = decoded.KreonSpace; + Array.Copy(decoded.KreonVersion, 0, buffer, 42, 5); + } + + if(decoded.HP_WORM || decoded.HP_WORMVersion > 0 || decoded.HP_OBDR != null) + { + length = 49; + + if(decoded.HP_WORM) buffer[40] = 0x01; + + buffer[40] += (byte)(decoded.HP_WORMVersion << 1); + Array.Copy(decoded.HP_OBDR, 0, buffer, 43, 6); + } + + if(decoded.IsHiMD) + { + length = 56; + Array.Copy(HiMDSignatureContents, 0, buffer, 36, 8); + + if(decoded.HiMDSpecific != null) Array.Copy(decoded.HiMDSpecific, 0, buffer, 44, 12); + } + + if(decoded is { VendorSpecific: not null, IsHiMD: false }) + { + length = 56; + Array.Copy(decoded.VendorSpecific, 0, buffer, 36, 20); + } + + if(decoded.Reserved3 > 0 || decoded.Clocking > 0 || decoded.QAS || decoded.IUS) + { + length = 57; + buffer[56] = (byte)(decoded.Reserved3 << 4); + buffer[56] += (byte)(decoded.Clocking << 2); + + if(decoded.QAS) buffer[56] += 0x02; + + if(decoded.IUS) buffer[56] += 0x01; + } + + if(decoded.Reserved4 != 0) + { + length = 58; + buffer[57] = decoded.Reserved4; + } + + if(decoded.VersionDescriptors != null) + { + length = (byte)(58 + decoded.VersionDescriptors.Length * 2); + + for(var i = 0; i < decoded.VersionDescriptors.Length; i++) + Array.Copy(BitConverter.GetBytes(decoded.VersionDescriptors[i]), 0, buffer, 56 + i * 2, 2); + } + + if(decoded.Reserved5 != null) + { + length = (byte)(74 + decoded.Reserved5.Length); + Array.Copy(decoded.Reserved5, 0, buffer, 74, decoded.Reserved5.Length); + } + + if(decoded.VendorSpecific2 != null) + { + length = (byte)(96 + decoded.VendorSpecific2.Length); + Array.Copy(decoded.VendorSpecific2, 0, buffer, 96, decoded.VendorSpecific2.Length); + } + + if(decoded.Seagate_Copyright != null) + { + length = 144; + Array.Copy(decoded.Seagate_Copyright, 0, buffer, 96, 48); + } + + if(decoded.Seagate_ServoPROMPartNo != null) + { + length = 148; + Array.Copy(decoded.Seagate_ServoPROMPartNo, 0, buffer, 144, 4); + } + + buffer[4] = length; + var dest = new byte[length]; + Array.Copy(buffer, 0, dest, 0, length); + + return dest; + } + +#endregion Public methods +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Structs/Devices/SCSI/Modes/2A.cs b/Aaru.CommonTypes/Structs/Devices/SCSI/Modes/2A.cs new file mode 100644 index 000000000..b59aebc1d --- /dev/null +++ b/Aaru.CommonTypes/Structs/Devices/SCSI/Modes/2A.cs @@ -0,0 +1,518 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 2A.cs +// Author(s) : Natalia Portillo +// +// Component : Common structures for SCSI devices. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 2Ah: CD-ROM capabilities page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; + +namespace Aaru.CommonTypes.Structs.Devices.SCSI.Modes; + +#region Mode Page 0x2A: CD-ROM capabilities page + +/// +/// CD-ROM capabilities page Page code 0x2A 16 bytes in OB-U0077C 20 bytes in SFF-8020i 22 bytes in MMC-1 26 bytes +/// in MMC-2 Variable bytes in MMC-3 +/// +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public class ModePage_2A +{ + /// Write speed performance descriptors + public ModePage_2A_WriteDescriptor[] WriteSpeedPerformanceDescriptors; + + /// Parameters can be saved + public bool PS { get; set; } + + /// Drive supports multi-session and/or Photo-CD + public bool MultiSession { get; set; } + + /// Drive is capable of reading sectors in Mode 2 Form 2 format + public bool Mode2Form2 { get; set; } + + /// Drive is capable of reading sectors in Mode 2 Form 1 format + public bool Mode2Form1 { get; set; } + + /// Drive is capable of playing audio + public bool AudioPlay { get; set; } + + /// Drive can return the ISRC + public bool ISRC { get; set; } + + /// Drive can return the media catalogue number + public bool UPC { get; set; } + + /// Drive can return C2 pointers + public bool C2Pointer { get; set; } + + /// Drive can read, deinterlave and correct R-W subchannels + public bool DeinterlaveSubchannel { get; set; } + + /// Drive can read interleaved and uncorrected R-W subchannels + public bool Subchannel { get; set; } + + /// Drive can continue from a loss of streaming on audio reading + public bool AccurateCDDA { get; set; } + + /// Audio can be read as digital data + public bool CDDACommand { get; set; } + + /// Loading Mechanism Type + public byte LoadingMechanism { get; set; } + + /// Drive can eject discs + public bool Eject { get; set; } + + /// Drive's optional prevent jumper status + public bool PreventJumper { get; set; } + + /// Current lock status + public bool LockState { get; set; } + + /// Drive can lock media + public bool Lock { get; set; } + + /// Each channel can be muted independently + public bool SeparateChannelMute { get; set; } + + /// Each channel's volume can be controlled independently + public bool SeparateChannelVolume { get; set; } + + /// Maximum drive speed in Kbytes/second + public ushort MaximumSpeed { get; set; } + + /// Supported volume levels + public ushort SupportedVolumeLevels { get; set; } + + /// Buffer size in Kbytes + public ushort BufferSize { get; set; } + + /// Current drive speed in Kbytes/second + public ushort CurrentSpeed { get; set; } + + /// Can read packet media + public bool Method2 { get; set; } + + /// Can read CD-RW + public bool ReadCDRW { get; set; } + + /// Can read CD-R + public bool ReadCDR { get; set; } + + /// Can write CD-RW + public bool WriteCDRW { get; set; } + + /// Can write CD-R + public bool WriteCDR { get; set; } + + /// Supports IEC-958 digital output on port 2 + public bool DigitalPort2 { get; set; } + + /// Supports IEC-958 digital output on port 1 + public bool DigitalPort1 { get; set; } + + /// Can deliver a composite audio and video data stream + public bool Composite { get; set; } + + /// This bit controls the behavior of the LOAD/UNLOAD command when trying to load a Slot with no Disc present + public bool SSS { get; set; } + + /// Contains a changer that can report the exact contents of the slots + public bool SDP { get; set; } + + /// Page length + public byte Length { get; set; } + + /// Set if LSB comes first + public bool LSBF { get; set; } + + /// Set if HIGH on LRCK indicates left channel. Clear if HIGH on LRCK indicates right channel. + public bool RCK { get; set; } + + /// + /// Set if data valid on the falling edge of the BCK signal. Clear if data valid on the rising edge of the BCK + /// signal + /// + public bool BCK { get; set; } + + /// Can do a test write + public bool TestWrite { get; set; } + + /// Maximum write speed + public ushort MaxWriteSpeed { get; set; } + + /// Current write speed + public ushort CurrentWriteSpeed { get; set; } + + /// Can read disc's barcode + public bool ReadBarcode { get; set; } + + /// Can read DVD-RAM + public bool ReadDVDRAM { get; set; } + + /// Can read DVD-R + public bool ReadDVDR { get; set; } + + /// Can read DVD-ROM + public bool ReadDVDROM { get; set; } + + /// Can write DVD-RAM + public bool WriteDVDRAM { get; set; } + + /// Can write DVD-R + public bool WriteDVDR { get; set; } + + /// Can read raw R-W subchannel from the Lead-In + public bool LeadInPW { get; set; } + + /// Can read both sides of a disc + public bool SCC { get; set; } + + /// Support copyright management + public ushort CMRSupported { get; set; } + + /// Supports buffer under-run free recording + public bool BUF { get; set; } + + /// Selected rotational control + public byte RotationControlSelected { get; set; } + + /// Current write speed selected + public ushort CurrentWriteSpeedSelected { get; set; } + + /// Database ID + [JsonIgnore] + [Key] + + // ReSharper disable once UnusedMember.Global + public int Id { get; set; } + + /// Decodes the page 2Ah of a MODE SENSE response + /// Raw page 2Ah + /// Decoded page 2Ah + public static ModePage_2A Decode(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x2A) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 16) return null; + + var decoded = new ModePage_2A(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.AudioPlay |= (pageResponse[4] & 0x01) == 0x01; + decoded.Mode2Form1 |= (pageResponse[4] & 0x10) == 0x10; + decoded.Mode2Form2 |= (pageResponse[4] & 0x20) == 0x20; + decoded.MultiSession |= (pageResponse[4] & 0x40) == 0x40; + + decoded.CDDACommand |= (pageResponse[5] & 0x01) == 0x01; + decoded.AccurateCDDA |= (pageResponse[5] & 0x02) == 0x02; + decoded.Subchannel |= (pageResponse[5] & 0x04) == 0x04; + decoded.DeinterlaveSubchannel |= (pageResponse[5] & 0x08) == 0x08; + decoded.C2Pointer |= (pageResponse[5] & 0x10) == 0x10; + decoded.UPC |= (pageResponse[5] & 0x20) == 0x20; + decoded.ISRC |= (pageResponse[5] & 0x40) == 0x40; + + decoded.LoadingMechanism = (byte)((pageResponse[6] & 0xE0) >> 5); + decoded.Lock |= (pageResponse[6] & 0x01) == 0x01; + decoded.LockState |= (pageResponse[6] & 0x02) == 0x02; + decoded.PreventJumper |= (pageResponse[6] & 0x04) == 0x04; + decoded.Eject |= (pageResponse[6] & 0x08) == 0x08; + + decoded.SeparateChannelVolume |= (pageResponse[7] & 0x01) == 0x01; + decoded.SeparateChannelMute |= (pageResponse[7] & 0x02) == 0x02; + + decoded.MaximumSpeed = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.SupportedVolumeLevels = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.BufferSize = (ushort)((pageResponse[12] << 8) + pageResponse[13]); + decoded.CurrentSpeed = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + + if(pageResponse.Length < 20) return decoded; + + decoded.Method2 |= (pageResponse[2] & 0x04) == 0x04; + decoded.ReadCDRW |= (pageResponse[2] & 0x02) == 0x02; + decoded.ReadCDR |= (pageResponse[2] & 0x01) == 0x01; + + decoded.WriteCDRW |= (pageResponse[3] & 0x02) == 0x02; + decoded.WriteCDR |= (pageResponse[3] & 0x01) == 0x01; + + decoded.Composite |= (pageResponse[4] & 0x02) == 0x02; + decoded.DigitalPort1 |= (pageResponse[4] & 0x04) == 0x04; + decoded.DigitalPort2 |= (pageResponse[4] & 0x08) == 0x08; + + decoded.SDP |= (pageResponse[7] & 0x04) == 0x04; + decoded.SSS |= (pageResponse[7] & 0x08) == 0x08; + + decoded.Length = (byte)((pageResponse[17] & 0x30) >> 4); + decoded.LSBF |= (pageResponse[17] & 0x08) == 0x08; + decoded.RCK |= (pageResponse[17] & 0x04) == 0x04; + decoded.BCK |= (pageResponse[17] & 0x02) == 0x02; + + if(pageResponse.Length < 22) return decoded; + + decoded.TestWrite |= (pageResponse[3] & 0x04) == 0x04; + decoded.MaxWriteSpeed = (ushort)((pageResponse[18] << 8) + pageResponse[19]); + decoded.CurrentWriteSpeed = (ushort)((pageResponse[20] << 8) + pageResponse[21]); + + decoded.ReadBarcode |= (pageResponse[5] & 0x80) == 0x80; + + if(pageResponse.Length < 26) return decoded; + + decoded.ReadDVDRAM |= (pageResponse[2] & 0x20) == 0x20; + decoded.ReadDVDR |= (pageResponse[2] & 0x10) == 0x10; + decoded.ReadDVDROM |= (pageResponse[2] & 0x08) == 0x08; + + decoded.WriteDVDRAM |= (pageResponse[3] & 0x20) == 0x20; + decoded.WriteDVDR |= (pageResponse[3] & 0x10) == 0x10; + + decoded.LeadInPW |= (pageResponse[3] & 0x20) == 0x20; + decoded.SCC |= (pageResponse[3] & 0x10) == 0x10; + + decoded.CMRSupported = (ushort)((pageResponse[22] << 8) + pageResponse[23]); + + if(pageResponse.Length < 32) return decoded; + + decoded.BUF |= (pageResponse[4] & 0x80) == 0x80; + decoded.RotationControlSelected = (byte)(pageResponse[27] & 0x03); + decoded.CurrentWriteSpeedSelected = (ushort)((pageResponse[28] << 8) + pageResponse[29]); + + var descriptors = (ushort)((pageResponse.Length - 32) / 4); + decoded.WriteSpeedPerformanceDescriptors = new ModePage_2A_WriteDescriptor[descriptors]; + + for(var i = 0; i < descriptors; i++) + { + decoded.WriteSpeedPerformanceDescriptors[i] = new ModePage_2A_WriteDescriptor + { + RotationControl = (byte)(pageResponse[1 + 32 + i * 4] & 0x07), + WriteSpeed = (ushort)((pageResponse[2 + 32 + i * 4] << 8) + pageResponse[3 + 32 + i * 4]) + }; + } + + return decoded; + } + + /// Encodes a page 2Ah of a MODE SENSE response + /// Decoded page 2Ah + /// Raw page 2Ah + public static byte[] Encode(ModePage_2A decoded) + { + var pageResponse = new byte[512]; + byte length = 16; + + pageResponse[0] = 0x2A; + + if(decoded.PS) pageResponse[0] += 0x80; + + if(decoded.AudioPlay) pageResponse[4] += 0x01; + + if(decoded.Mode2Form1) pageResponse[4] += 0x10; + + if(decoded.Mode2Form2) pageResponse[4] += 0x20; + + if(decoded.MultiSession) pageResponse[4] += 0x40; + + if(decoded.CDDACommand) pageResponse[5] += 0x01; + + if(decoded.AccurateCDDA) pageResponse[5] += 0x02; + + if(decoded.Subchannel) pageResponse[5] += 0x04; + + if(decoded.DeinterlaveSubchannel) pageResponse[5] += 0x08; + + if(decoded.C2Pointer) pageResponse[5] += 0x10; + + if(decoded.UPC) pageResponse[5] += 0x20; + + if(decoded.ISRC) pageResponse[5] += 0x40; + + decoded.LoadingMechanism = (byte)((pageResponse[6] & 0xE0) >> 5); + + if(decoded.Lock) pageResponse[6] += 0x01; + + if(decoded.LockState) pageResponse[6] += 0x02; + + if(decoded.PreventJumper) pageResponse[6] += 0x04; + + if(decoded.Eject) pageResponse[6] += 0x08; + + if(decoded.SeparateChannelVolume) pageResponse[7] += 0x01; + + if(decoded.SeparateChannelMute) pageResponse[7] += 0x02; + + decoded.MaximumSpeed = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.SupportedVolumeLevels = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.BufferSize = (ushort)((pageResponse[12] << 8) + pageResponse[13]); + decoded.CurrentSpeed = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + + if(decoded.Method2 || + decoded.ReadCDRW || + decoded.ReadCDR || + decoded.WriteCDRW || + decoded.WriteCDR || + decoded.Composite || + decoded.DigitalPort1 || + decoded.DigitalPort2 || + decoded.SDP || + decoded.SSS || + decoded.Length > 0 || + decoded.LSBF || + decoded.RCK || + decoded.BCK) + { + length = 20; + + if(decoded.Method2) pageResponse[2] += 0x04; + + if(decoded.ReadCDRW) pageResponse[2] += 0x02; + + if(decoded.ReadCDR) pageResponse[2] += 0x01; + + if(decoded.WriteCDRW) pageResponse[3] += 0x02; + + if(decoded.WriteCDR) pageResponse[3] += 0x01; + + if(decoded.Composite) pageResponse[4] += 0x02; + + if(decoded.DigitalPort1) pageResponse[4] += 0x04; + + if(decoded.DigitalPort2) pageResponse[4] += 0x08; + + if(decoded.SDP) pageResponse[7] += 0x04; + + if(decoded.SSS) pageResponse[7] += 0x08; + + pageResponse[17] = (byte)(decoded.Length << 4); + + if(decoded.LSBF) pageResponse[17] += 0x08; + + if(decoded.RCK) pageResponse[17] += 0x04; + + if(decoded.BCK) pageResponse[17] += 0x02; + } + + if(decoded.TestWrite || decoded.MaxWriteSpeed > 0 || decoded.CurrentWriteSpeed > 0 || decoded.ReadBarcode) + { + length = 22; + + if(decoded.TestWrite) pageResponse[3] += 0x04; + + pageResponse[18] = (byte)((decoded.MaxWriteSpeed & 0xFF00) >> 8); + pageResponse[19] = (byte)(decoded.MaxWriteSpeed & 0xFF); + pageResponse[20] = (byte)((decoded.CurrentWriteSpeed & 0xFF00) >> 8); + pageResponse[21] = (byte)(decoded.CurrentWriteSpeed & 0xFF); + + if(decoded.ReadBarcode) pageResponse[5] += 0x80; + } + + if(decoded.ReadDVDRAM || + decoded.ReadDVDR || + decoded.ReadDVDROM || + decoded.WriteDVDRAM || + decoded.WriteDVDR || + decoded.LeadInPW || + decoded.SCC || + decoded.CMRSupported > 0) + + { + length = 26; + + if(decoded.ReadDVDRAM) pageResponse[2] += 0x20; + + if(decoded.ReadDVDR) pageResponse[2] += 0x10; + + if(decoded.ReadDVDROM) pageResponse[2] += 0x08; + + if(decoded.WriteDVDRAM) pageResponse[3] += 0x20; + + if(decoded.WriteDVDR) pageResponse[3] += 0x10; + + if(decoded.LeadInPW) pageResponse[3] += 0x20; + + if(decoded.SCC) pageResponse[3] += 0x10; + + pageResponse[22] = (byte)((decoded.CMRSupported & 0xFF00) >> 8); + pageResponse[23] = (byte)(decoded.CMRSupported & 0xFF); + } + + if(decoded.BUF || decoded.RotationControlSelected > 0 || decoded.CurrentWriteSpeedSelected > 0) + { + length = 32; + + if(decoded.BUF) pageResponse[4] += 0x80; + + pageResponse[27] += decoded.RotationControlSelected; + pageResponse[28] = (byte)((decoded.CurrentWriteSpeedSelected & 0xFF00) >> 8); + pageResponse[29] = (byte)(decoded.CurrentWriteSpeedSelected & 0xFF); + } + + if(decoded.WriteSpeedPerformanceDescriptors != null) + { + length = 32; + + for(var i = 0; i < decoded.WriteSpeedPerformanceDescriptors.Length; i++) + { + length += 4; + pageResponse[1 + 32 + i * 4] = decoded.WriteSpeedPerformanceDescriptors[i].RotationControl; + + pageResponse[2 + 32 + i * 4] = + (byte)((decoded.WriteSpeedPerformanceDescriptors[i].WriteSpeed & 0xFF00) >> 8); + + pageResponse[3 + 32 + i * 4] = (byte)(decoded.WriteSpeedPerformanceDescriptors[i].WriteSpeed & 0xFF); + } + } + + pageResponse[1] = (byte)(length - 2); + var buf = new byte[length]; + Array.Copy(pageResponse, 0, buf, 0, length); + + return buf; + } +} + +/// Page 2Ah write descriptor +[SuppressMessage("ReSharper", "InconsistentNaming")] +public struct ModePage_2A_WriteDescriptor +{ + /// Rotational control + public byte RotationControl; + /// Write speed + public ushort WriteSpeed; +} + +#endregion Mode Page 0x2A: CD-ROM capabilities page \ No newline at end of file diff --git a/Aaru.CommonTypes/Structs/Filesystems.cs b/Aaru.CommonTypes/Structs/Filesystems.cs new file mode 100644 index 000000000..0e23dc0b9 --- /dev/null +++ b/Aaru.CommonTypes/Structs/Filesystems.cs @@ -0,0 +1,303 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Common structures. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains enumerations and structures of common usage by filesystem +// plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text.Json.Serialization; + +namespace Aaru.CommonTypes.Structs; + +/// File attributes. +[Flags] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum FileAttributes : ulong +{ + /// File has no attributes + None = 0, + /// File is an alias (Mac OS) + Alias = 0x01, + /// Indicates that the file can only be writable appended + AppendOnly = 0x02, + /// File is candidate for archival/backup + Archive = 0x04, + /// File is a block device + BlockDevice = 0x08, + /// File is stored on filesystem block units instead of device sectors + BlockUnits = 0x10, + /// Directory is a bundle or file contains a BNDL resource + Bundle = 0x20, + /// File is a char device + CharDevice = 0x40, + /// File is compressed + Compressed = 0x80, + /// File is compressed and should not be uncompressed on read + CompressedRaw = 0x100, + /// File has compression errors + CompressionError = 0x200, + /// Compressed file is dirty + CompressionDirty = 0x400, + /// File is a device + Device = 0x800, + /// File is a directory + Directory = 0x1000, + /// File is encrypted + Encrypted = 0x2000, + /// File is stored on disk using extents + Extents = 0x4000, + /// File is a FIFO + FIFO = 0x8000, + /// File is a normal file + File = 0x10000, + /// File is a Mac OS file containing desktop databases that has already been added to the desktop database + HasBeenInited = 0x20000, + /// File contains an icon resource / EA + HasCustomIcon = 0x40000, + /// File is a Mac OS extension or control panel lacking INIT resources + HasNoINITs = 0x80000, + /// File is hidden/invisible + Hidden = 0x100000, + /// File cannot be written, deleted, modified or linked to + Immutable = 0x200000, + /// Directory is indexed using hashed trees + IndexedDirectory = 0x400000, + /// File contents are stored alongside its inode (or equivalent) + Inline = 0x800000, + /// File contains integrity checks + IntegrityStream = 0x1000000, + /// File is on desktop + IsOnDesk = 0x2000000, + /// File changes are written to filesystem journal before being written to file itself + Journaled = 0x4000000, + /// Access time will not be modified + NoAccessTime = 0x8000000, + /// File will not be subject to copy-on-write + NoCopyOnWrite = 0x10000000, + /// File will not be backed up + NoDump = 0x20000000, + /// File contents should not be scrubbed + NoScrub = 0x40000000, + /// File contents should not be indexed + NotIndexed = 0x80000000, + /// File is offline + Offline = 0x100000000, + /// File is password protected, but contents are not encrypted on disk + Password = 0x200000000, + /// File is read-only + ReadOnly = 0x400000000, + /// File is a reparse point + ReparsePoint = 0x800000000, + /// When file is removed its content will be overwritten with zeroes + Secured = 0x1000000000, + /// File contents are sparse + Sparse = 0x2000000000, + /// File is a shadow (OS/2) + Shadow = 0x4000000000, + /// File is shared + Shared = 0x8000000000, + /// File is a stationery + Stationery = 0x10000000000, + /// File is a symbolic link + Symlink = 0x20000000000, + /// File writes are synchronously written to disk + Sync = 0x40000000000, + /// File belongs to the operating system + System = 0x80000000000, + /// If file end is a partial block its content will be merged with other files + TailMerged = 0x100000000000, + /// File is temporary + Temporary = 0x200000000000, + /// Subdirectories inside of this directory are not related and should be allocated elsewhere + TopDirectory = 0x400000000000, + /// If file is deleted, contents should be stored, for a possible future undeletion + Undeletable = 0x800000000000, + /// File is a pipe + Pipe = 0x1000000000000, + /// File is a socket + Socket = 0x2000000000000, + /// File has not been closed + Open = 0x4000000000000, + /// File has been deleted + Deleted = 0x8000000000000, + /// File can be executed + Executable = 0x10000000000000 +} + +/// Information about a file entry +public class FileEntryInfo +{ + /// File attributes + public FileAttributes Attributes { get; set; } + + /// File length in blocks + public long Blocks { get; set; } + + /// File block size in bytes + public long BlockSize { get; set; } + + /// If file points to a device, device number. Null if the underlying filesystem does not support them. + public ulong? DeviceNo { get; set; } + + /// POSIX group ID. Null if the underlying filesystem does not support them. + public ulong? GID { get; set; } + + /// inode number for this file (or other unique identifier for the volume) + public ulong Inode { get; set; } + + /// File length in bytes + public long Length { get; set; } + + /// Number of hard links pointing to this file (. and .. entries count as hard links) + public ulong Links { get; set; } + + /// POSIX permissions/mode for this file. Null if the underlying filesystem does not support them. + public uint? Mode { get; set; } + + /// POSIX owner ID. Null if the underlying filesystem does not support them. + public ulong? UID { get; set; } + + /// File creation date in UTC. Null if the underlying filesystem does not support them. + public DateTime? CreationTimeUtc { get; set; } + + /// File last access date in UTC. Null if the underlying filesystem does not support them. + public DateTime? AccessTimeUtc { get; set; } + + /// File attributes change date in UTC. Null if the underlying filesystem does not support them. + public DateTime? StatusChangeTimeUtc { get; set; } + + /// File last backup date in UTC. Null if the underlying filesystem does not support them. + public DateTime? BackupTimeUtc { get; set; } + + /// File last modification date in UTC. Null if the underlying filesystem does not support them. + public DateTime? LastWriteTimeUtc { get; set; } + + /// File creation date. Null if the underlying filesystem does not support them. + [JsonIgnore] + public DateTime? CreationTime + { + get => CreationTimeUtc?.ToLocalTime(); + set => CreationTimeUtc = value?.ToUniversalTime(); + } + + /// File last access date. Null if the underlying filesystem does not support them. + [JsonIgnore] + public DateTime? AccessTime + { + get => AccessTimeUtc?.ToLocalTime(); + set => AccessTimeUtc = value?.ToUniversalTime(); + } + + /// File attributes change date. Null if the underlying filesystem does not support them. + [JsonIgnore] + public DateTime? StatusChangeTime + { + get => StatusChangeTimeUtc?.ToLocalTime(); + set => StatusChangeTimeUtc = value?.ToUniversalTime(); + } + + /// File last backup date. Null if the underlying filesystem does not support them. + [JsonIgnore] + public DateTime? BackupTime + { + get => BackupTimeUtc?.ToLocalTime(); + set => BackupTimeUtc = value?.ToUniversalTime(); + } + + /// File last modification date. Null if the underlying filesystem does not support them. + [JsonIgnore] + public DateTime? LastWriteTime + { + get => LastWriteTimeUtc?.ToLocalTime(); + set => LastWriteTimeUtc = value?.ToUniversalTime(); + } +} + +/// Information about a volume +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class FileSystemInfo +{ + /// Blocks for this filesystem + public ulong Blocks; + /// Maximum length of filenames on this filesystem + public ushort FilenameLength; + /// Files on this filesystem + public ulong Files; + /// Blocks free on this filesystem + public ulong FreeBlocks; + /// Free inodes on this filesystem + public ulong FreeFiles; + /// Filesystem ID + public FileSystemId Id; + /// ID of plugin for this file + public Guid PluginId; + /// Filesystem type + public string Type; + + /// Initializes an empty instance of this structure + public FileSystemInfo() => Id = new FileSystemId(); + + /// Gets a clone of this structure + /// Clone of this structure + public FileSystemInfo ShallowCopy() => (FileSystemInfo)MemberwiseClone(); +} + +/// Stores a filesystem volume unique identifier or serial number +[StructLayout(LayoutKind.Explicit)] +public struct FileSystemId +{ + /// Set to true if the identifier is a 32-bit integer + [FieldOffset(0)] + public bool IsInt; + /// Set to true if the identifier is a 64-bit integer + [FieldOffset(1)] + public bool IsLong; + /// Set to true if the identifier is a GUID + [FieldOffset(2)] + public bool IsGuid; + + /// Identifier as a 32-bit integer + [FieldOffset(3)] + public uint Serial32; + /// Identifier as a 64-bit integer + [FieldOffset(3)] + public ulong Serial64; + /// Identifier as a GUID + [FieldOffset(3)] + public Guid uuid; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Structs/Images.cs b/Aaru.CommonTypes/Structs/Images.cs new file mode 100644 index 000000000..68a81846a --- /dev/null +++ b/Aaru.CommonTypes/Structs/Images.cs @@ -0,0 +1,256 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : IMediaImage.cs +// Author(s) : Natalia Portillo +// +// Component : Common structures. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines structures to be used by media image plugins. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.CommonTypes.Structs; + +/// Contains information about a dump image and its contents +public struct ImageInfo +{ + /// Image contains partitions (or tracks for optical media) + public bool HasPartitions; + /// Image contains sessions (optical media only) + public bool HasSessions; + /// Size of the image without headers + public ulong ImageSize; + /// Sectors contained in the image + public ulong Sectors; + /// Size of sectors contained in the image + public uint SectorSize; + /// Media tags contained by the image + public List ReadableMediaTags; + /// Sector tags contained by the image + public List ReadableSectorTags; + /// Image version + public string Version; + /// Application that created the image + public string Application; + /// Version of the application that created the image + public string ApplicationVersion; + /// Who (person) created the image? + public string Creator; + /// Image creation time + public DateTime CreationTime; + /// Image last modification time + public DateTime LastModificationTime; + /// Title of the media represented by the image + public string MediaTitle; + /// Image comments + public string Comments; + /// Manufacturer of the media represented by the image + public string MediaManufacturer; + /// Model of the media represented by the image + public string MediaModel; + /// Serial number of the media represented by the image + public string MediaSerialNumber; + /// Barcode of the media represented by the image + public string MediaBarcode; + /// Part number of the media represented by the image + public string MediaPartNumber; + /// Media type represented by the image + public MediaType MediaType; + /// Number in sequence for the media represented by the image + public int MediaSequence; + /// Last media of the sequence the media represented by the image corresponds to + public int LastMediaSequence; + /// Manufacturer of the drive used to read the media represented by the image + public string DriveManufacturer; + /// Model of the drive used to read the media represented by the image + public string DriveModel; + /// Serial number of the drive used to read the media represented by the image + public string DriveSerialNumber; + /// Firmware revision of the drive used to read the media represented by the image + public string DriveFirmwareRevision; + /// Type of the media represented by the image to use in XML sidecars + public MetadataMediaType MetadataMediaType; + + // CHS geometry... + /// Cylinders of the media represented by the image + public uint Cylinders; + /// Heads of the media represented by the image + public uint Heads; + /// Sectors per track of the media represented by the image (for variable image, the smallest) + public uint SectorsPerTrack; +} + +/// Session defining structure. +public struct Session +{ + /// Session number, 1-started + public ushort Sequence; + /// First track present on this session + public uint StartTrack; + /// Last track present on this session + public uint EndTrack; + /// First sector present on this session + public ulong StartSector; + /// Last sector present on this session + public ulong EndSector; +} + +/// Track defining structure. +public class Track +{ + /// How many main channel / user data bytes are per sector in this track + public int BytesPerSector; + /// Information that does not find space in this struct + public string Description; + /// Track ending sector + public ulong EndSector; + /// Which file stores this track + public string File; + /// Starting at which byte is this track stored + public ulong FileOffset; + /// What kind of file is storing this track + public string FileType; + /// Which filter stores this track + public IFilter Filter; + /// Indexes, 00 to 99 and sector offset + public Dictionary Indexes; + /// Track pre-gap + public ulong Pregap; + /// How many main channel bytes per sector are in the file with this track + public int RawBytesPerSector; + /// Track number, 1-started + public uint Sequence; + /// Session this track belongs to + public ushort Session; + /// Track starting sector + public ulong StartSector; + /// Which file stores this track's subchannel + public string SubchannelFile; + /// Which filter stores this track's subchannel + public IFilter SubchannelFilter; + /// Starting at which byte are this track's subchannel stored + public ulong SubchannelOffset; + /// Type of subchannel stored for this track + public TrackSubchannelType SubchannelType; + /// Partition type + public TrackType Type; + + /// Initializes an empty instance of this structure + public Track() => Indexes = new Dictionary(); +} + +/// Floppy physical characteristics structure. +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public struct FloppyInfo +{ + /// Physical floppy type. + public FloppyTypes Type; + /// Bitrate in bits per second used to write the floppy, 0 if unknown or track-variable. + public uint Bitrate; + /// Physical magnetic density (coercivity) of floppy medium. + public FloppyDensities Coercivity; + /// How many physical tracks are actually written in the floppy image. + public ushort Tracks; + /// How many physical heads are actually written in the floppy image. + public byte Heads; + /// How many tracks per inch are actually written in the floppy image. + public ushort TrackDensity; +} + +/// Provides a map for linear memory structure +public struct LinearMemoryMap +{ + /// List of devices that are mapped to linear memory + [NotNull] + public LinearMemoryDevice[] Devices { get; set; } +} + +/// Provides information about a linear memory device +public struct LinearMemoryDevice +{ + /// Device manufacturer + public string Manufacturer { get; set; } + + /// Device model + public string Model { get; set; } + + /// Device package, e.g. DIP28 + public string Package { get; set; } + + /// Device location marking in PCB, e.g. U28 + public string Location { get; set; } + + /// Device functional type + public LinearMemoryType Type { get; set; } + + /// Arbitrary device information + public string Description { get; set; } + + /// + /// Physical addressing is the address considering all devices in the linear memory media, starting at the lowest + /// marking in PCB and going up incrementally. This is the view of the memory inside Aaru. + /// + public LinearMemoryAddressing PhysicalAddress { get; set; } + + /// + /// Virtual addressing is the address as seen by the hardware directly accessing the linear memory media. This + /// allows devices to be overlapped or banked. + /// + public LinearMemoryAddressing VirtualAddress { get; set; } +} + +/// Maps the addressing of a linear memory device +public class LinearMemoryAddressing +{ + /// Start in memory where the device is mapped + public ulong Start { get; set; } + + /// Length in bytes of the device, not including interleaving + public ulong Length { get; set; } + + /// Interleaving information + public LinearMemoryInterleave Interleave { get; set; } +} + +/// Provides information about a device interleaving +public class LinearMemoryInterleave +{ + /// How many bytes to skip from start of map before device first byte starts + public uint Offset { get; set; } + + /// How many bytes in memory to skip every device byte + public uint Value { get; set; } +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Structs/TapeFile.cs b/Aaru.CommonTypes/Structs/TapeFile.cs new file mode 100644 index 000000000..f03d6a812 --- /dev/null +++ b/Aaru.CommonTypes/Structs/TapeFile.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : TapeFile.cs +// Author(s) : Natalia Portillo +// +// Component : Common structures. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines a structure to hold information about a tape file object. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.CommonTypes.Structs; + +/// Describes a tape file +public struct TapeFile +{ + /// File number + public uint File; + /// Partition number + public byte Partition; + /// First block, inclusive, of the file + public ulong FirstBlock; + /// Last block, inclusive, of the file + public ulong LastBlock; +} \ No newline at end of file diff --git a/Aaru.CommonTypes/Structs/TapePartition.cs b/Aaru.CommonTypes/Structs/TapePartition.cs new file mode 100644 index 000000000..a380337bb --- /dev/null +++ b/Aaru.CommonTypes/Structs/TapePartition.cs @@ -0,0 +1,50 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : TapeFile.cs +// Author(s) : Natalia Portillo +// +// Component : Common structures. +// +// --[ Description ] ---------------------------------------------------------- +// +// Defines a structure to hold information about a tape partition. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.CommonTypes.Structs; + +/// Describes a tape partition +public struct TapePartition +{ + /// Partition number + public byte Number; + /// First block, inclusive, of the partition + public ulong FirstBlock; + /// Last block, inclusive, of the partition + public ulong LastBlock; +} \ No newline at end of file diff --git a/Aaru.Compression/ADC.cs b/Aaru.Compression/ADC.cs index 42f0dabcd..1622eaa28 100644 --- a/Aaru.Compression/ADC.cs +++ b/Aaru.Compression/ADC.cs @@ -32,27 +32,29 @@ // THE SOFTWARE. // // ---------------------------------------------------------------------------- -// Copyright © 2016-2022 Natalia Portillo +// Copyright © 2016-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Compression; - using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +namespace Aaru.Compression; + /// Implements the Apple version of RLE + // ReSharper disable once InconsistentNaming -public static class ADC +public static partial class ADC { const int PLAIN = 1; const int TWO_BYTE = 2; const int THREE_BYTE = 3; + /// Set to true if this algorithm is supported, false otherwise. public static bool IsSupported => true; - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern int AARU_adc_decode_buffer(byte[] dstBuffer, int dstSize, byte[] srcBuffer, int srcSize); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial int AARU_adc_decode_buffer(byte[] dstBuffer, int dstSize, byte[] srcBuffer, int srcSize); [MethodImpl(MethodImplOptions.AggressiveInlining)] static int GetChunkType(byte byt) => (byt & 0x80) == 0x80 @@ -86,29 +88,28 @@ public static class ADC [MethodImpl(MethodImplOptions.AggressiveOptimization)] public static int DecodeBuffer(byte[] source, byte[] destination) { - if(Native.IsSupported) - return AARU_adc_decode_buffer(destination, destination.Length, source, source.Length); + if(Native.IsSupported) return AARU_adc_decode_buffer(destination, destination.Length, source, source.Length); var inputPosition = 0; - int chunkSize; - int offset; - int chunkType; - var outPosition = 0; - Span temp = stackalloc byte[3]; + var outPosition = 0; + Span temp = stackalloc byte[3]; while(inputPosition < source.Length) { byte readByte = source[inputPosition++]; - chunkType = GetChunkType(readByte); + int chunkType = GetChunkType(readByte); + + int chunkSize; + + int offset; switch(chunkType) { case PLAIN: chunkSize = GetChunkSize(readByte); - if(outPosition + chunkSize > destination.Length) - goto finished; + if(outPosition + chunkSize > destination.Length) goto finished; Array.Copy(source, inputPosition, destination, outPosition, chunkSize); outPosition += chunkSize; @@ -121,8 +122,7 @@ public static class ADC temp[1] = source[inputPosition++]; offset = GetOffset(temp); - if(outPosition + chunkSize > destination.Length) - goto finished; + if(outPosition + chunkSize > destination.Length) goto finished; if(offset == 0) { @@ -135,11 +135,13 @@ public static class ADC } } else + { for(var i = 0; i < chunkSize; i++) { destination[outPosition] = destination[outPosition - offset - 1]; outPosition++; } + } break; case THREE_BYTE: @@ -149,8 +151,7 @@ public static class ADC temp[2] = source[inputPosition++]; offset = GetOffset(temp); - if(outPosition + chunkSize > destination.Length) - goto finished; + if(outPosition + chunkSize > destination.Length) goto finished; if(offset == 0) { @@ -163,11 +164,13 @@ public static class ADC } } else + { for(var i = 0; i < chunkSize; i++) { destination[outPosition] = destination[outPosition - offset - 1]; outPosition++; } + } break; } diff --git a/Aaru.Compression/Aaru.Compression.csproj b/Aaru.Compression/Aaru.Compression.csproj index 39eec0a81..867ee014d 100644 --- a/Aaru.Compression/Aaru.Compression.csproj +++ b/Aaru.Compression/Aaru.Compression.csproj @@ -1,128 +1,125 @@  - - Debug - AnyCPU - {858398D1-7321-4763-8BAB-56BBFEC74E29} - Library - Properties - Aaru.Compression - Aaru.Compression - 512 - $(Version) - false - true - 6.0.0-alpha8 - Claunia.com - Copyright © 2011-2022 Natalia Portillo - Aaru Data Preservation Suite - Aaru Data Preservation Suite - $(Version) - net6.0 - 10 - Compression algorithms used by the Aaru Data Preservation Suite. - https://github.com/aaru-dps/ - LGPL-2.1-only - https://github.com/aaru-dps/Aaru - true - en-US - true - true - snupkg - Natalia Portillo <claunia@claunia.com> - true - - - $(Version)+{chash:8} - true - true - - - AnyCPU - true - full - false - bin\Debug - DEBUG;TRACE - prompt - 4 - true - - - AnyCPU - pdbonly - true - bin\Release - TRACE - prompt - 4 - true - - - - $(DefaultItemExcludes);cuetools.net/**/* - - - - - - - - - - - - - - - - - - - - - - - - - - LICENSE.LGPL - - - - - - - - - - - - - - - - /Library/Frameworks/Mono.framework/Versions/Current/lib/mono - /usr/lib/mono - /usr/local/lib/mono - - $(BaseFrameworkPathOverrideForMono)/4.0-api - $(BaseFrameworkPathOverrideForMono)/4.5-api - $(BaseFrameworkPathOverrideForMono)/4.5.1-api - $(BaseFrameworkPathOverrideForMono)/4.5.2-api - $(BaseFrameworkPathOverrideForMono)/4.6-api - $(BaseFrameworkPathOverrideForMono)/4.6.1-api - $(BaseFrameworkPathOverrideForMono)/4.6.2-api - $(BaseFrameworkPathOverrideForMono)/4.7-api - $(BaseFrameworkPathOverrideForMono)/4.7.1-api - true - - $(FrameworkPathOverride)/Facades;$(AssemblySearchPaths) - + + {858398D1-7321-4763-8BAB-56BBFEC74E29} + Library + Properties + Aaru.Compression + Aaru.Compression + 512 + $(Version) + false + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru Data Preservation Suite + $(Version) + net8.0 + 12 + Compression algorithms used by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + LGPL-2.1-only + https://github.com/aaru-dps/Aaru + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + $(DefaultItemExcludes);cuetools.net/**/* + + + + + + + + + + + + + + + + + + + + + + + + + LICENSE.LGPL + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + \ No newline at end of file diff --git a/Aaru.Compression/AppleRle.cs b/Aaru.Compression/AppleRle.cs index 5f8dd818d..7b22577d3 100644 --- a/Aaru.Compression/AppleRle.cs +++ b/Aaru.Compression/AppleRle.cs @@ -27,23 +27,25 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // Copyright © 2018-2019 David Ryskalczyk // ****************************************************************************/ -namespace Aaru.Compression; - using System.Runtime.InteropServices; +namespace Aaru.Compression; + /// Implements the Apple version of RLE -public static class AppleRle +public static partial class AppleRle { const uint DART_CHUNK = 20960; + /// Set to true if this algorithm is supported, false otherwise. public static bool IsSupported => true; - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern int AARU_apple_rle_decode_buffer(byte[] dstBuffer, int dstSize, byte[] srcBuffer, int srcSize); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial int AARU_apple_rle_decode_buffer(byte[] dstBuffer, int dstSize, byte[] srcBuffer, + int srcSize); /// Decodes a buffer compressed with Apple RLE /// Encoded buffer @@ -60,8 +62,7 @@ public static class AppleRle var repeatMode = false; // true if we're repeating, false if we're just copying int inPosition = 0, outPosition = 0; - while(inPosition <= source.Length && - outPosition <= destination.Length) + while(inPosition <= source.Length && outPosition <= destination.Length) { switch(repeatMode) { @@ -92,19 +93,15 @@ public static class AppleRle continue; } - if(inPosition == source.Length) - break; + if(inPosition == source.Length) break; while(true) { byte b1 = source[inPosition++]; byte b2 = source[inPosition++]; - var s = (short)((b1 << 8) | b2); + var s = (short)(b1 << 8 | b2); - if(s == 0 || - s >= DART_CHUNK || - s <= -DART_CHUNK) - continue; + if(s == 0 || s >= DART_CHUNK || s <= -DART_CHUNK) continue; if(s < 0) { diff --git a/Aaru.Compression/BZip2.cs b/Aaru.Compression/BZip2.cs index 9f0b611e9..3585b2330 100644 --- a/Aaru.Compression/BZip2.cs +++ b/Aaru.Compression/BZip2.cs @@ -23,29 +23,28 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Compression; - using System.IO; using System.Runtime.InteropServices; using Ionic.BZip2; -/// -/// Implements the BZIP2 compression algorithm -/// -public class BZip2 +namespace Aaru.Compression; + +/// Implements the BZIP2 compression algorithm +public partial class BZip2 { /// Set to true if this algorithm is supported, false otherwise. public static bool IsSupported => true; - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern int AARU_bzip2_decode_buffer(byte[] dstBuffer, ref uint dstSize, byte[] srcBuffer, uint srcSize); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial int AARU_bzip2_decode_buffer(byte[] dstBuffer, ref uint dstSize, byte[] srcBuffer, + uint srcSize); - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern int AARU_bzip2_encode_buffer(byte[] dstBuffer, ref uint dstSize, byte[] srcBuffer, uint srcSize, - int blockSize100K); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial int AARU_bzip2_encode_buffer(byte[] dstBuffer, ref uint dstSize, byte[] srcBuffer, + uint srcSize, int blockSize100K); /// Decodes a buffer compressed with BZIP2 /// Encoded buffer diff --git a/Aaru.Compression/FLAC.cs b/Aaru.Compression/FLAC.cs index 295cd54e4..c5762797e 100644 --- a/Aaru.Compression/FLAC.cs +++ b/Aaru.Compression/FLAC.cs @@ -23,35 +23,37 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Compression; - using System.IO; using System.Runtime.InteropServices; +using Aaru.Helpers.IO; using CUETools.Codecs; using CUETools.Codecs.Flake; +namespace Aaru.Compression; + // ReSharper disable once InconsistentNaming /// Implements the FLAC lossless audio compression algorithm -public class FLAC +public partial class FLAC { /// Set to true if this algorithm is supported, false otherwise. public static bool IsSupported => true; - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern nuint AARU_flac_decode_redbook_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, - nuint srcSize); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial nuint AARU_flac_decode_redbook_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, + nuint srcSize); - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern nuint AARU_flac_encode_redbook_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, - nuint srcSize, uint blocksize, int doMidSideStereo, - int looseMidSideStereo, string apodization, uint maxLpcOrder, - uint qlpCoeffPrecision, int doQlpCoeffPrecSearch, - int doExhaustiveModelSearch, uint minResidualPartitionOrder, - uint maxResidualPartitionOrder, string applicationID, - uint applicationIDLen); + [LibraryImport("libAaru.Compression.Native", SetLastError = true, StringMarshalling = StringMarshalling.Utf8)] + private static partial nuint AARU_flac_encode_redbook_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, + nuint srcSize, uint blocksize, int doMidSideStereo, + int looseMidSideStereo, string apodization, + uint maxLpcOrder, uint qlpCoeffPrecision, + int doQlpCoeffPrecSearch, int doExhaustiveModelSearch, + uint minResidualPartitionOrder, + uint maxResidualPartitionOrder, string applicationID, + uint applicationIDLen); /// Decodes a buffer compressed with FLAC /// Encoded buffer @@ -60,8 +62,12 @@ public class FLAC public static int DecodeBuffer(byte[] source, byte[] destination) { if(Native.IsSupported) - return (int)AARU_flac_decode_redbook_buffer(destination, (nuint)destination.Length, source, + { + return (int)AARU_flac_decode_redbook_buffer(destination, + (nuint)destination.Length, + source, (nuint)source.Length); + } var flacMs = new MemoryStream(source); var flakeReader = new AudioDecoder(new DecoderSettings(), "", flacMs); @@ -95,13 +101,24 @@ public class FLAC uint minResidualPartitionOrder, uint maxResidualPartitionOrder, string applicationID) { if(Native.IsSupported) - return (int)AARU_flac_encode_redbook_buffer(destination, (nuint)destination.Length, source, - (nuint)source.Length, blockSize, doMidSideStereo ? 1 : 0, - looseMidSideStereo ? 1 : 0, apodization, maxLpcOrder, - qlpCoeffPrecision, doQlpCoeffPrecSearch ? 1 : 0, - doExhaustiveModelSearch ? 1 : 0, minResidualPartitionOrder, - maxResidualPartitionOrder, applicationID, + { + return (int)AARU_flac_encode_redbook_buffer(destination, + (nuint)destination.Length, + source, + (nuint)source.Length, + blockSize, + doMidSideStereo ? 1 : 0, + looseMidSideStereo ? 1 : 0, + apodization, + maxLpcOrder, + qlpCoeffPrecision, + doQlpCoeffPrecSearch ? 1 : 0, + doExhaustiveModelSearch ? 1 : 0, + minResidualPartitionOrder, + maxResidualPartitionOrder, + applicationID, (uint)applicationID.Length); + } var flakeWriterSettings = new EncoderSettings { @@ -126,11 +143,9 @@ public class FLAC }; // Check if FLAKE's block size is bigger than what we want - if(flakeWriterSettings.BlockSize > 4608) - flakeWriterSettings.BlockSize = 4608; + if(flakeWriterSettings.BlockSize > 4608) flakeWriterSettings.BlockSize = 4608; - if(flakeWriterSettings.BlockSize < 256) - flakeWriterSettings.BlockSize = 256; + if(flakeWriterSettings.BlockSize < 256) flakeWriterSettings.BlockSize = 256; var flacMs = new NonClosableStream(destination); var flakeWriter = new AudioEncoder(flakeWriterSettings, "", flacMs); diff --git a/Aaru.Compression/LZFSE.cs b/Aaru.Compression/LZFSE.cs index b3d0c451f..e4c8c92fb 100644 --- a/Aaru.Compression/LZFSE.cs +++ b/Aaru.Compression/LZFSE.cs @@ -23,29 +23,27 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Compression; - using System.Runtime.InteropServices; +namespace Aaru.Compression; + // ReSharper disable once InconsistentNaming -/// -/// Implements the LZFSE compression algorithm -/// -public class LZFSE +/// Implements the LZFSE compression algorithm +public partial class LZFSE { /// Set to true if this algorithm is supported, false otherwise. public static bool IsSupported => Native.IsSupported; - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern nuint AARU_lzfse_decode_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, nuint srcSize, - byte[] scratchBuffer); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial nuint AARU_lzfse_decode_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, + nuint srcSize, byte[] scratchBuffer); - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern nuint AARU_lzfse_encode_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, nuint srcSize, - byte[] scratchBuffer); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial nuint AARU_lzfse_encode_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, + nuint srcSize, byte[] scratchBuffer); /// Decodes a buffer compressed with LZFSE /// Encoded buffer @@ -54,8 +52,11 @@ public class LZFSE public static int DecodeBuffer(byte[] source, byte[] destination) => Native.IsSupported ? (int) AARU_lzfse_decode_buffer(destination, - (nuint)destination.Length, source, - (nuint)source.Length, null) : 0; + (nuint)destination.Length, + source, + (nuint)source.Length, + null) + : 0; /// Compresses a buffer using BZIP2 /// Data to compress @@ -64,6 +65,9 @@ public class LZFSE public static int EncodeBuffer(byte[] source, byte[] destination) => Native.IsSupported ? (int) AARU_lzfse_encode_buffer(destination, - (nuint)destination.Length, source, - (nuint)source.Length, null) : 0; + (nuint)destination.Length, + source, + (nuint)source.Length, + null) + : 0; } \ No newline at end of file diff --git a/Aaru.Compression/LZIP.cs b/Aaru.Compression/LZIP.cs index 73267d969..5bbdd803d 100644 --- a/Aaru.Compression/LZIP.cs +++ b/Aaru.Compression/LZIP.cs @@ -23,28 +23,26 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Compression; - using System.Runtime.InteropServices; +namespace Aaru.Compression; + // ReSharper disable once InconsistentNaming -/// -/// Implements the LZIP compression algorithm -/// -public class LZIP +/// Implements the LZIP compression algorithm +public partial class LZIP { /// Set to true if this algorithm is supported, false otherwise. public static bool IsSupported => Native.IsSupported; - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern int AARU_lzip_decode_buffer(byte[] dstBuffer, int dstSize, byte[] srcBuffer, int srcSize); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial int AARU_lzip_decode_buffer(byte[] dstBuffer, int dstSize, byte[] srcBuffer, int srcSize); - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern int AARU_lzip_encode_buffer(byte[] dstBuffer, int dstSize, byte[] srcBuffer, int srcSize, - int dictionarySize, int matchLenLimit); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial int AARU_lzip_encode_buffer(byte[] dstBuffer, int dstSize, byte[] srcBuffer, int srcSize, + int dictionarySize, int matchLenLimit); /// Decodes a buffer compressed with LZIP /// Encoded buffer @@ -60,6 +58,12 @@ public class LZIP /// Match length limit /// The size of the compressed data public static int EncodeBuffer(byte[] source, byte[] destination, int dictionarySize, int matchLengthLimit) => - Native.IsSupported ? AARU_lzip_encode_buffer(destination, destination.Length, source, source.Length, - dictionarySize, matchLengthLimit) : 0; + Native.IsSupported + ? AARU_lzip_encode_buffer(destination, + destination.Length, + source, + source.Length, + dictionarySize, + matchLengthLimit) + : 0; } \ No newline at end of file diff --git a/Aaru.Compression/LZMA.cs b/Aaru.Compression/LZMA.cs index 66aa43018..fb3d6740a 100644 --- a/Aaru.Compression/LZMA.cs +++ b/Aaru.Compression/LZMA.cs @@ -23,31 +23,31 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Compression; - using System.IO; using System.Runtime.InteropServices; +using Aaru.Helpers; using SharpCompress.Compressors.LZMA; -/// -/// Implements the LZMA compression algorithm -/// -public class LZMA +namespace Aaru.Compression; + +/// Implements the LZMA compression algorithm +public partial class LZMA { /// Set to true if this algorithm is supported, false otherwise. public static bool IsSupported => true; - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern int AARU_lzma_decode_buffer(byte[] dstBuffer, ref nuint dstSize, byte[] srcBuffer, - ref nuint srcSize, byte[] props, nuint propsSize); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial int AARU_lzma_decode_buffer(byte[] dstBuffer, ref nuint dstSize, byte[] srcBuffer, + ref nuint srcSize, byte[] props, nuint propsSize); - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern int AARU_lzma_encode_buffer(byte[] dstBuffer, ref nuint dstSize, byte[] srcBuffer, nuint srcSize, - byte[] outProps, ref nuint outPropsSize, int level, uint dictSize, int lc, - int lp, int pb, int fb, int numThreads); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial int AARU_lzma_encode_buffer(byte[] dstBuffer, ref nuint dstSize, byte[] srcBuffer, + nuint srcSize, byte[] outProps, ref nuint outPropsSize, + int level, uint dictSize, int lc, int lp, int pb, int fb, + int numThreads); /// Decodes a buffer compressed with LZMA /// Encoded buffer @@ -61,7 +61,11 @@ public class LZMA var srcSize = (nuint)source.Length; var dstSize = (nuint)destination.Length; - AARU_lzma_decode_buffer(destination, ref dstSize, source, ref srcSize, properties, + AARU_lzma_decode_buffer(destination, + ref dstSize, + source, + ref srcSize, + properties, (nuint)properties.Length); return (int)dstSize; @@ -69,7 +73,7 @@ public class LZMA using var cmpMs = new MemoryStream(source); using var lzmaBlock = new LzmaStream(properties, cmpMs); - lzmaBlock.Read(destination, 0, destination.Length); + lzmaBlock.EnsureRead(destination, 0, destination.Length); return destination.Length; } @@ -83,9 +87,10 @@ public class LZMA /// Literal context bits /// Literal position bits /// Position bits - /// + /// Forward bits + /// How many bytes have been written to the destination buffer public static int EncodeBuffer(byte[] source, byte[] destination, out byte[] properties, int level, uint dictSize, - int lc, int lp, int pb, int fb) + int lc, int lp, int pb, int fb) { if(Native.IsSupported) { @@ -94,8 +99,19 @@ public class LZMA var propsSize = (nuint)properties.Length; var srcSize = (nuint)source.Length; - AARU_lzma_encode_buffer(destination, ref dstSize, source, srcSize, properties, ref propsSize, level, - dictSize, lc, lp, pb, fb, 0); + AARU_lzma_encode_buffer(destination, + ref dstSize, + source, + srcSize, + properties, + ref propsSize, + level, + dictSize, + lc, + lp, + pb, + fb, + 0); return (int)dstSize; } diff --git a/Aaru.Compression/Native.cs b/Aaru.Compression/Native.cs index 0e7dd2ba4..e7c802a38 100644 --- a/Aaru.Compression/Native.cs +++ b/Aaru.Compression/Native.cs @@ -27,17 +27,15 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Compression; - using System.Runtime.InteropServices; -/// -/// Handles native implementations of compression algorithms -/// -public static class Native +namespace Aaru.Compression; + +/// Handles native implementations of compression algorithms +public static partial class Native { static bool _checked; static bool _supported; @@ -53,11 +51,9 @@ public static class Native { get { - if(ForceManaged) - return false; + if(ForceManaged) return false; - if(_checked) - return _supported; + if(_checked) return _supported; ulong version; _checked = true; @@ -80,6 +76,6 @@ public static class Native } } - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern ulong AARU_get_acn_version(); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial ulong AARU_get_acn_version(); } \ No newline at end of file diff --git a/Aaru.Compression/TeleDiskLzh.cs b/Aaru.Compression/TeleDiskLzh.cs index 3a6a6db7f..47ef32b86 100644 --- a/Aaru.Compression/TeleDiskLzh.cs +++ b/Aaru.Compression/TeleDiskLzh.cs @@ -35,17 +35,18 @@ // POSSIBILITY OF SUCH DAMAGE. // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // Copyright © 2017 Miodrag Milanovic // Copyright © 1988 Haruhiko OKUMURA // Copyright © 1988 Haruyasu YOSHIZAKI // Copyright © 1988 Kenji RIKITAKE // ****************************************************************************/ -namespace Aaru.Compression; - using System; using System.IO; +using Aaru.Helpers; + +namespace Aaru.Compression; /* * Based on Japanese version 29-NOV-1988 @@ -79,7 +80,7 @@ public class TeleDiskLzh /* decoder table */ readonly byte[] _dCode = - { + [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, @@ -95,10 +96,10 @@ public class TeleDiskLzh 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F - }; + ]; readonly byte[] _dLen = - { + [ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, @@ -114,7 +115,7 @@ public class TeleDiskLzh 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 - }; + ]; readonly ushort[] _freq = new ushort[T + 1]; /* cumulative freq table */ readonly Stream _inStream; @@ -146,8 +147,7 @@ public class TeleDiskLzh _tdctl.Bufcnt = 0; StartHuff(); - for(i = 0; i < N - F; i++) - _textBuf[i] = 0x20; + for(i = 0; i < N - F; i++) _textBuf[i] = 0x20; _tdctl.R = N - F; _inStream = dataStream; @@ -168,15 +168,16 @@ public class TeleDiskLzh /// Number of decompressed bytes public int Decode(out byte[] buf, int len) /* Decoding/Uncompressing */ { - short c; buf = new byte[len]; int count; // was an unsigned long, seems unnecessary for(count = 0; count < len;) + { + short c; + if(_tdctl.Bufcnt == 0) { - if((c = DecodeChar()) < 0) - return count; // fatal error + if((c = DecodeChar()) < 0) return count; // fatal error if(c < 256) { @@ -189,21 +190,19 @@ public class TeleDiskLzh { short pos; - if((pos = DecodePosition()) < 0) - return count; // fatal error + if((pos = DecodePosition()) < 0) return count; // fatal error - _tdctl.Bufpos = (ushort)((_tdctl.R - pos - 1) & (N - 1)); - _tdctl.Bufcnt = (ushort)(c - 255 + THRESHOLD); + _tdctl.Bufpos = (ushort)(_tdctl.R - pos - 1 & N - 1); + _tdctl.Bufcnt = (ushort)(c - 255 + THRESHOLD); _tdctl.Bufndx = 0; } } else { // still chars from last string - while(_tdctl.Bufndx < _tdctl.Bufcnt && - count < len) + while(_tdctl.Bufndx < _tdctl.Bufcnt && count < len) { - c = _textBuf[(_tdctl.Bufpos + _tdctl.Bufndx) & (N - 1)]; + c = _textBuf[_tdctl.Bufpos + _tdctl.Bufndx & N - 1]; buf[count] = (byte)c; _tdctl.Bufndx++; _textBuf[_tdctl.R++] = (byte)c; @@ -212,20 +211,19 @@ public class TeleDiskLzh } // reset bufcnt after copy string from text_buf[] - if(_tdctl.Bufndx >= _tdctl.Bufcnt) - _tdctl.Bufndx = _tdctl.Bufcnt = 0; + if(_tdctl.Bufndx >= _tdctl.Bufcnt) _tdctl.Bufndx = _tdctl.Bufcnt = 0; } + } return count; // count == len, success } long DataRead(out byte[] buf, long size) { - if(size > _inStream.Length - _inStream.Position) - size = _inStream.Length - _inStream.Position; + if(size > _inStream.Length - _inStream.Position) size = _inStream.Length - _inStream.Position; buf = new byte[size]; - _inStream.Read(buf, 0, (int)size); + _inStream.EnsureRead(buf, 0, (int)size); return size; } @@ -237,14 +235,13 @@ public class TeleDiskLzh _tdctl.Ibufndx = 0; _tdctl.Ibufcnt = (ushort)DataRead(out _tdctl.Inbuf, BUFSZ); - if(_tdctl.Ibufcnt <= 0) - return -1; + if(_tdctl.Ibufcnt <= 0) return -1; } while(_getlen <= 8) { // typically reads a word at a time - _getbuf |= (ushort)(_tdctl.Inbuf[_tdctl.Ibufndx++] << (8 - _getlen)); + _getbuf |= (ushort)(_tdctl.Inbuf[_tdctl.Ibufndx++] << 8 - _getlen); _getlen += 8; } @@ -253,8 +250,7 @@ public class TeleDiskLzh int GetBit() /* get one bit */ { - if(NextWord() < 0) - return -1; + if(NextWord() < 0) return -1; var i = (short)_getbuf; _getbuf <<= 1; @@ -265,8 +261,7 @@ public class TeleDiskLzh int GetByte() /* get a byte */ { - if(NextWord() != 0) - return -1; + if(NextWord() != 0) return -1; ushort i = _getbuf; _getbuf <<= 8; @@ -315,12 +310,13 @@ public class TeleDiskLzh short j = 0; for(i = 0; i < T; i++) - if(_son[i] >= T) - { - _freq[j] = (ushort)((_freq[i] + 1) / 2); - _son[j] = _son[i]; - j++; - } + { + if(_son[i] < T) continue; + + _freq[j] = (ushort)((_freq[i] + 1) / 2); + _son[j] = _son[i]; + j++; + } /* make a tree : first, connect children nodes */ for(i = 0, j = N_CHAR; j < T; i += 2, j++) @@ -341,18 +337,19 @@ public class TeleDiskLzh /* connect parent nodes */ for(i = 0; i < T; i++) + { if((k = _son[i]) >= T) _prnt[k] = i; else _prnt[k] = _prnt[k + 1] = i; + } } /* update freq tree */ void Update(int c) { - if(_freq[ROOT] == MAX_FREQ) - Reconst(); + if(_freq[ROOT] == MAX_FREQ) Reconst(); c = _prnt[c + T]; @@ -363,8 +360,7 @@ public class TeleDiskLzh /* swap nodes to keep the tree freq-ordered */ int l; - if(k <= _freq[l = c + 1]) - continue; + if(k <= _freq[l = c + 1]) continue; while(k > _freq[++l]) {} @@ -375,16 +371,14 @@ public class TeleDiskLzh int i = _son[c]; _prnt[i] = (short)l; - if(i < T) - _prnt[i + 1] = (short)l; + if(i < T) _prnt[i + 1] = (short)l; int j = _son[l]; _son[l] = (short)i; _prnt[j] = (short)c; - if(j < T) - _prnt[j + 1] = (short)c; + if(j < T) _prnt[j + 1] = (short)c; _son[c] = (short)j; @@ -405,8 +399,7 @@ public class TeleDiskLzh { int ret; - if((ret = GetBit()) < 0) - return -1; + if((ret = GetBit()) < 0) return -1; c += (ushort)ret; c = (ushort)_son[c]; @@ -423,8 +416,7 @@ public class TeleDiskLzh short bit; /* decode upper 6 bits from given table */ - if((bit = (short)GetByte()) < 0) - return -1; + if((bit = (short)GetByte()) < 0) return -1; var i = (ushort)bit; var c = (ushort)(_dCode[i] << 6); @@ -435,22 +427,30 @@ public class TeleDiskLzh while(j-- > 0) { - if((bit = (short)GetBit()) < 0) - return -1; + if((bit = (short)GetBit()) < 0) return -1; i = (ushort)((i << 1) + bit); } - return (short)(c | (i & 0x3f)); + return (short)(c | i & 0x3f); } + +#region Nested type: Tdlzhuf + /* update when cumulative frequency */ /* reaches to this value */ struct Tdlzhuf { - public ushort R, Bufcnt, Bufndx, Bufpos, // string buffer + public ushort R, + Bufcnt, + Bufndx, + Bufpos, // string buffer // the following to allow block reads from input in next_word() - Ibufcnt, Ibufndx; // input buffer counters - public byte[] Inbuf; // input buffer + Ibufcnt, + Ibufndx; // input buffer counters + public byte[] Inbuf; // input buffer } + +#endregion } \ No newline at end of file diff --git a/Aaru.Compression/ZSTD.cs b/Aaru.Compression/ZSTD.cs index f1813716f..128c984a9 100644 --- a/Aaru.Compression/ZSTD.cs +++ b/Aaru.Compression/ZSTD.cs @@ -23,28 +23,27 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Compression; - using System.Runtime.InteropServices; +namespace Aaru.Compression; + // ReSharper disable once InconsistentNaming -/// -/// Implements the zstandard compression algorithm -/// -public class ZSTD +/// Implements the zstandard compression algorithm +public partial class ZSTD { /// Set to true if this algorithm is supported, false otherwise. public static bool IsSupported => Native.IsSupported; - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern nuint AARU_zstd_decode_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, nuint srcSize); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial nuint AARU_zstd_decode_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, + nuint srcSize); - [DllImport("libAaru.Compression.Native", SetLastError = true)] - static extern nuint AARU_zstd_encode_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, nuint srcSize, - int compressionLevel); + [LibraryImport("libAaru.Compression.Native", SetLastError = true)] + private static partial nuint AARU_zstd_encode_buffer(byte[] dstBuffer, nuint dstSize, byte[] srcBuffer, + nuint srcSize, int compressionLevel); /// Decodes a buffer compressed with ZSTD /// Encoded buffer @@ -52,7 +51,8 @@ public class ZSTD /// The number of decoded bytes public static int DecodeBuffer(byte[] source, byte[] destination) => (int)(Native.IsSupported - ? AARU_zstd_decode_buffer(destination, (nuint)destination.Length, source, (nuint)source.Length) : 0); + ? AARU_zstd_decode_buffer(destination, (nuint)destination.Length, source, (nuint)source.Length) + : 0); /// Compresses a buffer using ZSTD /// Data to compress @@ -61,6 +61,10 @@ public class ZSTD /// Length of the compressed data public static int EncodeBuffer(byte[] source, byte[] destination, int compressionLevel) => (int)(Native.IsSupported - ? AARU_zstd_encode_buffer(destination, (nuint)destination.Length, source, (nuint)source.Length, - compressionLevel) : 0); + ? AARU_zstd_encode_buffer(destination, + (nuint)destination.Length, + source, + (nuint)source.Length, + compressionLevel) + : 0); } \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net b/Aaru.Compression/cuetools.net deleted file mode 160000 index becd5fde9..000000000 --- a/Aaru.Compression/cuetools.net +++ /dev/null @@ -1 +0,0 @@ -Subproject commit becd5fde95b0e336740487ecde6d7add067cee83 diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/AudioDecoder.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/AudioDecoder.cs new file mode 100644 index 000000000..2962a29d9 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/AudioDecoder.cs @@ -0,0 +1,823 @@ +/** + * CUETools.Flake: pure managed FLAC audio encoder + * Copyright (c) 2009-2021 Grigory Chudov + * Based on Flake encoder, http://flake-enc.sourceforge.net/ + * Copyright (c) 2006-2009 Justin Ruggles + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +using System; +using System.IO; + +namespace CUETools.Codecs.Flake; + +public class AudioDecoder : IAudioSource +{ + readonly byte[] _framesBuffer; + readonly Stream _IO; + + readonly Crc8 crc8; + readonly FlacFrame frame; + readonly BitReader framereader; + + readonly DecoderSettings m_settings; + readonly int[] residualBuffer; + int _framesBufferLength, _framesBufferOffset; + + long _sampleOffset; + + int _samplesInBuffer, _samplesBufferOffset; + + long first_frame_offset; + uint max_block_size; + uint max_frame_size; + + uint min_block_size; + uint min_frame_size; + + SeekPoint[] seek_table; + + public AudioDecoder(DecoderSettings settings, string path, Stream IO = null) + { + m_settings = settings; + + Path = path; + _IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000); + + crc8 = new Crc8(); + + _framesBuffer = new byte[0x20000]; + decode_metadata(); + + frame = new FlacFrame(PCM.ChannelCount); + framereader = new BitReader(); + + //max_frame_size = 16 + ((Flake.MAX_BLOCKSIZE * PCM.BitsPerSample * PCM.ChannelCount + 1) + 7) >> 3); + if((int)max_frame_size * PCM.BitsPerSample * PCM.ChannelCount * 2 >> 3 > _framesBuffer.Length) + { + byte[] temp = _framesBuffer; + _framesBuffer = new byte[(int)max_frame_size * PCM.BitsPerSample * PCM.ChannelCount * 2 >> 3]; + if(_framesBufferLength > 0) Array.Copy(temp, _framesBufferOffset, _framesBuffer, 0, _framesBufferLength); + _framesBufferOffset = 0; + } + + _samplesInBuffer = 0; + + if(PCM.BitsPerSample != 16 && PCM.BitsPerSample != 24) throw new Exception("invalid flac file"); + + Samples = new int[FlakeConstants.MAX_BLOCKSIZE * PCM.ChannelCount]; + residualBuffer = new int[FlakeConstants.MAX_BLOCKSIZE * PCM.ChannelCount]; + } + + public AudioDecoder(AudioPCMConfig _pcm) + { + PCM = _pcm; + crc8 = new Crc8(); + + Samples = new int[FlakeConstants.MAX_BLOCKSIZE * PCM.ChannelCount]; + residualBuffer = new int[FlakeConstants.MAX_BLOCKSIZE * PCM.ChannelCount]; + frame = new FlacFrame(PCM.ChannelCount); + framereader = new BitReader(); + } + + public bool DoCRC { get; set; } = true; + + public int[] Samples { get; } + +#region IAudioSource Members + + public IAudioDecoderSettings Settings => m_settings; + + public void Close() + { + _IO.Close(); + } + + public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate); + + public long Length { get; private set; } + + public long Remaining => Length - Position; + + public long Position + { + get => _sampleOffset - _samplesInBuffer; + set + { + if(value > Length) throw new Exception("seeking past end of stream"); + + if(value < Position || value > _sampleOffset) + { + if(seek_table != null && _IO.CanSeek) + { + int best_st = -1; + + for(var st = 0; st < seek_table.Length; st++) + { + if(seek_table[st].number <= value && + (best_st == -1 || seek_table[st].number > seek_table[best_st].number)) + best_st = st; + } + + if(best_st != -1) + { + _framesBufferLength = 0; + _samplesInBuffer = 0; + _samplesBufferOffset = 0; + _IO.Position = seek_table[best_st].offset + first_frame_offset; + _sampleOffset = seek_table[best_st].number; + } + } + + if(value < Position) throw new Exception("cannot seek backwards without seek table"); + } + + while(value > _sampleOffset) + { + _samplesInBuffer = 0; + _samplesBufferOffset = 0; + + fill_frames_buffer(); + + if(_framesBufferLength == 0) throw new Exception("seek failed"); + + int bytesDecoded = DecodeFrame(_framesBuffer, _framesBufferOffset, _framesBufferLength); + _framesBufferLength -= bytesDecoded; + _framesBufferOffset += bytesDecoded; + + _sampleOffset += _samplesInBuffer; + } + + ; + int diff = _samplesInBuffer - (int)(_sampleOffset - value); + _samplesInBuffer -= diff; + _samplesBufferOffset += diff; + } + } + + public AudioPCMConfig PCM { get; private set; } + + public string Path { get; } + + public int Read(AudioBuffer buff, int maxLength) + { + buff.Prepare(this, maxLength); + + var offset = 0; + int sampleCount = buff.Length; + + while(_samplesInBuffer < sampleCount) + { + if(_samplesInBuffer > 0) + { + interlace(buff, offset, _samplesInBuffer); + sampleCount -= _samplesInBuffer; + offset += _samplesInBuffer; + _samplesInBuffer = 0; + _samplesBufferOffset = 0; + } + + fill_frames_buffer(); + + if(_framesBufferLength == 0) return buff.Length = offset; + + int bytesDecoded = DecodeFrame(_framesBuffer, _framesBufferOffset, _framesBufferLength); + _framesBufferLength -= bytesDecoded; + _framesBufferOffset += bytesDecoded; + + _samplesInBuffer -= _samplesBufferOffset; // can be set by Seek, otherwise zero + _sampleOffset += _samplesInBuffer; + } + + interlace(buff, offset, sampleCount); + _samplesInBuffer -= sampleCount; + _samplesBufferOffset += sampleCount; + if(_samplesInBuffer == 0) _samplesBufferOffset = 0; + + return buff.Length = offset + sampleCount; + } + +#endregion + + unsafe void interlace(AudioBuffer buff, int offset, int count) + { + if(PCM.ChannelCount == 2) + { + fixed(int* src = &Samples[_samplesBufferOffset]) + { + buff.Interlace(offset, src, src + FlakeConstants.MAX_BLOCKSIZE, count); + } + } + else + { + for(var ch = 0; ch < PCM.ChannelCount; ch++) + { + fixed(int* res = &buff.Samples[offset, ch], src = + &Samples[_samplesBufferOffset + ch * FlakeConstants.MAX_BLOCKSIZE]) + { + int* psrc = src; + for(var i = 0; i < count; i++) res[i * PCM.ChannelCount] = *psrc++; + } + } + } + } + + unsafe void fill_frames_buffer() + { + if(_framesBufferLength == 0) + _framesBufferOffset = 0; + else if(_framesBufferLength < _framesBuffer.Length / 2 && _framesBufferOffset >= _framesBuffer.Length / 2) + { + fixed(byte* buff = _framesBuffer) + { + AudioSamples.MemCpy(buff, buff + _framesBufferOffset, _framesBufferLength); + } + + _framesBufferOffset = 0; + } + + while(_framesBufferLength < _framesBuffer.Length / 2) + { + int read = _IO.Read(_framesBuffer, + _framesBufferOffset + _framesBufferLength, + _framesBuffer.Length - _framesBufferOffset - _framesBufferLength); + + _framesBufferLength += read; + + if(read == 0) break; + } + } + + unsafe void decode_frame_header(BitReader bitreader, FlacFrame frame) + { + int header_start = bitreader.Position; + + if(bitreader.readbits(15) != 0x7FFC) throw new Exception("invalid frame"); + uint vbs = bitreader.readbit(); + frame.bs_code0 = (int)bitreader.readbits(4); + uint sr_code0 = bitreader.readbits(4); + frame.ch_mode = (ChannelMode)bitreader.readbits(4); + uint bps_code = bitreader.readbits(3); + + if(FlakeConstants.flac_bitdepths[bps_code] != PCM.BitsPerSample) throw new Exception("unsupported bps coding"); + uint t1 = bitreader.readbit(); // == 0????? + + if(t1 != 0) throw new Exception("unsupported frame coding"); + frame.frame_number = (int)bitreader.read_utf8(); + + // custom block size + if(frame.bs_code0 == 6) + { + frame.bs_code1 = (int)bitreader.readbits(8); + frame.blocksize = frame.bs_code1 + 1; + } + else if(frame.bs_code0 == 7) + { + frame.bs_code1 = (int)bitreader.readbits(16); + frame.blocksize = frame.bs_code1 + 1; + } + else + frame.blocksize = FlakeConstants.flac_blocksizes[frame.bs_code0]; + + // custom sample rate + if(sr_code0 < 1 || sr_code0 > 11) + { + // sr_code0 == 12 -> sr == bitreader.readbits(8) * 1000; + // sr_code0 == 13 -> sr == bitreader.readbits(16); + // sr_code0 == 14 -> sr == bitreader.readbits(16) * 10; + throw new Exception("invalid sample rate mode"); + } + + int frame_channels = (int)frame.ch_mode + 1; + + if(frame_channels > 11) throw new Exception("invalid channel mode"); + + if(frame_channels == 2 || frame_channels > 8) // Mid/Left/Right Side Stereo + frame_channels = 2; + else + frame.ch_mode = ChannelMode.NotStereo; + + if(frame_channels != PCM.ChannelCount) throw new Exception("invalid channel mode"); + + // CRC-8 of frame header + byte crc = DoCRC + ? crc8.ComputeChecksum(bitreader.Buffer, header_start, bitreader.Position - header_start) + : (byte)0; + + frame.crc8 = (byte)bitreader.readbits(8); + + if(DoCRC && frame.crc8 != crc) throw new Exception("header crc mismatch"); + } + + unsafe void decode_subframe_constant(BitReader bitreader, FlacFrame frame, int ch) + { + int obits = frame.subframes[ch].obits; + frame.subframes[ch].best.residual[0] = bitreader.readbits_signed(obits); + } + + unsafe void decode_subframe_verbatim(BitReader bitreader, FlacFrame frame, int ch) + { + int obits = frame.subframes[ch].obits; + + for(var i = 0; i < frame.blocksize; i++) + frame.subframes[ch].best.residual[i] = bitreader.readbits_signed(obits); + } + + unsafe void decode_residual(BitReader bitreader, FlacFrame frame, int ch) + { + // rice-encoded block + // coding method + frame.subframes[ch].best.rc.coding_method = (int)bitreader.readbits(2); // ????? == 0 + + if(frame.subframes[ch].best.rc.coding_method != 0 && frame.subframes[ch].best.rc.coding_method != 1) + throw new Exception("unsupported residual coding"); + + // partition order + frame.subframes[ch].best.rc.porder = (int)bitreader.readbits(4); + + if(frame.subframes[ch].best.rc.porder > 8) throw new Exception("invalid partition order"); + int psize = frame.blocksize >> frame.subframes[ch].best.rc.porder; + int res_cnt = psize - frame.subframes[ch].best.order; + + int rice_len = 4 + frame.subframes[ch].best.rc.coding_method; + + // residual + int j = frame.subframes[ch].best.order; + int* r = frame.subframes[ch].best.residual + j; + + for(var p = 0; p < 1 << frame.subframes[ch].best.rc.porder; p++) + { + if(p == 1) res_cnt = psize; + int n = Math.Min(res_cnt, frame.blocksize - j); + + int k = frame.subframes[ch].best.rc.rparams[p] = (int)bitreader.readbits(rice_len); + + if(k == (1 << rice_len) - 1) + { + k = frame.subframes[ch].best.rc.esc_bps[p] = (int)bitreader.readbits(5); + for(int i = n; i > 0; i--) *r++ = bitreader.readbits_signed(k); + } + else + { + bitreader.read_rice_block(n, k, r); + r += n; + } + + j += n; + } + } + + unsafe void decode_subframe_fixed(BitReader bitreader, FlacFrame frame, int ch) + { + // warm-up samples + int obits = frame.subframes[ch].obits; + + for(var i = 0; i < frame.subframes[ch].best.order; i++) + frame.subframes[ch].best.residual[i] = bitreader.readbits_signed(obits); + + // residual + decode_residual(bitreader, frame, ch); + } + + unsafe void decode_subframe_lpc(BitReader bitreader, FlacFrame frame, int ch) + { + // warm-up samples + int obits = frame.subframes[ch].obits; + + for(var i = 0; i < frame.subframes[ch].best.order; i++) + frame.subframes[ch].best.residual[i] = bitreader.readbits_signed(obits); + + // LPC coefficients + frame.subframes[ch].best.cbits = (int)bitreader.readbits(4) + 1; // lpc_precision + + if(frame.subframes[ch].best.cbits >= 16) throw new Exception("cbits >= 16"); + frame.subframes[ch].best.shift = bitreader.readbits_signed(5); + + if(frame.subframes[ch].best.shift < 0) throw new Exception("negative shift"); + + for(var i = 0; i < frame.subframes[ch].best.order; i++) + frame.subframes[ch].best.coefs[i] = bitreader.readbits_signed(frame.subframes[ch].best.cbits); + + // residual + decode_residual(bitreader, frame, ch); + } + + unsafe void decode_subframes(BitReader bitreader, FlacFrame frame) + { + fixed(int* r = residualBuffer, s = Samples) + { + for(var ch = 0; ch < PCM.ChannelCount; ch++) + { + // subframe header + uint t1 = bitreader.readbit(); // ?????? == 0 + + if(t1 != 0) throw new Exception("unsupported subframe coding (ch == " + ch + ")"); + var type_code = (int)bitreader.readbits(6); + frame.subframes[ch].wbits = (int)bitreader.readbit(); + if(frame.subframes[ch].wbits != 0) frame.subframes[ch].wbits += (int)bitreader.read_unary(); + + frame.subframes[ch].obits = PCM.BitsPerSample - frame.subframes[ch].wbits; + + switch(frame.ch_mode) + { + case ChannelMode.MidSide: + frame.subframes[ch].obits += ch; + + break; + case ChannelMode.LeftSide: + frame.subframes[ch].obits += ch; + + break; + case ChannelMode.RightSide: + frame.subframes[ch].obits += 1 - ch; + + break; + } + + frame.subframes[ch].best.type = (SubframeType)type_code; + frame.subframes[ch].best.order = 0; + + if((type_code & (uint)SubframeType.LPC) != 0) + { + frame.subframes[ch].best.order = type_code - (int)SubframeType.LPC + 1; + frame.subframes[ch].best.type = SubframeType.LPC; + } + else if((type_code & (uint)SubframeType.Fixed) != 0) + { + frame.subframes[ch].best.order = type_code - (int)SubframeType.Fixed; + frame.subframes[ch].best.type = SubframeType.Fixed; + } + + frame.subframes[ch].best.residual = r + ch * FlakeConstants.MAX_BLOCKSIZE; + frame.subframes[ch].samples = s + ch * FlakeConstants.MAX_BLOCKSIZE; + + // subframe + switch(frame.subframes[ch].best.type) + { + case SubframeType.Constant: + decode_subframe_constant(bitreader, frame, ch); + + break; + case SubframeType.Verbatim: + decode_subframe_verbatim(bitreader, frame, ch); + + break; + case SubframeType.Fixed: + decode_subframe_fixed(bitreader, frame, ch); + + break; + case SubframeType.LPC: + decode_subframe_lpc(bitreader, frame, ch); + + break; + default: + throw new Exception("invalid subframe type"); + } + } + } + } + + unsafe void restore_samples_fixed(FlacFrame frame, int ch) + { + FlacSubframeInfo sub = frame.subframes[ch]; + + AudioSamples.MemCpy(sub.samples, sub.best.residual, sub.best.order); + int* data = sub.samples + sub.best.order; + int* residual = sub.best.residual + sub.best.order; + int data_len = frame.blocksize - sub.best.order; + int s0, s1, s2; + + switch(sub.best.order) + { + case 0: + AudioSamples.MemCpy(data, residual, data_len); + + break; + case 1: + s1 = data[-1]; + + for(int i = data_len; i > 0; i--) + { + s1 += *residual++; + *data++ = s1; + } + + //data[i] = residual[i] + data[i - 1]; + break; + case 2: + s2 = data[-2]; + s1 = data[-1]; + + for(int i = data_len; i > 0; i--) + { + s0 = *residual++ + (s1 << 1) - s2; + *data++ = s0; + s2 = s1; + s1 = s0; + } + + //data[i] = residual[i] + data[i - 1] * 2 - data[i - 2]; + break; + case 3: + for(var i = 0; i < data_len; i++) + { + data[i] = residual[i] + + (data[i - 1] - data[i - 2] << 1) + + (data[i - 1] - data[i - 2]) + + data[i - 3]; + } + + break; + case 4: + for(var i = 0; i < data_len; i++) + { + data[i] = residual[i] + + (data[i - 1] + data[i - 3] << 2) - + ((data[i - 2] << 2) + (data[i - 2] << 1)) - + data[i - 4]; + } + + break; + } + } + + unsafe void restore_samples_lpc(FlacFrame frame, int ch) + { + FlacSubframeInfo sub = frame.subframes[ch]; + ulong csum = 0; + + fixed(int* coefs = sub.best.coefs) + { + for(int i = sub.best.order; i > 0; i--) csum += (ulong)Math.Abs(coefs[i - 1]); + + if(csum << sub.obits >= 1UL << 32) + { + lpc.decode_residual_long(sub.best.residual, + sub.samples, + frame.blocksize, + sub.best.order, + coefs, + sub.best.shift); + } + else + { + lpc.decode_residual(sub.best.residual, + sub.samples, + frame.blocksize, + sub.best.order, + coefs, + sub.best.shift); + } + } + } + + unsafe void restore_samples(FlacFrame frame) + { + for(var ch = 0; ch < PCM.ChannelCount; ch++) + { + switch(frame.subframes[ch].best.type) + { + case SubframeType.Constant: + AudioSamples.MemSet(frame.subframes[ch].samples, + frame.subframes[ch].best.residual[0], + frame.blocksize); + + break; + case SubframeType.Verbatim: + AudioSamples.MemCpy(frame.subframes[ch].samples, + frame.subframes[ch].best.residual, + frame.blocksize); + + break; + case SubframeType.Fixed: + restore_samples_fixed(frame, ch); + + break; + case SubframeType.LPC: + restore_samples_lpc(frame, ch); + + break; + } + + if(frame.subframes[ch].wbits != 0) + { + int* s = frame.subframes[ch].samples; + int x = frame.subframes[ch].wbits; + for(int i = frame.blocksize; i > 0; i--) *s++ <<= x; + } + } + + if(frame.ch_mode != ChannelMode.NotStereo) + { + int* l = frame.subframes[0].samples; + int* r = frame.subframes[1].samples; + + switch(frame.ch_mode) + { + case ChannelMode.LeftRight: + break; + case ChannelMode.MidSide: + for(int i = frame.blocksize; i > 0; i--) + { + int mid = *l; + int side = *r; + mid <<= 1; + mid |= side & 1; /* i.e. if 'side' is odd... */ + *l++ = mid + side >> 1; + *r++ = mid - side >> 1; + } + + break; + case ChannelMode.LeftSide: + for(int i = frame.blocksize; i > 0; i--) + { + int _l = *l++, _r = *r; + *r++ = _l - _r; + } + + break; + case ChannelMode.RightSide: + for(int i = frame.blocksize; i > 0; i--) *l++ += *r++; + + break; + } + } + } + + public unsafe int DecodeFrame(byte[] buffer, int pos, int len) + { + fixed(byte* buf = buffer) + { + framereader.Reset(buf, pos, len); + decode_frame_header(framereader, frame); + decode_subframes(framereader, frame); + framereader.flush(); + ushort crc_1 = framereader.get_crc16(); + ushort crc_2 = framereader.read_ushort(); + + if(DoCRC && crc_1 != crc_2) throw new Exception("frame crc mismatch"); + restore_samples(frame); + _samplesInBuffer = frame.blocksize; + + return framereader.Position - pos; + } + } + + + bool skip_bytes(int bytes) + { + for(var j = 0; j < bytes; j++) + if(0 == _IO.Read(_framesBuffer, 0, 1)) + return false; + + return true; + } + + unsafe void decode_metadata() + { + byte x; + int i, id; + + //bool first = true; + byte[] FLAC__STREAM_SYNC_STRING = [(byte)'f', (byte)'L', (byte)'a', (byte)'C']; + byte[] ID3V2_TAG_ = [(byte)'I', (byte)'D', (byte)'3']; + + for(i = id = 0; i < 4;) + { + if(_IO.Read(_framesBuffer, 0, 1) == 0) throw new Exception("FLAC stream not found"); + x = _framesBuffer[0]; + + if(x == FLAC__STREAM_SYNC_STRING[i]) + { + //first = true; + i++; + id = 0; + + continue; + } + + if(id < 3 && x == ID3V2_TAG_[id]) + { + id++; + i = 0; + + if(id == 3) + { + if(!skip_bytes(3)) throw new Exception("FLAC stream not found"); + var skip = 0; + + for(var j = 0; j < 4; j++) + { + if(0 == _IO.Read(_framesBuffer, 0, 1)) throw new Exception("FLAC stream not found"); + skip <<= 7; + skip |= _framesBuffer[0] & 0x7f; + } + + if(!skip_bytes(skip)) throw new Exception("FLAC stream not found"); + } + + continue; + } + + id = 0; + + if(x == 0xff) /* MAGIC NUMBER for the first 8 frame sync bits */ + { + do + { + if(_IO.Read(_framesBuffer, 0, 1) == 0) throw new Exception("FLAC stream not found"); + x = _framesBuffer[0]; + } while(x == 0xff); + + if(x >> 2 == 0x3e) /* MAGIC NUMBER for the last 6 sync bits */ + { + //_IO.Position -= 2; + // state = frame + throw new Exception("headerless file unsupported"); + } + } + + throw new Exception("FLAC stream not found"); + } + + do + { + fill_frames_buffer(); + + fixed(byte* buf = _framesBuffer) + { + var bitreader = new BitReader(buf, _framesBufferOffset, _framesBufferLength - _framesBufferOffset); + bool is_last = bitreader.readbit() != 0; + var type = (MetadataType)bitreader.readbits(7); + var len = (int)bitreader.readbits(24); + + if(type == MetadataType.StreamInfo) + { + const int FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */ + const int FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */ + const int FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */ + const int FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */ + const int FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */ + const int FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */ + const int FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */ + const int FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */ + const int FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */ + + min_block_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN); + max_block_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN); + min_frame_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN); + max_frame_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN); + var sample_rate = (int)bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN); + int channels = 1 + (int)bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN); + + int bits_per_sample = + 1 + (int)bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN); + + PCM = new AudioPCMConfig(bits_per_sample, channels, sample_rate); + Length = (long)bitreader.readbits64(FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN); + bitreader.skipbits(FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN); + } + else if(type == MetadataType.Seektable) + { + int num_entries = len / 18; + seek_table = new SeekPoint[num_entries]; + + for(var e = 0; e < num_entries; e++) + { + seek_table[e].number = bitreader.read_long(); + seek_table[e].offset = bitreader.read_long(); + seek_table[e].framesize = bitreader.read_ushort(); + } + } + + if(_framesBufferLength < 4 + len) + { + _IO.Position += 4 + len - _framesBufferLength; + _framesBufferLength = 0; + } + else + { + _framesBufferLength -= 4 + len; + _framesBufferOffset += 4 + len; + } + + if(is_last) break; + } + } while(true); + + first_frame_offset = _IO.Position - _framesBufferLength; + } +} \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/AudioEncoder.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/AudioEncoder.cs new file mode 100644 index 000000000..e631a0963 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/AudioEncoder.cs @@ -0,0 +1,2737 @@ +/** + * CUETools.Flake: pure managed FLAC audio encoder + * Copyright (c) 2009-2021 Grigory Chudov + * Based on Flake encoder, http://flake-enc.sourceforge.net/ + * Copyright (c) 2006-2009 Justin Ruggles + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define NOINTEROP +#define VARIANT1 + +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using CUETools.Codecs.Flake.Properties; +#if INTEROP +using System.Runtime.InteropServices; +#endif + +namespace CUETools.Codecs.Flake; + +public class AudioEncoder : IAudioDest +{ + Stream _IO; + + // number of audio channels + // set by user prior to calling flake_encode_init + // valid values are 1 to 8 + readonly int channels; + int ch_code; + + // audio sample rate in Hz + // set by user prior to calling flake_encode_init + int sr_code0, sr_code1; + + // sample size in bits + // set by user prior to calling flake_encode_init + // only 16-bit is currently supported + int bps_code; + + // total stream samples + // set by user prior to calling flake_encode_init + // if 0, stream length is unknown + int sample_count = -1; + + FlakeEncodeParams eparams; + + // maximum frame size in bytes + // set by flake_encode_init + // this can be used to allocate memory for output + int max_frame_size; + + byte[] frame_buffer; + + int frame_count; + + long first_frame_offset; + +#if INTEROP + TimeSpan _userProcessorTime; +#endif + + // header bytes + // allocated by flake_encode_init and freed by flake_encode_close + byte[] header; + + readonly int[] samplesBuffer; + int[] verifyBuffer; + readonly int[] residualBuffer; + readonly float[] windowBuffer; + readonly double[] windowScale; + readonly LpcWindowSection[,,] windowSections; + + readonly WindowFunction[] windowType; + int samplesInBuffer; + + int m_blockSize; + int _windowsize, _windowcount; + + readonly Crc8 crc8; + MD5 md5; + + FlacFrame frame; + AudioDecoder verify; + + SeekPoint[] seek_table; + int seek_table_offset = -1; + + bool inited; + + public AudioEncoder(EncoderSettings settings, string path, Stream IO = null) + { + m_settings = settings.Clone() as EncoderSettings; + m_settings.Validate(); + + //if (Settings.PCM.BitsPerSample != 16) + // throw new Exception("Bits per sample must be 16."); + //if (Settings.PCM.ChannelCount != 2) + // throw new Exception("ChannelCount must be 2."); + + channels = Settings.PCM.ChannelCount; + + // flake_validate_params + + Path = path; + _IO = IO; + + samplesBuffer = new int[FlakeConstants.MAX_BLOCKSIZE * (channels == 2 ? 4 : channels)]; + residualBuffer = new int[FlakeConstants.MAX_BLOCKSIZE * (channels == 2 ? 10 : channels + 1)]; + windowBuffer = new float[FlakeConstants.MAX_BLOCKSIZE * 2 * lpc.MAX_LPC_WINDOWS]; + windowScale = new double[lpc.MAX_LPC_WINDOWS]; + windowType = new WindowFunction[lpc.MAX_LPC_WINDOWS]; + windowSections = new LpcWindowSection[12, lpc.MAX_LPC_WINDOWS, lpc.MAX_LPC_SECTIONS]; + + eparams.flake_set_defaults(m_settings); + + crc8 = new Crc8(); + frame = new FlacFrame(channels * 2); + } + + public int TotalSize { get; private set; } + + readonly EncoderSettings m_settings; + + public IAudioEncoderSettings Settings => m_settings; + +#if INTEROP + [DllImport("kernel32.dll")] + static extern bool GetThreadTimes(IntPtr hThread, out long lpCreationTime, out long lpExitTime, out long lpKernelTime, out long lpUserTime); + [DllImport("kernel32.dll")] + static extern IntPtr GetCurrentThread(); +#endif + + void DoClose() + { + if(inited) + { + while(samplesInBuffer > 0) + { + m_blockSize = samplesInBuffer; + output_frame(); + } + + if(_IO.CanSeek) + { + if(sample_count <= 0 && Position != 0) + { + var bitwriter = new BitWriter(header, 0, 4); + bitwriter.writebits(32, (int)Position); + bitwriter.flush(); + _IO.Position = 22; + _IO.Write(header, 0, 4); + } + + if(md5 != null) + { + md5.TransformFinalBlock(frame_buffer, 0, 0); + _IO.Position = 26; + _IO.Write(md5.Hash, 0, md5.Hash.Length); + } + + if(seek_table != null) + { + _IO.Position = seek_table_offset; + int len = write_seekpoints(header, 0, 0); + _IO.Write(header, 4, len - 4); + } + } + + _IO.Close(); + inited = false; + } + +#if INTEROP + long fake, KernelStart, UserStart; + GetThreadTimes(GetCurrentThread(), out fake, out fake, out KernelStart, out UserStart); + _userProcessorTime = new TimeSpan(UserStart); +#endif + } + + public void Close() + { + DoClose(); + + if(sample_count > 0 && Position != sample_count) throw new Exception(Resources.ExceptionSampleCount); + } + + public void Delete() + { + if(inited) + { + _IO.Close(); + inited = false; + } + + if(Path != "") File.Delete(Path); + } + + public long Position { get; private set; } + + public long FinalSampleCount + { + set => sample_count = (int)value; + } + + public OrderMethod OrderMethod + { + get => eparams.order_method; + set => eparams.order_method = value; + } + + public int DevelopmentMode + { + get => eparams.development_mode; + set => eparams.development_mode = value; + } + + public bool DoSeekTable + { + get => eparams.do_seektable; + set => eparams.do_seektable = value; + } + + public int VBRMode + { + get => eparams.variable_block_size; + set => eparams.variable_block_size = value; + } + + public TimeSpan UserProcessorTime + { + get + { +#if INTEROP + return _userProcessorTime; +#else + return new TimeSpan(0); +#endif + } + } + + unsafe int get_wasted_bits(int* signal, int samples) + { + int i, shift; + var x = 0; + + for(i = 0; i < samples && 0 == (x & 1); i++) x |= signal[i]; + + if(x == 0) + shift = 0; + else + for(shift = 0; 0 == (x & 1); shift++) + x >>= 1; + + if(shift > 0) + for(i = 0; i < samples; i++) + signal[i] >>= shift; + + return shift; + } + + /// + /// Copy channel-interleaved input samples into separate subframes + /// + /// + /// + /// + unsafe void copy_samples(int[,] samples, int pos, int block) + { + fixed(int* fsamples = samplesBuffer, src = &samples[pos, 0]) + { + if(channels == 2) + { + if(m_settings.StereoMethod == StereoMethod.Independent) + { + AudioSamples.Deinterlace(fsamples + samplesInBuffer, + fsamples + FlakeConstants.MAX_BLOCKSIZE + samplesInBuffer, + src, + block); + } + else + { + int* left = fsamples + samplesInBuffer; + int* right = left + FlakeConstants.MAX_BLOCKSIZE; + int* leftM = right + FlakeConstants.MAX_BLOCKSIZE; + int* rightM = leftM + FlakeConstants.MAX_BLOCKSIZE; + + for(var i = 0; i < block; i++) + { + int l = src[2 * i]; + int r = src[2 * i + 1]; + left[i] = l; + right[i] = r; + leftM[i] = l + r >> 1; + rightM[i] = l - r; + } + } + } + else + { + for(var ch = 0; ch < channels; ch++) + { + int* psamples = fsamples + ch * FlakeConstants.MAX_BLOCKSIZE + samplesInBuffer; + for(var i = 0; i < block; i++) psamples[i] = src[i * channels + ch]; + } + } + } + + samplesInBuffer += block; + } + + //unsafe static void channel_decorrelation(int* leftS, int* rightS, int *leftM, int *rightM, int blocksize) + //{ + // for (int i = 0; i < blocksize; i++) + // { + // leftM[i] = (leftS[i] + rightS[i]) >> 1; + // rightM[i] = leftS[i] - rightS[i]; + // } + //} + + unsafe void encode_residual_verbatim(int* res, int* smp, uint n) + { + AudioSamples.MemCpy(res, smp, (int)n); + } + + static unsafe ulong encode_residual_fixed_partition(int* res, int* smp, int* end, int order, int* last_errors) + { + var sum = 0UL; + + switch(order) + { + case 0: + { + while(smp < end) + { + int error = *res++ = *smp++; + sum += (uint)(error << 1 ^ error >> 31); + } + + break; + } + case 1: + { + int last_error_0 = last_errors[0]; + + while(smp < end) + { + int error, save; + error = *smp++; + save = error; + error -= last_error_0; + *res++ = error; + last_error_0 = save; + sum += (uint)(error << 1 ^ error >> 31); + } + + last_errors[0] = last_error_0; + + break; + } + case 2: + { + int last_error_0 = last_errors[0], last_error_1 = last_errors[1]; + + while(smp < end) + { + int error, save; + error = *smp++; + save = error; + error -= last_error_0; + last_error_0 = save; + save = error; + error -= last_error_1; + *res++ = error; + last_error_1 = save; + sum += (uint)(error << 1 ^ error >> 31); + } + + last_errors[0] = last_error_0; + last_errors[1] = last_error_1; + ; + + break; + } + case 3: + { + int last_error_0 = last_errors[0], last_error_1 = last_errors[1], last_error_2 = last_errors[2]; + + while(smp < end) + { + int error, save; + error = *smp++; + save = error; + error -= last_error_0; + last_error_0 = save; + save = error; + error -= last_error_1; + last_error_1 = save; + save = error; + error -= last_error_2; + *res++ = error; + last_error_2 = save; + sum += (uint)(error << 1 ^ error >> 31); + } + + last_errors[0] = last_error_0; + last_errors[1] = last_error_1; + last_errors[2] = last_error_2; + + break; + } + case 4: + { + int last_error_0 = last_errors[0], + last_error_1 = last_errors[1], + last_error_2 = last_errors[2], + last_error_3 = last_errors[3]; + + while(smp < end) + { + int error, save; + error = *smp++; + save = error; + error -= last_error_0; + last_error_0 = save; + save = error; + error -= last_error_1; + last_error_1 = save; + save = error; + error -= last_error_2; + last_error_2 = save; + save = error; + error -= last_error_3; + *res++ = error; + last_error_3 = save; + sum += (uint)(error << 1 ^ error >> 31); + } + + last_errors[0] = last_error_0; + last_errors[1] = last_error_1; + last_errors[2] = last_error_2; + last_errors[3] = last_error_3; + + break; + } + default: + throw new ArgumentOutOfRangeException(); + } + + return sum; + } + + static unsafe void encode_residual_fixed(int* res, int* smp, int n, int order, ulong* sums, int pmax) + { + int* last_errors = stackalloc int[4]; + int* end = smp + n; + int* seg_end = smp + (n >> pmax); + + if(order > 4) throw new ArgumentOutOfRangeException(); + + for(var i = 0; i < order; i++) + { + int* next_errors = stackalloc int[4]; + next_errors[0] = *res++ = *smp++; + for(var j = 0; j < i; j++) next_errors[j + 1] = next_errors[j] - last_errors[j]; + for(var j = 0; j <= i; j++) last_errors[j] = next_errors[j]; + } + + while(smp < end) + { + *sums++ = encode_residual_fixed_partition(res, smp, seg_end, order, last_errors); + res += seg_end - smp; + smp = seg_end; + seg_end += n >> pmax; + } + } + +#if XXX + unsafe static int encode_residual_fixed_estimate_best_order(int* res, int* smp, int n, int order) + { + int next_error_0, next_error_1, next_error_2, next_error_3, next_error_4; + int last_error_0, last_error_1, last_error_2, last_error_3; + int* end = smp + n; + ulong total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; + + if (order == 0) + { + AudioSamples.MemCpy(res, smp, n); + return 0; + } + + next_error_0 = *(res++) = *(smp++); + last_error_0 = next_error_0; + + if (order == 1) + { + while (smp < end) + { + next_error_0 = *(smp++); + next_error_1 = next_error_0 - last_error_0; + + last_error_0 = next_error_0; + + total_error_0 += (ulong)((next_error_0 << 1) ^ (next_error_0 >> 31)); + total_error_1 += (ulong)((next_error_1 << 1) ^ (next_error_1 >> 31)); + + *(res++) = (int)next_error_1; + } + + if ((total_error_0 < total_error_1)) + return 0; + return 1; + } + + next_error_0 = *(res++) = *(smp++); + next_error_1 = next_error_0 - last_error_0; + last_error_0 = next_error_0; + last_error_1 = next_error_1; + + if (order == 2) + { + while (smp < end) + { + next_error_0 = *(smp++); + next_error_1 = next_error_0 - last_error_0; + next_error_2 = next_error_1 - last_error_1; + + last_error_0 = next_error_0; + last_error_1 = next_error_1; + + total_error_0 += (ulong)((next_error_0 << 1) ^ (next_error_0 >> 31)); + total_error_1 += (ulong)((next_error_1 << 1) ^ (next_error_1 >> 31)); + total_error_2 += (ulong)((next_error_2 << 1) ^ (next_error_2 >> 31)); + + *(res++) = (int)next_error_2; + } + + if ((total_error_0 < total_error_1) & (total_error_0 < total_error_2)) + return 0; + else if ((total_error_1 < total_error_2)) + return 1; + return 2; + } + + next_error_0 = *(res++) = *(smp++); + next_error_1 = next_error_0 - last_error_0; + next_error_2 = next_error_1 - last_error_1; + last_error_0 = next_error_0; + last_error_1 = next_error_1; + last_error_2 = next_error_2; + + if (order == 3) + { + while (smp < end) + { + next_error_0 = *(smp++); + next_error_1 = next_error_0 - last_error_0; + next_error_2 = next_error_1 - last_error_1; + next_error_3 = next_error_2 - last_error_2; + + last_error_0 = next_error_0; + last_error_1 = next_error_1; + last_error_2 = next_error_2; + + total_error_0 += (ulong)((next_error_0 << 1) ^ (next_error_0 >> 31)); + total_error_1 += (ulong)((next_error_1 << 1) ^ (next_error_1 >> 31)); + total_error_2 += (ulong)((next_error_2 << 1) ^ (next_error_2 >> 31)); + total_error_3 += (ulong)((next_error_3 << 1) ^ (next_error_3 >> 31)); + + *(res++) = (int)next_error_3; + } + + if ((total_error_0 < total_error_1) & (total_error_0 < total_error_2) & (total_error_0 < total_error_3)) + return 0; + else if ((total_error_1 < total_error_2) & (total_error_1 < total_error_3)) + return 1; + else if ((total_error_2 < total_error_3)) + return 2; + return 3; + } + + next_error_0 = *(res++) = *(smp++); + next_error_1 = next_error_0 - last_error_0; + next_error_2 = next_error_1 - last_error_1; + next_error_3 = next_error_2 - last_error_2; + last_error_0 = next_error_0; + last_error_1 = next_error_1; + last_error_2 = next_error_2; + last_error_3 = next_error_3; + + if (order == 4) + { + while (smp < end) + { + next_error_0 = *(smp++); + next_error_1 = next_error_0 - last_error_0; + next_error_2 = next_error_1 - last_error_1; + next_error_3 = next_error_2 - last_error_2; + next_error_4 = next_error_3 - last_error_3; + + last_error_0 = next_error_0; + last_error_1 = next_error_1; + last_error_2 = next_error_2; + last_error_3 = next_error_3; + + total_error_0 += (ulong)((next_error_0 << 1) ^ (next_error_0 >> 31)); + total_error_1 += (ulong)((next_error_1 << 1) ^ (next_error_1 >> 31)); + total_error_2 += (ulong)((next_error_2 << 1) ^ (next_error_2 >> 31)); + total_error_3 += (ulong)((next_error_3 << 1) ^ (next_error_3 >> 31)); + total_error_4 += (ulong)((next_error_4 << 1) ^ (next_error_4 >> 31)); + + *(res++) = (int)next_error_4; + } + + if ((total_error_0 < total_error_1) & (total_error_0 < total_error_2) & (total_error_0 < total_error_3) & (total_error_0 < total_error_4)) + return 0; + else if ((total_error_1 < total_error_2) & (total_error_1 < total_error_3) & (total_error_1 < total_error_4)) + return 1; + else if ((total_error_2 < total_error_3) & (total_error_2 < total_error_4)) + return 2; + else if (total_error_3 < total_error_4) + return 3; + return 4; + } + + throw new ArgumentOutOfRangeException(); + } +#endif + static unsafe uint calc_optimal_rice_params(int porder, int* parm, ulong* sums, uint n, uint pred_order, + ref int method) + { + uint part = 1U << porder; + uint cnt = (n >> porder) - pred_order; + int maxK = method > 0 ? 30 : FlakeConstants.MAX_RICE_PARAM; + int k = cnt > 0 ? Math.Min(maxK, BitReader.log2i(sums[0] / cnt)) : 0; + int realMaxK0 = k; + ulong all_bits = cnt * ((uint)k + 1U) + (sums[0] >> k); + parm[0] = k; + cnt = n >> porder; + int logcnt = BitReader.log2i(cnt); + + if(cnt == 1 << logcnt) + { + for(uint i = 1; i < part; i++) + { + ulong s = sums[i]; + ulong u = s >> logcnt; + k = u >> maxK != 0 ? maxK : BitReader.log2i((uint)u); + realMaxK0 = Math.Max(realMaxK0, k); + all_bits += ((uint)k << logcnt) + (s >> k); + parm[i] = k; + } + } + else + { + for(uint i = 1; i < part; i++) + { + ulong s = sums[i]; + ulong u = s / cnt; + k = u >> maxK != 0 ? maxK : BitReader.log2i((uint)u); + realMaxK0 = Math.Max(realMaxK0, k); + all_bits += cnt * (uint)k + (s >> k); + parm[i] = k; + } + } + + all_bits += cnt * (part - 1U); + method = realMaxK0 > FlakeConstants.MAX_RICE_PARAM ? 1 : 0; + + return (uint)all_bits + (4U + (uint)method) * part; + } + + static unsafe void calc_lower_sums(int pmin, int pmax, ulong* sums) + { + for(int i = pmax - 1; i >= pmin; i--) + { + for(var j = 0; j < 1 << i; j++) + { + sums[i * FlakeConstants.MAX_PARTITIONS + j] = + sums[(i + 1) * FlakeConstants.MAX_PARTITIONS + 2 * j] + + sums[(i + 1) * FlakeConstants.MAX_PARTITIONS + 2 * j + 1]; + } + } + } + + static unsafe uint calc_rice_params_sums(RiceContext rc, int pmin, int pmax, ulong* sums, uint n, uint pred_order, + int bps) + { + int* parm = stackalloc int[(pmax + 1) * FlakeConstants.MAX_PARTITIONS]; + + //uint* bits = stackalloc uint[FlakeConstants.MAX_PARTITION_ORDER]; + + //assert(pmin >= 0 && pmin <= FlakeConstants.MAX_PARTITION_ORDER); + //assert(pmax >= 0 && pmax <= FlakeConstants.MAX_PARTITION_ORDER); + //assert(pmin <= pmax); + + // sums for lower levels + calc_lower_sums(pmin, pmax, sums); + + uint opt_bits = AudioSamples.UINT32_MAX; + int opt_porder = pmin; + var opt_method = 0; + + for(int i = pmin; i <= pmax; i++) + { + int method = bps > 16 ? 1 : 0; + + uint bits = calc_optimal_rice_params(i, + parm + i * FlakeConstants.MAX_PARTITIONS, + sums + i * FlakeConstants.MAX_PARTITIONS, + n, + pred_order, + ref method); + + if(bits <= opt_bits) + { + opt_bits = bits; + opt_porder = i; + opt_method = method; + } + } + + rc.porder = opt_porder; + rc.coding_method = opt_method; + + fixed(int* rparms = rc.rparams) + { + AudioSamples.MemCpy(rparms, parm + opt_porder * FlakeConstants.MAX_PARTITIONS, 1 << opt_porder); + } + + return opt_bits; + } + + static int get_max_p_order(int max_porder, int n, int order) + { + int porder = Math.Min(max_porder, BitReader.log2i(n ^ n - 1)); + if(order > 0) porder = Math.Min(porder, BitReader.log2i(n / order)); + + return porder; + } + +// private static int[,] best_x = new int[14,8193]; + static readonly int[][] good_x = + { + [], // 0 + [ // 1 + 0x03, 0x01, 0x00, 0x02 + ], + [ // 2 + 0x01, 0x07, 0x06, 0x02, 0x03, 0x04, 0x00, 0x05 + ], + [ // 3 + 0x0b, 0x0f, 0x0e, 0x0d, 0x03, 0x01, 0x05, 0x02 + ], + [ //4 + 0x17, 0x09, 0x03, 0x0a, 0x06, 0x1d, 0x1f, 0x05, 0x1c, 0x0d, 0x07, 0x0c + ], + [ // 5 + 0x2b, 0x3d, 0x37, 0x07, 0x11, 0x15, 0x36, 0x3f + ], + [ // 6 + 0x6b, 0x15, 0x7e, 0x31, 0x07, 0x1a, 0x29, 0x26, 0x5d, 0x23, 0x6f, 0x19, 0x56, 0x75 + ], + [ // 7 + 0xdb, 0xef, 0xb5, 0x47, 0xee, 0x63, 0x0b, 0xfd, 0x31, 0xbe, 0xed, 0x33, 0xff, 0xfb, 0xd6, 0xbb + ], + [ // 8 + 0x1bb, 0x1c7, 0x069, 0x087, 0x1fd, 0x16e, 0x095, 0x1de, 0x066, 0x071, 0x055, 0x09a + ], + [ // 9 + 0x36b, 0x3bd, 0x097, 0x0c3, 0x0e3, 0x0b1, 0x107, 0x2de, 0x3ef, 0x2fb, 0x3d5, 0x139 + ], + [ // 10 +//0x0e3,0x199,0x383,0x307, 0x1e3,0x01f,0x269,0x0f1, 0x266,0x03f,0x2cd,0x1c3, 0x19a,0x387,0x339,0x259, + 0x6eb, 0x187, 0x77d, 0x271, 0x195, 0x259, 0x5ae, 0x169 + ], + [ // 11 + 0xddb, 0xf77, 0xb6d, 0x587, 0x2c3, 0x03b, 0xef5, 0x1e3, 0xdbe + ], + [ // 12 + 0x1aeb, 0x0587, 0x0a71, 0x1dbd, 0x0559, 0x0aa5, 0x0a2e, 0x0d43, 0x05aa, 0x00f3, 0x0696, 0x03c6 + ], + [ // 13 + 0x35d7, 0x2f6f, 0x0aa3, 0x1569, 0x150f, 0x3d79, 0x0dc3, 0x309f /*?*/ + ], + [ // 14 + 0x75d7, 0x5f7b, 0x6a8f, 0x29a3 + ], + [ // 15 + 0xddd7, 0xaaaf, 0x55c3, 0xf77b + ], + [ // 16 + 0x1baeb, 0x1efaf, 0x1d5bf, 0x1cff3 + ], + [ // 17 + 0x36dd7, 0x3bb7b, 0x3df6f, 0x2d547 + ], + [ // 18 + 0x75dd7, 0x6f77b, 0x7aaaf, 0x5ddd3 + ], + [ // 19 + 0xdddd7, 0xf777b, 0xd5547, 0xb6ddb + ], + [ // 20 + 0x1baeeb, 0x1efbaf, 0x1aaabf, 0x17bbeb + ], + [ // 21 + 0x376dd7, 0x3ddf7b, 0x2d550f, 0x0aaaa3 + ], + [ // 22 + 0x6eddd7, 0x77777b, 0x5dcd4f, 0x5d76f9 + ], + [ // 23 + 0xdeddd7, 0xb5b6eb, 0x55552b, 0x2aaac3 + ], + [ // 24 + 0x1dddbb7, 0x1b76eeb, 0x17bbf5f, 0x1eeaa9f + ], + [ // 25 + ], + [ // 26 + ], + [ // 27 + ], + [ // 28 + ], + [ // 29 + ], + [ // 30 + ] + }; + + unsafe void postprocess_coefs(FlacFrame frame, FlacSubframe sf, int ch) + { + if(eparams.development_mode < 0) return; + if(sf.type != SubframeType.LPC || sf.order > 30) return; + int orig_window = sf.window; + int orig_order = sf.order; + int orig_shift = sf.shift; + int orig_cbits = sf.cbits; + uint orig_size = sf.size; + int* orig_coefs = stackalloc int[orig_order]; + for(var i = 0; i < orig_order; i++) orig_coefs[i] = sf.coefs[i]; + int orig_xx = -1; + var orig_seq = 0; + int maxxx = Math.Min(good_x[orig_order].Length, eparams.development_mode); + int pmax = get_max_p_order(m_settings.MaxPartitionOrder, frame.blocksize, orig_order); + int pmin = Math.Min(m_settings.MinPartitionOrder, pmax); + ulong* sums = stackalloc ulong[(pmax + 1) * FlakeConstants.MAX_PARTITIONS]; + + while(true) + { + int* best_coefs = stackalloc int[orig_order]; + int best_shift = orig_shift; + int best_cbits = orig_cbits; + uint best_size = orig_size; + int best_xx = -1; + + for(int xx = -1; xx < maxxx; xx++) + { + int x = xx; + + if(xx < 0) + { + if(orig_xx < 0 || maxxx < 1 /*3*/) // || (orig_xx >> orig_order) != 0) + continue; + + x = orig_xx; + orig_seq++; + } + else + { + orig_seq = 0; + if(orig_order < good_x.Length && good_x[orig_order] != null) x = good_x[orig_order][xx]; + } + + frame.current.type = SubframeType.LPC; + frame.current.order = orig_order; + frame.current.window = orig_window; + frame.current.shift = orig_shift; + frame.current.cbits = orig_cbits; + + if((x >> orig_order & 1) != 0) + { + frame.current.shift--; + frame.current.cbits--; + + if(frame.current.shift < 0 || frame.current.cbits < 2) continue; + } + + ulong csum = 0; + int qmax = (1 << frame.current.cbits - 1) - 1; + + for(var i = 0; i < frame.current.order; i++) + { + int shift = x >> orig_order & 1; + int increment = x == 1 << orig_order ? 0 : ((x >> i & 1) << 1) - 1; + frame.current.coefs[i] = orig_coefs[i] + (increment << orig_seq) >> shift; + if(frame.current.coefs[i] < -(qmax + 1)) frame.current.coefs[i] = -(qmax + 1); + if(frame.current.coefs[i] > qmax) frame.current.coefs[i] = qmax; + csum += (ulong)Math.Abs(frame.current.coefs[i]); + } + + fixed(int* coefs = frame.current.coefs) + { + if(csum << frame.subframes[ch].obits >= 1UL << 32) + { + lpc.encode_residual_long(frame.current.residual, + frame.subframes[ch].samples, + frame.blocksize, + frame.current.order, + coefs, + frame.current.shift, + sums + pmax * FlakeConstants.MAX_PARTITIONS, + pmax); + } + else + { + lpc.encode_residual(frame.current.residual, + frame.subframes[ch].samples, + frame.blocksize, + frame.current.order, + coefs, + frame.current.shift, + sums + pmax * FlakeConstants.MAX_PARTITIONS, + pmax); + } + } + + uint cur_size = calc_rice_params_sums(frame.current.rc, + pmin, + pmax, + sums, + (uint)frame.blocksize, + (uint)frame.current.order, + Settings.PCM.BitsPerSample); + + frame.current.size = (uint)(frame.current.order * frame.subframes[ch].obits + + 4 + + 5 + + frame.current.order * frame.current.cbits + + 6 + + (int)cur_size); + + if(frame.current.size < best_size) + { + //var dif = best_size - frame.current.size; + for(var i = 0; i < frame.current.order; i++) best_coefs[i] = frame.current.coefs[i]; + best_shift = frame.current.shift; + best_cbits = frame.current.cbits; + best_size = frame.current.size; + best_xx = x; + frame.ChooseBestSubframe(ch); + + //if (dif > orig_order * 5) + // break; + } + + if(xx < 0 && best_size < orig_size) break; + } + + if(best_size < orig_size) + { + //if (best_xx >= 0) best_x[order, best_xx]++; + //if (orig_size != 0x7FFFFFFF) + // System.Console.Write(string.Format(" {0}[{1:x}]", orig_size - best_size, best_xx)); + for(var i = 0; i < orig_order; i++) orig_coefs[i] = best_coefs[i]; + orig_shift = best_shift; + orig_cbits = best_cbits; + orig_size = best_size; + orig_xx = best_xx; + } + else + break; + } + + //if (orig_size != 0x7FFFFFFF) + // System.Console.WriteLine(); + + //if (frame_count % 0x400 == 0) + //{ + // for (int o = 0; o < best_x.GetLength(0); o++) + // { + // //for (int x = 0; x <= (1 << o); x++) + // // if (best_x[o, x] != 0) + // // System.Console.WriteLine(string.Format("{0:x2}\t{1:x4}\t{2}", o, x, best_x[o, x])); + // var s = new List>(); + // for (int x = 0; x < (1 << o); x++) + // if (best_x[o, x] != 0) + // s.Add(new KeyValuePair(x, best_x[o, x])); + // s.Sort((x, y) => y.Value.CompareTo(x.Value)); + // foreach (var x in s) + // System.Console.WriteLine(string.Format("{0:x2}\t{1:x4}\t{2}", o, x.Key, x.Value)); + // int i = 0; + // foreach (var x in s) + // { + // System.Console.Write(string.Format(o <= 8 ? "0x{0:x2}," : "0x{0:x3},", x.Key)); + // if ((++i) % 16 == 0) + // System.Console.WriteLine(); + // } + // System.Console.WriteLine(); + // } + //} + } + + public static void SetCoefs(int order, int[] coefs) + { + good_x[order] = new int[coefs.Length]; + for(var i = 0; i < coefs.Length; i++) good_x[order][i] = coefs[i]; + } + + unsafe void encode_residual_lpc_sub(FlacFrame frame, float* lpcs, int iWindow, int order, int ch) + { + // select LPC precision based on block size + uint lpc_precision; + + if(frame.blocksize <= 192) + lpc_precision = 7U; + else if(frame.blocksize <= 384) + lpc_precision = 8U; + else if(frame.blocksize <= 576) + lpc_precision = 9U; + else if(frame.blocksize <= 1152) + lpc_precision = 10U; + else if(frame.blocksize <= 2304) + lpc_precision = 11U; + else if(frame.blocksize <= 4608) + lpc_precision = 12U; + else if(frame.blocksize <= 8192) + lpc_precision = 13U; + else if(frame.blocksize <= 16384) + lpc_precision = 14U; + else + lpc_precision = 15; + + for(int i_precision = m_settings.MinPrecisionSearch; + i_precision <= m_settings.MaxPrecisionSearch && lpc_precision + i_precision < 16; + i_precision++) + + // check if we already calculated with this order, window and precision + { + if((frame.subframes[ch].lpc_ctx[iWindow].done_lpcs[i_precision] & 1U << order - 1) == 0) + { + frame.subframes[ch].lpc_ctx[iWindow].done_lpcs[i_precision] |= 1U << order - 1; + + uint cbits = lpc_precision + (uint)i_precision; + + frame.current.type = SubframeType.LPC; + frame.current.order = order; + frame.current.window = iWindow; + frame.current.cbits = (int)cbits; + + int pmax = get_max_p_order(m_settings.MaxPartitionOrder, frame.blocksize, frame.current.order); + int pmin = Math.Min(m_settings.MinPartitionOrder, pmax); + ulong* sums = stackalloc ulong[(pmax + 1) * FlakeConstants.MAX_PARTITIONS]; + ulong csum = 0; + + fixed(int* coefs = frame.current.coefs) + { + lpc.quantize_lpc_coefs(lpcs + (frame.current.order - 1) * lpc.MAX_LPC_ORDER, + frame.current.order, + cbits, + coefs, + out frame.current.shift, + 15, + 0); + + if(frame.current.shift < 0 || frame.current.shift > 15) throw new Exception("negative shift"); + + for(int i = frame.current.order; i > 0; i--) csum += (ulong)Math.Abs(coefs[i - 1]); + + if(csum << frame.subframes[ch].obits >= 1UL << 32) + { + lpc.encode_residual_long(frame.current.residual, + frame.subframes[ch].samples, + frame.blocksize, + frame.current.order, + coefs, + frame.current.shift, + sums + pmax * FlakeConstants.MAX_PARTITIONS, + pmax); + } + else + { + lpc.encode_residual(frame.current.residual, + frame.subframes[ch].samples, + frame.blocksize, + frame.current.order, + coefs, + frame.current.shift, + sums + pmax * FlakeConstants.MAX_PARTITIONS, + pmax); + } + } + + uint best_size = calc_rice_params_sums(frame.current.rc, + pmin, + pmax, + sums, + (uint)frame.blocksize, + (uint)frame.current.order, + Settings.PCM.BitsPerSample); + + frame.current.size = (uint)(frame.current.order * frame.subframes[ch].obits + + 4 + + 5 + + frame.current.order * (int)cbits + + 6 + + (int)best_size); + + frame.ChooseBestSubframe(ch); + + //if (frame.current.size >= frame.subframes[ch].best.size) + // postprocess_coefs(frame, frame.current, ch); + //else + //{ + // frame.ChooseBestSubframe(ch); + // postprocess_coefs(frame, frame.subframes[ch].best, ch); + //} + } + } + } + + unsafe void encode_residual_fixed_sub(FlacFrame frame, int order, int ch) + { + if((frame.subframes[ch].done_fixed & 1U << order) != 0) return; // already calculated; + + frame.current.order = order; + frame.current.type = SubframeType.Fixed; + +#if XXX + int best_order = order; + if (frame.subframes[ch].done_fixed == 0) + { + best_order = + encode_residual_fixed_estimate_best_order(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order); + if (best_order != order) + { + //frame.subframes[ch].done_fixed |= (1U << order); + order = best_order; + frame.current.order = order; + encode_residual_fixed(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order); + } + } + else +#endif + int pmax = get_max_p_order(m_settings.MaxPartitionOrder, frame.blocksize, frame.current.order); + int pmin = Math.Min(m_settings.MinPartitionOrder, pmax); + ulong* sums = stackalloc ulong[(pmax + 1) * FlakeConstants.MAX_PARTITIONS]; + + encode_residual_fixed(frame.current.residual, + frame.subframes[ch].samples, + frame.blocksize, + frame.current.order, + sums + pmax * FlakeConstants.MAX_PARTITIONS, + pmax); + + frame.current.size = (uint)(frame.current.order * frame.subframes[ch].obits) + + 6 + + calc_rice_params_sums(frame.current.rc, + pmin, + pmax, + sums, + (uint)frame.blocksize, + (uint)frame.current.order, + Settings.PCM.BitsPerSample); + + frame.subframes[ch].done_fixed |= 1U << order; + + frame.ChooseBestSubframe(ch); + } + + unsafe void + fixed_compute_best_predictor(int* data, uint data_len, ulong* errors) //, float* residual_bits_per_sample) + { + long last_error_0 = data[-1]; + long last_error_1 = data[-1] - data[-2]; + long last_error_2 = last_error_1 - (data[-2] - data[-3]); + long last_error_3 = last_error_2 - (data[-2] - 2 * data[-3] + data[-4]); + ulong total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; + +#if VARIANT1 + long error, save; + int* finish = data + data_len; + + while(data < finish) + { + error = *data++; + total_error_0 += (ulong)(error << 1 ^ error >> 63); + save = error; + error -= last_error_0; + total_error_1 += (ulong)(error << 1 ^ error >> 63); + last_error_0 = save; + save = error; + error -= last_error_1; + total_error_2 += (ulong)(error << 1 ^ error >> 63); + last_error_1 = save; + save = error; + error -= last_error_2; + total_error_3 += (ulong)(error << 1 ^ error >> 63); + last_error_2 = save; + save = error; + error -= last_error_3; + total_error_4 += (ulong)(error << 1 ^ error >> 63); + last_error_3 = save; + } +#else + int* finish = data + data_len; + while (data < finish) + { + long next_error_0 = *(data++); + long next_error_1 = next_error_0 - last_error_0; + long next_error_2 = next_error_1 - last_error_1; + long next_error_3 = next_error_2 - last_error_2; + long next_error_4 = next_error_3 - last_error_3; + + last_error_0 = next_error_0; + last_error_1 = next_error_1; + last_error_2 = next_error_2; + last_error_3 = next_error_3; + + total_error_0 += (ulong)((last_error_0 << 1) ^ (last_error_0 >> 63)); + total_error_1 += (ulong)((last_error_1 << 1) ^ (last_error_1 >> 63)); + total_error_2 += (ulong)((last_error_2 << 1) ^ (last_error_2 >> 63)); + total_error_3 += (ulong)((last_error_3 << 1) ^ (last_error_3 >> 63)); + total_error_4 += (ulong)((next_error_4 << 1) ^ (next_error_4 >> 63)); + } +#endif + + errors[0] = total_error_0; + errors[1] = total_error_1; + errors[2] = total_error_2; + errors[3] = total_error_3; + errors[4] = total_error_4; + + //residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0); + //residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0); + //residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0); + //residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0); + //residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0); + } + + unsafe int fixed_compute_best_predictor_order(ulong* error) + { + int order; + + if(error[0] < error[1] & error[0] < error[2] & error[0] < error[3] & error[0] < error[4]) + order = 0; + else if(error[1] < error[2] & error[1] < error[3] & error[1] < error[4]) + order = 1; + else if(error[2] < error[3] & error[2] < error[4]) + order = 2; + else if(error[3] < error[4]) + order = 3; + else + order = 4; + + return order; + } + + unsafe void encode_residual(FlacFrame frame, int ch, PredictionType predict, OrderMethod omethod, int pass, + int windows_mask) + { + int* smp = frame.subframes[ch].samples; + int i, n = frame.blocksize; + + // save best.window, because we can overwrite it later with fixed frame + + // CONSTANT + for(i = 1; i < n; i++) + { + if(smp[i] != smp[0]) break; + } + + if(i == n) + { + frame.subframes[ch].best.type = SubframeType.Constant; + frame.subframes[ch].best.residual[0] = smp[0]; + frame.subframes[ch].best.size = (uint)frame.subframes[ch].obits; + + return; + } + + // VERBATIM + frame.current.type = SubframeType.Verbatim; + frame.current.size = (uint)(frame.subframes[ch].obits * frame.blocksize); + frame.ChooseBestSubframe(ch); + + if(n < 5 || predict == PredictionType.None) return; + + // LPC + if(n > m_settings.MaxLPCOrder && (predict == PredictionType.Levinson || predict == PredictionType.Search) + + //predict == PredictionType.Search || + //(pass == 2 && frame.subframes[ch].best.type == SubframeType.LPC)) + ) + { + float* lpcs = stackalloc float[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_ORDER]; + int min_order = m_settings.MinLPCOrder; + int max_order = m_settings.MaxLPCOrder; + + for(var iWindow = 0; iWindow < _windowcount; iWindow++) + { + if((windows_mask & 1 << iWindow) == 0) continue; + + LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow]; + + fixed(LpcWindowSection* sections = &windowSections[frame.nSeg, iWindow, 0]) + { + lpc_ctx.GetReflection(frame.subframes[ch].sf, + max_order, + frame.blocksize, + smp, + frame.window_buffer + iWindow * FlakeConstants.MAX_BLOCKSIZE * 2, + sections); + } + + lpc_ctx.ComputeLPC(lpcs); + + //int frameSize = n; + //float* F = stackalloc float[frameSize]; + //float* B = stackalloc float[frameSize]; + //float* PE = stackalloc float[max_order + 1]; + //float* arp = stackalloc float[max_order]; + //float* rc = stackalloc float[max_order]; + + //for (int j = 0; j < frameSize; j++) + // F[j] = B[j] = smp[j]; + + //for (int K = 1; K <= max_order; K++) + //{ + // // BURG: + // float denominator = 0.0f; + // //float denominator = F[K - 1] * F[K - 1] + B[frameSize - K] * B[frameSize - K]; + // for (int j = 0; j < frameSize - K; j++) + // denominator += F[j + K] * F[j + K] + B[j] * B[j]; + // denominator /= 2; + + // // Estimate error + // PE[K - 1] = denominator / (frameSize - K); + + // float reflectionCoeff = 0.0f; + // for (int j = 0; j < frameSize - K; j++) + // reflectionCoeff += F[j + K] * B[j]; + // reflectionCoeff /= denominator; + // rc[K - 1] = arp[K - 1] = reflectionCoeff; + + // // Levinson-Durbin + // for (int j = 0; j < (K - 1) >> 1; j++) + // { + // float arptmp = arp[j]; + // arp[j] -= reflectionCoeff * arp[K - 2 - j]; + // arp[K - 2 - j] -= reflectionCoeff * arptmp; + // } + // if (((K - 1) & 1) != 0) + // arp[(K - 1) >> 1] -= reflectionCoeff * arp[(K - 1) >> 1]; + + // for (int j = 0; j < frameSize - K; j++) + // { + // float f = F[j + K]; + // float b = B[j]; + // F[j + K] = f - reflectionCoeff * b; + // B[j] = b - reflectionCoeff * f; + // } + + // for (int j = 0; j < K; j++) + // lpcs[(K - 1) * lpc.MAX_LPC_ORDER + j] = (float)arp[j]; + //} + + switch(omethod) + { + case OrderMethod.Akaike: + //lpc_ctx.SortOrdersAkaike(frame.blocksize, m_settings.EstimationDepth, max_order, 7.1, 0.0); + lpc_ctx.SortOrdersAkaike(frame.blocksize, + m_settings.EstimationDepth, + min_order, + max_order, + 4.5, + 0); + + break; + default: + throw new Exception("unknown order method"); + } + + for(i = 0; i < m_settings.EstimationDepth && i < max_order; i++) + encode_residual_lpc_sub(frame, lpcs, iWindow, lpc_ctx.best_orders[i], ch); + } + + postprocess_coefs(frame, frame.subframes[ch].best, ch); + } + + // FIXED + if(predict == PredictionType.Fixed || + predict == PredictionType.Search && pass != 1 || + + //predict == PredictionType.Search || + //(pass == 2 && frame.subframes[ch].best.type == SubframeType.Fixed) || + n > m_settings.MaxFixedOrder && n <= m_settings.MaxLPCOrder) + { + int max_fixed_order = Math.Min(m_settings.MaxFixedOrder, 4); + int min_fixed_order = Math.Min(m_settings.MinFixedOrder, max_fixed_order); + + if(min_fixed_order == 0 && max_fixed_order == 4) + { + fixed(ulong* fixed_errors = frame.subframes[ch].best_fixed) + { + if((frame.subframes[ch].done_fixed & 1U << 5) == 0) + { + fixed_compute_best_predictor(smp + 4, (uint)n - 4, fixed_errors); + frame.subframes[ch].done_fixed |= 1U << 5; + } + + i = fixed_compute_best_predictor_order(fixed_errors); + encode_residual_fixed_sub(frame, i, ch); + } + } + else + for(i = max_fixed_order; i >= min_fixed_order; i--) + encode_residual_fixed_sub(frame, i, ch); + } + } + + void output_frame_header(FlacFrame frame, BitWriter bitwriter) + { + bitwriter.writebits(15, 0x7FFC); + bitwriter.writebits(1, eparams.variable_block_size > 0 ? 1 : 0); + bitwriter.writebits(4, frame.bs_code0); + bitwriter.writebits(4, sr_code0); + + if(frame.ch_mode == ChannelMode.NotStereo) + bitwriter.writebits(4, ch_code); + else + bitwriter.writebits(4, (int)frame.ch_mode); + + bitwriter.writebits(3, bps_code); + bitwriter.writebits(1, 0); + bitwriter.write_utf8(frame_count); + + // custom block size + if(frame.bs_code1 >= 0) + { + if(frame.bs_code1 < 256) + bitwriter.writebits(8, frame.bs_code1); + else + bitwriter.writebits(16, frame.bs_code1); + } + + // custom sample rate + if(sr_code1 > 0) + { + if(sr_code1 < 256) + bitwriter.writebits(8, sr_code1); + else + bitwriter.writebits(16, sr_code1); + } + + // CRC-8 of frame header + bitwriter.flush(); + byte crc = crc8.ComputeChecksum(frame_buffer, 0, bitwriter.Length); + bitwriter.writebits(8, crc); + } + + unsafe void output_residual(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub) + { + // rice-encoded block + bitwriter.writebits(2, sub.best.rc.coding_method); + + // partition order + int porder = sub.best.rc.porder; + int psize = frame.blocksize >> porder; + + //assert(porder >= 0); + bitwriter.writebits(4, porder); + int res_cnt = psize - sub.best.order; + + int rice_len = 4 + sub.best.rc.coding_method; + + // residual + int j = sub.best.order; + + fixed(byte* fixbuf = &frame_buffer[0]) + { + for(var p = 0; p < 1 << porder; p++) + { + int k = sub.best.rc.rparams[p]; + bitwriter.writebits(rice_len, k); + if(p == 1) res_cnt = psize; + int cnt = Math.Min(res_cnt, frame.blocksize - j); + bitwriter.write_rice_block_signed(fixbuf, k, sub.best.residual + j, cnt); + j += cnt; + } + } + } + + unsafe void output_subframe_constant(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub) + { + bitwriter.writebits_signed(sub.obits, sub.best.residual[0]); + } + + unsafe void output_subframe_verbatim(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub) + { + int n = frame.blocksize; + for(var i = 0; i < n; i++) bitwriter.writebits_signed(sub.obits, sub.samples[i]); + + // Don't use residual here, because we don't copy samples to residual for verbatim frames. + } + + unsafe void output_subframe_fixed(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub) + { + // warm-up samples + for(var i = 0; i < sub.best.order; i++) bitwriter.writebits_signed(sub.obits, sub.best.residual[i]); + + // residual + output_residual(frame, bitwriter, sub); + } + + unsafe void output_subframe_lpc(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub) + { + // warm-up samples + for(var i = 0; i < sub.best.order; i++) bitwriter.writebits_signed(sub.obits, sub.best.residual[i]); + + // LPC coefficients + var cbits = 1; + + for(var i = 0; i < sub.best.order; i++) + while(cbits < 16 && sub.best.coefs[i] != sub.best.coefs[i] << 32 - cbits >> 32 - cbits) + cbits++; + + bitwriter.writebits(4, cbits - 1); + bitwriter.writebits_signed(5, sub.best.shift); + for(var i = 0; i < sub.best.order; i++) bitwriter.writebits_signed(cbits, sub.best.coefs[i]); + + // residual + output_residual(frame, bitwriter, sub); + } + + void output_subframes(FlacFrame frame, BitWriter bitwriter) + { + for(var ch = 0; ch < channels; ch++) + { + FlacSubframeInfo sub = frame.subframes[ch]; + + // subframe header + var type_code = (int)sub.best.type; + if(sub.best.type == SubframeType.Fixed) type_code |= sub.best.order; + if(sub.best.type == SubframeType.LPC) type_code |= sub.best.order - 1; + bitwriter.writebits(1, 0); + bitwriter.writebits(6, type_code); + bitwriter.writebits(1, sub.wbits != 0 ? 1 : 0); + if(sub.wbits > 0) bitwriter.writebits(sub.wbits, 1); + + // subframe + switch(sub.best.type) + { + case SubframeType.Constant: + output_subframe_constant(frame, bitwriter, sub); + + break; + case SubframeType.Verbatim: + output_subframe_verbatim(frame, bitwriter, sub); + + break; + case SubframeType.Fixed: + output_subframe_fixed(frame, bitwriter, sub); + + break; + case SubframeType.LPC: + output_subframe_lpc(frame, bitwriter, sub); + + break; + } + } + } + + void output_frame_footer(BitWriter bitwriter) + { + bitwriter.flush(); + ushort crc = bitwriter.get_crc16(); + bitwriter.writebits(16, crc); + bitwriter.flush(); + } + + void encode_residual_pass1(FlacFrame frame, int ch, int windows_mask) + { + int max_prediction_order = m_settings.MaxLPCOrder; + + //int max_fixed_order = m_settings.MaxFixedOrder; + //int min_fixed_order = m_settings.MinFixedOrder; + int lpc_min_precision_search = m_settings.MinPrecisionSearch; + int lpc_max_precision_search = m_settings.MaxPrecisionSearch; + int max_partition_order = m_settings.MaxPartitionOrder; + int estimation_depth = m_settings.EstimationDepth; + int development_mode = eparams.development_mode; + + //m_settings.MinFixedOrder = 2; + //m_settings.MaxFixedOrder = 2; + m_settings.MinPrecisionSearch = m_settings.MaxPrecisionSearch; + m_settings.MaxLPCOrder = Math.Min(m_settings.MaxLPCOrder, Math.Max(m_settings.MinLPCOrder, 8)); + m_settings.EstimationDepth = 1; + eparams.development_mode = Math.Min(eparams.development_mode, -1); + encode_residual(frame, ch, m_settings.PredictionType, OrderMethod.Akaike, 1, windows_mask); + + //m_settings.MinFixedOrder = min_fixed_order; + //m_settings.MaxFixedOrder = max_fixed_order; + m_settings.MaxLPCOrder = max_prediction_order; + m_settings.MinPrecisionSearch = lpc_min_precision_search; + m_settings.MaxPrecisionSearch = lpc_max_precision_search; + m_settings.MaxPartitionOrder = max_partition_order; + m_settings.EstimationDepth = estimation_depth; + eparams.development_mode = development_mode; + } + + void encode_residual_pass2(FlacFrame frame, int ch) + { + encode_residual(frame, + ch, + m_settings.PredictionType, + eparams.order_method, + 2, + estimate_best_windows(frame, ch)); + } + + unsafe int estimate_best_windows_akaike(FlacFrame frame, int ch, int count, bool onePerType) + { + int* windows_present = stackalloc int[_windowcount]; + for(var i = 0; i < _windowcount; i++) windows_present[i] = 0; + + if(onePerType) + { + for(var i = 0; i < _windowcount; i++) + { + for(var j = 0; j < _windowcount; j++) + if(windowType[j] == windowType[i]) + windows_present[j]++; + } + } + + float* err = stackalloc float[lpc.MAX_LPC_ORDER]; + + for(var i = 0; i < _windowcount; i++) + { + LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[i]; + + if(onePerType && windows_present[i] <= count) + { + err[i] = 0; + + continue; + } + + var estimate_order = 4; + + fixed(LpcWindowSection* sections = &windowSections[frame.nSeg, i, 0]) + { + lpc_ctx.GetReflection(frame.subframes[ch].sf, + estimate_order, + frame.blocksize, + frame.subframes[ch].samples, + frame.window_buffer + i * FlakeConstants.MAX_BLOCKSIZE * 2, + sections); + } + + lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 1, estimate_order, 4.5, 0.0); + + //err[i] = (float)(lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0)); + //err[i] = (float)((frame.blocksize * lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1] / windowScale[i]) + lpc_ctx.best_orders[0] * 4.5); + //err[i] = (float)((frame.blocksize * lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1] / windowScale[i]) + lpc_ctx.best_orders[0] * frame.subframes[ch].obits); + + // realistic + //err[i] = (float)(frame.blocksize * Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1]) / Math.Log(2) / 2.5 + //- windowScale[i] / 2 + lpc_ctx.best_orders[0] * frame.subframes[ch].obits / 2); + + //err[i] = (float)(frame.blocksize * Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1]) / Math.Log(2) / 2.5 + //- frame.blocksize * Math.Log(lpc_ctx.autocorr_values[0]) / 2.1 + //+ Math.Log(frame.blocksize) * lpc_ctx.best_orders[0] * 4.5 / 2.5 / Math.Log(2)); + + // Akaike + //err[i] = (float)(frame.blocksize * (Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1])) + Math.Log(frame.blocksize) * lpc_ctx.best_orders[0] * 4.5); + + //err[i] = (float)(lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) - frame.blocksize * (frame.subframes[ch].obits + Math.Log(windowScale[i] / frame.blocksize) / 2)); + + // tested good + err[i] = (float)(lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) - + frame.blocksize * Math.Log(lpc_ctx.autocorr_values[0]) / 2); + } + + int* best_windows = stackalloc int[lpc.MAX_LPC_ORDER]; + for(var i = 0; i < _windowcount; i++) best_windows[i] = i; + + for(var i = 0; i < _windowcount; i++) + { + for(int j = i + 1; j < _windowcount; j++) + { + if(err[best_windows[i]] > err[best_windows[j]]) + { + int tmp = best_windows[j]; + best_windows[j] = best_windows[i]; + best_windows[i] = tmp; + } + } + } + + var window_mask = 0; + + if(onePerType) + { + for(var i = 0; i < _windowcount; i++) windows_present[i] = count; + + for(var i = 0; i < _windowcount; i++) + { + int w = best_windows[i]; + + if(windows_present[w] > 0) + { + for(var j = 0; j < _windowcount; j++) + if(windowType[j] == windowType[w]) + windows_present[j]--; + + window_mask |= 1 << w; + } + } + } + else + for(var i = 0; i < _windowcount && i < count; i++) + window_mask |= 1 << best_windows[i]; + + return window_mask; + } + + int estimate_best_windows(FlacFrame frame, int ch) + { + if(_windowcount == 1 || m_settings.PredictionType == PredictionType.Fixed) return 1; + + switch(m_settings.WindowMethod) + { + case WindowMethod.Estimate: + return estimate_best_windows_akaike(frame, ch, 1, false); + case WindowMethod.Estimate2: + return estimate_best_windows_akaike(frame, ch, 2, false); + case WindowMethod.Estimate3: + return estimate_best_windows_akaike(frame, ch, 3, false); + case WindowMethod.EstimateN: + return estimate_best_windows_akaike(frame, ch, 1, true); + case WindowMethod.Evaluate2: + encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 2, false)); + + return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0; + case WindowMethod.Evaluate3: + encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 3, false)); + + return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0; + case WindowMethod.EvaluateN: + encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 1, true)); +#if XXX + if (frame.subframes[ch].best.type == SubframeType.LPC && frame.subframes[ch].best.order <= 4) + { + LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[frame.subframes[ch].best.window]; + double err = + lpc_ctx.prediction_error[frame.subframes[ch].best.order - 1] / lpc_ctx.autocorr_values[0]; + double est = frame.blocksize * (frame.subframes[ch].obits * (1 - err)); + double est1 = frame.blocksize * (frame.subframes[ch].obits * (err)); + if (est < 0 || est1 < 0) return -1; + } +#endif + return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0; + case WindowMethod.Evaluate2N: + encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 2, true)); + + return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0; + case WindowMethod.Evaluate3N: + encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 3, true)); + + return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0; + case WindowMethod.Evaluate: + encode_residual_pass1(frame, ch, -1); + + return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0; + case WindowMethod.Search: + return -1; + } + + return -1; + } + + unsafe void estimate_frame(FlacFrame frame, bool do_midside) + { + int subframes = do_midside ? channels * 2 : channels; + + switch(m_settings.StereoMethod) + { + case StereoMethod.Estimate: + for(var ch = 0; ch < subframes; ch++) + { + LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[0]; + var estimate_order = 4; + var iWindow = 0; + + fixed(LpcWindowSection* sections = &windowSections[frame.nSeg, iWindow, 0]) + { + lpc_ctx.GetReflection(frame.subframes[ch].sf, + estimate_order, + frame.blocksize, + frame.subframes[ch].samples, + frame.window_buffer + iWindow * FlakeConstants.MAX_BLOCKSIZE * 2, + sections); + } + + lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 1, estimate_order, 4.5, 0.0); + + frame.subframes[ch].best.size = (uint)Math.Max(0, + frame.blocksize * + Math.Log(lpc_ctx.prediction_error + [lpc_ctx.best_orders[0] - 1]) + + Math.Log(frame.blocksize) * + lpc_ctx.best_orders[0] * + 4.5 + + //= (uint)Math.Max(0, lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) + //* 2.0 / Math.Log(windowScale[0] / frame.blocksize) + + + 7.1 * + frame.subframes[ch].obits * + m_settings.MaxLPCOrder); + } + + break; + case StereoMethod.EstimateFixed: + for(var ch = 0; ch < subframes; ch++) + { + fixed(ulong* fixed_errors = frame.subframes[ch].best_fixed) + { + if((frame.subframes[ch].done_fixed & 1U << 5) == 0) + { + fixed_compute_best_predictor(frame.subframes[ch].samples + 4, + (uint)frame.blocksize - 4, + fixed_errors); + + frame.subframes[ch].done_fixed |= 1U << 5; + } + + int best_order = fixed_compute_best_predictor_order(fixed_errors); + + //residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0); + frame.subframes[ch].best.size = (uint)fixed_errors[best_order]; + } + } + + break; + case StereoMethod.EstimateX: + for(var ch = 0; ch < subframes; ch++) + { + for(var iWindow = 0; iWindow < _windowcount; iWindow++) + { + LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow]; + var estimate_order = 4; + + fixed(LpcWindowSection* sections = &windowSections[frame.nSeg, iWindow, 0]) + { + lpc_ctx.GetReflection(frame.subframes[ch].sf, + estimate_order, + frame.blocksize, + frame.subframes[ch].samples, + frame.window_buffer + iWindow * FlakeConstants.MAX_BLOCKSIZE * 2, + sections); + } + + lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 1, estimate_order, 4.5, 0.0); + + var estimate = (uint)Math.Max(0, + frame.blocksize * + Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1]) + + Math.Log(frame.blocksize) * lpc_ctx.best_orders[0] * 4.5 + + //= (uint)Math.Max(0, lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) + //* 2.0 / Math.Log(windowScale[0] / frame.blocksize) + + + 7.1 * frame.subframes[ch].obits * m_settings.MaxLPCOrder); + + if(iWindow == 0 || frame.subframes[ch].best.size > estimate) + frame.subframes[ch].best.size = estimate; + } + } + + break; + case StereoMethod.Evaluate: + for(var ch = 0; ch < subframes; ch++) encode_residual_pass1(frame, ch, 1); + + break; + case StereoMethod.EvaluateX: + for(var ch = 0; ch < subframes; ch++) + encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 1, false)); + + break; + case StereoMethod.Search: + for(var ch = 0; ch < subframes; ch++) encode_residual_pass2(frame, ch); + + break; + } + } + + uint measure_frame_size(FlacFrame frame, bool do_midside) + { + // crude estimation of header/footer size + var total = (uint)(32 + + (BitReader.log2i(frame_count) + 4) / 5 * 8 + + (eparams.variable_block_size != 0 ? 16 : 0) + + 16); + + if(do_midside) + { + uint bitsBest = AudioSamples.UINT32_MAX; + ChannelMode modeBest = ChannelMode.LeftRight; + + if(bitsBest > frame.subframes[2].best.size + frame.subframes[3].best.size) + { + bitsBest = frame.subframes[2].best.size + frame.subframes[3].best.size; + modeBest = ChannelMode.MidSide; + } + + if(bitsBest > frame.subframes[3].best.size + frame.subframes[1].best.size) + { + bitsBest = frame.subframes[3].best.size + frame.subframes[1].best.size; + modeBest = ChannelMode.RightSide; + } + + if(bitsBest > frame.subframes[3].best.size + frame.subframes[0].best.size) + { + bitsBest = frame.subframes[3].best.size + frame.subframes[0].best.size; + modeBest = ChannelMode.LeftSide; + } + + if(bitsBest > frame.subframes[0].best.size + frame.subframes[1].best.size) + { + bitsBest = frame.subframes[0].best.size + frame.subframes[1].best.size; + modeBest = ChannelMode.LeftRight; + } + + frame.ch_mode = modeBest; + + return total + bitsBest; + } + + for(var ch = 0; ch < channels; ch++) total += frame.subframes[ch].best.size; + + return total; + } + + void encode_estimated_frame(FlacFrame frame) + { + switch(m_settings.StereoMethod) + { + case StereoMethod.Estimate: + case StereoMethod.EstimateX: + case StereoMethod.EstimateFixed: + for(var ch = 0; ch < channels; ch++) + { + frame.subframes[ch].best.size = AudioSamples.UINT32_MAX; + encode_residual_pass2(frame, ch); + } + + break; + case StereoMethod.Evaluate: + case StereoMethod.EvaluateX: + for(var ch = 0; ch < channels; ch++) encode_residual_pass2(frame, ch); + + break; + case StereoMethod.Search: + break; + } + } + + unsafe delegate void window_function(float* window, int size); + + unsafe void calculate_window(float* window, window_function func, WindowFunction flag) + { + if((m_settings.WindowFunctions & flag) == 0 || _windowcount == lpc.MAX_LPC_WINDOWS) return; + int sz = _windowsize; + float* pos1 = window + _windowcount * FlakeConstants.MAX_BLOCKSIZE * 2; + float* pos = pos1; + var nSeg = 0; + + do + { + windowSections[nSeg, _windowcount, 0].setData(0, sz); + for(var j = 1; j < lpc.MAX_LPC_SECTIONS; j++) windowSections[nSeg, _windowcount, j].setZero(sz, sz); + + fixed(LpcWindowSection* sections = &windowSections[nSeg, _windowcount, 0]) + { + func(pos, sz); + } + + if((sz & 1) != 0) break; + nSeg++; + pos += sz; + sz >>= 1; + } while(sz >= 32); + + var scale = 0.0; + for(var i = 0; i < _windowsize; i++) scale += pos1[i] * pos1[i]; + windowScale[_windowcount] = scale; + windowType[_windowcount] = flag; + _windowcount++; + } + + class PunchoutTukeyVariant + { + public readonly double overlap; + public readonly double p; + public readonly int parts; + public readonly WindowFunction type; + + public PunchoutTukeyVariant(WindowFunction _type, int _parts, double _overlap, double _p) + { + parts = _parts; + type = _type; + overlap = _overlap; + p = _p; + } + } + + unsafe int encode_frame(out int size) + { + fixed(int* s = samplesBuffer, r = residualBuffer) + { + fixed(float* window = windowBuffer) + { + frame.InitSize(m_blockSize, eparams.variable_block_size != 0); + + if(frame.blocksize != _windowsize && + frame.blocksize > 4 && + m_settings.PredictionType != PredictionType.Fixed) + { + _windowsize = frame.blocksize; + _windowcount = 0; + calculate_window(window, lpc.window_welch, WindowFunction.Welch); + calculate_window(window, lpc.window_flattop, WindowFunction.Flattop); + calculate_window(window, lpc.window_hann, WindowFunction.Hann); + calculate_window(window, lpc.window_bartlett, WindowFunction.Bartlett); + + var tukeys = new PunchoutTukeyVariant[] + { + new(WindowFunction.Tukey4, 4, 0, 0.03), new(WindowFunction.Tukey4A, 4, 0, 0.03), + new(WindowFunction.Tukey4B, 4, 0, 0.03), + new(WindowFunction.Tukey4X, 4, m_settings.TukeyOverlap, m_settings.TukeyP), + new(WindowFunction.Tukey3, 3, 1.0 / 3, 0.03), new(WindowFunction.Tukey3A, 3, 1.0 / 3, 0.03), + new(WindowFunction.Tukey3B, 3, 1.0 / 3, 0.03), + new(WindowFunction.Tukey3X, 3, m_settings.TukeyOverlap, m_settings.TukeyP), + new(WindowFunction.Tukey2, 2, 0.25, 0.03), new(WindowFunction.Tukey2A, 2, 0.25, 0.03), + new(WindowFunction.Tukey2B, 2, 0.25, 0.03), + new(WindowFunction.Tukey2X, 2, m_settings.TukeyOverlap, m_settings.TukeyP), + new(WindowFunction.Tukey, 1, 0.0, 0.03), new(WindowFunction.Tukey1A, 1, 0.0, 0.03), + new(WindowFunction.Tukey1B, 1, 0.0, 0.03), + new(WindowFunction.Tukey1X, 1, m_settings.TukeyOverlap, m_settings.TukeyP) + }; + + foreach(PunchoutTukeyVariant tukey in tukeys) + { + if(tukey.parts == 0 || (m_settings.WindowFunctions & tukey.type) == 0) continue; + + if(tukey.parts == 1) + { + calculate_window(window, (w, wsz) => { lpc.window_tukey(w, wsz, tukey.p); }, tukey.type); + + continue; + } + + double overlap = tukey.overlap; + double overlap_units = overlap / (1.0 - overlap); + + for(var m = 0; m < tukey.parts; m++) + { + calculate_window(window, + (w, wsz) => + { + lpc.window_punchout_tukey(w, + wsz, + tukey.p, + tukey.p, + m / (tukey.parts + overlap_units), + (m + 1 + overlap_units) / + (tukey.parts + overlap_units)); + }, + tukey.type); + } + } + + if(_windowcount == 0) throw new Exception("invalid windowfunction"); + var nSeg = 0; + int sz = _windowsize; + float* window_segment = window; + + do + { + fixed(LpcWindowSection* sections = &windowSections[nSeg, 0, 0]) + { + LpcWindowSection.Detect(_windowcount, + window_segment, + FlakeConstants.MAX_BLOCKSIZE * 2, + sz, + Settings.PCM.BitsPerSample, + sections); + } + + if((sz & 1) != 0) break; + window_segment += sz; + nSeg++; + sz >>= 1; + } while(sz >= 32); +#if NONONO + using (TextWriter tx = File.CreateText(@"H:\ubuntu\flac\w.txt")) + { +#if !NONONO + int totaltotal = 0; + for (int i = 0; i < _windowcount; i++) + { + int total = 0; + for (int sec = 0; sec < lpc.MAX_LPC_SECTIONS; sec++) + if (windowSections[0, i, sec].m_type != LpcWindowSection.SectionType.Zero || windowSections[0, i, sec].m_start != windowSections[0, i, sec].m_end) + { + tx.WriteLine("{0}\t{1}\t{2}\t{3}", windowSections[0, i, sec].m_start, windowSections[0, i, sec].m_end, windowSections[0, i, sec].m_type, windowSections[0, i, sec].m_id); + if (windowSections[0, i, sec].m_type != LpcWindowSection.SectionType.One) + total += windowSections[0, i, sec].m_end - windowSections[0, i, sec].m_start; + } + totaltotal += total; + tx.WriteLine("{0} total window data", total); + } + tx.WriteLine("{0} grand total window data", totaltotal); +#endif + for (int x = 0; x < frame.blocksize; x++) + { + tx.Write("{0}", x); + for (int i = 0; i < _windowcount; i++) + tx.Write("\t{0}", window[i * FlakeConstants.MAX_BLOCKSIZE * 2 + x]); + tx.WriteLine(); + } + } +#endif + } + + if(channels != 2 || frame.blocksize <= 32 || m_settings.StereoMethod == StereoMethod.Independent) + { + frame.window_buffer = window; + frame.nSeg = 0; + frame.current.residual = r + channels * FlakeConstants.MAX_BLOCKSIZE; + frame.ch_mode = channels != 2 ? ChannelMode.NotStereo : ChannelMode.LeftRight; + + for(var ch = 0; ch < channels; ch++) + { + frame.subframes[ch] + .Init(s + ch * FlakeConstants.MAX_BLOCKSIZE, + r + ch * FlakeConstants.MAX_BLOCKSIZE, + Settings.PCM.BitsPerSample, + get_wasted_bits(s + ch * FlakeConstants.MAX_BLOCKSIZE, frame.blocksize)); + } + + for(var ch = 0; ch < channels; ch++) encode_residual_pass2(frame, ch); + } + else + { + //channel_decorrelation(s, s + FlakeConstants.MAX_BLOCKSIZE, s + 2 * FlakeConstants.MAX_BLOCKSIZE, s + 3 * FlakeConstants.MAX_BLOCKSIZE, frame.blocksize); + frame.window_buffer = window; + frame.nSeg = 0; + frame.current.residual = r + 4 * FlakeConstants.MAX_BLOCKSIZE; + + for(var ch = 0; ch < 4; ch++) + { + frame.subframes[ch] + .Init(s + ch * FlakeConstants.MAX_BLOCKSIZE, + r + ch * FlakeConstants.MAX_BLOCKSIZE, + Settings.PCM.BitsPerSample + (ch == 3 ? 1 : 0), + get_wasted_bits(s + ch * FlakeConstants.MAX_BLOCKSIZE, frame.blocksize)); + } + + //for (int ch = 0; ch < 4; ch++) + // for (int iWindow = 0; iWindow < _windowcount; iWindow++) + // frame.subframes[ch].lpc_ctx[iWindow].GetReflection(32, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer + iWindow * FlakeConstants.MAX_BLOCKSIZE * 2); + + estimate_frame(frame, true); + uint fs = measure_frame_size(frame, true); + + if(0 != eparams.variable_block_size) + { + var frame2 = new FlacFrame(channels * 2); + var frame3 = new FlacFrame(channels * 2); + var tumbler = 1; + + while((frame.blocksize & 1) == 0 && frame.blocksize >= 1024) + { + frame2.InitSize(frame.blocksize / 2, true); + frame2.window_buffer = frame.window_buffer + frame.blocksize; + frame2.nSeg = frame.nSeg + 1; + frame2.current.residual = r + tumbler * 5 * FlakeConstants.MAX_BLOCKSIZE; + + for(var ch = 0; ch < 4; ch++) + { + frame2.subframes[ch] + .Init(frame.subframes[ch].samples, + frame2.current.residual + (ch + 1) * frame2.blocksize, + frame.subframes[ch].obits + frame.subframes[ch].wbits, + frame.subframes[ch].wbits); + } + + estimate_frame(frame2, true); + + //measure_frame_size(frame2, true); + //frame2.ChooseSubframes(); + //encode_estimated_frame(frame2); + //uint fs2 = measure_frame_size(frame2, false); + uint fs2 = measure_frame_size(frame2, true); + uint fs3 = fs2; + + if(eparams.variable_block_size == 2 || eparams.variable_block_size == 4) + { + frame3.InitSize(frame2.blocksize, true); + frame3.window_buffer = frame2.window_buffer; + frame3.nSeg = frame2.nSeg; + frame3.current.residual = frame2.current.residual + 5 * frame2.blocksize; + + for(var ch = 0; ch < 4; ch++) + { + frame3.subframes[ch] + .Init(frame2.subframes[ch].samples + frame2.blocksize, + frame3.current.residual + (ch + 1) * frame3.blocksize, + frame.subframes[ch].obits + frame.subframes[ch].wbits, + frame.subframes[ch].wbits); + } + + estimate_frame(frame3, true); + fs3 = measure_frame_size(frame3, true); + } + + if(fs2 + fs3 > fs) break; + FlacFrame tmp = frame; + frame = frame2; + frame2 = tmp; + fs = fs2; + + if(eparams.variable_block_size <= 2) break; + tumbler = 1 - tumbler; + } + } + + frame.ChooseSubframes(); + encode_estimated_frame(frame); + } + + var bitwriter = new BitWriter(frame_buffer, 0, max_frame_size); + + output_frame_header(frame, bitwriter); + output_subframes(frame, bitwriter); + output_frame_footer(bitwriter); + + if(bitwriter.Length >= max_frame_size) throw new Exception("buffer overflow"); + + if(frame_buffer != null) + { + if(eparams.variable_block_size > 0) + frame_count += frame.blocksize; + else + frame_count++; + } + + size = frame.blocksize; + + return bitwriter.Length; + } + } + } + + unsafe int output_frame() + { + if(verify != null) + { + fixed(int* s = verifyBuffer, r = samplesBuffer) + { + for(var ch = 0; ch < channels; ch++) + { + AudioSamples.MemCpy(s + ch * FlakeConstants.MAX_BLOCKSIZE, + r + ch * FlakeConstants.MAX_BLOCKSIZE, + m_blockSize); + } + } + } + + int fs, bs; + + //if (0 != eparams.variable_block_size && 0 == (m_blockSize & 7) && m_blockSize >= 128) + // fs = encode_frame_vbs(); + //else + fs = encode_frame(out bs); + + if(seek_table != null && _IO.CanSeek) + { + for(var sp = 0; sp < seek_table.Length; sp++) + { + if(seek_table[sp].framesize != 0) continue; + + if(seek_table[sp].number > Position + bs) break; + + if(seek_table[sp].number >= Position) + { + seek_table[sp].number = Position; + seek_table[sp].offset = _IO.Position - first_frame_offset; + seek_table[sp].framesize = bs; + } + } + } + + Position += bs; + _IO.Write(frame_buffer, 0, fs); + TotalSize += fs; + + if(verify != null) + { + try + { + int decoded = verify.DecodeFrame(frame_buffer, 0, fs); + + if(decoded != fs || verify.Remaining != bs) throw new Exception(Resources.ExceptionValidationFailed); + + fixed(int* s = verifyBuffer, r = verify.Samples) + { + for(var ch = 0; ch < channels; ch++) + { + if(AudioSamples.MemCmp(s + ch * FlakeConstants.MAX_BLOCKSIZE, + r + ch * FlakeConstants.MAX_BLOCKSIZE, + bs)) + throw new Exception(Resources.ExceptionValidationFailed); + } + } + } + catch(Exception ex) + { + //if (channels == 2) + //{ + // var sw = new WAVWriter(string.Format("verify_{0}.wav", this.frame_count), new WAVWriterSettings(this.Settings.PCM)); + // sw.FinalSampleCount = this.frame.blocksize; + // var ab = new AudioBuffer(this.Settings.PCM, this.frame.blocksize); + // ab.Prepare(this.frame.blocksize); + // fixed (int* abs = ab.Samples, s = verifyBuffer) + // AudioSamples.Interlace(abs, s, s + FlakeConstants.MAX_BLOCKSIZE, this.frame.blocksize); + // sw.Write(ab); + // sw.Close(); + //} else + throw ex; + } + } + + if(bs < m_blockSize) + { + for(var ch = 0; ch < (channels == 2 ? 4 : channels); ch++) + { + Buffer.BlockCopy(samplesBuffer, + (bs + ch * FlakeConstants.MAX_BLOCKSIZE) * sizeof(int), + samplesBuffer, + ch * FlakeConstants.MAX_BLOCKSIZE * sizeof(int), + (m_blockSize - bs) * sizeof(int)); + } + + //fixed (int* s = samplesBuffer) + // for (int ch = 0; ch < channels; ch++) + // AudioSamples.MemCpy(s + ch * FlakeConstants.MAX_BLOCKSIZE, s + bs + ch * FlakeConstants.MAX_BLOCKSIZE, m_blockSize - bs); + } + + samplesInBuffer -= bs; + + return bs; + } + + public void Write(AudioBuffer buff) + { + if(!inited) + { + if(_IO == null) _IO = new FileStream(Path, FileMode.Create, FileAccess.Write, FileShare.Read, 0x20000); + inited = true; + int header_size = flake_encode_init(); + _IO.Write(header, 0, header_size); + if(_IO.CanSeek) first_frame_offset = _IO.Position; + } + + buff.Prepare(this); + + var pos = 0; + + while(pos < buff.Length) + { + int block = Math.Min(buff.Length - pos, m_blockSize - samplesInBuffer); + + copy_samples(buff.Samples, pos, block); + + pos += block; + + while(samplesInBuffer >= m_blockSize) output_frame(); + } + + if(md5 != null) md5.TransformBlock(buff.Bytes, 0, buff.ByteLength, null, 0); + } + + public string Path { get; } + + public static string Vendor + { + get + { + Version version = typeof(AudioEncoder).Assembly.GetName().Version; + + return vendor_string ?? "CUETools " + version.Major + "." + version.Minor + "." + version.Build; + } + set => vendor_string = value; + } + + static string vendor_string; + + int select_blocksize(int samplerate, int time_ms) + { + int blocksize = FlakeConstants.flac_blocksizes[1]; + int target = samplerate * time_ms / 1000; + + if(eparams.variable_block_size > 0) + { + blocksize = 1024; + while(target >= blocksize) blocksize <<= 1; + + return blocksize >> 1; + } + + for(var i = 8; i < FlakeConstants.flac_blocksizes.Length - 1; i++) + { + if(target >= FlakeConstants.flac_blocksizes[i] && FlakeConstants.flac_blocksizes[i] > blocksize) + blocksize = FlakeConstants.flac_blocksizes[i]; + } + + return blocksize; + } + + void write_streaminfo(byte[] header, int pos, int last) + { + Array.Clear(header, pos, 38); + var bitwriter = new BitWriter(header, pos, 38); + + // metadata header + bitwriter.writebits(1, last); + bitwriter.writebits(7, (int)MetadataType.StreamInfo); + bitwriter.writebits(24, 34); + + if(eparams.variable_block_size > 0) + bitwriter.writebits(16, 0); + else + bitwriter.writebits(16, m_blockSize); + + bitwriter.writebits(16, m_blockSize); + bitwriter.writebits(24, 0); + bitwriter.writebits(24, max_frame_size); + bitwriter.writebits(20, Settings.PCM.SampleRate); + bitwriter.writebits(3, channels - 1); + bitwriter.writebits(5, Settings.PCM.BitsPerSample - 1); + + // total samples + if(sample_count > 0) + { + bitwriter.writebits(4, 0); + bitwriter.writebits(32, sample_count); + } + else + { + bitwriter.writebits(4, 0); + bitwriter.writebits(32, 0); + } + + bitwriter.flush(); + } + + /** + * Write vorbis comment metadata block to byte array. + * Just writes the vendor string for now. + */ + int write_vorbis_comment(byte[] comment, int pos, int len, int last) + { + var bitwriter = new BitWriter(comment, pos, len); + Encoding enc = new UTF8Encoding(); + byte[] str = enc.GetBytes(Vendor); + + // metadata header + bitwriter.writebits(1, last); + bitwriter.writebits(7, (int)MetadataType.VorbisComment); + var tagsLen = 0; + + if(m_settings.Tags != null) + foreach(string t in m_settings.Tags) + tagsLen += 4 + enc.GetByteCount(t); + + bitwriter.writebits(24, 8 + str.Length + tagsLen); + for(var i = 0; i < 4; i++) bitwriter.writebits(8, str.Length >> i * 8 & 0xff); + bitwriter.write(str); + int nTags = m_settings.Tags != null ? m_settings.Tags.Length : 0; + for(var i = 0; i < 4; i++) bitwriter.writebits(8, nTags >> i * 8 & 0xff); + + if(m_settings.Tags != null) + { + foreach(string tag in m_settings.Tags) + { + str = enc.GetBytes(tag); + for(var i = 0; i < 4; i++) bitwriter.writebits(8, str.Length >> i * 8 & 0xff); + bitwriter.write(str); + } + } + + bitwriter.flush(); + + return bitwriter.Length; + } + + int write_seekpoints(byte[] header, int pos, int last) + { + seek_table_offset = pos + 4; + + var bitwriter = new BitWriter(header, pos, 4 + 18 * seek_table.Length); + + // metadata header + bitwriter.writebits(1, last); + bitwriter.writebits(7, (int)MetadataType.Seektable); + bitwriter.writebits(24, 18 * seek_table.Length); + + for(var i = 0; i < seek_table.Length; i++) + { + bitwriter.writebits(FlakeConstants.FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN, + (ulong)seek_table[i].number); + + bitwriter.writebits(FlakeConstants.FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN, + (ulong)seek_table[i].offset); + + bitwriter.writebits(FlakeConstants.FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN, + seek_table[i].framesize); + } + + bitwriter.flush(); + + return 4 + 18 * seek_table.Length; + } + + /** + * Write padding metadata block to byte array. + */ + int write_padding(byte[] padding, int pos, int last, int padlen) + { + var bitwriter = new BitWriter(padding, pos, 4); + + // metadata header + bitwriter.writebits(1, last); + bitwriter.writebits(7, (int)MetadataType.Padding); + bitwriter.writebits(24, padlen); + + bitwriter.flush(); + + return padlen + 4; + } + + int write_headers() + { + var header_size = 0; + var last = 0; + + // stream marker + header[0] = 0x66; + header[1] = 0x4C; + header[2] = 0x61; + header[3] = 0x43; + header_size += 4; + + // streaminfo + write_streaminfo(header, header_size, last); + header_size += 38; + + // seek table + if(_IO.CanSeek && seek_table != null) header_size += write_seekpoints(header, header_size, last); + + // vorbis comments + if(m_settings.Padding == 0) last = 1; + header_size += write_vorbis_comment(header, header_size, header.Length - header_size, last); + + // padding + if(m_settings.Padding > 0) + { + last = 1; + header_size += write_padding(header, header_size, last, m_settings.Padding); + } + + return header_size; + } + + int flake_encode_init() + { + int i, header_len; + + //if(flake_validate_params(s) < 0) + + ch_code = channels - 1; + + // find samplerate in table + for(i = 1; i < 12; i++) + { + if(Settings.PCM.SampleRate == FlakeConstants.flac_samplerates[i]) + { + sr_code0 = i; + + break; + } + } + + // if not in table, samplerate is non-standard + if(i == 12) throw new Exception("non-standard samplerate"); + + for(i = 1; i < 8; i++) + { + if(Settings.PCM.BitsPerSample == FlakeConstants.flac_bitdepths[i]) + { + bps_code = i; + + break; + } + } + + if(i == 8) throw new Exception("non-standard bps"); + + m_blockSize = m_settings.BlockSize != 0 + ? m_settings.BlockSize + : select_blocksize(Settings.PCM.SampleRate, eparams.block_time_ms); + + // set maximum encoded frame size (if larger, re-encodes in verbatim mode) + if(channels == 2) + { + max_frame_size = + 16 + (m_blockSize * (Settings.PCM.BitsPerSample + Settings.PCM.BitsPerSample + 1) + 7 >> 3); + } + else + max_frame_size = 16 + (m_blockSize * channels * Settings.PCM.BitsPerSample + 7 >> 3); + + if(_IO.CanSeek && eparams.do_seektable && sample_count > 0) + { + int seek_points_distance = Settings.PCM.SampleRate * 10; + int num_seek_points = 1 + sample_count / seek_points_distance; // 1 seek point per 10 seconds + if(sample_count % seek_points_distance == 0) num_seek_points--; + seek_table = new SeekPoint[num_seek_points]; + + for(var sp = 0; sp < num_seek_points; sp++) + { + seek_table[sp].framesize = 0; + seek_table[sp].offset = 0; + seek_table[sp].number = sp * seek_points_distance; + } + } + + // output header bytes + var tagsLen = 0; + Encoding enc = new UTF8Encoding(); + + if(m_settings.Tags != null) + foreach(string t in m_settings.Tags) + tagsLen += 4 + enc.GetByteCount(t); + + header = new byte[m_settings.Padding + 1024 + (seek_table == null ? 0 : seek_table.Length * 18) + tagsLen]; + header_len = write_headers(); + + // initialize CRC & MD5 + if(_IO.CanSeek && m_settings.DoMD5) md5 = new MD5CryptoServiceProvider(); + + if(m_settings.DoVerify) + { + verify = new AudioDecoder(Settings.PCM); + verifyBuffer = new int[FlakeConstants.MAX_BLOCKSIZE * channels]; + } + + frame_buffer = new byte[max_frame_size]; + + return header_len; + } +} + +struct FlakeEncodeParams +{ + // prediction order selection method + // set by user prior to calling flake_encode_init + // if set to less than 0, it is chosen based on compression. + // valid values are 0 to 5 + // 0 = use maximum order only + // 1 = use estimation + // 2 = 2-level + // 3 = 4-level + // 4 = 8-level + // 5 = full search + // 6 = log search + public OrderMethod order_method; + + // block time in milliseconds + // set by the user prior to calling flake_encode_init + // used to calculate block_size based on sample rate + // can also be changed by user before encoding a frame + public int block_time_ms; + + // whether to use variable block sizes + // set by user prior to calling flake_encode_init + // 0 = fixed block size + // 1 = variable block size + public int variable_block_size; + + public bool do_seektable; + + public int development_mode; + + public int flake_set_defaults(EncoderSettings settings) + { + order_method = OrderMethod.Akaike; + block_time_ms = 105; + variable_block_size = 0; + do_seektable = true; + development_mode = -1; + + if(settings.GetEncoderModeIndex() == 11) variable_block_size = 4; + + return 0; + } +} \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/COPYING b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/COPYING new file mode 100644 index 000000000..69352d1d3 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/COPYING @@ -0,0 +1,503 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/CUETools.Codecs.Flake.csproj b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/CUETools.Codecs.Flake.csproj new file mode 100644 index 000000000..a7db18bb0 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/CUETools.Codecs.Flake.csproj @@ -0,0 +1,29 @@ + + + + netstandard2.0 + 2.1.9.0 + CUETools.Codecs.Flake + CUETools.Codecs.Flake + CUETools + A library for encoding and decoding FLAC. + Copyright (c) 2008-2021 Grigory Chudov + Grigory Chudov + true + ..\bin\$(Configuration)\plugins + https://github.com/gchudov/cuetools.net + git + + + + + + False + + + + + + + + diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/ChannelMode.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/ChannelMode.cs new file mode 100644 index 000000000..e2544a336 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/ChannelMode.cs @@ -0,0 +1,11 @@ +namespace CUETools.Codecs.Flake +{ + public enum ChannelMode + { + NotStereo = 0, + LeftRight = 1, + LeftSide = 8, + RightSide = 9, + MidSide = 10 + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/DecoderSettings.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/DecoderSettings.cs new file mode 100644 index 000000000..dea9e8865 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/DecoderSettings.cs @@ -0,0 +1,36 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace CUETools.Codecs.Flake +{ + [JsonObject(MemberSerialization.OptIn)] + public class DecoderSettings : IAudioDecoderSettings + { + #region IAudioDecoderSettings implementation + [Browsable(false)] + public string Extension => "flac"; + + [Browsable(false)] + public string Name => "cuetools"; + + [Browsable(false)] + public Type DecoderType => typeof(AudioDecoder); + + [Browsable(false)] + public int Priority => 2; + + public IAudioDecoderSettings Clone() + { + return MemberwiseClone() as IAudioDecoderSettings; + } + #endregion + + public DecoderSettings() + { + this.Init(); + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/EncoderSettings.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/EncoderSettings.cs new file mode 100644 index 000000000..ba782b6e4 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/EncoderSettings.cs @@ -0,0 +1,271 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace CUETools.Codecs.Flake +{ + [JsonObject(MemberSerialization.OptIn)] + public class EncoderSettings : IAudioEncoderSettings + { + #region IAudioEncoderSettings implementation + [Browsable(false)] + public string Extension => "flac"; + + [Browsable(false)] + public string Name => "cuetools"; + + [Browsable(false)] + public Type EncoderType => typeof(AudioEncoder); + + [Browsable(false)] + public bool Lossless => true; + + [Browsable(false)] + public int Priority => 4; + + [Browsable(false)] + public string SupportedModes => this.AllowNonSubset || (this.PCM != null && this.PCM.SampleRate > 48000) ? "0 1 2 3 4 5 6 7 8 9 10 11" : "0 1 2 3 4 5 6 7 8"; + + [Browsable(false)] + public string DefaultMode => "5"; + + [Browsable(false)] + [DefaultValue("")] + [JsonProperty] + public string EncoderMode { get; set; } + + [Browsable(false)] + public AudioPCMConfig PCM { get; set; } + + [Browsable(false)] + public int BlockSize { get; set; } + + [Browsable(false)] + [DefaultValue(4096)] + public int Padding { get; set; } + + public IAudioEncoderSettings Clone() + { + return MemberwiseClone() as IAudioEncoderSettings; + } + #endregion + + public EncoderSettings() + { + this.Init(); + } + + public bool IsSubset() + { + return (BlockSize == 0 || (BlockSize <= 16384 && (PCM.SampleRate > 48000 || BlockSize <= 4608))) + && (PCM.SampleRate > 48000 || MaxLPCOrder <= 12) + && MaxPartitionOrder <= 8 + ; + //The blocksize bits in the frame header must be 0001-1110. The blocksize must be <=16384; if the sample rate is <= 48000Hz, the blocksize must be <=4608. + //The sample rate bits in the frame header must be 0001-1110. + //The bits-per-sample bits in the frame header must be 001-111. + //If the sample rate is <= 48000Hz, the filter order in LPC subframes must be less than or equal to 12, i.e. the subframe type bits in the subframe header may not be 101100-111111. + //The Rice partition order in a Rice-coded residual section must be less than or equal to 8. + } + + public void Validate() + { + if (this.GetEncoderModeIndex() < 0) + throw new Exception("unsupported encoder mode"); + this.SetDefaultValuesForMode(); + if (Padding < 0) + throw new Exception("unsupported padding value " + Padding.ToString()); + if (BlockSize != 0 && (BlockSize < 256 || BlockSize >= FlakeConstants.MAX_BLOCKSIZE)) + throw new Exception("unsupported block size " + BlockSize.ToString()); + if (MinLPCOrder > MaxLPCOrder || MaxLPCOrder > lpc.MAX_LPC_ORDER) + throw new Exception("invalid MaxLPCOrder " + MaxLPCOrder.ToString()); + if (MinFixedOrder < 0 || MinFixedOrder > 4) + throw new Exception("invalid MinFixedOrder " + MinFixedOrder.ToString()); + if (MaxFixedOrder < 0 || MaxFixedOrder > 4) + throw new Exception("invalid MaxFixedOrder " + MaxFixedOrder.ToString()); + if (MinPartitionOrder < 0) + throw new Exception("invalid MinPartitionOrder " + MinPartitionOrder.ToString()); + if (MinPartitionOrder > MaxPartitionOrder || MaxPartitionOrder > 8) + throw new Exception("invalid MaxPartitionOrder " + MaxPartitionOrder.ToString()); + if (PredictionType == PredictionType.None) + throw new Exception("invalid PredictionType " + PredictionType.ToString()); + if (PredictionType != PredictionType.Fixed) + { + if (WindowMethod == WindowMethod.Invalid) + throw new InvalidOperationException("invalid WindowMethod " + WindowMethod.ToString()); + if (WindowFunctions == WindowFunction.None) + throw new InvalidOperationException("invalid WindowFunctions " + WindowFunctions.ToString()); + if (EstimationDepth > 32 || EstimationDepth < 1) + throw new InvalidOperationException("invalid EstimationDepth " + EstimationDepth.ToString()); + if (MinPrecisionSearch < 0 || MinPrecisionSearch >= lpc.MAX_LPC_PRECISIONS) + throw new Exception("unsupported MinPrecisionSearch value"); + if (MaxPrecisionSearch < 0 || MaxPrecisionSearch >= lpc.MAX_LPC_PRECISIONS) + throw new Exception("unsupported MaxPrecisionSearch value"); + if (MaxPrecisionSearch < MinPrecisionSearch) + throw new Exception("unsupported MaxPrecisionSearch value"); + } + if (!AllowNonSubset && !IsSubset()) + throw new Exception("the encoding parameters specified do not conform to the FLAC Subset"); + } + + [DefaultValue(-1)] + [DefaultValueForMode(2, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0)] + [Browsable(false)] + [DisplayName("MinFixedOrder")] + [SRDescription(typeof(Properties.Resources), "MinFixedOrderDescription")] + public int MinFixedOrder { get; set; } + + [DefaultValue(-1)] + [DefaultValueForMode(2, 4, 4, 4, 2, 2, 4, 4, 4, 4, 4, 4)] + [Browsable(false)] + [DisplayName("MaxFixedOrder")] + [SRDescription(typeof(Properties.Resources), "MaxFixedOrderDescription")] + public int MaxFixedOrder { get; set; } + + [DefaultValue(1)] + [Browsable(false)] + [DisplayName("MinLPCOrder")] + [SRDescription(typeof(Properties.Resources), "MinLPCOrderDescription")] + public int MinLPCOrder { get; set; } + + [DefaultValue(-1)] + [DefaultValueForMode(8, 8, 8, 12, 12, 12, 12, 12, 12, 32, 32, 32)] + [Browsable(false)] + [DisplayName("MaxLPCOrder")] + [SRDescription(typeof(Properties.Resources), "MaxLPCOrderDescription")] + public int MaxLPCOrder { get; set; } + + [DefaultValue(0)] + [DisplayName("MinPartitionOrder")] + [Browsable(false)] + [SRDescription(typeof(Properties.Resources), "MinPartitionOrderDescription")] + public int MinPartitionOrder { get; set; } + + [DefaultValue(-1)] + [DefaultValueForMode(6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 8)] + [DisplayName("MaxPartitionOrder")] + [Browsable(false)] + [SRDescription(typeof(Properties.Resources), "MaxPartitionOrderDescription")] + public int MaxPartitionOrder { get; set; } + + [DefaultValue(false)] + [DisplayName("Verify")] + [SRDescription(typeof(Properties.Resources), "DoVerifyDescription")] + [JsonProperty] + public bool DoVerify { get; set; } + + [DefaultValue(true)] + [DisplayName("MD5")] + [SRDescription(typeof(Properties.Resources), "DoMD5Description")] + [JsonProperty] + public bool DoMD5 { get; set; } + + [DefaultValue(false)] + [DisplayName("Allow Non-subset")] + [SRDescription(typeof(Properties.Resources), "AllowNonSubsetDescription")] + [JsonProperty] + public bool AllowNonSubset { get; set; } + + [DefaultValue(StereoMethod.Invalid)] + [DefaultValueForMode( + /* 0 */ StereoMethod.Independent, + /* 1 */ StereoMethod.EstimateFixed, + /* 2 */ StereoMethod.Estimate, + /* 3 */ StereoMethod.Estimate, + /* 4 */ StereoMethod.Evaluate, + /* 5 */ StereoMethod.Evaluate, + /* 6 */ StereoMethod.Evaluate, + /* 7 */ StereoMethod.Evaluate, + /* 8 */ StereoMethod.Evaluate, + /* 9 */ StereoMethod.Evaluate, + /* 10 */ StereoMethod.Evaluate, + /* 11 */ StereoMethod.Evaluate)] + [Browsable(false)] + public StereoMethod StereoMethod { get; set; } + + [DefaultValue(PredictionType.None)] + [DefaultValueForMode( + /* 0 */ PredictionType.Fixed, + /* 1 */ PredictionType.Fixed, + /* 2 */ PredictionType.Levinson, + /* 3 */ PredictionType.Levinson, + /* 4 */ PredictionType.Search, + /* 5 */ PredictionType.Search, + /* 6 */ PredictionType.Search, + /* 7 */ PredictionType.Search, + /* 8 */ PredictionType.Search, + /* 9 */ PredictionType.Levinson, + /* 10 */ PredictionType.Search, + /* 11 */ PredictionType.Search)] + [Browsable(false)] + public PredictionType PredictionType { get; set; } + + [DefaultValue(WindowMethod.Invalid)] + [DefaultValueForMode( + /* 0 */ WindowMethod.Invalid, + /* 1 */ WindowMethod.Invalid, + /* 2 */ WindowMethod.Estimate, + /* 3 */ WindowMethod.Estimate, + /* 4 */ WindowMethod.Estimate, + /* 5 */ WindowMethod.EvaluateN, + /* 6 */ WindowMethod.EvaluateN, + /* 7 */ WindowMethod.EvaluateN, + /* 8 */ WindowMethod.EvaluateN, + /* 9 */ WindowMethod.EvaluateN, + /* 10 */ WindowMethod.EvaluateN, + /* 11 */ WindowMethod.EvaluateN)] + [Browsable(false)] + public WindowMethod WindowMethod { get; set; } + + [DefaultValue(WindowFunction.None)] + [DefaultValueForMode( + /* 0 */ WindowFunction.None, + /* 1 */ WindowFunction.None, + /* 2 */ WindowFunction.Tukey3, + /* 3 */ WindowFunction.Tukey4, + /* 4 */ WindowFunction.Tukey4, + /* 5 */ WindowFunction.Tukey4 | WindowFunction.Tukey3, + /* 6 */ WindowFunction.Tukey4 | WindowFunction.Tukey3 | WindowFunction.Tukey, + /* 7 */ WindowFunction.Tukey4 | WindowFunction.Tukey3 | WindowFunction.Tukey2 | WindowFunction.Tukey, + /* 8 */ WindowFunction.Tukey4 | WindowFunction.Tukey3 | WindowFunction.Tukey2 | WindowFunction.Tukey, + /* 9 */ WindowFunction.Tukey3 | WindowFunction.Tukey2 | WindowFunction.Tukey, + /* 10 */ WindowFunction.Tukey3 | WindowFunction.Tukey2 | WindowFunction.Tukey, + /* 11 */ WindowFunction.Tukey3 | WindowFunction.Tukey2 | WindowFunction.Tukey)] + [Browsable(false)] + [DisplayName("WindowFunctions")] + [SRDescription(typeof(Properties.Resources), "WindowFunctionsDescription")] + public WindowFunction WindowFunctions { get; set; } + + [DefaultValue(0)] + [DefaultValueForMode(0, 0, 1, 1, 1, 1, 1, 1, 3, 1, 1, 5)] + [Browsable(false)] + public int EstimationDepth { get; set; } + + [DefaultValue(-1)] + [DefaultValueForMode(1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1)] + [Browsable(false)] + public int MinPrecisionSearch { get; set; } + + [DefaultValue(-1)] + [DefaultValueForMode(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)] + [Browsable(false)] + public int MaxPrecisionSearch { get; set; } + + [DefaultValue(0)] + [Browsable(false)] + public int TukeyParts { get; set; } + + [DefaultValue(1.0)] + [Browsable(false)] + public double TukeyOverlap { get; set; } + + [DefaultValue(1.0)] + [Browsable(false)] + public double TukeyP { get; set; } + + [Browsable(false)] + public string[] Tags { get; set; } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/FlacFrame.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/FlacFrame.cs new file mode 100644 index 000000000..9397fdd99 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/FlacFrame.cs @@ -0,0 +1,96 @@ +namespace CUETools.Codecs.Flake +{ + unsafe public class FlacFrame + { + public int blocksize; + public int bs_code0, bs_code1; + public ChannelMode ch_mode; + //public int ch_order0, ch_order1; + public byte crc8; + public FlacSubframeInfo[] subframes; + public int frame_number; + public FlacSubframe current; + public float* window_buffer; + public int nSeg = 0; + + public BitWriter writer = null; + public int writer_offset = 0; + + public FlacFrame(int subframes_count) + { + subframes = new FlacSubframeInfo[subframes_count]; + for (int ch = 0; ch < subframes_count; ch++) + subframes[ch] = new FlacSubframeInfo(); + current = new FlacSubframe(); + } + + public void InitSize(int bs, bool vbs) + { + blocksize = bs; + int i = 15; + if (!vbs) + { + for (i = 0; i < 15; i++) + { + if (bs == FlakeConstants.flac_blocksizes[i]) + { + bs_code0 = i; + bs_code1 = -1; + break; + } + } + } + if (i == 15) + { + if (blocksize <= 256) + { + bs_code0 = 6; + bs_code1 = blocksize - 1; + } + else + { + bs_code0 = 7; + bs_code1 = blocksize - 1; + } + } + } + + public void ChooseBestSubframe(int ch) + { + if (current.size >= subframes[ch].best.size) + return; + FlacSubframe tmp = subframes[ch].best; + subframes[ch].best = current; + current = tmp; + } + + public void SwapSubframes(int ch1, int ch2) + { + FlacSubframeInfo tmp = subframes[ch1]; + subframes[ch1] = subframes[ch2]; + subframes[ch2] = tmp; + } + + /// + /// Swap subframes according to channel mode. + /// It is assumed that we have 4 subframes, + /// 0 is right, 1 is left, 2 is middle, 3 is difference + /// + public void ChooseSubframes() + { + switch (ch_mode) + { + case ChannelMode.MidSide: + SwapSubframes(0, 2); + SwapSubframes(1, 3); + break; + case ChannelMode.RightSide: + SwapSubframes(0, 3); + break; + case ChannelMode.LeftSide: + SwapSubframes(1, 3); + break; + } + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/FlacSubframe.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/FlacSubframe.cs new file mode 100644 index 000000000..4b69fd758 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/FlacSubframe.cs @@ -0,0 +1,21 @@ +namespace CUETools.Codecs.Flake +{ + unsafe public class FlacSubframe + { + public FlacSubframe() + { + rc = new RiceContext(); + coefs = new int[lpc.MAX_LPC_ORDER]; + } + public SubframeType type; + public int order; + public int* residual; + public RiceContext rc; + public uint size; + + public int cbits; + public int shift; + public int[] coefs; + public int window; + }; +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/FlacSubframeInfo.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/FlacSubframeInfo.cs new file mode 100644 index 000000000..4f6bd26de --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/FlacSubframeInfo.cs @@ -0,0 +1,45 @@ +using System; + +namespace CUETools.Codecs.Flake +{ + unsafe public class FlacSubframeInfo + { + public FlacSubframeInfo() + { + best = new FlacSubframe(); + sf = new LpcSubframeInfo(); + best_fixed = new ulong[5]; + lpc_ctx = new LpcContext[lpc.MAX_LPC_WINDOWS]; + for (int i = 0; i < lpc.MAX_LPC_WINDOWS; i++) + lpc_ctx[i] = new LpcContext(); + } + + public void Init(int* s, int* r, int bps, int w) + { + if (w > bps) + throw new Exception("internal error"); + samples = s; + obits = bps - w; + wbits = w; + for (int o = 0; o <= 4; o++) + best_fixed[o] = 0; + best.residual = r; + best.type = SubframeType.Verbatim; + best.size = AudioSamples.UINT32_MAX; + sf.Reset(); + for (int iWindow = 0; iWindow < lpc.MAX_LPC_WINDOWS; iWindow++) + lpc_ctx[iWindow].Reset(); + //sf.obits = obits; + done_fixed = 0; + } + + public FlacSubframe best; + public int obits; + public int wbits; + public int* samples; + public uint done_fixed; + public ulong[] best_fixed; + public LpcContext[] lpc_ctx; + public LpcSubframeInfo sf; + }; +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Flake.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Flake.cs new file mode 100644 index 000000000..0e4b0456d --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Flake.cs @@ -0,0 +1,68 @@ +/** + * CUETools.Flake: pure managed FLAC audio encoder + * Copyright (c) 2009-2021 Grigory Chudov + * Based on Flake encoder, http://flake-enc.sourceforge.net/ + * Copyright (c) 2006-2009 Justin Ruggles + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +using System; + +namespace CUETools.Codecs.Flake; + +public class FlakeConstants +{ + public const int MAX_BLOCKSIZE = 65535; + public const int MAX_RICE_PARAM = 14; + public const int MAX_PARTITION_ORDER = 8; + public const int MAX_PARTITIONS = 1 << MAX_PARTITION_ORDER; + + public const int FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */ + public const int FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */ + public const int FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */ + + public static readonly int[] flac_samplerates = + [ + 0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000, 0, 0, 0, 0 + ]; + + //1100 : get 8 bit sample rate (in kHz) from end of header + //1101 : get 16 bit sample rate (in Hz) from end of header + //1110 : get 16 bit sample rate (in tens of Hz) from end of header + public static readonly int[] flac_blocksizes = + [ + 0, 192, 576, 1152, 2304, 4608, 0, 0, 256, 512, 1024, 2048, 4096, 8192, 16384 + ]; + + //0110 : get 8 bit (blocksize-1) from end of header + //0111 : get 16 bit (blocksize-1) from end of header + public static readonly int[] flac_bitdepths = [0, 8, 12, 0, 16, 20, 24, 0]; + + public static PredictionType LookupPredictionType(string name) => + (PredictionType)Enum.Parse(typeof(PredictionType), name, true); + + public static StereoMethod LookupStereoMethod(string name) => + (StereoMethod)Enum.Parse(typeof(StereoMethod), name, true); + + public static WindowMethod LookupWindowMethod(string name) => + (WindowMethod)Enum.Parse(typeof(WindowMethod), name, true); + + public static OrderMethod LookupOrderMethod(string name) => + (OrderMethod)Enum.Parse(typeof(OrderMethod), name, true); + + public static WindowFunction LookupWindowFunction(string name) => + (WindowFunction)Enum.Parse(typeof(WindowFunction), name, true); +} \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/MetadataType.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/MetadataType.cs new file mode 100644 index 000000000..8f7f7055d --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/MetadataType.cs @@ -0,0 +1,45 @@ +namespace CUETools.Codecs.Flake +{ + public enum MetadataType + { + /// + /// STREAMINFO block + /// + StreamInfo = 0, + + /// + /// PADDING block + /// + Padding = 1, + + /// + /// APPLICATION block + /// + Application = 2, + + /// + /// SEEKTABLE block + /// + Seektable = 3, + + /// + /// VORBISCOMMENT block (a.k.a. FLAC tags) + /// + VorbisComment = 4, + + /// + /// CUESHEET block + /// + CUESheet = 5, + + /// + /// PICTURE block + /// + Picture = 6, + + /// + /// marker to denote beginning of undefined type range; this number will increase as new metadata types are added + /// + Undefined = 7 + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/OrderMethod.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/OrderMethod.cs new file mode 100644 index 000000000..25f38ba49 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/OrderMethod.cs @@ -0,0 +1,10 @@ +namespace CUETools.Codecs.Flake +{ + public enum OrderMethod + { + /// + /// Select orders based on Akaike's criteria + /// + Akaike = 0 + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/PredictionType.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/PredictionType.cs new file mode 100644 index 000000000..d41ef8257 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/PredictionType.cs @@ -0,0 +1,25 @@ +namespace CUETools.Codecs.Flake +{ + /// + /// Type of linear prediction + /// + public enum PredictionType + { + /// + /// Verbatim + /// + None = 0, + /// + /// Fixed prediction only + /// + Fixed = 1, + /// + /// Levinson-Durbin recursion + /// + Levinson = 2, + /// + /// Exhaustive search + /// + Search = 3 + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.Designer.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.Designer.cs new file mode 100644 index 000000000..dab1dc995 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.Designer.cs @@ -0,0 +1,108 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18033 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace CUETools.Codecs.Flake.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CUETools.Codecs.Flake.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Allow non-subset modes, which allow for greater compression, but are less compatible. + /// + internal static string AllowNonSubsetDescription { + get { + return ResourceManager.GetString("AllowNonSubsetDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Calculate MD5 hash for audio stream. + /// + internal static string DoMD5Description { + get { + return ResourceManager.GetString("DoMD5Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Decode each frame and compare with original. + /// + internal static string DoVerifyDescription { + get { + return ResourceManager.GetString("DoVerifyDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Samples written differs from the expected sample count. + /// + internal static string ExceptionSampleCount { + get { + return ResourceManager.GetString("ExceptionSampleCount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Validation failed. + /// + internal static string ExceptionValidationFailed { + get { + return ResourceManager.GetString("ExceptionValidationFailed", resourceCulture); + } + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.de-DE.resx b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.de-DE.resx new file mode 100644 index 000000000..40b3cd6dd --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.de-DE.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Non-subset Modi erlauben, die eine höhere Kompression ermöglichen, allerdings weniger kompatibel sind + + + MD5-Prüfsumme für Audiodaten berechnen + + + Jeden Frame dekodieren und mit dem Original vergleichen + + + Die geschriebenen Samples unterscheiden sich von der erwarteten Anzahl + + + Validierung fehlgeschlagen + + \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.resx b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.resx new file mode 100644 index 000000000..1fdb388fc --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Allow non-subset modes, which allow for greater compression, but are less compatible + + + Calculate MD5 hash for audio stream + + + Decode each frame and compare with original + + + Samples written differs from the expected sample count + + + Validation failed + + \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.ru-RU.resx b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.ru-RU.resx new file mode 100644 index 000000000..cbe431646 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/Properties/Resources.ru-RU.resx @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Вычислять MD5-хеш аудиопотока + + + Декодировать каждый кадр и сравнивать с оригиналом + + + Количество записанных сэмплов отличается от ожидаемого + + + Ошибка верификации + + + Разрешить non-subset режимы допускающие большее сжатие, +но меньшую совместимость с декодерами + + \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/RiceContext.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/RiceContext.cs new file mode 100644 index 000000000..c00aafbdc --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/RiceContext.cs @@ -0,0 +1,30 @@ +namespace CUETools.Codecs.Flake +{ + unsafe public class RiceContext + { + public RiceContext() + { + rparams = new int[FlakeConstants.MAX_PARTITIONS]; + esc_bps = new int[FlakeConstants.MAX_PARTITIONS]; + } + /// + /// partition order + /// + public int porder; + + /// + /// coding method: rice parameters use 4 bits for coding_method 0 and 5 bits for coding_method 1 + /// + public int coding_method; + + /// + /// Rice parameters + /// + public int[] rparams; + + /// + /// bps if using escape code + /// + public int[] esc_bps; + }; +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/SeekPoint.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/SeekPoint.cs new file mode 100644 index 000000000..f17bd7429 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/SeekPoint.cs @@ -0,0 +1,9 @@ +namespace CUETools.Codecs.Flake +{ + public struct SeekPoint + { + public long number; + public long offset; + public int framesize; + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/StereoMethod.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/StereoMethod.cs new file mode 100644 index 000000000..ddcc61d10 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/StereoMethod.cs @@ -0,0 +1,15 @@ + +namespace CUETools.Codecs.Flake +{ + public enum StereoMethod + { + Invalid, + Independent, + Estimate, + Evaluate, + Search, + EstimateX, + EvaluateX, + EstimateFixed, + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/SubframeType.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/SubframeType.cs new file mode 100644 index 000000000..3c5cadda5 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/SubframeType.cs @@ -0,0 +1,10 @@ +namespace CUETools.Codecs.Flake +{ + public enum SubframeType + { + Constant = 0, + Verbatim = 1, + Fixed = 8, + LPC = 32 + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/WindowFunction.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/WindowFunction.cs new file mode 100644 index 000000000..9723b56d4 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/WindowFunction.cs @@ -0,0 +1,27 @@ +namespace CUETools.Codecs.Flake +{ + public enum WindowFunction + { + None = 0, + Welch = 1, + Tukey = 2, + Hann = 4, + Flattop = 8, + Bartlett = 16, + Tukey2 = 32, + Tukey3 = 64, + Tukey4 = (1 << 7), + Tukey2A = (1 << 9), + Tukey2B = (1 << 10), + Tukey3A = (1 << 11), + Tukey3B = (1 << 12), + Tukey4A = (1 << 13), + Tukey4B = (1 << 14), + Tukey1A = (1 << 15), + Tukey1B = (1 << 16), + Tukey1X = (1 << 17), + Tukey2X = (1 << 18), + Tukey3X = (1 << 19), + Tukey4X = (1 << 20), + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/WindowMethod.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/WindowMethod.cs new file mode 100644 index 000000000..de4cc239a --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs.Flake/WindowMethod.cs @@ -0,0 +1,18 @@ +namespace CUETools.Codecs.Flake +{ + public enum WindowMethod + { + Invalid, + Evaluate, + Search, + Estimate, + Estimate2, + Estimate3, + EstimateN, + Evaluate2, + Evaluate2N, + Evaluate3, + Evaluate3N, + EvaluateN, + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioBuffer.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioBuffer.cs new file mode 100644 index 000000000..88fdce6b6 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioBuffer.cs @@ -0,0 +1,484 @@ +using System; + +namespace CUETools.Codecs +{ + public class AudioBuffer + { + #region Static Methods + + public static unsafe void FLACSamplesToBytes_16(int[,] inSamples, int inSampleOffset, + byte* outSamples, int sampleCount, int channelCount) + { + int loopCount = sampleCount * channelCount; + + if (inSamples.GetLength(0) - inSampleOffset < sampleCount) + throw new IndexOutOfRangeException(); + + fixed (int* pInSamplesFixed = &inSamples[inSampleOffset, 0]) + { + int* pInSamples = pInSamplesFixed; + short* pOutSamples = (short*)outSamples; + for (int i = 0; i < loopCount; i++) + pOutSamples[i] = (short)pInSamples[i]; + //*(pOutSamples++) = (short)*(pInSamples++); + } + } + + public static unsafe void FLACSamplesToBytes_16(int[,] inSamples, int inSampleOffset, + byte[] outSamples, int outByteOffset, int sampleCount, int channelCount) + { + int loopCount = sampleCount * channelCount; + + if ((inSamples.GetLength(0) - inSampleOffset < sampleCount) || + (outSamples.Length - outByteOffset < loopCount * 2)) + { + throw new IndexOutOfRangeException(); + } + + fixed (byte* pOutSamplesFixed = &outSamples[outByteOffset]) + FLACSamplesToBytes_16(inSamples, inSampleOffset, pOutSamplesFixed, sampleCount, channelCount); + } + + public static unsafe void FLACSamplesToBytes_24(int[,] inSamples, int inSampleOffset, + byte[] outSamples, int outByteOffset, int sampleCount, int channelCount, int wastedBits) + { + int loopCount = sampleCount * channelCount; + + if ((inSamples.GetLength(0) - inSampleOffset < sampleCount) || + (outSamples.Length - outByteOffset < loopCount * 3)) + { + throw new IndexOutOfRangeException(); + } + + fixed (int* pInSamplesFixed = &inSamples[inSampleOffset, 0]) + { + fixed (byte* pOutSamplesFixed = &outSamples[outByteOffset]) + { + int* pInSamples = pInSamplesFixed; + byte* pOutSamples = pOutSamplesFixed; + + for (int i = 0; i < loopCount; i++) + { + uint sample_out = (uint)*(pInSamples++) << wastedBits; + *(pOutSamples++) = (byte)(sample_out & 0xFF); + sample_out >>= 8; + *(pOutSamples++) = (byte)(sample_out & 0xFF); + sample_out >>= 8; + *(pOutSamples++) = (byte)(sample_out & 0xFF); + } + } + } + } + + public static unsafe void FloatToBytes_16(float[,] inSamples, int inSampleOffset, + byte[] outSamples, int outByteOffset, int sampleCount, int channelCount) + { + int loopCount = sampleCount * channelCount; + + if ((inSamples.GetLength(0) - inSampleOffset < sampleCount) || + (outSamples.Length - outByteOffset < loopCount * 2)) + { + throw new IndexOutOfRangeException(); + } + + fixed (float* pInSamplesFixed = &inSamples[inSampleOffset, 0]) + { + fixed (byte* pOutSamplesFixed = &outSamples[outByteOffset]) + { + float* pInSamples = pInSamplesFixed; + short* pOutSamples = (short*)pOutSamplesFixed; + + for (int i = 0; i < loopCount; i++) + { + *(pOutSamples++) = (short)(32758 * (*(pInSamples++))); + } + } + } + } + + public static unsafe void FloatToBytes(float[,] inSamples, int inSampleOffset, + byte[] outSamples, int outByteOffset, int sampleCount, int channelCount, int bitsPerSample) + { + if (bitsPerSample == 16) + FloatToBytes_16(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount); + //else if (bitsPerSample > 16 && bitsPerSample <= 24) + // FLACSamplesToBytes_24(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount, 24 - bitsPerSample); + else if (bitsPerSample == 32) + Buffer.BlockCopy(inSamples, inSampleOffset * 4 * channelCount, outSamples, outByteOffset, sampleCount * 4 * channelCount); + else + throw new Exception("Unsupported bitsPerSample value"); + } + + public static unsafe void FLACSamplesToBytes(int[,] inSamples, int inSampleOffset, + byte[] outSamples, int outByteOffset, int sampleCount, int channelCount, int bitsPerSample) + { + if (bitsPerSample == 16) + FLACSamplesToBytes_16(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount); + else if (bitsPerSample > 16 && bitsPerSample <= 24) + FLACSamplesToBytes_24(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount, 24 - bitsPerSample); + else + throw new Exception("Unsupported bitsPerSample value"); + } + + public static unsafe void FLACSamplesToBytes(int[,] inSamples, int inSampleOffset, + byte* outSamples, int sampleCount, int channelCount, int bitsPerSample) + { + if (bitsPerSample == 16) + FLACSamplesToBytes_16(inSamples, inSampleOffset, outSamples, sampleCount, channelCount); + else + throw new Exception("Unsupported bitsPerSample value"); + } + + public static unsafe void Bytes16ToFloat(byte[] inSamples, int inByteOffset, + float[,] outSamples, int outSampleOffset, int sampleCount, int channelCount) + { + int loopCount = sampleCount * channelCount; + + if ((inSamples.Length - inByteOffset < loopCount * 2) || + (outSamples.GetLength(0) - outSampleOffset < sampleCount)) + throw new IndexOutOfRangeException(); + + fixed (byte* pInSamplesFixed = &inSamples[inByteOffset]) + { + fixed (float* pOutSamplesFixed = &outSamples[outSampleOffset, 0]) + { + short* pInSamples = (short*)pInSamplesFixed; + float* pOutSamples = pOutSamplesFixed; + for (int i = 0; i < loopCount; i++) + *(pOutSamples++) = *(pInSamples++) / 32768.0f; + } + } + } + + public static unsafe void BytesToFLACSamples_16(byte[] inSamples, int inByteOffset, + int[,] outSamples, int outSampleOffset, int sampleCount, int channelCount) + { + int loopCount = sampleCount * channelCount; + + if ((inSamples.Length - inByteOffset < loopCount * 2) || + (outSamples.GetLength(0) - outSampleOffset < sampleCount)) + { + throw new IndexOutOfRangeException(); + } + + fixed (byte* pInSamplesFixed = &inSamples[inByteOffset]) + { + fixed (int* pOutSamplesFixed = &outSamples[outSampleOffset, 0]) + { + short* pInSamples = (short*)pInSamplesFixed; + int* pOutSamples = pOutSamplesFixed; + + for (int i = 0; i < loopCount; i++) + { + *(pOutSamples++) = (int)*(pInSamples++); + } + } + } + } + + public static unsafe void BytesToFLACSamples_24(byte[] inSamples, int inByteOffset, + int[,] outSamples, int outSampleOffset, int sampleCount, int channelCount, int wastedBits) + { + int loopCount = sampleCount * channelCount; + + if ((inSamples.Length - inByteOffset < loopCount * 3) || + (outSamples.GetLength(0) - outSampleOffset < sampleCount)) + throw new IndexOutOfRangeException(); + + fixed (byte* pInSamplesFixed = &inSamples[inByteOffset]) + { + fixed (int* pOutSamplesFixed = &outSamples[outSampleOffset, 0]) + { + byte* pInSamples = (byte*)pInSamplesFixed; + int* pOutSamples = pOutSamplesFixed; + for (int i = 0; i < loopCount; i++) + { + int sample = (int)*(pInSamples++); + sample += (int)*(pInSamples++) << 8; + sample += (int)*(pInSamples++) << 16; + *(pOutSamples++) = (sample << 8) >> (8 + wastedBits); + } + } + } + } + + public static unsafe void BytesToFLACSamples(byte[] inSamples, int inByteOffset, + int[,] outSamples, int outSampleOffset, int sampleCount, int channelCount, int bitsPerSample) + { + if (bitsPerSample == 16) + BytesToFLACSamples_16(inSamples, inByteOffset, outSamples, outSampleOffset, sampleCount, channelCount); + else if (bitsPerSample > 16 && bitsPerSample <= 24) + BytesToFLACSamples_24(inSamples, inByteOffset, outSamples, outSampleOffset, sampleCount, channelCount, 24 - bitsPerSample); + else + throw new Exception("Unsupported bitsPerSample value"); + } + + #endregion + + private int[,] samples; + private float[,] fsamples; + private byte[] bytes; + private int length; + private int size; + private AudioPCMConfig pcm; + private bool dataInSamples = false; + private bool dataInBytes = false; + private bool dataInFloat = false; + + public int Length + { + get { return length; } + set { length = value; } + } + + public int Size + { + get { return size; } + } + + public AudioPCMConfig PCM { get { return pcm; } } + + public int ByteLength + { + get + { + return length * pcm.BlockAlign; + } + } + + public int[,] Samples + { + get + { + if (samples == null || samples.GetLength(0) < length) + samples = new int[size, pcm.ChannelCount]; + if (!dataInSamples && dataInBytes && length != 0) + BytesToFLACSamples(bytes, 0, samples, 0, length, pcm.ChannelCount, pcm.BitsPerSample); + dataInSamples = true; + return samples; + } + } + + public float[,] Float + { + get + { + if (fsamples == null || fsamples.GetLength(0) < length) + fsamples = new float[size, pcm.ChannelCount]; + if (!dataInFloat && dataInBytes && length != 0) + { + if (pcm.BitsPerSample == 16) + Bytes16ToFloat(bytes, 0, fsamples, 0, length, pcm.ChannelCount); + //else if (pcm.BitsPerSample > 16 && PCM.BitsPerSample <= 24) + // BytesToFLACSamples_24(bytes, 0, fsamples, 0, length, pcm.ChannelCount, 24 - pcm.BitsPerSample); + else if (pcm.BitsPerSample == 32) + Buffer.BlockCopy(bytes, 0, fsamples, 0, length * 4 * pcm.ChannelCount); + else + throw new Exception("Unsupported bitsPerSample value"); + } + dataInFloat = true; + return fsamples; + } + } + + public byte[] Bytes + { + get + { + if (bytes == null || bytes.Length < length * pcm.BlockAlign) + bytes = new byte[size * pcm.BlockAlign]; + if (!dataInBytes && length != 0) + { + if (dataInSamples) + FLACSamplesToBytes(samples, 0, bytes, 0, length, pcm.ChannelCount, pcm.BitsPerSample); + else if (dataInFloat) + FloatToBytes(fsamples, 0, bytes, 0, length, pcm.ChannelCount, pcm.BitsPerSample); + } + dataInBytes = true; + return bytes; + } + } + + public AudioBuffer(AudioPCMConfig _pcm, int _size) + { + pcm = _pcm; + size = _size; + length = 0; + } + + public AudioBuffer(AudioPCMConfig _pcm, int[,] _samples, int _length) + { + pcm = _pcm; + // assert _samples.GetLength(1) == pcm.ChannelCount + Prepare(_samples, _length); + } + + public AudioBuffer(AudioPCMConfig _pcm, byte[] _bytes, int _length) + { + pcm = _pcm; + Prepare(_bytes, _length); + } + + public AudioBuffer(IAudioSource source, int _size) + { + pcm = source.PCM; + size = _size; + } + + public void Prepare(IAudioDest dest) + { + if (dest.Settings.PCM.ChannelCount != pcm.ChannelCount || dest.Settings.PCM.BitsPerSample != pcm.BitsPerSample) + throw new Exception("AudioBuffer format mismatch"); + } + + public void Prepare(IAudioSource source, int maxLength) + { + if (source.PCM.ChannelCount != pcm.ChannelCount || source.PCM.BitsPerSample != pcm.BitsPerSample) + throw new Exception("AudioBuffer format mismatch"); + length = size; + if (maxLength >= 0) + length = Math.Min(length, maxLength); + if (source.Remaining >= 0) + length = (int)Math.Min((long)length, source.Remaining); + dataInBytes = false; + dataInSamples = false; + dataInFloat = false; + } + + public void Prepare(int maxLength) + { + length = size; + if (maxLength >= 0) + length = Math.Min(length, maxLength); + dataInBytes = false; + dataInSamples = false; + dataInFloat = false; + } + + public void Prepare(int[,] _samples, int _length) + { + length = _length; + size = _samples.GetLength(0); + samples = _samples; + dataInSamples = true; + dataInBytes = false; + dataInFloat = false; + if (length > size) + throw new Exception("Invalid length"); + } + + public void Prepare(byte[] _bytes, int _length) + { + length = _length; + size = _bytes.Length / PCM.BlockAlign; + bytes = _bytes; + dataInSamples = false; + dataInBytes = true; + dataInFloat = false; + if (length > size) + throw new Exception("Invalid length"); + } + + internal unsafe void Load(int dstOffset, AudioBuffer src, int srcOffset, int copyLength) + { + if (dataInBytes) + Buffer.BlockCopy(src.Bytes, srcOffset * pcm.BlockAlign, Bytes, dstOffset * pcm.BlockAlign, copyLength * pcm.BlockAlign); + if (dataInSamples) + Buffer.BlockCopy(src.Samples, srcOffset * pcm.ChannelCount * 4, Samples, dstOffset * pcm.ChannelCount * 4, copyLength * pcm.ChannelCount * 4); + if (dataInFloat) + Buffer.BlockCopy(src.Float, srcOffset * pcm.ChannelCount * 4, Float, dstOffset * pcm.ChannelCount * 4, copyLength * pcm.ChannelCount * 4); + } + + public unsafe void Prepare(AudioBuffer _src, int _offset, int _length) + { + length = Math.Min(size, _src.Length - _offset); + if (_length >= 0) + length = Math.Min(length, _length); + dataInBytes = false; + dataInFloat = false; + dataInSamples = false; + if (_src.dataInBytes) + dataInBytes = true; + else if (_src.dataInSamples) + dataInSamples = true; + else if (_src.dataInFloat) + dataInFloat = true; + Load(0, _src, _offset, length); + } + + public void Swap(AudioBuffer buffer) + { + if (pcm.BitsPerSample != buffer.PCM.BitsPerSample || pcm.ChannelCount != buffer.PCM.ChannelCount) + throw new Exception("AudioBuffer format mismatch"); + + int[,] samplesTmp = samples; + float[,] floatsTmp = fsamples; + byte[] bytesTmp = bytes; + + fsamples = buffer.fsamples; + samples = buffer.samples; + bytes = buffer.bytes; + length = buffer.length; + size = buffer.size; + dataInSamples = buffer.dataInSamples; + dataInBytes = buffer.dataInBytes; + dataInFloat = buffer.dataInFloat; + + buffer.samples = samplesTmp; + buffer.bytes = bytesTmp; + buffer.fsamples = floatsTmp; + buffer.length = 0; + buffer.dataInSamples = false; + buffer.dataInBytes = false; + buffer.dataInFloat = false; + } + + unsafe public void Interlace(int pos, int* src1, int* src2, int n) + { + if (PCM.ChannelCount != 2) + { + throw new Exception("Must be stereo"); + } + if (PCM.BitsPerSample == 16) + { + fixed (byte* bs = Bytes) + { + int* res = ((int*)bs) + pos; + for (int i = n; i > 0; i--) + *(res++) = (*(src1++) & 0xffff) ^ (*(src2++) << 16); + } + } + else if (PCM.BitsPerSample == 24) + { + fixed (byte* bs = Bytes) + { + byte* res = bs + pos * 6; + for (int i = n; i > 0; i--) + { + uint sample_out = (uint)*(src1++); + *(res++) = (byte)(sample_out & 0xFF); + sample_out >>= 8; + *(res++) = (byte)(sample_out & 0xFF); + sample_out >>= 8; + *(res++) = (byte)(sample_out & 0xFF); + sample_out = (uint)*(src2++); + *(res++) = (byte)(sample_out & 0xFF); + sample_out >>= 8; + *(res++) = (byte)(sample_out & 0xFF); + sample_out >>= 8; + *(res++) = (byte)(sample_out & 0xFF); + } + } + } + else + { + throw new Exception("Unsupported BPS"); + } + } + + //public void Clear() + //{ + // length = 0; + //} + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioDecoderSettings.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioDecoderSettings.cs new file mode 100644 index 000000000..52a8234ce --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioDecoderSettings.cs @@ -0,0 +1,54 @@ +using System; +using System.ComponentModel; +using System.Collections.Generic; +using System.Xml.Serialization; +using System.Text; +using Newtonsoft.Json; +using System.IO; + +namespace CUETools.Codecs +{ + public interface IAudioDecoderSettings + { + string Name { get; } + + string Extension { get; } + + Type DecoderType { get; } + + int Priority { get; } + + IAudioDecoderSettings Clone(); + } + + public static class IAudioDecoderSettingsExtensions + { + public static bool HasBrowsableAttributes(this IAudioDecoderSettings settings) + { + bool hasBrowsable = false; + foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(settings)) + { + bool isBrowsable = true; + foreach (var attribute in property.Attributes) + { + var browsable = attribute as BrowsableAttribute; + isBrowsable &= browsable == null || browsable.Browsable; + } + hasBrowsable |= isBrowsable; + } + return hasBrowsable; + } + + public static void Init(this IAudioDecoderSettings settings) + { + // Iterate through each property and call ResetValue() + foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(settings)) + property.ResetValue(settings); + } + + public static IAudioSource Open(this IAudioDecoderSettings settings, string path, Stream IO = null) + { + return Activator.CreateInstance(settings.DecoderType, settings, path, IO) as IAudioSource; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioEncoderSettings.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioEncoderSettings.cs new file mode 100644 index 000000000..7d01b2f07 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioEncoderSettings.cs @@ -0,0 +1,124 @@ +using System; +using System.ComponentModel; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json; + +#if NET20 + namespace System.Runtime.CompilerServices + { + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class + | AttributeTargets.Method)] + public sealed class ExtensionAttribute : Attribute { } + } +#endif + +namespace CUETools.Codecs +{ + public interface IAudioEncoderSettings + { + string Name { get; } + + string Extension { get; } + + Type EncoderType { get; } + + bool Lossless { get; } + + int Priority { get; } + + string SupportedModes { get; } + + string DefaultMode { get; } + + string EncoderMode { get; set; } + + AudioPCMConfig PCM { get; set; } + + int BlockSize { get; set; } + + int Padding { get; set; } + + IAudioEncoderSettings Clone(); + } + + public static class IAudioEncoderSettingsExtensions + { + public static bool HasBrowsableAttributes(this IAudioEncoderSettings settings) + { + bool hasBrowsable = false; + foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(settings)) + { + bool isBrowsable = true; + foreach (var attribute in property.Attributes) + { + var browsable = attribute as BrowsableAttribute; + isBrowsable &= browsable == null || browsable.Browsable; + } + hasBrowsable |= isBrowsable; + } + return hasBrowsable; + } + + public static int GetEncoderModeIndex(this IAudioEncoderSettings settings) + { + return new List(settings.SupportedModes.Split(' ')).FindIndex(m => m == settings.EncoderMode); + } + + public static void SetEncoderModeIndex(this IAudioEncoderSettings settings, int value) + { + string[] modes = settings.SupportedModes.Split(' '); + if (modes.Length == 0 && value < 0) + return; + if (value < 0 || value >= modes.Length) + throw new IndexOutOfRangeException(); + settings.EncoderMode = modes[value]; + } + + public static void SetDefaultValuesForMode(this IAudioEncoderSettings settings) + { + foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(settings)) + if (!property.CanResetValue(settings)) + foreach (var attribute in property.Attributes) + if (attribute is DefaultValueForModeAttribute) + { + var defaultValueForMode = attribute as DefaultValueForModeAttribute; + property.SetValue(settings, defaultValueForMode.m_values[settings.GetEncoderModeIndex()]); + } + } + + public static bool HasDefaultValuesForMode(this IAudioEncoderSettings settings, int index) + { + bool res = true; + foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(settings)) + foreach (var attribute in property.Attributes) + if (attribute is DefaultValueForModeAttribute) + { + var defaultValueForMode = attribute as DefaultValueForModeAttribute; + res &= property.GetValue(settings).Equals(defaultValueForMode.m_values[index]); + } + return res; + } + + public static int GuessEncoderMode(this IAudioEncoderSettings settings) + { + // return new List(settings.SupportedModes.Split(' ')).FindIndex(m => settings.HasDefaultValuesForMode(m)); + string[] modes = settings.SupportedModes.Split(' '); + if (modes == null || modes.Length < 1) + return -1; + for (int i = 0; i < modes.Length; i++) + if (settings.HasDefaultValuesForMode(i)) + return i; + return -1; + } + + public static void Init(this IAudioEncoderSettings settings, AudioPCMConfig pcm = null) + { + // Iterate through each property and call ResetValue() + foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(settings)) + property.ResetValue(settings); + settings.EncoderMode = settings.DefaultMode; + settings.PCM = pcm; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioPCMConfig.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioPCMConfig.cs new file mode 100644 index 000000000..d0e2e72cd --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioPCMConfig.cs @@ -0,0 +1,138 @@ +namespace CUETools.Codecs +{ + public class AudioPCMConfig + { + public static readonly AudioPCMConfig RedBook = new AudioPCMConfig(16, 2, 44100); + public enum SpeakerConfig + { + SPEAKER_FRONT_LEFT = 0x1, + SPEAKER_FRONT_RIGHT = 0x2, + SPEAKER_FRONT_CENTER = 0x4, + SPEAKER_LOW_FREQUENCY = 0x8, + SPEAKER_BACK_LEFT = 0x10, + SPEAKER_BACK_RIGHT = 0x20, + SPEAKER_FRONT_LEFT_OF_CENTER = 0x40, + SPEAKER_FRONT_RIGHT_OF_CENTER = 0x80, + SPEAKER_BACK_CENTER = 0x100, + SPEAKER_SIDE_LEFT = 0x200, + SPEAKER_SIDE_RIGHT = 0x400, + SPEAKER_TOP_CENTER = 0x800, + SPEAKER_TOP_FRONT_LEFT = 0x1000, + SPEAKER_TOP_FRONT_CENTER = 0x2000, + SPEAKER_TOP_FRONT_RIGHT = 0x4000, + SPEAKER_TOP_BACK_LEFT = 0x8000, + SPEAKER_TOP_BACK_CENTER = 0x10000, + SPEAKER_TOP_BACK_RIGHT = 0x20000, + + DIRECTOUT = 0, + KSAUDIO_SPEAKER_MONO = (SPEAKER_FRONT_CENTER), + KSAUDIO_SPEAKER_STEREO = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT), + KSAUDIO_SPEAKER_QUAD = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT), + KSAUDIO_SPEAKER_SURROUND = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER), + KSAUDIO_SPEAKER_5POINT1 = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT), + KSAUDIO_SPEAKER_5POINT1_SURROUND = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT), + KSAUDIO_SPEAKER_7POINT1 = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER), + KSAUDIO_SPEAKER_7POINT1_SURROUND = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT), + + DVDAUDIO_GR1_0 = SPEAKER_FRONT_CENTER, + DVDAUDIO_GR1_1 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_2 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_3 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_4 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_5 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_6 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_7 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_8 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_9 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_10 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_11 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_12 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, + DVDAUDIO_GR1_13 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER, + DVDAUDIO_GR1_14 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER, + DVDAUDIO_GR1_15 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER, + DVDAUDIO_GR1_16 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER, + DVDAUDIO_GR1_17 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER, + DVDAUDIO_GR1_18 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, + DVDAUDIO_GR1_19 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, + DVDAUDIO_GR1_20 = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, + + DVDAUDIO_GR2_0 = 0, + DVDAUDIO_GR2_1 = 0, + DVDAUDIO_GR2_2 = SPEAKER_BACK_CENTER, + DVDAUDIO_GR2_3 = SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, + DVDAUDIO_GR2_4 = SPEAKER_LOW_FREQUENCY, + DVDAUDIO_GR2_5 = SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_CENTER, + DVDAUDIO_GR2_6 = SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, + DVDAUDIO_GR2_7 = SPEAKER_FRONT_CENTER, + DVDAUDIO_GR2_8 = SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER, + DVDAUDIO_GR2_9 = SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, + DVDAUDIO_GR2_10 = SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY, + DVDAUDIO_GR2_11 = SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_CENTER, + DVDAUDIO_GR2_12 = SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, + DVDAUDIO_GR2_13 = SPEAKER_BACK_CENTER, + DVDAUDIO_GR2_14 = SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, + DVDAUDIO_GR2_15 = SPEAKER_LOW_FREQUENCY, + DVDAUDIO_GR2_16 = SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_CENTER, + DVDAUDIO_GR2_17 = SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, + DVDAUDIO_GR2_18 = SPEAKER_LOW_FREQUENCY, + DVDAUDIO_GR2_19 = SPEAKER_FRONT_CENTER, + DVDAUDIO_GR2_20 = SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY, + } + + private int _bitsPerSample; + private int _channelCount; + private int _sampleRate; + private SpeakerConfig _channelMask; + + public int BitsPerSample { get { return _bitsPerSample; } } + public int ChannelCount { get { return _channelCount; } } + public int SampleRate { get { return _sampleRate; } } + public int BlockAlign { get { return _channelCount * ((_bitsPerSample + 7) / 8); } } + public SpeakerConfig ChannelMask { get { return _channelMask; } } + public bool IsRedBook { get { return _bitsPerSample == 16 && _channelCount == 2 && _sampleRate == 44100; } } + public static int ChannelsInMask(SpeakerConfig mask) + { + int count = 0; + while (mask != 0) + { + count++; + mask &= (mask - 1); + } + return count; + } + + public static SpeakerConfig GetDefaultChannelMask(int channelCount) + { + switch (channelCount) + { + case 1: + return SpeakerConfig.KSAUDIO_SPEAKER_MONO; + case 2: + return SpeakerConfig.KSAUDIO_SPEAKER_STEREO; + case 3: + return SpeakerConfig.KSAUDIO_SPEAKER_STEREO | SpeakerConfig.SPEAKER_LOW_FREQUENCY; + case 4: + return SpeakerConfig.KSAUDIO_SPEAKER_QUAD; + case 5: + //return SpeakerConfig.KSAUDIO_SPEAKER_5POINT1 & ~SpeakerConfig.SPEAKER_LOW_FREQUENCY; + return SpeakerConfig.KSAUDIO_SPEAKER_5POINT1_SURROUND & ~SpeakerConfig.SPEAKER_LOW_FREQUENCY; + case 6: + //return SpeakerConfig.KSAUDIO_SPEAKER_5POINT1; + return SpeakerConfig.KSAUDIO_SPEAKER_5POINT1_SURROUND; + case 7: + return SpeakerConfig.KSAUDIO_SPEAKER_5POINT1_SURROUND | SpeakerConfig.SPEAKER_BACK_CENTER; + case 8: + return SpeakerConfig.KSAUDIO_SPEAKER_7POINT1_SURROUND; + } + return (SpeakerConfig)((1 << channelCount) - 1); + } + + public AudioPCMConfig(int bitsPerSample, int channelCount, int sampleRate, SpeakerConfig channelMask = SpeakerConfig.DIRECTOUT) + { + _bitsPerSample = bitsPerSample; + _channelCount = channelCount; + _sampleRate = sampleRate; + _channelMask = channelMask == 0 ? GetDefaultChannelMask(channelCount) : channelMask; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioPipe.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioPipe.cs new file mode 100644 index 000000000..5715d8017 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioPipe.cs @@ -0,0 +1,269 @@ +using System; +using System.Threading; + +namespace CUETools.Codecs +{ + public class AudioPipe : IAudioSource//, IDisposable + { + private AudioBuffer _readBuffer, _writeBuffer; + private AudioPCMConfig pcm; + private long _sampleLen, _samplePos; + private int _maxLength; + private Thread _workThread; + private IAudioSource _source; + private bool _close = false; + private bool _haveData = false; + private int _bufferPos = 0; + private Exception _ex = null; + private bool own; + private ThreadPriority priority; + + public IAudioDecoderSettings Settings => null; + + public long Position + { + get + { + return _samplePos; + } + set + { + if (value == _samplePos) + return; + + if (_source == null) + throw new NotSupportedException(); + + lock (this) + { + _close = true; + Monitor.Pulse(this); + } + if (_workThread != null) + { + _workThread.Join(); + _workThread = null; + } + _source.Position = value; + _samplePos = value; + _bufferPos = 0; + _haveData = false; + _close = false; + //Go(); + //throw new Exception("not supported"); + } + } + + public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate); + + public long Length + { + get + { + return _sampleLen; + } + } + + public long Remaining + { + get + { + return _sampleLen - _samplePos; + } + } + + public AudioPCMConfig PCM + { + get + { + return pcm; + } + } + + public string Path + { + get + { + if (_source == null) + return ""; + return _source.Path; + } + } + + public AudioPipe(AudioPCMConfig pcm, int size) + { + this.pcm = pcm; + _readBuffer = new AudioBuffer(pcm, size); + _writeBuffer = new AudioBuffer(pcm, size); + _maxLength = size; + _sampleLen = -1; + _samplePos = 0; + } + + public AudioPipe(IAudioSource source, int size, bool own, ThreadPriority priority) + : this(source.PCM, size) + { + this.own = own; + this.priority = priority; + _source = source; + _sampleLen = _source.Length; + _samplePos = _source.Position; + } + + public AudioPipe(IAudioSource source, int size) + : this(source, size, true, ThreadPriority.BelowNormal) + { + } + + private void Decompress(object o) + { +#if !DEBUG + try +#endif + { + bool done = false; + do + { + done = _source.Read(_writeBuffer, -1) == 0; + lock (this) + { + while (_haveData && !_close) + Monitor.Wait(this); + if (_close) + break; + AudioBuffer temp = _writeBuffer; + _writeBuffer = _readBuffer; + _readBuffer = temp; + _haveData = true; + Monitor.Pulse(this); + } + } while (!done); + } +#if !DEBUG + catch (Exception ex) + { + lock (this) + { + _ex = ex; + Monitor.Pulse(this); + } + } +#endif + } + + private void Go() + { + if (_workThread != null || _ex != null || _source == null) return; + _workThread = new Thread(Decompress); + _workThread.Priority = priority; + _workThread.IsBackground = true; + _workThread.Name = "AudioPipe"; + _workThread.Start(null); + } + + //public new void Dispose() + //{ + // _buffer.Clear(); + //} + + public void Close() + { + lock (this) + { + _close = true; + Monitor.Pulse(this); + } + if (_workThread != null) + { + _workThread.Join(); + _workThread = null; + } + if (_source != null) + { + if (own) _source.Close(); + _source = null; + } + if (_readBuffer != null) + { + //_readBuffer.Clear(); + _readBuffer = null; + } + if (_writeBuffer != null) + { + //_writeBuffer.Clear(); + _writeBuffer = null; + } + } + + public int Write(AudioBuffer buff) + { + if (_writeBuffer.Size < _writeBuffer.Length + buff.Length) + { + AudioBuffer realloced = new AudioBuffer(pcm, _writeBuffer.Size + buff.Size); + realloced.Prepare(_writeBuffer, 0, _writeBuffer.Length); + _writeBuffer = realloced; + } + if (_writeBuffer.Length == 0) + _writeBuffer.Prepare(buff, 0, buff.Length); + else + { + _writeBuffer.Load(_writeBuffer.Length, buff, 0, buff.Length); + _writeBuffer.Length += buff.Length; + } + lock (this) + { + if (!_haveData) + { + AudioBuffer temp = _writeBuffer; + _writeBuffer = _readBuffer; + _writeBuffer.Length = 0; + _readBuffer = temp; + _haveData = true; + Monitor.Pulse(this); + } + } + return _writeBuffer.Length; + } + + public int Read(AudioBuffer buff, int maxLength) + { + Go(); + + bool needToCopy = false; + if (_bufferPos != 0) + needToCopy = true; + else + lock (this) + { + while (!_haveData && _ex == null) + Monitor.Wait(this); + if (_ex != null) + throw _ex; + if (_bufferPos == 0 && (maxLength < 0 || _readBuffer.Length <= maxLength)) + { + buff.Swap(_readBuffer); + _haveData = false; + Monitor.Pulse(this); + } + else + needToCopy = true; + } + if (needToCopy) + { + buff.Prepare(_readBuffer, _bufferPos, maxLength); + _bufferPos += buff.Length; + if (_bufferPos == _readBuffer.Length) + { + _bufferPos = 0; + lock (this) + { + _haveData = false; + Monitor.Pulse(this); + } + } + } + _samplePos += buff.Length; + return buff.Length; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioSamples.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioSamples.cs new file mode 100644 index 000000000..a8bf2c54e --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/AudioSamples.cs @@ -0,0 +1,142 @@ +using System; + +namespace CUETools.Codecs +{ + public class AudioSamples + { + public const uint UINT32_MAX = 0xffffffff; + + unsafe public static void Interlace(int* res, int* src1, int* src2, int n) + { + for (int i = n; i > 0; i--) + { + *(res++) = *(src1++); + *(res++) = *(src2++); + } + } + + unsafe public static void Deinterlace(int* dst1, int* dst2, int* src, int n) + { + for (int i = n; i > 0; i--) + { + *(dst1++) = *(src++); + *(dst2++) = *(src++); + } + } + + unsafe public static bool MemCmp(int* res, int* smp, int n) + { + for (int i = n; i > 0; i--) + if (*(res++) != *(smp++)) + return true; + return false; + } + + unsafe public static void MemCpy(uint* res, uint* smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = *(smp++); + } + + unsafe public static void MemCpy(int* res, int* smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = *(smp++); + } + + unsafe public static void MemCpy(long* res, long* smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = *(smp++); + } + + unsafe public static void MemCpy(short* res, short* smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = *(smp++); + } + + unsafe public static void MemCpy(byte* res, byte* smp, int n) + { + if ((((IntPtr)smp).ToInt64() & 7) == (((IntPtr)res).ToInt64() & 7) && n > 32) + { + int delta = (int)((8 - (((IntPtr)smp).ToInt64() & 7)) & 7); + for (int i = delta; i > 0; i--) + *(res++) = *(smp++); + n -= delta; + + MemCpy((long*)res, (long*)smp, n >> 3); + int n8 = (n >> 3) << 3; + n -= n8; + smp += n8; + res += n8; + } + if ((((IntPtr)smp).ToInt64() & 3) == (((IntPtr)res).ToInt64() & 3) && n > 16) + { + int delta = (int)((4 - (((IntPtr)smp).ToInt64() & 3)) & 3); + for (int i = delta; i > 0; i--) + *(res++) = *(smp++); + n -= delta; + + MemCpy((int*)res, (int*)smp, n >> 2); + int n4 = (n >> 2) << 2; + n -= n4; + smp += n4; + res += n4; + } + for (int i = n; i > 0; i--) + *(res++) = *(smp++); + } + + unsafe public static void MemSet(int* res, int smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = smp; + } + + unsafe public static void MemSet(long* res, long smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = smp; + } + + unsafe public static void MemSet(byte* res, byte smp, int n) + { + if (IntPtr.Size == 8 && (((IntPtr)res).ToInt64() & 7) == 0 && smp == 0 && n > 8) + { + MemSet((long*)res, 0, n >> 3); + int n8 = (n >> 3) << 3; + n -= n8; + res += n8; + } + if ((((IntPtr)res).ToInt64() & 3) == 0 && smp == 0 && n > 4) + { + MemSet((int*)res, 0, n >> 2); + int n4 = (n >> 2) << 2; + n -= n4; + res += n4; + } + for (int i = n; i > 0; i--) + *(res++) = smp; + } + + unsafe public static void MemSet(byte[] res, byte smp, int offs, int n) + { + fixed (byte* pres = &res[offs]) + MemSet(pres, smp, n); + } + + unsafe public static void MemSet(int[] res, int smp, int offs, int n) + { + fixed (int* pres = &res[offs]) + MemSet(pres, smp, n); + } + + unsafe public static void MemSet(long[] res, long smp, int offs, int n) + { + fixed (long* pres = &res[offs]) + MemSet(pres, smp, n); + } + } + +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/BitReader.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/BitReader.cs new file mode 100644 index 000000000..7989e28e9 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/BitReader.cs @@ -0,0 +1,309 @@ +using System; + +namespace CUETools.Codecs; + +public unsafe class BitReader +{ + byte* bptr_m; + int buffer_len_m; + + ulong cache_m; + ushort crc16_m; + int have_bits_m; + + public BitReader() + { + Buffer = null; + bptr_m = null; + buffer_len_m = 0; + have_bits_m = 0; + cache_m = 0; + crc16_m = 0; + } + + public BitReader(byte* _buffer, int _pos, int _len) + { + Reset(_buffer, _pos, _len); + } + + public int Position => (int)(bptr_m - Buffer - (have_bits_m >> 3)); + + public byte* Buffer { get; private set; } + + public void Reset(byte* _buffer, int _pos, int _len) + { + Buffer = _buffer; + bptr_m = _buffer + _pos; + buffer_len_m = _len; + have_bits_m = 0; + cache_m = 0; + crc16_m = 0; + fill(); + } + + public void fill() + { + while(have_bits_m < 56) + { + have_bits_m += 8; + byte b = *bptr_m++; + cache_m |= (ulong)b << 64 - have_bits_m; + crc16_m = (ushort)(crc16_m << 8 ^ Crc16.table[crc16_m >> 8 ^ b]); + } + } + + /* skip any number of bits */ + public void skipbits(int bits) + { + while(bits > have_bits_m) + { + bits -= have_bits_m; + cache_m = 0; + have_bits_m = 0; + fill(); + } + + cache_m <<= bits; + have_bits_m -= bits; + } + + public long read_long() => (long)readbits(32) << 32 | readbits(32); + + public ulong read_ulong() => (ulong)readbits(32) << 32 | readbits(32); + + public int read_int() => (int)readbits(sizeof(int)); + + public uint read_uint() => readbits(sizeof(uint)); + + public short read_short() => (short)readbits(16); + + public ushort read_ushort() => (ushort)readbits(16); + + /* supports reading 1 to 32 bits, in big endian format */ + public uint readbits(int bits) + { + fill(); + var result = (uint)(cache_m >> 64 - bits); + skipbits(bits); + + return result; + } + + /* supports reading 1 to 64 bits, in big endian format */ + public ulong readbits64(int bits) + { + if(bits <= 56) return readbits(bits); + + return (ulong)readbits(32) << bits - 32 | readbits(bits - 32); + } + + /* reads a single bit */ + public uint readbit() => readbits(1); + + public uint read_unary() + { + fill(); + uint val = 0; + ulong result = cache_m >> 56; + + while(result == 0) + { + val += 8; + cache_m <<= 8; + byte b = *bptr_m++; + cache_m |= (ulong)b << 64 - have_bits_m; + crc16_m = (ushort)(crc16_m << 8 ^ Crc16.table[crc16_m >> 8 ^ b]); + result = cache_m >> 56; + } + + val += byte_to_unary_table[result]; + skipbits((int)(val & 7) + 1); + + return val; + } + + public void flush() + { + if((have_bits_m & 7) > 0) + { + cache_m <<= have_bits_m & 7; + have_bits_m -= have_bits_m & 7; + } + } + + public ushort get_crc16() + { + if(have_bits_m == 0) return crc16_m; + ushort crc = 0; + int n = have_bits_m >> 3; + for(var i = 0; i < n; i++) crc = (ushort)(crc << 8 ^ Crc16.table[crc >> 8 ^ (byte)(cache_m >> 56 - (i << 3))]); + + return Crc16.Subtract(crc16_m, crc, n); + } + + public int readbits_signed(int bits) + { + var val = (int)readbits(bits); + val <<= 32 - bits; + val >>= 32 - bits; + + return val; + } + + public uint read_utf8() + { + uint x = readbits(8); + uint v; + int i; + + if(0 == (x & 0x80)) + { + v = x; + i = 0; + } + else if(0xC0 == (x & 0xE0)) /* 110xxxxx */ + { + v = x & 0x1F; + i = 1; + } + else if(0xE0 == (x & 0xF0)) /* 1110xxxx */ + { + v = x & 0x0F; + i = 2; + } + else if(0xF0 == (x & 0xF8)) /* 11110xxx */ + { + v = x & 0x07; + i = 3; + } + else if(0xF8 == (x & 0xFC)) /* 111110xx */ + { + v = x & 0x03; + i = 4; + } + else if(0xFC == (x & 0xFE)) /* 1111110x */ + { + v = x & 0x01; + i = 5; + } + else if(0xFE == x) /* 11111110 */ + { + v = 0; + i = 6; + } + else + throw new Exception("invalid utf8 encoding"); + + for(; i > 0; i--) + { + x = readbits(8); + + if(0x80 != (x & 0xC0)) /* 10xxxxxx */ throw new Exception("invalid utf8 encoding"); + v <<= 6; + v |= x & 0x3F; + } + + return v; + } + + public void read_rice_block(int n, int k, int* r) + { + fill(); + + fixed(byte* unary_table = byte_to_unary_table) + { + fixed(ushort* t = Crc16.table) + { + uint mask = (1U << k) - 1; + byte* bptr = bptr_m; + int have_bits = have_bits_m; + ulong cache = cache_m; + ushort crc = crc16_m; + + for(int i = n; i > 0; i--) + { + uint bits; + byte* orig_bptr = bptr; + + while((bits = unary_table[cache >> 56]) == 8) + { + cache <<= 8; + byte b = *bptr++; + cache |= (ulong)b << 64 - have_bits; + crc = (ushort)(crc << 8 ^ t[crc >> 8 ^ b]); + } + + uint msbs = bits + ((uint)(bptr - orig_bptr) << 3); + + // assumes k <= 41 (have_bits < 41 + 7 + 1 + 8 == 57, so we don't loose bits here) + while(have_bits < 56) + { + have_bits += 8; + byte b = *bptr++; + cache |= (ulong)b << 64 - have_bits; + crc = (ushort)(crc << 8 ^ t[crc >> 8 ^ b]); + } + + int btsk = k + (int)bits + 1; + uint uval = msbs << k | (uint)(cache >> 64 - btsk & mask); + cache <<= btsk; + have_bits -= btsk; + *r++ = (int)(uval >> 1 ^ -(int)(uval & 1)); + } + + have_bits_m = have_bits; + cache_m = cache; + bptr_m = bptr; + crc16_m = crc; + } + } + } + +#region Static Methods + + public static int log2i(int v) => log2i((uint)v); + + public static readonly byte[] MultiplyDeBruijnBitPosition = + [ + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, + 5, 4, 31 + ]; + + public static int log2i(ulong v) + { + v |= v >> 1; // first round down to one less than a power of 2 + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + + if(v >> 32 == 0) return MultiplyDeBruijnBitPosition[(uint)v * 0x07C4ACDDU >> 27]; + + return 32 + MultiplyDeBruijnBitPosition[(uint)(v >> 32) * 0x07C4ACDDU >> 27]; + } + + public static int log2i(uint v) + { + v |= v >> 1; // first round down to one less than a power of 2 + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + + return MultiplyDeBruijnBitPosition[v * 0x07C4ACDDU >> 27]; + } + + public static readonly byte[] byte_to_unary_table = + [ + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 + ]; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/BitWriter.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/BitWriter.cs new file mode 100644 index 000000000..524c727ac --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/BitWriter.cs @@ -0,0 +1,370 @@ +using System; + +namespace CUETools.Codecs +{ + public class BitWriter + { + private ushort crc16_m; + private ulong bit_buf_m; + private int bit_left_m; + private byte[] buffer; + private int buf_start, buf_ptr_m, buf_end; + private bool eof; + + public byte[] Buffer + { + get + { + return buffer; + } + } + + public int Length + { + get + { + return buf_ptr_m - buf_start; + } + set + { + flush(); + buf_ptr_m = buf_start + value; + } + } + + public int BitLength + { + get + { + return buf_ptr_m * 8 + 64 - bit_left_m; + } + } + + public ushort get_crc16() + { + return crc16_m; + } + + public BitWriter(byte[] buf, int pos, int len) + { + buffer = buf; + buf_start = pos; + buf_ptr_m = pos; + buf_end = pos + len; + bit_left_m = 64; + bit_buf_m = 0; + crc16_m = 0; + eof = false; + } + + public void Reset() + { + buf_ptr_m = buf_start; + bit_left_m = 64; + bit_buf_m = 0; + crc16_m = 0; + eof = false; + } + + public void writebytes(int bytes, byte c) + { + for (; bytes > 0; bytes--) + { + writebits(8, c); + } + } + + public unsafe void writeints(int len, int pos, byte* buf) + { + int old_pos = BitLength; + int start = old_pos / 8; + int start1 = pos / 8; + int end = (old_pos + len) / 8; + int end1 = (pos + len) / 8; + flush(); + byte start_val = old_pos % 8 != 0 ? buffer[start] : (byte)0; + fixed (byte* buf1 = &buffer[0]) + { + if (old_pos % 8 != 0) + crc16_m = Crc16.Subtract(crc16_m, 0, 1); + crc16_m = Crc16.ComputeChecksum(crc16_m, buf + start1, end - start); + AudioSamples.MemCpy(buf1 + start, buf + start1, end - start); + buf1[start] |= start_val; + } + buf_ptr_m = end; + if ((old_pos + len) % 8 != 0) + writebits((old_pos + len) % 8, buf[end1] >> (8 - ((old_pos + len) % 8))); + } + + public void write(params char[] chars) + { + foreach (char c in chars) + writebits(8, (byte)c); + } + + public void write(string s) + { + for (int i = 0; i < s.Length; i++) + writebits(8, (byte)s[i]); + } + + public void write(byte[] s) + { + for (int i = 0; i < s.Length; i++) + writebits(8, s[i]); + } + + public void writebits_signed(int bits, int val) + { + writebits(bits, val & ((1 << bits) - 1)); + } + + public void writebits_signed(uint bits, int val) + { + writebits((int)bits, val & ((1 << (int)bits) - 1)); + } + + public void writebits(int bits, int val) + { + writebits(bits, (ulong)val); + } + + public void writebits(DateTime val) + { + TimeSpan span = val.ToUniversalTime() - new DateTime(1904, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + writebits(32, (ulong)span.TotalSeconds); + } + + public void writebits(int bits, uint val) + { + writebits(bits, (ulong)val); + } + + public void writebits(int bits, ulong val) + { + //assert(bits == 32 || val < (1U << bits)); + + if (bits == 0 || eof) return; + if (bits < bit_left_m) + { + bit_left_m -= bits; + bit_buf_m |= val << bit_left_m; + } + else + { + ulong bb = bit_buf_m | (val >> (bits - bit_left_m)); + if (buffer != null) + { + if (buf_ptr_m + 8 > buf_end) + { + eof = true; + return; + } + + crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ (byte)(bb >> 56)]); + crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ (byte)(bb >> 48)]); + crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ (byte)(bb >> 40)]); + crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ (byte)(bb >> 32)]); + crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ (byte)(bb >> 24)]); + crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ (byte)(bb >> 16)]); + crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ (byte)(bb >> 8)]); + crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ (byte)(bb )]); + + buffer[buf_ptr_m + 7] = (byte)(bb & 0xFF); bb >>= 8; + buffer[buf_ptr_m + 6] = (byte)(bb & 0xFF); bb >>= 8; + buffer[buf_ptr_m + 5] = (byte)(bb & 0xFF); bb >>= 8; + buffer[buf_ptr_m + 4] = (byte)(bb & 0xFF); bb >>= 8; + buffer[buf_ptr_m + 3] = (byte)(bb & 0xFF); bb >>= 8; + buffer[buf_ptr_m + 2] = (byte)(bb & 0xFF); bb >>= 8; + buffer[buf_ptr_m + 1] = (byte)(bb & 0xFF); bb >>= 8; + buffer[buf_ptr_m + 0] = (byte)(bb & 0xFF); + buf_ptr_m += 8; + } + // cannot do this in one shift, because bit_left_m can be 64, + // + bit_left_m += 64 - bits; + bit_buf_m = bit_left_m == 64 ? 0 : val << bit_left_m; + } + } + + /// + /// Assumes there's enough space, buffer != null and bits is in range 1..31 + /// + /// + /// +// unsafe void writebits_fast(int bits, uint val, ref byte* buf) +// { +//#if DEBUG +// if ((buf_ptr + 3) >= buf_end) +// { +// eof = true; +// return; +// } +//#endif +// if (bits < bit_left) +// { +// bit_buf = (bit_buf << bits) | val; +// bit_left -= bits; +// } +// else +// { +// uint bb = (bit_buf << bit_left) | (val >> (bits - bit_left)); +// bit_left += (32 - bits); + +// *(buf++) = (byte)(bb >> 24); +// *(buf++) = (byte)(bb >> 16); +// *(buf++) = (byte)(bb >> 8); +// *(buf++) = (byte)(bb); + +// bit_buf = val; +// } +// } + + public void write_utf8(int val) + { + write_utf8((uint)val); + } + + public void write_utf8(uint val) + { + if (val < 0x80) + { + writebits(8, val); + return; + } + int bytes = (BitReader.log2i(val) + 4) / 5; + int shift = (bytes - 1) * 6; + writebits(8, (256U - (256U >> bytes)) | (val >> shift)); + while (shift >= 6) + { + shift -= 6; + writebits(8, 0x80 | ((val >> shift) & 0x3F)); + } + } + + public void write_unary_signed(int val) + { + // convert signed to unsigned + int v = -2 * val - 1; + v ^= (v >> 31); + + // write quotient in unary + int q = v + 1; + while (q > 31) + { + writebits(31, 0); + q -= 31; + } + writebits(q, 1); + } + + public void write_rice_signed(int k, int val) + { + // convert signed to unsigned + int v = -2 * val - 1; + v ^= (v >> 31); + + // write quotient in unary + int q = (v >> k) + 1; + while (q + k > 31) + { + int b = Math.Min(q + k - 31, 31); + writebits(b, 0); + q -= b; + } + + // write remainder in binary using 'k' bits + writebits(k + q, (v & ((1 << k) - 1)) | (1 << k)); + } + + public unsafe void write_rice_block_signed(byte* fixedbuf, int k, int* residual, int count) + { + byte* buf = &fixedbuf[buf_ptr_m]; + ulong bit_buf = bit_buf_m; + int bit_left = bit_left_m; + ushort crc16 = crc16_m; + fixed (ushort *crc16_t = Crc16.table) + for (int i = count; i > 0; i--) + { + int vi = *(residual++); + uint v = (uint)((vi << 1) ^ (vi >> 31)); + + // write quotient in unary + int q = (int)(v >> k) + 1; + int bits = k + q; + while (bits > 64) + { +#if DEBUG + if (buf + 1 > fixedbuf + buf_end) + { + eof = true; + return; + } +#endif + crc16 = (ushort)((crc16 << 8) ^ crc16_t[(crc16 >> 8) ^ (*(buf++) = (byte)(bit_buf >> 56))]); + bit_buf <<= 8; + bits -= 8; + } + + // write remainder in binary using 'k' bits + //writebits_fast(k + q, (uint)((v & ((1 << k) - 1)) | (1 << k)), ref buf); + ulong val = (uint)((v & ((1U << k) - 1)) | (1U << k)); + if (bits < bit_left) + { + bit_left -= bits; + bit_buf |= val << bit_left; + } + else + { + ulong bb = bit_buf | (val >> (bits - bit_left)); +#if DEBUG + if (buf + 8 > fixedbuf + buf_end) + { + eof = true; + return; + } +#endif + + crc16 = (ushort)((crc16 << 8) ^ crc16_t[(crc16 >> 8) ^ (*(buf++) = (byte)(bb >> 56))]); + crc16 = (ushort)((crc16 << 8) ^ crc16_t[(crc16 >> 8) ^ (*(buf++) = (byte)(bb >> 48))]); + crc16 = (ushort)((crc16 << 8) ^ crc16_t[(crc16 >> 8) ^ (*(buf++) = (byte)(bb >> 40))]); + crc16 = (ushort)((crc16 << 8) ^ crc16_t[(crc16 >> 8) ^ (*(buf++) = (byte)(bb >> 32))]); + crc16 = (ushort)((crc16 << 8) ^ crc16_t[(crc16 >> 8) ^ (*(buf++) = (byte)(bb >> 24))]); + crc16 = (ushort)((crc16 << 8) ^ crc16_t[(crc16 >> 8) ^ (*(buf++) = (byte)(bb >> 16))]); + crc16 = (ushort)((crc16 << 8) ^ crc16_t[(crc16 >> 8) ^ (*(buf++) = (byte)(bb >> 8))]); + crc16 = (ushort)((crc16 << 8) ^ crc16_t[(crc16 >> 8) ^ (*(buf++) = (byte)(bb))]); + + bit_left += 64 - bits; + bit_buf = (val << bit_left - 1) << 1; + } + } + crc16_m = crc16; + buf_ptr_m = (int)(buf - fixedbuf); + bit_buf_m = bit_buf; + bit_left_m = bit_left; + } + + public void flush() + { + while (bit_left_m < 64 && !eof) + { + if (buf_ptr_m >= buf_end) + { + eof = true; + break; + } + if (buffer != null) + { + byte b = (byte)(bit_buf_m >> 56); + crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ b]); + buffer[buf_ptr_m] = b; + } + buf_ptr_m++; + bit_buf_m <<= 8; + bit_left_m += 8; + } + bit_left_m = 64; + bit_buf_m = 0; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC16.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC16.cs new file mode 100644 index 000000000..85b321919 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC16.cs @@ -0,0 +1,164 @@ +using System; +namespace CUETools.Codecs +{ + public static class Crc16 + { + const int GF2_DIM = 16; + public static ushort[] table = new ushort[256]; + private static readonly ushort[,] combineTable = new ushort[GF2_DIM, GF2_DIM]; + private static readonly ushort[,] substractTable = new ushort[GF2_DIM, GF2_DIM]; + + public static unsafe ushort ComputeChecksum(ushort crc, byte[] bytes, int pos, int count) + { + fixed (byte* bs = bytes) + return ComputeChecksum(crc, bs + pos, count); + } + + public static unsafe ushort ComputeChecksum(ushort crc, byte* bytes, int count) + { + fixed (ushort* t = table) + for (int i = count; i > 0; i--) + { + crc = (ushort)((crc << 8) ^ t[(crc >> 8) ^ *(bytes++)]); + } + return crc; + } + + const ushort polynomial = 0x8005; + const ushort reversePolynomial = 0x4003; + + static unsafe Crc16() + { + for (ushort i = 0; i < table.Length; i++) + { + int crc = i; + for (int j = 0; j < GF2_DIM; j++) + { + if ((crc & (1U << (GF2_DIM - 1))) != 0) + crc = ((crc << 1) ^ polynomial); + else + crc <<= 1; + } + table[i] = (ushort)(crc & ((1 << GF2_DIM) - 1)); + } + + combineTable[0, 0] = Crc16.Reflect(polynomial); + substractTable[0, GF2_DIM - 1] = reversePolynomial; + for (int n = 1; n < GF2_DIM; n++) + { + combineTable[0, n] = (ushort)(1 << (n - 1)); + substractTable[0, n - 1] = (ushort)(1 << n); + } + + fixed (ushort* ct = &combineTable[0, 0], st = &substractTable[0, 0]) + { + //for (int i = 0; i < GF2_DIM; i++) + // st[32 + i] = ct[i]; + //invert_binary_matrix(st + 32, st, GF2_DIM); + + for (int i = 1; i < GF2_DIM; i++) + { + gf2_matrix_square(ct + i * GF2_DIM, ct + (i - 1) * GF2_DIM); + gf2_matrix_square(st + i * GF2_DIM, st + (i - 1) * GF2_DIM); + } + } + } + + private static unsafe ushort gf2_matrix_times(ushort* mat, ushort uvec) + { + int vec = ((int) uvec) << 16; + return (ushort)( + (*(mat++) & ((vec << 15) >> 31)) ^ + (*(mat++) & ((vec << 14) >> 31)) ^ + (*(mat++) & ((vec << 13) >> 31)) ^ + (*(mat++) & ((vec << 12) >> 31)) ^ + (*(mat++) & ((vec << 11) >> 31)) ^ + (*(mat++) & ((vec << 10) >> 31)) ^ + (*(mat++) & ((vec << 09) >> 31)) ^ + (*(mat++) & ((vec << 08) >> 31)) ^ + (*(mat++) & ((vec << 07) >> 31)) ^ + (*(mat++) & ((vec << 06) >> 31)) ^ + (*(mat++) & ((vec << 05) >> 31)) ^ + (*(mat++) & ((vec << 04) >> 31)) ^ + (*(mat++) & ((vec << 03) >> 31)) ^ + (*(mat++) & ((vec << 02) >> 31)) ^ + (*(mat++) & ((vec << 01) >> 31)) ^ + (*(mat++) & (vec >> 31))); + } + + private static unsafe void gf2_matrix_square(ushort* square, ushort* mat) + { + for (int n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); + } + + public static ushort Reflect(ushort crc) + { + return (ushort)Crc32.Reflect(crc, 16); + } + + public static unsafe ushort Combine(ushort crc1, ushort crc2, long len2) + { + crc1 = Crc16.Reflect(crc1); + crc2 = Crc16.Reflect(crc2); + + /* degenerate case */ + if (len2 == 0) + return crc1; + if (crc1 == 0) + return crc2; + if (len2 < 0) + throw new ArgumentException("crc.Combine length cannot be negative", "len2"); + + fixed (ushort* ct = &combineTable[0, 0]) + { + int n = 3; + do + { + /* apply zeros operator for this bit of len2 */ + if ((len2 & 1) != 0) + crc1 = gf2_matrix_times(ct + GF2_DIM * n, crc1); + len2 >>= 1; + n = (n + 1) & (GF2_DIM - 1); + /* if no more bits set, then done */ + } while (len2 != 0); + } + + /* return combined crc */ + crc1 ^= crc2; + crc1 = Crc16.Reflect(crc1); + return crc1; + } + + public static unsafe ushort Subtract(ushort crc1, ushort crc2, long len2) + { + crc1 = Crc16.Reflect(crc1); + crc2 = Crc16.Reflect(crc2); + /* degenerate case */ + if (len2 == 0) + return crc1; + if (len2 < 0) + throw new ArgumentException("crc.Combine length cannot be negative", "len2"); + + crc1 ^= crc2; + + fixed (ushort* st = &substractTable[0, 0]) + { + int n = 3; + do + { + /* apply zeros operator for this bit of len2 */ + if ((len2 & 1) != 0) + crc1 = gf2_matrix_times(st + GF2_DIM * n, crc1); + len2 >>= 1; + n = (n + 1) & (GF2_DIM - 1); + /* if no more bits set, then done */ + } while (len2 != 0); + } + + /* return combined crc */ + crc1 = Crc16.Reflect(crc1); + return crc1; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC16CCITT.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC16CCITT.cs new file mode 100644 index 000000000..aba9c60a6 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC16CCITT.cs @@ -0,0 +1,54 @@ +namespace CUETools.Codecs; + +public enum InitialCrcValue +{ + Zeros, + NonZero1 = 0xffff, + NonZero2 = 0x1D0F +} + +public class Crc16Ccitt +{ + const ushort poly = 4129; + readonly ushort initialValue; + readonly ushort[] table = new ushort[256]; + + public Crc16Ccitt(InitialCrcValue initialValue) + { + this.initialValue = (ushort)initialValue; + ushort temp, a; + + for(var i = 0; i < table.Length; i++) + { + temp = 0; + a = (ushort)(i << 8); + + for(var j = 0; j < 8; j++) + { + if(((temp ^ a) & 0x8000) != 0) + temp = (ushort)(temp << 1 ^ poly); + else + temp <<= 1; + + a <<= 1; + } + + table[i] = temp; + } + } + + public ushort ComputeChecksum(byte[] bytes, int pos, int count) + { + ushort crc = initialValue; + for(int i = pos; i < pos + count; i++) crc = (ushort)(crc << 8 ^ table[crc >> 8 ^ 0xff & bytes[i]]); + + return crc; + } + + public byte[] ComputeChecksumBytes(byte[] bytes, int pos, int count) + { + ushort crc = ComputeChecksum(bytes, pos, count); + + return [(byte)(crc >> 8), (byte)(crc & 0x00ff)]; + } +} \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC32.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC32.cs new file mode 100644 index 000000000..48a629f39 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC32.cs @@ -0,0 +1,259 @@ +using System; + +namespace CUETools.Codecs +{ + public static class Crc32 + { + public static readonly uint[] table; + + public static uint ComputeChecksum(uint crc, byte val) + { + return (crc >> 8) ^ table[(crc & 0xff) ^ val]; + } + + public static unsafe uint ComputeChecksum(uint crc, byte* bytes, int count) + { + fixed (uint *t = table) + for (int i = 0; i < count; i++) + crc = (crc >> 8) ^ t[(crc ^ bytes[i]) & 0xff]; + return crc; + } + + public static unsafe uint ComputeChecksum(uint crc, byte[] bytes, int pos, int count) + { + fixed (byte* pbytes = &bytes[pos]) + return ComputeChecksum(crc, pbytes, count); + } + + public static uint ComputeChecksum(uint crc, uint s) + { + return ComputeChecksum(ComputeChecksum(ComputeChecksum(ComputeChecksum( + crc, (byte)s), (byte)(s >> 8)), (byte)(s >> 16)), (byte)(s >> 24)); + } + + public static unsafe uint ComputeChecksum(uint crc, int* samples, int count) + { + for (int i = 0; i < count; i++) + { + int s1 = samples[2 * i], s2 = samples[2 * i + 1]; + crc = ComputeChecksum(ComputeChecksum(ComputeChecksum(ComputeChecksum( + crc, (byte)s1), (byte)(s1 >> 8)), (byte)s2), (byte)(s2 >> 8)); + } + return crc; + } + + internal static uint Reflect(uint val, int ch) + { + uint value = 0; + // Swap bit 0 for bit 7 + // bit 1 for bit 6, etc. + for (int i = 1; i < (ch + 1); i++) + { + if (0 != (val & 1)) + value |= 1U << (ch - i); + val >>= 1; + } + return value; + } + + const uint uPolynomial = 0x04c11db7; + const uint uReversePolynomial = 0xedb88320; + const uint uReversePolynomial2 = 0xdb710641; + + private static readonly uint[,] combineTable; + private static readonly uint[,] substractTable; + +#if need_invert_binary_matrix + static unsafe void invert_binary_matrix(uint* mat, uint* inv, int rows) + { + int cols, i, j; + uint tmp; + + cols = rows; + + for (i = 0; i < rows; i++) inv[i] = (1U << i); + + /* First -- convert into upper triangular */ + + for (i = 0; i < cols; i++) + { + + /* Swap rows if we ave a zero i,i element. If we can't swap, then the + matrix was not invertible */ + + if ((mat[i] & (1 << i)) == 0) + { + for (j = i + 1; j < rows && (mat[j] & (1 << i)) == 0; j++) ; + if (j == rows) + throw new Exception("Matrix not invertible"); + tmp = mat[i]; mat[i] = mat[j]; mat[j] = tmp; + tmp = inv[i]; inv[i] = inv[j]; inv[j] = tmp; + } + + /* Now for each j>i, add A_ji*Ai to Aj */ + for (j = i + 1; j != rows; j++) + { + if ((mat[j] & (1 << i)) != 0) + { + mat[j] ^= mat[i]; + inv[j] ^= inv[i]; + } + } + } + + /* Now the matrix is upper triangular. Start at the top and multiply down */ + + for (i = rows - 1; i >= 0; i--) + { + for (j = 0; j < i; j++) + { + if ((mat[j] & (1 << i)) != 0) + { + /* mat[j] ^= mat[i]; */ + inv[j] ^= inv[i]; + } + } + } + } +#endif + + static unsafe Crc32() + { + table = new uint[256]; + for (uint i = 0; i < table.Length; i++) + { + table[i] = Reflect(i, 8) << 24; + for (int j = 0; j < 8; j++) + table[i] = (table[i] << 1) ^ ((table[i] & (1U << 31)) == 0 ? 0 : uPolynomial); + table[i] = Reflect(table[i], 32); + } + combineTable = new uint[GF2_DIM, GF2_DIM]; + substractTable = new uint[GF2_DIM, GF2_DIM]; + combineTable[0, 0] = uReversePolynomial; + substractTable[0, 31] = uReversePolynomial2; + for (int n = 1; n < GF2_DIM; n++) + { + combineTable[0, n] = 1U << (n - 1); + substractTable[0, n - 1] = 1U << n; + } + fixed (uint* ct = &combineTable[0, 0], st = &substractTable[0, 0]) + { + //for (int i = 0; i < GF2_DIM; i++) + // st[32 + i] = ct[i]; + //invert_binary_matrix(st + 32, st, GF2_DIM); + + for (int i = 1; i < GF2_DIM; i++) + { + gf2_matrix_square(ct + i * 32, ct + (i - 1) * 32); + gf2_matrix_square(st + i * 32, st + (i - 1) * 32); + } + } + } + + const int GF2_DIM = 32; + //const int GF2_DIM2 = 67; + + private static unsafe uint gf2_matrix_times(uint* umat, uint uvec) + { + int vec = (int)uvec; + int* mat = (int*)umat; + return (uint)( + (*(mat++) & ((vec << 31) >> 31)) ^ + (*(mat++) & ((vec << 30) >> 31)) ^ + (*(mat++) & ((vec << 29) >> 31)) ^ + (*(mat++) & ((vec << 28) >> 31)) ^ + (*(mat++) & ((vec << 27) >> 31)) ^ + (*(mat++) & ((vec << 26) >> 31)) ^ + (*(mat++) & ((vec << 25) >> 31)) ^ + (*(mat++) & ((vec << 24) >> 31)) ^ + (*(mat++) & ((vec << 23) >> 31)) ^ + (*(mat++) & ((vec << 22) >> 31)) ^ + (*(mat++) & ((vec << 21) >> 31)) ^ + (*(mat++) & ((vec << 20) >> 31)) ^ + (*(mat++) & ((vec << 19) >> 31)) ^ + (*(mat++) & ((vec << 18) >> 31)) ^ + (*(mat++) & ((vec << 17) >> 31)) ^ + (*(mat++) & ((vec << 16) >> 31)) ^ + (*(mat++) & ((vec << 15) >> 31)) ^ + (*(mat++) & ((vec << 14) >> 31)) ^ + (*(mat++) & ((vec << 13) >> 31)) ^ + (*(mat++) & ((vec << 12) >> 31)) ^ + (*(mat++) & ((vec << 11) >> 31)) ^ + (*(mat++) & ((vec << 10) >> 31)) ^ + (*(mat++) & ((vec << 09) >> 31)) ^ + (*(mat++) & ((vec << 08) >> 31)) ^ + (*(mat++) & ((vec << 07) >> 31)) ^ + (*(mat++) & ((vec << 06) >> 31)) ^ + (*(mat++) & ((vec << 05) >> 31)) ^ + (*(mat++) & ((vec << 04) >> 31)) ^ + (*(mat++) & ((vec << 03) >> 31)) ^ + (*(mat++) & ((vec << 02) >> 31)) ^ + (*(mat++) & ((vec << 01) >> 31)) ^ + (*(mat++) & (vec >> 31))); + } + + /* ========================================================================= */ + private static unsafe void gf2_matrix_square(uint *square, uint *mat) + { + for (int n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); + } + + public static unsafe uint Combine(uint crc1, uint crc2, long len2) + { + /* degenerate case */ + if (len2 == 0) + return crc1; + if (crc1 == 0) + return crc2; + if (len2 < 0) + throw new ArgumentException("crc.Combine length cannot be negative", "len2"); + + fixed (uint* ct = &combineTable[0, 0]) + { + int n = 3; + do + { + /* apply zeros operator for this bit of len2 */ + if ((len2 & 1) != 0) + crc1 = gf2_matrix_times(ct + 32 * n, crc1); + len2 >>= 1; + n = (n + 1) & (GF2_DIM - 1); + /* if no more bits set, then done */ + } while (len2 != 0); + } + + /* return combined crc */ + crc1 ^= crc2; + return crc1; + } + + public static unsafe uint Subtract(uint crc1, uint crc2, long len2) + { + /* degenerate case */ + if (len2 == 0) + return crc1; + if (len2 < 0) + throw new ArgumentException("crc.Combine length cannot be negative", "len2"); + + crc1 ^= crc2; + + fixed (uint* st = &substractTable[0, 0]) + { + int n = 3; + do + { + /* apply zeros operator for this bit of len2 */ + if ((len2 & 1) != 0) + crc1 = gf2_matrix_times(st + 32 * n, crc1); + len2 >>= 1; + n = (n + 1) & (GF2_DIM - 1); + /* if no more bits set, then done */ + } while (len2 != 0); + } + + /* return combined crc */ + return crc1; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC8.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC8.cs new file mode 100644 index 000000000..2b2914d0b --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CRC/CRC8.cs @@ -0,0 +1,43 @@ +namespace CUETools.Codecs +{ + public class Crc8 + { + private const ushort poly8 = 0x07; + + private ushort[] table = new ushort[256]; + + public Crc8() + { + int bits = 8; + ushort poly = (ushort) (poly8 + (1U << bits)); + for (ushort i = 0; i < table.Length; i++) + { + ushort crc = i; + for (int j = 0; j < bits; j++) + { + if ((crc & (1U << (bits - 1))) != 0) + crc = (ushort)((crc << 1) ^ poly); + else + crc <<= 1; + } + table[i] = (ushort)(crc & 0x00ff); + } + } + + public byte ComputeChecksum(byte[] bytes, int pos, int count) + { + ushort crc = 0; + for (int i = pos; i < pos + count; i++) + crc = table[crc ^ bytes[i]]; + return (byte)crc; + } + + public unsafe byte ComputeChecksum(byte* bytes, int pos, int count) + { + ushort crc = 0; + for (int i = pos; i < pos + count; i++) + crc = table[crc ^ bytes[i]]; + return (byte)crc; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CUETools.Codecs.csproj b/Aaru.Compression/cuetools.net/CUETools.Codecs/CUETools.Codecs.csproj new file mode 100644 index 000000000..a7491076c --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CUETools.Codecs.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.0 + 2.1.9.0 + CUETools.Codecs + CUETools.Codecs + CUETools + A library for encoding and decoding audio. + Copyright (c) 2008-2021 Grigory Chudov + Grigory Chudov + true + ..\bin\$(Configuration)\ + https://github.com/gchudov/cuetools.net + git + + + + + + + + diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CUEToolsCodecsConfig.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CUEToolsCodecsConfig.cs new file mode 100644 index 000000000..108d886b8 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CUEToolsCodecsConfig.cs @@ -0,0 +1,296 @@ +using System; +using System.Collections.Generic; +using CUETools.Codecs.CommandLine; +using Newtonsoft.Json; + +namespace CUETools.Codecs; + +public class CUEToolsCodecsConfig +{ + public List decoders; + [JsonIgnore] + public DecoderListViewModel decodersViewModel; + public List encoders; + [JsonIgnore] + public EncoderListViewModel encodersViewModel; + [JsonIgnore] + public Dictionary formats; + + public CUEToolsCodecsConfig() + { + encoders = []; + decoders = []; + encodersViewModel = new EncoderListViewModel(encoders); + decodersViewModel = new DecoderListViewModel(decoders); + formats = new Dictionary(); + } + + public CUEToolsCodecsConfig(CUEToolsCodecsConfig src) + { + encoders = []; + decoders = []; + src.encoders.ForEach(item => encoders.Add(item.Clone())); + src.decoders.ForEach(item => decoders.Add(item.Clone())); + encodersViewModel = new EncoderListViewModel(encoders); + decodersViewModel = new DecoderListViewModel(decoders); + formats = new Dictionary(); + foreach(KeyValuePair fmt in src.formats) formats.Add(fmt.Key, fmt.Value.Clone(this)); + } + + public void Init(List src_encoders, List src_decoders) + { + encoders = []; + decoders = []; + src_encoders.ForEach(item => encoders.Add(item.Clone())); + src_decoders.ForEach(item => decoders.Add(item.Clone())); + + if(Type.GetType("Mono.Runtime", false) == null) + { + encoders.Add(new EncoderSettings("flake.exe", + "flac", + true, + "0 1 2 3 4 5 6 7 8 9 10 11 12", + "8", + "flake.exe", + "-%M - -o %O -p %P")); + + encoders.Add(new EncoderSettings("takc.exe", + "tak", + true, + "0 1 2 2e 2m 3 3e 3m 4 4e 4m", + "2", + "takc.exe", + "-e -p%M -overwrite - %O")); + + encoders.Add(new EncoderSettings("ffmpeg.exe", + "m4a", + true, + "", + "", + "ffmpeg.exe", + "-i - -f ipod -acodec alac -y %O")); + + encoders.Add(new EncoderSettings("lame.exe (VBR)", + "mp3", + false, + "V9 V8 V7 V6 V5 V4 V3 V2 V1 V0", + "V2", + "lame.exe", + "--vbr-new -%M - %O")); + + encoders.Add(new EncoderSettings("lame.exe (CBR)", + "mp3", + false, + "96 128 192 256 320", + "256", + "lame.exe", + "-m s -q 0 -b %M --noreplaygain - %O")); + + encoders.Add(new EncoderSettings("oggenc.exe", + "ogg", + false, + "-1 -0.5 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8", + "3", + "oggenc.exe", + "-q %M - -o %O")); + + encoders.Add(new EncoderSettings("opusenc.exe", + "opus", + false, + "6 16 32 48 64 96 128 192 256", + "128", + "opusenc.exe", + "--bitrate %M - %O")); + + encoders.Add(new EncoderSettings("neroAacEnc.exe", + "m4a", + false, + "0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9", + "0.4", + "neroAacEnc.exe", + "-q %M -if - -of %O")); + + encoders.Add(new EncoderSettings("qaac.exe (tvbr)", + "m4a", + false, + "10 20 30 40 50 60 70 80 90 100 110 127", + "80", + "qaac.exe", + "-s -V %M -q 2 - -o %O")); + + decoders.Add(new DecoderSettings("takc.exe", "tak", "takc.exe", "-d %I -")); + decoders.Add(new DecoderSettings("ffmpeg.exe", "m4a", "ffmpeg.exe", "-v 0 -i %I -f wav -")); + } + + // !!! + encodersViewModel = new EncoderListViewModel(encoders); + decodersViewModel = new DecoderListViewModel(decoders); + + formats = new Dictionary(); + + formats.Add("flac", + new CUEToolsFormat("flac", + CUEToolsTagger.TagLibSharp, + true, + false, + true, + true, + encodersViewModel.GetDefault("flac", true), + null, + decodersViewModel.GetDefault("flac"))); + + formats.Add("wv", + new CUEToolsFormat("wv", + CUEToolsTagger.TagLibSharp, + true, + false, + true, + true, + encodersViewModel.GetDefault("wv", true), + null, + decodersViewModel.GetDefault("wv"))); + + formats.Add("ape", + new CUEToolsFormat("ape", + CUEToolsTagger.TagLibSharp, + true, + false, + true, + true, + encodersViewModel.GetDefault("ape", true), + null, + decodersViewModel.GetDefault("ape"))); + + formats.Add("tta", + new CUEToolsFormat("tta", + CUEToolsTagger.APEv2, + true, + false, + false, + true, + encodersViewModel.GetDefault("tta", true), + null, + decodersViewModel.GetDefault("tta"))); + + formats.Add("m2ts", + new CUEToolsFormat("m2ts", + CUEToolsTagger.APEv2, + true, + false, + false, + true, + null, + null, + decodersViewModel.GetDefault("m2ts"))); + + formats.Add("mpls", + new CUEToolsFormat("mpls", + CUEToolsTagger.APEv2, + true, + false, + false, + true, + null, + null, + decodersViewModel.GetDefault("mpls"))); + + formats.Add("wav", + new CUEToolsFormat("wav", + CUEToolsTagger.TagLibSharp, + true, + false, + false, + true, + encodersViewModel.GetDefault("wav", true), + null, + decodersViewModel.GetDefault("wav"))); + + formats.Add("m4a", + new CUEToolsFormat("m4a", + CUEToolsTagger.TagLibSharp, + true, + true, + false, + true, + encodersViewModel.GetDefault("m4a", true), + encodersViewModel.GetDefault("m4a", false), + decodersViewModel.GetDefault("m4a"))); + + formats.Add("tak", + new CUEToolsFormat("tak", + CUEToolsTagger.APEv2, + true, + false, + true, + true, + encodersViewModel.GetDefault("tak", true), + null, + decodersViewModel.GetDefault("tak"))); + + formats.Add("wma", + new CUEToolsFormat("wma", + CUEToolsTagger.TagLibSharp, + true, + true, + false, + true, + encodersViewModel.GetDefault("wma", true), + encodersViewModel.GetDefault("wma", false), + decodersViewModel.GetDefault("wma"))); + + formats.Add("mp3", + new CUEToolsFormat("mp3", + CUEToolsTagger.TagLibSharp, + false, + true, + false, + true, + null, + encodersViewModel.GetDefault("mp3", false), + null)); + + formats.Add("ogg", + new CUEToolsFormat("ogg", + CUEToolsTagger.TagLibSharp, + false, + true, + false, + true, + null, + encodersViewModel.GetDefault("ogg", false), + null)); + + formats.Add("opus", + new CUEToolsFormat("opus", + CUEToolsTagger.TagLibSharp, + false, + true, + false, + true, + null, + encodersViewModel.GetDefault("opus", false), + null)); + + formats.Add("mlp", + new CUEToolsFormat("mlp", + CUEToolsTagger.APEv2, + true, + false, + false, + false, + null, + null, + decodersViewModel.GetDefault("mlp"))); + + formats.Add("aob", + new CUEToolsFormat("aob", + CUEToolsTagger.APEv2, + true, + false, + false, + false, + null, + null, + decodersViewModel.GetDefault("aob"))); + } +} \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CUEToolsFormat.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CUEToolsFormat.cs new file mode 100644 index 000000000..b42cf9b30 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CUEToolsFormat.cs @@ -0,0 +1,55 @@ +namespace CUETools.Codecs +{ + public class CUEToolsFormat + { + public CUEToolsFormat( + string _extension, + CUEToolsTagger _tagger, + bool _allowLossless, + bool _allowLossy, + bool _allowEmbed, + bool _builtin, + AudioEncoderSettingsViewModel _encoderLossless, + AudioEncoderSettingsViewModel _encoderLossy, + AudioDecoderSettingsViewModel _decoder) + { + extension = _extension; + tagger = _tagger; + allowLossless = _allowLossless; + allowLossy = _allowLossy; + allowEmbed = _allowEmbed; + builtin = _builtin; + encoderLossless = _encoderLossless; + encoderLossy = _encoderLossy; + decoder = _decoder; + } + public string DotExtension + { + get + { + return "." + extension; + } + } + + public CUEToolsFormat Clone(CUEToolsCodecsConfig cfg) + { + var res = this.MemberwiseClone() as CUEToolsFormat; + if (decoder != null) cfg.decodersViewModel.TryGetValue(decoder.Settings.Extension, decoder.Settings.Name, out res.decoder); + if (encoderLossy != null) cfg.encodersViewModel.TryGetValue(encoderLossy.Settings.Extension, encoderLossy.Lossless, encoderLossy.Settings.Name, out res.encoderLossy); + if (encoderLossless != null) cfg.encodersViewModel.TryGetValue(encoderLossless.Settings.Extension, encoderLossless.Lossless, encoderLossless.Settings.Name, out res.encoderLossless); + return res; + } + + public override string ToString() + { + return extension; + } + + public string extension; + public AudioEncoderSettingsViewModel encoderLossless; + public AudioEncoderSettingsViewModel encoderLossy; + public AudioDecoderSettingsViewModel decoder; + public CUEToolsTagger tagger; + public bool allowLossless, allowLossy, allowEmbed, builtin; + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CUEToolsTagger.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CUEToolsTagger.cs new file mode 100644 index 000000000..d0354bf3b --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CUEToolsTagger.cs @@ -0,0 +1,9 @@ +namespace CUETools.Codecs +{ + public enum CUEToolsTagger + { + TagLibSharp = 0, + APEv2 = 1, + ID3v2 = 2, + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/AudioDecoder.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/AudioDecoder.cs new file mode 100644 index 000000000..91ea5c186 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/AudioDecoder.cs @@ -0,0 +1,121 @@ +using System; +using System.Diagnostics; +using System.IO; + +namespace CUETools.Codecs.CommandLine +{ + public class AudioDecoder : IAudioSource + { + string _path; + Process _decoderProcess; + WAV.AudioDecoder rdr; + + private DecoderSettings m_settings; + public IAudioDecoderSettings Settings => m_settings; + + public long Position + { + get + { + Initialize(); + return rdr.Position; + } + set + { + Initialize(); + rdr.Position = value; + } + } + + public TimeSpan Duration + { + get + { + Initialize(); + return rdr.Duration; + } + } + + public long Length + { + get + { + Initialize(); + return rdr.Length; + } + } + + public long Remaining + { + get + { + Initialize(); + return rdr.Remaining; + } + } + + public AudioPCMConfig PCM + { + get + { + Initialize(); + return rdr.PCM; + } + } + + public string Path { get { return _path; } } + + public AudioDecoder(DecoderSettings settings, string path, Stream IO) + { + m_settings = settings; + _path = path; + _decoderProcess = null; + rdr = null; + } + + void Initialize() + { + if (_decoderProcess != null) + return; + _decoderProcess = new Process(); + _decoderProcess.StartInfo.FileName = m_settings.Path; + _decoderProcess.StartInfo.Arguments = m_settings.Parameters.Replace("%I", "\"" + _path + "\""); + _decoderProcess.StartInfo.CreateNoWindow = true; + _decoderProcess.StartInfo.RedirectStandardOutput = true; + _decoderProcess.StartInfo.UseShellExecute = false; + bool started = false; + Exception ex = null; + try + { + started = _decoderProcess.Start(); + if (started) + _decoderProcess.PriorityClass = Process.GetCurrentProcess().PriorityClass; + } + catch (Exception _ex) + { + ex = _ex; + } + if (!started) + { + _decoderProcess = null; + throw new Exception(m_settings.Path + ": " + (ex == null ? "please check the path" : ex.Message)); + } + rdr = new WAV.AudioDecoder(new WAV.DecoderSettings(), _path, _decoderProcess.StandardOutput.BaseStream); + } + + public void Close() + { + if (rdr != null) + rdr.Close(); + if (_decoderProcess != null && !_decoderProcess.HasExited) + try { _decoderProcess.Kill(); _decoderProcess.WaitForExit(); } + catch { } + } + + public int Read(AudioBuffer buff, int maxLength) + { + Initialize(); + return rdr.Read(buff, maxLength); + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/AudioEncoder.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/AudioEncoder.cs new file mode 100644 index 000000000..24d23ad2d --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/AudioEncoder.cs @@ -0,0 +1,137 @@ +using System; +using System.Diagnostics; +using System.IO; + +namespace CUETools.Codecs.CommandLine +{ + public class AudioEncoder : IAudioDest + { + string _path; + Process _encoderProcess; + WAV.AudioEncoder wrt; + CyclicBuffer outputBuffer = null; + bool useTempFile = false; + string tempFile = null; + long _finalSampleCount = -1; + bool closed = false; + + public long Position + { + get + { + return wrt.Position; + } + } + + public long FinalSampleCount + { + set { _finalSampleCount = wrt.FinalSampleCount = value; } + } + + // !!!! Must not start the process in constructor, so that we can set CompressionLevel via Settings! + private EncoderSettings m_settings; + public IAudioEncoderSettings Settings => m_settings; + + public string Path { get { return _path; } } + + public AudioEncoder(EncoderSettings settings, string path, Stream IO = null) + { + m_settings = settings; + _path = path; + useTempFile = m_settings.Parameters.Contains("%I"); + tempFile = path + ".tmp.wav"; + + _encoderProcess = new Process(); + _encoderProcess.StartInfo.FileName = m_settings.Path; + _encoderProcess.StartInfo.Arguments = m_settings.Parameters.Replace("%O", "\"" + path + "\"").Replace("%M", m_settings.EncoderMode).Replace("%P", m_settings.Padding.ToString()).Replace("%I", "\"" + tempFile + "\""); + _encoderProcess.StartInfo.CreateNoWindow = true; + if (!useTempFile) + _encoderProcess.StartInfo.RedirectStandardInput = true; + _encoderProcess.StartInfo.UseShellExecute = false; + if (!m_settings.Parameters.Contains("%O")) + _encoderProcess.StartInfo.RedirectStandardOutput = true; + if (useTempFile) + { + wrt = new WAV.AudioEncoder(new WAV.EncoderSettings(settings.PCM), tempFile); + return; + } + bool started = false; + Exception ex = null; + try + { + started = _encoderProcess.Start(); + if (started) + _encoderProcess.PriorityClass = Process.GetCurrentProcess().PriorityClass; + } + catch (Exception _ex) + { + ex = _ex; + } + if (!started) + throw new Exception(m_settings.Path + ": " + (ex == null ? "please check the path" : ex.Message)); + if (_encoderProcess.StartInfo.RedirectStandardOutput) + { + Stream outputStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read); + outputBuffer = new CyclicBuffer(2 * 1024 * 1024, _encoderProcess.StandardOutput.BaseStream, outputStream); + } + Stream inputStream = new CyclicBufferOutputStream(_encoderProcess.StandardInput.BaseStream, 128 * 1024); + wrt = new WAV.AudioEncoder(new WAV.EncoderSettings(settings.PCM), path, inputStream); + } + + public void Close() + { + if (closed) + return; + closed = true; + wrt.Close(); + if (useTempFile && (_finalSampleCount < 0 || wrt.Position == _finalSampleCount)) + { + bool started = false; + Exception ex = null; + try + { + started = _encoderProcess.Start(); + if (started) + _encoderProcess.PriorityClass = Process.GetCurrentProcess().PriorityClass; + } + catch (Exception _ex) + { + ex = _ex; + } + if (!started) + throw new Exception(m_settings.Path + ": " + (ex == null ? "please check the path" : ex.Message)); + } + wrt = null; + if (!_encoderProcess.HasExited) + _encoderProcess.WaitForExit(); + if (useTempFile) + File.Delete(tempFile); + if (outputBuffer != null) + outputBuffer.Close(); + if (_encoderProcess.ExitCode != 0) + throw new Exception(String.Format("{0} returned error code {1}", m_settings.Path, _encoderProcess.ExitCode)); + } + + public void Delete() + { + Close(); + File.Delete(_path); + } + + public void Write(AudioBuffer buff) + { + try + { + wrt.Write(buff); + } + catch (IOException ex) + { + if (_encoderProcess.HasExited) + throw new IOException(string.Format("{0} has exited prematurely with code {1}", m_settings.Path, _encoderProcess.ExitCode), ex); + else + throw ex; + } + //_sampleLen += sampleCount; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/DecoderSettings.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/DecoderSettings.cs new file mode 100644 index 000000000..9bdba0d58 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/DecoderSettings.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using Newtonsoft.Json; + +namespace CUETools.Codecs.CommandLine +{ + [JsonObject(MemberSerialization.OptIn)] + public class DecoderSettings : IAudioDecoderSettings + { + #region IAudioDecoderSettings implementation + [DefaultValue("")] + [JsonProperty] + public string Name { get; set; } + + [DefaultValue("")] + [JsonProperty] + public string Extension { get; set; } + + [Browsable(false)] + public Type DecoderType => typeof(AudioDecoder); + + [Browsable(false)] + public int Priority => 2; + + public IAudioDecoderSettings Clone() + { + return MemberwiseClone() as IAudioDecoderSettings; + } + #endregion + + public DecoderSettings() + { + this.Init(); + } + + public DecoderSettings( + string name, + string extension, + string path, + string parameters) + : base() + { + Name = name; + Extension = extension; + Path = path; + Parameters = parameters; + } + + [DefaultValue("")] + [JsonProperty] + public string Path + { + get; + set; + } + + [DefaultValue("")] + [JsonProperty] + public string Parameters + { + get; + set; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/EncoderSettings.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/EncoderSettings.cs new file mode 100644 index 000000000..004e7bfb0 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CommandLine/EncoderSettings.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using Newtonsoft.Json; + +namespace CUETools.Codecs.CommandLine +{ + [JsonObject(MemberSerialization.OptIn)] + public class EncoderSettings : IAudioEncoderSettings + { + #region IAudioEncoderSettings implementation + [DefaultValue("")] + [JsonProperty] + public string Name { get; set; } + + [DefaultValue("")] + [JsonProperty] + public string Extension { get; set; } + + [Browsable(false)] + public Type EncoderType => typeof(AudioEncoder); + + [JsonProperty] + public bool Lossless { get; set; } + + [Browsable(false)] + public int Priority => 0; + + [DefaultValue("")] + [JsonProperty] + public string SupportedModes { get; set; } + + public string DefaultMode => EncoderMode; + + [Browsable(false)] + [DefaultValue("")] + [JsonProperty] + public string EncoderMode { get; set; } + + [Browsable(false)] + public AudioPCMConfig PCM { get; set; } + + [Browsable(false)] + public int BlockSize { get; set; } + + [Browsable(false)] + [DefaultValue(4096)] + public int Padding { get; set; } + + public IAudioEncoderSettings Clone() + { + return MemberwiseClone() as IAudioEncoderSettings; + } + #endregion + + public EncoderSettings() + { + this.Init(); + } + + public EncoderSettings( + string name, + string extension, + bool lossless, + string supportedModes, + string defaultMode, + string path, + string parameters + ) + { + this.Init(); + Name = name; + Extension = extension; + Lossless = lossless; + SupportedModes = supportedModes; + Path = path; + EncoderMode = defaultMode; + Parameters = parameters; + } + + [DefaultValue("")] + [JsonProperty] + public string Path + { + get; + set; + } + + [DefaultValue("")] + [JsonProperty] + public string Parameters + { + get; + set; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CyclicBuffer.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CyclicBuffer.cs new file mode 100644 index 000000000..5c68c2c89 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CyclicBuffer.cs @@ -0,0 +1,231 @@ +using System; +using System.IO; +using System.Threading; + +namespace CUETools.Codecs +{ + public class CyclicBuffer + { + private byte[] _buffer; + private int _size; + private int _start = 0; // moved only by Write + private int _end = 0; // moved only by Read + private bool _eof = false; + private Thread _readThread = null, _writeThread = null; + private Exception _ex = null; + + private int DataAvailable + { + get + { + return _end - _start; + } + } + + private int FreeSpace + { + get + { + return _size - DataAvailable; + } + } + + public CyclicBuffer(int len) + { + _size = len; + _buffer = new byte[len]; + } + + public CyclicBuffer(int len, Stream input, Stream output) + { + _size = len; + _buffer = new byte[len]; + ReadFrom(input); + WriteTo(output); + } + + public void ReadFrom(Stream input) + { + _readThread = new Thread(PumpRead); + _readThread.Priority = ThreadPriority.Highest; + _readThread.IsBackground = true; + _readThread.Start(input); + } + + public void WriteTo(Stream output) + { + WriteTo(flushOutputToStream, closeOutputToStream, ThreadPriority.Highest, output); + } + + public void WriteTo(FlushOutput flushOutputDelegate, CloseOutput closeOutputDelegate, ThreadPriority priority, object to) + { + if (flushOutputDelegate != null) + flushOutput += flushOutputDelegate; + if (closeOutputDelegate != null) + closeOutput += closeOutputDelegate; + _writeThread = new Thread(FlushThread); + _writeThread.Priority = priority; + _writeThread.IsBackground = true; + _writeThread.Start(to); + } + + private void closeOutputToStream(object to) + { + ((Stream)to).Close(); + } + + private void flushOutputToStream(byte[] buffer, int pos, int chunk, object to) + { + ((Stream)to).Write(buffer, pos, chunk); + } + + private void PumpRead(object o) + { + while (Read((Stream)o)) + ; + SetEOF(); + } + + public void Close() + { + if (_readThread != null) + { + _readThread.Join(); + _readThread = null; + } + SetEOF(); + if (_writeThread != null) + { + _writeThread.Join(); + _writeThread = null; + } + } + + public void SetEOF() + { + lock (this) + { + _eof = true; + Monitor.Pulse(this); + } + } + + public bool Read(Stream input) + { + int pos, chunk; + lock (this) + { + while (FreeSpace == 0 && _ex == null) + Monitor.Wait(this); + if (_ex != null) + throw _ex; + pos = _end % _size; + chunk = Math.Min(FreeSpace, _size - pos); + } + chunk = input.Read(_buffer, pos, chunk); + if (chunk == 0) + return false; + lock (this) + { + _end += chunk; + Monitor.Pulse(this); + } + return true; + } + + public void Read(byte[] array, int offset, int count) + { + int pos, chunk; + while (count > 0) + { + lock (this) + { + while (FreeSpace == 0 && _ex == null) + Monitor.Wait(this); + if (_ex != null) + throw _ex; + pos = _end % _size; + chunk = Math.Min(FreeSpace, _size - pos); + chunk = Math.Min(chunk, count); + } + Array.Copy(array, offset, _buffer, pos, chunk); + lock (this) + { + _end += chunk; + Monitor.Pulse(this); + } + count -= chunk; + offset += chunk; + } + } + + public void Write(byte[] buff, int offs, int count) + { + while (count > 0) + { + int pos, chunk; + lock (this) + { + while (DataAvailable == 0 && !_eof) + Monitor.Wait(this); + if (DataAvailable == 0) + break; + pos = _start % _size; + chunk = Math.Min(DataAvailable, _size - pos); + } + if (flushOutput != null) + Array.Copy(_buffer, pos, buff, offs, chunk); + offs += chunk; + lock (this) + { + _start += chunk; + Monitor.Pulse(this); + } + } + } + + private void FlushThread(object to) + { + while (true) + { + int pos, chunk; + lock (this) + { + while (DataAvailable == 0 && !_eof) + Monitor.Wait(this); + if (DataAvailable == 0) + break; + pos = _start % _size; + chunk = Math.Min(DataAvailable, _size - pos); + } + if (flushOutput != null) + try + { + flushOutput(_buffer, pos, chunk, to); + } + catch (Exception ex) + { + lock (this) + { + _ex = ex; + Monitor.Pulse(this); + return; + } + } + lock (this) + { + _start += chunk; + Monitor.Pulse(this); + } + } + if (closeOutput != null) + closeOutput(to); + } + + public delegate void FlushOutput(byte[] buffer, int pos, int chunk, object to); + public delegate void CloseOutput(object to); + + public event FlushOutput flushOutput; + public event CloseOutput closeOutput; + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CyclicBufferInputStream.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CyclicBufferInputStream.cs new file mode 100644 index 000000000..05309a03e --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CyclicBufferInputStream.cs @@ -0,0 +1,75 @@ +using System; +using System.IO; + +namespace CUETools.Codecs +{ + public class CyclicBufferInputStream : Stream + { + private CyclicBuffer _buffer; + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override long Length + { + get + { + throw new NotSupportedException(); + } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public CyclicBufferInputStream(CyclicBuffer buffer) + { + _buffer = buffer; + } + + public override void Close() + { + _buffer.Close(); + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override int Read(byte[] array, int offset, int count) + { + _buffer.Write(array, offset, count); + return count; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] array, int offset, int count) + { + throw new NotSupportedException(); + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/CyclicBufferOutputStream.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/CyclicBufferOutputStream.cs new file mode 100644 index 000000000..4c18c0dd7 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/CyclicBufferOutputStream.cs @@ -0,0 +1,80 @@ +using System; +using System.IO; + +namespace CUETools.Codecs +{ + public class CyclicBufferOutputStream : Stream + { + private CyclicBuffer _buffer; + + public override bool CanRead + { + get { return false; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override long Length + { + get + { + throw new NotSupportedException(); + } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public CyclicBufferOutputStream(CyclicBuffer buffer) + { + _buffer = buffer; + } + + public CyclicBufferOutputStream(Stream output, int size) + { + _buffer = new CyclicBuffer(size); + _buffer.WriteTo(output); + } + + public override void Close() + { + _buffer.Close(); + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override int Read(byte[] array, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] array, int offset, int count) + { + _buffer.Read(array, offset, count); + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/DefaultValueForMode.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/DefaultValueForMode.cs new file mode 100644 index 000000000..f99c88679 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/DefaultValueForMode.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CUETools.Codecs +{ + /// + /// Default property value for each encoder mode attribute + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class DefaultValueForModeAttribute : Attribute + { + /// + /// Resource manager to use; + /// + public object[] m_values; + + /// + /// Construct the description attribute + /// + /// + public DefaultValueForModeAttribute(params object[] values) + { + this.m_values = values; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/IAudioDest.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/IAudioDest.cs new file mode 100644 index 000000000..018d27ae7 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/IAudioDest.cs @@ -0,0 +1,14 @@ +namespace CUETools.Codecs +{ + public interface IAudioDest + { + IAudioEncoderSettings Settings { get; } + + string Path { get; } + long FinalSampleCount { set; } + + void Write(AudioBuffer buffer); + void Close(); + void Delete(); + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/IAudioFilter.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/IAudioFilter.cs new file mode 100644 index 000000000..2f1eeceb4 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/IAudioFilter.cs @@ -0,0 +1,7 @@ +namespace CUETools.Codecs +{ + public interface IAudioFilter + { + IAudioDest AudioDest { set; } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/IAudioSource.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/IAudioSource.cs new file mode 100644 index 000000000..37481dd04 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/IAudioSource.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; + +namespace CUETools.Codecs; + +public interface IAudioSource +{ + IAudioDecoderSettings Settings { get; } + + AudioPCMConfig PCM { get; } + string Path { get; } + + TimeSpan Duration { get; } + long Length { get; } + long Position { get; set; } + long Remaining { get; } + + int Read(AudioBuffer buffer, int maxLength); + void Close(); +} + +public interface IAudioTitle +{ + List Chapters { get; } + AudioPCMConfig PCM { get; } + string Codec { get; } + string Language { get; } + int StreamId { get; } + + //IAudioSource Open { get; } +} + +public interface IAudioTitleSet +{ + List AudioTitles { get; } +} + +public static class IAudioTitleExtensions +{ + public static TimeSpan GetDuration(this IAudioTitle title) + { + List chapters = title.Chapters; + + return chapters[chapters.Count - 1]; + } + + + public static string GetRateString(this IAudioTitle title) + { + int sr = title.PCM.SampleRate; + + if(sr % 1000 == 0) return $"{sr / 1000}KHz"; + if(sr % 100 == 0) return $"{sr / 100}.{sr / 100 % 10}KHz"; + + return $"{sr}Hz"; + } + + public static string GetFormatString(this IAudioTitle title) + { + switch(title.PCM.ChannelCount) + { + case 1: + return "mono"; + case 2: + return "stereo"; + default: + return "multi-channel"; + } + } +} + +public class SingleAudioTitle : IAudioTitle +{ + readonly IAudioSource source; + public SingleAudioTitle(IAudioSource source) => this.source = source; + +#region IAudioTitle Members + + public List Chapters => [TimeSpan.Zero, source.Duration]; + public AudioPCMConfig PCM => source.PCM; + public string Codec => source.Settings.Extension; + public string Language => ""; + public int StreamId => 0; + +#endregion +} + +public class SingleAudioTitleSet : IAudioTitleSet +{ + readonly IAudioSource source; + public SingleAudioTitleSet(IAudioSource source) => this.source = source; + +#region IAudioTitleSet Members + + public List AudioTitles => [new SingleAudioTitle(source)]; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/IWavePlayer.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/IWavePlayer.cs new file mode 100644 index 000000000..6133d853c --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/IWavePlayer.cs @@ -0,0 +1,41 @@ +using System; + +namespace CUETools.Codecs +{ + /// + /// Represents the interface to a device that can play a WaveFile + /// + public interface IWavePlayer : IDisposable, IAudioDest + { + /// + /// Begin playback + /// + void Play(); + + /// + /// Stop playback + /// + void Stop(); + + /// + /// Pause Playback + /// + void Pause(); + + /// + /// Current playback state + /// + PlaybackState PlaybackState { get; } + + /// + /// The volume 1.0 is full scale + /// + float Volume { get; set; } + + /// + /// Indicates that playback has gone into a stopped state due to + /// reaching the end of the input stream + /// + event EventHandler PlaybackStopped; + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/LPC.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/LPC.cs new file mode 100644 index 000000000..90cc56d28 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/LPC.cs @@ -0,0 +1,1182 @@ +using System; + +namespace CUETools.Codecs +{ + public class lpc + { + public const int MAX_LPC_ORDER = 32; + public const int MAX_LPC_WINDOWS = 16; + public const int MAX_LPC_PRECISIONS = 4; + public const int MAX_LPC_SECTIONS = 128; + + public unsafe static void window_welch(float* window, int L) + { + int N = L - 1; + double N2 = (double)N / 2.0; + + for (int n = 0; n <= N; n++) + { + double k = ((double)n - N2) / N2; + k = 1.0 - k * k; + window[n] = (float)(k); + } + } + + public unsafe static void window_bartlett(float* window, int L) + { + int N = L - 1; + double N2 = (double)N / 2.0; + for (int n = 0; n <= N; n++) + { + double k = ((double)n - N2) / N2; + k = 1.0 - k * k; + window[n] = (float)(k * k); + } + } + + public unsafe static void window_rectangle(float* window, int L) + { + for (int n = 0; n < L; n++) + window[n] = 1.0F; + } + + public unsafe static void window_flattop(float* window, int L) + { + int N = L - 1; + for (int n = 0; n < L; n++) + window[n] = (float)(1.0 - 1.93 * Math.Cos(2.0 * Math.PI * n / N) + 1.29 * Math.Cos(4.0 * Math.PI * n / N) - 0.388 * Math.Cos(6.0 * Math.PI * n / N) + 0.0322 * Math.Cos(8.0 * Math.PI * n / N)); + } + + public unsafe static void window_tukey(float* window, int L, double p) + { + int z = 0; + int Np = (int)(p / 2.0 * L) - z; + if (Np > 0) + { + for (int n = 0; n < z; n++) + window[n] = window[L - n - 1] = 0; + for (int n = 0; n < Np - 1; n++) + window[n + z] = window[L - n - 1 - z] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * (n + 1) / Np)); + for (int n = z + Np - 1; n < L - z - Np + 1; n++) + window[n] = 1.0F; + } + } + + public unsafe static void window_punchout_tukey(float* window, int L, double p, double p1, double start, double end) + { + int start_n = (int)(start * L); + int end_n = (int)(end * L); + int Np = (int)(p / 2.0 * L); + int Np1 = (int)(p1 / 2.0 * L); + int i, n = 0; + + if (start_n != 0) + { + for (i = 1; n < Np; n++, i++) + window[n] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * i / Np)); + for (; n < start_n - Np1; n++) + window[n] = 1.0f; + for (i = Np1; n < start_n; n++, i--) + window[n] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * i / Np1)); + } + for (; n < end_n; n++) + window[n] = 0.0f; + if (end_n != L) + { + for (i = 1; n < end_n + Np1; n++, i++) + window[n] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * i / Np1)); + for (; n < L - Np; n++) + window[n] = 1.0f; + for (i = Np; n < L; n++, i--) + window[n] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * i / Np)); + } + } + + public unsafe static void window_hann(float* window, int L) + { + int N = L - 1; + for (int n = 0; n < L; n++) + window[n] = (float)(0.5 - 0.5 * Math.Cos(2.0 * Math.PI * n / N)); + } + + private static short sign_only(int val) + { + return (short)((val >> 31) + ((val - 1) >> 31) + 1); + } + +#if XXX + static public unsafe void + compute_corr_int(/*const*/ short* data1, short* data2, int len, int min, int lag, int* autoc) + { + for (int i = min; i <= lag; ++i) + { + int temp = 0; + int temp2 = 0; + + for (int j = 0; j <= lag - i; ++j) + temp += data1[j + i] * data2[j]; + + for (int j = lag + 1 - i; j < len - i; j += 2) + { + temp += data1[j + i] * data2[j]; + temp2 += data1[j + i + 1] * data2[j + 1]; + } + autoc[i] = temp + temp2; + } + } +#endif + + /** + * Calculates autocorrelation data from audio samples + * A window function is applied before calculation. + */ + static public unsafe void + compute_autocorr(/*const*/ int* data, float* window, int len, int min, int lag, double* autoc) + { +#if FPAC + short* data1 = stackalloc short[len + 1]; + short* data2 = stackalloc short[len + 1]; + int* c1 = stackalloc int[lpc.MAX_LPC_ORDER + 1]; + int* c2 = stackalloc int[lpc.MAX_LPC_ORDER + 1]; + int* c3 = stackalloc int[lpc.MAX_LPC_ORDER + 1]; + int* c4 = stackalloc int[lpc.MAX_LPC_ORDER + 1]; + + for (int i = 0; i < len; i++) + { + int val = (int)(data[i] * window[i]); + data1[i] = (short)(sign_only(val) * (Math.Abs(val) >> 9)); + data2[i] = (short)(sign_only(val) * (Math.Abs(val) & 0x1ff)); + } + data1[len] = 0; + data2[len] = 0; + + compute_corr_int(data1, data1, len, min, lag, c1); + compute_corr_int(data1, data2, len, min, lag, c2); + compute_corr_int(data2, data1, len, min, lag, c3); + compute_corr_int(data2, data2, len, min, lag, c4); + + for (int coeff = min; coeff <= lag; coeff++) + autoc[coeff] = (c1[coeff] * (double)(1 << 18) + (c2[coeff] + c3[coeff]) * (double)(1 << 9) + c4[coeff]); +#else +#if XXX + if (min == 0 && lag >= 4) + { + int* pdata = data; + float* pwindow = window; + + double temp0 = 1.0; + double temp1 = 1.0; + double temp2 = 1.0; + double temp3 = 1.0; + double temp4 = 1.0; + + double c0 = *(pdata++) * *(pwindow++); + float c1 = *(pdata++) * *(pwindow++); + float c2 = *(pdata++) * *(pwindow++); + float c3 = *(pdata++) * *(pwindow++); + float c4 = *(pdata++) * *(pwindow++); + + int* finish = data + len; + + while (pdata <= finish) + { + temp0 += c0 * c0; + temp1 += c0 * c1; + temp2 += c0 * c2; + temp3 += c0 * c3; + temp4 += c0 * c4; + + c0 = c1; + c1 = c2; + c2 = c3; + c3 = c4; + c4 = *(pdata++) * *(pwindow++); + } + + temp0 += c0 * c0; + temp1 += c0 * c1; + temp2 += c0 * c2; + temp3 += c0 * c3; + c0 = c1; + c1 = c2; + c2 = c3; + temp0 += c0 * c0; + temp1 += c0 * c1; + temp2 += c0 * c2; + c0 = c1; + c1 = c2; + temp0 += c0 * c0; + temp1 += c0 * c1; + c0 = c1; + temp0 += c0 * c0; + + autoc[0] += temp0; + autoc[1] += temp1; + autoc[2] += temp2; + autoc[3] += temp3; + autoc[4] += temp4; + min = 5; + + if (lag < min) return; + } +#endif + double* data1 = stackalloc double[len]; + int i; + + for (i = 0; i < len; i++) + data1[i] = data[i] * window[i]; + + for (i = min; i <= lag; ++i) + { + double temp = 0; + double temp2 = 0; + double* pdata = data1; + double* finish = data1 + len - 1 - i; + + while (pdata < finish) + { + temp += pdata[i] * (*pdata++); + temp2 += pdata[i] * (*pdata++); + } + if (pdata <= finish) + temp += pdata[i] * (*pdata++); + + autoc[i] += temp + temp2; + } +#endif + } + + static public unsafe void + compute_autocorr_windowless(/*const*/ int* data, int len, int min, int lag, double* autoc) + { + // if databits*2 + log2(len) <= 64 +#if !XXX +#if XXX + if (min == 0 && lag >= 4) + { + long temp0 = 0; + long temp1 = 0; + long temp2 = 0; + long temp3 = 0; + long temp4 = 0; + int* pdata = data; + int* finish = data + len - 4; + while (pdata < finish) + { + long c0 = *(pdata++); + temp0 += c0 * c0; + temp1 += c0 * pdata[0]; + temp2 += c0 * pdata[1]; + temp3 += c0 * pdata[2]; + temp4 += c0 * pdata[3]; + } + { + long c0 = *(pdata++); + temp0 += c0 * c0; + temp1 += c0 * pdata[0]; + temp2 += c0 * pdata[1]; + temp3 += c0 * pdata[2]; + } + { + long c0 = *(pdata++); + temp0 += c0 * c0; + temp1 += c0 * pdata[0]; + temp2 += c0 * pdata[1]; + } + { + long c0 = *(pdata++); + temp0 += c0 * c0; + temp1 += c0 * pdata[0]; + } + { + long c0 = *(pdata++); + temp0 += c0 * c0; + } + autoc[0] += temp0; + autoc[1] += temp1; + autoc[2] += temp2; + autoc[3] += temp3; + autoc[4] += temp4; + min = 5; + + if (lag < min) return; + } +#endif + for (int i = min; i <= lag; ++i) + { + long temp = 0; + long temp2 = 0; + int* pdata = data; + int* finish = data + len - i - 1; + while (pdata < finish) + { + temp += (long)pdata[i] * (*pdata++); + temp2 += (long)pdata[i] * (*pdata++); + } + if (pdata <= finish) + temp += (long)pdata[i] * (*pdata++); + autoc[i] += temp + temp2; + } +#else + for (int i = min; i <= lag; ++i) + { + double temp = 0; + double temp2 = 0; + int* pdata = data; + int* finish = data + len - i - 1; + + while (pdata < finish) + { + temp += (double)pdata[i] * (double)(*pdata++); + temp2 += (double)pdata[i] * (double)(*pdata++); + } + if (pdata <= finish) + temp += (double)pdata[i] * (double)(*pdata++); + autoc[i] += temp + temp2; + } +#endif + } + + static public unsafe void + compute_autocorr_windowless_large(/*const*/ int* data, int len, int min, int lag, double* autoc) + { + for (int i = min; i <= lag; ++i) + { + double temp = 0; + double temp2 = 0; + int* pdata = data; + int* finish = data + len - i - 1; + while (pdata < finish) + { + temp += (long)pdata[i] * (*pdata++); + temp2 += (long)pdata[i] * (*pdata++); + } + if (pdata <= finish) + temp += (long)pdata[i] * (*pdata++); + autoc[i] += temp + temp2; + } + } + + static public unsafe void + compute_autocorr_glue(/*const*/ int* data, float* window, int offs, int offs1, int min, int lag, double* autoc) + { + double* data1 = stackalloc double[lag + lag]; + for (int i = -lag; i < lag; i++) + data1[i + lag] = offs + i >= 0 && offs + i < offs1 ? data[offs + i] * window[offs + i] : 0; + for (int i = min; i <= lag; ++i) + { + double temp = 0; + double* pdata = data1 + lag - i; + double* finish = data1 + lag; + while (pdata < finish) + temp += pdata[i] * (*pdata++); + autoc[i] += temp; + } + } + + static public unsafe void + compute_autocorr_glue(/*const*/ int* data, int min, int lag, double* autoc) + { + for (int i = min; i <= lag; ++i) + { + long temp = 0; + int* pdata = data - i; + int* finish = data; + while (pdata < finish) + temp += (long)pdata[i] * (*pdata++); + autoc[i] += temp; + } + } + + /** + * Levinson-Durbin recursion. + * Produces LPC coefficients from autocorrelation data. + */ + public static unsafe void + compute_lpc_coefs(uint max_order, double* reff, float* lpc/*[][MAX_LPC_ORDER]*/) + { + double* lpc_tmp = stackalloc double[MAX_LPC_ORDER]; + + if (max_order > MAX_LPC_ORDER) + throw new Exception("weird"); + + for (int i = 0; i < max_order; i++) + lpc_tmp[i] = 0; + + for (int i = 0; i < max_order; i++) + { + double r = reff[i]; + int i2 = (i >> 1); + lpc_tmp[i] = r; + for (int j = 0; j < i2; j++) + { + double tmp = lpc_tmp[j]; + lpc_tmp[j] += r * lpc_tmp[i - 1 - j]; + lpc_tmp[i - 1 - j] += r * tmp; + } + + if (0 != (i & 1)) + lpc_tmp[i2] += lpc_tmp[i2] * r; + + for (int j = 0; j <= i; j++) + lpc[i * MAX_LPC_ORDER + j] = (float)-lpc_tmp[j]; + } + } + + public static unsafe void + compute_schur_reflection(/*const*/ double* autoc, uint max_order, + double* reff/*[][MAX_LPC_ORDER]*/, double * err) + { + double* gen0 = stackalloc double[MAX_LPC_ORDER]; + double* gen1 = stackalloc double[MAX_LPC_ORDER]; + + // Schur recursion + for (uint i = 0; i < max_order; i++) + gen0[i] = gen1[i] = autoc[i + 1]; + + double error = autoc[0]; + reff[0] = -gen1[0] / error; + error += gen1[0] * reff[0]; + err[0] = error; + for (uint i = 1; i < max_order; i++) + { + for (uint j = 0; j < max_order - i; j++) + { + gen1[j] = gen1[j + 1] + reff[i - 1] * gen0[j]; + gen0[j] = gen1[j + 1] * reff[i - 1] + gen0[j]; + } + reff[i] = -gen1[0] / error; + error += gen1[0] * reff[i]; + err[i] = error; + } + } + + /** + * Quantize LPC coefficients + */ + public static unsafe void + quantize_lpc_coefs(float* lpc_in, int order, uint precision, int* lpc_out, + out int shift, int max_shift, int zero_shift) + { + int i; + float d, cmax, error; + int qmax; + int sh, q; + + // define maximum levels + qmax = (1 << ((int)precision - 1)) - 1; + + // find maximum coefficient value + cmax = 0.0F; + for (i = 0; i < order; i++) + { + d = Math.Abs(lpc_in[i]); + if (d > cmax) + cmax = d; + } + // if maximum value quantizes to zero, return all zeros + if (cmax * (1 << max_shift) < 1.0) + { + shift = zero_shift; + for (i = 0; i < order; i++) + lpc_out[i] = 0; + return; + } + + // calculate level shift which scales max coeff to available bits + sh = max_shift; + while ((cmax * (1 << sh) > qmax) && (sh > 0)) + { + sh--; + } + + // since negative shift values are unsupported in decoder, scale down + // coefficients instead + if (sh == 0 && cmax > qmax) + { + float scale = ((float)qmax) / cmax; + for (i = 0; i < order; i++) + { + lpc_in[i] *= scale; + } + } + + // output quantized coefficients and level shift + error = 0; + for (i = 0; i < order; i++) + { + error += lpc_in[i] * (1 << sh); + q = (int)(error + 0.5); + if (q < -(qmax+1)) q = -(qmax + 1); + if (q > qmax) q = qmax; + error -= q; + lpc_out[i] = q; + } + shift = sh; + } + + private static unsafe ulong + encode_residual_partition(int* s, int* r, int* seg_end, int* coefs, int shift, int order) + { + ulong sum = 0ul; + int c0 = coefs[0]; + int c1 = coefs[1]; + switch (order) + { + case 1: + while (s < seg_end) + { + int pred = c0 * *(s++); + //*(r++) = *s - (pred >> shift); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + } + break; + case 2: + while (s < seg_end) + { + int pred = c1 * *(s++); + pred += c0 * *(s++); + int d = *(r++) = *(s--) - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + } + break; + case 3: + while (s < seg_end) + { + int pred = coefs[2] * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 2; + } + break; + case 4: + while (s < seg_end) + { + int* c = coefs + order - 1; + int pred = + *(c--) * *(s++) + *(c--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 3; + } + break; + case 5: + while (s < seg_end) + { + int* c = coefs + order - 1; + int pred = + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 4; + } + break; + case 6: + while (s < seg_end) + { + int* c = coefs + order - 1; + int pred = + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 5; + } + break; + case 7: + while (s < seg_end) + { + int* c = coefs + order - 1; + int pred = + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 6; + } + break; + case 8: + while (s < seg_end) + { + int* c = coefs + order - 1; + int pred = + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 7; + } + break; + case 9: + while (s < seg_end) + { + int* c = coefs + order - 1; + int pred = + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 8; + } + break; + case 10: + while (s < seg_end) + { + int* c = coefs + order - 1; + int pred = + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 9; + } + break; + case 11: + while (s < seg_end) + { + int* c = coefs + order - 1; + int pred = + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 10; + } + break; + case 12: + while (s < seg_end) + { + int* c = coefs + order - 1; + int pred = + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 11; + } + break; + default: + while (s < seg_end) + { + int pred = 0; + int* c = coefs + order - 1; + int* c11 = coefs + 11; + while (c > c11) + pred += *(c--) * *(s++); + pred += + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + *(c--) * *(s++) + *(c--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + int d = *(r++) = *s - (pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= order - 1; + } + break; + } + return sum; + } + + public static unsafe void + encode_residual(int* res, int* smp, int n, int order, + int* coefs, int shift, ulong* sums, int pmax) + { + for (int i = 0; i < order; i++) + res[i] = smp[i]; + + int* s = smp; + int* s_end = smp + n - order; + int* seg_end = s + (n >> pmax) - order; + int* r = res + order; + while (s < s_end) + { + *(sums++) = encode_residual_partition(s, r, seg_end, coefs, shift, order); + r += seg_end - s; + s = seg_end; + seg_end += n >> pmax; + } + } + + private static unsafe ulong + encode_residual_long_partition(int* s, int* r, int* seg_end, int* coefs, int shift, int order) + { + ulong sum = 0ul; + int c0 = coefs[0]; + int c1 = coefs[1]; + switch (order) + { + case 1: + while (s < seg_end) + { + long pred = c0 * (long)*(s++); + int d = *(r++) = *s - (int)(pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + } + break; + case 2: + while (s < seg_end) + { + long pred = c1 * (long)*(s++); + pred += c0 * (long)*(s++); + int d = *(r++) = *(s--) - (int)(pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + } + break; + case 3: + while (s < seg_end) + { + long pred = coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + int d = *(r++) = *s - (int)(pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 2; + } + break; + case 4: + while (s < seg_end) + { + long pred = coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + int d = *(r++) = *s - (int)(pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 3; + } + break; + case 5: + while (s < seg_end) + { + long pred = coefs[4] * (long)*(s++); + pred += coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + int d = *(r++) = *s - (int)(pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 4; + } + break; + case 6: + while (s < seg_end) + { + long pred = coefs[5] * (long)*(s++); + pred += coefs[4] * (long)*(s++); + pred += coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + int d = *(r++) = *s - (int)(pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 5; + } + break; + case 7: + while (s < seg_end) + { + long pred = coefs[6] * (long)*(s++); + pred += coefs[5] * (long)*(s++); + pred += coefs[4] * (long)*(s++); + pred += coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + int d = *(r++) = *s - (int)(pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 6; + } + break; + case 8: + while (s < seg_end) + { + long pred = coefs[7] * (long)*(s++); + pred += coefs[6] * (long)*(s++); + pred += coefs[5] * (long)*(s++); + pred += coefs[4] * (long)*(s++); + pred += coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + int d = *(r++) = *s - (int)(pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= 7; + } + break; + default: + while (s < seg_end) + { + long pred = 0; + int* co = coefs + order - 1; + int* c7 = coefs + 7; + while (co > c7) + pred += *(co--) * (long)*(s++); + pred += coefs[7] * (long)*(s++); + pred += coefs[6] * (long)*(s++); + pred += coefs[5] * (long)*(s++); + pred += coefs[4] * (long)*(s++); + pred += coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + int d = *(r++) = *s - (int)(pred >> shift); + sum += (uint)((d << 1) ^ (d >> 31)); + s -= order - 1; + } + break; + } + return sum; + } + + public static unsafe void + encode_residual_long(int* res, int* smp, int n, int order, + int* coefs, int shift, ulong* sums, int pmax) + { + for (int i = 0; i < order; i++) + res[i] = smp[i]; + + int* s = smp; + int* s_end = smp + n - order; + int* seg_end = s + (n >> pmax) - order; + int* r = res + order; + while (s < s_end) + { + *(sums++) = encode_residual_long_partition(s, r, seg_end, coefs, shift, order); + r += seg_end - s; + s = seg_end; + seg_end += n >> pmax; + } + } + + public static unsafe void + decode_residual(int* res, int* smp, int n, int order, + int* coefs, int shift) + { + for (int i = 0; i < order; i++) + smp[i] = res[i]; + + int* s = smp; + int* r = res + order; + int c0 = coefs[0]; + int c1 = coefs[1]; + switch (order) + { + case 1: + for (int i = n - order; i > 0; i--) + { + int pred = c0 * *(s++); + *s = *(r++) + (pred >> shift); + } + break; + case 2: + for (int i = n - order; i > 0; i--) + { + int pred = c1 * *(s++) + c0 * *(s++); + *(s--) = *(r++) + (pred >> shift); + } + break; + case 3: + for (int i = n - order; i > 0; i--) + { + int* co = coefs + order - 1; + int pred = + *(co--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + *s = *(r++) + (pred >> shift); + s -= 2; + } + break; + case 4: + for (int i = n - order; i > 0; i--) + { + int* co = coefs + order - 1; + int pred = + *(co--) * *(s++) + *(co--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + *s = *(r++) + (pred >> shift); + s -= 3; + } + break; + case 5: + for (int i = n - order; i > 0; i--) + { + int* co = coefs + order - 1; + int pred = + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + *s = *(r++) + (pred >> shift); + s -= 4; + } + break; + case 6: + for (int i = n - order; i > 0; i--) + { + int* co = coefs + order - 1; + int pred = + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + *s = *(r++) + (pred >> shift); + s -= 5; + } + break; + case 7: + for (int i = n - order; i > 0; i--) + { + int* co = coefs + order - 1; + int pred = + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + *s = *(r++) + (pred >> shift); + s -= 6; + } + break; + case 8: + for (int i = n - order; i > 0; i--) + { + int* co = coefs + order - 1; + int pred = + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + *s = *(r++) + (pred >> shift); + s -= 7; + } + break; + case 9: + for (int i = n - order; i > 0; i--) + { + int* co = coefs + order - 1; + int pred = + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + *s = *(r++) + (pred >> shift); + s -= 8; + } + break; + case 10: + for (int i = n - order; i > 0; i--) + { + int* co = coefs + order - 1; + int pred = + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + *s = *(r++) + (pred >> shift); + s -= 9; + } + break; + case 11: + for (int i = n - order; i > 0; i--) + { + int* co = coefs + order - 1; + int pred = + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + *s = *(r++) + (pred >> shift); + s -= 10; + } + break; + case 12: + for (int i = n - order; i > 0; i--) + { + int* co = coefs + order - 1; + int pred = + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + *(co--) * *(s++) + *(co--) * *(s++) + + c1 * *(s++) + c0 * *(s++); + *s = *(r++) + (pred >> shift); + s -= 11; + } + break; + default: + for (int i = order; i < n; i++) + { + s = smp + i - order; + int pred = 0; + int* co = coefs + order - 1; + int* c7 = coefs + 7; + while (co > c7) + pred += *(co--) * *(s++); + pred += coefs[7] * *(s++); + pred += coefs[6] * *(s++); + pred += coefs[5] * *(s++); + pred += coefs[4] * *(s++); + pred += coefs[3] * *(s++); + pred += coefs[2] * *(s++); + pred += c1 * *(s++); + pred += c0 * *(s++); + *s = *(r++) + (pred >> shift); + } + break; + } + } + public static unsafe void + decode_residual_long(int* res, int* smp, int n, int order, + int* coefs, int shift) + { + for (int i = 0; i < order; i++) + smp[i] = res[i]; + + int* s = smp; + int* r = res + order; + int c0 = coefs[0]; + int c1 = coefs[1]; + switch (order) + { + case 1: + for (int i = n - order; i > 0; i--) + { + long pred = c0 * (long)*(s++); + *s = *(r++) + (int)(pred >> shift); + } + break; + case 2: + for (int i = n - order; i > 0; i--) + { + long pred = c1 * (long)*(s++); + pred += c0 * (long)*(s++); + *(s--) = *(r++) + (int)(pred >> shift); + } + break; + case 3: + for (int i = n - order; i > 0; i--) + { + long pred = coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + *s = *(r++) + (int)(pred >> shift); + s -= 2; + } + break; + case 4: + for (int i = n - order; i > 0; i--) + { + long pred = coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + *s = *(r++) + (int)(pred >> shift); + s -= 3; + } + break; + case 5: + for (int i = n - order; i > 0; i--) + { + long pred = coefs[4] * (long)*(s++); + pred += coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + *s = *(r++) + (int)(pred >> shift); + s -= 4; + } + break; + case 6: + for (int i = n - order; i > 0; i--) + { + long pred = coefs[5] * (long)*(s++); + pred += coefs[4] * (long)*(s++); + pred += coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + *s = *(r++) + (int)(pred >> shift); + s -= 5; + } + break; + case 7: + for (int i = n - order; i > 0; i--) + { + long pred = coefs[6] * (long)*(s++); + pred += coefs[5] * (long)*(s++); + pred += coefs[4] * (long)*(s++); + pred += coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + *s = *(r++) + (int)(pred >> shift); + s -= 6; + } + break; + case 8: + for (int i = n - order; i > 0; i--) + { + long pred = coefs[7] * (long)*(s++); + pred += coefs[6] * (long)*(s++); + pred += coefs[5] * (long)*(s++); + pred += coefs[4] * (long)*(s++); + pred += coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + *s = *(r++) + (int)(pred >> shift); + s -= 7; + } + break; + default: + for (int i = order; i < n; i++) + { + s = smp + i - order; + long pred = 0; + int* co = coefs + order - 1; + int* c7 = coefs + 7; + while (co > c7) + pred += *(co--) * (long)*(s++); + pred += coefs[7] * (long)*(s++); + pred += coefs[6] * (long)*(s++); + pred += coefs[5] * (long)*(s++); + pred += coefs[4] * (long)*(s++); + pred += coefs[3] * (long)*(s++); + pred += coefs[2] * (long)*(s++); + pred += c1 * (long)*(s++); + pred += c0 * (long)*(s++); + *s = *(r++) + (int)(pred >> shift); + } + break; + } + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/License.txt b/Aaru.Compression/cuetools.net/CUETools.Codecs/License.txt new file mode 100644 index 000000000..389f55a8b --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/License.txt @@ -0,0 +1,16 @@ +CUETools.Codecs: common audio encoder/decoder routines +Copyright (c) 2009-2021 Gregory S. Chudov + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/LpcContext.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/LpcContext.cs new file mode 100644 index 000000000..295a8c640 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/LpcContext.cs @@ -0,0 +1,393 @@ +using System; +using System.Collections.Generic; + +namespace CUETools.Codecs +{ + unsafe public class LpcSubframeInfo + { + public LpcSubframeInfo() + { + autocorr_section_values = new double[lpc.MAX_LPC_SECTIONS, lpc.MAX_LPC_ORDER + 1]; + autocorr_section_orders = new int[lpc.MAX_LPC_SECTIONS]; + } + + // public LpcContext[] lpc_ctx; + public double[,] autocorr_section_values; + public int[] autocorr_section_orders; + //public int obits; + + public void Reset() + { + for (int sec = 0; sec < autocorr_section_orders.Length; sec++) + autocorr_section_orders[sec] = 0; + } + } + + unsafe public struct LpcWindowSection + { + public enum SectionType + { + Zero, + One, + OneLarge, + Data, + OneGlue, + Glue + }; + public int m_start; + public int m_end; + public SectionType m_type; + public int m_id; + public LpcWindowSection(int end) + { + m_id = -1; + m_start = 0; + m_end = end; + m_type = SectionType.Data; + } + public void setData(int start, int end) + { + m_id = -1; + m_start = start; + m_end = end; + m_type = SectionType.Data; + } + public void setOne(int start, int end) + { + m_id = -1; + m_start = start; + m_end = end; + m_type = SectionType.One; + } + public void setGlue(int start) + { + m_id = -1; + m_start = start; + m_end = start; + m_type = SectionType.Glue; + } + public void setZero(int start, int end) + { + m_id = -1; + m_start = start; + m_end = end; + m_type = SectionType.Zero; + } + + unsafe public void compute_autocorr(/*const*/ int* data, float* window, int min_order, int order, int blocksize, double* autoc) + { + if (m_type == SectionType.OneLarge) + lpc.compute_autocorr_windowless_large(data + m_start, m_end - m_start, min_order, order, autoc); + else if (m_type == SectionType.One) + lpc.compute_autocorr_windowless(data + m_start, m_end - m_start, min_order, order, autoc); + else if (m_type == SectionType.Data) + lpc.compute_autocorr(data + m_start, window + m_start, m_end - m_start, min_order, order, autoc); + else if (m_type == SectionType.Glue) + lpc.compute_autocorr_glue(data, window, m_start, m_end, min_order, order, autoc); + else if (m_type == SectionType.OneGlue) + lpc.compute_autocorr_glue(data + m_start, min_order, order, autoc); + } + + unsafe public static void Detect(int _windowcount, float* window_segment, int stride, int sz, int bps, LpcWindowSection* sections) + { + int section_id = 0; + var boundaries = new List(); + var types = new LpcWindowSection.SectionType[_windowcount, lpc.MAX_LPC_SECTIONS * 2]; + var alias = new int[_windowcount, lpc.MAX_LPC_SECTIONS * 2]; + var alias_set = new int[_windowcount, lpc.MAX_LPC_SECTIONS * 2]; + for (int x = 0; x < sz; x++) + { + for (int i = 0; i < _windowcount; i++) + { + int a = alias[i, boundaries.Count]; + float w = window_segment[i * stride + x]; + float wa = window_segment[a * stride + x]; + if (wa != w) + { + for (int i1 = i; i1 < _windowcount; i1++) + if (alias[i1, boundaries.Count] == a + && w == window_segment[i1 * stride + x]) + alias[i1, boundaries.Count] = i; + } + if (boundaries.Count >= lpc.MAX_LPC_SECTIONS * 2) throw new IndexOutOfRangeException(); + types[i, boundaries.Count] = + boundaries.Count >= lpc.MAX_LPC_SECTIONS * 2 - 2 ? + LpcWindowSection.SectionType.Data : w == 0.0 ? + LpcWindowSection.SectionType.Zero : w != 1.0 ? + LpcWindowSection.SectionType.Data : bps * 2 + BitReader.log2i(sz) >= 61 ? + LpcWindowSection.SectionType.OneLarge : + LpcWindowSection.SectionType.One ; + } + bool isBoundary = false; + for (int i = 0; i < _windowcount; i++) + { + isBoundary |= boundaries.Count == 0 || + types[i, boundaries.Count - 1] != types[i, boundaries.Count]; + } + if (isBoundary) + { + for (int i = 0; i < _windowcount; i++) + for (int i1 = 0; i1 < _windowcount; i1++) + if (i != i1 && alias[i, boundaries.Count] == alias[i1, boundaries.Count]) + alias_set[i, boundaries.Count] |= 1 << i1; + boundaries.Add(x); + } + } + boundaries.Add(sz); + var secs = new int[_windowcount]; + // Reconstruct segments list. + for (int j = 0; j < boundaries.Count - 1; j++) + { + for (int i = 0; i < _windowcount; i++) + { + LpcWindowSection* window_sections = sections + i * lpc.MAX_LPC_SECTIONS; + // leave room for glue + if (secs[i] >= lpc.MAX_LPC_SECTIONS - 1) + { + throw new IndexOutOfRangeException(); + //window_sections[secs[i] - 1].m_type = LpcWindowSection.SectionType.Data; + //window_sections[secs[i] - 1].m_end = boundaries[j + 1]; + //continue; + } + window_sections[secs[i]].setData(boundaries[j], boundaries[j + 1]); + window_sections[secs[i]++].m_type = types[i, j]; + } + for (int i = 0; i < _windowcount; i++) + { + LpcWindowSection* window_sections = sections + i * lpc.MAX_LPC_SECTIONS; + int sec = secs[i] - 1; + if (sec > 0 + && j > 0 && (alias_set[i, j] == alias_set[i, j - 1] || window_sections[sec].m_type == SectionType.Zero) + && window_sections[sec].m_start == boundaries[j] + && window_sections[sec].m_end == boundaries[j + 1] + && window_sections[sec - 1].m_end == boundaries[j] + && window_sections[sec - 1].m_type == window_sections[sec].m_type) + { + window_sections[sec - 1].m_end = window_sections[sec].m_end; + secs[i]--; + continue; + } + if (section_id >= lpc.MAX_LPC_SECTIONS) throw new IndexOutOfRangeException(); + if (alias_set[i, j] != 0 + && types[i, j] != SectionType.Zero + && section_id < lpc.MAX_LPC_SECTIONS) + { + for (int i1 = i; i1 < _windowcount; i1++) + if (alias[i1, j] == i && secs[i1] > 0) + sections[i1 * lpc.MAX_LPC_SECTIONS + secs[i1] - 1].m_id = section_id; + section_id++; + } + // TODO: section_id for glue? nontrivial, must be sure next sections are the same size + if (sec > 0 + && (window_sections[sec].m_type == SectionType.One || window_sections[sec].m_type == SectionType.OneLarge) + && window_sections[sec].m_end - window_sections[sec].m_start >= lpc.MAX_LPC_ORDER + && (window_sections[sec - 1].m_type == SectionType.One || window_sections[sec - 1].m_type == SectionType.OneLarge) + && window_sections[sec - 1].m_end - window_sections[sec - 1].m_start >= lpc.MAX_LPC_ORDER) + { + window_sections[sec + 1] = window_sections[sec]; + window_sections[sec].m_end = window_sections[sec].m_start; + window_sections[sec].m_type = SectionType.OneGlue; + window_sections[sec].m_id = -1; + secs[i]++; + continue; + } + if (sec > 0 + && window_sections[sec].m_type != SectionType.Zero + && window_sections[sec - 1].m_type != SectionType.Zero) + { + window_sections[sec + 1] = window_sections[sec]; + window_sections[sec].m_end = window_sections[sec].m_start; + window_sections[sec].m_type = SectionType.Glue; + window_sections[sec].m_id = -1; + secs[i]++; + continue; + } + } + } + for (int i = 0; i < _windowcount; i++) + { + for (int s = 0; s < secs[i]; s++) + { + LpcWindowSection* window_sections = sections + i * lpc.MAX_LPC_SECTIONS; + if (window_sections[s].m_type == SectionType.Glue + || window_sections[s].m_type == SectionType.OneGlue) + { + window_sections[s].m_end = window_sections[s + 1].m_end; + } + } + while (secs[i] < lpc.MAX_LPC_SECTIONS) + { + LpcWindowSection* window_sections = sections + i * lpc.MAX_LPC_SECTIONS; + window_sections[secs[i]++].setZero(sz, sz); + } + } + } + } + + /// + /// Context for LPC coefficients calculation and order estimation + /// + unsafe public class LpcContext + { + public LpcContext() + { + coefs = new int[lpc.MAX_LPC_ORDER]; + reflection_coeffs = new double[lpc.MAX_LPC_ORDER]; + prediction_error = new double[lpc.MAX_LPC_ORDER]; + autocorr_values = new double[lpc.MAX_LPC_ORDER + 1]; + best_orders = new int[lpc.MAX_LPC_ORDER]; + done_lpcs = new uint[lpc.MAX_LPC_PRECISIONS]; + } + + /// + /// Reset to initial (blank) state + /// + public void Reset() + { + autocorr_order = 0; + for (int iPrecision = 0; iPrecision < lpc.MAX_LPC_PRECISIONS; iPrecision++) + done_lpcs[iPrecision] = 0; + } + + /// + /// Calculate autocorrelation data and reflection coefficients. + /// Can be used to incrementaly compute coefficients for higher orders, + /// because it caches them. + /// + /// Maximum order + /// Samples pointer + /// Block size + /// Window function + public void GetReflection(LpcSubframeInfo subframe, int order, int blocksize, int* samples, float* window, LpcWindowSection* sections) + { + if (autocorr_order > order) + return; + fixed (double* reff = reflection_coeffs, autoc = autocorr_values, err = prediction_error) + { + for (int i = autocorr_order; i <= order; i++) autoc[i] = 0; + for (int section = 0; section < lpc.MAX_LPC_SECTIONS; section++) + { + if (sections[section].m_type == LpcWindowSection.SectionType.Zero) + { + continue; + } + if (sections[section].m_id >= 0) + { + if (subframe.autocorr_section_orders[sections[section].m_id] <= order) + { + fixed (double* autocsec = &subframe.autocorr_section_values[sections[section].m_id, 0]) + { + int min_order = subframe.autocorr_section_orders[sections[section].m_id]; + for (int i = min_order; i <= order; i++) autocsec[i] = 0; + sections[section].compute_autocorr(samples, window, min_order, order, blocksize, autocsec); + } + subframe.autocorr_section_orders[sections[section].m_id] = order + 1; + } + for (int i = autocorr_order; i <= order; i++) + autoc[i] += subframe.autocorr_section_values[sections[section].m_id, i]; + } + else + { + sections[section].compute_autocorr(samples, window, autocorr_order, order, blocksize, autoc); + } + } + lpc.compute_schur_reflection(autoc, (uint)order, reff, err); + autocorr_order = order + 1; + } + } +#if XXX + public void GetReflection1(int order, int* samples, int blocksize, float* window) + { + if (autocorr_order > order) + return; + fixed (double* reff = reflection_coeffs, autoc = autocorr_values, err = prediction_error) + { + lpc.compute_autocorr(samples, blocksize, 0, order + 1, autoc, window); + for (int i = 1; i <= order; i++) + autoc[i] = autoc[i + 1]; + lpc.compute_schur_reflection(autoc, (uint)order, reff, err); + autocorr_order = order + 1; + } + } + + public void ComputeReflection(int order, float* autocorr) + { + fixed (double* reff = reflection_coeffs, autoc = autocorr_values, err = prediction_error) + { + for (int i = 0; i <= order; i++) + autoc[i] = autocorr[i]; + lpc.compute_schur_reflection(autoc, (uint)order, reff, err); + autocorr_order = order + 1; + } + } + + public void ComputeReflection(int order, double* autocorr) + { + fixed (double* reff = reflection_coeffs, autoc = autocorr_values, err = prediction_error) + { + for (int i = 0; i <= order; i++) + autoc[i] = autocorr[i]; + lpc.compute_schur_reflection(autoc, (uint)order, reff, err); + autocorr_order = order + 1; + } + } +#endif + public double Akaike(int blocksize, int order, double alpha, double beta) + { + //return (blocksize - order) * (Math.Log(prediction_error[order - 1]) - Math.Log(1.0)) + Math.Log(blocksize) * order * (alpha + beta * order); + //return blocksize * (Math.Log(prediction_error[order - 1]) - Math.Log(autocorr_values[0]) / 2) + Math.Log(blocksize) * order * (alpha + beta * order); + return blocksize * (Math.Log(prediction_error[order - 1])) + Math.Log(blocksize) * order * (alpha + beta * order); + } + + /// + /// Sorts orders based on Akaike's criteria + /// + /// Frame size + public void SortOrdersAkaike(int blocksize, int count, int min_order, int max_order, double alpha, double beta) + { + for (int i = min_order; i <= max_order; i++) + best_orders[i - min_order] = i; + int lim = max_order - min_order + 1; + for (int i = 0; i < lim && i < count; i++) + { + for (int j = i + 1; j < lim; j++) + { + if (Akaike(blocksize, best_orders[j], alpha, beta) < Akaike(blocksize, best_orders[i], alpha, beta)) + { + int tmp = best_orders[j]; + best_orders[j] = best_orders[i]; + best_orders[i] = tmp; + } + } + } + } + + /// + /// Produces LPC coefficients from autocorrelation data. + /// + /// LPC coefficients buffer (for all orders) + public void ComputeLPC(float* lpcs) + { + fixed (double* reff = reflection_coeffs) + lpc.compute_lpc_coefs((uint)autocorr_order - 1, reff, lpcs); + } + + public double[] autocorr_values; + double[] reflection_coeffs; + public double[] prediction_error; + public int[] best_orders; + public int[] coefs; + int autocorr_order; + public int shift; + + public double[] Reflection + { + get + { + return reflection_coeffs; + } + } + + public uint[] done_lpcs; + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/NULL/AudioDecoder.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/NULL/AudioDecoder.cs new file mode 100644 index 000000000..651db6a22 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/NULL/AudioDecoder.cs @@ -0,0 +1,65 @@ +using System; + +namespace CUETools.Codecs.NULL +{ + public class AudioDecoder : IAudioSource + { + private long _sampleOffset, _sampleCount; + private AudioPCMConfig pcm; + private int _sampleVal; + + public IAudioDecoderSettings Settings => null; + + public TimeSpan Duration => TimeSpan.FromSeconds((double)Length / PCM.SampleRate); + + public long Length + { + get { return _sampleCount; } + } + + public long Remaining + { + get { return _sampleCount - _sampleOffset; } + } + + public long Position + { + get { return _sampleOffset; } + set { _sampleOffset = value; } + } + + public AudioPCMConfig PCM { get { return pcm; } } + + public string Path { get { return null; } } + + public AudioDecoder(AudioPCMConfig pcm, long sampleCount, int sampleVal) + { + this._sampleVal = sampleVal; + this._sampleOffset = 0; + this._sampleCount = sampleCount; + this.pcm = pcm; + } + + public AudioDecoder(long sampleCount) + : this(AudioPCMConfig.RedBook, sampleCount, 0) + { + } + + public int Read(AudioBuffer buff, int maxLength) + { + buff.Prepare(this, maxLength); + + int[,] samples = buff.Samples; + for (int i = 0; i < buff.Length; i++) + for (int j = 0; j < PCM.ChannelCount; j++) + samples[i, j] = _sampleVal; + + _sampleOffset += buff.Length; + return buff.Length; + } + + public void Close() + { + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/NULL/AudioEncoder.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/NULL/AudioEncoder.cs new file mode 100644 index 000000000..fbeb36749 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/NULL/AudioEncoder.cs @@ -0,0 +1,35 @@ +using System; + +namespace CUETools.Codecs.NULL +{ + public class AudioEncoder : IAudioDest + { + IAudioEncoderSettings m_settings; + + public AudioEncoder(string path, IAudioEncoderSettings settings) + { + m_settings = settings; + } + + public void Close() + { + } + + public void Delete() + { + } + + public long FinalSampleCount + { + set { } + } + + public IAudioEncoderSettings Settings => m_settings; + + public void Write(AudioBuffer buff) + { + } + + public string Path => null; + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/NullStream.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/NullStream.cs new file mode 100644 index 000000000..a19b70a3d --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/NullStream.cs @@ -0,0 +1,66 @@ +using System; +using System.IO; + +namespace CUETools.Codecs +{ + public class NullStream : Stream + { + public override bool CanRead + { + get { return false; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public NullStream() + { + } + + public override void Close() + { + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override int Read(byte[] array, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] array, int offset, int count) + { + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/PlaybackState.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/PlaybackState.cs new file mode 100644 index 000000000..e4a49d13b --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/PlaybackState.cs @@ -0,0 +1,21 @@ +namespace CUETools.Codecs +{ + /// + /// Playback State + /// + public enum PlaybackState + { + /// + /// Stopped + /// + Stopped, + /// + /// Playing + /// + Playing, + /// + /// Paused + /// + Paused + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/SRDescriptionAttribute.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/SRDescriptionAttribute.cs new file mode 100644 index 000000000..0ccb04675 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/SRDescriptionAttribute.cs @@ -0,0 +1,56 @@ +using System; +using System.ComponentModel; +using System.Reflection; + +namespace CUETools.Codecs; + +/// +/// Localized description attribute +/// +[AttributeUsage(AttributeTargets.All)] +public class SRDescriptionAttribute : DescriptionAttribute +{ + /// + /// Resource manager to use; + /// + readonly Type SR; + /// + /// Store a flag indicating whether this has been localized + /// + bool localized; + + /// + /// Construct the description attribute + /// + /// + public SRDescriptionAttribute(Type SR, string text) : base(text) + { + localized = false; + this.SR = SR; + } + + /// + /// Override the return of the description text to localize the text + /// + public override string Description + { + get + { + if(!localized) + { + localized = true; + + DescriptionValue = SR.InvokeMember(DescriptionValue, + BindingFlags.GetProperty | + BindingFlags.Static | + BindingFlags.Public | + BindingFlags.NonPublic, + null, + null, + []) as string; + } + + return base.Description; + } + } +} \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/AudioDecoderSettingsViewModel.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/AudioDecoderSettingsViewModel.cs new file mode 100644 index 000000000..a58d23e7e --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/AudioDecoderSettingsViewModel.cs @@ -0,0 +1,97 @@ +using Newtonsoft.Json; +using System; +using System.ComponentModel; + +namespace CUETools.Codecs +{ + [JsonObject(MemberSerialization.OptIn)] + public class AudioDecoderSettingsViewModel : INotifyPropertyChanged + { + [JsonProperty] + public IAudioDecoderSettings Settings = null; + + public event PropertyChangedEventHandler PropertyChanged; + + [JsonConstructor] + private AudioDecoderSettingsViewModel() + { + } + + public AudioDecoderSettingsViewModel(IAudioDecoderSettings settings) + { + this.Settings = settings; + } + + public override string ToString() + { + return Name; + } + + public string FullName => Name + " [" + Extension + "]"; + + public string Path + { + get + { + if (Settings is CommandLine.DecoderSettings) + return (Settings as CommandLine.DecoderSettings).Path; + return ""; + } + set + { + if (Settings is CommandLine.DecoderSettings) + (Settings as CommandLine.DecoderSettings).Path = value; + else throw new InvalidOperationException(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Path")); + } + } + public string Parameters + { + get + { + if (Settings is CommandLine.DecoderSettings) + return (Settings as CommandLine.DecoderSettings).Parameters; + return ""; + } + set + { + if (Settings is CommandLine.DecoderSettings) + (Settings as CommandLine.DecoderSettings).Parameters = value; + else throw new InvalidOperationException(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Parameters")); + } + } + + public string Name + { + get => Settings.Name; + set + { + if (Settings is CommandLine.DecoderSettings) + (Settings as CommandLine.DecoderSettings).Name = value; + else throw new InvalidOperationException(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); + } + } + + public string Extension + { + get => Settings.Extension; + set + { + if (Settings is CommandLine.DecoderSettings) + (Settings as CommandLine.DecoderSettings).Extension = value; + else throw new InvalidOperationException(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Extension")); + } + } + + public string DotExtension => "." + Extension; + + public bool CanBeDeleted => Settings is CommandLine.DecoderSettings; + + public bool IsValid => + (Settings != null) + && (Settings is CommandLine.DecoderSettings ? (Settings as CommandLine.DecoderSettings).Path != "" : true); + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/AudioEncoderSettingsViewModel.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/AudioEncoderSettingsViewModel.cs new file mode 100644 index 000000000..a9e0f1062 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/AudioEncoderSettingsViewModel.cs @@ -0,0 +1,137 @@ +using Newtonsoft.Json; +using System; +using System.ComponentModel; + +namespace CUETools.Codecs +{ + [JsonObject(MemberSerialization.OptIn)] + public class AudioEncoderSettingsViewModel : INotifyPropertyChanged + { + [JsonProperty] + public IAudioEncoderSettings Settings = null; + + public event PropertyChangedEventHandler PropertyChanged; + + [JsonConstructor] + private AudioEncoderSettingsViewModel() + { + } + + public AudioEncoderSettingsViewModel(IAudioEncoderSettings settings) + { + this.Settings = settings; + } + + public override string ToString() + { + return Name; + } + + public string FullName => Name + " [" + Extension + "]"; + + public string Path + { + get + { + if (Settings is CommandLine.EncoderSettings) + return (Settings as CommandLine.EncoderSettings).Path; + return ""; + } + set + { + var settings = this.Settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.Path = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Path")); + } + } + + public string Parameters + { + get + { + if (Settings is CommandLine.EncoderSettings) + return (Settings as CommandLine.EncoderSettings).Parameters; + return ""; + } + set + { + var settings = this.Settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.Parameters = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Parameters")); + } + } + + public bool Lossless + { + get => Settings.Lossless; + set + { + var settings = this.Settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.Lossless = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Lossless")); + } + } + + + public string Name + { + get => Settings.Name; + set + { + var settings = this.Settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.Name = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); + } + } + + public string Extension + { + get => Settings.Extension; + set + { + var settings = this.Settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.Extension = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Extension")); + } + } + + public string DotExtension => "." + Extension; + + public string SupportedModes + { + get => Settings.SupportedModes; + set + { + var settings = this.Settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.SupportedModes = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SupportedModes")); + } + } + + public int EncoderModeIndex + { + get + { + string[] modes = this.SupportedModes.Split(' '); + if (modes == null || modes.Length < 2) + return -1; + for (int i = 0; i < modes.Length; i++) + if (modes[i] == this.Settings.EncoderMode) + return i; + return -1; + } + } + + public bool CanBeDeleted => Settings is CommandLine.EncoderSettings; + + public bool IsValid => + (Settings != null) + && (Settings is CommandLine.EncoderSettings ? (Settings as CommandLine.EncoderSettings).Path != "" : true); + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/DecoderListViewModel.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/DecoderListViewModel.cs new file mode 100644 index 000000000..0a790cf18 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/DecoderListViewModel.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; + +namespace CUETools.Codecs +{ + public class DecoderListViewModel : BindingList + { + private List model; + + public DecoderListViewModel(List model) + : base() + { + this.model = model; + model.ForEach(item => Add(new AudioDecoderSettingsViewModel(item))); + AddingNew += OnAddingNew; + } + + private void OnAddingNew(object sender, AddingNewEventArgs e) + { + var item = new CommandLine.DecoderSettings("new", "wav", "", ""); + model.Add(item); + e.NewObject = new AudioDecoderSettingsViewModel(item); + } + + public bool TryGetValue(string extension, string name, out AudioDecoderSettingsViewModel result) + { + foreach (AudioDecoderSettingsViewModel udc in this) + { + if (udc.Settings.Extension == extension && udc.Settings.Name == name) + { + result = udc; + return true; + } + } + result = null; + return false; + } + + public AudioDecoderSettingsViewModel GetDefault(string extension) + { + AudioDecoderSettingsViewModel result = null; + foreach (AudioDecoderSettingsViewModel udc in this) + { + if (udc.Settings.Extension == extension && (result == null || result.Settings.Priority < udc.Settings.Priority)) + { + result = udc; + } + } + return result; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/EncoderListViewModel.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/EncoderListViewModel.cs new file mode 100644 index 000000000..1c5ba2c20 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/ViewModel/EncoderListViewModel.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; + +namespace CUETools.Codecs +{ + public class EncoderListViewModel : BindingList + { + private List model; + + public EncoderListViewModel(List model) + : base() + { + this.model = model; + model.ForEach(item => Add(new AudioEncoderSettingsViewModel(item))); + AddingNew += OnAddingNew; + } + + private void OnAddingNew(object sender, AddingNewEventArgs e) + { + var item = new CommandLine.EncoderSettings("new", "wav", true, "", "", "", ""); + model.Add(item); + e.NewObject = new AudioEncoderSettingsViewModel(item); + } + + public bool TryGetValue(string extension, bool lossless, string name, out AudioEncoderSettingsViewModel result) + { + //result = this.Where(udc => udc.settings.Extension == extension && udc.settings.Lossless == lossless && udc.settings.Name == name).First(); + foreach (AudioEncoderSettingsViewModel udc in this) + { + if (udc.Settings.Extension == extension && udc.Settings.Lossless == lossless && udc.Settings.Name == name) + { + result = udc; + return true; + } + } + result = null; + return false; + } + + public AudioEncoderSettingsViewModel GetDefault(string extension, bool lossless) + { + AudioEncoderSettingsViewModel result = null; + foreach (AudioEncoderSettingsViewModel udc in this) + { + if (udc.Settings.Extension == extension && udc.Settings.Lossless == lossless && (result == null || result.Settings.Priority < udc.Settings.Priority)) + { + result = udc; + } + } + return result; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/AudioDecoder.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/AudioDecoder.cs new file mode 100644 index 000000000..3cd32d0a3 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/AudioDecoder.cs @@ -0,0 +1,271 @@ +using System; +using System.IO; + +namespace CUETools.Codecs.WAV +{ + public class AudioDecoder : IAudioSource + { + Stream _IO; + BinaryReader _br; + long _dataOffset, _samplePos, _sampleLen; + private AudioPCMConfig pcm; + long _dataLen; + bool _largeFile; + string _path; + + private DecoderSettings m_settings; + public IAudioDecoderSettings Settings => m_settings; + + public long Position + { + get + { + return _samplePos; + } + set + { + long seekPos; + + if (_samplePos == value) + { + return; + } + + var oldSamplePos = _samplePos; + if (_sampleLen >= 0 && value > _sampleLen) + _samplePos = _sampleLen; + else + _samplePos = value; + + if (_IO.CanSeek || _samplePos < oldSamplePos) + { + seekPos = _dataOffset + _samplePos * PCM.BlockAlign; + _IO.Seek(seekPos, SeekOrigin.Begin); + } + else + { + int offs = (int)(_samplePos - oldSamplePos) * PCM.BlockAlign; + while (offs > 0) + { + int chunk = Math.Min(offs, 16536); + _br.ReadBytes(chunk); + offs -= chunk; + } + } + } + } + + public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate); + + public long Length + { + get + { + return _sampleLen; + } + } + + public long Remaining + { + get + { + return _sampleLen - _samplePos; + } + } + + public AudioPCMConfig PCM { get { return pcm; } } + + public string Path { get { return _path; } } + + public AudioDecoder(DecoderSettings settings, string path, Stream IO = null) + { + m_settings = settings; + _path = path; + _IO = IO ?? new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000, FileOptions.SequentialScan); + _br = new BinaryReader(_IO); + + ParseHeaders(); + + if (_dataLen < 0 || m_settings.IgnoreChunkSizes) + _sampleLen = -1; + else + _sampleLen = _dataLen / pcm.BlockAlign; + } + + public AudioDecoder(DecoderSettings settings, string path, Stream IO, AudioPCMConfig _pcm) + { + m_settings = settings; + _path = path; + _IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000, FileOptions.SequentialScan); + _br = new BinaryReader(_IO); + + _largeFile = false; + _dataOffset = 0; + _samplePos = 0; + pcm = _pcm; + _dataLen = _IO.CanSeek ? _IO.Length : -1; + if (_dataLen < 0) + _sampleLen = -1; + else + { + _sampleLen = _dataLen / pcm.BlockAlign; + if ((_dataLen % pcm.BlockAlign) != 0) + throw new Exception("odd file size"); + } + } + + public static AudioBuffer ReadAllSamples(DecoderSettings settings, string path, Stream IO = null) + { + AudioDecoder reader = new AudioDecoder(settings, path, IO); + AudioBuffer buff = new AudioBuffer(reader, (int)reader.Length); + reader.Read(buff, -1); + if (reader.Remaining != 0) + throw new Exception("couldn't read the whole file"); + reader.Close(); + return buff; + } + + public void Close() + { + if (_br != null) + { + _br.Close(); + _br = null; + } + _IO = null; + } + + private void ParseHeaders() + { + const long maxFileSize = 0x7FFFFFFEL; + const uint fccRIFF = 0x46464952; + const uint fccWAVE = 0x45564157; + const uint fccFormat = 0x20746D66; + const uint fccData = 0x61746164; + + uint lenRIFF; + bool foundFormat, foundData; + + if (_br.ReadUInt32() != fccRIFF) + { + throw new Exception("Not a valid RIFF file."); + } + + lenRIFF = _br.ReadUInt32(); + + if (_br.ReadUInt32() != fccWAVE) + { + throw new Exception("Not a valid WAVE file."); + } + + _largeFile = false; + foundFormat = false; + foundData = false; + long pos = 12; + do + { + uint ckID, ckSize, ckSizePadded; + long ckEnd; + + ckID = _br.ReadUInt32(); + ckSize = _br.ReadUInt32(); + ckSizePadded = (ckSize + 1U) & ~1U; + pos += 8; + ckEnd = pos + (long)ckSizePadded; + + if (ckID == fccFormat) + { + foundFormat = true; + + uint fmtTag = _br.ReadUInt16(); + int _channelCount = _br.ReadInt16(); + int _sampleRate = _br.ReadInt32(); + _br.ReadInt32(); // bytes per second + int _blockAlign = _br.ReadInt16(); + int _bitsPerSample = _br.ReadInt16(); + int _channelMask = 0; + pos += 16; + + if (fmtTag == 0xFFFEU && ckSize >= 34) // WAVE_FORMAT_EXTENSIBLE + { + _br.ReadInt16(); // CbSize + _br.ReadInt16(); // ValidBitsPerSample + _channelMask = _br.ReadInt32(); + fmtTag = _br.ReadUInt16(); + pos += 10; + } + + if (fmtTag != 1) // WAVE_FORMAT_PCM + throw new Exception("WAVE format tag not WAVE_FORMAT_PCM."); + + pcm = new AudioPCMConfig(_bitsPerSample, _channelCount, _sampleRate, (AudioPCMConfig.SpeakerConfig)_channelMask); + if (pcm.BlockAlign != _blockAlign) + throw new Exception("WAVE has strange BlockAlign"); + } + else if (ckID == fccData) + { + foundData = true; + + _dataOffset = pos; + if (!_IO.CanSeek || _IO.Length <= maxFileSize) + { + if (ckSize == 0 || ckSize >= 0x7fffffff) + _dataLen = -1; + else + _dataLen = (long)ckSize; + } + else + { + _largeFile = true; + _dataLen = _IO.Length - pos; + } + } + + if ((foundFormat & foundData) || _largeFile) + break; + if (_IO.CanSeek) + _IO.Seek(ckEnd, SeekOrigin.Begin); + else + _br.ReadBytes((int)(ckEnd - pos)); + pos = ckEnd; + } while (true); + + if ((foundFormat & foundData) == false || pcm == null) + throw new Exception("Format or data chunk not found."); + if (pcm.ChannelCount <= 0) + throw new Exception("Channel count is invalid."); + if (pcm.SampleRate <= 0) + throw new Exception("Sample rate is invalid."); + if ((pcm.BitsPerSample <= 0) || (pcm.BitsPerSample > 32)) + throw new Exception("Bits per sample is invalid."); + if (pos != _dataOffset) + Position = 0; + } + + public int Read(AudioBuffer buff, int maxLength) + { + buff.Prepare(this, maxLength); + + byte[] bytes = buff.Bytes; + int byteCount = (int)buff.ByteLength; + int pos = 0; + + while (pos < byteCount) + { + int len = _IO.Read(bytes, pos, byteCount - pos); + if (len <= 0) + { + if ((pos % PCM.BlockAlign) != 0 || _sampleLen >= 0) + throw new Exception("Incomplete file read."); + buff.Length = pos / PCM.BlockAlign; + _samplePos += buff.Length; + _sampleLen = _samplePos; + return buff.Length; + } + pos += len; + } + _samplePos += buff.Length; + return buff.Length; + } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/AudioEncoder.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/AudioEncoder.cs new file mode 100644 index 000000000..d028f6e90 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/AudioEncoder.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace CUETools.Codecs.WAV; + +public class AudioEncoder : IAudioDest +{ + readonly EncoderSettings m_settings; + BinaryWriter _bw; + List _chunkFCCs; + List _chunks; + long _finalSampleCount = -1; + bool _headersWritten; + Stream _IO; + long hdrLen; + + public AudioEncoder(EncoderSettings settings, string path, Stream IO = null) + { + m_settings = settings; + Path = path; + _IO = IO ?? new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read); + _bw = new BinaryWriter(_IO); + } + + public long Position { get; private set; } + +#region IAudioDest Members + + public long FinalSampleCount + { + set => _finalSampleCount = value; + } + + public IAudioEncoderSettings Settings => m_settings; + + public string Path { get; } + + public void Close() + { + if(_finalSampleCount <= 0 && _IO.CanSeek) + { + long dataLen = Position * Settings.PCM.BlockAlign; + long dataLenPadded = dataLen + (dataLen & 1); + + if(dataLenPadded + hdrLen - 8 < 0xffffffff) + { + if((dataLen & 1) == 1) _bw.Write((byte)0); + + _bw.Seek(4, SeekOrigin.Begin); + _bw.Write((uint)(dataLenPadded + hdrLen - 8)); + + _bw.Seek((int)hdrLen - 4, SeekOrigin.Begin); + _bw.Write((uint)dataLen); + } + } + + _bw.Close(); + + _bw = null; + _IO = null; + + if(_finalSampleCount > 0 && Position != _finalSampleCount) + throw new Exception("Samples written differs from the expected sample count."); + } + + public void Delete() + { + _bw.Close(); + _bw = null; + _IO = null; + if(Path != "") File.Delete(Path); + } + + public void Write(AudioBuffer buff) + { + if(buff.Length == 0) return; + buff.Prepare(this); + if(!_headersWritten) WriteHeaders(); + _IO.Write(buff.Bytes, 0, buff.ByteLength); + Position += buff.Length; + } + +#endregion + + public void WriteChunk(uint fcc, byte[] data) + { + if(Position > 0) throw new Exception("data already written, no chunks allowed"); + + if(_chunks == null) + { + _chunks = []; + _chunkFCCs = []; + } + + _chunkFCCs.Add(fcc); + _chunks.Add(data); + hdrLen += 8 + data.Length + (data.Length & 1); + } + + void WriteHeaders() + { + const uint fccRIFF = 0x46464952; + const uint fccWAVE = 0x45564157; + const uint fccFormat = 0x20746D66; + const uint fccData = 0x61746164; + + bool wavex = Settings.PCM.BitsPerSample != 16 && Settings.PCM.BitsPerSample != 24 || + Settings.PCM.ChannelMask != AudioPCMConfig.GetDefaultChannelMask(Settings.PCM.ChannelCount); + + hdrLen += 36 + (wavex ? 24 : 0) + 8; + + var dataLen = (uint)(_finalSampleCount * Settings.PCM.BlockAlign); + uint dataLenPadded = dataLen + (dataLen & 1); + + _bw.Write(fccRIFF); + + if(_finalSampleCount <= 0) + _bw.Write(0xffffffff); + else + _bw.Write((uint)(dataLenPadded + hdrLen - 8)); + + _bw.Write(fccWAVE); + _bw.Write(fccFormat); + + if(wavex) + { + _bw.Write((uint)40); + _bw.Write((ushort)0xfffe); // WAVEX follows + } + else + { + _bw.Write((uint)16); + _bw.Write((ushort)1); // PCM + } + + _bw.Write((ushort)Settings.PCM.ChannelCount); + _bw.Write((uint)Settings.PCM.SampleRate); + _bw.Write((uint)(Settings.PCM.SampleRate * Settings.PCM.BlockAlign)); + _bw.Write((ushort)Settings.PCM.BlockAlign); + _bw.Write((ushort)((Settings.PCM.BitsPerSample + 7) / 8 * 8)); + + if(wavex) + { + _bw.Write((ushort)22); // length of WAVEX structure + _bw.Write((ushort)Settings.PCM.BitsPerSample); + _bw.Write((uint)Settings.PCM.ChannelMask); + _bw.Write((ushort)1); // PCM Guid + _bw.Write((ushort)0); + _bw.Write((ushort)0); + _bw.Write((ushort)0x10); + _bw.Write((byte)0x80); + _bw.Write((byte)0x00); + _bw.Write((byte)0x00); + _bw.Write((byte)0xaa); + _bw.Write((byte)0x00); + _bw.Write((byte)0x38); + _bw.Write((byte)0x9b); + _bw.Write((byte)0x71); + } + + if(_chunks != null) + { + for(var i = 0; i < _chunks.Count; i++) + { + _bw.Write(_chunkFCCs[i]); + _bw.Write((uint)_chunks[i].Length); + _bw.Write(_chunks[i]); + if((_chunks[i].Length & 1) != 0) _bw.Write((byte)0); + } + } + + _bw.Write(fccData); + + if(_finalSampleCount <= 0) + _bw.Write(0xffffffff); + else + _bw.Write(dataLen); + + _headersWritten = true; + } +} \ No newline at end of file diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/DecoderSettings.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/DecoderSettings.cs new file mode 100644 index 000000000..1163647bb --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/DecoderSettings.cs @@ -0,0 +1,36 @@ +using Newtonsoft.Json; +using System; +using System.ComponentModel; + +namespace CUETools.Codecs.WAV +{ + [JsonObject(MemberSerialization.OptIn)] + public class DecoderSettings : IAudioDecoderSettings + { + #region IAudioDecoderSettings implementation + [Browsable(false)] + public string Extension => "wav"; + + [Browsable(false)] + public string Name => "cuetools"; + + [Browsable(false)] + public Type DecoderType => typeof(AudioDecoder); + + [Browsable(false)] + public int Priority => 2; + + public IAudioDecoderSettings Clone() + { + return MemberwiseClone() as IAudioDecoderSettings; + } + #endregion + + public DecoderSettings() + { + this.Init(); + } + + public bool IgnoreChunkSizes { get; set; } + } +} diff --git a/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/EncoderSettings.cs b/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/EncoderSettings.cs new file mode 100644 index 000000000..2a55a0fb2 --- /dev/null +++ b/Aaru.Compression/cuetools.net/CUETools.Codecs/WAV/EncoderSettings.cs @@ -0,0 +1,64 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace CUETools.Codecs.WAV +{ + [JsonObject(MemberSerialization.OptIn)] + public class EncoderSettings : IAudioEncoderSettings + { + #region IAudioEncoderSettings implementation + [Browsable(false)] + public string Extension => "wav"; + + [Browsable(false)] + public string Name => "cuetools"; + + [Browsable(false)] + public Type EncoderType => typeof(WAV.AudioEncoder); + + [Browsable(false)] + public bool Lossless => true; + + [Browsable(false)] + public int Priority => 10; + + [Browsable(false)] + public string SupportedModes => ""; + + [Browsable(false)] + public string DefaultMode => ""; + + [Browsable(false)] + [DefaultValue("")] + public string EncoderMode { get; set; } + + [Browsable(false)] + public AudioPCMConfig PCM { get; set; } + + [Browsable(false)] + public int BlockSize { get; set; } + + [Browsable(false)] + [DefaultValue(4096)] + public int Padding { get; set; } + + public IAudioEncoderSettings Clone() + { + return MemberwiseClone() as IAudioEncoderSettings; + } + #endregion + + public EncoderSettings() + { + this.Init(); + } + + public EncoderSettings(AudioPCMConfig pcm) + { + this.Init(pcm); + } + } +} diff --git a/Aaru.Console b/Aaru.Console deleted file mode 160000 index 0b3682ef5..000000000 --- a/Aaru.Console +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0b3682ef51e7cfd411208105e3ae47f5ca56d5f6 diff --git a/Aaru.Console/.gitignore b/Aaru.Console/.gitignore new file mode 100644 index 000000000..05c540d38 --- /dev/null +++ b/Aaru.Console/.gitignore @@ -0,0 +1,595 @@ +### VisualStudio template +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ +### Linux template + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +### C++ template +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o + +# Precompiled Headers +*.gch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### MonoDevelop template +#User Specific +*.usertasks + +#Mono Project Files +*.resources +test-results/ +### GPG template +secring.* + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests +### CMake template +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +### C template +# Object files +*.ko +*.elf + +# Linker output +*.map +*.exp + +*.so.* + +# Executables +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# NuGet Packages Directory +packages/ +## TODO: If the tool you use requires repositories.config uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +# This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) +!packages/build/ + + +# Others +sql/ +*.Cache + +# Visual Studio 2017 +.vs + +workspace.xml +cmake-build-debug +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +pkg/**/pkg +pkg/**/src +pkg/**/*.asc +pkg/**/*.sig +pkg/**/*.tar.xz +pkg/**/*.zip +pkg/**/aaru + +.sonarqube \ No newline at end of file diff --git a/Aaru.Console/Aaru.Console.csproj b/Aaru.Console/Aaru.Console.csproj new file mode 100644 index 000000000..c4087d01b --- /dev/null +++ b/Aaru.Console/Aaru.Console.csproj @@ -0,0 +1,89 @@ + + + + 2.0 + {CCAA7AFE-C094-4D82-A66D-630DE8A3F545} + Library + Aaru.Console + Aaru.Console + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Console + $(Version) + net8.0 + 12 + Contains console implementation used by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + LGPL-2.1-only + https://github.com/aaru-dps/Aaru.Console + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + LICENSE.LGPL + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + \ No newline at end of file diff --git a/Aaru.Console/AaruConsole.cs b/Aaru.Console/AaruConsole.cs new file mode 100644 index 000000000..901c8caa0 --- /dev/null +++ b/Aaru.Console/AaruConsole.cs @@ -0,0 +1,261 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : AaruConsole.cs +// Author(s) : Natalia Portillo +// +// Component : Console. +// +// --[ Description ] ---------------------------------------------------------- +// +// Handlers for normal, verbose and debug consoles. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Console; + +/// +/// Writes the text representation of the specified array of objects, followed by the current line terminator, to +/// the standard output console using the specified format information. +/// +/// A composite format string. +/// An array of objects to write using . +public delegate void WriteLineHandler(string format, params object[] arg); + +/// +/// Writes the text representation of the specified array of objects, followed by the current line terminator, to +/// the error output console using the specified format information. +/// +/// A composite format string. +/// An array of objects to write using . +public delegate void ErrorWriteLineHandler(string format, params object[] arg); + +/// +/// Writes the text representation of the specified array of objects, followed by the current line terminator, to +/// the verbose output console using the specified format information. +/// +/// A composite format string. +/// An array of objects to write using . +public delegate void VerboseWriteLineHandler(string format, params object[] arg); + +/// +/// Writes the text representation of the specified array of objects, followed by the current line terminator, to +/// the debug output console using the specified format information. +/// +/// A composite format string. +/// An array of objects to write using . +public delegate void DebugWriteLineHandler(string format, params object[] arg); + +/// +/// Writes the text representation of the specified array of objects, to the standard output console using the +/// specified format information. +/// +/// A composite format string. +/// An array of objects to write using . +public delegate void WriteHandler(string format, params object[] arg); + +/// +/// Writes the text representation of the specified array of objects, to the error output console using the +/// specified format information. +/// +/// A composite format string. +/// An array of objects to write using . +public delegate void ErrorWriteHandler(string format, params object[] arg); + +/// +/// Writes the text representation of the specified array of objects, to the verbose output console using the +/// specified format information. +/// +/// A composite format string. +/// An array of objects to write using . +public delegate void VerboseWriteHandler(string format, params object[] arg); + +/// +/// Writes the text representation of the specified array of objects, to the debug output console using the +/// specified format information. +/// +/// A composite format string. +/// An array of objects to write using . +public delegate void DebugWriteHandler(string format, params object[] arg); + +/// +/// Writes the text representation of the specified array of objects, followed by the current line terminator, to +/// the debug output console using the specified format information. +/// +/// Description of the module writing to the debug console +/// A composite format string. +/// An array of objects to write using . +public delegate void DebugWithModuleWriteLineHandler(string module, string format, params object[] arg); + +/// +/// Writes the exception to the debug output console. +/// +/// Exception. +public delegate void WriteExceptionHandler(Exception ex); + +/// +/// Implements a console abstraction that defines four level of messages that can be routed to different consoles: +/// standard, error, verbose and debug. +/// +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static class AaruConsole +{ + /// Event to receive writings to the standard output console that should be followed by a line termination. + public static event WriteLineHandler WriteLineEvent; + + /// Event to receive writings to the error output console that should be followed by a line termination. + public static event ErrorWriteLineHandler ErrorWriteLineEvent; + + /// Event to receive writings to the verbose output console that should be followed by a line termination. + public static event VerboseWriteLineHandler VerboseWriteLineEvent; + + /// Event to receive line terminations to the debug output console. + public static event DebugWriteLineHandler DebugWriteLineEvent; + + /// Event to receive writings to the debug output console that should be followed by a line termination. + public static event DebugWithModuleWriteLineHandler DebugWithModuleWriteLineEvent; + + /// Event to receive writings to the standard output console. + public static event WriteHandler WriteEvent; + + /// Event to receive writings to the error output console. + public static event ErrorWriteHandler ErrorWriteEvent; + + /// Event to receive writings to the verbose output console. + public static event VerboseWriteHandler VerboseWriteEvent; + + /// Event to receive writings to the debug output console. + public static event DebugWriteHandler DebugWriteEvent; + + /// Event to receive exceptions to write to the debug output console. + public static event WriteExceptionHandler WriteExceptionEvent; + + /// + /// Writes the text representation of the specified array of objects, followed by the current line terminator, to + /// the standard output console using the specified format information. + /// + /// A composite format string. + /// An array of objects to write using . + public static void WriteLine(string format, params object[] arg) => WriteLineEvent?.Invoke(format, arg); + + /// + /// Writes the text representation of the specified array of objects, followed by the current line terminator, to + /// the error output console using the specified format information. + /// + /// A composite format string. + /// An array of objects to write using . + public static void ErrorWriteLine(string format, params object[] arg) => ErrorWriteLineEvent?.Invoke(format, arg); + + /// + /// Writes the text representation of the specified array of objects, followed by the current line terminator, to + /// the verbose output console using the specified format information. + /// + /// A composite format string. + /// An array of objects to write using . + public static void VerboseWriteLine(string format, params object[] arg) => + VerboseWriteLineEvent?.Invoke(format, arg); + + /// + /// Writes the text representation of the specified array of objects, followed by the current line terminator, to + /// the debug output console using the specified format information. + /// + /// Description of the module writing to the debug console + /// A composite format string. + /// An array of objects to write using . + public static void DebugWriteLine(string module, string format, params object[] arg) + { + DebugWriteLineEvent?.Invoke("DEBUG (" + module + "): " + format, arg); + DebugWithModuleWriteLineEvent?.Invoke(module, format, arg); + } + + /// Writes the current line terminator to the standard output console. + public static void WriteLine() => WriteLineEvent?.Invoke("", null); + + /// Writes the current line terminator to the error output console. + public static void ErrorWriteLine() => ErrorWriteLineEvent?.Invoke("", null); + + /// Writes the current line terminator to the verbose output console. + public static void VerboseWriteLine() => VerboseWriteLineEvent?.Invoke("", null); + + /// Writes the current line terminator to the debug output console. + public static void DebugWriteLine() => DebugWriteLineEvent?.Invoke("", null); + + /// + /// Writes the text representation of the specified array of objects to the standard output console using the + /// specified format information. + /// + /// A composite format string. + /// An array of objects to write using . + public static void Write(string format, params object[] arg) => WriteEvent?.Invoke(format, arg); + + /// + /// Writes the text representation of the specified array of objects to the error output console using the + /// specified format information. + /// + /// A composite format string. + /// An array of objects to write using . + public static void ErrorWrite(string format, params object[] arg) => ErrorWriteEvent?.Invoke(format, arg); + + /// + /// Writes the text representation of the specified array of objects to the verbose output console using the + /// specified format information. + /// + /// A composite format string. + /// An array of objects to write using . + public static void VerboseWrite(string format, params object[] arg) => VerboseWriteEvent?.Invoke(format, arg); + + /// + /// Writes the text representation of the specified array of objects to the debug output console using the + /// specified format information. + /// + /// Description of the module writing to the debug console + /// A composite format string. + /// An array of objects to write using . + public static void DebugWrite(string module, string format, params object[] arg) => + DebugWriteEvent?.Invoke("DEBUG (" + module + "): " + format, arg); + + /// Writes the specified string value, followed by the current line terminator, to the standard output console. + /// The value to write. + public static void WriteLine(string value) => WriteLineEvent?.Invoke("{0}", value); + + /// Writes the specified string value, followed by the current line terminator, to the error output console. + /// The value to write. + public static void ErrorWriteLine(string value) => ErrorWriteLineEvent?.Invoke("{0}", value); + + /// Writes the specified string value, followed by the current line terminator, to the verbose output console. + /// The value to write. + public static void VerboseWriteLine(string value) => VerboseWriteLineEvent?.Invoke("{0}", value); + + /// Writes the specified string value, followed by the current line terminator, to the debug output console. + /// Description of the module writing to the debug console + /// The value to write. + public static void DebugWriteLine(string module, string value) => + DebugWriteLineEvent?.Invoke("{0}", "DEBUG (" + module + "): " + value); + + /// + /// Writes the exception to the debug output console. + /// + /// Exception. + public static void WriteException(Exception ex) => WriteExceptionEvent?.Invoke(ex); +} \ No newline at end of file diff --git a/Aaru.Core/Aaru.Core.csproj b/Aaru.Core/Aaru.Core.csproj index 328c16818..f1b83adf2 100644 --- a/Aaru.Core/Aaru.Core.csproj +++ b/Aaru.Core/Aaru.Core.csproj @@ -1,220 +1,126 @@  - - Debug - AnyCPU - 2.0 - {679659B8-25D0-4279-B632-56EF8F94ADC0} - Library - Aaru.Core - Aaru.Core - $(Version) - false - true - 6.0.0-alpha8 - Claunia.com - Copyright © 2011-2022 Natalia Portillo - Aaru Data Preservation Suite - Aaru.Core - $(Version) - net6.0 - 10 - Contains core algorithms used by the Aaru Data Preservation Suite. - https://github.com/aaru-dps/ - GPL-3.0-or-later - https://github.com/aaru-dps/Aaru - true - en-US - true - true - snupkg - Natalia Portillo <claunia@claunia.com> - true - - - $(Version)+{chash:8} - true - true - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - true - bin\Release - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LICENSE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /Library/Frameworks/Mono.framework/Versions/Current/lib/mono - /usr/lib/mono - /usr/local/lib/mono - - $(BaseFrameworkPathOverrideForMono)/4.0-api - $(BaseFrameworkPathOverrideForMono)/4.5-api - $(BaseFrameworkPathOverrideForMono)/4.5.1-api - $(BaseFrameworkPathOverrideForMono)/4.5.2-api - $(BaseFrameworkPathOverrideForMono)/4.6-api - $(BaseFrameworkPathOverrideForMono)/4.6.1-api - $(BaseFrameworkPathOverrideForMono)/4.6.2-api - $(BaseFrameworkPathOverrideForMono)/4.7-api - $(BaseFrameworkPathOverrideForMono)/4.7.1-api - true - - $(FrameworkPathOverride)/Facades;$(AssemblySearchPaths) - + + 2.0 + {679659B8-25D0-4279-B632-56EF8F94ADC0} + Library + Aaru.Core + Aaru.Core + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Core + $(Version) + net8.0 + 12 + Contains core algorithms used by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + GPL-3.0-or-later + https://github.com/aaru-dps/Aaru + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LICENSE + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/Aaru.Core/Aaru.Core.csproj.DotSettings b/Aaru.Core/Aaru.Core.csproj.DotSettings index ce5fbb3bc..0fa4ea42a 100644 --- a/Aaru.Core/Aaru.Core.csproj.DotSettings +++ b/Aaru.Core/Aaru.Core.csproj.DotSettings @@ -1,6 +1,13 @@ - - True - True - True - True - True \ No newline at end of file + + True + True + True + True + True \ No newline at end of file diff --git a/Aaru.Core/ArchiveFormat.cs b/Aaru.Core/ArchiveFormat.cs new file mode 100644 index 000000000..af93ce200 --- /dev/null +++ b/Aaru.Core/ArchiveFormat.cs @@ -0,0 +1,85 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ArchiveFormat.cs +// Author(s) : Natalia Portillo +// +// Component : Core algorithms. +// +// --[ Description ] ---------------------------------------------------------- +// +// Detects archive format. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using Aaru.CommonTypes; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; + +namespace Aaru.Core; + +/// Core archive format operations +public static class ArchiveFormat +{ + const string MODULE_NAME = "Format detection"; + + /// Detects the archive plugin that recognizes the data inside a filter + /// Filter + /// Detected archive plugin + public static IArchive Detect(IFilter archiveFilter) + { + try + { + PluginRegister plugins = PluginRegister.Singleton; + + IArchive format = null; + + // Check all but RAW plugin + foreach(IArchive plugin in plugins.Archives.Values) + { + if(plugin is null) continue; + + try + { + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Trying_plugin_0, plugin.Name); + + if(!plugin.Identify(archiveFilter)) continue; + + format = plugin; + + break; + } +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body + catch + { + // ignored + } + } + + // Not recognized + return format; + } + catch + { + return null; + } + } +} \ No newline at end of file diff --git a/Aaru.Gui/ResourceHandler.cs b/Aaru.Core/ArchiveInfo.cs similarity index 56% rename from Aaru.Gui/ResourceHandler.cs rename to Aaru.Core/ArchiveInfo.cs index 887a5c22c..d0a7efe85 100644 --- a/Aaru.Gui/ResourceHandler.cs +++ b/Aaru.Core/ArchiveInfo.cs @@ -1,15 +1,15 @@ -// /*************************************************************************** +// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : ResourceHandler.cs +// Filename : ArchiveInfo.cs // Author(s) : Natalia Portillo // -// Component : Aaru GUI. +// Component : Core algorithms. // // --[ Description ] ---------------------------------------------------------- // -// Handles embedded resources. +// Prints image information to console. // // --[ License ] -------------------------------------------------------------- // @@ -27,18 +27,29 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Gui; +using System.Text; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Spectre.Console; -using System.IO; -using System.Reflection; -using JetBrains.Annotations; +namespace Aaru.Core; -static class ResourceHandler +/// Image information operations +public static class ArchiveInfo { - [CanBeNull] - internal static Stream GetResourceStream([NotNull] string resourcePath) => - Assembly.GetExecutingAssembly().GetManifestResourceStream(resourcePath); + /// Prints archive information to console + /// Archive + public static void PrintArchiveInfo(IArchive imageFormat, IFilter filter, Encoding encoding) + { + AaruConsole.WriteLine(Localization.Core.Archive_Information_With_Markup); + + imageFormat.GetInformation(filter, encoding, out string information); + + AaruConsole.WriteLine(Markup.Escape(information)); + + AaruConsole.WriteLine(); + } } \ No newline at end of file diff --git a/Aaru.Core/Checksum.cs b/Aaru.Core/Checksum.cs index 4afa8972b..89693173b 100644 --- a/Aaru.Core/Checksum.cs +++ b/Aaru.Core/Checksum.cs @@ -27,17 +27,17 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; using System.Collections.Generic; using System.Threading; using Aaru.Checksums; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Interfaces; -using Schemas; + +namespace Aaru.Core; /// Enabled checksums [Flags] @@ -130,7 +130,7 @@ public sealed class Checksum if(enabled.HasFlag(EnableChecksum.Crc16)) { - _crc16Ctx = new CRC16IBMContext(); + _crc16Ctx = new CRC16IbmContext(); _crc16Pkt = new HashPacket { @@ -341,187 +341,149 @@ public sealed class Checksum _f16Thread.IsAlive || _f32Thread.IsAlive) {} - if(_enabled.HasFlag(EnableChecksum.Adler32)) - _adlerThread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Adler32)) _adlerThread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.Crc16)) - _crc16Thread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Crc16)) _crc16Thread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.Crc32)) - _crc32Thread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Crc32)) _crc32Thread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.Crc16)) - _crc64Thread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Crc16)) _crc64Thread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.Md5)) - _md5Thread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Md5)) _md5Thread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.Sha1)) - _sha1Thread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Sha1)) _sha1Thread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.Sha256)) - _sha256Thread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Sha256)) _sha256Thread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.Sha384)) - _sha384Thread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Sha384)) _sha384Thread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.Sha512)) - _sha512Thread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Sha512)) _sha512Thread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.SpamSum)) - _spamsumThread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.SpamSum)) _spamsumThread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.Fletcher16)) - _f16Thread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Fletcher16)) _f16Thread = new Thread(UpdateHash); - if(_enabled.HasFlag(EnableChecksum.Fletcher32)) - _f32Thread = new Thread(UpdateHash); + if(_enabled.HasFlag(EnableChecksum.Fletcher32)) _f32Thread = new Thread(UpdateHash); } /// Finishes the checksums /// Returns the checksum results - public List End() + public List End() { - var chks = new List(); + List chks = []; - ChecksumType chk; - - if(_enabled.HasFlag(EnableChecksum.All)) + if(_enabled.HasFlag(EnableChecksum.Adler32)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.adler32, + Type = ChecksumType.Adler32, Value = _adler32Ctx.End() - }; - - chks.Add(chk); + }); } if(_enabled.HasFlag(EnableChecksum.Crc16)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.crc16, + Type = ChecksumType.CRC16, Value = _crc16Ctx.End() - }; - - chks.Add(chk); + }); } if(_enabled.HasFlag(EnableChecksum.Crc32)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.crc32, + Type = ChecksumType.CRC32, Value = _crc32Ctx.End() - }; - - chks.Add(chk); + }); } if(_enabled.HasFlag(EnableChecksum.Crc64)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.crc64, + Type = ChecksumType.CRC64, Value = _crc64Ctx.End() - }; - - chks.Add(chk); + }); } if(_enabled.HasFlag(EnableChecksum.Md5)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.md5, + Type = ChecksumType.Md5, Value = _md5Ctx.End() - }; - - chks.Add(chk); + }); } if(_enabled.HasFlag(EnableChecksum.Sha1)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.sha1, + Type = ChecksumType.Sha1, Value = _sha1Ctx.End() - }; - - chks.Add(chk); + }); } if(_enabled.HasFlag(EnableChecksum.Sha256)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.sha256, + Type = ChecksumType.Sha256, Value = _sha256Ctx.End() - }; - - chks.Add(chk); + }); } if(_enabled.HasFlag(EnableChecksum.Sha384)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.sha384, + Type = ChecksumType.Sha384, Value = _sha384Ctx.End() - }; - - chks.Add(chk); + }); } if(_enabled.HasFlag(EnableChecksum.Sha512)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.sha512, + Type = ChecksumType.Sha512, Value = _sha512Ctx.End() - }; - - chks.Add(chk); + }); } if(_enabled.HasFlag(EnableChecksum.SpamSum)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.spamsum, + Type = ChecksumType.SpamSum, Value = _ssCtx.End() - }; - - chks.Add(chk); + }); } if(_enabled.HasFlag(EnableChecksum.Fletcher16)) { - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.fletcher16, + Type = ChecksumType.Fletcher16, Value = _f16Ctx.End() - }; - - chks.Add(chk); + }); } - if(!_enabled.HasFlag(EnableChecksum.Fletcher32)) - return chks; + if(!_enabled.HasFlag(EnableChecksum.Fletcher32)) return chks; - chk = new ChecksumType + chks.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.fletcher32, + Type = ChecksumType.Fletcher32, Value = _f32Ctx.End() - }; - - chks.Add(chk); + }); return chks; } - internal static List GetChecksums(byte[] data, EnableChecksum enabled = EnableChecksum.All) + internal static List GetChecksums( + byte[] data, EnableChecksum enabled = EnableChecksum.All) { IChecksum adler32CtxData = null; IChecksum crc16CtxData = null; @@ -564,7 +526,7 @@ public sealed class Checksum if(enabled.HasFlag(EnableChecksum.Crc16)) { - crc16CtxData = new CRC16IBMContext(); + crc16CtxData = new CRC16IbmContext(); var crc16PktData = new HashPacket { @@ -718,145 +680,120 @@ public sealed class Checksum f16ThreadData.IsAlive || f32ThreadData.IsAlive) {} - var dataChecksums = new List(); - ChecksumType chk; + List dataChecksums = []; if(enabled.HasFlag(EnableChecksum.Adler32)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.adler32, + Type = ChecksumType.Adler32, Value = adler32CtxData.End() - }; - - dataChecksums.Add(chk); + }); } if(enabled.HasFlag(EnableChecksum.Crc16)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.crc16, + Type = ChecksumType.CRC16, Value = crc16CtxData.End() - }; - - dataChecksums.Add(chk); + }); } if(enabled.HasFlag(EnableChecksum.Crc32)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.crc32, + Type = ChecksumType.CRC32, Value = crc32CtxData.End() - }; - - dataChecksums.Add(chk); + }); } if(enabled.HasFlag(EnableChecksum.Crc64)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.crc64, + Type = ChecksumType.CRC64, Value = crc64CtxData.End() - }; - - dataChecksums.Add(chk); + }); } if(enabled.HasFlag(EnableChecksum.Md5)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.md5, + Type = ChecksumType.Md5, Value = md5CtxData.End() - }; - - dataChecksums.Add(chk); + }); } if(enabled.HasFlag(EnableChecksum.Sha1)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.sha1, + Type = ChecksumType.Sha1, Value = sha1CtxData.End() - }; - - dataChecksums.Add(chk); + }); } if(enabled.HasFlag(EnableChecksum.Sha256)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.sha256, + Type = ChecksumType.Sha256, Value = sha256CtxData.End() - }; - - dataChecksums.Add(chk); + }); } if(enabled.HasFlag(EnableChecksum.Sha384)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.sha384, + Type = ChecksumType.Sha384, Value = sha384CtxData.End() - }; - - dataChecksums.Add(chk); + }); } if(enabled.HasFlag(EnableChecksum.Sha512)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.sha512, + Type = ChecksumType.Sha512, Value = sha512CtxData.End() - }; - - dataChecksums.Add(chk); + }); } if(enabled.HasFlag(EnableChecksum.SpamSum)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.spamsum, + Type = ChecksumType.SpamSum, Value = ssctxData.End() - }; - - dataChecksums.Add(chk); + }); } if(enabled.HasFlag(EnableChecksum.Fletcher16)) { - chk = new ChecksumType + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - type = ChecksumTypeType.fletcher16, + Type = ChecksumType.Fletcher16, Value = f16CtxData.End() - }; - - dataChecksums.Add(chk); + }); } - if(enabled.HasFlag(EnableChecksum.Fletcher32)) + if(!enabled.HasFlag(EnableChecksum.Fletcher32)) return dataChecksums; + + dataChecksums.Add(new CommonTypes.AaruMetadata.Checksum { - chk = new ChecksumType - { - type = ChecksumTypeType.fletcher32, - Value = f32CtxData.End() - }; - - dataChecksums.Add(chk); - } + Type = ChecksumType.Fletcher32, + Value = f32CtxData.End() + }); return dataChecksums; } - #region Threading helpers +#region Threading helpers + struct HashPacket { public IChecksum Context; @@ -864,5 +801,6 @@ public sealed class Checksum } static void UpdateHash(object packet) => ((HashPacket)packet).Context.Update(((HashPacket)packet).Data); - #endregion Threading helpers + +#endregion Threading helpers } \ No newline at end of file diff --git a/Aaru.Core/DataFile.cs b/Aaru.Core/DataFile.cs index 609c11eb3..6d1487f82 100644 --- a/Aaru.Core/DataFile.cs +++ b/Aaru.Core/DataFile.cs @@ -27,17 +27,19 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System.Diagnostics.CodeAnalysis; using System.IO; using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Core; /// Abstracts a datafile with a block based interface -[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global"), SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] public sealed class DataFile { readonly FileStream _dataFs; @@ -47,6 +49,9 @@ public sealed class DataFile public DataFile(string outputFile) => _dataFs = new FileStream(outputFile, FileMode.OpenOrCreate, FileAccess.ReadWrite); + /// Current file position + public long Position => _dataFs.Position; + /// Closes the file public void Close() => _dataFs?.Close(); @@ -55,7 +60,7 @@ public sealed class DataFile /// Offset of where data will be read /// How many bytes to read /// How many bytes were read - public int Read(byte[] array, int offset, int count) => _dataFs.Read(array, offset, count); + public int Read(byte[] array, int offset, int count) => _dataFs.EnsureRead(array, offset, count); /// Seeks to the specified block /// Block to seek to @@ -103,9 +108,6 @@ public sealed class DataFile _dataFs.Write(data, offset, count); } - /// Current file position - public long Position => _dataFs.Position; - /// Writes data to a newly created file /// Who asked the file to be written (class, plugin, etc.) /// Data to write @@ -114,8 +116,7 @@ public sealed class DataFile /// What is the data about? public static void WriteTo(string who, string outputPrefix, string outputSuffix, string whatWriting, byte[] data) { - if(!string.IsNullOrEmpty(outputPrefix) && - !string.IsNullOrEmpty(outputSuffix)) + if(!string.IsNullOrEmpty(outputPrefix) && !string.IsNullOrEmpty(outputSuffix)) WriteTo(who, outputPrefix + outputSuffix, data, whatWriting); } @@ -126,31 +127,32 @@ public sealed class DataFile /// What is the data about? /// If set to true overwrites the file, does nothing otherwise public static void WriteTo(string who, string filename, byte[] data, string whatWriting = null, - bool overwrite = false) + bool overwrite = false) { - if(string.IsNullOrEmpty(filename)) - return; + if(string.IsNullOrEmpty(filename)) return; if(File.Exists(filename)) + { if(overwrite) File.Delete(filename); else { - AaruConsole.ErrorWriteLine("Not overwriting file {0}", filename); + AaruConsole.ErrorWriteLine(Localization.Core.Not_overwriting_file_0, filename); return; } + } try { - AaruConsole.DebugWriteLine(who, "Writing " + whatWriting + " to {0}", filename); + AaruConsole.DebugWriteLine(who, string.Format(Localization.Core.Writing_0_to_1, whatWriting, filename)); var outputFs = new FileStream(filename, FileMode.CreateNew); outputFs.Write(data, 0, data.Length); outputFs.Close(); } catch { - AaruConsole.ErrorWriteLine("Unable to write file {0}", filename); + AaruConsole.ErrorWriteLine(Localization.Core.Unable_to_write_file_0, filename); } } } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/ATA.cs b/Aaru.Core/Devices/Dumping/ATA.cs index 2660879df..6d56f3b1a 100644 --- a/Aaru.Core/Devices/Dumping/ATA.cs +++ b/Aaru.Core/Devices/Dumping/ATA.cs @@ -27,41 +27,42 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Xml.Serialization; +using System.Text.Json; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs; using Aaru.Core.Devices.Report; +using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.ATA; using Aaru.Decoders.PCMCIA; -using Schemas; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; using Identify = Aaru.CommonTypes.Structs.Devices.ATA.Identify; using Tuple = Aaru.Decoders.PCMCIA.Tuple; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Devices.Dumping; + /// Implements dumping ATA devices public partial class Dump { /// Dumps an ATA device void Ata() { - bool recoveredError; - if(_outputPlugin is not IWritableImage outputFormat) { - StoppingErrorMessage?.Invoke("Image is not writable, aborting..."); + StoppingErrorMessage?.Invoke(Localization.Core.Image_is_not_writable_aborting); return; } @@ -69,10 +70,10 @@ public partial class Dump if(_dumpRaw) { if(_force) - ErrorMessage?.Invoke("Raw dumping not yet supported in ATA devices, continuing..."); + ErrorMessage?.Invoke(Localization.Core.Raw_dumping_not_yet_supported_in_ATA_devices_continuing); else { - StoppingErrorMessage?.Invoke("Raw dumping not yet supported in ATA devices, aborting..."); + StoppingErrorMessage?.Invoke(Localization.Core.Raw_dumping_not_yet_supported_in_ATA_devices_aborting); return; } @@ -83,8 +84,8 @@ public partial class Dump double imageWriteDuration = 0; MediaType mediaType = MediaType.Unknown; - UpdateStatus?.Invoke("Requesting ATA IDENTIFY DEVICE."); - _dumpLog.WriteLine("Requesting ATA IDENTIFY DEVICE."); + UpdateStatus?.Invoke(Localization.Core.Requesting_ATA_IDENTIFY_DEVICE); + _dumpLog.WriteLine(Localization.Core.Requesting_ATA_IDENTIFY_DEVICE); bool sense = _dev.AtaIdentify(out byte[] cmdBuf, out AtaErrorRegistersChs errorChs); if(sense) @@ -95,20 +96,18 @@ public partial class Dump if(ataIdNullable != null) { - Identify.IdentifyDevice ataId = ataIdNullable.Value; - byte[] ataIdentify = cmdBuf; - cmdBuf = Array.Empty(); - - DateTime start; - DateTime end; - double totalDuration = 0; - double currentSpeed = 0; - double maxSpeed = double.MinValue; - double minSpeed = double.MaxValue; + // Guaranteed to never fall into default + Identify.IdentifyDevice ataId = ataIdNullable ?? default(Identify.IdentifyDevice); + byte[] ataIdentify = cmdBuf; + double totalDuration = 0; + double currentSpeed = 0; + double maxSpeed = double.MinValue; + double minSpeed = double.MaxValue; + cmdBuf = []; // Initialize reader - UpdateStatus?.Invoke("Initializing reader."); - _dumpLog.WriteLine("Initializing reader."); + UpdateStatus?.Invoke(Localization.Core.Initializing_reader); + _dumpLog.WriteLine(Localization.Core.Initializing_reader); var ataReader = new Reader(_dev, timeout, ataIdentify, _errorLog); // Fill reader blocks @@ -117,7 +116,7 @@ public partial class Dump // Check block sizes if(ataReader.GetBlockSize()) { - _dumpLog.WriteLine("ERROR: Cannot get block size: {0}.", ataReader.ErrorMessage); + _dumpLog.WriteLine(Localization.Core.ERROR_Cannot_get_block_size_0, ataReader.ErrorMessage); ErrorMessage(ataReader.ErrorMessage); return; @@ -128,7 +127,9 @@ public partial class Dump if(ataReader.FindReadCommand()) { - _dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", ataReader.ErrorMessage); + _dumpLog.WriteLine(Localization.Core.ERROR_Cannot_find_correct_read_command_0, + ataReader.ErrorMessage); + ErrorMessage(ataReader.ErrorMessage); return; @@ -137,7 +138,7 @@ public partial class Dump // Check how many blocks to read, if error show and return if(ataReader.GetBlocksToRead(_maximumReadable)) { - _dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", ataReader.ErrorMessage); + _dumpLog.WriteLine(Localization.Core.ERROR_Cannot_get_blocks_to_read_0, ataReader.ErrorMessage); ErrorMessage(ataReader.ErrorMessage); return; @@ -148,37 +149,58 @@ public partial class Dump byte heads = ataReader.Heads; byte sectors = ataReader.Sectors; - UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes)."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_blocks_1_bytes, + blocks, + blocks * blockSize)); - UpdateStatus?. - Invoke($"Device reports {cylinders} cylinders {heads} heads {sectors} sectors per track."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Device_reports_0_cylinders_1_heads_2_sectors_per_track, + cylinders, + heads, + sectors)); - UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time."); - UpdateStatus?.Invoke($"Device reports {blockSize} bytes per logical block."); - UpdateStatus?.Invoke($"Device reports {physicalSectorSize} bytes per physical block."); - _dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead)); - _dumpLog.WriteLine("Device reports {0} cylinders {1} heads {2} sectors per track.", cylinders, heads, + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_bytes_per_logical_block, + blockSize)); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_bytes_per_physical_block, + physicalSectorSize)); + + _dumpLog.WriteLine(Localization.Core.Device_reports_0_blocks_1_bytes, blocks, blocks * blockSize); + + _dumpLog.WriteLine(Localization.Core.Device_reports_0_cylinders_1_heads_2_sectors_per_track, + cylinders, + heads, sectors); - _dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead); - _dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize); - _dumpLog.WriteLine("Device reports {0} bytes per physical block.", physicalSectorSize); + _dumpLog.WriteLine(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_bytes_per_physical_block, physicalSectorSize); bool removable = !_dev.IsCompactFlash && ataId.GeneralConfiguration.HasFlag(Identify.GeneralConfigurationBit.Removable); - DumpHardwareType currentTry = null; - ExtentsULong extents = null; + DumpHardware currentTry = null; + ExtentsULong extents = null; - ResumeSupport.Process(ataReader.IsLba, removable, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial, - _dev.PlatformId, ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision, - _private, _force); + ResumeSupport.Process(ataReader.IsLba, + removable, + blocks, + _dev.Manufacturer, + _dev.Model, + _dev.Serial, + _dev.PlatformId, + ref _resume, + ref currentTry, + ref extents, + _dev.FirmwareRevision, + _private, + _force); - if(currentTry == null || - extents == null) + if(currentTry == null || extents == null) { - StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_process_resume_file_not_continuing); return; } @@ -194,8 +216,8 @@ public partial class Dump !outputFormat.SupportedMediaTags.Contains(MediaTagType.USB_Descriptors)) { ret = false; - _dumpLog.WriteLine("Output format does not support USB descriptors."); - ErrorMessage("Output format does not support USB descriptors."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_USB_descriptors); + ErrorMessage(Localization.Core.Output_format_does_not_support_USB_descriptors); } if(_dev.IsPcmcia && @@ -203,43 +225,50 @@ public partial class Dump !outputFormat.SupportedMediaTags.Contains(MediaTagType.PCMCIA_CIS)) { ret = false; - _dumpLog.WriteLine("Output format does not support PCMCIA CIS descriptors."); - ErrorMessage("Output format does not support PCMCIA CIS descriptors."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_PCMCIA_CIS_descriptors); + ErrorMessage(Localization.Core.Output_format_does_not_support_PCMCIA_CIS_descriptors); } if(!outputFormat.SupportedMediaTags.Contains(MediaTagType.ATA_IDENTIFY)) { ret = false; - _dumpLog.WriteLine("Output format does not support ATA IDENTIFY."); - ErrorMessage("Output format does not support ATA IDENTIFY."); + _dumpLog.WriteLine(Localization.Core.Dump_Ata_Output_format_does_not_support_ATA_IDENTIFY_); + ErrorMessage(Localization.Core.Dump_Ata_Output_format_does_not_support_ATA_IDENTIFY_); } if(!ret) { - _dumpLog.WriteLine("Several media tags not supported, {0}continuing...", _force ? "" : "not "); - if(_force) - ErrorMessage("Several media tags not supported, continuing..."); + { + _dumpLog.WriteLine(Localization.Core.Several_media_tags_not_supported_continuing); + ErrorMessage(Localization.Core.Several_media_tags_not_supported_continuing); + } else { - StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Several_media_tags_not_supported_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Several_media_tags_not_supported_not_continuing); return; } } - mediaType = MediaTypeFromDevice.GetFromAta(_dev.Manufacturer, _dev.Model, _dev.IsRemovable, - _dev.IsCompactFlash, _dev.IsPcmcia, blocks); + mediaType = MediaTypeFromDevice.GetFromAta(_dev.Manufacturer, + _dev.Model, + _dev.IsRemovable, + _dev.IsCompactFlash, + _dev.IsPcmcia, + blocks); ret = outputFormat.Create(_outputPath, mediaType, _formatOptions, blocks, blockSize); // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputFormat.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -248,29 +277,53 @@ public partial class Dump // Setting geometry outputFormat.SetGeometry(cylinders, heads, sectors); + bool recoveredError; + if(ataReader.IsLba) { - UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time, blocksToRead)); - if(_skip < blocksToRead) - _skip = blocksToRead; + if(_skip < blocksToRead) _skip = blocksToRead; - mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, - _private); + mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", + _dev, + blocks, + blockSize, + blocksToRead, + _private, + _dimensions); ibgLog = new IbgLog(_outputPrefix + ".ibg", ataProfile); if(_resume.NextBlock > 0) { - UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}."); - _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); + UpdateStatus?.Invoke(string.Format(Localization.Core.Resuming_from_block_0, _resume.NextBlock)); + _dumpLog.WriteLine(Localization.Core.Resuming_from_block_0, _resume.NextBlock); + } + + if(_createGraph) + { + Spiral.DiscParameters discSpiralParameters = Spiral.DiscParametersFromMediaType(mediaType); + + if(discSpiralParameters is not null) + _mediaGraph = new Spiral((int)_dimensions, (int)_dimensions, discSpiralParameters, blocks); + else + _mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, blocks); + + if(_mediaGraph is not null) + { + foreach(Tuple e in extents.ToArray()) + _mediaGraph?.PaintSectorsGood(e.Item1, (uint)(e.Item2 - e.Item1 + 2)); + } + + _mediaGraph?.PaintSectorsBad(_resume.BadBlocks); } var newTrim = false; - start = DateTime.UtcNow; - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _dumpStopwatch.Restart(); + _speedStopwatch.Reset(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead) @@ -278,103 +331,121 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(blocks - i < blocksToRead) - blocksToRead = (byte)(blocks - i); + if(blocks - i < blocksToRead) blocksToRead = (byte)(blocks - i); - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed) + .Per(_oneSecond) + .Humanize()), + (long)i, (long)blocks); + _speedStopwatch.Start(); bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration, out _, out _); + _speedStopwatch.Stop(); + + _writeStopwatch.Restart(); if(!error) { - mhddLog.Write(i, duration); + mhddLog.Write(i, duration, blocksToRead); ibgLog.Write(i, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; outputFormat.WriteSectors(cmdBuf, i, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(i, blocksToRead, true); + _mediaGraph?.PaintSectorsGood(i, blocksToRead); } else { - if(i + _skip > blocks) - _skip = (uint)(blocks - i); + if(i + _skip > blocks) _skip = (uint)(blocks - i); - for(ulong b = i; b < i + _skip; b++) - _resume.BadBlocks.Add(b); + for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b); - mhddLog.Write(i, duration < 500 ? 65535 : duration); + mhddLog.Write(i, duration < 500 ? 65535 : duration, _skip); ibgLog.Write(i, 0); - DateTime writeStart = DateTime.Now; outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i); i += _skip - blocksToRead; newTrim = true; } + _writeStopwatch.Stop(); + sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } + _speedStopwatch.Stop(); + _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); - end = DateTime.Now; + _dumpStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), _devicePath); + ibgLog.Close(_dev, + blocks, + blockSize, + _dumpStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), + _devicePath); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize()); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - #region Trimming - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _trim && - newTrim) +#region Trimming + + if(_resume.BadBlocks.Count > 0 && !_aborted && _trim && newTrim) { - start = DateTime.UtcNow; - UpdateStatus?.Invoke("Trimming skipped sectors"); - _dumpLog.WriteLine("Trimming skipped sectors"); + _trimStopwatch.Restart(); + UpdateStatus?.Invoke(Localization.Core.Trimming_skipped_sectors); + _dumpLog.WriteLine(Localization.Core.Trimming_skipped_sectors); ulong[] tmpArray = _resume.BadBlocks.ToArray(); InitProgress?.Invoke(); @@ -384,38 +455,42 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke($"Trimming sector {badSector}"); + PulseProgress?.Invoke(string.Format(Localization.Core.Trimming_sector_0, badSector)); bool error = ataReader.ReadBlock(out cmdBuf, badSector, out duration, out recoveredError, out _); totalDuration += duration; - if(error && !recoveredError) - continue; + if(error && !recoveredError) continue; _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(cmdBuf, badSector); + _mediaGraph?.PaintSectorGood(badSector); } EndProgress?.Invoke(); - end = DateTime.UtcNow; - UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds."); - _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds); - } - #endregion Trimming + _trimStopwatch.Stop(); - #region Error handling - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _retryPasses > 0) + UpdateStatus?.Invoke(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + } + +#endregion Trimming + +#region Error handling + + if(_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0) { var pass = 1; var forward = true; @@ -429,15 +504,36 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, - pass, forward ? "forward" : "reverse", - _persistent ? "recovering partial data, " : "")); + if(forward) + { + PulseProgress?.Invoke(_persistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_forward, + badSector, + pass) + : string.Format(Localization.Core + .Retrying_sector_0_pass_1_forward, + badSector, + pass)); + } + else + { + PulseProgress?.Invoke(_persistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_reverse, + badSector, + pass) + : string.Format(Localization.Core + .Retrying_sector_0_pass_1_reverse, + badSector, + pass)); + } bool error = ataReader.ReadBlock(out cmdBuf, badSector, out duration, out recoveredError, out _); @@ -449,45 +545,73 @@ public partial class Dump _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(cmdBuf, badSector); - UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}."); - _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); + _mediaGraph?.PaintSectorGood(badSector); + + UpdateStatus?.Invoke(string.Format(Localization.Core + .Correctly_retried_block_0_in_pass_1, + badSector, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_block_0_in_pass_1, + badSector, + pass); } - else if(_persistent) - outputFormat.WriteSector(cmdBuf, badSector); + else if(_persistent) outputFormat.WriteSector(cmdBuf, badSector); } - if(pass < _retryPasses && - !_aborted && - _resume.BadBlocks.Count > 0) + if(pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); - if(!forward) - _resume.BadBlocks.Reverse(); + if(!forward) _resume.BadBlocks.Reverse(); goto repeatRetryLba; } EndProgress?.Invoke(); } - #endregion Error handling LBA + +#endregion Error handling LBA currentTry.Extents = ExtentsConverter.ToMetadata(extents); } else { - mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, - _private); + mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", + _dev, + blocks, + blockSize, + blocksToRead, + _private, + _dimensions); ibgLog = new IbgLog(_outputPrefix + ".ibg", ataProfile); + if(_createGraph) + { + Spiral.DiscParameters discSpiralParameters = Spiral.DiscParametersFromMediaType(mediaType); + + if(discSpiralParameters is not null) + _mediaGraph = new Spiral((int)_dimensions, (int)_dimensions, discSpiralParameters, blocks); + else + _mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, blocks); + + if(_mediaGraph is not null) + { + foreach(Tuple e in extents.ToArray()) + _mediaGraph?.PaintSectorsGood(e.Item1, (uint)(e.Item2 - e.Item1 + 2)); + } + + _mediaGraph?.PaintSectorsBad(_resume.BadBlocks); + } + ulong currentBlock = 0; blocks = (ulong)(cylinders * heads * sectors); - start = DateTime.UtcNow; - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _dumpStopwatch.Restart(); + _speedStopwatch.Reset(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ushort cy = 0; cy < cylinders; cy++) @@ -499,40 +623,51 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - PulseProgress?. - Invoke($"Reading cylinder {cy} head {hd} sector {sc} ({currentSpeed:F3} MiB/sec.)"); + PulseProgress?.Invoke(string.Format(Localization.Core + .Reading_cylinder_0_head_1_sector_2_3, + cy, + hd, + sc, + ByteSize.FromMegabytes(currentSpeed) + .Per(_oneSecond) + .Humanize())); + + _speedStopwatch.Start(); bool error = ataReader.ReadChs(out cmdBuf, cy, hd, sc, out duration, out recoveredError); + _speedStopwatch.Stop(); + totalDuration += duration; + _writeStopwatch.Restart(); + if(!error || recoveredError) { mhddLog.Write(currentBlock, duration); ibgLog.Write(currentBlock, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; outputFormat.WriteSector(cmdBuf, (ulong)((cy * heads + hd) * sectors + (sc - 1))); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(currentBlock); + _mediaGraph?.PaintSectorGood((ulong)((cy * heads + hd) * sectors + (sc - 1))); - _dumpLog.WriteLine("Error reading cylinder {0} head {1} sector {2}.", cy, hd, sc); + _dumpLog.WriteLine(Localization.Core.Error_reading_cylinder_0_head_1_sector_2, + cy, + hd, + sc); } else { @@ -540,86 +675,108 @@ public partial class Dump mhddLog.Write(currentBlock, duration < 500 ? 65535 : duration); ibgLog.Write(currentBlock, 0); - DateTime writeStart = DateTime.Now; outputFormat.WriteSector(new byte[blockSize], (ulong)((cy * heads + hd) * sectors + (sc - 1))); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; } + _writeStopwatch.Stop(); + sectorSpeedStart++; currentBlock++; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } } } + _speedStopwatch.Stop(); _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); - end = DateTime.Now; + _dumpStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), _devicePath); + ibgLog.Close(_dev, + blocks, + blockSize, + _dumpStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), + _devicePath); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {blockSize * (double)(blocks + 1) / 1024 / (imageWriteDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize()); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (imageWriteDuration / 1000)); + _dumpLog.WriteLine(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize()); } foreach(ulong bad in _resume.BadBlocks) - _dumpLog.WriteLine("Sector {0} could not be read.", bad); + _dumpLog.WriteLine(Localization.Core.Sector_0_could_not_be_read, bad); outputFormat.SetDumpHardware(_resume.Tries); // TODO: Non-removable - var metadata = new ImageInfo + var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; - if(!outputFormat.SetMetadata(metadata)) - ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + + if(!outputFormat.SetImageInfo(metadata)) + { + ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + + Environment.NewLine + outputFormat.ErrorMessage); + } - if(_preSidecar != null) - outputFormat.SetCicmMetadata(_preSidecar); + if(_preSidecar != null) outputFormat.SetMetadata(_preSidecar); - _dumpLog.WriteLine("Closing output file."); - UpdateStatus?.Invoke("Closing output file."); - DateTime closeStart = DateTime.Now; + _dumpLog.WriteLine(Localization.Core.Closing_output_file); + UpdateStatus?.Invoke(Localization.Core.Closing_output_file); + _imageCloseStopwatch.Restart(); outputFormat.Close(); - DateTime closeEnd = DateTime.Now; - UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); - _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); + _imageCloseStopwatch.Stop(); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); if(_aborted) { - _dumpLog.WriteLine("Aborted!"); - UpdateStatus?.Invoke("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); + UpdateStatus?.Invoke(Localization.Core.Aborted); return; } @@ -628,31 +785,28 @@ public partial class Dump outputFormat.WriteMediaTag(ataIdentify, MediaTagType.ATA_IDENTIFY); - if(_dev.IsUsb && - _dev.UsbDescriptors != null) + if(_dev.IsUsb && _dev.UsbDescriptors != null) outputFormat.WriteMediaTag(_dev.UsbDescriptors, MediaTagType.USB_Descriptors); - if(_dev.IsPcmcia && - _dev.Cis != null) - outputFormat.WriteMediaTag(_dev.Cis, MediaTagType.PCMCIA_CIS); + if(_dev.IsPcmcia && _dev.Cis != null) outputFormat.WriteMediaTag(_dev.Cis, MediaTagType.PCMCIA_CIS); if(_metadata) { - _dumpLog.WriteLine("Creating sidecar."); - UpdateStatus?.Invoke("Creating sidecar."); - var filters = new FiltersList(); - IFilter filter = filters.GetFilter(_outputPath); + _dumpLog.WriteLine(Localization.Core.Creating_sidecar); + UpdateStatus?.Invoke(Localization.Core.Creating_sidecar); + IFilter filter = PluginRegister.Singleton.GetFilter(_outputPath); var inputPlugin = ImageFormat.Detect(filter) as IMediaImage; ErrorNumber opened = inputPlugin.Open(filter); if(opened != ErrorNumber.NoError) { - StoppingErrorMessage?.Invoke($"Error {opened} opening created image."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_0_opening_created_image, + opened)); return; } - DateTime chkStart = DateTime.UtcNow; + _sidecarStopwatch.Restart(); _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); @@ -663,57 +817,57 @@ public partial class Dump _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; - CICMMetadataType sidecar = _sidecarClass.Create(); + Metadata sidecar = _sidecarClass.Create(); if(!_aborted) { if(_preSidecar != null) { - _preSidecar.BlockMedia = sidecar.BlockMedia; - sidecar = _preSidecar; + _preSidecar.BlockMedias = sidecar.BlockMedias; + sidecar = _preSidecar; } - if(_dev.IsUsb && - _dev.UsbDescriptors != null) + if(_dev.IsUsb && _dev.UsbDescriptors != null) { - _dumpLog.WriteLine("Reading USB descriptors."); - UpdateStatus?.Invoke("Reading USB descriptors."); + _dumpLog.WriteLine(Localization.Core.Reading_USB_descriptors); + UpdateStatus?.Invoke(Localization.Core.Reading_USB_descriptors); - sidecar.BlockMedia[0].USB = new USBType + sidecar.BlockMedias[0].Usb = new Usb { ProductID = _dev.UsbProductId, VendorID = _dev.UsbVendorId, - Descriptors = new DumpType + Descriptors = new CommonTypes.AaruMetadata.Dump { Image = _outputPath, Size = (ulong)_dev.UsbDescriptors.Length, - Checksums = Checksum.GetChecksums(_dev.UsbDescriptors).ToArray() + Checksums = Checksum.GetChecksums(_dev.UsbDescriptors) } }; } - if(_dev.IsPcmcia && - _dev.Cis != null) + if(_dev.IsPcmcia && _dev.Cis != null) { - _dumpLog.WriteLine("Reading PCMCIA CIS."); - UpdateStatus?.Invoke("Reading PCMCIA CIS."); + _dumpLog.WriteLine(Localization.Core.Reading_PCMCIA_CIS); + UpdateStatus?.Invoke(Localization.Core.Reading_PCMCIA_CIS); - sidecar.BlockMedia[0].PCMCIA = new PCMCIAType + sidecar.BlockMedias[0].Pcmcia = new Pcmcia { - CIS = new DumpType + Cis = new CommonTypes.AaruMetadata.Dump { Image = _outputPath, Size = (ulong)_dev.Cis.Length, - Checksums = Checksum.GetChecksums(_dev.Cis).ToArray() + Checksums = Checksum.GetChecksums(_dev.Cis) } }; - _dumpLog.WriteLine("Decoding PCMCIA CIS."); - UpdateStatus?.Invoke("Decoding PCMCIA CIS."); + _dumpLog.WriteLine(Localization.Core.Decoding_PCMCIA_CIS); + UpdateStatus?.Invoke(Localization.Core.Decoding_PCMCIA_CIS); Tuple[] tuples = CIS.GetTuples(_dev.Cis); if(tuples != null) + { foreach(Tuple tuple in tuples) + { switch(tuple.Code) { case TupleCodes.CISTPL_MANFID: @@ -722,12 +876,10 @@ public partial class Dump if(manufacturerId != null) { - sidecar.BlockMedia[0].PCMCIA.ManufacturerCode = + sidecar.BlockMedias[0].Pcmcia.ManufacturerCode = manufacturerId.ManufacturerID; - sidecar.BlockMedia[0].PCMCIA.CardCode = manufacturerId.CardID; - sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true; - sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true; + sidecar.BlockMedias[0].Pcmcia.CardCode = manufacturerId.CardID; } break; @@ -736,125 +888,155 @@ public partial class Dump if(version != null) { - sidecar.BlockMedia[0].PCMCIA.Manufacturer = version.Manufacturer; - sidecar.BlockMedia[0].PCMCIA.ProductName = version.Product; + sidecar.BlockMedias[0].Pcmcia.Manufacturer = version.Manufacturer; + sidecar.BlockMedias[0].Pcmcia.ProductName = version.Product; - sidecar.BlockMedia[0].PCMCIA.Compliance = + sidecar.BlockMedias[0].Pcmcia.Compliance = $"{version.MajorVersion}.{version.MinorVersion}"; - sidecar.BlockMedia[0].PCMCIA.AdditionalInformation = - version.AdditionalInformation; + sidecar.BlockMedias[0].Pcmcia.AdditionalInformation = + [ + ..version.AdditionalInformation + ]; } break; } + } + } } - if(_private) - DeviceReport.ClearIdentify(ataIdentify); + if(_private) DeviceReport.ClearIdentify(ataIdentify); - sidecar.BlockMedia[0].ATA = new ATAType + sidecar.BlockMedias[0].ATA = new ATA { - Identify = new DumpType + Identify = new CommonTypes.AaruMetadata.Dump { Image = _outputPath, Size = (ulong)cmdBuf.Length, - Checksums = Checksum.GetChecksums(cmdBuf).ToArray() + Checksums = Checksum.GetChecksums(cmdBuf) } }; - DateTime chkEnd = DateTime.UtcNow; + _sidecarStopwatch.Stop(); - totalChkDuration = (chkEnd - chkStart).TotalMilliseconds; - UpdateStatus?.Invoke($"Sidecar created in {(chkEnd - chkStart).TotalSeconds} seconds."); + totalChkDuration = _sidecarStopwatch.Elapsed.TotalMilliseconds; - UpdateStatus?. - Invoke($"Average checksum speed {blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed + .Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Sidecar created in {0} seconds.", (chkEnd - chkStart).TotalSeconds); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); + _dumpLog.WriteLine(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); - List<(ulong start, string type)> filesystems = new(); + _dumpLog.WriteLine(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize()); - if(sidecar.BlockMedia[0].FileSystemInformation != null) - filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation + List<(ulong start, string type)> filesystems = []; + + if(sidecar.BlockMedias[0].FileSystemInformation != null) + { + filesystems.AddRange(from partition in sidecar.BlockMedias[0].FileSystemInformation where partition.FileSystems != null from fileSystem in partition.FileSystems select (partition.StartSector, fileSystem.Type)); + } if(filesystems.Count > 0) + { foreach(var filesystem in filesystems.Select(o => new - { - o.start, - o.type - }).Distinct()) + { + o.start, + o.type + }) + .Distinct()) { - UpdateStatus?. - Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Found_filesystem_0_at_sector_1, + filesystem.type, + filesystem.start)); - _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, + _dumpLog.WriteLine(Localization.Core.Found_filesystem_0_at_sector_1, + filesystem.type, filesystem.start); } + } (string type, string subType) = CommonTypes.Metadata.MediaType.MediaTypeToString(mediaType); - sidecar.BlockMedia[0].DiskType = type; - sidecar.BlockMedia[0].DiskSubType = subType; - sidecar.BlockMedia[0].Interface = "ATA"; - sidecar.BlockMedia[0].LogicalBlocks = blocks; - sidecar.BlockMedia[0].PhysicalBlockSize = physicalSectorSize; - sidecar.BlockMedia[0].LogicalBlockSize = blockSize; - sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer; - sidecar.BlockMedia[0].Model = _dev.Model; + sidecar.BlockMedias[0].MediaType = type; + sidecar.BlockMedias[0].MediaSubType = subType; + sidecar.BlockMedias[0].Interface = "ATA"; + sidecar.BlockMedias[0].LogicalBlocks = blocks; + sidecar.BlockMedias[0].PhysicalBlockSize = physicalSectorSize; + sidecar.BlockMedias[0].LogicalBlockSize = blockSize; + sidecar.BlockMedias[0].Manufacturer = _dev.Manufacturer; + sidecar.BlockMedias[0].Model = _dev.Model; - if(!_private) - sidecar.BlockMedia[0].Serial = _dev.Serial; + if(!_private) sidecar.BlockMedias[0].Serial = _dev.Serial; - sidecar.BlockMedia[0].Size = blocks * blockSize; + sidecar.BlockMedias[0].Size = blocks * blockSize; - if(cylinders > 0 && - heads > 0 && - sectors > 0) + if(cylinders > 0 && heads > 0 && sectors > 0) { - sidecar.BlockMedia[0].Cylinders = cylinders; - sidecar.BlockMedia[0].CylindersSpecified = true; - sidecar.BlockMedia[0].Heads = heads; - sidecar.BlockMedia[0].HeadsSpecified = true; - sidecar.BlockMedia[0].SectorsPerTrack = sectors; - sidecar.BlockMedia[0].SectorsPerTrackSpecified = true; + sidecar.BlockMedias[0].Cylinders = cylinders; + sidecar.BlockMedias[0].Heads = heads; + sidecar.BlockMedias[0].SectorsPerTrack = sectors; } - UpdateStatus?.Invoke("Writing metadata sidecar"); + UpdateStatus?.Invoke(Localization.Core.Writing_metadata_sidecar); - var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); + var jsonFs = new FileStream(_outputPrefix + ".metadata.json", FileMode.Create); - var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); - xmlSer.Serialize(xmlFs, sidecar); - xmlFs.Close(); + JsonSerializer.Serialize(jsonFs, + new MetadataJson + { + AaruMetadata = sidecar + }, + typeof(MetadataJson), + MetadataJsonContext.Default); + + jsonFs.Close(); } } UpdateStatus?.Invoke(""); - UpdateStatus?. - Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second), + totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second), + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average speed: {blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); if(maxSpeed > 0) - UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0, + ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize())); + } - if(minSpeed > 0 && - minSpeed < double.MaxValue) - UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); + if(minSpeed is > 0 and < double.MaxValue) + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0, + ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize())); + } - UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); + UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_could_not_be_read, + _resume.BadBlocks.Count)); - if(_resume.BadBlocks.Count > 0) - _resume.BadBlocks.Sort(); + if(_resume.BadBlocks.Count > 0) _resume.BadBlocks.Sort(); UpdateStatus?.Invoke(""); } @@ -862,6 +1044,6 @@ public partial class Dump Statistics.AddMedia(mediaType, true); } else - StoppingErrorMessage?.Invoke("Unable to communicate with ATA device."); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_communicate_with_ATA_device); } } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs b/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs index 8b129aadf..a3240e200 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs @@ -27,25 +27,27 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.Linq; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs; using Aaru.Core.Logging; using Aaru.Decoders.CD; using Aaru.Devices; -using Schemas; +using Humanizer; +using Humanizer.Bytes; +using Track = Aaru.CommonTypes.Structs.Track; + +namespace Aaru.Core.Devices.Dumping; partial class Dump { @@ -54,13 +56,9 @@ partial class Dump /// true if it contains Yellow Book data, false otherwise static bool IsData(byte[] sector) { - if(sector?.Length != 2352) - return false; + if(sector?.Length != 2352) return false; - byte[] syncMark = - { - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 - }; + byte[] syncMark = [0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00]; var testMark = new byte[12]; Array.Copy(sector, 0, testMark, 0, 12); @@ -77,13 +75,9 @@ partial class Dump { offset = 0; - if(sector?.Length != 2352) - return false; + if(sector?.Length != 2352) return false; - byte[] syncMark = - { - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 - }; + byte[] syncMark = [0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00]; var testMark = new byte[12]; @@ -146,7 +140,7 @@ partial class Dump /// Disc media catalogue number /// List of subchannels not yet dumped correctly /// List of smallest pregap relative address per track - void ReadCdiReady(uint blockSize, ref double currentSpeed, DumpHardwareType currentTry, ExtentsULong extents, + void ReadCdiReady(uint blockSize, ref double currentSpeed, DumpHardware currentTry, ExtentsULong extents, IbgLog ibgLog, ref double imageWriteDuration, ExtentsULong leadOutExtents, ref double maxSpeed, MhddLog mhddLog, ref double minSpeed, uint subSize, MmcSubchannel supportedSubchannel, ref double totalDuration, Track[] tracks, SubchannelLog subLog, MmcSubchannel desiredSubchannel, @@ -154,24 +148,22 @@ partial class Dump bool cdiReadyReadAsAudio, int offsetBytes, int sectorsForOffset, Dictionary smallestPregapLbaPerTrack) { - ulong sectorSpeedStart = 0; // Used to calculate correct speed - DateTime timeSpeedStart = DateTime.UtcNow; // Time of start for speed calculation - bool sense; // Sense indicator - byte[] cmdBuf; // Data buffer - byte[] senseBuf; // Sense buffer - double cmdDuration; // Command execution time - const uint sectorSize = 2352; // Full sector size + ulong sectorSpeedStart = 0; // Used to calculate correct speed + bool sense; // Sense indicator + byte[] cmdBuf; // Data buffer + byte[] senseBuf; // Sense buffer + double cmdDuration; // Command execution time + const uint sectorSize = 2352; // Full sector size Track firstTrack = tracks.FirstOrDefault(); uint blocksToRead; // How many sectors to read at once var outputOptical = _outputPlugin as IWritableOpticalImage; - if(firstTrack is null) - return; + if(firstTrack is null) return; if(cdiReadyReadAsAudio) { - _dumpLog.WriteLine("Setting speed to 8x for CD-i Ready reading as audio."); - UpdateStatus?.Invoke("Setting speed to 8x for CD-i Ready reading as audio."); + _dumpLog.WriteLine(Localization.Core.Setting_speed_to_8x_for_CD_i_Ready_reading_as_audio); + UpdateStatus?.Invoke(Localization.Core.Setting_speed_to_8x_for_CD_i_Ready_reading_as_audio); _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); } @@ -183,8 +175,8 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } @@ -193,10 +185,10 @@ partial class Dump blocksToRead = _maximumReadable; - if(blocksToRead == 1 && cdiReadyReadAsAudio) - blocksToRead += (uint)sectorsForOffset; + if(blocksToRead == 1 && cdiReadyReadAsAudio) blocksToRead += (uint)sectorsForOffset; if(cdiReadyReadAsAudio) + { if(offsetBytes < 0) { if(i == 0) @@ -204,50 +196,97 @@ partial class Dump else firstSectorToRead -= (uint)sectorsForOffset; } + } - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)blocks); - sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); + _speedStopwatch.Start(); + + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + firstSectorToRead, + blockSize, + blocksToRead, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); totalDuration += cmdDuration; - + _speedStopwatch.Stop(); double elapsed; // Overcome the track mode change drive error if(sense) + { for(uint r = 0; r < _maximumReadable; r++) { - UpdateProgress?.Invoke($"Reading sector {i + r} of {blocks} ({currentSpeed:F3} MiB/sec.)", - (long)i + r, (long)blocks); + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i + r, + blocks, + ByteSize.FromMegabytes(currentSpeed) + .Per(_oneSecond) + .Humanize()), + (long)i + r, + (long)blocks); - sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(i + r), blockSize, (uint)sectorsForOffset + 1, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); + _speedStopwatch.Start(); + + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + (uint)(i + r), + blockSize, + (uint)sectorsForOffset + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); totalDuration += cmdDuration; + _speedStopwatch.Stop(); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { mhddLog.Write(i + r, cmdDuration); ibgLog.Write(i + r, currentSpeed * 1024); extents.Add(i + r, 1, true); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); if(cdiReadyReadAsAudio) - FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, - ref blocksToRead, subSize, ref cmdBuf, blockSize, false); + { + FixOffsetData(offsetBytes, + sectorSize, + sectorsForOffset, + supportedSubchannel, + ref blocksToRead, + subSize, + ref cmdBuf, + blockSize, + false); + } if(supportedSubchannel != MmcSubchannel.None) { @@ -258,16 +297,30 @@ partial class Dump Array.Copy(cmdBuf, sectorSize, sub, 0, subSize); - if(cdiReadyReadAsAudio) - data = Sector.Scramble(data); + if(cdiReadyReadAsAudio) data = Sector.Scramble(data); outputOptical.WriteSectorsLong(data, i + r, 1); bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, - desiredSubchannel, sub, i + r, 1, subLog, isrcs, 1, ref mcn, tracks, - subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel, - _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true, - out List newPregapSectors); + desiredSubchannel, + sub, + i + r, + 1, + subLog, + isrcs, + 1, + ref mcn, + tracks, + subchannelExtents, + _fixSubchannelPosition, + outputOptical, + _fixSubchannel, + _fixSubchannelCrc, + _dumpLog, + UpdateStatus, + smallestPregapLbaPerTrack, + true, + out List _); // Set tracks and go back if(indexesChanged) @@ -281,7 +334,9 @@ partial class Dump else outputOptical.WriteSectorsLong(cmdBuf, i + r, 1); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + + _mediaGraph?.PaintSectorGood(i + r); } else { @@ -289,40 +344,52 @@ partial class Dump leadOutExtents.Add(i + r, firstTrack.EndSector); - UpdateStatus?. - Invoke($"Adding CD-i Ready hole from LBA {i + r} to {firstTrack.EndSector} inclusive."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Adding_CD_i_Ready_hole_from_LBA_0_to_1_inclusive, + i + r, + firstTrack.EndSector)); - _dumpLog.WriteLine("Adding CD-i Ready hole from LBA {0} to {1} inclusive.", i + r, + _dumpLog.WriteLine(Localization.Core.Adding_CD_i_Ready_hole_from_LBA_0_to_1_inclusive, + i + r, firstTrack.EndSector); break; } + _writeStopwatch.Stop(); sectorSpeedStart += r; _resume.NextBlock = i + r; - elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } + } - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { if(cdiReadyReadAsAudio) - FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead, - subSize, ref cmdBuf, blockSize, false); + { + FixOffsetData(offsetBytes, + sectorSize, + sectorsForOffset, + supportedSubchannel, + ref blocksToRead, + subSize, + ref cmdBuf, + blockSize, + false); + } mhddLog.Write(i, cmdDuration); ibgLog.Write(i, currentSpeed * 1024); extents.Add(i, blocksToRead, true); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); if(supportedSubchannel != MmcSubchannel.None) { @@ -347,9 +414,24 @@ partial class Dump outputOptical.WriteSectorsLong(data, i, blocksToRead); bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, - desiredSubchannel, sub, i, blocksToRead, subLog, isrcs, 1, ref mcn, tracks, - subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel, - _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true, + desiredSubchannel, + sub, + i, + blocksToRead, + subLog, + isrcs, + 1, + ref mcn, + tracks, + subchannelExtents, + _fixSubchannelPosition, + outputOptical, + _fixSubchannel, + _fixSubchannelCrc, + _dumpLog, + UpdateStatus, + smallestPregapLbaPerTrack, + true, out List newPregapSectors); // Set tracks and go back @@ -357,16 +439,14 @@ partial class Dump { outputOptical.SetTracks(tracks.ToList()); - foreach(ulong newPregapSector in newPregapSectors) - _resume.BadBlocks.Add(newPregapSector); + foreach(ulong newPregapSector in newPregapSectors) _resume.BadBlocks.Add(newPregapSector); if(i >= blocksToRead) i -= blocksToRead; else i = 0; - if(i > 0) - i--; + if(i > 0) i--; continue; } @@ -391,7 +471,9 @@ partial class Dump outputOptical.WriteSectorsLong(cmdBuf, i, blocksToRead); } - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + + _mediaGraph?.PaintSectorsGood(i, blocksToRead); } else { @@ -402,20 +484,21 @@ partial class Dump break; } + _writeStopwatch.Stop(); sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; - elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } + _speedStopwatch.Stop(); EndProgress?.Invoke(); } } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs index b12406810..c85978e73 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs @@ -27,31 +27,34 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Aaru.Checksums; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Core.Logging; using Aaru.Decoders.CD; using Aaru.Decoders.SCSI; using Aaru.Devices; -using Schemas; +using Humanizer; +using Humanizer.Bytes; +using Track = Aaru.CommonTypes.Structs.Track; using TrackType = Aaru.CommonTypes.Enums.TrackType; +namespace Aaru.Core.Devices.Dumping; + partial class Dump { /// Reads all CD user data @@ -89,7 +92,7 @@ partial class Dump /// List of subchannels not yet dumped correctly /// List of smallest pregap relative address per track void ReadCdData(ExtentsULong audioExtents, ulong blocks, uint blockSize, ref double currentSpeed, - DumpHardwareType currentTry, ExtentsULong extents, IbgLog ibgLog, ref double imageWriteDuration, + DumpHardware currentTry, ExtentsULong extents, IbgLog ibgLog, ref double imageWriteDuration, long lastSector, ExtentsULong leadOutExtents, ref double maxSpeed, MhddLog mhddLog, ref double minSpeed, out bool newTrim, bool nextData, int offsetBytes, bool read6, bool read10, bool read12, bool read16, bool readcd, int sectorsForOffset, uint subSize, @@ -98,37 +101,24 @@ partial class Dump Dictionary isrcs, ref string mcn, HashSet subchannelExtents, Dictionary smallestPregapLbaPerTrack) { - ulong sectorSpeedStart = 0; // Used to calculate correct speed - DateTime timeSpeedStart = DateTime.UtcNow; // Time of start for speed calculation - uint blocksToRead; // How many sectors to read at once - var sense = true; // Sense indicator - byte[] cmdBuf = null; // Data buffer - byte[] senseBuf = null; // Sense buffer - double cmdDuration = 0; // Command execution time - const uint sectorSize = 2352; // Full sector size + ulong sectorSpeedStart = 0; // Used to calculate correct speed + uint blocksToRead; // How many sectors to read at once + var sense = true; // Sense indicator + byte[] cmdBuf = null; // Data buffer + byte[] senseBuf = null; // Sense buffer + double cmdDuration = 0; // Command execution time + const uint sectorSize = 2352; // Full sector size newTrim = false; PlextorSubchannel supportedPlextorSubchannel; var outputFormat = _outputPlugin as IWritableImage; - switch(supportedSubchannel) - { - case MmcSubchannel.None: - supportedPlextorSubchannel = PlextorSubchannel.None; - - break; - case MmcSubchannel.Raw: - supportedPlextorSubchannel = PlextorSubchannel.Pack; - - break; - case MmcSubchannel.Q16: - supportedPlextorSubchannel = PlextorSubchannel.Q16; - - break; - default: - supportedPlextorSubchannel = PlextorSubchannel.None; - - break; - } + supportedPlextorSubchannel = supportedSubchannel switch + { + MmcSubchannel.None => PlextorSubchannel.None, + MmcSubchannel.Raw => PlextorSubchannel.Pack, + MmcSubchannel.Q16 => PlextorSubchannel.Q16, + _ => PlextorSubchannel.None + }; InitProgress?.Invoke(); @@ -142,8 +132,8 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } @@ -154,8 +144,7 @@ partial class Dump i++; } - if((long)i > lastSector) - break; + if((long)i > lastSector) break; var firstSectorToRead = (uint)i; @@ -168,13 +157,9 @@ partial class Dump { if(j > (ulong)lastSector) { - if(!failedCrossingLeadOut && - !inData) - blocksToRead += (uint)sectorsForOffset; + if(!failedCrossingLeadOut && !inData) blocksToRead += (uint)sectorsForOffset; - if(sectorsForOffset > 0 && - !inData) - crossingLeadOut = true; + if(sectorsForOffset > 0 && !inData) crossingLeadOut = true; break; } @@ -203,18 +188,14 @@ partial class Dump } } - if(track.Sequence != 0 && - i + blocksToRead - (ulong)sectorsForOffset > track.EndSector + 1) + if(track.Sequence != 0 && i + blocksToRead - (ulong)sectorsForOffset > track.EndSector + 1) blocksToRead = (uint)(track.EndSector + 1 - i + (ulong)sectorsForOffset); - if(blocksToRead == 1 && - !inData) - blocksToRead += (uint)sectorsForOffset; + if(blocksToRead == 1 && !inData) blocksToRead += (uint)sectorsForOffset; if(blocksToRead == 0) { - if(!skippingLead) - i += (ulong)sectorsForOffset; + if(!skippingLead) i += (ulong)sectorsForOffset; skippingLead = false; @@ -222,6 +203,7 @@ partial class Dump } if(_fixOffset && !inData) + { if(offsetBytes < 0) { if(i == 0) @@ -229,35 +211,43 @@ partial class Dump else firstSectorToRead -= (uint)sectorsForOffset; - if(blocksToRead <= sectorsForOffset) - blocksToRead += (uint)sectorsForOffset; + if(blocksToRead <= sectorsForOffset) blocksToRead += (uint)sectorsForOffset; } - - if(!inData && - currentReadSpeed == 0xFFFF) - { - _dumpLog.WriteLine("Setting speed to 8x for audio reading."); - UpdateStatus?.Invoke("Setting speed to 8x for audio reading."); - - _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); - - currentReadSpeed = 1200; } - if(inData && currentReadSpeed != _speed) + switch(inData) { - _dumpLog.WriteLine($"Setting speed to {(_speed == 0xFFFF ? "MAX for data reading" : $"{_speed}x")}."); + case false when currentReadSpeed == 0xFFFF: + _dumpLog.WriteLine(Localization.Core.Setting_speed_to_8x_for_audio_reading); + UpdateStatus?.Invoke(Localization.Core.Setting_speed_to_8x_for_audio_reading); - UpdateStatus?.Invoke($"Setting speed to {(_speed == 0xFFFF ? "MAX for data reading" : $"{_speed}x")}."); + _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _); - _speed *= _speedMultiplier; + currentReadSpeed = 1200; - if(_speed is 0 or > 0xFFFF) - _speed = 0xFFFF; + break; + case true when currentReadSpeed != _speed: + { + _dumpLog.WriteLine(_speed == 0xFFFF + ? Localization.Core.Setting_speed_to_MAX_for_data_reading + : string.Format(Localization.Core.Setting_speed_to_0_x_for_data_reading, + _speed)); - currentReadSpeed = _speed; + UpdateStatus?.Invoke(_speed == 0xFFFF + ? Localization.Core.Setting_speed_to_MAX_for_data_reading + : string.Format(Localization.Core.Setting_speed_to_0_x_for_data_reading, + _speed)); - _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _); + _speed *= _speedMultiplier; + + if(_speed is 0 or > 0xFFFF) _speed = 0xFFFF; + + currentReadSpeed = _speed; + + _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _); + + break; + } } if(inData && crossingLeadOut) @@ -267,36 +257,58 @@ partial class Dump crossingLeadOut = false; } - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)blocks); - if(crossingLeadOut && - failedCrossingLeadOut && - blocksToRead > 1) - blocksToRead--; + if(crossingLeadOut && failedCrossingLeadOut && blocksToRead > 1) blocksToRead--; if(_supportsPlextorD8 && !inData) { - sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead, - supportedPlextorSubchannel, out cmdDuration); + _speedStopwatch.Start(); + + sense = ReadPlextorWithSubchannel(out cmdBuf, + out senseBuf, + firstSectorToRead, + blockSize, + blocksToRead, + supportedPlextorSubchannel, + out cmdDuration); totalDuration += cmdDuration; + _speedStopwatch.Stop(); } else if(readcd) { if(inData) { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); + _speedStopwatch.Start(); + + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + firstSectorToRead, + blockSize, + blocksToRead, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); if(sense) { @@ -310,10 +322,26 @@ partial class Dump // Go one for one as the drive does not tell us which one failed for(var bi = 0; bi < blocksToRead; bi++) { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(firstSectorToRead + bi), blockSize, - 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out double cmdDuration2); + _speedStopwatch.Start(); + + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + (uint)(firstSectorToRead + bi), + blockSize, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out double cmdDuration2); + + _speedStopwatch.Stop(); cmdDuration += cmdDuration2; @@ -353,50 +381,115 @@ partial class Dump // Drive definitively didn't like to read everything so just do something clever... // Try again - sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, - true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, + _speedStopwatch.Start(); + + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + firstSectorToRead, + blockSize, + blocksToRead, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, out cmdDuration); + _speedStopwatch.Stop(); + if(sense) // Try reading one less every time + { for(uint bi = blocksToRead; bi > 0; bi--) { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, bi, - MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out cmdDuration); + _speedStopwatch.Start(); - if(sense) - continue; + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + firstSectorToRead, + blockSize, + bi, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); + + if(sense) continue; blocksToRead = bi; break; } + } } } } else { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead, - MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); + _speedStopwatch.Start(); + + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + firstSectorToRead, + blockSize, + blocksToRead, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); if(sense) { DecodedSense? decSense = Sense.Decode(senseBuf); // Try to workaround firmware - if(decSense?.ASC == 0x11 && decSense?.ASCQ == 0x05 || - decSense?.ASC == 0x64) + if(decSense is { ASC: 0x11, ASCQ: 0x05 } || decSense?.ASC == 0x64) { - sense = _dev.ReadCd(out cmdBuf, out _, firstSectorToRead, blockSize, blocksToRead, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, - true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, + _speedStopwatch.Start(); + + sense = _dev.ReadCd(out cmdBuf, + out _, + firstSectorToRead, + blockSize, + blocksToRead, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, out double cmdDuration2); + _speedStopwatch.Stop(); + cmdDuration += cmdDuration2; } } @@ -405,84 +498,280 @@ partial class Dump totalDuration += cmdDuration; } else if(read16) - sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, false, false, firstSectorToRead, blockSize, 0, - blocksToRead, false, _dev.Timeout, out cmdDuration); + { + _speedStopwatch.Start(); + + sense = _dev.Read16(out cmdBuf, + out senseBuf, + 0, + false, + false, + false, + firstSectorToRead, + blockSize, + 0, + blocksToRead, + false, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); + } else if(read12) - sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, false, false, false, firstSectorToRead, - blockSize, 0, blocksToRead, false, _dev.Timeout, out cmdDuration); + { + _speedStopwatch.Start(); + + sense = _dev.Read12(out cmdBuf, + out senseBuf, + 0, + false, + false, + false, + false, + firstSectorToRead, + blockSize, + 0, + blocksToRead, + false, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); + } else if(read10) - sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, false, false, false, firstSectorToRead, - blockSize, 0, (ushort)blocksToRead, _dev.Timeout, out cmdDuration); + { + _speedStopwatch.Start(); + + sense = _dev.Read10(out cmdBuf, + out senseBuf, + 0, + false, + false, + false, + false, + firstSectorToRead, + blockSize, + 0, + (ushort)blocksToRead, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); + } else if(read6) - sense = _dev.Read6(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, (byte)blocksToRead, - _dev.Timeout, out cmdDuration); + { + _speedStopwatch.Start(); + + sense = _dev.Read6(out cmdBuf, + out senseBuf, + firstSectorToRead, + blockSize, + (byte)blocksToRead, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); + } double elapsed; // Overcome the track mode change drive error - if(inData && - !nextData && - sense) + if(inData && !nextData && sense) { for(uint r = 0; r < blocksToRead; r++) { - UpdateProgress?.Invoke($"Reading sector {i + r} of {blocks} ({currentSpeed:F3} MiB/sec.)", - (long)i + r, (long)blocks); + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i + r, + blocks, + ByteSize.FromMegabytes(currentSpeed) + .Per(_oneSecond) + .Humanize()), + (long)i + r, + (long)blocks); if(_supportsPlextorD8) { var adjustment = 0; - if(offsetBytes < 0) - adjustment = -sectorsForOffset; + if(offsetBytes < 0) adjustment = -sectorsForOffset; - sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, - (uint)(firstSectorToRead + r + adjustment), blockSize, - (uint)sectorsForOffset + 1, supportedPlextorSubchannel, + _speedStopwatch.Start(); + + sense = ReadPlextorWithSubchannel(out cmdBuf, + out senseBuf, + (uint)(firstSectorToRead + r + adjustment), + blockSize, + (uint)sectorsForOffset + 1, + supportedPlextorSubchannel, out cmdDuration); + _speedStopwatch.Stop(); + totalDuration += cmdDuration; if(!sense) { var sectorsForFix = (uint)(1 + sectorsForOffset); - FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, - ref sectorsForFix, subSize, ref cmdBuf, blockSize, false); + FixOffsetData(offsetBytes, + sectorSize, + sectorsForOffset, + supportedSubchannel, + ref sectorsForFix, + subSize, + ref cmdBuf, + blockSize, + false); - // TODO: Implement sector validity + // Descramble cmdBuf = Sector.Scramble(cmdBuf); + + // Check valid sector + CdChecksums.CheckCdSector(cmdBuf, + out bool? correctEccP, + out bool? correctEccQ, + out bool? correctEdc); + + // Check mode, set sense if EDC/ECC validity is not correct + switch(cmdBuf[15] & 0x03) + { + case 0: + + for(var c = 16; c < 2352; c++) + { + if(cmdBuf[c] == 0x00) continue; + + sense = true; + + break; + } + + break; + case 1: + sense = correctEdc != true || correctEccP != true || correctEccQ != true; + + break; + case 2: + if((cmdBuf[18] & 0x20) != 0x20) + { + if(correctEccP != true) sense = true; + + if(correctEccQ != true) sense = true; + } + + if(correctEdc != true) sense = true; + + break; + } } } else if(readcd) { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(i + r), blockSize, 1, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, - true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, + _speedStopwatch.Start(); + + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + (uint)(i + r), + blockSize, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, out cmdDuration); + _speedStopwatch.Stop(); + totalDuration += cmdDuration; } else if(read16) - sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, i + r, blockSize, 0, 1, - false, _dev.Timeout, out cmdDuration); + { + _speedStopwatch.Start(); + + sense = _dev.Read16(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + i + r, + blockSize, + 0, + 1, + false, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); + } else if(read12) - sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)(i + r), - blockSize, 0, 1, false, _dev.Timeout, out cmdDuration); + { + _speedStopwatch.Start(); + + sense = _dev.Read12(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)(i + r), + blockSize, + 0, + 1, + false, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); + } else if(read10) - sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)(i + r), - blockSize, 0, 1, _dev.Timeout, out cmdDuration); + { + _speedStopwatch.Start(); + + sense = _dev.Read10(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)(i + r), + blockSize, + 0, + 1, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); + } else if(read6) - sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)(i + r), blockSize, 1, _dev.Timeout, + { + _speedStopwatch.Start(); + + sense = _dev.Read6(out cmdBuf, + out senseBuf, + (uint)(i + r), + blockSize, + 1, + _dev.Timeout, out cmdDuration); - if(!sense && - !_dev.Error) + _speedStopwatch.Stop(); + } + + if(!sense && !_dev.Error) { mhddLog.Write(i + r, cmdDuration); ibgLog.Write(i + r, currentSpeed * 1024); extents.Add(i + r, 1, true); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); if(supportedSubchannel != MmcSubchannel.None) { @@ -511,10 +800,25 @@ partial class Dump } bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, - desiredSubchannel, sub, i + r, 1, subLog, isrcs, (byte)track.Sequence, ref mcn, - tracks, subchannelExtents, _fixSubchannelPosition, - outputFormat as IWritableOpticalImage, _fixSubchannel, _fixSubchannelCrc, _dumpLog, - UpdateStatus, smallestPregapLbaPerTrack, true, out List newPregapSectors); + desiredSubchannel, + sub, + i + r, + 1, + subLog, + isrcs, + (byte)track.Sequence, + ref mcn, + tracks, + subchannelExtents, + _fixSubchannelPosition, + outputFormat as IWritableOpticalImage, + _fixSubchannel, + _fixSubchannelCrc, + _dumpLog, + UpdateStatus, + smallestPregapLbaPerTrack, + true, + out List newPregapSectors); // Set tracks and go back if(indexesChanged) @@ -529,8 +833,7 @@ partial class Dump else i = 0; - if(i > 0) - i--; + if(i > 0) i--; foreach(Track aTrack in tracks.Where(aTrack => aTrack.Type == TrackType.Audio)) audioExtents.Add(aTrack.StartSector, aTrack.EndSector); @@ -558,22 +861,28 @@ partial class Dump } } - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + _mediaGraph?.PaintSectorGood(i + r); + + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; } else { _errorLog?.WriteLine(i + r, _dev.Error, _dev.LastError, senseBuf); // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); if(supportedSubchannel != MmcSubchannel.None) { outputFormat.WriteSectorsLong(new byte[sectorSize], i + r, 1); if(desiredSubchannel != MmcSubchannel.None) - outputFormat.WriteSectorsTag(new byte[subSize], i + r, 1, + { + outputFormat.WriteSectorsTag(new byte[subSize], + i + r, + 1, SectorTagType.CdSectorSubchannel); + } } else { @@ -588,37 +897,42 @@ partial class Dump } } - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + + _mediaGraph?.PaintSectorBad(i + r); _resume.BadBlocks.Add(i + r); - AaruConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_error_0, + Sense.PrettifySense(senseBuf)); + mhddLog.Write(i + r, cmdDuration < 500 ? 65535 : cmdDuration); - ibgLog.Write(i + r, 0); - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", 1, i + r); + ibgLog.Write(i + r, 0); + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, 1, i + r); newTrim = true; } + _writeStopwatch.Stop(); + sectorSpeedStart += r; _resume.NextBlock = i + r; - elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } continue; } - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { if(crossingLeadOut && failedCrossingLeadOut) { @@ -627,16 +941,23 @@ partial class Dump } // Because one block has been partially used to fix the offset - if(_fixOffset && - !inData && - offsetBytes != 0) - FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead, - subSize, ref cmdBuf, blockSize, failedCrossingLeadOut); + if(_fixOffset && !inData && offsetBytes != 0) + { + FixOffsetData(offsetBytes, + sectorSize, + sectorsForOffset, + supportedSubchannel, + ref blocksToRead, + subSize, + ref cmdBuf, + blockSize, + failedCrossingLeadOut); + } - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, cmdDuration, blocksToRead); ibgLog.Write(i, currentSpeed * 1024); extents.Add(i, blocksToRead, true); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); if(supportedSubchannel != MmcSubchannel.None) { @@ -668,9 +989,24 @@ partial class Dump } bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, - desiredSubchannel, sub, i, blocksToRead, subLog, isrcs, (byte)track.Sequence, ref mcn, - tracks, subchannelExtents, _fixSubchannelPosition, outputFormat as IWritableOpticalImage, - _fixSubchannel, _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true, + desiredSubchannel, + sub, + i, + blocksToRead, + subLog, + isrcs, + (byte)track.Sequence, + ref mcn, + tracks, + subchannelExtents, + _fixSubchannelPosition, + outputFormat as IWritableOpticalImage, + _fixSubchannel, + _fixSubchannelCrc, + _dumpLog, + UpdateStatus, + smallestPregapLbaPerTrack, + true, out List newPregapSectors); // Set tracks and go back @@ -678,16 +1014,14 @@ partial class Dump { (outputFormat as IWritableOpticalImage).SetTracks(tracks.ToList()); - foreach(ulong newPregapSector in newPregapSectors) - _resume.BadBlocks.Add(newPregapSector); + foreach(ulong newPregapSector in newPregapSectors) _resume.BadBlocks.Add(newPregapSector); if(i >= blocksToRead) i -= blocksToRead; else i = 0; - if(i > 0) - i--; + if(i > 0) i--; foreach(Track aTrack in tracks.Where(aTrack => aTrack.Type == TrackType.Audio)) audioExtents.Add(aTrack.StartSector, aTrack.EndSector); @@ -715,14 +1049,15 @@ partial class Dump } } - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + _mediaGraph?.PaintSectorsGood(i, blocksToRead); + + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; } else { if(crossingLeadOut && Sense.Decode(senseBuf)?.ASC == 0x21) { - if(failedCrossingLeadOut) - break; + if(failedCrossingLeadOut) break; failedCrossingLeadOut = true; blocksToRead = 0; @@ -733,22 +1068,24 @@ partial class Dump _errorLog?.WriteLine(firstSectorToRead, _dev.Error, _dev.LastError, senseBuf); // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly - if(i + _skip > blocks) - _skip = (uint)(blocks - i); + if(i + _skip > blocks) _skip = (uint)(blocks - i); // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); if(supportedSubchannel != MmcSubchannel.None) { outputFormat.WriteSectorsLong(new byte[sectorSize * _skip], i, _skip); if(desiredSubchannel != MmcSubchannel.None) - outputFormat.WriteSectorsTag(new byte[subSize * _skip], i, _skip, + { + outputFormat.WriteSectorsTag(new byte[subSize * _skip], + i, + _skip, SectorTagType.CdSectorSubchannel); + } } else { @@ -763,42 +1100,42 @@ partial class Dump } } - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; - for(ulong b = i; b < i + _skip; b++) - _resume.BadBlocks.Add(b); + for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b); - AaruConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf)); - mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.READ_error_0, Sense.PrettifySense(senseBuf)); + mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip); ibgLog.Write(i, 0); - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i); i += _skip - blocksToRead; newTrim = true; } + _writeStopwatch.Stop(); + sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; - elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } + _speedStopwatch.Stop(); EndProgress?.Invoke(); _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); - if(!failedCrossingLeadOut) - return; + if(!failedCrossingLeadOut) return; - _dumpLog.WriteLine("Failed crossing into Lead-Out, dump may not be correct."); - UpdateStatus?.Invoke("Failed crossing into Lead-Out, dump may not be correct."); + _dumpLog.WriteLine(Localization.Core.Failed_crossing_into_Lead_Out); + UpdateStatus?.Invoke(Localization.Core.Failed_crossing_into_Lead_Out); } } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs index c55e8dd90..7539b9187 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Dump.cs @@ -27,34 +27,38 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.Linq; using System.Text; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs; using Aaru.Console; +using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Core.Media.Detection; using Aaru.Database.Models; using Aaru.Decoders.CD; using Aaru.Devices; -using Schemas; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; +using Track = Aaru.CommonTypes.Structs.Track; using TrackType = Aaru.CommonTypes.Enums.TrackType; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Devices.Dumping; + /// Implement dumping Compact Discs // TODO: Barcode @@ -68,12 +72,10 @@ sealed partial class Dump uint blockSize; // Size of the read sector in bytes CdOffset cdOffset; // Read offset from database byte[] cmdBuf; // Data buffer - DumpHardwareType currentTry = null; // Current dump hardware try + DumpHardware currentTry = null; // Current dump hardware try double currentSpeed = 0; // Current read speed int? discOffset = null; // Disc write offset - DateTime dumpStart = DateTime.UtcNow; // Time of dump start - DateTime end; // Time of operation end - ExtentsULong extents = null; // Extents + ExtentsULong extents = null; // Extents bool hiddenData; // Hidden track is data IbgLog ibgLog; // IMGBurn log double imageWriteDuration = 0; // Duration of image write @@ -89,15 +91,14 @@ sealed partial class Dump var read10 = false; // Device supports READ(10) var read12 = false; // Device supports READ(12) var read16 = false; // Device supports READ(16) - bool readcd; // Device supports READ CD + var readcd = true; // Device supports READ CD bool ret; // Image writing return status const uint sectorSize = 2352; // Full sector size var sectorsForOffset = 0; // Sectors needed to fix offset var sense = true; // Sense indicator int sessions; // Number of sessions in disc - DateTime start; // Start of operation - SubchannelLog subLog = null; // Subchannel log - uint subSize; // Subchannel size in bytes + SubchannelLog subLog = null; // Subchannel log + uint subSize = 0; // Subchannel size in bytes TrackSubchannelType subType; // Track subchannel type var supportsLongSectors = true; // Supports reading EDC and ECC bool supportsPqSubchannel; // Supports reading PQ subchannel @@ -114,7 +115,7 @@ sealed partial class Dump var bcdSubchannel = false; // Subchannel positioning is in BCD Dictionary isrcs = new(); string mcn = null; - HashSet subchannelExtents = new(); + HashSet subchannelExtents = []; var cdiReadyReadAsAudio = false; uint firstLba; var outputOptical = _outputPlugin as IWritableOpticalImage; @@ -126,19 +127,27 @@ sealed partial class Dump if(_dumpRaw) { - _dumpLog.WriteLine("Raw CD dumping not yet implemented"); - StoppingErrorMessage?.Invoke("Raw CD dumping not yet implemented"); + _dumpLog.WriteLine(Localization.Core.Raw_CD_dumping_not_yet_implemented); + StoppingErrorMessage?.Invoke(Localization.Core.Raw_CD_dumping_not_yet_implemented); return; } - tracks = GetCdTracks(_dev, _dumpLog, _force, out lastSector, leadOutStarts, mediaTags, StoppingErrorMessage, - out toc, trackFlags, UpdateStatus); + tracks = GetCdTracks(_dev, + _dumpLog, + _force, + out lastSector, + leadOutStarts, + mediaTags, + StoppingErrorMessage, + out toc, + trackFlags, + UpdateStatus); if(tracks is null) { - _dumpLog.WriteLine("Could not get tracks!"); - StoppingErrorMessage?.Invoke("Could not get tracks!"); + _dumpLog.WriteLine(Localization.Core.Could_not_get_tracks); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_get_tracks); return; } @@ -174,10 +183,11 @@ sealed partial class Dump desiredSubchannel = MmcSubchannel.Raw; else { - _dumpLog.WriteLine("Drive does not support the requested subchannel format, not continuing..."); + _dumpLog.WriteLine(Localization.Core + .Drive_does_not_support_the_requested_subchannel_format_not_continuing); - StoppingErrorMessage?. - Invoke("Drive does not support the requested subchannel format, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Drive_does_not_support_the_requested_subchannel_format_not_continuing); return; } @@ -190,10 +200,11 @@ sealed partial class Dump desiredSubchannel = MmcSubchannel.Q16; else { - _dumpLog.WriteLine("Drive does not support the requested subchannel format, not continuing..."); + _dumpLog.WriteLine(Localization.Core + .Drive_does_not_support_the_requested_subchannel_format_not_continuing); - StoppingErrorMessage?. - Invoke("Drive does not support the requested subchannel format, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Drive_does_not_support_the_requested_subchannel_format_not_continuing); return; } @@ -204,10 +215,11 @@ sealed partial class Dump desiredSubchannel = MmcSubchannel.Q16; else { - _dumpLog.WriteLine("Drive does not support the requested subchannel format, not continuing..."); + _dumpLog.WriteLine(Localization.Core + .Drive_does_not_support_the_requested_subchannel_format_not_continuing); - StoppingErrorMessage?. - Invoke("Drive does not support the requested subchannel format, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Drive_does_not_support_the_requested_subchannel_format_not_continuing); return; } @@ -217,11 +229,11 @@ sealed partial class Dump desiredSubchannel = MmcSubchannel.None; break; - default: throw new ArgumentOutOfRangeException(); + default: + throw new ArgumentOutOfRangeException(); } - if(desiredSubchannel == MmcSubchannel.Q16 && supportsPqSubchannel) - supportedSubchannel = MmcSubchannel.Q16; + if(desiredSubchannel == MmcSubchannel.Q16 && supportsPqSubchannel) supportedSubchannel = MmcSubchannel.Q16; // Check if output format supports subchannels if(!outputOptical.SupportedSectorTags.Contains(SectorTagType.CdSectorSubchannel) && @@ -229,13 +241,15 @@ sealed partial class Dump { if(_force || _subchannel == DumpSubchannel.None) { - _dumpLog.WriteLine("Output format does not support subchannels, continuing..."); - UpdateStatus?.Invoke("Output format does not support subchannels, continuing..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_subchannels_continuing); + UpdateStatus?.Invoke(Localization.Core.Output_format_does_not_support_subchannels_continuing); } else { - _dumpLog.WriteLine("Output format does not support subchannels, not continuing..."); - StoppingErrorMessage?.Invoke("Output format does not support subchannels, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_subchannels_not_continuing); + + StoppingErrorMessage?.Invoke(Localization.Core + .Output_format_does_not_support_subchannels_not_continuing); return; } @@ -246,150 +260,156 @@ sealed partial class Dump switch(supportedSubchannel) { case MmcSubchannel.None: - _dumpLog.WriteLine("Checking if drive supports reading without subchannel..."); - UpdateStatus?.Invoke("Checking if drive supports reading without subchannel..."); + _dumpLog.WriteLine(Localization.Core.Checking_if_drive_supports_reading_without_subchannel); + UpdateStatus?.Invoke(Localization.Core.Checking_if_drive_supports_reading_without_subchannel); - readcd = !_dev.ReadCd(out cmdBuf, out _, firstLba, sectorSize, 1, MmcSectorTypes.AllTypes, false, false, - true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out _) || + readcd = !_dev.ReadCd(out cmdBuf, + out _, + firstLba, + sectorSize, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out _) || !_dev.ReadCd(out cmdBuf, out _, firstLba + 5, sectorSize, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out _); if(!readcd) { - _dumpLog.WriteLine("Drive does not support READ CD, trying SCSI READ commands..."); - ErrorMessage?.Invoke("Drive does not support READ CD, trying SCSI READ commands..."); + _dumpLog.WriteLine(Localization.Core.Drive_does_not_support_READ_CD_trying_SCSI_READ_commands); + ErrorMessage?.Invoke(Localization.Core.Drive_does_not_support_READ_CD_trying_SCSI_READ_commands); - _dumpLog.WriteLine("Checking if drive supports READ(6)..."); - UpdateStatus?.Invoke("Checking if drive supports READ(6)..."); - read6 = !_dev.Read6(out cmdBuf, out _, firstLba, 2048, 1, _dev.Timeout, out _); - _dumpLog.WriteLine("Checking if drive supports READ(10)..."); - UpdateStatus?.Invoke("Checking if drive supports READ(10)..."); + _dumpLog.WriteLine(Localization.Core.Checking_if_drive_supports_READ_6); + UpdateStatus?.Invoke(Localization.Core.Checking_if_drive_supports_READ_6); + + read6 = !_dev.Read6(out cmdBuf, out _, firstLba, 2048, 1, _dev.Timeout, out _) || + !_dev.Read6(out cmdBuf, out _, firstLba + 5, 2048, 1, _dev.Timeout, out _); + + _dumpLog.WriteLine(Localization.Core.Checking_if_drive_supports_READ_10); + UpdateStatus?.Invoke(Localization.Core.Checking_if_drive_supports_READ_10); read10 = !_dev.Read10(out cmdBuf, out _, 0, false, true, false, false, firstLba, 2048, 0, 1, _dev.Timeout, out _) || !_dev.Read10(out cmdBuf, out _, 0, false, true, false, false, firstLba + 5, 2048, 0, 1, _dev.Timeout, out _); - _dumpLog.WriteLine("Checking if drive supports READ(12)..."); - UpdateStatus?.Invoke("Checking if drive supports READ(12)..."); + _dumpLog.WriteLine(Localization.Core.Checking_if_drive_supports_READ_12); + UpdateStatus?.Invoke(Localization.Core.Checking_if_drive_supports_READ_12); read12 = !_dev.Read12(out cmdBuf, out _, 0, false, true, false, false, firstLba, 2048, 0, 1, false, _dev.Timeout, out _) || !_dev.Read12(out cmdBuf, out _, 0, false, true, false, false, firstLba + 5, 2048, 0, 1, false, _dev.Timeout, out _); - _dumpLog.WriteLine("Checking if drive supports READ(16)..."); - UpdateStatus?.Invoke("Checking if drive supports READ(16)..."); + _dumpLog.WriteLine(Localization.Core.Checking_if_drive_supports_READ_16); + UpdateStatus?.Invoke(Localization.Core.Checking_if_drive_supports_READ_16); read16 = !_dev.Read16(out cmdBuf, out _, 0, false, true, false, firstLba, 2048, 0, 1, false, _dev.Timeout, out _) || !_dev.Read16(out cmdBuf, out _, 0, false, true, false, firstLba + 5, 2048, 0, 1, false, _dev.Timeout, out _); - if(!read6 && - !read10 && - !read12 && - !read16) + switch(read6) { - _dumpLog.WriteLine("Cannot read from disc, not continuing..."); - StoppingErrorMessage?.Invoke("Cannot read from disc, not continuing..."); + case false when !read10 && !read12 && !read16: + _dumpLog.WriteLine(Localization.Core.Cannot_read_from_disc_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_read_from_disc_not_continuing); - return; - } + return; + case true: + _dumpLog.WriteLine(Localization.Core.Drive_supports_READ_6); + UpdateStatus?.Invoke(Localization.Core.Drive_supports_READ_6); - if(read6) - { - _dumpLog.WriteLine("Drive supports READ(6)..."); - UpdateStatus?.Invoke("Drive supports READ(6)..."); + break; } if(read10) { - _dumpLog.WriteLine("Drive supports READ(10)..."); - UpdateStatus?.Invoke("Drive supports READ(10)..."); + _dumpLog.WriteLine(Localization.Core.Drive_supports_READ_10); + UpdateStatus?.Invoke(Localization.Core.Drive_supports_READ_10); } if(read12) { - _dumpLog.WriteLine("Drive supports READ(12)..."); - UpdateStatus?.Invoke("Drive supports READ(12)..."); + _dumpLog.WriteLine(Localization.Core.Drive_supports_READ_12); + UpdateStatus?.Invoke(Localization.Core.Drive_supports_READ_12); } if(read16) { - _dumpLog.WriteLine("Drive supports READ(16)..."); - UpdateStatus?.Invoke("Drive supports READ(16)..."); + _dumpLog.WriteLine(Localization.Core.Drive_supports_READ_16); + UpdateStatus?.Invoke(Localization.Core.Drive_supports_READ_16); } } - _dumpLog.WriteLine("Drive can read without subchannel..."); - UpdateStatus?.Invoke("Drive can read without subchannel..."); + _dumpLog.WriteLine(Localization.Core.Drive_can_read_without_subchannel); + UpdateStatus?.Invoke(Localization.Core.Drive_can_read_without_subchannel); subSize = 0; - subType = TrackSubchannelType.None; break; case MmcSubchannel.Raw: - _dumpLog.WriteLine("Full raw subchannel reading supported..."); - UpdateStatus?.Invoke("Full raw subchannel reading supported..."); - subType = TrackSubchannelType.Raw; + _dumpLog.WriteLine(Localization.Core.Full_raw_subchannel_reading_supported); + UpdateStatus?.Invoke(Localization.Core.Full_raw_subchannel_reading_supported); subSize = 96; - readcd = true; break; case MmcSubchannel.Q16: - _dumpLog.WriteLine("PQ subchannel reading supported..."); - _dumpLog.WriteLine("WARNING: If disc says CD+G, CD+EG, CD-MIDI, CD Graphics or CD Enhanced Graphics, dump will be incorrect!"); - UpdateStatus?.Invoke("PQ subchannel reading supported..."); + _dumpLog.WriteLine(Localization.Core.PQ_subchannel_reading_supported); + _dumpLog.WriteLine(Localization.Core.WARNING_If_disc_says_CDG_CDEG_CDMIDI_dump_will_be_incorrect); + UpdateStatus?.Invoke(Localization.Core.PQ_subchannel_reading_supported); - UpdateStatus?. - Invoke("WARNING: If disc says CD+G, CD+EG, CD-MIDI, CD Graphics or CD Enhanced Graphics, dump will be incorrect!"); + UpdateStatus?.Invoke(Localization.Core.WARNING_If_disc_says_CDG_CDEG_CDMIDI_dump_will_be_incorrect); - subType = TrackSubchannelType.Q16; subSize = 16; - readcd = true; - - break; - default: - _dumpLog.WriteLine("Handling subchannel type {0} not supported, exiting...", supportedSubchannel); - - StoppingErrorMessage?. - Invoke($"Handling subchannel type {supportedSubchannel} not supported, exiting..."); - - return; - } - - switch(desiredSubchannel) - { - case MmcSubchannel.None: - subType = TrackSubchannelType.None; - - break; - case MmcSubchannel.Raw: - case MmcSubchannel.Q16: - subType = TrackSubchannelType.Raw; break; } + subType = desiredSubchannel switch + { + MmcSubchannel.None => TrackSubchannelType.None, + MmcSubchannel.Raw or MmcSubchannel.Q16 => TrackSubchannelType.Raw, + _ => throw new ArgumentOutOfRangeException() + }; + blockSize = sectorSize + subSize; // Check if subchannel is BCD if(supportedSubchannel != MmcSubchannel.None) { - sense = _dev.ReadCd(out cmdBuf, out _, (firstLba / 75 + 1) * 75 + 35, blockSize, 1, MmcSectorTypes.AllTypes, - false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out _); + sense = _dev.ReadCd(out cmdBuf, + out _, + (firstLba / 75 + 1) * 75 + 35, + blockSize, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out _); if(!sense) { tmpBuf = new byte[subSize]; Array.Copy(cmdBuf, sectorSize, tmpBuf, 0, subSize); - if(supportedSubchannel == MmcSubchannel.Q16) - tmpBuf = Subchannel.ConvertQToRaw(tmpBuf); + if(supportedSubchannel == MmcSubchannel.Q16) tmpBuf = Subchannel.ConvertQToRaw(tmpBuf); tmpBuf = Subchannel.Deinterleave(tmpBuf); @@ -400,102 +420,113 @@ sealed partial class Dump if(bcdSubchannel) { - _dumpLog.WriteLine("Drive returns subchannel in BCD..."); - UpdateStatus?.Invoke("Drive returns subchannel in BCD..."); + _dumpLog.WriteLine(Localization.Core.Drive_returns_subchannel_in_BCD); + UpdateStatus?.Invoke(Localization.Core.Drive_returns_subchannel_in_BCD); } else { - _dumpLog.WriteLine("Drive does not returns subchannel in BCD..."); - UpdateStatus?.Invoke("Drive does not returns subchannel in BCD..."); + _dumpLog.WriteLine(Localization.Core.Drive_does_not_returns_subchannel_in_BCD); + UpdateStatus?.Invoke(Localization.Core.Drive_does_not_returns_subchannel_in_BCD); } } } - foreach(Track trk in tracks) - trk.SubchannelType = subType; + foreach(Track trk in tracks) trk.SubchannelType = subType; - _dumpLog.WriteLine("Calculating pregaps, can take some time..."); - UpdateStatus?.Invoke("Calculating pregaps, can take some time..."); + _dumpLog.WriteLine(Localization.Core.Calculating_pregaps__can_take_some_time); + UpdateStatus?.Invoke(Localization.Core.Calculating_pregaps__can_take_some_time); - SolveTrackPregaps(_dev, _dumpLog, UpdateStatus, tracks, supportsPqSubchannel, supportsRwSubchannel, _dbDev, - out bool inexactPositioning, true); + SolveTrackPregaps(_dev, + _dumpLog, + UpdateStatus, + tracks, + supportsPqSubchannel, + supportsRwSubchannel, + _dbDev, + out bool inexactPositioning, + true); if(inexactPositioning) { - _dumpLog.WriteLine("WARNING: The drive has returned incorrect Q positioning when calculating pregaps. A best effort has been tried but they may be incorrect."); + _dumpLog.WriteLine(Localization.Core.The_drive_has_returned_incorrect_Q_positioning_calculating_pregaps); - UpdateStatus?. - Invoke("WARNING: The drive has returned incorrect Q positioning when calculating pregaps. A best effort has been tried but they may be incorrect."); + UpdateStatus?.Invoke(Localization.Core.The_drive_has_returned_incorrect_Q_positioning_calculating_pregaps); } if(!outputOptical.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreRawData)) { if(!_force) { - _dumpLog.WriteLine("Output format does not support storing raw data, this may end in a loss of data, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_storing_raw_data_not_continuing); - StoppingErrorMessage?. - Invoke("Output format does not support storing raw data, this may end in a loss of data, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Output_format_does_not_support_storing_raw_data_not_continuing); return; } - _dumpLog.WriteLine("Output format does not support storing raw data, this may end in a loss of data, continuing..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_storing_raw_data_continuing); - ErrorMessage?. - Invoke("Output format does not support storing raw data, this may end in a loss of data, continuing..."); + ErrorMessage?.Invoke(Localization.Core.Output_format_does_not_support_storing_raw_data_continuing); } if(!outputOptical.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreAudioTracks) && tracks.Any(track => track.Type == TrackType.Audio)) { - _dumpLog.WriteLine("Output format does not support audio tracks, cannot continue..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_audio_tracks_cannot_continue); - StoppingErrorMessage?.Invoke("Output format does not support audio tracks, cannot continue..."); + StoppingErrorMessage?.Invoke(Localization.Core.Output_format_does_not_support_audio_tracks_cannot_continue); return; } if(!outputOptical.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStorePregaps) && - tracks.Where(track => track.Sequence != tracks.First(t => t.Session == track.Session).Sequence). - Any(track => track.Pregap > 0)) + tracks.Where(track => track.Sequence != tracks.First(t => t.Session == track.Session).Sequence) + .Any(track => track.Pregap > 0)) { if(!_force) { - _dumpLog.WriteLine("Output format does not support pregaps, this may end in a loss of data, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_pregaps_not_continuing); - StoppingErrorMessage?. - Invoke("Output format does not support pregaps, this may end in a loss of data, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core.Output_format_does_not_support_pregaps_not_continuing); return; } - _dumpLog.WriteLine("Output format does not support pregaps, this may end in a loss of data, continuing..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_pregaps_continuing); - ErrorMessage?. - Invoke("Output format does not support pregaps, this may end in a loss of data, continuing..."); + ErrorMessage?.Invoke(Localization.Core.Output_format_does_not_support_pregaps_continuing); } - for(var t = 1; t < tracks.Length; t++) - tracks[t - 1].EndSector = tracks[t].StartSector - 1; + for(var t = 1; t < tracks.Length; t++) tracks[t - 1].EndSector = tracks[t].StartSector - 1; tracks[^1].EndSector = (ulong) lastSector; blocks = (ulong) (lastSector + 1); if(blocks == 0) { - StoppingErrorMessage?.Invoke("Cannot dump blank media."); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_dump_blank_media); return; } - ResumeSupport.Process(true, true, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial, _dev.PlatformId, - ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision, _private, _force); + ResumeSupport.Process(true, + true, + blocks, + _dev.Manufacturer, + _dev.Model, + _dev.Serial, + _dev.PlatformId, + ref _resume, + ref currentTry, + ref extents, + _dev.FirmwareRevision, + _private, + _force); - if(currentTry == null || - extents == null) + if(currentTry == null || extents == null) { - StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_process_resume_file_not_continuing); return; } @@ -503,16 +534,14 @@ sealed partial class Dump // Read media tags ReadCdTags(ref dskType, mediaTags, out sessions, out firstTrackLastSession); - if(!outputOptical.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreSessions) && - sessions > 1) + if(!outputOptical.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreSessions) && sessions > 1) { // TODO: Disabled until 6.0 /*if(!_force) {*/ - _dumpLog.WriteLine("Output format does not support sessions, this will end in a loss of data, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_sessions); - StoppingErrorMessage?. - Invoke("Output format does not support sessions, this will end in a loss of data, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core.Output_format_does_not_support_sessions); return; /*} @@ -525,32 +554,38 @@ sealed partial class Dump // Check if output format supports all disc tags we have retrieved so far foreach(MediaTagType tag in mediaTags.Keys.Where(tag => !outputOptical.SupportedMediaTags.Contains(tag))) + { if(_force) { - _dumpLog.WriteLine("Output format does not support {0}, continuing...", tag); - ErrorMessage?.Invoke($"Output format does not support {tag}, continuing..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_0_continuing, tag); + ErrorMessage?.Invoke(string.Format(Localization.Core.Output_format_does_not_support_0_continuing, tag)); } else { - _dumpLog.WriteLine("Output format does not support {0}, not continuing...", tag); - StoppingErrorMessage?.Invoke($"Output format does not support {tag}, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_0_not_continuing, tag); + + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Output_format_does_not_support_0_not_continuing, + tag)); return; } + } if(leadOutStarts.Any()) { - UpdateStatus?.Invoke("Solving lead-outs..."); + UpdateStatus?.Invoke(Localization.Core.Solving_lead_outs); foreach(KeyValuePair leadOuts in leadOutStarts) - foreach(Track trk in tracks.Where(trk => trk.Session == leadOuts.Key). - Where(trk => trk.EndSector >= (ulong) leadOuts.Value)) - trk.EndSector = (ulong) leadOuts.Value - 1; + { + foreach(Track trk in tracks.Where(trk => trk.Session == leadOuts.Key) + .Where(trk => trk.EndSector >= (ulong)leadOuts.Value)) + trk.EndSector = (ulong)leadOuts.Value - 1; + } var dataExtents = new ExtentsULong(); - foreach(Track trk in tracks) - dataExtents.Add(trk.StartSector, trk.EndSector); + foreach(Track trk in tracks) dataExtents.Add(trk.StartSector, trk.EndSector); Tuple[] dataExtentsArray = dataExtents.ToArray(); @@ -558,19 +593,37 @@ sealed partial class Dump leadOutExtents.Add(dataExtentsArray[i].Item2 + 1, dataExtentsArray[i + 1].Item1 - 1); } - _dumpLog.WriteLine("Detecting disc type..."); - UpdateStatus?.Invoke("Detecting disc type..."); + _dumpLog.WriteLine(Localization.Core.Detecting_disc_type); + UpdateStatus?.Invoke(Localization.Core.Detecting_disc_type); - MMC.DetectDiscType(ref dskType, sessions, toc, _dev, out hiddenTrack, out hiddenData, firstTrackLastSession, + MMC.DetectDiscType(ref dskType, + sessions, + toc, + _dev, + out hiddenTrack, + out hiddenData, + firstTrackLastSession, blocks); + // Fix CD-i discs with wrong Lead-Out type + if(dskType is MediaType.CDI or MediaType.CDIREADY && tracks.Length == 1 && tracks[0].Type == TrackType.Audio) + tracks[0].Type = TrackType.CdMode2Formless; + if(hiddenTrack || firstLba > 0) { - _dumpLog.WriteLine("Disc contains a hidden track..."); - UpdateStatus?.Invoke("Disc contains a hidden track..."); + _dumpLog.WriteLine(Localization.Core.Disc_contains_a_hidden_track); + UpdateStatus?.Invoke(Localization.Core.Disc_contains_a_hidden_track); - List trkList = new() + if(!outputOptical.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreHiddenTracks)) { + StoppingErrorMessage?.Invoke(Localization.Core.Output_format_does_not_support_hidden_tracks); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_hidden_tracks); + + return; + } + + List trkList = + [ new Track { Sequence = (uint) (tracks.Any(t => t.Sequence == 1) ? 0 : 1), @@ -582,19 +635,17 @@ sealed partial class Dump SubchannelType = subType, EndSector = tracks.First(t => t.Sequence >= 1).StartSector - 1 } - }; + ]; trkList.AddRange(tracks); tracks = trkList.ToArray(); } - if(tracks.Any(t => t.Type == TrackType.Audio) && - desiredSubchannel != MmcSubchannel.Raw) + if(tracks.Any(t => t.Type == TrackType.Audio) && desiredSubchannel != MmcSubchannel.Raw) { - _dumpLog.WriteLine("WARNING: If disc says CD+G, CD+EG, CD-MIDI, CD Graphics or CD Enhanced Graphics, dump will be incorrect!"); + _dumpLog.WriteLine(Localization.Core.WARNING_If_disc_says_CDG_CDEG_CDMIDI_dump_will_be_incorrect); - UpdateStatus?. - Invoke("WARNING: If disc says CD+G, CD+EG, CD-MIDI, CD Graphics or CD Enhanced Graphics, dump will be incorrect!"); + UpdateStatus?.Invoke(Localization.Core.WARNING_If_disc_says_CDG_CDEG_CDMIDI_dump_will_be_incorrect); } // Check mode for tracks @@ -607,18 +658,32 @@ sealed partial class Dump continue; } - _dumpLog.WriteLine("Checking mode for track {0}...", trk.Sequence); - UpdateStatus?.Invoke($"Checking mode for track {trk.Sequence}..."); + _dumpLog.WriteLine(Localization.Core.Checking_mode_for_track_0, trk.Sequence); + UpdateStatus?.Invoke(string.Format(Localization.Core.Checking_mode_for_track_0, trk.Sequence)); - sense = _dev.ReadCd(out cmdBuf, out _, (uint) (trk.StartSector + trk.Pregap), blockSize, 1, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, supportedSubchannel, _dev.Timeout, out _); + sense = _dev.ReadCd(out cmdBuf, + out _, + (uint)(trk.StartSector + trk.Pregap), + blockSize, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out _); if(sense) { - _dumpLog.WriteLine("Unable to guess mode for track {0}, continuing...", trk.Sequence); + _dumpLog.WriteLine(Localization.Core.Unable_to_guess_mode_for_track_0_continuing, trk.Sequence); - UpdateStatus?.Invoke($"Unable to guess mode for track {trk.Sequence}, continuing..."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Unable_to_guess_mode_for_track_0_continuing, + trk.Sequence)); continue; } @@ -638,8 +703,7 @@ sealed partial class Dump cmdBuf[10 + bufOffset] != 0xFF || cmdBuf[11 + bufOffset] != 0x00) { - if(bufOffset + 12 >= cmdBuf.Length) - break; + if(bufOffset + 12 >= cmdBuf.Length) break; bufOffset++; } @@ -648,8 +712,8 @@ sealed partial class Dump { case 1: case 0x61: // Scrambled - UpdateStatus?.Invoke($"Track {trk.Sequence} is MODE1"); - _dumpLog.WriteLine("Track {0} is MODE1", trk.Sequence); + UpdateStatus?.Invoke(string.Format(Localization.Core.Track_0_is_MODE1, trk.Sequence)); + _dumpLog.WriteLine(Localization.Core.Track_0_is_MODE1, trk.Sequence); trk.Type = TrackType.CdMode1; break; @@ -657,8 +721,8 @@ sealed partial class Dump case 0x62: // Scrambled if(dskType is MediaType.CDI or MediaType.CDIREADY) { - UpdateStatus?.Invoke($"Track {trk.Sequence} is MODE2"); - _dumpLog.WriteLine("Track {0} is MODE2", trk.Sequence); + UpdateStatus?.Invoke(string.Format(Localization.Core.Track_0_is_MODE2, trk.Sequence)); + _dumpLog.WriteLine(Localization.Core.Track_0_is_MODE2, trk.Sequence); trk.Type = TrackType.CdMode2Formless; break; @@ -666,25 +730,27 @@ sealed partial class Dump if((cmdBuf[0x012] & 0x20) == 0x20) // mode 2 form 2 { - UpdateStatus?.Invoke($"Track {trk.Sequence} is MODE2 FORM 2"); - _dumpLog.WriteLine("Track {0} is MODE2 FORM 2", trk.Sequence); + UpdateStatus?.Invoke(string.Format(Localization.Core.Track_0_is_MODE2_FORM_2, trk.Sequence)); + _dumpLog.WriteLine(Localization.Core.Track_0_is_MODE2_FORM_2, trk.Sequence); trk.Type = TrackType.CdMode2Form2; break; } - UpdateStatus?.Invoke($"Track {trk.Sequence} is MODE2 FORM 1"); - _dumpLog.WriteLine("Track {0} is MODE2 FORM 1", trk.Sequence); + UpdateStatus?.Invoke(string.Format(Localization.Core.Track_0_is_MODE2_FORM_1, trk.Sequence)); + _dumpLog.WriteLine(Localization.Core.Track_0_is_MODE2_FORM_1, trk.Sequence); trk.Type = TrackType.CdMode2Form1; // These media type specifications do not legally allow mode 2 tracks to be present - if(dskType is MediaType.CDROM or MediaType.CDPLUS or MediaType.CDV) - dskType = MediaType.CD; + if(dskType is MediaType.CDROM or MediaType.CDPLUS or MediaType.CDV) dskType = MediaType.CD; break; default: - UpdateStatus?.Invoke($"Track {trk.Sequence} is unknown mode {cmdBuf[15]}"); - _dumpLog.WriteLine("Track {0} is unknown mode {1}", trk.Sequence, cmdBuf[15]); + UpdateStatus?.Invoke(string.Format(Localization.Core.Track_0_is_unknown_mode_1, + trk.Sequence, + cmdBuf[15])); + + _dumpLog.WriteLine(Localization.Core.Track_0_is_unknown_mode_1, trk.Sequence, cmdBuf[15]); break; } @@ -694,24 +760,30 @@ sealed partial class Dump { if(tracks.Length > 1) { - StoppingErrorMessage?.Invoke("Output format does not support more than 1 track, not continuing..."); - _dumpLog.WriteLine("Output format does not support more than 1 track, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Output_format_does_not_support_more_than_1_track_not_continuing); + + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_more_than_1_track_not_continuing); return; } if(tracks.Any(t => t.Type == TrackType.Audio)) { - StoppingErrorMessage?.Invoke("Output format does not support audio tracks, not continuing..."); - _dumpLog.WriteLine("Output format does not support audio tracks, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Output_format_does_not_support_audio_tracks_not_continuing); + + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_audio_tracks_not_continuing); return; } if(tracks.Any(t => t.Type != TrackType.CdMode1)) { - StoppingErrorMessage?.Invoke("Output format only supports MODE 1 tracks, not continuing..."); - _dumpLog.WriteLine("Output format only supports MODE 1 tracks, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Output_format_only_supports_MODE_1_tracks_not_continuing); + + _dumpLog.WriteLine(Localization.Core.Output_format_only_supports_MODE_1_tracks_not_continuing); return; } @@ -721,86 +793,134 @@ sealed partial class Dump // Check if something prevents from dumping the first track pregap if(_dumpFirstTrackPregap && readcd) + { if(!outputOptical.SupportedMediaTags.Contains(MediaTagType.CD_FirstTrackPregap)) { if(_force) { - _dumpLog.WriteLine("Output format does not support CD first track pregap, continuing..."); - ErrorMessage?.Invoke("Output format does not support CD first track pregap, continuing..."); + _dumpLog.WriteLine(Localization.Core + .Output_format_does_not_support_CD_first_track_pregap_continuing); + + ErrorMessage?.Invoke(Localization.Core + .Output_format_does_not_support_CD_first_track_pregap_continuing); } else { - _dumpLog.WriteLine("Output format does not support CD first track pregap, not continuing..."); + _dumpLog.WriteLine(Localization.Core + .Output_format_does_not_support_CD_first_track_pregap_not_continuing); - StoppingErrorMessage?. - Invoke("Output format does not support CD first track pregap, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Output_format_does_not_support_CD_first_track_pregap_not_continuing); return; } _dumpFirstTrackPregap = false; } + } // Try how many blocks are readable at once while(true) { if(readcd) { - sense = _dev.ReadCd(out cmdBuf, out _, firstLba, blockSize, _maximumReadable, MmcSectorTypes.AllTypes, - false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out _); + sense = _dev.ReadCd(out cmdBuf, + out _, + firstLba, + blockSize, + _maximumReadable, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out _); - if(_dev.Error || sense) - _maximumReadable /= 2; + if(_dev.Error || sense) _maximumReadable /= 2; } else if(read16) { - sense = _dev.Read16(out cmdBuf, out _, 0, false, true, false, firstLba, blockSize, 0, _maximumReadable, - false, _dev.Timeout, out _); + sense = _dev.Read16(out cmdBuf, + out _, + 0, + false, + true, + false, + firstLba, + blockSize, + 0, + _maximumReadable, + false, + _dev.Timeout, + out _); - if(_dev.Error || sense) - _maximumReadable /= 2; + if(_dev.Error || sense) _maximumReadable /= 2; } else if(read12) { - sense = _dev.Read12(out cmdBuf, out _, 0, false, true, false, false, firstLba, blockSize, 0, - _maximumReadable, false, _dev.Timeout, out _); + sense = _dev.Read12(out cmdBuf, + out _, + 0, + false, + true, + false, + false, + firstLba, + blockSize, + 0, + _maximumReadable, + false, + _dev.Timeout, + out _); - if(_dev.Error || sense) - _maximumReadable /= 2; + if(_dev.Error || sense) _maximumReadable /= 2; } else if(read10) { - sense = _dev.Read10(out cmdBuf, out _, 0, false, true, false, false, firstLba, blockSize, 0, - (ushort) _maximumReadable, _dev.Timeout, out _); + sense = _dev.Read10(out cmdBuf, + out _, + 0, + false, + true, + false, + false, + firstLba, + blockSize, + 0, + (ushort)_maximumReadable, + _dev.Timeout, + out _); - if(_dev.Error || sense) - _maximumReadable /= 2; + if(_dev.Error || sense) _maximumReadable /= 2; } else if(read6) { sense = _dev.Read6(out cmdBuf, out _, firstLba, blockSize, (byte) _maximumReadable, _dev.Timeout, out _); - if(_dev.Error || sense) - _maximumReadable /= 2; + if(_dev.Error || sense) _maximumReadable /= 2; } - if(!_dev.Error || - _maximumReadable == 1) - break; + if(!_dev.Error || _maximumReadable == 1) break; } if(_dev.Error || sense) { - _dumpLog.WriteLine("Device error {0} trying to guess ideal transfer length.", _dev.LastError); - StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length."); + _dumpLog.WriteLine(Localization.Core.Device_error_0_trying_to_guess_ideal_transfer_length, _dev.LastError); + + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Device_error_0_trying_to_guess_ideal_transfer_length, + _dev.LastError)); } var cdiWithHiddenTrack1 = false; - if(dskType is MediaType.CDIREADY && - tracks.Min(t => t.Sequence) == 1) + if(dskType is MediaType.CDIREADY && tracks.Min(t => t.Sequence) == 1) { cdiWithHiddenTrack1 = true; dskType = MediaType.CDI; @@ -810,30 +930,38 @@ sealed partial class Dump if(_dumpFirstTrackPregap && readcd) ReadCdFirstTrackPregap(blockSize, ref currentSpeed, mediaTags, supportedSubchannel, ref totalDuration); - _dumpLog.WriteLine("Reading {0} sectors at a time.", _maximumReadable); - _dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize); - _dumpLog.WriteLine("Device can read {0} blocks at a time.", _maximumReadable); - _dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize); - _dumpLog.WriteLine("SCSI device type: {0}.", _dev.ScsiType); - _dumpLog.WriteLine("Media identified as {0}.", dskType); + _dumpLog.WriteLine(Localization.Core.Reading_0_sectors_at_a_time, _maximumReadable); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_blocks_1_bytes, blocks, blocks * blockSize); + _dumpLog.WriteLine(Localization.Core.Device_can_read_0_blocks_at_a_time, _maximumReadable); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize); + _dumpLog.WriteLine(Localization.Core.SCSI_device_type_0, _dev.ScsiType); + _dumpLog.WriteLine(Localization.Core.Media_identified_as_0, dskType); - UpdateStatus?.Invoke($"Reading {_maximumReadable} sectors at a time."); - UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes)."); - UpdateStatus?.Invoke($"Device can read {_maximumReadable} blocks at a time."); - UpdateStatus?.Invoke($"Device reports {blockSize} bytes per logical block."); - UpdateStatus?.Invoke($"SCSI device type: {_dev.ScsiType}."); - UpdateStatus?.Invoke($"Media identified as {dskType}."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time, _maximumReadable)); - ret = outputOptical.Create(_outputPath, dskType, _formatOptions, blocks, + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_blocks_1_bytes, + blocks, + blocks * blockSize)); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_can_read_0_blocks_at_a_time, _maximumReadable)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize)); + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_device_type_0, _dev.ScsiType)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_identified_as_0, dskType)); + + ret = outputOptical.Create(_outputPath, + dskType, + _formatOptions, + blocks, supportsLongSectors ? blockSize : 2048); // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputOptical.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputOptical.ErrorMessage); return; @@ -841,40 +969,38 @@ sealed partial class Dump ErrorNumber errno = outputOptical.ReadMediaTag(MediaTagType.CD_MCN, out byte[] mcnBytes); - if(errno == ErrorNumber.NoError) - mcn = Encoding.ASCII.GetString(mcnBytes); + if(errno == ErrorNumber.NoError) mcn = Encoding.ASCII.GetString(mcnBytes); if(outputOptical.Tracks != null) + { foreach(Track imgTrack in outputOptical.Tracks) { errno = outputOptical.ReadSectorTag(imgTrack.Sequence, SectorTagType.CdTrackIsrc, out byte[] isrcBytes); - if(errno == ErrorNumber.NoError) - isrcs[(byte) imgTrack.Sequence] = Encoding.ASCII.GetString(isrcBytes); + if(errno == ErrorNumber.NoError) isrcs[(byte)imgTrack.Sequence] = Encoding.ASCII.GetString(isrcBytes); Track trk = tracks.FirstOrDefault(t => t.Sequence == imgTrack.Sequence); - if(trk == null) - continue; + if(trk == null) continue; trk.Pregap = imgTrack.Pregap; trk.StartSector = imgTrack.StartSector; trk.EndSector = imgTrack.EndSector; - foreach(KeyValuePair imgIdx in imgTrack.Indexes) - trk.Indexes[imgIdx.Key] = imgIdx.Value; + foreach(KeyValuePair imgIdx in imgTrack.Indexes) trk.Indexes[imgIdx.Key] = imgIdx.Value; } + } // Send track list to output plugin. This may fail if subchannel is set but unsupported. ret = outputOptical.SetTracks(tracks.ToList()); - if(!ret && - desiredSubchannel == MmcSubchannel.None) + if(!ret && desiredSubchannel == MmcSubchannel.None) { - _dumpLog.WriteLine("Error sending tracks to output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_sending_tracks_to_output_image_not_continuing); _dumpLog.WriteLine(outputOptical.ErrorMessage); - StoppingErrorMessage?.Invoke("Error sending tracks to output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_sending_tracks_to_output_image_not_continuing + + Environment.NewLine + outputOptical.ErrorMessage); return; @@ -884,13 +1010,17 @@ sealed partial class Dump if(desiredSubchannel != MmcSubchannel.None && !outputOptical.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreSubchannelRw)) { - _dumpLog.WriteLine("Output image does not support subchannels, {0}continuing...", _force ? "" : "not "); - if(_force) - ErrorMessage?.Invoke("Output image does not support subchannels, continuing..."); + { + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_subchannels_continuing); + ErrorMessage?.Invoke(Localization.Core.Output_format_does_not_support_subchannels_continuing); + } else { - StoppingErrorMessage?.Invoke("Output image does not support subchannels, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Output_format_does_not_support_subchannels_not_continuing); + + StoppingErrorMessage?.Invoke(Localization.Core + .Output_format_does_not_support_subchannels_not_continuing); return; } @@ -898,7 +1028,9 @@ sealed partial class Dump if(supportedSubchannel != MmcSubchannel.None) { - _dumpLog.WriteLine($"Creating subchannel log in {_outputPrefix + ".sub.log"}"); + _dumpLog.WriteLine(string.Format(Localization.Core.Creating_subchannel_log_in_0, + _outputPrefix + ".sub.log")); + subLog = new SubchannelLog(_outputPrefix + ".sub.log", bcdSubchannel); } @@ -907,16 +1039,12 @@ sealed partial class Dump { Track track = tracks.FirstOrDefault(t => t.Sequence == kvp.Key); - if(track is null) - continue; + if(track is null) continue; - _dumpLog.WriteLine("Setting flags for track {0}...", track.Sequence); - UpdateStatus?.Invoke($"Setting flags for track {track.Sequence}..."); + _dumpLog.WriteLine(Localization.Core.Setting_flags_for_track_0, track.Sequence); + UpdateStatus?.Invoke(string.Format(Localization.Core.Setting_flags_for_track_0, track.Sequence)); - outputOptical.WriteSectorTag(new[] - { - kvp.Value - }, kvp.Key, SectorTagType.CdTrackFlags); + outputOptical.WriteSectorTag([kvp.Value], kvp.Key, SectorTagType.CdTrackFlags); } // Set MCN @@ -924,12 +1052,10 @@ sealed partial class Dump { sense = _dev.ReadMcn(out mcn, out _, out _, _dev.Timeout, out _); - if(!sense && - mcn != null && - mcn != "0000000000000") + if(!sense && mcn != null && mcn != "0000000000000") { - UpdateStatus?.Invoke($"Found Media Catalogue Number: {mcn}"); - _dumpLog.WriteLine("Found Media Catalogue Number: {0}", mcn); + UpdateStatus?.Invoke(string.Format(Localization.Core.Found_Media_Catalogue_Number_0, mcn)); + _dumpLog.WriteLine(Localization.Core.Found_Media_Catalogue_Number_0, mcn); } else mcn = null; @@ -937,28 +1063,27 @@ sealed partial class Dump // Set ISRCs if(supportedSubchannel == MmcSubchannel.None) + { foreach(Track trk in tracks) { sense = _dev.ReadIsrc((byte) trk.Sequence, out string isrc, out _, out _, _dev.Timeout, out _); - if(sense || isrc is null or "000000000000") - continue; + if(sense || isrc is null or "000000000000") continue; isrcs[(byte) trk.Sequence] = isrc; - UpdateStatus?.Invoke($"Found ISRC for track {trk.Sequence}: {isrc}"); - _dumpLog.WriteLine($"Found ISRC for track {trk.Sequence}: {isrc}"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Found_ISRC_for_track_0_1, trk.Sequence, isrc)); + _dumpLog.WriteLine(string.Format(Localization.Core.Found_ISRC_for_track_0_1, trk.Sequence, isrc)); } + } - if(supportedSubchannel != MmcSubchannel.None && - desiredSubchannel != MmcSubchannel.None) + if(supportedSubchannel != MmcSubchannel.None && desiredSubchannel != MmcSubchannel.None) { - subchannelExtents = new HashSet(); + subchannelExtents = []; - _resume.BadSubchannels ??= new List(); + _resume.BadSubchannels ??= []; - foreach(int sub in _resume.BadSubchannels) - subchannelExtents.Add(sub); + foreach(int sub in _resume.BadSubchannels) subchannelExtents.Add(sub); if(_resume.NextBlock < blocks) for(ulong i = _resume.NextBlock; i < blocks; i++) @@ -967,18 +1092,21 @@ sealed partial class Dump if(_resume.NextBlock > 0) { - UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}."); - _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); + UpdateStatus?.Invoke(string.Format(Localization.Core.Resuming_from_block_0, _resume.NextBlock)); + _dumpLog.WriteLine(Localization.Core.Resuming_from_block_0, _resume.NextBlock); } - if(_skip < _maximumReadable) - _skip = _maximumReadable; + if(_skip < _maximumReadable) _skip = _maximumReadable; - #if DEBUG +#if DEBUG foreach(Track trk in tracks) - UpdateStatus?. - Invoke($"Track {trk.Sequence} starts at LBA {trk.StartSector} and ends at LBA {trk.EndSector}"); - #endif + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Track_0_starts_at_LBA_1_and_ends_at_LBA_2, + trk.Sequence, + trk.StartSector, + trk.EndSector)); + } +#endif // Check offset if(_fixOffset) @@ -986,26 +1114,30 @@ sealed partial class Dump if(tracks.All(t => t.Type != TrackType.Audio)) { // No audio tracks so no need to fix offset - _dumpLog.WriteLine("No audio tracks, disabling offset fix."); - UpdateStatus.Invoke("No audio tracks, disabling offset fix."); + _dumpLog.WriteLine(Localization.Core.No_audio_tracks_disabling_offset_fix); + UpdateStatus.Invoke(Localization.Core.No_audio_tracks_disabling_offset_fix); _fixOffset = false; } if(!readcd) { - _dumpLog.WriteLine("READ CD command is not supported, disabling offset fix. Dump may not be correct."); + _dumpLog.WriteLine(Localization.Core + .READ_CD_command_is_not_supported_disabling_offset_fix_Dump_may_not_be_correct); - UpdateStatus?. - Invoke("READ CD command is not supported, disabling offset fix. Dump may not be correct."); + UpdateStatus?.Invoke(Localization.Core + .READ_CD_command_is_not_supported_disabling_offset_fix_Dump_may_not_be_correct); _fixOffset = false; } } else if(tracks.Any(t => t.Type == TrackType.Audio)) { - _dumpLog.WriteLine("There are audio tracks and offset fixing is disabled, dump may not be correct."); - UpdateStatus?.Invoke("There are audio tracks and offset fixing is disabled, dump may not be correct."); + _dumpLog.WriteLine(Localization.Core + .There_are_audio_tracks_and_offset_fixing_is_disabled_dump_may_not_be_correct); + + UpdateStatus?.Invoke(Localization.Core + .There_are_audio_tracks_and_offset_fixing_is_disabled_dump_may_not_be_correct); } // Search for read offset in main database @@ -1014,45 +1146,56 @@ sealed partial class Dump d.Manufacturer == _dev.Manufacturer.Replace('/', '-')) && (d.Model == _dev.Model || d.Model == _dev.Model.Replace('/', '-'))); - Core.Media.Info.CompactDisc.GetOffset(cdOffset, _dbDev, _debug, _dev, dskType, _dumpLog, tracks, UpdateStatus, - out int? driveOffset, out int? combinedOffset, out _supportsPlextorD8); + Media.Info.CompactDisc.GetOffset(cdOffset, + _dbDev, + _debug, + _dev, + dskType, + _dumpLog, + tracks, + UpdateStatus, + out int? driveOffset, + out int? combinedOffset, + out _supportsPlextorD8); if(combinedOffset is null) { if(driveOffset is null) { - _dumpLog.WriteLine("Drive reading offset not found in database."); - UpdateStatus?.Invoke("Drive reading offset not found in database."); - _dumpLog.WriteLine("Disc offset cannot be calculated."); - UpdateStatus?.Invoke("Disc offset cannot be calculated."); + _dumpLog.WriteLine(Localization.Core.Drive_reading_offset_not_found_in_database); + UpdateStatus?.Invoke(Localization.Core.Drive_reading_offset_not_found_in_database); + _dumpLog.WriteLine(Localization.Core.Disc_offset_cannot_be_calculated); + UpdateStatus?.Invoke(Localization.Core.Disc_offset_cannot_be_calculated); if(tracks.Any(t => t.Type == TrackType.Audio)) { - _dumpLog.WriteLine("Dump may not be correct."); + _dumpLog.WriteLine(Localization.Core.Dump_may_not_be_correct); - UpdateStatus?.Invoke("Dump may not be correct."); + UpdateStatus?.Invoke(Localization.Core.Dump_may_not_be_correct); } - if(_fixOffset) - _fixOffset = false; + if(_fixOffset) _fixOffset = false; } else { - _dumpLog.WriteLine($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); - UpdateStatus?.Invoke($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); + _dumpLog.WriteLine(string.Format(Localization.Core.Drive_reading_offset_is_0_bytes_1_samples, + driveOffset, + driveOffset / 4)); - _dumpLog.WriteLine("Disc write offset is unknown, dump may not be correct."); - UpdateStatus?.Invoke("Disc write offset is unknown, dump may not be correct."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Drive_reading_offset_is_0_bytes_1_samples, + driveOffset, + driveOffset / 4)); + + _dumpLog.WriteLine(Localization.Core.Disc_write_offset_is_unknown_dump_may_not_be_correct); + UpdateStatus?.Invoke(Localization.Core.Disc_write_offset_is_unknown_dump_may_not_be_correct); offsetBytes = driveOffset.Value; sectorsForOffset = offsetBytes / (int) sectorSize; - if(sectorsForOffset < 0) - sectorsForOffset *= -1; + if(sectorsForOffset < 0) sectorsForOffset *= -1; - if(offsetBytes % sectorSize != 0) - sectorsForOffset++; + if(offsetBytes % sectorSize != 0) sectorsForOffset++; } } else @@ -1060,43 +1203,73 @@ sealed partial class Dump offsetBytes = combinedOffset.Value; sectorsForOffset = offsetBytes / (int) sectorSize; - if(sectorsForOffset < 0) - sectorsForOffset *= -1; + if(sectorsForOffset < 0) sectorsForOffset *= -1; - if(offsetBytes % sectorSize != 0) - sectorsForOffset++; + if(offsetBytes % sectorSize != 0) sectorsForOffset++; if(driveOffset is null) { - _dumpLog.WriteLine("Drive reading offset not found in database."); - UpdateStatus?.Invoke("Drive reading offset not found in database."); - _dumpLog.WriteLine($"Combined disc and drive offsets are {offsetBytes} bytes ({offsetBytes / 4} samples)."); + _dumpLog.WriteLine(Localization.Core.Drive_reading_offset_not_found_in_database); + UpdateStatus?.Invoke(Localization.Core.Drive_reading_offset_not_found_in_database); - UpdateStatus?. - Invoke($"Combined disc and drive offsets are {offsetBytes} bytes ({offsetBytes / 4} samples)."); + _dumpLog.WriteLine(string.Format(Localization.Core.Combined_disc_and_drive_offset_are_0_bytes_1_samples, + offsetBytes, + offsetBytes / 4)); + + UpdateStatus?.Invoke(string.Format(Localization.Core + .Combined_disc_and_drive_offset_are_0_bytes_1_samples, + offsetBytes, + offsetBytes / 4)); } else { - _dumpLog.WriteLine($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); - UpdateStatus?.Invoke($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); + _dumpLog.WriteLine(string.Format(Localization.Core.Drive_reading_offset_is_0_bytes_1_samples, + driveOffset, + driveOffset / 4)); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Drive_reading_offset_is_0_bytes_1_samples, + driveOffset, + driveOffset / 4)); discOffset = offsetBytes - driveOffset; - _dumpLog.WriteLine($"Disc offsets is {discOffset} bytes ({discOffset / 4} samples)"); + _dumpLog.WriteLine(string.Format(Localization.Core.Disc_offset_is_0_bytes_1_samples, + discOffset, + discOffset / 4)); - UpdateStatus?.Invoke($"Disc offsets is {discOffset} bytes ({discOffset / 4} samples)"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Disc_offset_is_0_bytes_1_samples, + discOffset, + discOffset / 4)); } } - if(!_fixOffset || - tracks.All(t => t.Type != TrackType.Audio)) - { - offsetBytes = 0; - sectorsForOffset = 0; - } + mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", + _dev, + blocks, + blockSize, + _maximumReadable, + _private, + _dimensions); - mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, _maximumReadable, _private); - ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0008); + ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0008); + + if(_createGraph) + { + Spiral.DiscParameters discSpiralParameters = Spiral.DiscParametersFromMediaType(dskType); + + if(discSpiralParameters is not null) + _mediaGraph = new Spiral((int)_dimensions, (int)_dimensions, discSpiralParameters, blocks); + else + _mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, blocks); + + if(_mediaGraph is not null) + { + foreach(Tuple e in extents.ToArray()) + _mediaGraph?.PaintSectorsGood(e.Item1, (uint)(e.Item2 - e.Item1 + 2)); + } + + _mediaGraph?.PaintSectorsBad(_resume.BadBlocks); + } audioExtents = new ExtentsULong(); @@ -1106,19 +1279,23 @@ sealed partial class Dump // Set speed if(_speedMultiplier >= 0) { - _dumpLog.WriteLine($"Setting speed to {(_speed == 0 ? "MAX for data reading" : $"{_speed}x")}."); - UpdateStatus?.Invoke($"Setting speed to {(_speed == 0 ? "MAX for data reading" : $"{_speed}x")}."); + _dumpLog.WriteLine(_speed == 0xFFFF + ? Localization.Core.Setting_speed_to_MAX_for_data_reading + : string.Format(Localization.Core.Setting_speed_to_0_x_for_data_reading, _speed)); + + UpdateStatus?.Invoke(_speed == 0xFFFF + ? Localization.Core.Setting_speed_to_MAX_for_data_reading + : string.Format(Localization.Core.Setting_speed_to_0_x_for_data_reading, _speed)); _speed *= _speedMultiplier; - if(_speed is 0 or > 0xFFFF) - _speed = 0xFFFF; + if(_speed is 0 or > 0xFFFF) _speed = 0xFFFF; _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort) _speed, 0, _dev.Timeout, out _); } // Start reading - start = DateTime.UtcNow; + _dumpStopwatch.Restart(); if(dskType == MediaType.CDIREADY || cdiWithHiddenTrack1) { @@ -1128,25 +1305,41 @@ sealed partial class Dump if(!supportsLongSectors) { - _dumpLog.WriteLine("Dumping CD-i Ready requires the output image format to support long sectors."); + _dumpLog.WriteLine(Localization.Core + .Dumping_CD_i_Ready_requires_the_output_image_format_to_support_long_sectors); - StoppingErrorMessage?. - Invoke("Dumping CD-i Ready requires the output image format to support long sectors."); + StoppingErrorMessage?.Invoke(Localization.Core + .Dumping_CD_i_Ready_requires_the_output_image_format_to_support_long_sectors); return; } if(!readcd) { - _dumpLog.WriteLine("Dumping CD-i Ready requires the drive to support the READ CD command."); + _dumpLog.WriteLine(Localization.Core + .Dumping_CD_i_Ready_requires_the_drive_to_support_the_READ_CD_command); - StoppingErrorMessage?.Invoke("Dumping CD-i Ready requires the drive to support the READ CD command."); + StoppingErrorMessage?.Invoke(Localization.Core + .Dumping_CD_i_Ready_requires_the_drive_to_support_the_READ_CD_command); return; } - _dev.ReadCd(out cmdBuf, out _, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, _dev.Timeout, + _dev.ReadCd(out cmdBuf, + out _, + 0, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, out _); hiddenData = IsData(cmdBuf); @@ -1160,65 +1353,127 @@ sealed partial class Dump offsetBytes = combinedOffset.Value; sectorsForOffset = offsetBytes / (int) sectorSize; - if(sectorsForOffset < 0) - sectorsForOffset *= -1; + if(sectorsForOffset < 0) sectorsForOffset *= -1; - if(offsetBytes % sectorSize != 0) - sectorsForOffset++; + if(offsetBytes % sectorSize != 0) sectorsForOffset++; - _dumpLog.WriteLine("Enabling skipping CD-i Ready hole because drive returns data as audio."); + _dumpLog.WriteLine(Localization.Core + .Enabling_skipping_CD_i_Ready_hole_because_drive_returns_data_as_audio); - UpdateStatus?.Invoke("Enabling skipping CD-i Ready hole because drive returns data as audio."); + UpdateStatus?.Invoke(Localization.Core + .Enabling_skipping_CD_i_Ready_hole_because_drive_returns_data_as_audio); _skipCdireadyHole = true; if(driveOffset is null) { - _dumpLog.WriteLine("Drive reading offset not found in database."); - UpdateStatus?.Invoke("Drive reading offset not found in database."); + _dumpLog.WriteLine(Localization.Core.Drive_reading_offset_not_found_in_database); + UpdateStatus?.Invoke(Localization.Core.Drive_reading_offset_not_found_in_database); - _dumpLog. - WriteLine($"Combined disc and drive offsets are {offsetBytes} bytes ({offsetBytes / 4} samples)."); + _dumpLog.WriteLine(string.Format(Localization.Core + .Combined_disc_and_drive_offset_are_0_bytes_1_samples, + offsetBytes, + offsetBytes / 4)); - UpdateStatus?. - Invoke($"Combined disc and drive offsets are {offsetBytes} bytes ({offsetBytes / 4} samples)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Combined_disc_and_drive_offset_are_0_bytes_1_samples, + offsetBytes, + offsetBytes / 4)); } else { - _dumpLog.WriteLine($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); + _dumpLog.WriteLine(string.Format(Localization.Core.Drive_reading_offset_is_0_bytes_1_samples, + driveOffset, + driveOffset / 4)); - UpdateStatus?. - Invoke($"Drive reading offset is {driveOffset} bytes ({driveOffset / 4} samples)."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Drive_reading_offset_is_0_bytes_1_samples, + driveOffset, + driveOffset / 4)); discOffset = offsetBytes - driveOffset; - _dumpLog.WriteLine($"Disc offsets is {discOffset} bytes ({discOffset / 4} samples)"); + _dumpLog.WriteLine(string.Format(Localization.Core.Disc_offset_is_0_bytes_1_samples, + discOffset, + discOffset / 4)); - UpdateStatus?.Invoke($"Disc offsets is {discOffset} bytes ({discOffset / 4} samples)"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Disc_offset_is_0_bytes_1_samples, + discOffset, + discOffset / 4)); } } } if(!_skipCdireadyHole) { - _dumpLog.WriteLine("There will be thousand of errors between track 0 and track 1, that is normal and you can ignore them."); + _dumpLog.WriteLine(Localization.Core + .There_will_be_thousand_of_errors_between_track_0_and_track_1_that_is_normal_and_you_can_ignore_them); - UpdateStatus?. - Invoke("There will be thousand of errors between track 0 and track 1, that is normal and you can ignore them."); + UpdateStatus?.Invoke(Localization.Core + .There_will_be_thousand_of_errors_between_track_0_and_track_1_that_is_normal_and_you_can_ignore_them); } if(_skipCdireadyHole) - ReadCdiReady(blockSize, ref currentSpeed, currentTry, extents, ibgLog, ref imageWriteDuration, - leadOutExtents, ref maxSpeed, mhddLog, ref minSpeed, subSize, supportedSubchannel, - ref totalDuration, tracks, subLog, desiredSubchannel, isrcs, ref mcn, subchannelExtents, - blocks, cdiReadyReadAsAudio, offsetBytes, sectorsForOffset, smallestPregapLbaPerTrack); + { + ReadCdiReady(blockSize, + ref currentSpeed, + currentTry, + extents, + ibgLog, + ref imageWriteDuration, + leadOutExtents, + ref maxSpeed, + mhddLog, + ref minSpeed, + subSize, + supportedSubchannel, + ref totalDuration, + tracks, + subLog, + desiredSubchannel, + isrcs, + ref mcn, + subchannelExtents, + blocks, + cdiReadyReadAsAudio, + offsetBytes, + sectorsForOffset, + smallestPregapLbaPerTrack); + } } - ReadCdData(audioExtents, blocks, blockSize, ref currentSpeed, currentTry, extents, ibgLog, - ref imageWriteDuration, lastSector, leadOutExtents, ref maxSpeed, mhddLog, ref minSpeed, out newTrim, - tracks[0].Type != TrackType.Audio, offsetBytes, read6, read10, read12, read16, readcd, - sectorsForOffset, subSize, supportedSubchannel, supportsLongSectors, ref totalDuration, tracks, - subLog, desiredSubchannel, isrcs, ref mcn, subchannelExtents, smallestPregapLbaPerTrack); + ReadCdData(audioExtents, + blocks, + blockSize, + ref currentSpeed, + currentTry, + extents, + ibgLog, + ref imageWriteDuration, + lastSector, + leadOutExtents, + ref maxSpeed, + mhddLog, + ref minSpeed, + out newTrim, + tracks[0].Type != TrackType.Audio, + offsetBytes, + read6, + read10, + read12, + read16, + readcd, + sectorsForOffset, + subSize, + supportedSubchannel, + supportsLongSectors, + ref totalDuration, + tracks, + subLog, + desiredSubchannel, + isrcs, + ref mcn, + subchannelExtents, + smallestPregapLbaPerTrack); // TODO: Enable when underlying images support lead-outs /* @@ -1228,108 +1483,184 @@ sealed partial class Dump smallestPregapLbaPerTrack); */ - end = DateTime.UtcNow; + _dumpStopwatch.Stop(); mhddLog.Close(); - ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double) (blocks + 1) / 1024 / (totalDuration / 1000), _devicePath); + ibgLog.Close(_dev, + blocks, + blockSize, + _dumpStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), + _devicePath); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {blockSize * (double) (blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {blockSize * (double) (blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - blockSize * (double) (blocks + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - blockSize * (double) (blocks + 1) / 1024 / imageWriteDuration); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - TrimCdUserData(audioExtents, blockSize, currentTry, extents, newTrim, offsetBytes, read6, read10, read12, - read16, readcd, sectorsForOffset, subSize, supportedSubchannel, supportsLongSectors, - ref totalDuration, subLog, desiredSubchannel, tracks, isrcs, ref mcn, subchannelExtents, + TrimCdUserData(audioExtents, + blockSize, + currentTry, + extents, + newTrim, + offsetBytes, + read6, + read10, + read12, + read16, + readcd, + sectorsForOffset, + subSize, + supportedSubchannel, + supportsLongSectors, + ref totalDuration, + subLog, + desiredSubchannel, + tracks, + isrcs, + ref mcn, + subchannelExtents, smallestPregapLbaPerTrack); - if(dskType is MediaType.CDR or MediaType.CDRW && - _resume.BadBlocks.Count > 0 && - _ignoreCdrRunOuts > 0) - HandleCdrRunOutSectors(blocks, desiredSubchannel, extents, subchannelExtents, subLog, supportsLongSectors, - trackFlags, tracks); + if(dskType is MediaType.CDR or MediaType.CDRW && _resume.BadBlocks.Count > 0 && _ignoreCdrRunOuts > 0) + { + HandleCdrRunOutSectors(blocks, + desiredSubchannel, + extents, + subchannelExtents, + subLog, + supportsLongSectors, + trackFlags, + tracks); + } - RetryCdUserData(audioExtents, blockSize, currentTry, extents, offsetBytes, readcd, sectorsForOffset, subSize, - supportedSubchannel, ref totalDuration, subLog, desiredSubchannel, tracks, isrcs, ref mcn, - subchannelExtents, smallestPregapLbaPerTrack, supportsLongSectors); + RetryCdUserData(audioExtents, + blockSize, + currentTry, + extents, + offsetBytes, + readcd, + sectorsForOffset, + subSize, + supportedSubchannel, + ref totalDuration, + subLog, + desiredSubchannel, + tracks, + isrcs, + ref mcn, + subchannelExtents, + smallestPregapLbaPerTrack, + supportsLongSectors); foreach(Tuple leadoutExtent in leadOutExtents.ToArray()) for(ulong e = leadoutExtent.Item1; e <= leadoutExtent.Item2; e++) subchannelExtents.Remove((int) e); - if(subchannelExtents.Count > 0 && - _retryPasses > 0 && - _retrySubchannel) - RetrySubchannel(readcd, subSize, supportedSubchannel, ref totalDuration, subLog, desiredSubchannel, tracks, - isrcs, ref mcn, subchannelExtents, smallestPregapLbaPerTrack); + if(subchannelExtents.Count > 0 && _retryPasses > 0 && _retrySubchannel) + { + RetrySubchannel(readcd, + subSize, + supportedSubchannel, + ref totalDuration, + subLog, + desiredSubchannel, + tracks, + isrcs, + ref mcn, + subchannelExtents, + smallestPregapLbaPerTrack); + } // Write media tags to image if(!_aborted) + { foreach(KeyValuePair tag in mediaTags) { if(tag.Value is null) { - AaruConsole.ErrorWriteLine("Error: Tag type {0} is null, skipping...", tag.Key); + AaruConsole.ErrorWriteLine(Localization.Core.Error_Tag_type_0_is_null_skipping, tag.Key); continue; } ret = outputOptical.WriteMediaTag(tag.Value, tag.Key); - if(ret || _force) - continue; + if(ret || _force) continue; // Cannot write tag to image - _dumpLog.WriteLine($"Cannot write tag {tag.Key}."); + _dumpLog.WriteLine(string.Format(Localization.Core.Cannot_write_tag_0, tag.Key)); StoppingErrorMessage?.Invoke(outputOptical.ErrorMessage); return; } + } _resume.BadBlocks.Sort(); - foreach(ulong bad in _resume.BadBlocks) - _dumpLog.WriteLine("Sector {0} could not be read.", bad); + foreach(ulong bad in _resume.BadBlocks) _dumpLog.WriteLine(Localization.Core.Sector_0_could_not_be_read, bad); currentTry.Extents = ExtentsConverter.ToMetadata(extents); - _resume.BadSubchannels = new List(); + _resume.BadSubchannels = []; _resume.BadSubchannels.AddRange(subchannelExtents); _resume.BadSubchannels.Sort(); if(_generateSubchannels && outputOptical.SupportedSectorTags.Contains(SectorTagType.CdSectorSubchannel) && !_aborted) - Core.Media.CompactDisc.GenerateSubchannels(subchannelExtents, tracks, trackFlags, blocks, subLog, _dumpLog, - InitProgress, UpdateProgress, EndProgress, outputOptical); + { + Media.CompactDisc.GenerateSubchannels(subchannelExtents, + tracks, + trackFlags, + blocks, + subLog, + _dumpLog, + InitProgress, + UpdateProgress, + EndProgress, + outputOptical); + } // TODO: Disc ID - var metadata = new ImageInfo + var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; - if(!outputOptical.SetMetadata(metadata)) - ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + + if(!outputOptical.SetImageInfo(metadata)) + { + ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + + Environment.NewLine + outputOptical.ErrorMessage); + } outputOptical.SetDumpHardware(_resume.Tries); - if(_preSidecar != null) - outputOptical.SetCicmMetadata(_preSidecar); + if(_preSidecar != null) outputOptical.SetMetadata(_preSidecar); foreach(KeyValuePair isrc in isrcs) { @@ -1337,25 +1668,22 @@ sealed partial class Dump if(!outputOptical.WriteSectorTag(Encoding.ASCII.GetBytes(isrc.Value), isrc.Key, SectorTagType.CdTrackIsrc)) continue; - UpdateStatus?.Invoke($"Setting ISRC for track {isrc.Key} to {isrc.Value}"); - _dumpLog.WriteLine("Setting ISRC for track {0} to {1}", isrc.Key, isrc.Value); + UpdateStatus?.Invoke(string.Format(Localization.Core.Setting_ISRC_for_track_0_to_1, isrc.Key, isrc.Value)); + _dumpLog.WriteLine(Localization.Core.Setting_ISRC_for_track_0_to_1, isrc.Key, isrc.Value); } - if(mcn != null && - outputOptical.WriteMediaTag(Encoding.ASCII.GetBytes(mcn), MediaTagType.CD_MCN)) + if(mcn != null && outputOptical.WriteMediaTag(Encoding.ASCII.GetBytes(mcn), MediaTagType.CD_MCN)) { - UpdateStatus?.Invoke($"Setting disc Media Catalogue Number to {mcn}"); - _dumpLog.WriteLine("Setting disc Media Catalogue Number to {0}", mcn); + UpdateStatus?.Invoke(string.Format(Localization.Core.Setting_disc_Media_Catalogue_Number_to_0, mcn)); + _dumpLog.WriteLine(Localization.Core.Setting_disc_Media_Catalogue_Number_to_0, mcn); } foreach(Track trk in tracks) { // Fix track starts in each session's first track - if(tracks.Where(t => t.Session == trk.Session).OrderBy(t => t.Sequence).FirstOrDefault().Sequence == - trk.Sequence) + if(tracks.Where(t => t.Session == trk.Session).MinBy(t => t.Sequence).Sequence == trk.Sequence) { - if(trk.Sequence == 1) - continue; + if(trk.Sequence == 1) continue; trk.StartSector -= trk.Pregap; trk.Indexes[0] = (int) trk.StartSector; @@ -1363,26 +1691,26 @@ sealed partial class Dump continue; } - if(trk.Indexes.TryGetValue(0, out int idx0) && - trk.Indexes.TryGetValue(1, out int idx1) && - idx0 == idx1) + if(trk.Indexes.TryGetValue(0, out int idx0) && trk.Indexes.TryGetValue(1, out int idx1) && idx0 == idx1) trk.Indexes.Remove(0); } outputOptical.SetTracks(tracks.ToList()); - _dumpLog.WriteLine("Closing output file."); - UpdateStatus?.Invoke("Closing output file."); - DateTime closeStart = DateTime.Now; + _dumpLog.WriteLine(Localization.Core.Closing_output_file); + UpdateStatus?.Invoke(Localization.Core.Closing_output_file); + _imageCloseStopwatch.Restart(); outputOptical.Close(); - DateTime closeEnd = DateTime.Now; - UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); + _imageCloseStopwatch.Stop(); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); subLog?.Close(); if(_aborted) { - _dumpLog.WriteLine("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); return; } @@ -1390,27 +1718,50 @@ sealed partial class Dump double totalChkDuration = 0; if(_metadata) - WriteOpticalSidecar(blockSize, blocks, dskType, null, mediaTags, sessions, out totalChkDuration, + { + WriteOpticalSidecar(blockSize, + blocks, + dskType, + null, + mediaTags, + sessions, + out totalChkDuration, discOffset); + } - end = DateTime.UtcNow; + _dumpStopwatch.Stop(); UpdateStatus?.Invoke(""); - UpdateStatus?. - Invoke($"Took a total of {(end - dumpStart).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second), + totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second), + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average speed: {blockSize * (double) (blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); if(maxSpeed > 0) - UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0, + ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize())); + } - if(minSpeed > 0 && - minSpeed < double.MaxValue) - UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); + if(minSpeed is > 0 and < double.MaxValue) + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0, + ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize())); + } + + UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_could_not_be_read, _resume.BadBlocks.Count)); + + UpdateStatus?.Invoke(string.Format(Localization.Core._0_subchannels_could_not_be_read, + _resume.BadSubchannels.Count)); - UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); - UpdateStatus?.Invoke($"{_resume.BadSubchannels.Count} subchannels could not be read."); UpdateStatus?.Invoke(""); Statistics.AddMedia(dskType, true); diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Error.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Error.cs index 527f54276..1e4a0abbf 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Error.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Error.cs @@ -27,30 +27,31 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.Linq; +using Aaru.Checksums; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Console; using Aaru.Core.Logging; using Aaru.Decoders.CD; using Aaru.Decoders.SCSI; using Aaru.Devices; -using Schemas; +using Track = Aaru.CommonTypes.Structs.Track; using TrackType = Aaru.CommonTypes.Enums.TrackType; +namespace Aaru.Core.Devices.Dumping; + partial class Dump { /// Retried errored sectors in CompactDisc @@ -72,7 +73,7 @@ partial class Dump /// Disc media catalogue number /// List of subchannels not yet dumped correctly /// List of smallest pregap relative address per track - void RetryCdUserData(ExtentsULong audioExtents, uint blockSize, DumpHardwareType currentTry, ExtentsULong extents, + void RetryCdUserData(ExtentsULong audioExtents, uint blockSize, DumpHardware currentTry, ExtentsULong extents, int offsetBytes, bool readcd, int sectorsForOffset, uint subSize, MmcSubchannel supportedSubchannel, ref double totalDuration, SubchannelLog subLog, MmcSubchannel desiredSubchannel, Track[] tracks, Dictionary isrcs, @@ -87,30 +88,15 @@ partial class Dump PlextorSubchannel supportedPlextorSubchannel; var outputOptical = _outputPlugin as IWritableOpticalImage; - switch(supportedSubchannel) - { - case MmcSubchannel.None: - supportedPlextorSubchannel = PlextorSubchannel.None; + supportedPlextorSubchannel = supportedSubchannel switch + { + MmcSubchannel.None => PlextorSubchannel.None, + MmcSubchannel.Raw => PlextorSubchannel.Pack, + MmcSubchannel.Q16 => PlextorSubchannel.Q16, + _ => PlextorSubchannel.None + }; - break; - case MmcSubchannel.Raw: - supportedPlextorSubchannel = PlextorSubchannel.Pack; - - break; - case MmcSubchannel.Q16: - supportedPlextorSubchannel = PlextorSubchannel.Q16; - - break; - default: - supportedPlextorSubchannel = PlextorSubchannel.None; - - break; - } - - if(_resume.BadBlocks.Count <= 0 || - _aborted || - _retryPasses <= 0) - return; + if(_resume.BadBlocks.Count <= 0 || _aborted || _retryPasses <= 0) return; var pass = 1; var forward = true; @@ -124,12 +110,25 @@ partial class Dump { Modes.ModePage_01_MMC pgMmc; - sense = _dev.ModeSense6(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, 0x01, _dev.Timeout, + sense = _dev.ModeSense6(out cmdBuf, + out _, + false, + ScsiModeSensePageControl.Current, + 0x01, + _dev.Timeout, out _); - if(sense) + Modes.DecodedMode? dcMode6 = null; + if(!sense) dcMode6 = Modes.DecodeMode6(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice); + + if(sense || dcMode6 is null) { - sense = _dev.ModeSense10(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, 0x01, _dev.Timeout, + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + ScsiModeSensePageControl.Current, + 0x01, + _dev.Timeout, out _); if(!sense) @@ -137,19 +136,23 @@ partial class Dump Modes.DecodedMode? dcMode10 = Modes.DecodeMode10(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice); if(dcMode10?.Pages != null) + { foreach(Modes.ModePage modePage in dcMode10.Value.Pages.Where(modePage => - modePage.Page == 0x01 && modePage.Subpage == 0x00)) + modePage is { Page: 0x01, Subpage: 0x00 })) currentModePage = modePage; + } } } else { - Modes.DecodedMode? dcMode6 = Modes.DecodeMode6(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice); - - if(dcMode6?.Pages != null) - foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage => modePage.Page == 0x01 && - modePage.Subpage == 0x00)) + if(dcMode6.Value.Pages != null) + { + foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage => modePage is + { + Page: 0x01, Subpage: 0x00 + })) currentModePage = modePage; + } } if(currentModePage == null) @@ -179,35 +182,35 @@ partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { + Pages = + [ new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01_MMC(pgMmc) } - } + ] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); md10 = Modes.EncodeMode10(md, _dev.ScsiType); - UpdateStatus?.Invoke("Sending MODE SELECT to drive (return damaged blocks)."); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks)."); + UpdateStatus?.Invoke(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); sense = _dev.ModeSelect(md6, out senseBuf, true, false, _dev.Timeout, out _); - if(sense) - sense = _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); + if(sense) sense = _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); if(sense) { - UpdateStatus?. - Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + UpdateStatus?.Invoke(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); - AaruConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(Localization.Core.Error_0, Sense.PrettifySense(senseBuf)); - _dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + _dumpLog.WriteLine(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); } else runningPersistent = true; @@ -215,8 +218,8 @@ partial class Dump InitProgress?.Invoke(); cdRepeatRetry: - ulong[] tmpArray = _resume.BadBlocks.ToArray(); - var sectorsNotEvenPartial = new List(); + ulong[] tmpArray = _resume.BadBlocks.ToArray(); + List sectorsNotEvenPartial = []; for(var i = 0; i < tmpArray.Length; i++) { @@ -225,34 +228,61 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - _dumpLog.WriteLine("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass, - forward ? "forward" : "reverse", - runningPersistent ? "recovering partial data, " : "")); + if(forward) + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_forward, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_forward, + badSector, + pass)); + } + else + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_reverse, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_reverse, + badSector, + pass)); + } Track track = tracks.OrderBy(t => t.StartSector).LastOrDefault(t => badSector >= t.StartSector); byte sectorsToReRead = 1; var badSectorToReRead = (uint)badSector; - if(_fixOffset && - audioExtents.Contains(badSector) && - offsetBytes != 0) + if(_fixOffset && audioExtents.Contains(badSector) && offsetBytes != 0) { - if(offsetBytes > 0) - badSectorToReRead -= (uint)sectorsForOffset; + if(offsetBytes < 0) + { + if(badSectorToReRead == 0) + badSectorToReRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1 + else + badSectorToReRead -= (uint)sectorsForOffset; + } - sectorsToReRead = (byte)(sectorsForOffset + 1); + sectorsToReRead += (byte)sectorsForOffset; } if(_supportsPlextorD8 && audioExtents.Contains(badSector)) { - sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, badSectorToReRead, blockSize, - sectorsToReRead, supportedPlextorSubchannel, out cmdDuration); + sense = ReadPlextorWithSubchannel(out cmdBuf, + out senseBuf, + badSectorToReRead, + blockSize, + sectorsToReRead, + supportedPlextorSubchannel, + out cmdDuration); totalDuration += cmdDuration; } @@ -260,21 +290,45 @@ partial class Dump { if(audioExtents.Contains(badSector)) { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, badSectorToReRead, blockSize, sectorsToReRead, - MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + badSectorToReRead, + blockSize, + sectorsToReRead, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); if(sense) { DecodedSense? decSense = Sense.Decode(senseBuf); // Try to workaround firmware - if(decSense?.ASC == 0x11 && decSense?.ASCQ == 0x05 || - decSense?.ASC == 0x64) + if(decSense is { ASC: 0x11, ASCQ: 0x05 } || decSense?.ASC == 0x64) { - sense = _dev.ReadCd(out cmdBuf, out _, badSectorToReRead, blockSize, sectorsToReRead, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, - true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, + sense = _dev.ReadCd(out cmdBuf, + out _, + badSectorToReRead, + blockSize, + sectorsToReRead, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, out double cmdDuration2); cmdDuration += cmdDuration2; @@ -283,24 +337,121 @@ partial class Dump } else { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, badSectorToReRead, blockSize, sectorsToReRead, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + badSectorToReRead, + blockSize, + sectorsToReRead, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); if(sense) { DecodedSense? decSense = Sense.Decode(senseBuf); // Try to workaround firmware - if(decSense?.ASC == 0x11 && decSense?.ASCQ == 0x05 || - decSense?.ASC == 0x64) + if(decSense is { ASC: 0x11, ASCQ: 0x05 } || decSense?.ASC == 0x64) { - sense = _dev.ReadCd(out cmdBuf, out _, badSectorToReRead, blockSize, sectorsToReRead, - MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, supportedSubchannel, _dev.Timeout, + byte scrambledSectorsToReRead = sectorsToReRead; + uint scrambledBadSectorToReRead = badSectorToReRead; + + // Contrary to normal read, this must always be offset fixed, because it's data not audio + if(offsetBytes != 0) + { + if(offsetBytes < 0) + { + if(scrambledBadSectorToReRead == 0) + scrambledBadSectorToReRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1 + else + scrambledBadSectorToReRead -= (uint)sectorsForOffset; + } + + scrambledSectorsToReRead += (byte)sectorsForOffset; + } + + sense = _dev.ReadCd(out cmdBuf, + out _, + scrambledBadSectorToReRead, + blockSize, + scrambledSectorsToReRead, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, out double cmdDuration2); cmdDuration += cmdDuration2; + + if(!sense) + { + uint scrambledBlocksToReRead = scrambledSectorsToReRead; + + FixOffsetData(offsetBytes, + sectorSize, + sectorsForOffset, + supportedSubchannel, + ref scrambledBlocksToReRead, + subSize, + ref cmdBuf, + blockSize, + false); + + // Descramble + cmdBuf = Sector.Scramble(cmdBuf); + + // Check valid sector + CdChecksums.CheckCdSector(cmdBuf, + out bool? correctEccP, + out bool? correctEccQ, + out bool? correctEdc); + + // Check mode, set sense if EDC/ECC validity is not correct + switch(cmdBuf[15] & 0x03) + { + case 0: + + for(var c = 16; c < 2352; c++) + { + if(cmdBuf[c] == 0x00) continue; + + sense = true; + + break; + } + + break; + case 1: + sense = correctEdc != true || correctEccP != true || correctEccQ != true; + + break; + case 2: + if((cmdBuf[18] & 0x20) != 0x20) + { + if(correctEccP != true) sense = true; + + if(correctEccQ != true) sense = true; + } + + if(correctEdc != true) sense = true; + + break; + } + } } } } @@ -312,35 +463,44 @@ partial class Dump { _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); - if(!runningPersistent) - continue; + if(!runningPersistent) continue; DecodedSense? decSense = Sense.Decode(senseBuf); // MEDIUM ERROR, retry with ignore error below if(decSense is { ASC: 0x11 }) - if(!sectorsNotEvenPartial.Contains(badSector)) - sectorsNotEvenPartial.Add(badSector); + { + if(!sectorsNotEvenPartial.Contains(badSector)) sectorsNotEvenPartial.Add(badSector); + } } // Because one block has been partially used to fix the offset - if(_fixOffset && - audioExtents.Contains(badSector) && - offsetBytes != 0) + if(_fixOffset && audioExtents.Contains(badSector) && offsetBytes != 0) { uint blocksToRead = sectorsToReRead; - FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead, subSize, - ref cmdBuf, blockSize, false); + FixOffsetData(offsetBytes, + sectorSize, + sectorsForOffset, + supportedSubchannel, + ref blocksToRead, + subSize, + ref cmdBuf, + blockSize, + false); } - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { _resume.BadBlocks.Remove(badSector); extents.Add(badSector); - UpdateStatus?.Invoke($"Correctly retried sector {badSector} in pass {pass}."); - _dumpLog.WriteLine("Correctly retried sector {0} in pass {1}.", badSector, pass); + _mediaGraph?.PaintSectorGood(badSector); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_sector_0_in_pass_1, + badSector, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_sector_0_in_pass_1, badSector, pass); sectorsNotEvenPartial.Remove(badSector); } else @@ -350,26 +510,37 @@ partial class Dump { var data = new byte[sectorSize]; var sub = new byte[subSize]; - Array.Copy(cmdBuf, 0, data, 0, sectorSize); - Array.Copy(cmdBuf, sectorSize, sub, 0, subSize); + Array.Copy(cmdBuf, 0, data, 0, sectorSize); + Array.Copy(cmdBuf, sectorSize, sub, 0, subSize); if(supportsLongSectors) outputOptical.WriteSectorLong(data, badSector); else outputOptical.WriteSector(Sector.GetUserData(data), badSector); - bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, desiredSubchannel, - sub, badSector, 1, subLog, isrcs, - (byte)track.Sequence, ref mcn, tracks, + bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, + desiredSubchannel, + sub, + badSector, + 1, + subLog, + isrcs, + (byte)track.Sequence, + ref mcn, + tracks, subchannelExtents, - _fixSubchannelPosition, outputOptical, - _fixSubchannel, _fixSubchannelCrc, - _dumpLog, UpdateStatus, - smallestPregapLbaPerTrack, true, out _); + _fixSubchannelPosition, + outputOptical, + _fixSubchannel, + _fixSubchannelCrc, + _dumpLog, + UpdateStatus, + smallestPregapLbaPerTrack, + true, + out _); // Set tracks and go back - if(!indexesChanged) - continue; + if(!indexesChanged) continue; outputOptical.SetTracks(tracks.ToList()); i--; @@ -383,16 +554,13 @@ partial class Dump } } - if(pass < _retryPasses && - !_aborted && - _resume.BadBlocks.Count > 0) + if(pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); - if(!forward) - _resume.BadBlocks.Reverse(); + if(!forward) _resume.BadBlocks.Reverse(); goto cdRepeatRetry; } @@ -419,25 +587,24 @@ partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { + Pages = + [ new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01_MMC(pgMmc) } - } + ] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); md10 = Modes.EncodeMode10(md, _dev.ScsiType); - _dumpLog.WriteLine("Sending MODE SELECT to drive (ignore error correction)."); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_ignore_error_correction); sense = _dev.ModeSelect(md6, out senseBuf, true, false, _dev.Timeout, out _); - if(sense) - sense = _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); + if(sense) sense = _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); if(!sense) { @@ -452,20 +619,33 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - _dumpLog.WriteLine("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke($"Trying to get partial data for sector {badSector}"); + PulseProgress?.Invoke(string.Format(Localization.Core.Trying_to_get_partial_data_for_sector_0, + badSector)); Track track = tracks.OrderBy(t => t.StartSector).LastOrDefault(t => badSector >= t.StartSector); if(readcd) { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)badSector, blockSize, 1, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, - true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + (uint)badSector, + blockSize, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, out cmdDuration); totalDuration += cmdDuration; @@ -478,14 +658,14 @@ partial class Dump continue; } - _dumpLog.WriteLine("Got partial data for sector {0} in pass {1}.", badSector, pass); + _dumpLog.WriteLine(Localization.Core.Got_partial_data_for_sector_0_in_pass_1, badSector, pass); if(supportedSubchannel != MmcSubchannel.None) { var data = new byte[sectorSize]; var sub = new byte[subSize]; - Array.Copy(cmdBuf, 0, data, 0, sectorSize); - Array.Copy(cmdBuf, sectorSize, sub, 0, subSize); + Array.Copy(cmdBuf, 0, data, 0, sectorSize); + Array.Copy(cmdBuf, sectorSize, sub, 0, subSize); if(supportsLongSectors) outputOptical.WriteSectorLong(data, badSector); @@ -493,13 +673,28 @@ partial class Dump outputOptical.WriteSector(Sector.GetUserData(data), badSector); bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, - desiredSubchannel, sub, badSector, 1, subLog, isrcs, (byte)track.Sequence, ref mcn, - tracks, subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel, - _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true, out _); + desiredSubchannel, + sub, + badSector, + 1, + subLog, + isrcs, + (byte)track.Sequence, + ref mcn, + tracks, + subchannelExtents, + _fixSubchannelPosition, + outputOptical, + _fixSubchannel, + _fixSubchannelCrc, + _dumpLog, + UpdateStatus, + smallestPregapLbaPerTrack, + true, + out _); // Set tracks and go back - if(!indexesChanged) - continue; + if(!indexesChanged) continue; outputOptical.SetTracks(tracks.ToList()); i--; @@ -522,20 +717,16 @@ partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { - currentModePage.Value - } + Pages = [currentModePage.Value] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); md10 = Modes.EncodeMode10(md, _dev.ScsiType); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status)."); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_device_to_previous_status); sense = _dev.ModeSelect(md6, out senseBuf, true, false, _dev.Timeout, out _); - if(sense) - _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); + if(sense) _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); } EndProgress?.Invoke(); @@ -565,36 +756,17 @@ partial class Dump PlextorSubchannel supportedPlextorSubchannel; var outputOptical = _outputPlugin as IWritableOpticalImage; - if(supportedSubchannel == MmcSubchannel.None || - desiredSubchannel == MmcSubchannel.None) - return; + if(supportedSubchannel == MmcSubchannel.None || desiredSubchannel == MmcSubchannel.None) return; - switch(supportedSubchannel) - { - case MmcSubchannel.None: - supportedPlextorSubchannel = PlextorSubchannel.None; + supportedPlextorSubchannel = supportedSubchannel switch + { + MmcSubchannel.Raw => PlextorSubchannel.All, + MmcSubchannel.Q16 => PlextorSubchannel.Q16, + MmcSubchannel.Rw => PlextorSubchannel.Pack, + _ => PlextorSubchannel.None + }; - break; - case MmcSubchannel.Raw: - supportedPlextorSubchannel = PlextorSubchannel.All; - - break; - case MmcSubchannel.Q16: - supportedPlextorSubchannel = PlextorSubchannel.Q16; - - break; - case MmcSubchannel.Rw: - supportedPlextorSubchannel = PlextorSubchannel.Pack; - - break; - default: - supportedPlextorSubchannel = PlextorSubchannel.None; - - break; - } - - if(_aborted) - return; + if(_aborted) return; var pass = 1; var forward = true; @@ -603,12 +775,11 @@ partial class Dump cdRepeatRetry: - _resume.BadSubchannels = new List(); + _resume.BadSubchannels = []; _resume.BadSubchannels.AddRange(subchannelExtents); _resume.BadSubchannels.Sort(); - if(!forward) - _resume.BadSubchannels.Reverse(); + if(!forward) _resume.BadSubchannels.Reverse(); int[] tmpArray = _resume.BadSubchannels.ToArray(); @@ -620,29 +791,52 @@ partial class Dump if(_aborted) { - _dumpLog.WriteLine("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?. - Invoke($"Retrying sector {badSector} subchannel, pass {pass}, {(forward ? "forward" : "reverse")}"); + PulseProgress?.Invoke(forward + ? string.Format(Localization.Core.Retrying_sector_0_subchannel_pass_1_forward, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_subchannel_pass_1_reverse, + badSector, + pass)); uint startSector = badSector - 2; if(_supportsPlextorD8) { - sense = _dev.PlextorReadCdDa(out cmdBuf, out senseBuf, startSector, subSize, 5, - supportedPlextorSubchannel, 0, out cmdDuration); + sense = _dev.PlextorReadCdDa(out cmdBuf, + out senseBuf, + startSector, + subSize, + 5, + supportedPlextorSubchannel, + 0, + out cmdDuration); totalDuration += cmdDuration; } else if(readcd) { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, startSector, subSize, 5, + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + startSector, + subSize, + 5, track.Type == TrackType.Audio ? MmcSectorTypes.Cdda : MmcSectorTypes.AllTypes, - false, false, false, MmcHeaderCodes.None, false, false, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out cmdDuration); + false, + false, + false, + MmcHeaderCodes.None, + false, + false, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); totalDuration += cmdDuration; } @@ -654,22 +848,37 @@ partial class Dump continue; } - Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, desiredSubchannel, cmdBuf, badSector, 5, - subLog, isrcs, (byte)track.Sequence, ref mcn, tracks, - subchannelExtents, _fixSubchannelPosition, outputOptical, - _fixSubchannel, _fixSubchannelCrc, _dumpLog, UpdateStatus, - smallestPregapLbaPerTrack, true, out _); + Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, + desiredSubchannel, + cmdBuf, + badSector, + 5, + subLog, + isrcs, + (byte)track.Sequence, + ref mcn, + tracks, + subchannelExtents, + _fixSubchannelPosition, + outputOptical, + _fixSubchannel, + _fixSubchannelCrc, + _dumpLog, + UpdateStatus, + smallestPregapLbaPerTrack, + true, + out _); - if(subchannelExtents.Contains(bs)) - continue; + if(subchannelExtents.Contains(bs)) continue; - UpdateStatus?.Invoke($"Correctly retried sector {badSector} subchannel in pass {pass}."); - _dumpLog.WriteLine("Correctly retried sector {0} subchannel in pass {1}.", badSector, pass); + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_sector_0_subchannel_in_pass_1, + badSector, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_sector_0_subchannel_in_pass_1, badSector, pass); } - if(pass < _retryPasses && - !_aborted && - subchannelExtents.Count > 0) + if(pass < _retryPasses && !_aborted && subchannelExtents.Count > 0) { pass++; forward = !forward; diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/LeadOuts.cs b/Aaru.Core/Devices/Dumping/CompactDisc/LeadOuts.cs index f793d08c2..56413a91e 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/LeadOuts.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/LeadOuts.cs @@ -27,25 +27,28 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs; using Aaru.Core.Logging; using Aaru.Devices; -using Schemas; +using Humanizer; +using Humanizer.Bytes; +using Track = Aaru.CommonTypes.Structs.Track; + +namespace Aaru.Core.Devices.Dumping; partial class Dump { @@ -75,7 +78,10 @@ partial class Dump /// Disc media catalogue number /// List of subchannels not yet dumped correctly /// List of smallest pregap relative address per track - void DumpCdLeadOuts(uint blockSize, ref double currentSpeed, DumpHardwareType currentTry, ExtentsULong extents, + + // TODO: Use it + [SuppressMessage("ReSharper", "UnusedMember.Local")] + void DumpCdLeadOuts(uint blockSize, ref double currentSpeed, DumpHardware currentTry, ExtentsULong extents, IbgLog ibgLog, ref double imageWriteDuration, ExtentsULong leadOutExtents, ref double maxSpeed, MhddLog mhddLog, ref double minSpeed, bool read6, bool read10, bool read12, bool read16, bool readcd, MmcSubchannel supportedSubchannel, uint subSize, ref double totalDuration, @@ -89,62 +95,113 @@ partial class Dump byte[] senseBuf = null; var outputOptical = _outputPlugin as IWritableOpticalImage; - UpdateStatus?.Invoke("Reading lead-outs"); - _dumpLog.WriteLine("Reading lead-outs"); + UpdateStatus?.Invoke(Localization.Core.Reading_lead_outs); + _dumpLog.WriteLine(Localization.Core.Reading_lead_outs); InitProgress?.Invoke(); foreach((ulong item1, ulong item2) in leadOutExtents.ToArray()) + { for(ulong i = item1; i <= item2; i++) { if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - _dumpLog.WriteLine("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } double cmdDuration = 0; - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - PulseProgress?.Invoke($"Reading sector {i} at lead-out ({currentSpeed:F3} MiB/sec.)"); + PulseProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_at_lead_out_1, + i, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize())); if(readcd) { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, MmcSectorTypes.AllTypes, false, - false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + (uint)i, + blockSize, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); totalDuration += cmdDuration; } else if(read16) - sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, i, blockSize, 0, 1, false, - _dev.Timeout, out cmdDuration); + { + sense = _dev.Read16(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + i, + blockSize, + 0, + 1, + false, + _dev.Timeout, + out cmdDuration); + } else if(read12) - sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0, - 1, false, _dev.Timeout, out cmdDuration); + { + sense = _dev.Read12(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)i, + blockSize, + 0, + 1, + false, + _dev.Timeout, + out cmdDuration); + } else if(read10) - sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0, - 1, _dev.Timeout, out cmdDuration); + { + sense = _dev.Read10(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)i, + blockSize, + 0, + 1, + _dev.Timeout, + out cmdDuration); + } else if(read6) sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, _dev.Timeout, out cmdDuration); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { mhddLog.Write(i, cmdDuration); ibgLog.Write(i, currentSpeed * 1024); extents.Add(i, _maximumReadable, true); leadOutExtents.Remove(i); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); if(supportedSubchannel != MmcSubchannel.None) { @@ -161,9 +218,25 @@ partial class Dump outputOptical.WriteSectorsLong(data, i, _maximumReadable); bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, - desiredSubchannel, sub, i, _maximumReadable, subLog, isrcs, 0xAA, ref mcn, tracks, - subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel, - _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true, out _); + desiredSubchannel, + sub, + i, + _maximumReadable, + subLog, + isrcs, + 0xAA, + ref mcn, + tracks, + subchannelExtents, + _fixSubchannelPosition, + outputOptical, + _fixSubchannel, + _fixSubchannelCrc, + _dumpLog, + UpdateStatus, + smallestPregapLbaPerTrack, + true, + out _); // Set tracks and go back if(indexesChanged) @@ -177,43 +250,45 @@ partial class Dump else outputOptical.WriteSectors(cmdBuf, i, _maximumReadable); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; } else { _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); if(supportedSubchannel != MmcSubchannel.None) { outputOptical.WriteSectorsLong(new byte[sectorSize * _skip], i, 1); - outputOptical.WriteSectorsTag(new byte[subSize * _skip], i, 1, + outputOptical.WriteSectorsTag(new byte[subSize * _skip], + i, + 1, SectorTagType.CdSectorSubchannel); } else outputOptical.WriteSectors(new byte[blockSize * _skip], i, 1); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; - mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); + mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip); ibgLog.Write(i, 0); } + _writeStopwatch.Stop(); double newSpeed = (double)blockSize * _maximumReadable / 1048576 / (cmdDuration / 1000); - if(!double.IsInfinity(newSpeed)) - currentSpeed = newSpeed; + if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed; _resume.NextBlock = i + 1; } + } EndProgress?.Invoke(); } @@ -244,7 +319,10 @@ partial class Dump /// Disc media catalogue number /// List of subchannels not yet dumped correctly /// List of smallest pregap relative address per track - void RetryCdLeadOuts(uint blockSize, ref double currentSpeed, DumpHardwareType currentTry, ExtentsULong extents, + + // TODO: Use it + [SuppressMessage("ReSharper", "UnusedMember.Local")] + void RetryCdLeadOuts(uint blockSize, ref double currentSpeed, DumpHardware currentTry, ExtentsULong extents, IbgLog ibgLog, ref double imageWriteDuration, ExtentsULong leadOutExtents, ref double maxSpeed, MhddLog mhddLog, ref double minSpeed, bool read6, bool read10, bool read12, bool read16, bool readcd, MmcSubchannel supportedSubchannel, uint subSize, ref double totalDuration, @@ -263,56 +341,107 @@ partial class Dump InitProgress?.Invoke(); foreach((ulong item1, ulong item2) in leadOutExtents.ToArray()) + { for(ulong i = item1; i <= item2; i++) { if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - _dumpLog.WriteLine("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } double cmdDuration = 0; - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - PulseProgress?.Invoke($"Reading sector {i} at lead-out ({currentSpeed:F3} MiB/sec.)"); + PulseProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_at_lead_out_1, + i, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize())); if(readcd) { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, MmcSectorTypes.AllTypes, false, - false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + (uint)i, + blockSize, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); totalDuration += cmdDuration; } else if(read16) - sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, i, blockSize, 0, 1, false, - _dev.Timeout, out cmdDuration); + { + sense = _dev.Read16(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + i, + blockSize, + 0, + 1, + false, + _dev.Timeout, + out cmdDuration); + } else if(read12) - sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0, - 1, false, _dev.Timeout, out cmdDuration); + { + sense = _dev.Read12(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)i, + blockSize, + 0, + 1, + false, + _dev.Timeout, + out cmdDuration); + } else if(read10) - sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0, - 1, _dev.Timeout, out cmdDuration); + { + sense = _dev.Read10(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)i, + blockSize, + 0, + 1, + _dev.Timeout, + out cmdDuration); + } else if(read6) sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, _dev.Timeout, out cmdDuration); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, cmdDuration, _maximumReadable); ibgLog.Write(i, currentSpeed * 1024); extents.Add(i, _maximumReadable, true); leadOutExtents.Remove(i); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); if(supportedSubchannel != MmcSubchannel.None) { @@ -329,9 +458,25 @@ partial class Dump outputOptical.WriteSectorsLong(data, i, _maximumReadable); bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, - desiredSubchannel, sub, i, _maximumReadable, subLog, isrcs, 0xAA, ref mcn, tracks, - subchannelExtents, _fixSubchannelPosition, outputOptical, _fixSubchannel, - _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true, out _); + desiredSubchannel, + sub, + i, + _maximumReadable, + subLog, + isrcs, + 0xAA, + ref mcn, + tracks, + subchannelExtents, + _fixSubchannelPosition, + outputOptical, + _fixSubchannel, + _fixSubchannelCrc, + _dumpLog, + UpdateStatus, + smallestPregapLbaPerTrack, + true, + out _); // Set tracks and go back if(indexesChanged) @@ -345,42 +490,46 @@ partial class Dump else outputOptical.WriteSectors(cmdBuf, i, _maximumReadable); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; } else { _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); if(supportedSubchannel != MmcSubchannel.None) { outputOptical.WriteSectorsLong(new byte[sectorSize * _skip], i, 1); if(desiredSubchannel != MmcSubchannel.None) - outputOptical.WriteSectorsTag(new byte[subSize * _skip], i, 1, + { + outputOptical.WriteSectorsTag(new byte[subSize * _skip], + i, + 1, SectorTagType.CdSectorSubchannel); + } } else outputOptical.WriteSectors(new byte[blockSize * _skip], i, 1); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); ibgLog.Write(i, 0); } + _writeStopwatch.Stop(); double newSpeed = (double)blockSize * _maximumReadable / 1048576 / (cmdDuration / 1000); - if(!double.IsInfinity(newSpeed)) - currentSpeed = newSpeed; + if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed; } + } EndProgress?.Invoke(); } diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Offset.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Offset.cs index 6b2b75f5e..36cbf19c3 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Offset.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Offset.cs @@ -27,20 +27,18 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using Aaru.Devices; +namespace Aaru.Core.Devices.Dumping; + partial class Dump { /// Fix offset in audio/scrambled sectors @@ -57,8 +55,7 @@ partial class Dump ref uint blocksToRead, uint subSize, ref byte[] cmdBuf, uint blockSize, bool failedCrossingLeadOut) { - if(cmdBuf.Length == 0) - return; + if(cmdBuf.Length == 0) return; int offsetFix = offsetBytes < 0 ? (int)(sectorSize * sectorsForOffset + offsetBytes) : offsetBytes; @@ -73,7 +70,7 @@ partial class Dump for(var b = 0; b < blocksToRead; b++) { Array.Copy(cmdBuf, (int)(0 + b * blockSize), data, sectorSize * b, sectorSize); - Array.Copy(cmdBuf, (int)(sectorSize + b * blockSize), sub, subSize * b, subSize); + Array.Copy(cmdBuf, (int)(sectorSize + b * blockSize), sub, subSize * b, subSize); } if(failedCrossingLeadOut) @@ -100,7 +97,7 @@ partial class Dump for(var b = 0; b < blocksToRead; b++) { Array.Copy(data, sectorSize * b, cmdBuf, (int)(0 + b * blockSize), sectorSize); - Array.Copy(sub, subSize * b, cmdBuf, (int)(sectorSize + b * blockSize), subSize); + Array.Copy(sub, subSize * b, cmdBuf, (int)(sectorSize + b * blockSize), subSize); } } else diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Plextor.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Plextor.cs index 0d2e7c12f..87420724a 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Plextor.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Plextor.cs @@ -27,14 +27,14 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - using System; using Aaru.Devices; +namespace Aaru.Core.Devices.Dumping; + partial class Dump { /// Reads a sector using Plextor's D8h READ CDDA command with subchannel @@ -46,8 +46,8 @@ partial class Dump /// Supported subchannel type /// Time spent sending commands to the drive /// true if an error occured, false otherwise - bool ReadPlextorWithSubchannel(out byte[] cmdBuf, out byte[] senseBuf, uint firstSectorToRead, uint blockSize, - uint blocksToRead, PlextorSubchannel supportedPlextorSubchannel, + bool ReadPlextorWithSubchannel(out byte[] cmdBuf, out byte[] senseBuf, uint firstSectorToRead, uint blockSize, + uint blocksToRead, PlextorSubchannel supportedPlextorSubchannel, out double cmdDuration) { bool sense; @@ -55,58 +55,95 @@ partial class Dump if(supportedPlextorSubchannel == PlextorSubchannel.None) { - sense = _dev.PlextorReadCdDa(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead, - supportedPlextorSubchannel, 0, out cmdDuration); + sense = _dev.PlextorReadCdDa(out cmdBuf, + out senseBuf, + firstSectorToRead, + blockSize, + blocksToRead, + supportedPlextorSubchannel, + 0, + out cmdDuration); - if(!sense) - return false; + if(!sense) return false; // As a workaround for some firmware bugs, seek far away. - _dev.PlextorReadCdDa(out _, out senseBuf, firstSectorToRead - 32, blockSize, blocksToRead, - supportedPlextorSubchannel, 0, out _); + _dev.PlextorReadCdDa(out _, + out senseBuf, + firstSectorToRead - 32, + blockSize, + blocksToRead, + supportedPlextorSubchannel, + 0, + out _); - sense = _dev.PlextorReadCdDa(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead, - supportedPlextorSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.PlextorReadCdDa(out cmdBuf, + out senseBuf, + firstSectorToRead, + blockSize, + blocksToRead, + supportedPlextorSubchannel, + _dev.Timeout, + out cmdDuration); return sense; } - byte[] subBuf; - uint subSize = supportedPlextorSubchannel == PlextorSubchannel.Q16 ? 16u : 96u; if(supportedPlextorSubchannel is PlextorSubchannel.Q16 or PlextorSubchannel.Pack) { - sense = _dev.PlextorReadCdDa(out cmdBuf, out senseBuf, firstSectorToRead, 2352 + subSize, blocksToRead, - supportedPlextorSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.PlextorReadCdDa(out cmdBuf, + out senseBuf, + firstSectorToRead, + 2352 + subSize, + blocksToRead, + supportedPlextorSubchannel, + _dev.Timeout, + out cmdDuration); - if(!sense) - return false; + if(!sense) return false; } // As a workaround for some firmware bugs, seek far away. - _dev.PlextorReadCdDa(out _, out senseBuf, firstSectorToRead - 32, blockSize, blocksToRead, - supportedPlextorSubchannel, 0, out _); + _dev.PlextorReadCdDa(out _, + out senseBuf, + firstSectorToRead - 32, + blockSize, + blocksToRead, + supportedPlextorSubchannel, + 0, + out _); - sense = _dev.PlextorReadCdDa(out byte[] dataBuf, out senseBuf, firstSectorToRead, 2352, blocksToRead, - PlextorSubchannel.None, 0, out cmdDuration); + sense = _dev.PlextorReadCdDa(out byte[] dataBuf, + out senseBuf, + firstSectorToRead, + 2352, + blocksToRead, + PlextorSubchannel.None, + 0, + out cmdDuration); - if(sense) - return true; + if(sense) return true; - sense = _dev.PlextorReadCdDa(out subBuf, out senseBuf, firstSectorToRead, subSize, blocksToRead, - supportedPlextorSubchannel == PlextorSubchannel.Pack ? PlextorSubchannel.All - : supportedPlextorSubchannel, 0, out cmdDuration); + sense = _dev.PlextorReadCdDa(out byte[] subBuf, + out senseBuf, + firstSectorToRead, + subSize, + blocksToRead, + supportedPlextorSubchannel == PlextorSubchannel.Pack + ? PlextorSubchannel.All + : supportedPlextorSubchannel, + 0, + out cmdDuration); - if(sense) - return true; + if(sense) return true; cmdBuf = new byte[2352 * blocksToRead + subSize * blocksToRead]; for(var b = 0; b < blocksToRead; b++) { - Array.Copy(dataBuf, 2352 * b, cmdBuf, (2352 + subSize) * b, 2352); - Array.Copy(subBuf, subSize * b, cmdBuf, (2352 + subSize) * b + 2352, subSize); + Array.Copy(dataBuf, 2352 * b, cmdBuf, (2352 + subSize) * b, 2352); + Array.Copy(subBuf, subSize * b, cmdBuf, (2352 + subSize) * b + 2352, subSize); } return false; diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Pregap.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Pregap.cs index 60dc2d205..1fe2e0795 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Pregap.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Pregap.cs @@ -27,17 +27,13 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.IO; @@ -49,6 +45,10 @@ using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Core.Logging; using Aaru.Devices; +using Humanizer; +using Humanizer.Bytes; + +namespace Aaru.Core.Devices.Dumping; partial class Dump { @@ -62,43 +62,56 @@ partial class Dump void ReadCdFirstTrackPregap(uint blockSize, ref double currentSpeed, Dictionary mediaTags, MmcSubchannel supportedSubchannel, ref double totalDuration) { - bool sense; // Sense indicator - byte[] cmdBuf; // Data buffer - double cmdDuration; // Command execution time - DateTime timeSpeedStart; // Time of start for speed calculation - ulong sectorSpeedStart = 0; // Used to calculate correct speed - var gotFirstTrackPregap = false; - var firstTrackPregapSectorsGood = 0; - var firstTrackPregapMs = new MemoryStream(); + bool sense; // Sense indicator + byte[] cmdBuf; // Data buffer + double cmdDuration; // Command execution time + ulong sectorSpeedStart = 0; // Used to calculate correct speed + var gotFirstTrackPregap = false; + var firstTrackPregapSectorsGood = 0; + var firstTrackPregapMs = new MemoryStream(); - _dumpLog.WriteLine("Reading first track pregap"); - UpdateStatus?.Invoke("Reading first track pregap"); + _dumpLog.WriteLine(Localization.Core.Reading_first_track_pregap); + UpdateStatus?.Invoke(Localization.Core.Reading_first_track_pregap); InitProgress?.Invoke(); - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Restart(); - for(int firstTrackPregapBlock = -150; firstTrackPregapBlock < 0 && _resume.NextBlock == 0; + for(int firstTrackPregapBlock = -150; + firstTrackPregapBlock < 0 && _resume.NextBlock == 0; firstTrackPregapBlock++) { if(_aborted) { - _dumpLog.WriteLine("Aborted!"); - UpdateStatus?.Invoke("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); + UpdateStatus?.Invoke(Localization.Core.Aborted); break; } - PulseProgress?. - Invoke($"Trying to read first track pregap sector {firstTrackPregapBlock} ({currentSpeed:F3} MiB/sec.)"); + PulseProgress?.Invoke(string.Format(Localization.Core.Trying_to_read_first_track_pregap_sector_0_1, + firstTrackPregapBlock, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize())); // ReSharper disable IntVariableOverflowInUncheckedContext - sense = _dev.ReadCd(out cmdBuf, out _, (uint)firstTrackPregapBlock, blockSize, 1, MmcSectorTypes.AllTypes, - false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.ReadCd(out cmdBuf, + out _, + (uint)firstTrackPregapBlock, + blockSize, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); // ReSharper restore IntVariableOverflowInUncheckedContext - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { firstTrackPregapMs.Write(cmdBuf, 0, (int)blockSize); gotFirstTrackPregap = true; @@ -108,28 +121,31 @@ partial class Dump else { // Write empty data - if(gotFirstTrackPregap) - firstTrackPregapMs.Write(new byte[blockSize], 0, (int)blockSize); + if(gotFirstTrackPregap) firstTrackPregapMs.Write(new byte[blockSize], 0, (int)blockSize); } sectorSpeedStart++; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Restart(); } + _speedStopwatch.Stop(); + if(firstTrackPregapSectorsGood > 0) mediaTags.Add(MediaTagType.CD_FirstTrackPregap, firstTrackPregapMs.ToArray()); EndProgress?.Invoke(); - UpdateStatus?.Invoke($"Got {firstTrackPregapSectorsGood} first track pregap sectors."); - _dumpLog.WriteLine("Got {0} first track pregap sectors.", firstTrackPregapSectorsGood); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Got_0_first_track_pregap_sectors, + firstTrackPregapSectorsGood)); + + _dumpLog.WriteLine(Localization.Core.Got_0_first_track_pregap_sectors, firstTrackPregapSectorsGood); firstTrackPregapMs.Close(); } @@ -148,52 +164,52 @@ partial class Dump bool supportsPqSubchannel, bool supportsRwSubchannel, Database.Models.Device dbDev, out bool inexactPositioning, bool dumping) { - var sense = true; // Sense indicator - byte[] subBuf = null; - int posQ; - uint retries; - bool? bcd = null; - byte[] crc; - var pregaps = new Dictionary(); + var sense = true; // Sense indicator + byte[] subBuf = null; + int posQ; + uint retries; + bool? bcd = null; + byte[] crc; + Dictionary pregaps = new(); inexactPositioning = false; - if(!supportsPqSubchannel && - !supportsRwSubchannel) - return; + if(!supportsPqSubchannel && !supportsRwSubchannel) return; // Check if subchannel is BCD for(retries = 0; retries < 10; retries++) { - sense = supportsRwSubchannel ? GetSectorForPregapRaw(dev, 11, dbDev, out subBuf, false) + sense = supportsRwSubchannel + ? GetSectorForPregapRaw(dev, 11, dbDev, out subBuf, false) : GetSectorForPregapQ16(dev, 11, out subBuf, false); - if(sense) - continue; + if(sense) continue; bcd = (subBuf[9] & 0x10) > 0; break; } - AaruConsole.DebugWriteLine("Pregap calculator", bcd == true - ? "Subchannel is BCD" - : bcd == false - ? "Subchannel is not BCD" - : "Could not detect drive subchannel BCD"); + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, + bcd switch + { + true => Localization.Core.Subchannel_is_BCD, + false => Localization.Core.Subchannel_is_not_BCD, + _ => Localization.Core.Could_not_detect_drive_subchannel_BCD + }); if(bcd is null) { - dumpLog?.WriteLine("Could not detect if drive subchannel is BCD or not, pregaps could not be calculated, dump may be incorrect..."); + dumpLog?.WriteLine(Localization.Core + .Could_not_detect_if_drive_subchannel_is_BCD_or_not_pregaps_could_not_be_calculated_dump_may_be_incorrect); - updateStatus?. - Invoke("Could not detect if drive subchannel is BCD or not, pregaps could not be calculated, dump may be incorrect..."); + updateStatus?.Invoke(Localization.Core + .Could_not_detect_if_drive_subchannel_is_BCD_or_not_pregaps_could_not_be_calculated_dump_may_be_incorrect); return; } // Initialize the dictionary - foreach(Track t in tracks) - pregaps[t.Sequence] = 0; + foreach(Track t in tracks) pregaps[t.Sequence] = 0; for(var t = 0; t < tracks.Length; t++) { @@ -201,35 +217,32 @@ partial class Dump var trackRetries = 0; // First track of each session has at least 150 sectors of pregap and is not always readable - if(tracks.Where(trk => trk.Session == track.Session).OrderBy(trk => trk.Sequence).FirstOrDefault(). - Sequence == track.Sequence) + if(tracks.Where(trk => trk.Session == track.Session).MinBy(trk => trk.Sequence).Sequence == track.Sequence) { - AaruConsole.DebugWriteLine("Pregap calculator", "Skipping track {0}", track.Sequence); + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, Localization.Core.Skipping_track_0, track.Sequence); - if(track.Sequence > 1) - pregaps[track.Sequence] = 150; + if(track.Sequence > 1) pregaps[track.Sequence] = 150; continue; } - if(t > 0 && - tracks[t - 1].Type == tracks[t].Type && - dumping) + if(t > 0 && tracks[t - 1].Type == tracks[t].Type && dumping) { - AaruConsole.DebugWriteLine("Pregap calculator", "Skipping track {0}", track.Sequence); + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, Localization.Core.Skipping_track_0, track.Sequence); continue; } if(dumping && dev.Manufacturer.ToLowerInvariant().StartsWith("plextor", StringComparison.Ordinal)) { - AaruConsole.DebugWriteLine("Pregap calculator", "Skipping track {0} due to Plextor firmware bug", + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, + Localization.Core.Skipping_track_0_due_to_Plextor_firmware_bug, track.Sequence); continue; } - AaruConsole.DebugWriteLine("Pregap calculator", "Track {0}", track.Sequence); + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, Localization.Core.Track_0, track.Sequence); int lba = (int)track.StartSector - 1; var pregapFound = false; @@ -250,22 +263,39 @@ partial class Dump if(sense) { - AaruConsole.DebugWriteLine("Pregap calculator", "LBA: {0}, Try {1}, Sense {2}", lba, retries + 1, + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, + Localization.Core.LBA_0_Try_1_Sense_2, + lba, + retries + 1, sense); continue; } - if(bcd == false) - BinaryToBcdQ(subBuf); + if(bcd == false) BinaryToBcdQ(subBuf); - CRC16CCITTContext.Data(subBuf, 10, out crc); + CRC16CcittContext.Data(subBuf, 10, out crc); - AaruConsole.DebugWriteLine("Pregap calculator", - "LBA: {0}, Try {1}, Sense {2}, Q: {3:X2} {4:X2} {5:X2} {6:X2} {7:X2} {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} CRC 0x{13:X2}{14:X2}, Calculated CRC: 0x{15:X2}{16:X2}", - lba, retries + 1, sense, subBuf[0], subBuf[1], subBuf[2], subBuf[3], - subBuf[4], subBuf[5], subBuf[6], subBuf[7], subBuf[8], subBuf[9], subBuf[10], - subBuf[11], crc[0], crc[1]); + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, + Localization.Core + .LBA_0_Try_1_Sense_2_Q_3_4_5_6_7_8_9_10_11_12_CRC_13_14_Calculated_CRC_15_16, + lba, + retries + 1, + sense, + subBuf[0], + subBuf[1], + subBuf[2], + subBuf[3], + subBuf[4], + subBuf[5], + subBuf[6], + subBuf[7], + subBuf[8], + subBuf[9], + subBuf[10], + subBuf[11], + crc[0], + crc[1]); crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11]; @@ -273,8 +303,7 @@ partial class Dump if(!crcOk) { // Data track cannot have 11xxb in CONTROL - if((subBuf[0] & 0x40) > 0) - subBuf[0] &= 0x7F; + if((subBuf[0] & 0x40) > 0) subBuf[0] &= 0x7F; // ADR only uses two bits subBuf[0] &= 0xF3; @@ -288,24 +317,39 @@ partial class Dump // Fix BCD numbering for(var i = 1; i < 10; i++) { - if((subBuf[i] & 0xF0) > 0xA0) - subBuf[i] &= 0x7F; + if((subBuf[i] & 0xF0) > 0xA0) subBuf[i] &= 0x7F; - if((subBuf[i] & 0x0F) > 0x0A) - subBuf[i] &= 0xF7; + if((subBuf[i] & 0x0F) > 0x0A) subBuf[i] &= 0xF7; } } - CRC16CCITTContext.Data(subBuf, 10, out crc); + CRC16CcittContext.Data(subBuf, 10, out crc); crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11]; if(crcOk) - AaruConsole.DebugWriteLine("Pregap calculator", - "LBA: {0}, Try {1}, Sense {2}, Q (FIXED): {3:X2} {4:X2} {5:X2} {6:X2} {7:X2} {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} CRC 0x{13:X2}{14:X2}, Calculated CRC: 0x{15:X2}{16:X2}", - lba, retries + 1, sense, subBuf[0], subBuf[1], subBuf[2], subBuf[3], - subBuf[4], subBuf[5], subBuf[6], subBuf[7], subBuf[8], subBuf[9], - subBuf[10], subBuf[11], crc[0], crc[1]); + { + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, + Localization.Core + .LBA_0_Try_1_Sense_2_Q_FIXED_3_4_5_6_7_8_9_10_11_12_CRC_13_14_Calculated_CRC_15_16, + lba, + retries + 1, + sense, + subBuf[0], + subBuf[1], + subBuf[2], + subBuf[3], + subBuf[4], + subBuf[5], + subBuf[6], + subBuf[7], + subBuf[8], + subBuf[9], + subBuf[10], + subBuf[11], + crc[0], + crc[1]); + } else continue; } @@ -313,57 +357,72 @@ partial class Dump BcdToBinaryQ(subBuf); // Q position - if((subBuf[0] & 0xF) != 1) - continue; + if((subBuf[0] & 0xF) != 1) continue; posQ = subBuf[7] * 60 * 75 + subBuf[8] * 75 + subBuf[9] - 150; - if(subBuf[1] != track.Sequence - 1 || - subBuf[2] == 0 || - posQ != lba) - break; + if(subBuf[1] != track.Sequence - 1 || subBuf[2] == 0 || posQ != lba) break; pregaps[track.Sequence] = 0; pregapFound = true; } - if(pregapFound) - continue; + if(pregapFound) continue; // Calculate pregap lba = (int)track.StartSector - 150; - while(lba > (int)previousTrack.StartSector && - lba <= (int)track.StartSector) + while(lba > (int)previousTrack.StartSector && lba <= (int)track.StartSector) { // Some drives crash if you try to read just before the previous read, so seek away first if(!forward) + { sense = supportsRwSubchannel - ? GetSectorForPregapRaw(dev, (uint)lba - 10, dbDev, out subBuf, + ? GetSectorForPregapRaw(dev, + (uint)lba - 10, + dbDev, + out subBuf, track.Type == TrackType.Audio) : GetSectorForPregapQ16(dev, (uint)lba - 10, out subBuf, track.Type == TrackType.Audio); + } for(retries = 0; retries < 10; retries++) { sense = supportsRwSubchannel - ? GetSectorForPregapRaw(dev, (uint)lba, dbDev, out subBuf, + ? GetSectorForPregapRaw(dev, + (uint)lba, + dbDev, + out subBuf, track.Type == TrackType.Audio) : GetSectorForPregapQ16(dev, (uint)lba, out subBuf, track.Type == TrackType.Audio); - if(sense) - continue; + if(sense) continue; - if(bcd == false) - BinaryToBcdQ(subBuf); + if(bcd == false) BinaryToBcdQ(subBuf); - CRC16CCITTContext.Data(subBuf, 10, out crc); + CRC16CcittContext.Data(subBuf, 10, out crc); - AaruConsole.DebugWriteLine("Pregap calculator", - "LBA: {0}, Try {1}, Sense {2}, Q: {3:X2} {4:X2} {5:X2} {6:X2} {7:X2} {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} CRC 0x{13:X2}{14:X2}, Calculated CRC: 0x{15:X2}{16:X2}", - lba, retries + 1, sense, subBuf[0], subBuf[1], subBuf[2], subBuf[3], - subBuf[4], subBuf[5], subBuf[6], subBuf[7], subBuf[8], subBuf[9], - subBuf[10], subBuf[11], crc[0], crc[1]); + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, + Localization.Core + .LBA_0_Try_1_Sense_2_Q_3_4_5_6_7_8_9_10_11_12_CRC_13_14_Calculated_CRC_15_16, + lba, + retries + 1, + sense, + subBuf[0], + subBuf[1], + subBuf[2], + subBuf[3], + subBuf[4], + subBuf[5], + subBuf[6], + subBuf[7], + subBuf[8], + subBuf[9], + subBuf[10], + subBuf[11], + crc[0], + crc[1]); crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11]; @@ -371,8 +430,7 @@ partial class Dump if(!crcOk) { // Data track cannot have 11xxb in CONTROL - if((subBuf[0] & 0x40) > 0) - subBuf[0] &= 0x7F; + if((subBuf[0] & 0x40) > 0) subBuf[0] &= 0x7F; // ADR only uses two bits subBuf[0] &= 0xF3; @@ -386,32 +444,44 @@ partial class Dump // Fix BCD numbering for(var i = 1; i < 10; i++) { - if((subBuf[i] & 0xF0) > 0xA0) - subBuf[i] &= 0x7F; + if((subBuf[i] & 0xF0) > 0xA0) subBuf[i] &= 0x7F; - if((subBuf[i] & 0x0F) > 0x0A) - subBuf[i] &= 0xF7; + if((subBuf[i] & 0x0F) > 0x0A) subBuf[i] &= 0xF7; } } - CRC16CCITTContext.Data(subBuf, 10, out crc); + CRC16CcittContext.Data(subBuf, 10, out crc); crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11]; if(crcOk) { - AaruConsole.DebugWriteLine("Pregap calculator", - "LBA: {0}, Try {1}, Sense {2}, Q (FIXED): {3:X2} {4:X2} {5:X2} {6:X2} {7:X2} {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} CRC 0x{13:X2}{14:X2}, Calculated CRC: 0x{15:X2}{16:X2}", - lba, retries + 1, sense, subBuf[0], subBuf[1], subBuf[2], - subBuf[3], subBuf[4], subBuf[5], subBuf[6], subBuf[7], subBuf[8], - subBuf[9], subBuf[10], subBuf[11], crc[0], crc[1]); + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, + Localization.Core + .LBA_0_Try_1_Sense_2_Q_FIXED_3_4_5_6_7_8_9_10_11_12_CRC_13_14_Calculated_CRC_15_16, + lba, + retries + 1, + sense, + subBuf[0], + subBuf[1], + subBuf[2], + subBuf[3], + subBuf[4], + subBuf[5], + subBuf[6], + subBuf[7], + subBuf[8], + subBuf[9], + subBuf[10], + subBuf[11], + crc[0], + crc[1]); break; } } - if(crcOk) - break; + if(crcOk) break; } if(retries == 10) @@ -427,35 +497,40 @@ partial class Dump if(previousTrack.Type == TrackType.Audio && track.Type != TrackType.Audio || previousTrack.Type != TrackType.Audio && track.Type == TrackType.Audio) { - dumpLog?. - WriteLine("Could not read subchannel for this track, supposing 150 sectors."); + dumpLog?.WriteLine(Localization.Core + .Could_not_read_subchannel_for_this_track_supposing_hundred_fifty_sectors); - updateStatus?. - Invoke("Could not read subchannel for this track, supposing 150 sectors."); + updateStatus?.Invoke(Localization.Core + .Could_not_read_subchannel_for_this_track_supposing_hundred_fifty_sectors); } else { - dumpLog?. - WriteLine("Could not read subchannel for this track, supposing 0 sectors."); + dumpLog?.WriteLine(Localization.Core + .Could_not_read_subchannel_for_this_track_supposing_zero_sectors); - updateStatus?. - Invoke("Could not read subchannel for this track, supposing 0 sectors."); + updateStatus?.Invoke(Localization.Core + .Could_not_read_subchannel_for_this_track_supposing_zero_sectors); } } else { - dumpLog?. - WriteLine($"Could not read subchannel for this track, supposing {pregaps[track.Sequence]} sectors."); + dumpLog?.WriteLine(string.Format(Localization.Core + .Could_not_read_subchannel_for_this_track_supposing_0_sectors, + pregaps[track.Sequence])); - updateStatus?. - Invoke($"Could not read subchannel for this track, supposing {pregaps[track.Sequence]} sectors."); + updateStatus?.Invoke(string.Format(Localization.Core + .Could_not_read_subchannel_for_this_track_supposing_0_sectors, + pregaps[track.Sequence])); } break; } - dumpLog?.WriteLine($"Could not read subchannel for sector {lba}"); - updateStatus?.Invoke($"Could not read subchannel for sector {lba}"); + dumpLog?.WriteLine(string.Format(Localization.Core.Could_not_read_subchannel_for_sector_0, + lba)); + + updateStatus?.Invoke(string.Format(Localization.Core.Could_not_read_subchannel_for_sector_0, + lba)); lba++; forward = true; @@ -463,15 +538,18 @@ partial class Dump continue; } - dumpLog?.WriteLine($"Could not get correct subchannel for sector {lba}"); - updateStatus?.Invoke($"Could not get correct subchannel for sector {lba}"); + dumpLog?.WriteLine(string.Format(Localization.Core.Could_not_get_correct_subchannel_for_sector_0, + lba)); + + updateStatus?.Invoke(string.Format(Localization.Core.Could_not_get_correct_subchannel_for_sector_0, + lba)); } if(subBuf.All(b => b == 0)) { inexactPositioning = true; - AaruConsole.DebugWriteLine("Pregap calculator", "All Q empty for LBA {0}", lba); + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, Localization.Core.All_Q_empty_for_LBA_0, lba); break; } @@ -487,8 +565,7 @@ partial class Dump lba++; forward = true; - if(lba == (int)previousTrack.StartSector) - break; + if(lba == (int)previousTrack.StartSector) break; continue; } @@ -509,21 +586,18 @@ partial class Dump previousPregapIsPreviousTrack = true; // Already gone back, so go forward - if(goneBack) - goFront = true; + if(goneBack) goFront = true; continue; } // Same track, but not pregap - if(subBuf[1] == track.Sequence && - subBuf[2] > 0) + if(subBuf[1] == track.Sequence && subBuf[2] > 0) { lba--; forward = false; - if(previousPregapIsPreviousTrack) - break; + if(previousPregapIsPreviousTrack) break; continue; } @@ -537,7 +611,9 @@ partial class Dump if(diff != 0) { - AaruConsole.DebugWriteLine("Pregap calculator", "Invalid Q position for LBA {0}, got {1}", lba, + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, + Localization.Core.Invalid_Q_position_for_LBA_0_got_1, + lba, posQ); inexactPositioning = true; @@ -546,8 +622,7 @@ partial class Dump // Received a Q post the LBA we wanted, just go back. If we are already going forward, break if(posQ > lba) { - if(forward) - break; + if(forward) break; lba--; @@ -560,7 +635,9 @@ partial class Dump // If CRC is not OK, only accept pregaps less than 10 sectors longer than previously now if(crcOk || pregapQ - pregaps[track.Sequence] < 10) { - AaruConsole.DebugWriteLine("Pregap calculator", "Pregap for track {0}: {1}", track.Sequence, + AaruConsole.DebugWriteLine(PREGAP_MODULE_NAME, + Localization.Core.Pregap_for_track_0_1, + track.Sequence, pregapQ); pregaps[track.Sequence] = pregapQ; @@ -574,8 +651,7 @@ partial class Dump break; } } - else if(pregapQ == pregaps[track.Sequence]) - break; + else if(pregapQ == pregaps[track.Sequence]) break; lba--; forward = false; @@ -587,17 +663,14 @@ partial class Dump trk.Pregap = (ulong)pregaps[trk.Sequence]; // Do not reduce pregap, or starting position of session's first track - if(tracks.Where(t => t.Session == trk.Session).OrderBy(t => t.Sequence).FirstOrDefault().Sequence == - trk.Sequence) - continue; + if(tracks.Where(t => t.Session == trk.Session).MinBy(t => t.Sequence).Sequence == trk.Sequence) continue; if(dumping) { // Minus five, to ensure dumping will fix if there is a pregap LBA 0 var red = 5; - while(trk.Pregap > 0 && - red > 0) + while(trk.Pregap > 0 && red > 0) { trk.Pregap--; red--; @@ -606,10 +679,13 @@ partial class Dump trk.StartSector -= trk.Pregap; - #if DEBUG - dumpLog?.WriteLine($"Track {trk.Sequence} pregap is {trk.Pregap} sectors"); - updateStatus?.Invoke($"Track {trk.Sequence} pregap is {trk.Pregap} sectors"); - #endif +#if DEBUG + dumpLog?.WriteLine(string.Format(Localization.Core.Track_0_pregap_is_1_sectors, trk.Sequence, trk.Pregap)); + + updateStatus?.Invoke(string.Format(Localization.Core.Track_0_pregap_is_1_sectors, + trk.Sequence, + trk.Pregap)); +#endif } } @@ -621,7 +697,7 @@ partial class Dump /// Set if it is an audio track /// true if read correctly, false otherwise static bool GetSectorForPregapRaw(Device dev, uint lba, Database.Models.Device dbDev, out byte[] subBuf, - bool audioTrack) + bool audioTrack) { byte[] cmdBuf; bool sense; @@ -629,25 +705,81 @@ partial class Dump if(audioTrack) { - sense = dev.ReadCd(out cmdBuf, out _, lba, 2448, 1, MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 2448, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + dev.Timeout, out _); if(sense) - sense = dev.ReadCd(out cmdBuf, out _, lba, 2448, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Raw, - dev.Timeout, out _); + { + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 2448, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Raw, + dev.Timeout, + out _); + } } else { - sense = dev.ReadCd(out cmdBuf, out _, lba, 2448, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Raw, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 2448, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Raw, + dev.Timeout, + out _); if(sense) - sense = dev.ReadCd(out cmdBuf, out _, lba, 2448, 1, MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, + { + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 2448, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + dev.Timeout, out _); + } } if(!sense) @@ -658,25 +790,52 @@ partial class Dump } else { - sense = dev.ReadCd(out cmdBuf, out _, lba, 96, 1, MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 96, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + false, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + dev.Timeout, out _); if(sense) - sense = dev.ReadCd(out cmdBuf, out _, lba, 96, 1, MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Raw, - dev.Timeout, out _); + { + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 96, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + false, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + dev.Timeout, + out _); + } if(!sense) subBuf = DeinterleaveQ(cmdBuf); else if(dbDev?.ATAPI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true || dbDev?.SCSI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true || - dev.Manufacturer.ToLowerInvariant() == "plextor") + dev.Manufacturer.Equals("plextor", StringComparison.InvariantCultureIgnoreCase)) sense = dev.PlextorReadCdDa(out cmdBuf, out _, lba, 96, 1, PlextorSubchannel.All, dev.Timeout, out _); { - if(!sense) - subBuf = DeinterleaveQ(cmdBuf); + if(!sense) subBuf = DeinterleaveQ(cmdBuf); } } @@ -697,25 +856,81 @@ partial class Dump if(audioTrack) { - sense = dev.ReadCd(out cmdBuf, out _, lba, 2368, 1, MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.Q16, dev.Timeout, + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 2368, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + dev.Timeout, out _); if(sense) - sense = dev.ReadCd(out cmdBuf, out _, lba, 2368, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Q16, - dev.Timeout, out _); + { + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 2368, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Q16, + dev.Timeout, + out _); + } } else { - sense = dev.ReadCd(out cmdBuf, out _, lba, 2368, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Q16, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 2368, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Q16, + dev.Timeout, + out _); if(sense) - sense = dev.ReadCd(out cmdBuf, out _, lba, 2368, 1, MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.Q16, dev.Timeout, + { + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 2368, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + dev.Timeout, out _); + } } if(!sense) @@ -725,17 +940,44 @@ partial class Dump } else { - sense = dev.ReadCd(out cmdBuf, out _, lba, 16, 1, MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Q16, dev.Timeout, + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 16, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + false, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + dev.Timeout, out _); if(sense) - sense = dev.ReadCd(out cmdBuf, out _, lba, 16, 1, MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Q16, - dev.Timeout, out _); + { + sense = dev.ReadCd(out cmdBuf, + out _, + lba, + 16, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + false, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + dev.Timeout, + out _); + } - if(!sense) - subBuf = cmdBuf; + if(!sense) subBuf = cmdBuf; } return sense; @@ -763,8 +1005,7 @@ partial class Dump var deQ = new byte[q.Length]; - for(var iq = 0; iq < q.Length; iq++) - deQ[iq] = (byte)q[iq]; + for(var iq = 0; iq < q.Length; iq++) deQ[iq] = (byte)q[iq]; return deQ; } @@ -773,15 +1014,15 @@ partial class Dump /// Q subchannel static void BinaryToBcdQ(byte[] q) { - q[1] = (byte)(((q[1] / 10) << 4) + q[1] % 10); - q[2] = (byte)(((q[2] / 10) << 4) + q[2] % 10); - q[3] = (byte)(((q[3] / 10) << 4) + q[3] % 10); - q[4] = (byte)(((q[4] / 10) << 4) + q[4] % 10); - q[5] = (byte)(((q[5] / 10) << 4) + q[5] % 10); - q[6] = (byte)(((q[6] / 10) << 4) + q[6] % 10); - q[7] = (byte)(((q[7] / 10) << 4) + q[7] % 10); - q[8] = (byte)(((q[8] / 10) << 4) + q[8] % 10); - q[9] = (byte)(((q[9] / 10) << 4) + q[9] % 10); + q[1] = (byte)((q[1] / 10 << 4) + q[1] % 10); + q[2] = (byte)((q[2] / 10 << 4) + q[2] % 10); + q[3] = (byte)((q[3] / 10 << 4) + q[3] % 10); + q[4] = (byte)((q[4] / 10 << 4) + q[4] % 10); + q[5] = (byte)((q[5] / 10 << 4) + q[5] % 10); + q[6] = (byte)((q[6] / 10 << 4) + q[6] % 10); + q[7] = (byte)((q[7] / 10 << 4) + q[7] % 10); + q[8] = (byte)((q[8] / 10 << 4) + q[8] % 10); + q[9] = (byte)((q[9] / 10 << 4) + q[9] % 10); } /// In place converts Q subchannel from BCD to binary numbering diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Recordable.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Recordable.cs index e47f7aaef..d4445b17d 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Recordable.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Recordable.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - using System.Collections.Generic; using System.Linq; using Aaru.CommonTypes.Enums; @@ -42,57 +40,64 @@ using Aaru.Core.Logging; using Aaru.Decoders.CD; using Aaru.Devices; +namespace Aaru.Core.Devices.Dumping; + partial class Dump { void HandleCdrRunOutSectors(ulong blocks, MmcSubchannel desiredSubchannel, ExtentsULong extents, HashSet subchannelExtents, SubchannelLog subLog, bool supportsLongSectors, Dictionary trackFlags, Track[] tracks) { - List runOutSectors = new(); + List runOutSectors = []; - if(_outputPlugin is not IWritableOpticalImage outputOptical) - return; + if(_outputPlugin is not IWritableOpticalImage outputOptical) return; // Count how many run end sectors are detected as bad blocks for(ulong i = blocks - 1; i > blocks - 1 - _ignoreCdrRunOuts; i--) + { if(_resume.BadBlocks.Contains(i)) runOutSectors.Add(i); else break; + } - if(runOutSectors.Count == 0) - return; + if(runOutSectors.Count == 0) return; - _dumpLog.WriteLine($"{runOutSectors.Count} sectors at the end of the disc are unreadable. This is normal in CD-R(W) discs as these sectors are created by burning software as part of the recording process. Empty ones will be generated and stored in the image."); + _dumpLog.WriteLine(string.Format(Localization.Core._0_sectors_at_the_end_of_the_disc_are_unreadable, + runOutSectors.Count)); - UpdateStatus?. - Invoke($"{runOutSectors.Count} sectors at the end of the disc are unreadable. This is normal in CD-R(W) discs as these sectors are created by burning software as part of the recording process. Empty ones will be generated and stored in the image."); + UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_at_the_end_of_the_disc_are_unreadable, + runOutSectors.Count)); foreach(ulong s in runOutSectors) { Track track = tracks.FirstOrDefault(t => t.StartSector <= s && t.EndSector >= s); - if(track is null) - continue; + if(track is null) continue; var sector = new byte[2352]; switch(track.Type) { - case TrackType.Audio: break; + case TrackType.Audio: + break; case TrackType.Data: sector = new byte[2048]; break; - case TrackType.CdMode1: break; - case TrackType.CdMode2Formless: break; - case TrackType.CdMode2Form1: break; - case TrackType.CdMode2Form2: break; - default: continue; + case TrackType.CdMode1: + break; + case TrackType.CdMode2Formless: + break; + case TrackType.CdMode2Form1: + break; + case TrackType.CdMode2Form2: + break; + default: + continue; } - if(track.Type != TrackType.Audio && - track.Type != TrackType.Data) + if(track.Type != TrackType.Audio && track.Type != TrackType.Data) { SectorBuilder sb = new(); sb.ReconstructPrefix(ref sector, track.Type, (long)s); @@ -107,8 +112,7 @@ partial class Dump _resume.BadBlocks.Remove(s); extents.Add(s); - if(desiredSubchannel == MmcSubchannel.None) - continue; + if(desiredSubchannel == MmcSubchannel.None) continue; // Hidden track ulong trackStart; diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Subchannel.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Subchannel.cs index 80f9607d5..4d1f884a3 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Subchannel.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Subchannel.cs @@ -27,21 +27,19 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using Aaru.CommonTypes; using Aaru.Core.Logging; using Aaru.Devices; +namespace Aaru.Core.Devices.Dumping; + partial class Dump { /// Check if the drive can read RW raw subchannel @@ -52,11 +50,24 @@ partial class Dump /// true if read correctly, false otherwise public static bool SupportsRwSubchannel(Device dev, DumpLog dumpLog, UpdateStatusHandler updateStatus, uint lba) { - dumpLog?.WriteLine("Checking if drive supports full raw subchannel reading..."); - updateStatus?.Invoke("Checking if drive supports full raw subchannel reading..."); + dumpLog?.WriteLine(Localization.Core.Checking_if_drive_supports_full_raw_subchannel_reading); + updateStatus?.Invoke(Localization.Core.Checking_if_drive_supports_full_raw_subchannel_reading); - return !dev.ReadCd(out _, out _, lba, 2352 + 96, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, + return !dev.ReadCd(out _, + out _, + lba, + 2352 + 96, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Raw, + dev.Timeout, out _); } @@ -68,11 +79,24 @@ partial class Dump /// true if read correctly, false otherwise public static bool SupportsPqSubchannel(Device dev, DumpLog dumpLog, UpdateStatusHandler updateStatus, uint lba) { - dumpLog?.WriteLine("Checking if drive supports PQ subchannel reading..."); - updateStatus?.Invoke("Checking if drive supports PQ subchannel reading..."); + dumpLog?.WriteLine(Localization.Core.Checking_if_drive_supports_PQ_subchannel_reading); + updateStatus?.Invoke(Localization.Core.Checking_if_drive_supports_PQ_subchannel_reading); - return !dev.ReadCd(out _, out _, lba, 2352 + 16, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Q16, dev.Timeout, + return !dev.ReadCd(out _, + out _, + lba, + 2352 + 16, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Q16, + dev.Timeout, out _); } } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Tags.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Tags.cs index e278b3705..b4f137290 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Tags.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Tags.cs @@ -27,17 +27,13 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using Aaru.CommonTypes; @@ -46,6 +42,8 @@ using Aaru.Decoders.CD; using Aaru.Decoders.SCSI.MMC; using Aaru.Devices; +namespace Aaru.Core.Devices.Dumping; + partial class Dump { /// Reads media tags from Compact Disc media @@ -54,7 +52,7 @@ partial class Dump /// Sessions /// First track in last session void ReadCdTags(ref MediaType mediaType, Dictionary mediaTags, out int sessions, - out int firstTrackLastSession) + out int firstTrackLastSession) { byte[] cmdBuf; // Data buffer bool sense; // Sense indicator @@ -63,8 +61,8 @@ partial class Dump firstTrackLastSession = 1; // ATIP exists on blank CDs - _dumpLog.WriteLine("Reading ATIP"); - UpdateStatus?.Invoke("Reading ATIP"); + _dumpLog.WriteLine(Localization.Core.Reading_ATIP); + UpdateStatus?.Invoke(Localization.Core.Reading_ATIP); sense = _dev.ReadAtip(out cmdBuf, out _, _dev.Timeout, out _); if(!sense) @@ -79,48 +77,48 @@ partial class Dump tmpBuf = new byte[cmdBuf.Length - 4]; Array.Copy(cmdBuf, 4, tmpBuf, 0, cmdBuf.Length - 4); mediaTags.Add(MediaTagType.CD_ATIP, tmpBuf); + _mediaGraph?.PaintRecordableInformationGood(); } } - _dumpLog.WriteLine("Reading Disc Information"); - UpdateStatus?.Invoke("Reading Disc Information"); + _dumpLog.WriteLine(Localization.Core.Reading_Disc_Information); + UpdateStatus?.Invoke(Localization.Core.Reading_Disc_Information); - sense = _dev.ReadDiscInformation(out cmdBuf, out _, MmcDiscInformationDataTypes.DiscInformation, _dev.Timeout, + sense = _dev.ReadDiscInformation(out cmdBuf, + out _, + MmcDiscInformationDataTypes.DiscInformation, + _dev.Timeout, out _); if(!sense) { DiscInformation.StandardDiscInformation? discInfo = DiscInformation.Decode000b(cmdBuf); - if(discInfo.HasValue && - mediaType == MediaType.CD) - switch(discInfo.Value.DiscType) - { - case 0x10: - mediaType = MediaType.CDI; - - break; - case 0x20: - mediaType = MediaType.CDROMXA; - - break; - } + if(discInfo.HasValue && mediaType == MediaType.CD) + { + mediaType = discInfo.Value.DiscType switch + { + 0x10 => MediaType.CDI, + 0x20 => MediaType.CDROMXA, + _ => mediaType + }; + } } - _dumpLog.WriteLine("Reading PMA"); - UpdateStatus?.Invoke("Reading PMA"); + _dumpLog.WriteLine(Localization.Core.Reading_PMA); + UpdateStatus?.Invoke(Localization.Core.Reading_PMA); sense = _dev.ReadPma(out cmdBuf, out _, _dev.Timeout, out _); - if(!sense && - PMA.Decode(cmdBuf).HasValue) + if(!sense && PMA.Decode(cmdBuf).HasValue) { tmpBuf = new byte[cmdBuf.Length - 4]; Array.Copy(cmdBuf, 4, tmpBuf, 0, cmdBuf.Length - 4); mediaTags.Add(MediaTagType.CD_PMA, tmpBuf); + _mediaGraph?.PaintRecordableInformationGood(); } - _dumpLog.WriteLine("Reading Session Information"); - UpdateStatus?.Invoke("Reading Session Information"); + _dumpLog.WriteLine(Localization.Core.Reading_Session_Information); + UpdateStatus?.Invoke(Localization.Core.Reading_Session_Information); sense = _dev.ReadSessionInfo(out cmdBuf, out _, _dev.Timeout, out _); if(!sense) @@ -134,12 +132,11 @@ partial class Dump } } - _dumpLog.WriteLine("Reading CD-Text from Lead-In"); - UpdateStatus?.Invoke("Reading CD-Text from Lead-In"); + _dumpLog.WriteLine(Localization.Core.Reading_CD_Text_from_Lead_In); + UpdateStatus?.Invoke(Localization.Core.Reading_CD_Text_from_Lead_In); sense = _dev.ReadCdText(out cmdBuf, out _, _dev.Timeout, out _); - if(sense || !CDTextOnLeadIn.Decode(cmdBuf).HasValue) - return; + if(sense || !CDTextOnLeadIn.Decode(cmdBuf).HasValue) return; tmpBuf = new byte[cmdBuf.Length - 4]; Array.Copy(cmdBuf, 4, tmpBuf, 0, cmdBuf.Length - 4); diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Tracks.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Tracks.cs index 948b08857..09d32d9bd 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Tracks.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Tracks.cs @@ -27,15 +27,13 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.Linq; @@ -46,6 +44,8 @@ using Aaru.Core.Logging; using Aaru.Decoders.CD; using Aaru.Devices; +namespace Aaru.Core.Devices.Dumping; + partial class Dump { /// Reads the TOC, processes it, returns the track list and last sector @@ -60,24 +60,24 @@ partial class Dump /// Track flags /// Update status handler /// List of tracks - public static Track[] GetCdTracks(Device dev, DumpLog dumpLog, bool force, out long lastSector, - Dictionary leadOutStarts, Dictionary mediaTags, - ErrorMessageHandler stoppingErrorMessage, out FullTOC.CDFullTOC? toc, + public static Track[] GetCdTracks(Device dev, DumpLog dumpLog, bool force, out long lastSector, + Dictionary leadOutStarts, Dictionary mediaTags, + ErrorMessageHandler stoppingErrorMessage, out FullTOC.CDFullTOC? toc, Dictionary trackFlags, UpdateStatusHandler updateStatus) { - byte[] cmdBuf; // Data buffer - const uint sectorSize = 2352; // Full sector size - bool sense; // Sense indicator - var trackList = new List(); // Tracks in disc - byte[] tmpBuf; // Temporary buffer + byte[] cmdBuf; // Data buffer + const uint sectorSize = 2352; // Full sector size + bool sense; // Sense indicator + List trackList = []; // Tracks in disc + byte[] tmpBuf; // Temporary buffer toc = null; lastSector = 0; TrackType leadoutTrackType = TrackType.Audio; // We discarded all discs that falsify a TOC before requesting a real TOC // No TOC, no CD (or an empty one) - dumpLog?.WriteLine("Reading full TOC"); - updateStatus?.Invoke("Reading full TOC"); + dumpLog?.WriteLine(Localization.Core.Reading_full_TOC); + updateStatus?.Invoke(Localization.Core.Reading_full_TOC); sense = dev.ReadRawToc(out cmdBuf, out _, 0, dev.Timeout, out _); if(!sense) @@ -92,8 +92,8 @@ partial class Dump } } - updateStatus?.Invoke("Building track map..."); - dumpLog?.WriteLine("Building track map..."); + updateStatus?.Invoke(Localization.Core.Building_track_map); + dumpLog?.WriteLine(Localization.Core.Building_track_map); if(toc.HasValue) { @@ -101,126 +101,143 @@ partial class Dump toc.Value.TrackDescriptors.OrderBy(track => track.POINT).ToArray(); foreach(FullTOC.TrackDataDescriptor trk in sortedTracks.Where(trk => trk.ADR is 1 or 4)) - if(trk.POINT >= 0x01 && - trk.POINT <= 0x63) + { + switch(trk.POINT) { - trackList.Add(new Track - { - Sequence = trk.POINT, - Session = trk.SessionNumber, - Type = (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack || - (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental ? TrackType.Data - : TrackType.Audio, - StartSector = - (ulong)(trk.PHOUR * 3600 * 75 + trk.PMIN * 60 * 75 + trk.PSEC * 75 + trk.PFRAME - 150), - BytesPerSector = (int)sectorSize, - RawBytesPerSector = (int)sectorSize - }); - - trackFlags?.Add(trk.POINT, trk.CONTROL); - } - else if(trk.POINT == 0xA2) - { - int phour, pmin, psec, pframe; - - if(trk.PFRAME == 0) - { - pframe = 74; - - if(trk.PSEC == 0) + case >= 0x01 and <= 0x63: + trackList.Add(new Track { - psec = 59; + Sequence = trk.POINT, + Session = trk.SessionNumber, + Type = (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack || + (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental + ? TrackType.Data + : TrackType.Audio, + StartSector = + (ulong)(trk.PHOUR * 3600 * 75 + trk.PMIN * 60 * 75 + trk.PSEC * 75 + trk.PFRAME - 150), + BytesPerSector = (int)sectorSize, + RawBytesPerSector = (int)sectorSize + }); - if(trk.PMIN == 0) + trackFlags?.Add(trk.POINT, trk.CONTROL); + + break; + case 0xA2: + { + int phour, pmin, psec, pframe; + + if(trk.PFRAME == 0) + { + pframe = 74; + + if(trk.PSEC == 0) { - pmin = 59; - phour = trk.PHOUR - 1; + psec = 59; + + if(trk.PMIN == 0) + { + pmin = 59; + phour = trk.PHOUR - 1; + } + else + { + pmin = trk.PMIN - 1; + phour = trk.PHOUR; + } } else { - pmin = trk.PMIN - 1; + psec = trk.PSEC - 1; + pmin = trk.PMIN; phour = trk.PHOUR; } } else { - psec = trk.PSEC - 1; - pmin = trk.PMIN; - phour = trk.PHOUR; + pframe = trk.PFRAME - 1; + psec = trk.PSEC; + pmin = trk.PMIN; + phour = trk.PHOUR; } - } - else - { - pframe = trk.PFRAME - 1; - psec = trk.PSEC; - pmin = trk.PMIN; - phour = trk.PHOUR; - } - lastSector = phour * 3600 * 75 + pmin * 60 * 75 + psec * 75 + pframe - 150; - leadOutStarts?.Add(trk.SessionNumber, lastSector + 1); + lastSector = phour * 3600 * 75 + pmin * 60 * 75 + psec * 75 + pframe - 150; + leadOutStarts?.Add(trk.SessionNumber, lastSector + 1); + + break; + } + case 0xA0 when trk.ADR == 1: + leadoutTrackType = + (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack || + (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental + ? TrackType.Data + : TrackType.Audio; + + break; } - else if(trk.POINT == 0xA0 && - trk.ADR == 1) - leadoutTrackType = - (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack || - (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental ? TrackType.Data - : TrackType.Audio; + } } else { - updateStatus?.Invoke("Cannot read RAW TOC, requesting processed one..."); - dumpLog?.WriteLine("Cannot read RAW TOC, requesting processed one..."); + updateStatus?.Invoke(Localization.Core.Cannot_read_RAW_TOC_requesting_processed_one); + dumpLog?.WriteLine(Localization.Core.Cannot_read_RAW_TOC_requesting_processed_one); sense = dev.ReadToc(out cmdBuf, out _, false, 0, dev.Timeout, out _); TOC.CDTOC? oldToc = TOC.Decode(cmdBuf); - if((sense || !oldToc.HasValue) && - !force) + if((sense || !oldToc.HasValue) && !force) { - dumpLog?.WriteLine("Could not read TOC, if you want to continue, use force, and will try from LBA 0 to 360000..."); + dumpLog?.WriteLine(Localization.Core + .Could_not_read_TOC_if_you_want_to_continue_use_force_and_will_try_from_LBA_0_to_360000); - stoppingErrorMessage?. - Invoke("Could not read TOC, if you want to continue, use force, and will try from LBA 0 to 360000..."); + stoppingErrorMessage?.Invoke(Localization.Core + .Could_not_read_TOC_if_you_want_to_continue_use_force_and_will_try_from_LBA_0_to_360000); return null; } if(oldToc.HasValue) - foreach(TOC.CDTOCTrackDataDescriptor trk in oldToc.Value.TrackDescriptors.OrderBy(t => t.TrackNumber). - Where(trk => trk.ADR is 1 or 4)) - if(trk.TrackNumber >= 0x01 && - trk.TrackNumber <= 0x63) + { + foreach(TOC.CDTOCTrackDataDescriptor trk in oldToc.Value.TrackDescriptors.OrderBy(t => t.TrackNumber) + .Where(trk => trk.ADR is 1 or 4)) + { + switch(trk.TrackNumber) { - trackList.Add(new Track - { - Sequence = trk.TrackNumber, - Session = 1, - Type = (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack || - (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental ? TrackType.Data - : TrackType.Audio, - StartSector = trk.TrackStartAddress, - BytesPerSector = (int)sectorSize, - RawBytesPerSector = (int)sectorSize - }); + case >= 0x01 and <= 0x63: + trackList.Add(new Track + { + Sequence = trk.TrackNumber, + Session = 1, + Type = (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack || + (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental + ? TrackType.Data + : TrackType.Audio, + StartSector = trk.TrackStartAddress, + BytesPerSector = (int)sectorSize, + RawBytesPerSector = (int)sectorSize + }); - trackFlags?.Add(trk.TrackNumber, trk.CONTROL); - } - else if(trk.TrackNumber == 0xAA) - { - leadoutTrackType = - (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack || - (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental ? TrackType.Data - : TrackType.Audio; + trackFlags?.Add(trk.TrackNumber, trk.CONTROL); - lastSector = trk.TrackStartAddress - 1; + break; + case 0xAA: + leadoutTrackType = + (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrack || + (TocControl)(trk.CONTROL & 0x0D) == TocControl.DataTrackIncremental + ? TrackType.Data + : TrackType.Audio; + + lastSector = trk.TrackStartAddress - 1; + + break; } + } + } } if(trackList.Count == 0) { - updateStatus?.Invoke("No tracks found, adding a single track from 0 to Lead-Out"); - dumpLog?.WriteLine("No tracks found, adding a single track from 0 to Lead-Out"); + updateStatus?.Invoke(Localization.Core.No_tracks_found_adding_a_single_track_from_zero_to_Lead_Out); + dumpLog?.WriteLine(Localization.Core.No_tracks_found_adding_a_single_track_from_zero_to_Lead_Out); trackList.Add(new Track { @@ -235,8 +252,7 @@ partial class Dump trackFlags?.Add(1, (byte)(leadoutTrackType == TrackType.Audio ? 0 : 4)); } - if(lastSector != 0) - return trackList.ToArray(); + if(lastSector != 0) return trackList.ToArray(); sense = dev.ReadCapacity16(out cmdBuf, out _, dev.Timeout, out _); @@ -252,27 +268,24 @@ partial class Dump { sense = dev.ReadCapacity(out cmdBuf, out _, dev.Timeout, out _); - if(!sense) - lastSector = ((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]) & 0xFFFFFFFF; + if(!sense) lastSector = (cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3] & 0xFFFFFFFF; } - if(lastSector > 0) - return trackList.ToArray(); + if(lastSector > 0) return trackList.ToArray(); if(!force) { - stoppingErrorMessage?. - Invoke("Could not find Lead-Out, if you want to continue use force option and will continue until 360000 sectors..."); + stoppingErrorMessage?.Invoke(Localization.Core + .Could_not_find_Lead_Out_if_you_want_to_continue_use_force_option); - dumpLog?.WriteLine("Could not find Lead-Out, if you want to continue use force option and will continue until 360000 sectors..."); + dumpLog?.WriteLine(Localization.Core.Could_not_find_Lead_Out_if_you_want_to_continue_use_force_option); return null; } - updateStatus?. - Invoke("WARNING: Could not find Lead-Out start, will try to read up to 360000 sectors, probably will fail before..."); + updateStatus?.Invoke(Localization.Core.WARNING_Could_not_find_Lead_Out_start_will_try_to_read_up_to); - dumpLog?.WriteLine("WARNING: Could not find Lead-Out start, will try to read up to 360000 sectors, probably will fail before..."); + dumpLog?.WriteLine(Localization.Core.WARNING_Could_not_find_Lead_Out_start_will_try_to_read_up_to); lastSector = 360000; return trackList.ToArray(); diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Trim.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Trim.cs index 4511577b4..93cc09f6c 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Trim.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Trim.cs @@ -27,26 +27,29 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.Linq; +using Aaru.Checksums; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs; using Aaru.Core.Logging; using Aaru.Decoders.CD; using Aaru.Decoders.SCSI; using Aaru.Devices; -using Schemas; +using Humanizer; +using Humanizer.Localisation; +using Track = Aaru.CommonTypes.Structs.Track; + +namespace Aaru.Core.Devices.Dumping; partial class Dump { @@ -74,15 +77,13 @@ partial class Dump /// Disc media catalogue number /// List of subchannels not yet dumped correctly /// List of smallest pregap relative address per track - void TrimCdUserData(ExtentsULong audioExtents, uint blockSize, DumpHardwareType currentTry, ExtentsULong extents, + void TrimCdUserData(ExtentsULong audioExtents, uint blockSize, DumpHardware currentTry, ExtentsULong extents, bool newTrim, int offsetBytes, bool read6, bool read10, bool read12, bool read16, bool readcd, int sectorsForOffset, uint subSize, MmcSubchannel supportedSubchannel, bool supportsLongSectors, ref double totalDuration, SubchannelLog subLog, MmcSubchannel desiredSubchannel, Track[] tracks, Dictionary isrcs, ref string mcn, HashSet subchannelExtents, Dictionary smallestPregapLbaPerTrack) { - DateTime start; - DateTime end; var sense = true; // Sense indicator byte[] cmdBuf = null; // Data buffer double cmdDuration = 0; // Command execution time @@ -91,36 +92,20 @@ partial class Dump byte[] senseBuf = null; var outputOptical = _outputPlugin as IWritableOpticalImage; - switch(supportedSubchannel) - { - case MmcSubchannel.None: - supportedPlextorSubchannel = PlextorSubchannel.None; + supportedPlextorSubchannel = supportedSubchannel switch + { + MmcSubchannel.None => PlextorSubchannel.None, + MmcSubchannel.Raw => PlextorSubchannel.Pack, + MmcSubchannel.Q16 => PlextorSubchannel.Q16, + _ => PlextorSubchannel.None + }; - break; - case MmcSubchannel.Raw: - supportedPlextorSubchannel = PlextorSubchannel.Pack; + if(_resume.BadBlocks.Count <= 0 || _aborted || !_trim || !newTrim) return; - break; - case MmcSubchannel.Q16: - supportedPlextorSubchannel = PlextorSubchannel.Q16; - - break; - default: - supportedPlextorSubchannel = PlextorSubchannel.None; - - break; - } - - if(_resume.BadBlocks.Count <= 0 || - _aborted || - !_trim || - !newTrim) - return; - - start = DateTime.UtcNow; - UpdateStatus?.Invoke("Trimming skipped sectors"); - _dumpLog.WriteLine("Trimming skipped sectors"); + UpdateStatus?.Invoke(Localization.Core.Trimming_skipped_sectors); + _dumpLog.WriteLine(Localization.Core.Trimming_skipped_sectors); InitProgress?.Invoke(); + _trimStopwatch.Restart(); trimStart: ulong[] tmpArray = _resume.BadBlocks.ToArray(); @@ -132,51 +117,85 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke($"Trimming sector {badSector}"); + PulseProgress?.Invoke(string.Format(Localization.Core.Trimming_sector_0, badSector)); Track track = tracks.OrderBy(t => t.StartSector).LastOrDefault(t => badSector >= t.StartSector); byte sectorsToTrim = 1; var badSectorToRead = (uint)badSector; - if(_fixOffset && - audioExtents.Contains(badSector) && - offsetBytes != 0) + if(_fixOffset && audioExtents.Contains(badSector) && offsetBytes != 0) { - if(offsetBytes > 0) - badSectorToRead -= (uint)sectorsForOffset; + if(offsetBytes < 0) + { + if(badSectorToRead == 0) + badSectorToRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1 + else + badSectorToRead -= (uint)sectorsForOffset; + } - sectorsToTrim = (byte)(sectorsForOffset + 1); + sectorsToTrim += (byte)sectorsForOffset; } if(_supportsPlextorD8 && audioExtents.Contains(badSector)) - sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, badSectorToRead, blockSize, sectorsToTrim, - supportedPlextorSubchannel, out cmdDuration); + { + sense = ReadPlextorWithSubchannel(out cmdBuf, + out senseBuf, + badSectorToRead, + blockSize, + sectorsToTrim, + supportedPlextorSubchannel, + out cmdDuration); + } else if(readcd) { if(audioExtents.Contains(badSector)) { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, badSectorToRead, blockSize, sectorsToTrim, - MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + badSectorToRead, + blockSize, + sectorsToTrim, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); if(sense) { DecodedSense? decSense = Sense.Decode(senseBuf); // Try to workaround firmware - if(decSense?.ASC == 0x11 && decSense?.ASCQ == 0x05 || - decSense?.ASC == 0x64) + if(decSense is { ASC: 0x11, ASCQ: 0x05 } || decSense?.ASC == 0x64) { - sense = _dev.ReadCd(out cmdBuf, out _, badSectorToRead, blockSize, sectorsToTrim, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, - true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, + sense = _dev.ReadCd(out cmdBuf, + out _, + badSectorToRead, + blockSize, + sectorsToTrim, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, out double cmdDuration2); cmdDuration += cmdDuration2; @@ -185,23 +204,121 @@ partial class Dump } else { - sense = _dev.ReadCd(out cmdBuf, out senseBuf, badSectorToRead, blockSize, sectorsToTrim, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.ReadCd(out cmdBuf, + out senseBuf, + badSectorToRead, + blockSize, + sectorsToTrim, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, + out cmdDuration); if(sense) { DecodedSense? decSense = Sense.Decode(senseBuf); // Try to workaround firmware - if(decSense?.ASC == 0x64) + if(decSense is { ASC: 0x11, ASCQ: 0x05 } || decSense?.ASC == 0x64) { - sense = _dev.ReadCd(out cmdBuf, out _, badSectorToRead, blockSize, sectorsToTrim, - MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, supportedSubchannel, _dev.Timeout, + byte scrambledSectorsToTrim = sectorsToTrim; + uint scrambledBadSectorToRead = badSectorToRead; + + // Contrary to normal read, this must always be offset fixed, because it's data not audio + if(offsetBytes != 0) + { + if(offsetBytes < 0) + { + if(scrambledBadSectorToRead == 0) + scrambledBadSectorToRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1 + else + scrambledBadSectorToRead -= (uint)sectorsForOffset; + } + + scrambledSectorsToTrim += (byte)sectorsForOffset; + } + + sense = _dev.ReadCd(out cmdBuf, + out _, + scrambledBadSectorToRead, + blockSize, + scrambledSectorsToTrim, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + supportedSubchannel, + _dev.Timeout, out double cmdDuration2); cmdDuration += cmdDuration2; + + if(!sense) + { + uint scrambledBlocksToRead = scrambledSectorsToTrim; + + FixOffsetData(offsetBytes, + sectorSize, + sectorsForOffset, + supportedSubchannel, + ref scrambledBlocksToRead, + subSize, + ref cmdBuf, + blockSize, + false); + + // Descramble + cmdBuf = Sector.Scramble(cmdBuf); + + // Check valid sector + CdChecksums.CheckCdSector(cmdBuf, + out bool? correctEccP, + out bool? correctEccQ, + out bool? correctEdc); + + // Check mode, set sense if EDC/ECC validity is not correct + switch(cmdBuf[15] & 0x03) + { + case 0: + + for(var c = 16; c < 2352; c++) + { + if(cmdBuf[c] == 0x00) continue; + + sense = true; + + break; + } + + break; + case 1: + sense = correctEdc != true || correctEccP != true || correctEccQ != true; + + break; + case 2: + if((cmdBuf[18] & 0x20) != 0x20) + { + if(correctEccP != true) sense = true; + + if(correctEccQ != true) sense = true; + } + + if(correctEdc != true) sense = true; + + break; + } + } } } } @@ -209,17 +326,64 @@ partial class Dump totalDuration += cmdDuration; } else if(read16) - sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, badSectorToRead, blockSize, 0, - sectorsToTrim, false, _dev.Timeout, out cmdDuration); + { + sense = _dev.Read16(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + badSectorToRead, + blockSize, + 0, + sectorsToTrim, + false, + _dev.Timeout, + out cmdDuration); + } else if(read12) - sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, badSectorToRead, blockSize, - 0, sectorsToTrim, false, _dev.Timeout, out cmdDuration); + { + sense = _dev.Read12(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + false, + badSectorToRead, + blockSize, + 0, + sectorsToTrim, + false, + _dev.Timeout, + out cmdDuration); + } else if(read10) - sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, badSectorToRead, blockSize, - 0, sectorsToTrim, _dev.Timeout, out cmdDuration); + { + sense = _dev.Read10(out cmdBuf, + out senseBuf, + 0, + false, + true, + false, + false, + badSectorToRead, + blockSize, + 0, + sectorsToTrim, + _dev.Timeout, + out cmdDuration); + } else if(read6) - sense = _dev.Read6(out cmdBuf, out senseBuf, badSectorToRead, blockSize, sectorsToTrim, _dev.Timeout, + { + sense = _dev.Read6(out cmdBuf, + out senseBuf, + badSectorToRead, + blockSize, + sectorsToTrim, + _dev.Timeout, out cmdDuration); + } totalDuration += cmdDuration; @@ -230,30 +394,35 @@ partial class Dump continue; } - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { _resume.BadBlocks.Remove(badSector); extents.Add(badSector); + _mediaGraph?.PaintSectorGood(badSector); } // Because one block has been partially used to fix the offset - if(_fixOffset && - audioExtents.Contains(badSector) && - offsetBytes != 0) + if(_fixOffset && audioExtents.Contains(badSector) && offsetBytes != 0) { uint blocksToRead = sectorsToTrim; - FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead, subSize, - ref cmdBuf, blockSize, false); + FixOffsetData(offsetBytes, + sectorSize, + sectorsForOffset, + supportedSubchannel, + ref blocksToRead, + subSize, + ref cmdBuf, + blockSize, + false); } if(supportedSubchannel != MmcSubchannel.None) { var data = new byte[sectorSize]; var sub = new byte[subSize]; - Array.Copy(cmdBuf, 0, data, 0, sectorSize); - Array.Copy(cmdBuf, sectorSize, sub, 0, subSize); + Array.Copy(cmdBuf, 0, data, 0, sectorSize); + Array.Copy(cmdBuf, sectorSize, sub, 0, subSize); if(supportsLongSectors) outputOptical.WriteSectorLong(data, badSector); @@ -262,23 +431,33 @@ partial class Dump ulong trkStartBefore = track.StartSector; - bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, desiredSubchannel, - sub, badSector, 1, subLog, isrcs, - (byte)track.Sequence, ref mcn, tracks, + bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel, + desiredSubchannel, + sub, + badSector, + 1, + subLog, + isrcs, + (byte)track.Sequence, + ref mcn, + tracks, subchannelExtents, - _fixSubchannelPosition, outputOptical, - _fixSubchannel, _fixSubchannelCrc, - _dumpLog, UpdateStatus, - smallestPregapLbaPerTrack, true, out _); + _fixSubchannelPosition, + outputOptical, + _fixSubchannel, + _fixSubchannelCrc, + _dumpLog, + UpdateStatus, + smallestPregapLbaPerTrack, + true, + out _); // Set tracks and go back - if(!indexesChanged) - continue; + if(!indexesChanged) continue; outputOptical.SetTracks(tracks.ToList()); - if(track.StartSector != trkStartBefore && - !_resume.BadBlocks.Contains(track.StartSector)) + if(track.StartSector != trkStartBefore && !_resume.BadBlocks.Contains(track.StartSector)) { _resume.BadBlocks.Add(track.StartSector); @@ -296,9 +475,13 @@ partial class Dump outputOptical.WriteSector(Sector.GetUserData(cmdBuf), badSector); } + _trimStopwatch.Stop(); EndProgress?.Invoke(); - end = DateTime.UtcNow; - UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds."); - _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); } } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/Dump.cs b/Aaru.Core/Devices/Dumping/Dump.cs index aec1866fb..bb2316a1f 100644 --- a/Aaru.Core/Devices/Dumping/Dump.cs +++ b/Aaru.Core/Devices/Dumping/Dump.cs @@ -27,27 +27,29 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// Copyright © 2020-2022 Rebecca Wallander +// Copyright © 2011-2024 Natalia Portillo +// Copyright © 2020-2024 Rebecca Wallander // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; -using System.Xml.Serialization; +using System.Text.Json; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Metadata; using Aaru.Core.Logging; using Aaru.Database; using Aaru.Devices; -using Aaru.Settings; -using Schemas; +using Humanizer; +using File = System.IO.File; + +namespace Aaru.Core.Devices.Dumping; /// Subchannel requested to dump public enum DumpSubchannel @@ -66,49 +68,61 @@ public enum DumpSubchannel public partial class Dump { - readonly bool _debug; - readonly Device _dev; - readonly string _devicePath; - readonly bool _doResume; - readonly DumpLog _dumpLog; - readonly bool _dumpRaw; - readonly Encoding _encoding; - readonly ErrorLog _errorLog; - readonly bool _fixSubchannel; - readonly bool _fixSubchannelCrc; - readonly bool _fixSubchannelPosition; - readonly bool _force; - readonly Dictionary _formatOptions; - readonly bool _generateSubchannels; - readonly bool _metadata; - readonly string _outputPath; - readonly IBaseWritableImage _outputPlugin; - readonly string _outputPrefix; - readonly bool _persistent; - readonly CICMMetadataType _preSidecar; - readonly bool _private; - readonly ushort _retryPasses; - readonly bool _retrySubchannel; - readonly bool _stopOnError; - readonly bool _storeEncrypted; - readonly DumpSubchannel _subchannel; - readonly bool _titleKeys; - readonly bool _trim; - bool _aborted; - AaruContext _ctx; // Main database context - Database.Models.Device _dbDev; // Device database entry - bool _dumpFirstTrackPregap; - bool _fixOffset; - readonly uint _ignoreCdrRunOuts; - uint _maximumReadable; // Maximum number of sectors drive can read at once - Resume _resume; - Sidecar _sidecarClass; - uint _skip; - bool _skipCdireadyHole; - int _speed; - int _speedMultiplier; - bool _supportsPlextorD8; - bool _useBufferedReads; + const string PREGAP_MODULE_NAME = "Pregap calculator"; + const string MODULE_NAME = "Media dumping"; + static readonly TimeSpan _oneSecond = 1.Seconds(); + readonly bool _createGraph; + readonly bool _debug; + readonly Device _dev; + readonly string _devicePath; + readonly uint _dimensions; + readonly bool _doResume; + readonly DumpLog _dumpLog; + readonly bool _dumpRaw; + readonly Stopwatch _dumpStopwatch; + readonly Encoding _encoding; + readonly ErrorLog _errorLog; + readonly bool _fixSubchannel; + readonly bool _fixSubchannelCrc; + readonly bool _fixSubchannelPosition; + readonly bool _force; + readonly Dictionary _formatOptions; + readonly bool _generateSubchannels; + readonly uint _ignoreCdrRunOuts; + readonly Stopwatch _imageCloseStopwatch; + readonly bool _metadata; + readonly string _outputPath; + readonly IBaseWritableImage _outputPlugin; + readonly string _outputPrefix; + readonly bool _persistent; + readonly Metadata _preSidecar; + readonly bool _private; + readonly ushort _retryPasses; + readonly bool _retrySubchannel; + readonly Stopwatch _sidecarStopwatch; + readonly Stopwatch _speedStopwatch; + readonly bool _stopOnError; + readonly bool _storeEncrypted; + readonly DumpSubchannel _subchannel; + readonly bool _titleKeys; + readonly bool _trim; + readonly Stopwatch _trimStopwatch; + readonly Stopwatch _writeStopwatch; + bool _aborted; + AaruContext _ctx; // Main database context + Database.Models.Device _dbDev; // Device database entry + bool _dumpFirstTrackPregap; + bool _fixOffset; + uint _maximumReadable; // Maximum number of sectors drive can read at once + IMediaGraph _mediaGraph; + Resume _resume; + Sidecar _sidecarClass; + uint _skip; + bool _skipCdireadyHole; + int _speed; + int _speedMultiplier; + bool _supportsPlextorD8; + bool _useBufferedReads; /// Initializes dumpers /// Should resume? @@ -151,14 +165,16 @@ public partial class Dump /// Store encrypted data as is /// Dump DVD CSS title keys /// How many CD-R(W) run end sectors to ignore and regenerate - public Dump(bool doResume, Device dev, string devicePath, IBaseWritableImage outputPlugin, ushort retryPasses, - bool force, bool dumpRaw, bool persistent, bool stopOnError, Resume resume, DumpLog dumpLog, + /// If set to true creates a graph of the dump. + /// Dimensions of graph in pixels for a square + public Dump(bool doResume, Device dev, string devicePath, IBaseWritableImage outputPlugin, ushort retryPasses, + bool force, bool dumpRaw, bool persistent, bool stopOnError, Resume resume, DumpLog dumpLog, Encoding encoding, string outputPrefix, string outputPath, Dictionary formatOptions, - CICMMetadataType preSidecar, uint skip, bool metadata, bool trim, bool dumpFirstTrackPregap, - bool fixOffset, bool debug, DumpSubchannel subchannel, int speed, bool @private, - bool fixSubchannelPosition, bool retrySubchannel, bool fixSubchannel, bool fixSubchannelCrc, - bool skipCdireadyHole, ErrorLog errorLog, bool generateSubchannels, uint maximumReadable, - bool useBufferedReads, bool storeEncrypted, bool titleKeys, uint ignoreCdrRunOuts) + Metadata preSidecar, uint skip, bool metadata, bool trim, bool dumpFirstTrackPregap, bool fixOffset, + bool debug, DumpSubchannel subchannel, int speed, bool @private, bool fixSubchannelPosition, + bool retrySubchannel, bool fixSubchannel, bool fixSubchannelCrc, bool skipCdireadyHole, + ErrorLog errorLog, bool generateSubchannels, uint maximumReadable, bool useBufferedReads, + bool storeEncrypted, bool titleKeys, uint ignoreCdrRunOuts, bool createGraph, uint dimensions) { _doResume = doResume; _dev = dev; @@ -199,32 +215,39 @@ public partial class Dump _storeEncrypted = storeEncrypted; _titleKeys = titleKeys; _ignoreCdrRunOuts = ignoreCdrRunOuts; + _createGraph = createGraph; + _dimensions = dimensions; + _dumpStopwatch = new Stopwatch(); + _sidecarStopwatch = new Stopwatch(); + _speedStopwatch = new Stopwatch(); + _trimStopwatch = new Stopwatch(); + _writeStopwatch = new Stopwatch(); + _imageCloseStopwatch = new Stopwatch(); } /// Starts dumping with the established fields and autodetecting the device type public void Start() { // Open main database - _ctx = AaruContext.Create(Settings.MainDbPath); + _ctx = AaruContext.Create(Settings.Settings.MainDbPath); // Search for device in main database - _dbDev = _ctx.Devices.FirstOrDefault(d => d.Manufacturer == _dev.Manufacturer && d.Model == _dev.Model && + _dbDev = _ctx.Devices.FirstOrDefault(d => d.Manufacturer == _dev.Manufacturer && + d.Model == _dev.Model && d.Revision == _dev.FirmwareRevision); if(_dbDev is null) { - _dumpLog.WriteLine("Device not in database, please create a device report and attach it to a Github issue."); + _dumpLog.WriteLine(Localization.Core.Device_not_in_database); - UpdateStatus?. - Invoke("Device not in database, please create a device report and attach it to a Github issue."); + UpdateStatus?.Invoke(Localization.Core.Device_not_in_database); } else { - _dumpLog.WriteLine($"Device in database since {_dbDev.LastSynchronized}."); - UpdateStatus?.Invoke($"Device in database since {_dbDev.LastSynchronized}."); + _dumpLog.WriteLine(string.Format(Localization.Core.Device_in_database_since_0, _dbDev.LastSynchronized)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_in_database_since_0, _dbDev.LastSynchronized)); - if(_dbDev.OptimalMultipleSectorsRead > 0) - _maximumReadable = (uint)_dbDev.OptimalMultipleSectorsRead; + if(_dbDev.OptimalMultipleSectorsRead > 0) _maximumReadable = (uint)_dbDev.OptimalMultipleSectorsRead; } switch(_dev.IsUsb) @@ -259,9 +282,9 @@ public partial class Dump break; default: - _dumpLog.WriteLine("Unknown device type."); + _dumpLog.WriteLine(Localization.Core.Unknown_device_type); _dumpLog.Close(); - StoppingErrorMessage?.Invoke("Unknown device type."); + StoppingErrorMessage?.Invoke(Localization.Core.Unknown_device_type); return; } @@ -272,19 +295,31 @@ public partial class Dump _errorLog.Close(); _dumpLog.Close(); - if(_resume == null || - !_doResume) - return; + if(_resume == null || !_doResume) return; _resume.LastWriteDate = DateTime.UtcNow; _resume.BadBlocks.Sort(); - if(File.Exists(_outputPrefix + ".resume.xml")) - File.Delete(_outputPrefix + ".resume.xml"); + if(_createGraph && _mediaGraph is not null) + { + _mediaGraph?.PaintSectorsBad(_resume.BadBlocks); + _mediaGraph?.WriteTo($"{_outputPrefix}.graph.png"); + } + + if(File.Exists(_outputPrefix + ".resume.xml")) File.Delete(_outputPrefix + ".resume.xml"); + + if(File.Exists(_outputPrefix + ".resume.json")) File.Delete(_outputPrefix + ".resume.json"); + + var fs = new FileStream(_outputPrefix + ".resume.json", FileMode.Create, FileAccess.ReadWrite); + + JsonSerializer.Serialize(fs, + new ResumeJson + { + Resume = _resume + }, + typeof(ResumeJson), + ResumeJsonContext.Default); - var fs = new FileStream(_outputPrefix + ".resume.xml", FileMode.Create, FileAccess.ReadWrite); - var xs = new XmlSerializer(_resume.GetType()); - xs.Serialize(fs, _resume); fs.Close(); } @@ -297,22 +332,31 @@ public partial class Dump /// Event raised when the progress bar is not longer needed public event EndProgressHandler EndProgress; + /// Event raised when a progress bar is needed public event InitProgressHandler InitProgress; + /// Event raised to report status updates public event UpdateStatusHandler UpdateStatus; + /// Event raised to report a non-fatal error public event ErrorMessageHandler ErrorMessage; + /// Event raised to report a fatal error that stops the dumping operation and should call user's attention public event ErrorMessageHandler StoppingErrorMessage; + /// Event raised to update the values of a determinate progress bar public event UpdateProgressHandler UpdateProgress; + /// Event raised to update the status of an undeterminate progress bar public event PulseProgressHandler PulseProgress; + /// Event raised when the progress bar is not longer needed public event EndProgressHandler2 EndProgress2; + /// Event raised when a progress bar is needed public event InitProgressHandler2 InitProgress2; + /// Event raised to update the values of a determinate progress bar public event UpdateProgressHandler2 UpdateProgress2; } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/LinearMemory/Retrode.cs b/Aaru.Core/Devices/Dumping/LinearMemory/Retrode.cs index 67638df27..eec2c71e7 100644 --- a/Aaru.Core/Devices/Dumping/LinearMemory/Retrode.cs +++ b/Aaru.Core/Devices/Dumping/LinearMemory/Retrode.cs @@ -27,66 +27,53 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - using System; using System.Linq; using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs; +using Aaru.Core.Graphics; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Devices.Dumping; + public partial class Dump { - static readonly byte[] _sfcExtension = - { - 0x53, 0x46, 0x43 - }; - - static readonly byte[] _genesisExtension = - { - 0x42, 0x49, 0x4E - }; - - static readonly byte[] _smsExtension = - { - 0x53, 0x4D, 0x53 - }; - - static readonly byte[] _z64Extension = - { - 0x5A, 0x36, 0x34 - }; - - static readonly byte[] _gbExtension = - { - 0x47, 0x42, 0x20 - }; - - static readonly byte[] _gbcExtension = - { - 0x47, 0x42, 0x43 - }; - - static readonly byte[] _gbaExtension = - { - 0x47, 0x42, 0x41 - }; + static readonly byte[] _sfcExtension = "SFC"u8.ToArray(); + static readonly byte[] _genesisExtension = "BIN"u8.ToArray(); + static readonly byte[] _smsExtension = "SMS"u8.ToArray(); + static readonly byte[] _z64Extension = "Z64"u8.ToArray(); + static readonly byte[] _gbExtension = "GB "u8.ToArray(); + static readonly byte[] _gbcExtension = "GBC"u8.ToArray(); + static readonly byte[] _gbaExtension = "GBA"u8.ToArray(); /// Dumps a game cartridge using a Retrode adapter void Retrode() { - bool sense = _dev.Read10(out byte[] buffer, out _, 0, false, true, false, false, 0, 512, 0, 1, _dev.Timeout, + bool sense = _dev.Read10(out byte[] buffer, + out _, + 0, + false, + true, + false, + false, + 0, + 512, + 0, + 1, + _dev.Timeout, out _); if(sense) { - _dumpLog.WriteLine("Could not read..."); - StoppingErrorMessage?.Invoke("Could not read..."); + _dumpLog.WriteLine(Localization.Core.Could_not_read); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_read); return; } @@ -98,8 +85,8 @@ public partial class Dump // UMDs are stored inside a FAT16 volume if(!tmp.SequenceEqual(_fatSignature)) { - _dumpLog.WriteLine("Retrode partition not recognized, not dumping..."); - StoppingErrorMessage?.Invoke("Retrode partition not recognized, not dumping..."); + _dumpLog.WriteLine(Localization.Core.Retrode_partition_not_recognized_not_dumping); + StoppingErrorMessage?.Invoke(Localization.Core.Retrode_partition_not_recognized_not_dumping); return; } @@ -110,15 +97,15 @@ public partial class Dump var rootSize = (ushort)(((buffer[0x12] << 8) + buffer[0x11]) * 32 / 512); byte sectorsPerCluster = buffer[0x0D]; - UpdateStatus?.Invoke($"Reading root directory in sector {rootStart}..."); - _dumpLog.WriteLine("Reading root directory in sector {0}...", rootStart); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_root_directory_in_sector_0, rootStart)); + _dumpLog.WriteLine(Localization.Core.Reading_root_directory_in_sector_0, rootStart); sense = _dev.Read10(out buffer, out _, 0, false, true, false, false, rootStart, 512, 0, 1, _dev.Timeout, out _); if(sense) { - StoppingErrorMessage?.Invoke("Could not read..."); - _dumpLog.WriteLine("Could not read..."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_read); + _dumpLog.WriteLine(Localization.Core.Could_not_read); return; } @@ -179,21 +166,17 @@ public partial class Dump break; } - if(tmp.SequenceEqual(_gbaExtension)) - { - gbaFound = true; + if(!tmp.SequenceEqual(_gbaExtension)) continue; - break; - } + gbaFound = true; + + break; } - if(!sfcFound && - !genesisFound && - !smsFound && - !n64Found) + if(!sfcFound && !genesisFound && !smsFound && !n64Found && !gbaFound && !gbFound && !gbcFound) { - StoppingErrorMessage?.Invoke("No cartridge found, not dumping..."); - _dumpLog.WriteLine("No cartridge found, not dumping..."); + StoppingErrorMessage?.Invoke(Localization.Core.No_cartridge_found_not_dumping); + _dumpLog.WriteLine(Localization.Core.No_cartridge_found_not_dumping); return; } @@ -220,22 +203,34 @@ public partial class Dump double minSpeed = double.MaxValue; byte[] senseBuf; - if(_outputPlugin is not IByteAddressableImage outputBai || - !outputBai.SupportedMediaTypes.Contains(mediaType)) + if(_outputPlugin is not IByteAddressableImage outputBai || !outputBai.SupportedMediaTypes.Contains(mediaType)) { - _dumpLog.WriteLine("The specified format does not support the inserted cartridge..."); - StoppingErrorMessage?.Invoke("The specified format does not support the inserted cartridge..."); + _dumpLog.WriteLine(Localization.Core.The_specified_format_does_not_support_the_inserted_cartridge); + + StoppingErrorMessage?.Invoke(Localization.Core + .The_specified_format_does_not_support_the_inserted_cartridge); return; } - sense = _dev.Read10(out byte[] readBuffer, out _, 0, false, true, false, false, 0, 512, 0, 1, _dev.Timeout, + sense = _dev.Read10(out byte[] readBuffer, + out _, + 0, + false, + true, + false, + false, + 0, + 512, + 0, + 1, + _dev.Timeout, out _); if(sense) { - _dumpLog.WriteLine("Could not read..."); - StoppingErrorMessage?.Invoke("Could not read..."); + _dumpLog.WriteLine(Localization.Core.Could_not_read); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_read); return; } @@ -244,183 +239,243 @@ public partial class Dump uint romSectors = romSize / 512; uint romRemaining = romSize % 512; - if(romSize > 1073741824) - UpdateStatus?.Invoke($"Cartridge has {romSize} bytes ({romSize / 1073741824d:F3} GiB)"); - else if(romSize > 1048576) - UpdateStatus?.Invoke($"Cartridge has {romSize} bytes ({romSize / 1048576d:F3} MiB)"); - else if(romSize > 1024) - UpdateStatus?.Invoke($"Cartridge has {romSize} bytes ({romSize / 1024d:F3} KiB)"); - else - UpdateStatus?.Invoke($"Cartridge has {romSize} bytes"); + switch(romSize) + { + case > 1073741824: + UpdateStatus?.Invoke(string.Format(Localization.Core.Cartridge_has_0_bytes_1_GiB, + romSize, + romSize / 1073741824d)); - UpdateStatus?.Invoke($"Media identified as {mediaType}."); - _dumpLog.WriteLine("Media identified as {0}.", mediaType); + break; + case > 1048576: + UpdateStatus?.Invoke(string.Format(Localization.Core.Cartridge_has_0_bytes_1_MiB, + romSize, + romSize / 1048576d)); + + break; + case > 1024: + UpdateStatus?.Invoke(string.Format(Localization.Core.Cartridge_has_0_bytes_1_KiB, + romSize, + romSize / 1024d)); + + break; + default: + UpdateStatus?.Invoke(string.Format(Localization.Core.Cartridge_has_0_bytes, romSize)); + + break; + } + + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_identified_as_0, mediaType)); + _dumpLog.WriteLine(Localization.Core.Media_identified_as_0, mediaType); ErrorNumber ret = outputBai.Create(_outputPath, mediaType, _formatOptions, romSize); // Cannot create image if(ret != ErrorNumber.NoError) { - _dumpLog.WriteLine("Error {0} creating output image, not continuing.", ret); + _dumpLog.WriteLine(Localization.Core.Error_0_creating_output_image_not_continuing, ret); _dumpLog.WriteLine(outputBai.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputBai.ErrorMessage); return; } - DateTime start = DateTime.UtcNow; - double imageWriteDuration = 0; + if(_createGraph) _mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, romSectors); - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _dumpStopwatch.Restart(); + double imageWriteDuration = 0; + + _speedStopwatch.Restart(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ulong i = 0; i < romSectors; i += blocksToRead) { if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(romSectors - i < blocksToRead) - blocksToRead = (uint)(romSectors - i); + if(romSectors - i < blocksToRead) blocksToRead = (uint)(romSectors - i); - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading byte {i * 512} of {romSize} ({currentSpeed:F3} MiB/sec.)", (long)i * 512, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_byte_0_of_1_2, + i * 512, + romSize, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i * 512, romSize); - sense = _dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)(startSector + i), - 512, 0, (ushort)blocksToRead, _dev.Timeout, out double cmdDuration); + _speedStopwatch.Start(); + sense = _dev.Read10(out readBuffer, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)(startSector + i), + 512, + 0, + (ushort)blocksToRead, + _dev.Timeout, + out double cmdDuration); + + _speedStopwatch.Stop(); totalDuration += cmdDuration; - if(!sense && - !_dev.Error) + _writeStopwatch.Restart(); + + if(!sense && !_dev.Error) { - DateTime writeStart = DateTime.Now; outputBai.WriteBytes(readBuffer, 0, readBuffer.Length, out _); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + _mediaGraph.PaintSectorsGood(i, blocksToRead); } else { _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly - _dumpLog.WriteLine("Skipping {0} bytes from errored byte {1}.", _skip * 512, i * 512); + _dumpLog.WriteLine(Localization.Core.Skipping_0_bytes_from_errored_byte_1, _skip * 512, i * 512); i += _skip - blocksToRead; } + _writeStopwatch.Stop(); + sectorSpeedStart += blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * 512 < 524288) continue; currentSpeed = sectorSpeedStart * 512 / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } - if(romRemaining > 0 && - !_aborted) + _speedStopwatch.Stop(); + + if(romRemaining > 0 && !_aborted) { - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading byte {romSectors * 512} of {romSize} ({currentSpeed:F3} MiB/sec.)", - (long)romSectors * 512, romSize); + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_byte_0_of_1_2, + romSectors * 512, + romSize, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)romSectors * 512, + romSize); - sense = _dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, romSectors, 512, 0, 1, - _dev.Timeout, out double cmdDuration); + sense = _dev.Read10(out readBuffer, + out senseBuf, + 0, + false, + true, + false, + false, + romSectors, + 512, + 0, + 1, + _dev.Timeout, + out double cmdDuration); totalDuration += cmdDuration; - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputBai.WriteBytes(readBuffer, 0, (int)romRemaining, out _); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + _writeStopwatch.Stop(); } else { _errorLog?.WriteLine(romSectors, _dev.Error, _dev.LastError, senseBuf); // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly - _dumpLog.WriteLine("Skipping {0} bytes from errored byte {1}.", _skip * 512, romSectors * 512); + _dumpLog.WriteLine(Localization.Core.Skipping_0_bytes_from_errored_byte_1, + _skip * 512, + romSectors * 512); } } - DateTime end = DateTime.UtcNow; EndProgress?.Invoke(); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {512 * (double)(romSectors + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(512 * (romSectors + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {512 * (double)(romSectors + 1) / 1024 / imageWriteDuration:F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(512 * (romSectors + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - 512 * (double)(romSectors + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(512 * (romSectors + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - 512 * (double)(romSectors + 1) / 1024 / imageWriteDuration); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(512 * (romSectors + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - var metadata = new ImageInfo + var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; - if(!outputBai.SetMetadata(metadata)) - ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + + if(!outputBai.SetImageInfo(metadata)) + { + ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + + Environment.NewLine + outputBai.ErrorMessage); + } // TODO: Set dump hardware //outputBAI.SetDumpHardware(); - if(_preSidecar != null) - outputBai.SetCicmMetadata(_preSidecar); + if(_preSidecar != null) outputBai.SetMetadata(_preSidecar); - _dumpLog.WriteLine("Closing output file."); - UpdateStatus?.Invoke("Closing output file."); - DateTime closeStart = DateTime.Now; + _dumpLog.WriteLine(Localization.Core.Closing_output_file); + UpdateStatus?.Invoke(Localization.Core.Closing_output_file); + _imageCloseStopwatch.Restart(); outputBai.Close(); - DateTime closeEnd = DateTime.Now; - _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); + _imageCloseStopwatch.Stop(); + + _dumpLog.WriteLine(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); return; } @@ -433,17 +488,30 @@ public partial class Dump */ UpdateStatus?.Invoke(""); - UpdateStatus?. - Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second), + totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second), + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average speed: {512 * (double)(romSectors + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0, + ByteSize.FromBytes(512 * (romSectors + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); if(maxSpeed > 0) - UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0, + ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize())); + } if(minSpeed is > 0 and < double.MaxValue) - UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0, + ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize())); + } UpdateStatus?.Invoke(""); diff --git a/Aaru.Core/Devices/Dumping/MMC.cs b/Aaru.Core/Devices/Dumping/MMC.cs index 1c0ff5e42..35cdea42e 100644 --- a/Aaru.Core/Devices/Dumping/MMC.cs +++ b/Aaru.Core/Devices/Dumping/MMC.cs @@ -27,19 +27,14 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// Copyright © 2020-2022 Rebecca Wallander +// Copyright © 2011-2024 Natalia Portillo +// Copyright © 2020-2024 Rebecca Wallander // ****************************************************************************/ -using DVDDecryption = Aaru.Decryption.DVD.Dump; - -// ReSharper disable JoinDeclarationAndInitializer - -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.Bluray; @@ -49,13 +44,16 @@ using Aaru.Decoders.SCSI.MMC; using Aaru.Decryption; using Aaru.Decryption.DVD; using Aaru.Devices; -using Aaru.Settings; -using Schemas; using DDS = Aaru.Decoders.DVD.DDS; using DMI = Aaru.Decoders.Xbox.DMI; +using DVDDecryption = Aaru.Decryption.DVD.Dump; using Inquiry = Aaru.CommonTypes.Structs.Devices.SCSI.Inquiry; using Spare = Aaru.Decoders.DVD.Spare; +// ReSharper disable JoinDeclarationAndInitializer + +namespace Aaru.Core.Devices.Dumping; + /// Implement dumping optical discs from MultiMedia devices partial class Dump { @@ -78,7 +76,7 @@ partial class Dump { gotConfiguration = true; Features.SeparatedFeatures ftr = Features.Separate(cmdBuf); - _dumpLog.WriteLine("Device reports current profile is 0x{0:X4}", ftr.CurrentProfile); + _dumpLog.WriteLine(Localization.Core.Device_reports_current_profile_is_0, ftr.CurrentProfile); switch(ftr.CurrentProfile) { @@ -211,38 +209,68 @@ partial class Dump if(sense || _dev.Error) { - sense = _dev.ModeSense6(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, 0x00, _dev.Timeout, + sense = _dev.ModeSense6(out cmdBuf, + out _, + false, + ScsiModeSensePageControl.Current, + 0x00, + _dev.Timeout, out _); - if(!sense && - !_dev.Error) - decMode = Modes.DecodeMode6(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice); + if(!sense && !_dev.Error) decMode = Modes.DecodeMode6(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice); } else decMode = Modes.DecodeMode6(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice); if(decMode is null) { - sense = _dev.ModeSense10(out cmdBuf, out _, false, true, ScsiModeSensePageControl.Current, 0x3F, 0x00, - _dev.Timeout, out _); + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + _dev.Timeout, + out _); if(sense || _dev.Error) { - sense = _dev.ModeSense10(out cmdBuf, out _, false, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, - _dev.Timeout, out _); + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + _dev.Timeout, + out _); if(sense || _dev.Error) { - sense = _dev.ModeSense10(out cmdBuf, out _, false, true, ScsiModeSensePageControl.Current, 0x00, - 0x00, _dev.Timeout, out _); + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + true, + ScsiModeSensePageControl.Current, + 0x00, + 0x00, + _dev.Timeout, + out _); if(sense || _dev.Error) { - sense = _dev.ModeSense10(out cmdBuf, out _, false, false, ScsiModeSensePageControl.Current, - 0x00, 0x00, _dev.Timeout, out _); + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + false, + ScsiModeSensePageControl.Current, + 0x00, + 0x00, + _dev.Timeout, + out _); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) decMode = Modes.DecodeMode10(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice); } else @@ -258,8 +286,9 @@ partial class Dump if(decMode.HasValue && _dev.IsUsb && !gotConfiguration && - decMode.Value.Header.MediumType is MediumTypes.UnknownBlockDevice or MediumTypes.ReadOnlyBlockDevice - or MediumTypes.ReadWriteBlockDevice) + decMode.Value.Header.MediumType is MediumTypes.UnknownBlockDevice + or MediumTypes.ReadOnlyBlockDevice + or MediumTypes.ReadWriteBlockDevice) { _speedMultiplier = -1; Sbc(null, MediaType.Unknown, false); @@ -279,50 +308,49 @@ partial class Dump var scsiReader = new Reader(_dev, _dev.Timeout, null, _errorLog, _dumpRaw); ulong blocks = scsiReader.GetDeviceBlocks(); - _dumpLog.WriteLine("Device reports disc has {0} blocks", blocks); - var mediaTags = new Dictionary(); + _dumpLog.WriteLine(Localization.Core.Device_reports_disc_has_0_blocks, blocks); + Dictionary mediaTags = new(); if(dskType == MediaType.PD650) - switch(blocks + 1) - { - case 1281856: - dskType = MediaType.PD650_WORM; + { + dskType = (blocks + 1) switch + { + 1281856 => MediaType.PD650_WORM, + 58620544 => MediaType.REV120, + 17090880 => MediaType.REV35, + 34185728 => MediaType.REV70, + _ => dskType + }; + } - break; - case 58620544: - dskType = MediaType.REV120; +#region Nintendo - break; - case 17090880: - dskType = MediaType.REV35; - - break; - - case 34185728: - dskType = MediaType.REV70; - - break; - } - - #region Nintendo switch(dskType) { case MediaType.Unknown when blocks > 0: - _dumpLog.WriteLine("Reading Physical Format Information"); + _dumpLog.WriteLine(Localization.Core.Reading_Physical_Format_Information); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + _dev.Timeout, + out _); if(!sense) { PFI.PhysicalFormatInformation? nintendoPfi = PFI.Decode(cmdBuf, dskType); - if(nintendoPfi?.DiskCategory == DiskCategory.Nintendo && - nintendoPfi.Value.PartVersion == 15) + if(nintendoPfi is { DiskCategory: DiskCategory.Nintendo, PartVersion: 15 }) { - _dumpLog.WriteLine("Dumping Nintendo GameCube or Wii discs is not yet implemented."); + _dumpLog.WriteLine(Localization.Core + .Dumping_Nintendo_GameCube_or_Wii_discs_is_not_yet_implemented); - StoppingErrorMessage?.Invoke("Dumping Nintendo GameCube or Wii discs is not yet implemented."); + StoppingErrorMessage?.Invoke(Localization.Core + .Dumping_Nintendo_GameCube_or_Wii_discs_is_not_yet_implemented); return; } @@ -346,10 +374,17 @@ partial class Dump case MediaType.HDDVDROM: case MediaType.HDDVDRW: case MediaType.HDDVDRWDL: - _dumpLog.WriteLine("Reading Physical Format Information"); + _dumpLog.WriteLine(Localization.Core.Reading_Physical_Format_Information); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + _dev.Timeout, + out _); if(!sense) { @@ -365,78 +400,45 @@ partial class Dump UpdateStatus?.Invoke($"PFI:\n{PFI.Prettify(decPfi)}"); // False book types - switch(decPfi.DiskCategory) - { - case DiskCategory.DVDPR: - dskType = MediaType.DVDPR; - - break; - case DiskCategory.DVDPRDL: - dskType = MediaType.DVDPRDL; - - break; - case DiskCategory.DVDPRW: - dskType = MediaType.DVDPRW; - - break; - case DiskCategory.DVDPRWDL: - dskType = MediaType.DVDPRWDL; - - break; - case DiskCategory.DVDR: - dskType = decPfi.PartVersion >= 6 ? MediaType.DVDRDL : MediaType.DVDR; - - break; - case DiskCategory.DVDRAM: - dskType = MediaType.DVDRAM; - - break; - default: - dskType = MediaType.DVDROM; - - break; - case DiskCategory.DVDRW: - dskType = decPfi.PartVersion >= 15 ? MediaType.DVDRWDL : MediaType.DVDRW; - - break; - case DiskCategory.HDDVDR: - dskType = MediaType.HDDVDR; - - break; - case DiskCategory.HDDVDRAM: - dskType = MediaType.HDDVDRAM; - - break; - case DiskCategory.HDDVDROM: - dskType = MediaType.HDDVDROM; - - break; - case DiskCategory.HDDVDRW: - dskType = MediaType.HDDVDRW; - - break; - case DiskCategory.Nintendo: - dskType = decPfi.DiscSize == DVDSize.Eighty ? MediaType.GOD : MediaType.WOD; - - break; - case DiskCategory.UMD: - dskType = MediaType.UMD; - - break; - } + dskType = decPfi.DiskCategory switch + { + DiskCategory.DVDPR => MediaType.DVDPR, + DiskCategory.DVDPRDL => MediaType.DVDPRDL, + DiskCategory.DVDPRW => MediaType.DVDPRW, + DiskCategory.DVDPRWDL => MediaType.DVDPRWDL, + DiskCategory.DVDR => decPfi.PartVersion >= 6 ? MediaType.DVDRDL : MediaType.DVDR, + DiskCategory.DVDRAM => MediaType.DVDRAM, + DiskCategory.DVDRW => decPfi.PartVersion >= 15 + ? MediaType.DVDRWDL + : MediaType.DVDRW, + DiskCategory.HDDVDR => MediaType.HDDVDR, + DiskCategory.HDDVDRAM => MediaType.HDDVDRAM, + DiskCategory.HDDVDROM => MediaType.HDDVDROM, + DiskCategory.HDDVDRW => MediaType.HDDVDRW, + DiskCategory.Nintendo => decPfi.DiscSize == DVDSize.Eighty + ? MediaType.GOD + : MediaType.WOD, + DiskCategory.UMD => MediaType.UMD, + _ => MediaType.DVDROM + }; } } - _dumpLog.WriteLine("Reading Disc Manufacturing Information"); + _dumpLog.WriteLine(Localization.Core.Reading_Disc_Manufacturing_Information); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DiscManufacturingInformation, 0, _dev.Timeout, + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DiscManufacturingInformation, + 0, + _dev.Timeout, out _); if(!sense) { - if(DMI.IsXbox(cmdBuf) || - DMI.IsXbox360(cmdBuf)) + if(DMI.IsXbox(cmdBuf) || DMI.IsXbox360(cmdBuf)) { if(DMI.IsXbox(cmdBuf)) dskType = MediaType.XGD; @@ -457,21 +459,21 @@ partial class Dump if(sense || Inquiry.Decode(inqBuf)?.KreonPresent != true) { - _dumpLog.WriteLine("Dumping Xbox Game Discs requires a drive with Kreon firmware."); + _dumpLog.WriteLine(Localization.Core + .Dumping_Xbox_Game_Discs_requires_a_drive_with_Kreon_firmware); - StoppingErrorMessage?. - Invoke("Dumping Xbox Game Discs requires a drive with Kreon firmware."); + StoppingErrorMessage?.Invoke(Localization.Core + .Dumping_Xbox_Game_Discs_requires_a_drive_with_Kreon_firmware); - if(!_force) - return; + if(!_force) return; isXbox = false; } if(_dumpRaw && !_force) { - StoppingErrorMessage?. - Invoke("Not continuing. If you want to continue reading cooked data when raw is not available use the force option."); + StoppingErrorMessage?.Invoke(Localization.Core + .If_you_want_to_continue_reading_cooked_data_when_raw_is_not_available_use_the_force_option); // TODO: Exit more gracefully return; @@ -488,20 +490,31 @@ partial class Dump break; } - #endregion Nintendo - #region All DVD and HD DVD types - #endregion All DVD and HD DVD types +#endregion Nintendo + +#region All DVD and HD DVD types + +#endregion All DVD and HD DVD types + +#region DVD-ROM - #region DVD-ROM if(dskType is MediaType.DVDDownload or MediaType.DVDROM) { - _dumpLog.WriteLine("Reading Lead-in Copyright Information."); + _dumpLog.WriteLine(Localization.Core.Reading_Lead_in_Copyright_Information); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.CopyrightInformation, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.CopyrightInformation, + 0, + _dev.Timeout, + out _); if(!sense) + { if(CSS_CPRM.DecodeLeadInCopyright(cmdBuf).HasValue) { tmpBuf = new byte[cmdBuf.Length - 4]; @@ -511,46 +524,58 @@ partial class Dump CSS_CPRM.LeadInCopyright? cmi = CSS_CPRM.DecodeLeadInCopyright(cmdBuf); if(cmi?.CopyrightType == CopyrightType.NoProtection) - UpdateStatus?.Invoke("Drive reports no copy protection on disc."); + UpdateStatus?.Invoke(Localization.Core.Drive_reports_no_copy_protection_on_disc); else { - if(!Settings.Current.EnableDecryption) - UpdateStatus?.Invoke("Drive reports the disc uses copy protection. " + - "The dump will be incorrect unless decryption is enabled."); + if(!Settings.Settings.Current.EnableDecryption) + { + UpdateStatus?.Invoke(Localization.Core + .Drive_reports_the_disc_uses_copy_protection_The_dump_will_be_incorrect_unless_decryption_is_enabled); + } else { if(cmi?.CopyrightType == CopyrightType.CSS) { - UpdateStatus?.Invoke("Drive reports disc uses CSS copy protection."); + UpdateStatus?.Invoke(Localization.Core.Drive_reports_disc_uses_CSS_copy_protection); dvdDecrypt = new DVDDecryption(_dev); - sense = dvdDecrypt.ReadBusKey(out cmdBuf, out _, + sense = dvdDecrypt.ReadBusKey(out cmdBuf, + out _, CSS_CPRM.DecodeLeadInCopyright(cmdBuf)?.CopyrightType ?? - CopyrightType.NoProtection, _dev.Timeout, out _); + CopyrightType.NoProtection, + _dev.Timeout, + out _); if(!sense) { byte[] busKey = cmdBuf; - UpdateStatus?.Invoke("Reading disc key."); + UpdateStatus?.Invoke(Localization.Core.Reading_disc_key); sense = dvdDecrypt.ReadDiscKey(out cmdBuf, out _, _dev.Timeout, out _); if(!sense) { CSS_CPRM.DiscKey? decodedDiscKey = CSS.DecodeDiscKey(cmdBuf, busKey); - sense = dvdDecrypt.ReadAsf(out cmdBuf, out _, DvdCssKeyClass.DvdCssCppmOrCprm, - _dev.Timeout, out _); + sense = dvdDecrypt.ReadAsf(out cmdBuf, + out _, + DvdCssKeyClass.DvdCssCppmOrCprm, + _dev.Timeout, + out _); if(!sense) + { if(cmdBuf[7] == 1) { - UpdateStatus?.Invoke("Disc and drive authentication succeeded."); + UpdateStatus?.Invoke(Localization.Core + .Disc_and_drive_authentication_succeeded); - sense = dvdDecrypt.ReadRpc(out cmdBuf, out _, + sense = dvdDecrypt.ReadRpc(out cmdBuf, + out _, DvdCssKeyClass.DvdCssCppmOrCprm, - _dev.Timeout, out _); + _dev.Timeout, + out _); if(!sense) { @@ -558,51 +583,75 @@ partial class Dump CSS_CPRM.DecodeRegionalPlaybackControlState(cmdBuf); if(rpc.HasValue) + { UpdateStatus?.Invoke(CSS.CheckRegion(rpc.Value, cmi.Value) - ? "Disc and drive regions match." - : "Disc and drive regions do not match. The dump will be incorrect"); + ? Localization.Core + .Disc_and_drive_regions_match + : Localization.Core + .Disc_and_drive_regions_do_not_match_The_dump_will_be_incorrect); + } } if(decodedDiscKey.HasValue) { mediaTags.Add(MediaTagType.DVD_DiscKey, decodedDiscKey.Value.Key); - UpdateStatus?.Invoke("Decrypting disc key."); + UpdateStatus?.Invoke(Localization.Core.Decrypting_disc_key); CSS.DecryptDiscKey(decodedDiscKey.Value.Key, out byte[] discKey); if(discKey != null) { - UpdateStatus?.Invoke("Decryption of disc key succeeded."); + UpdateStatus?.Invoke(Localization.Core + .Decryption_of_disc_key_succeeded); + mediaTags.Add(MediaTagType.DVD_DiscKey_Decrypted, discKey); } else - UpdateStatus?.Invoke("Decryption of disc key failed."); + { + UpdateStatus?.Invoke(Localization.Core + .Decryption_of_disc_key_failed); + } } } + } } } } else - UpdateStatus?. - Invoke($"Drive reports disc uses {(CSS_CPRM.DecodeLeadInCopyright(cmdBuf)?.CopyrightType ?? CopyrightType.NoProtection).ToString()} copy protection. " + - "This is not yet supported and the dump will be incorrect."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core + .Drive_reports_0_copy_protection_not_yet_supported_dump_incorrect, + (CSS_CPRM.DecodeLeadInCopyright(cmdBuf) + ?.CopyrightType ?? + CopyrightType.NoProtection).ToString())); + } } } } + } } - #endregion DVD-ROM + +#endregion DVD-ROM switch(dskType) { - #region DVD-ROM and HD DVD-ROM +#region DVD-ROM and HD DVD-ROM + case MediaType.DVDDownload: case MediaType.DVDROM: case MediaType.HDDVDROM: - _dumpLog.WriteLine("Reading Burst Cutting Area."); + _dumpLog.WriteLine(Localization.Core.Reading_Burst_Cutting_Area); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.BurstCuttingArea, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.BurstCuttingArea, + 0, + _dev.Timeout, + out _); if(!sense) { @@ -612,48 +661,76 @@ partial class Dump } break; - #endregion DVD-ROM and HD DVD-ROM - #region DVD-RAM and HD DVD-RAM +#endregion DVD-ROM and HD DVD-ROM + +#region DVD-RAM and HD DVD-RAM + case MediaType.DVDRAM: case MediaType.HDDVDRAM: - _dumpLog.WriteLine("Reading Disc Description Structure."); + _dumpLog.WriteLine(Localization.Core.Reading_Disc_Description_Structure); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdramDds, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdramDds, + 0, + _dev.Timeout, + out _); if(!sense) + { if(DDS.Decode(cmdBuf).HasValue) { tmpBuf = new byte[cmdBuf.Length - 4]; Array.Copy(cmdBuf, 4, tmpBuf, 0, cmdBuf.Length - 4); mediaTags.Add(MediaTagType.DVDRAM_DDS, tmpBuf); } + } - _dumpLog.WriteLine("Reading Spare Area Information."); + _dumpLog.WriteLine(Localization.Core.Reading_Spare_Area_Information); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdramSpareAreaInformation, 0, _dev.Timeout, + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdramSpareAreaInformation, + 0, + _dev.Timeout, out _); if(!sense) + { if(Spare.Decode(cmdBuf).HasValue) { tmpBuf = new byte[cmdBuf.Length - 4]; Array.Copy(cmdBuf, 4, tmpBuf, 0, cmdBuf.Length - 4); mediaTags.Add(MediaTagType.DVDRAM_SpareArea, tmpBuf); } + } break; - #endregion DVD-RAM and HD DVD-RAM - #region DVD-R and DVD-RW +#endregion DVD-RAM and HD DVD-RAM + +#region DVD-R and DVD-RW + case MediaType.DVDR: case MediaType.DVDRW: - _dumpLog.WriteLine("Reading Pre-Recorded Information."); + _dumpLog.WriteLine(Localization.Core.Reading_Pre_Recorded_Information); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PreRecordedInfo, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PreRecordedInfo, + 0, + _dev.Timeout, + out _); if(!sense) { @@ -663,19 +740,28 @@ partial class Dump } break; - #endregion DVD-R and DVD-RW + +#endregion DVD-R and DVD-RW } switch(dskType) { - #region DVD-R, DVD-RW and HD DVD-R +#region DVD-R, DVD-RW and HD DVD-R + case MediaType.DVDR: case MediaType.DVDRW: case MediaType.HDDVDR: - _dumpLog.WriteLine("Reading Media Identifier."); + _dumpLog.WriteLine(Localization.Core.Reading_Media_Identifier); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdrMediaIdentifier, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdrMediaIdentifier, + 0, + _dev.Timeout, + out _); if(!sense) { @@ -684,10 +770,17 @@ partial class Dump mediaTags.Add(MediaTagType.DVDR_MediaIdentifier, tmpBuf); } - _dumpLog.WriteLine("Reading Recordable Physical Information."); + _dumpLog.WriteLine(Localization.Core.Reading_Recordable_Physical_Information); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdrPhysicalInformation, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdrPhysicalInformation, + 0, + _dev.Timeout, + out _); if(!sense) { @@ -697,17 +790,26 @@ partial class Dump } break; - #endregion DVD-R, DVD-RW and HD DVD-R - #region All DVD+ +#endregion DVD-R, DVD-RW and HD DVD-R + +#region All DVD+ + case MediaType.DVDPR: case MediaType.DVDPRDL: case MediaType.DVDPRW: case MediaType.DVDPRWDL: - _dumpLog.WriteLine("Reading ADdress In Pregroove."); + _dumpLog.WriteLine(Localization.Core.Reading_ADdress_In_Pregroove); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.Adip, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.Adip, + 0, + _dev.Timeout, + out _); if(!sense) { @@ -716,10 +818,17 @@ partial class Dump mediaTags.Add(MediaTagType.DVD_ADIP, tmpBuf); } - _dumpLog.WriteLine("Reading Disc Control Blocks."); + _dumpLog.WriteLine(Localization.Core.Reading_Disc_Control_Blocks); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.Dcb, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.Dcb, + 0, + _dev.Timeout, + out _); if(!sense) { @@ -729,14 +838,22 @@ partial class Dump } break; - #endregion All DVD+ - #region HD DVD-ROM +#endregion All DVD+ + +#region HD DVD-ROM + case MediaType.HDDVDROM: - _dumpLog.WriteLine("Reading Lead-in Copyright Information."); + _dumpLog.WriteLine(Localization.Core.Reading_Lead_in_Copyright_Information); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.HddvdCopyrightInformation, 0, _dev.Timeout, + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.HddvdCopyrightInformation, + 0, + _dev.Timeout, out _); if(!sense) @@ -747,27 +864,38 @@ partial class Dump } break; - #endregion HD DVD-ROM - #region All Blu-ray +#endregion HD DVD-ROM + +#region All Blu-ray + case MediaType.BDR: case MediaType.BDRE: case MediaType.BDROM: case MediaType.BDRXL: case MediaType.BDREXL: case MediaType.UHDBD: - _dumpLog.WriteLine("Reading Disc Information."); + _dumpLog.WriteLine(Localization.Core.Reading_Disc_Information); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.DiscInformation, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.DiscInformation, + 0, + _dev.Timeout, + out _); if(!sense) + { if(DI.Decode(cmdBuf).HasValue) { tmpBuf = new byte[cmdBuf.Length - 4]; Array.Copy(cmdBuf, 4, tmpBuf, 0, cmdBuf.Length - 4); mediaTags.Add(MediaTagType.BD_DI, tmpBuf); } + } // TODO: PAC /* @@ -781,18 +909,27 @@ partial class Dump mediaTags.Add(MediaTagType.PAC, tmpBuf); }*/ break; - #endregion All Blu-ray + +#endregion All Blu-ray } switch(dskType) { - #region BD-ROM only +#region BD-ROM only + case MediaType.BDROM: case MediaType.UHDBD: - _dumpLog.WriteLine("Reading Burst Cutting Area."); + _dumpLog.WriteLine(Localization.Core.Reading_Burst_Cutting_Area); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.BdBurstCuttingArea, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.BdBurstCuttingArea, + 0, + _dev.Timeout, + out _); if(!sense) { @@ -802,17 +939,26 @@ partial class Dump } break; - #endregion BD-ROM only - #region Writable Blu-ray only +#endregion BD-ROM only + +#region Writable Blu-ray only + case MediaType.BDR: case MediaType.BDRE: case MediaType.BDRXL: case MediaType.BDREXL: - _dumpLog.WriteLine("Reading Disc Definition Structure."); + _dumpLog.WriteLine(Localization.Core.Reading_Disc_Definition_Structure); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.BdDds, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.BdDds, + 0, + _dev.Timeout, + out _); if(!sense) { @@ -821,10 +967,17 @@ partial class Dump mediaTags.Add(MediaTagType.BD_DDS, tmpBuf); } - _dumpLog.WriteLine("Reading Spare Area Information."); + _dumpLog.WriteLine(Localization.Core.Reading_Spare_Area_Information); - sense = _dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.BdSpareAreaInformation, 0, _dev.Timeout, out _); + sense = _dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.BdSpareAreaInformation, + 0, + _dev.Timeout, + out _); if(!sense) { @@ -834,7 +987,8 @@ partial class Dump } break; - #endregion Writable Blu-ray only + +#endregion Writable Blu-ray only } if(isXbox) @@ -848,36 +1002,35 @@ partial class Dump } // TODO: Move somewhere else - internal static void AddMediaTagToSidecar(string outputPath, MediaTagType tagType, byte[] tag, - ref CICMMetadataType sidecar) + internal static void AddMediaTagToSidecar(string outputPath, MediaTagType tagType, byte[] tag, ref Metadata sidecar) { switch(tagType) { case MediaTagType.DVD_PFI: - sidecar.OpticalDisc[0].PFI = new DumpType + sidecar.OpticalDiscs[0].Pfi = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.DVD_DMI: - sidecar.OpticalDisc[0].DMI = new DumpType + sidecar.OpticalDiscs[0].Dmi = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.DVD_CMI: case MediaTagType.HDDVD_CPI: - sidecar.OpticalDisc[0].CMI = new DumpType + sidecar.OpticalDiscs[0].Cmi = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; var tmp = new byte[tag.Length + 4]; @@ -887,194 +1040,193 @@ partial class Dump CSS_CPRM.LeadInCopyright? cpy = CSS_CPRM.DecodeLeadInCopyright(tmp); - if(cpy.HasValue && - cpy.Value.CopyrightType != CopyrightType.NoProtection) - sidecar.OpticalDisc[0].CopyProtection = cpy.Value.CopyrightType.ToString(); + if(cpy.HasValue && cpy.Value.CopyrightType != CopyrightType.NoProtection) + sidecar.OpticalDiscs[0].CopyProtection = cpy.Value.CopyrightType.ToString(); break; case MediaTagType.DVD_BCA: case MediaTagType.BD_BCA: - sidecar.OpticalDisc[0].BCA = new DumpType + sidecar.OpticalDiscs[0].Bca = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.BD_DDS: case MediaTagType.DVDRAM_DDS: - sidecar.OpticalDisc[0].DDS = new DumpType + sidecar.OpticalDiscs[0].Dds = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.DVDRAM_SpareArea: case MediaTagType.BD_SpareArea: - sidecar.OpticalDisc[0].SAI = new DumpType + sidecar.OpticalDiscs[0].Sai = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.DVDR_PreRecordedInfo: - sidecar.OpticalDisc[0].PRI = new DumpType + sidecar.OpticalDiscs[0].Pri = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.DVD_MediaIdentifier: - sidecar.OpticalDisc[0].MediaID = new DumpType + sidecar.OpticalDiscs[0].MediaID = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.DVDR_PFI: - sidecar.OpticalDisc[0].PFIR = new DumpType + sidecar.OpticalDiscs[0].Pfir = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.DVD_ADIP: - sidecar.OpticalDisc[0].ADIP = new DumpType + sidecar.OpticalDiscs[0].Adip = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.DCB: - sidecar.OpticalDisc[0].DCB = new DumpType + sidecar.OpticalDiscs[0].Dcb = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.BD_DI: - sidecar.OpticalDisc[0].DI = new DumpType + sidecar.OpticalDiscs[0].Di = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.Xbox_SecuritySector: - sidecar.OpticalDisc[0].Xbox ??= new XboxType(); + sidecar.OpticalDiscs[0].Xbox ??= new Xbox(); - sidecar.OpticalDisc[0].Xbox.SecuritySectors = new[] - { - new XboxSecuritySectorsType + sidecar.OpticalDiscs[0].Xbox.SecuritySectors = + [ + new XboxSecuritySector { RequestNumber = 0, RequestVersion = 1, - SecuritySectors = new DumpType + SecuritySectors = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) } } - }; + ]; break; case MediaTagType.Xbox_PFI: - sidecar.OpticalDisc[0].Xbox ??= new XboxType(); + sidecar.OpticalDiscs[0].Xbox ??= new Xbox(); - sidecar.OpticalDisc[0].Xbox.PFI = new DumpType + sidecar.OpticalDiscs[0].Xbox.Pfi = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.Xbox_DMI: - sidecar.OpticalDisc[0].Xbox ??= new XboxType(); + sidecar.OpticalDiscs[0].Xbox ??= new Xbox(); - sidecar.OpticalDisc[0].Xbox.DMI = new DumpType + sidecar.OpticalDiscs[0].Xbox.Dmi = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.CD_FullTOC: - sidecar.OpticalDisc[0].TOC = new DumpType + sidecar.OpticalDiscs[0].Toc = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.CD_ATIP: - sidecar.OpticalDisc[0].ATIP = new DumpType + sidecar.OpticalDiscs[0].Atip = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.CD_PMA: - sidecar.OpticalDisc[0].PMA = new DumpType + sidecar.OpticalDiscs[0].Pma = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.CD_TEXT: - sidecar.OpticalDisc[0].LeadInCdText = new DumpType + sidecar.OpticalDiscs[0].LeadInCdText = new CommonTypes.AaruMetadata.Dump { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) }; break; case MediaTagType.CD_FirstTrackPregap: - sidecar.OpticalDisc[0].FirstTrackPregrap = new[] - { - new BorderType + sidecar.OpticalDiscs[0].FirstTrackPregrap = + [ + new Border { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) } - }; + ]; break; case MediaTagType.CD_LeadIn: - sidecar.OpticalDisc[0].LeadIn = new[] - { - new BorderType + sidecar.OpticalDiscs[0].LeadIn = + [ + new Border { Image = outputPath, Size = (ulong)tag.Length, - Checksums = Checksum.GetChecksums(tag).ToArray() + Checksums = Checksum.GetChecksums(tag) } - }; + ]; break; } diff --git a/Aaru.Core/Devices/Dumping/Metadata.cs b/Aaru.Core/Devices/Dumping/Metadata.cs index 1734b2019..fd7ed0b56 100644 --- a/Aaru.Core/Devices/Dumping/Metadata.cs +++ b/Aaru.Core/Devices/Dumping/Metadata.cs @@ -27,22 +27,22 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - -using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Xml.Serialization; +using System.Text.Json; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Metadata; -using Schemas; -using MediaType = Aaru.CommonTypes.MediaType; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; + +namespace Aaru.Core.Devices.Dumping; partial class Dump { @@ -55,18 +55,17 @@ partial class Dump /// Disc sessions /// Total time spent doing checksums /// Disc write offset - void WriteOpticalSidecar(uint blockSize, ulong blocks, MediaType mediaType, LayersType layers, + void WriteOpticalSidecar(uint blockSize, ulong blocks, MediaType mediaType, Layers layers, Dictionary mediaTags, int sessions, out double totalChkDuration, int? discOffset) { - _dumpLog.WriteLine("Creating sidecar."); - var filters = new FiltersList(); - IFilter filter = filters.GetFilter(_outputPath); + _dumpLog.WriteLine(Localization.Core.Creating_sidecar); + IFilter filter = PluginRegister.Singleton.GetFilter(_outputPath); totalChkDuration = 0; if(ImageFormat.Detect(filter) is not IMediaImage inputPlugin) { - StoppingErrorMessage?.Invoke("Could not detect image format."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_detect_image_format); return; } @@ -75,12 +74,12 @@ partial class Dump if(opened != ErrorNumber.NoError) { - StoppingErrorMessage?.Invoke($"Error {opened} opening created image."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_0_opening_created_image, opened)); return; } - DateTime chkStart = DateTime.UtcNow; + _sidecarStopwatch.Restart(); // ReSharper disable once UseObjectOrCollectionInitializer _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); @@ -91,66 +90,79 @@ partial class Dump _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; - CICMMetadataType sidecar = _sidecarClass.Create(); - DateTime end = DateTime.UtcNow; + Metadata sidecar = _sidecarClass.Create(); + _sidecarStopwatch.Stop(); - if(_aborted) - return; + if(_aborted) return; - totalChkDuration = (end - chkStart).TotalMilliseconds; - _dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds); + totalChkDuration = _sidecarStopwatch.Elapsed.TotalMilliseconds; - _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); + _dumpLog.WriteLine(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); + + _dumpLog.WriteLine(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize()); if(_preSidecar != null) { - _preSidecar.OpticalDisc = sidecar.OpticalDisc; - sidecar = _preSidecar; + _preSidecar.OpticalDiscs = sidecar.OpticalDiscs; + sidecar = _preSidecar; } - List<(ulong start, string type)> filesystems = new(); + List<(ulong start, string type)> filesystems = []; - if(sidecar.OpticalDisc[0].Track != null) - filesystems.AddRange(from xmlTrack in sidecar.OpticalDisc[0].Track - where xmlTrack.FileSystemInformation != null - from partition in xmlTrack.FileSystemInformation where partition.FileSystems != null + if(sidecar.OpticalDiscs[0].Track != null) + { + filesystems.AddRange(from xmlTrack in sidecar.OpticalDiscs[0].Track + where xmlTrack.FileSystemInformation != null + from partition in xmlTrack.FileSystemInformation + where partition.FileSystems != null from fileSystem in partition.FileSystems select (partition.StartSector, fileSystem.Type)); - - if(filesystems.Count > 0) - foreach(var filesystem in filesystems.Select(o => new - { - o.start, - o.type - }).Distinct()) - _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start); - - sidecar.OpticalDisc[0].Dimensions = Dimensions.DimensionsFromMediaType(mediaType); - (string type, string subType) discType = CommonTypes.Metadata.MediaType.MediaTypeToString(mediaType); - sidecar.OpticalDisc[0].DiscType = discType.type; - sidecar.OpticalDisc[0].DiscSubType = discType.subType; - sidecar.OpticalDisc[0].DumpHardwareArray = _resume.Tries.ToArray(); - sidecar.OpticalDisc[0].Sessions = (uint)sessions; - sidecar.OpticalDisc[0].Layers = layers; - - if(discOffset.HasValue) - { - sidecar.OpticalDisc[0].Offset = (int)(discOffset / 4); - sidecar.OpticalDisc[0].OffsetSpecified = true; } + if(filesystems.Count > 0) + { + foreach(var filesystem in filesystems.Select(o => new + { + o.start, + o.type + }) + .Distinct()) + _dumpLog.WriteLine(Localization.Core.Found_filesystem_0_at_sector_1, filesystem.type, filesystem.start); + } + + sidecar.OpticalDiscs[0].Dimensions = Dimensions.FromMediaType(mediaType); + (string type, string subType) discType = CommonTypes.Metadata.MediaType.MediaTypeToString(mediaType); + sidecar.OpticalDiscs[0].DiscType = discType.type; + sidecar.OpticalDiscs[0].DiscSubType = discType.subType; + sidecar.OpticalDiscs[0].DumpHardware = _resume.Tries; + sidecar.OpticalDiscs[0].Sessions = (uint)sessions; + sidecar.OpticalDiscs[0].Layers = layers; + + if(discOffset.HasValue) sidecar.OpticalDiscs[0].Offset = (int)(discOffset / 4); + if(mediaTags != null) - foreach(KeyValuePair tag in mediaTags.Where(tag => _outputPlugin.SupportedMediaTags. - Contains(tag.Key))) + { + foreach(KeyValuePair tag in + mediaTags.Where(tag => _outputPlugin.SupportedMediaTags.Contains(tag.Key))) AddMediaTagToSidecar(_outputPath, tag.Key, tag.Value, ref sidecar); + } - UpdateStatus?.Invoke("Writing metadata sidecar"); + UpdateStatus?.Invoke(Localization.Core.Writing_metadata_sidecar); - var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); + var jsonFs = new FileStream(_outputPrefix + ".metadata.json", FileMode.Create); - var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); - xmlSer.Serialize(xmlFs, sidecar); - xmlFs.Close(); + JsonSerializer.Serialize(jsonFs, + new MetadataJson + { + AaruMetadata = sidecar + }, + typeof(MetadataJson), + MetadataJsonContext.Default); + + jsonFs.Close(); } } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/MiniDisc.cs b/Aaru.Core/Devices/Dumping/MiniDisc.cs index 018b1be1b..33154372d 100644 --- a/Aaru.Core/Devices/Dumping/MiniDisc.cs +++ b/Aaru.Core/Devices/Dumping/MiniDisc.cs @@ -27,34 +27,33 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable JoinDeclarationAndInitializer -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Xml.Serialization; +using System.Text.Json; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Metadata; -using Aaru.CommonTypes.Structs; using Aaru.Console; +using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.SCSI; using Aaru.Devices; -using Schemas; -using MediaType = Aaru.CommonTypes.MediaType; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Devices.Dumping; + /// Implements dumping MiniDisc Data devices partial class Dump { @@ -64,59 +63,54 @@ partial class Dump bool sense; byte scsiMediumType = 0; const ushort sbcProfile = 0x0001; - DateTime start; - DateTime end; - double totalDuration = 0; - double currentSpeed = 0; - double maxSpeed = double.MinValue; - double minSpeed = double.MaxValue; + double totalDuration = 0; + double currentSpeed = 0; + double maxSpeed = double.MinValue; + double minSpeed = double.MaxValue; byte[] readBuffer; Modes.DecodedMode? decMode = null; Dictionary mediaTags = new(); - byte[] cmdBuf; bool ret; if(_outputPlugin is not IWritableImage outputFormat) { - StoppingErrorMessage?.Invoke("Image is not writable, aborting..."); + StoppingErrorMessage?.Invoke(Localization.Core.Image_is_not_writable_aborting); return; } - _dumpLog.WriteLine("Initializing reader."); + _dumpLog.WriteLine(Localization.Core.Initializing_reader); var scsiReader = new Reader(_dev, _dev.Timeout, null, _errorLog); ulong blocks = scsiReader.GetDeviceBlocks(); uint blockSize = scsiReader.LogicalBlockSize; - _dumpLog.WriteLine("Requesting MODE SENSE (6)."); - UpdateStatus?.Invoke("Requesting MODE SENSE (6)."); + _dumpLog.WriteLine(Localization.Core.Requesting_MODE_SENSE_6); + UpdateStatus?.Invoke(Localization.Core.Requesting_MODE_SENSE_6); - sense = _dev.ModeSense6(out cmdBuf, out _, true, ScsiModeSensePageControl.Current, 0x3F, 5, out _); + sense = _dev.ModeSense6(out byte[] cmdBuf, out _, true, ScsiModeSensePageControl.Current, 0x3F, 5, out _); - if(!sense && - !_dev.Error && - Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue) + if(!sense && !_dev.Error && Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue) decMode = Modes.DecodeMode6(cmdBuf, _dev.ScsiType); - if(decMode.HasValue) - scsiMediumType = (byte)decMode.Value.Header.MediumType; + if(decMode.HasValue) scsiMediumType = (byte)(decMode?.Header.MediumType ?? default(MediumTypes)); if(blockSize != 2048) { - _dumpLog.WriteLine("MiniDisc albums, NetMD discs or user-written audio MiniDisc cannot be dumped."); + _dumpLog.WriteLine(Localization.Core + .MiniDisc_albums_NetMD_discs_or_user_written_audio_MiniDisc_cannot_be_dumped); - StoppingErrorMessage?. - Invoke("MiniDisc albums, NetMD discs or user-written audio MiniDisc cannot be dumped."); + StoppingErrorMessage?.Invoke(Localization.Core + .MiniDisc_albums_NetMD_discs_or_user_written_audio_MiniDisc_cannot_be_dumped); return; } - MediaType dskType = MediaType.MDData; + const MediaType dskType = MediaType.MDData; if(scsiReader.FindReadCommand()) { - _dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", scsiReader.ErrorMessage); - StoppingErrorMessage?.Invoke("Unable to read medium."); + _dumpLog.WriteLine(Localization.Core.ERROR_Cannot_find_correct_read_command_0, scsiReader.ErrorMessage); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_read_medium); return; } @@ -125,80 +119,66 @@ partial class Dump { blocks++; - ulong totalSize = blocks * blockSize; - - if(totalSize > 1099511627776) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1099511627776d:F3} TiB)"); - else if(totalSize > 1073741824) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1073741824d:F3} GiB)"); - else if(totalSize > 1048576) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1048576d:F3} MiB)"); - else if(totalSize > 1024) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1024d:F3} KiB)"); - else - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize} bytes)"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_has_0_blocks_of_1_bytes_each_for_a_total_of_2, + blocks, + blockSize, + ByteSize.FromBytes(blocks * blockSize).ToString("0.000"))); } // Check how many blocks to read, if error show and return // 64 works, gets maximum speed (150KiB/s), slow I know... if(scsiReader.GetBlocksToRead()) { - _dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", scsiReader.ErrorMessage); + _dumpLog.WriteLine(Localization.Core.ERROR_Cannot_get_blocks_to_read_0, scsiReader.ErrorMessage); StoppingErrorMessage?.Invoke(scsiReader.ErrorMessage); return; } uint blocksToRead = scsiReader.BlocksToRead; - uint logicalBlockSize = blockSize; uint physicalBlockSize = scsiReader.PhysicalBlockSize; if(blocks == 0) { - _dumpLog.WriteLine("ERROR: Unable to read medium or empty medium present..."); - StoppingErrorMessage?.Invoke("Unable to read medium or empty medium present..."); + _dumpLog.WriteLine(Localization.Core.ERROR_Unable_to_read_medium_or_empty_medium_present); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_read_medium_or_empty_medium_present); return; } - UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes)."); - UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time."); - UpdateStatus?.Invoke($"Device reports {blockSize} bytes per logical block."); - UpdateStatus?.Invoke($"Device reports {scsiReader.LongBlockSize} bytes per physical block."); - UpdateStatus?.Invoke($"SCSI device type: {_dev.ScsiType}."); - UpdateStatus?.Invoke($"SCSI medium type: {scsiMediumType}."); - UpdateStatus?.Invoke($"Media identified as {dskType}"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_blocks_1_bytes, + blocks, + blocks * blockSize)); - _dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize); - _dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead); - _dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize); - _dumpLog.WriteLine("Device reports {0} bytes per physical block.", scsiReader.LongBlockSize); - _dumpLog.WriteLine("SCSI device type: {0}.", _dev.ScsiType); - _dumpLog.WriteLine("SCSI medium type: {0}.", scsiMediumType); - _dumpLog.WriteLine("Media identified as {0}.", dskType); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize)); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_bytes_per_physical_block, + scsiReader.LongBlockSize)); + + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_device_type_0, _dev.ScsiType)); + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_medium_type_0, scsiMediumType)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_identified_as_0, dskType)); + + _dumpLog.WriteLine(Localization.Core.Device_reports_0_blocks_1_bytes, blocks, blocks * blockSize); + _dumpLog.WriteLine(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_bytes_per_physical_block, scsiReader.LongBlockSize); + _dumpLog.WriteLine(Localization.Core.SCSI_device_type_0, _dev.ScsiType); + _dumpLog.WriteLine(Localization.Core.SCSI_medium_type_0, scsiMediumType); + _dumpLog.WriteLine(Localization.Core.Media_identified_as_0, dskType); sense = _dev.MiniDiscGetType(out cmdBuf, out _, _dev.Timeout, out _); - if(!sense && - !_dev.Error) - mediaTags.Add(MediaTagType.MiniDiscType, cmdBuf); + if(!sense && !_dev.Error) mediaTags.Add(MediaTagType.MiniDiscType, cmdBuf); sense = _dev.MiniDiscD5(out cmdBuf, out _, _dev.Timeout, out _); - if(!sense && - !_dev.Error) - mediaTags.Add(MediaTagType.MiniDiscD5, cmdBuf); + if(!sense && !_dev.Error) mediaTags.Add(MediaTagType.MiniDiscD5, cmdBuf); sense = _dev.MiniDiscReadDataTOC(out cmdBuf, out _, _dev.Timeout, out _); - if(!sense && - !_dev.Error) - mediaTags.Add(MediaTagType.MiniDiscDTOC, cmdBuf); + if(!sense && !_dev.Error) mediaTags.Add(MediaTagType.MiniDiscDTOC, cmdBuf); var utocMs = new MemoryStream(); @@ -206,60 +186,66 @@ partial class Dump { sense = _dev.MiniDiscReadUserTOC(out cmdBuf, out _, i, _dev.Timeout, out _); - if(sense || _dev.Error) - break; + if(sense || _dev.Error) break; utocMs.Write(cmdBuf, 0, 2336); } - if(utocMs.Length > 0) - mediaTags.Add(MediaTagType.MiniDiscUTOC, utocMs.ToArray()); + if(utocMs.Length > 0) mediaTags.Add(MediaTagType.MiniDiscUTOC, utocMs.ToArray()); ret = true; foreach(MediaTagType tag in mediaTags.Keys.Where(tag => !outputFormat.SupportedMediaTags.Contains(tag))) { ret = false; - _dumpLog.WriteLine($"Output format does not support {tag}."); - ErrorMessage?.Invoke($"Output format does not support {tag}."); + _dumpLog.WriteLine(string.Format(Localization.Core.Output_format_does_not_support_0, tag)); + ErrorMessage?.Invoke(string.Format(Localization.Core.Output_format_does_not_support_0, tag)); } if(!ret) { if(_force) { - _dumpLog.WriteLine("Several media tags not supported, continuing..."); - ErrorMessage?.Invoke("Several media tags not supported, continuing..."); + _dumpLog.WriteLine(Localization.Core.Several_media_tags_not_supported_continuing); + ErrorMessage?.Invoke(Localization.Core.Several_media_tags_not_supported_continuing); } else { - _dumpLog.WriteLine("Several media tags not supported, not continuing..."); - StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Several_media_tags_not_supported_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Several_media_tags_not_supported_not_continuing); return; } } - UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time."); - _dumpLog.WriteLine("Reading {0} sectors at a time.", blocksToRead); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time, blocksToRead)); + _dumpLog.WriteLine(Localization.Core.Reading_0_sectors_at_a_time, blocksToRead); - var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private); - var ibgLog = new IbgLog(_outputPrefix + ".ibg", sbcProfile); + var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", + _dev, + blocks, + blockSize, + blocksToRead, + _private, + _dimensions); + + var ibgLog = new IbgLog(_outputPrefix + ".ibg", sbcProfile); ret = outputFormat.Create(_outputPath, dskType, _formatOptions, blocks, blockSize); // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputFormat.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputFormat.ErrorMessage); return; } - start = DateTime.UtcNow; + _dumpStopwatch.Restart(); double imageWriteDuration = 0; if(decMode?.Pages != null) @@ -267,72 +253,118 @@ partial class Dump var setGeometry = false; foreach(Modes.ModePage page in decMode.Value.Pages) - if(page.Page == 0x04 && - page.Subpage == 0x00) + { + switch(page.Page) { - Modes.ModePage_04? rigidPage = Modes.DecodeModePage_04(page.PageResponse); + case 0x04 when page.Subpage == 0x00: + { + Modes.ModePage_04? rigidPage = Modes.DecodeModePage_04(page.PageResponse); - if(!rigidPage.HasValue || setGeometry) - continue; + if(!rigidPage.HasValue || setGeometry) continue; - _dumpLog.WriteLine("Setting geometry to {0} cylinders, {1} heads, {2} sectors per track", - rigidPage.Value.Cylinders, rigidPage.Value.Heads, - (uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))); + _dumpLog.WriteLine(Localization.Core + .Setting_geometry_to_0_cylinders_1_heads_2_sectors_per_track, + rigidPage.Value.Cylinders, + rigidPage.Value.Heads, + (uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))); - UpdateStatus?. - Invoke($"Setting geometry to {rigidPage.Value.Cylinders} cylinders, {rigidPage.Value.Heads} heads, {(uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))} sectors per track"); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Setting_geometry_to_0_cylinders_1_heads_2_sectors_per_track, + rigidPage.Value.Cylinders, + rigidPage.Value.Heads, + (uint)(blocks / + (rigidPage.Value.Cylinders * + rigidPage.Value.Heads)))); - outputFormat.SetGeometry(rigidPage.Value.Cylinders, rigidPage.Value.Heads, - (uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))); + outputFormat.SetGeometry(rigidPage.Value.Cylinders, + rigidPage.Value.Heads, + (uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))); - setGeometry = true; - } - else if(page.Page == 0x05 && - page.Subpage == 0x00) - { - Modes.ModePage_05? flexiblePage = Modes.DecodeModePage_05(page.PageResponse); - - if(!flexiblePage.HasValue) - continue; - - _dumpLog.WriteLine("Setting geometry to {0} cylinders, {1} heads, {2} sectors per track", - flexiblePage.Value.Cylinders, flexiblePage.Value.Heads, - flexiblePage.Value.SectorsPerTrack); - - UpdateStatus?. - Invoke($"Setting geometry to {flexiblePage.Value.Cylinders} cylinders, {flexiblePage.Value.Heads} heads, {flexiblePage.Value.SectorsPerTrack} sectors per track"); - - outputFormat.SetGeometry(flexiblePage.Value.Cylinders, flexiblePage.Value.Heads, - flexiblePage.Value.SectorsPerTrack); - - setGeometry = true; + setGeometry = true; + + break; + } + case 0x05 when page.Subpage == 0x00: + { + Modes.ModePage_05? flexiblePage = Modes.DecodeModePage_05(page.PageResponse); + + if(!flexiblePage.HasValue) continue; + + _dumpLog.WriteLine(Localization.Core + .Setting_geometry_to_0_cylinders_1_heads_2_sectors_per_track, + flexiblePage.Value.Cylinders, + flexiblePage.Value.Heads, + flexiblePage.Value.SectorsPerTrack); + + UpdateStatus?.Invoke(string.Format(Localization.Core + .Setting_geometry_to_0_cylinders_1_heads_2_sectors_per_track, + flexiblePage.Value.Cylinders, + flexiblePage.Value.Heads, + flexiblePage.Value.SectorsPerTrack)); + + outputFormat.SetGeometry(flexiblePage.Value.Cylinders, + flexiblePage.Value.Heads, + flexiblePage.Value.SectorsPerTrack); + + setGeometry = true; + + break; + } } + } } - DumpHardwareType currentTry = null; - ExtentsULong extents = null; + DumpHardware currentTry = null; + ExtentsULong extents = null; - ResumeSupport.Process(true, _dev.IsRemovable, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial, - _dev.PlatformId, ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision, - _private, _force); + ResumeSupport.Process(true, + _dev.IsRemovable, + blocks, + _dev.Manufacturer, + _dev.Model, + _dev.Serial, + _dev.PlatformId, + ref _resume, + ref currentTry, + ref extents, + _dev.FirmwareRevision, + _private, + _force); - if(currentTry == null || - extents == null) + if(currentTry == null || extents == null) { - StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_process_resume_file_not_continuing); return; } if(_resume.NextBlock > 0) { - UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}."); - _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); + UpdateStatus?.Invoke(string.Format(Localization.Core.Resuming_from_block_0, _resume.NextBlock)); + _dumpLog.WriteLine(Localization.Core.Resuming_from_block_0, _resume.NextBlock); } - var newTrim = false; - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + if(_createGraph) + { + Spiral.DiscParameters discSpiralParameters = Spiral.DiscParametersFromMediaType(dskType); + + if(discSpiralParameters is not null) + _mediaGraph = new Spiral((int)_dimensions, (int)_dimensions, discSpiralParameters, blocks); + else + _mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, blocks); + + if(_mediaGraph is not null) + { + foreach(Tuple e in extents.ToArray()) + _mediaGraph?.PaintSectorsGood(e.Item1, (uint)(e.Item2 - e.Item1 + 2)); + } + + _mediaGraph?.PaintSectorsBad(_resume.BadBlocks); + } + + var newTrim = false; + _speedStopwatch.Reset(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead) @@ -340,113 +372,132 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(blocks - i < blocksToRead) - blocksToRead = (uint)(blocks - i); + if(blocks - i < blocksToRead) blocksToRead = (uint)(blocks - i); - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)blocks); - sense = _dev.Read6(out readBuffer, out _, (uint)i, blockSize, (byte)blocksToRead, _dev.Timeout, + _speedStopwatch.Start(); + + sense = _dev.Read6(out readBuffer, + out _, + (uint)i, + blockSize, + (byte)blocksToRead, + _dev.Timeout, out double cmdDuration); + _speedStopwatch.Stop(); + totalDuration += cmdDuration; - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, cmdDuration, blocksToRead); ibgLog.Write(i, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(readBuffer, i, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(i, blocksToRead, true); + _mediaGraph?.PaintSectorsGood(i, blocksToRead); } else { // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly - if(i + _skip > blocks) - _skip = (uint)(blocks - i); + if(i + _skip > blocks) _skip = (uint)(blocks - i); // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; - for(ulong b = i; b < i + _skip; b++) - _resume.BadBlocks.Add(b); + for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b); - mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); + mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip); ibgLog.Write(i, 0); - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i); i += _skip - blocksToRead; newTrim = true; } + _writeStopwatch.Stop(); sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } + _speedStopwatch.Stop(); _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); - end = DateTime.UtcNow; + _dumpStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), _devicePath); + ibgLog.Close(_dev, + blocks, + blockSize, + _dumpStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), + _devicePath); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - #region Trimming - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _trim && - newTrim) +#region Trimming + + if(_resume.BadBlocks.Count > 0 && !_aborted && _trim && newTrim) { - start = DateTime.UtcNow; - UpdateStatus?.Invoke("Trimming skipped sectors"); - _dumpLog.WriteLine("Trimming skipped sectors"); + _trimStopwatch.Restart(); + UpdateStatus?.Invoke(Localization.Core.Trimming_skipped_sectors); + _dumpLog.WriteLine(Localization.Core.Trimming_skipped_sectors); ulong[] tmpArray = _resume.BadBlocks.ToArray(); InitProgress?.Invoke(); @@ -456,35 +507,39 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke($"Trimming sector {badSector}"); + PulseProgress?.Invoke(string.Format(Localization.Core.Trimming_sector_0, badSector)); sense = _dev.Read6(out readBuffer, out _, (uint)badSector, blockSize, 1, _dev.Timeout, out double _); - if(sense || _dev.Error) - continue; + if(sense || _dev.Error) continue; _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(readBuffer, badSector); + _mediaGraph?.PaintSectorGood(badSector); } EndProgress?.Invoke(); - end = DateTime.UtcNow; - UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds."); - _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds); - } - #endregion Trimming + _trimStopwatch.Stop(); - #region Error handling - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _retryPasses > 0) + UpdateStatus?.Invoke(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + } + +#endregion Trimming + +#region Error handling + + if(_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0) { var pass = 1; var forward = true; @@ -497,17 +552,24 @@ partial class Dump { Modes.ModePage_01 pg; - sense = _dev.ModeSense6(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01, - _dev.Timeout, out _); + sense = _dev.ModeSense6(out readBuffer, + out _, + false, + ScsiModeSensePageControl.Current, + 0x01, + _dev.Timeout, + out _); if(!sense) { Modes.DecodedMode? dcMode6 = Modes.DecodeMode6(readBuffer, _dev.ScsiType); if(dcMode6?.Pages != null) + { foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage => - modePage.Page == 0x01 && modePage.Subpage == 0x00)) + modePage is { Page: 0x01, Subpage: 0x00 })) currentModePage = modePage; + } } if(currentModePage == null) @@ -551,31 +613,32 @@ partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { + Pages = + [ new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01(pg) } - } + ] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); - UpdateStatus?.Invoke("Sending MODE SELECT to drive (return damaged blocks)."); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks)."); + UpdateStatus?.Invoke(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); sense = _dev.ModeSelect(md6, out byte[] senseBuf, true, false, _dev.Timeout, out _); if(sense) { - UpdateStatus?. - Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + UpdateStatus?.Invoke(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); - AaruConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(Localization.Core.Error_0, Sense.PrettifySense(senseBuf)); - _dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + _dumpLog.WriteLine(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); } else runningPersistent = true; @@ -590,44 +653,68 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass, - forward ? "forward" : "reverse", - runningPersistent ? "recovering partial data, " : "")); + if(forward) + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_forward, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_forward, + badSector, + pass)); + } + else + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_reverse, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_reverse, + badSector, + pass)); + } - sense = _dev.Read6(out readBuffer, out _, (uint)badSector, blockSize, 1, _dev.Timeout, + sense = _dev.Read6(out readBuffer, + out _, + (uint)badSector, + blockSize, + 1, + _dev.Timeout, out double cmdDuration); totalDuration += cmdDuration; - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(readBuffer, badSector); - UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}."); - _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); + _mediaGraph?.PaintSectorGood(badSector); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_block_0_in_pass_1, + badSector, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_block_0_in_pass_1, badSector, pass); } - else if(runningPersistent) - outputFormat.WriteSector(readBuffer, badSector); + else if(runningPersistent) outputFormat.WriteSector(readBuffer, badSector); } - if(pass < _retryPasses && - !_aborted && - _resume.BadBlocks.Count > 0) + if(pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); - if(!forward) - _resume.BadBlocks.Reverse(); + if(!forward) _resume.BadBlocks.Reverse(); goto repeatRetry; } @@ -637,57 +724,60 @@ partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { - currentModePage.Value - } + Pages = [currentModePage.Value] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); - UpdateStatus?.Invoke("Sending MODE SELECT to drive (return device to previous status)."); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status)."); + UpdateStatus?.Invoke(Localization.Core.Sending_MODE_SELECT_to_drive_return_device_to_previous_status); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_device_to_previous_status); _dev.ModeSelect(md6, out _, true, false, _dev.Timeout, out _); } EndProgress?.Invoke(); } - #endregion Error handling + +#endregion Error handling _resume.BadBlocks.Sort(); - foreach(ulong bad in _resume.BadBlocks) - _dumpLog.WriteLine("Sector {0} could not be read.", bad); + foreach(ulong bad in _resume.BadBlocks) _dumpLog.WriteLine(Localization.Core.Sector_0_could_not_be_read, bad); currentTry.Extents = ExtentsConverter.ToMetadata(extents); outputFormat.SetDumpHardware(_resume.Tries); - var metadata = new ImageInfo + var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; - if(!outputFormat.SetMetadata(metadata)) - ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + + if(!outputFormat.SetImageInfo(metadata)) + { + ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + + Environment.NewLine + outputFormat.ErrorMessage); + } - if(_preSidecar != null) - outputFormat.SetCicmMetadata(_preSidecar); + if(_preSidecar != null) outputFormat.SetMetadata(_preSidecar); - _dumpLog.WriteLine("Closing output file."); - UpdateStatus?.Invoke("Closing output file."); - DateTime closeStart = DateTime.Now; + _dumpLog.WriteLine(Localization.Core.Closing_output_file); + UpdateStatus?.Invoke(Localization.Core.Closing_output_file); + _imageCloseStopwatch.Restart(); outputFormat.Close(); - DateTime closeEnd = DateTime.Now; - UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); - _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); + _imageCloseStopwatch.Stop(); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); return; } @@ -696,21 +786,20 @@ partial class Dump if(_metadata) { - UpdateStatus?.Invoke("Creating sidecar."); - _dumpLog.WriteLine("Creating sidecar."); - var filters = new FiltersList(); - IFilter filter = filters.GetFilter(_outputPath); + UpdateStatus?.Invoke(Localization.Core.Creating_sidecar); + _dumpLog.WriteLine(Localization.Core.Creating_sidecar); + IFilter filter = PluginRegister.Singleton.GetFilter(_outputPath); var inputPlugin = ImageFormat.Detect(filter) as IMediaImage; ErrorNumber opened = inputPlugin.Open(filter); if(opened != ErrorNumber.NoError) { - StoppingErrorMessage?.Invoke($"Error {opened} opening created image."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_0_opening_created_image, opened)); return; } - DateTime chkStart = DateTime.UtcNow; + _sidecarStopwatch.Restart(); _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); _sidecarClass.InitProgressEvent += InitProgress; _sidecarClass.UpdateProgressEvent += UpdateProgress; @@ -719,102 +808,137 @@ partial class Dump _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; - CICMMetadataType sidecar = _sidecarClass.Create(); - end = DateTime.UtcNow; + Metadata sidecar = _sidecarClass.Create(); + _sidecarStopwatch.Stop(); if(!_aborted) { - totalChkDuration = (end - chkStart).TotalMilliseconds; - UpdateStatus?.Invoke($"Sidecar created in {(end - chkStart).TotalSeconds} seconds."); + totalChkDuration = _sidecarStopwatch.Elapsed.TotalMilliseconds; - UpdateStatus?. - Invoke($"Average checksum speed {blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); + _dumpLog.WriteLine(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); + + _dumpLog.WriteLine(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize()); if(_preSidecar != null) { - _preSidecar.BlockMedia = sidecar.BlockMedia; - sidecar = _preSidecar; + _preSidecar.BlockMedias = sidecar.BlockMedias; + sidecar = _preSidecar; } - List<(ulong start, string type)> filesystems = new(); + List<(ulong start, string type)> filesystems = []; - if(sidecar.BlockMedia[0].FileSystemInformation != null) - filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation - where partition.FileSystems != null from fileSystem in partition.FileSystems + if(sidecar.BlockMedias[0].FileSystemInformation != null) + { + filesystems.AddRange(from partition in sidecar.BlockMedias[0].FileSystemInformation + where partition.FileSystems != null + from fileSystem in partition.FileSystems select (partition.StartSector, fileSystem.Type)); + } if(filesystems.Count > 0) + { foreach(var filesystem in filesystems.Select(o => new - { - o.start, - o.type - }).Distinct()) + { + o.start, + o.type + }) + .Distinct()) { - UpdateStatus?.Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}"); - _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start); + UpdateStatus?.Invoke(string.Format(Localization.Core.Found_filesystem_0_at_sector_1, + filesystem.type, + filesystem.start)); + + _dumpLog.WriteLine(Localization.Core.Found_filesystem_0_at_sector_1, + filesystem.type, + filesystem.start); } + } - sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(dskType); + sidecar.BlockMedias[0].Dimensions = Dimensions.FromMediaType(dskType); (string type, string subType) xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType); - sidecar.BlockMedia[0].DiskType = xmlType.type; - sidecar.BlockMedia[0].DiskSubType = xmlType.subType; + sidecar.BlockMedias[0].MediaType = xmlType.type; + sidecar.BlockMedias[0].MediaSubType = xmlType.subType; - if(!_dev.IsRemovable || - _dev.IsUsb) + if(!_dev.IsRemovable || _dev.IsUsb) + { if(_dev.Type == DeviceType.ATAPI) - sidecar.BlockMedia[0].Interface = "ATAPI"; + sidecar.BlockMedias[0].Interface = "ATAPI"; else if(_dev.IsUsb) - sidecar.BlockMedia[0].Interface = "USB"; + sidecar.BlockMedias[0].Interface = "USB"; else if(_dev.IsFireWire) - sidecar.BlockMedia[0].Interface = "FireWire"; + sidecar.BlockMedias[0].Interface = "FireWire"; else - sidecar.BlockMedia[0].Interface = "SCSI"; + sidecar.BlockMedias[0].Interface = "SCSI"; + } - sidecar.BlockMedia[0].LogicalBlocks = blocks; - sidecar.BlockMedia[0].PhysicalBlockSize = physicalBlockSize; - sidecar.BlockMedia[0].LogicalBlockSize = logicalBlockSize; - sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer; - sidecar.BlockMedia[0].Model = _dev.Model; + sidecar.BlockMedias[0].LogicalBlocks = blocks; + sidecar.BlockMedias[0].PhysicalBlockSize = physicalBlockSize; + sidecar.BlockMedias[0].LogicalBlockSize = blockSize; + sidecar.BlockMedias[0].Manufacturer = _dev.Manufacturer; + sidecar.BlockMedias[0].Model = _dev.Model; - if(!_private) - sidecar.BlockMedia[0].Serial = _dev.Serial; + if(!_private) sidecar.BlockMedias[0].Serial = _dev.Serial; - sidecar.BlockMedia[0].Size = blocks * blockSize; + sidecar.BlockMedias[0].Size = blocks * blockSize; - if(_dev.IsRemovable) - sidecar.BlockMedia[0].DumpHardwareArray = _resume.Tries.ToArray(); + if(_dev.IsRemovable) sidecar.BlockMedias[0].DumpHardware = _resume.Tries; - UpdateStatus?.Invoke("Writing metadata sidecar"); + UpdateStatus?.Invoke(Localization.Core.Writing_metadata_sidecar); - var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); + var jsonFs = new FileStream(_outputPrefix + ".metadata.json", FileMode.Create); - var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); - xmlSer.Serialize(xmlFs, sidecar); - xmlFs.Close(); + JsonSerializer.Serialize(jsonFs, + new MetadataJson + { + AaruMetadata = sidecar + }, + typeof(MetadataJson), + MetadataJsonContext.Default); + + jsonFs.Close(); } } UpdateStatus?.Invoke(""); - UpdateStatus?. - Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second), + totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second), + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average speed: {blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); if(maxSpeed > 0) - UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0, + ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize())); + } - if(minSpeed > 0 && - minSpeed < double.MaxValue) - UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); + if(minSpeed is > 0 and < double.MaxValue) + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0, + ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize())); + } - UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); + UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_could_not_be_read, _resume.BadBlocks.Count)); UpdateStatus?.Invoke(""); Statistics.AddMedia(dskType, true); diff --git a/Aaru.Core/Devices/Dumping/NVMe.cs b/Aaru.Core/Devices/Dumping/NVMe.cs index 614c881f7..b9d5374bf 100644 --- a/Aaru.Core/Devices/Dumping/NVMe.cs +++ b/Aaru.Core/Devices/Dumping/NVMe.cs @@ -27,7 +27,7 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable InconsistentNaming @@ -37,5 +37,5 @@ namespace Aaru.Core.Devices.Dumping; public partial class Dump { /// Dumps an NVMe device - public void NVMe() => StoppingErrorMessage?.Invoke("NVMe devices not yet supported."); + public void NVMe() => StoppingErrorMessage?.Invoke(Localization.Core.NVMe_devices_not_yet_supported); } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs b/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs index c562bac9d..d93d644d1 100644 --- a/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs +++ b/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs @@ -28,31 +28,32 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Xml.Serialization; +using System.Text.Json; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Metadata; -using Aaru.CommonTypes.Structs; using Aaru.Console; +using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.SCSI; using Aaru.Devices; -using Schemas; -using MediaType = Aaru.CommonTypes.MediaType; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Devices.Dumping; + public partial class Dump { [SuppressMessage("ReSharper", "JoinDeclarationAndInitializer")] @@ -65,15 +66,13 @@ public partial class Dump double maxSpeed = double.MinValue; double minSpeed = double.MaxValue; uint blocksToRead = 64; - DateTime start; - DateTime end; MediaType dskType; bool sense; byte[] senseBuf; if(_outputPlugin is not IWritableImage outputFormat) { - StoppingErrorMessage?.Invoke("Image is not writable, aborting..."); + StoppingErrorMessage?.Invoke(Localization.Core.Image_is_not_writable_aborting); return; } @@ -82,8 +81,8 @@ public partial class Dump if(sense) { - _dumpLog.WriteLine("Could not detect capacity..."); - StoppingErrorMessage?.Invoke("Could not detect capacity..."); + _dumpLog.WriteLine(Localization.Core.Could_not_detect_capacity); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_detect_capacity); return; } @@ -92,93 +91,117 @@ public partial class Dump blocks++; - ulong totalSize = blocks * (ulong)blockSize; - - if(totalSize > 1099511627776) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1099511627776d:F3} TiB)"); - else if(totalSize > 1073741824) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1073741824d:F3} GiB)"); - else if(totalSize > 1048576) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1048576d:F3} MiB)"); - else if(totalSize > 1024) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1024d:F3} KiB)"); - else - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize} bytes)"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_has_0_blocks_of_1_bytes_each_for_a_total_of_2, + blocks, + blockSize, + ByteSize.FromBytes(blocks * blockSize).ToString("0.000"))); if(blocks == 0) { - _dumpLog.WriteLine("ERROR: Unable to read medium or empty medium present..."); - StoppingErrorMessage?.Invoke("Unable to read medium or empty medium present..."); + _dumpLog.WriteLine(Localization.Core.ERROR_Unable_to_read_medium_or_empty_medium_present); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_read_medium_or_empty_medium_present); return; } - UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes)."); - UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time."); - UpdateStatus?.Invoke($"Device reports {blockSize} bytes per logical block."); - UpdateStatus?.Invoke($"SCSI device type: {_dev.ScsiType}."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_blocks_1_bytes, + blocks, + blocks * blockSize)); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize)); + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_device_type_0, _dev.ScsiType)); if(blocks > 262144) { dskType = MediaType.MemoryStickProDuo; - _dumpLog.WriteLine("Media detected as MemoryStick Pro Duo..."); - UpdateStatus?.Invoke("Media detected as MemoryStick Pro Duo..."); + _dumpLog.WriteLine(Localization.Core.Media_detected_as_MemoryStick_Pro_Duo); + UpdateStatus?.Invoke(Localization.Core.Media_detected_as_MemoryStick_Pro_Duo); } else { dskType = MediaType.MemoryStickDuo; - _dumpLog.WriteLine("Media detected as MemoryStick Duo..."); - UpdateStatus?.Invoke("Media detected as MemoryStick Duo..."); + _dumpLog.WriteLine(Localization.Core.Media_detected_as_MemoryStick_Duo); + UpdateStatus?.Invoke(Localization.Core.Media_detected_as_MemoryStick_Duo); } bool ret; - var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private); - var ibgLog = new IbgLog(_outputPrefix + ".ibg", sbcProfile); + var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", + _dev, + blocks, + blockSize, + blocksToRead, + _private, + _dimensions); + + var ibgLog = new IbgLog(_outputPrefix + ".ibg", sbcProfile); ret = outputFormat.Create(_outputPath, dskType, _formatOptions, blocks, blockSize); // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputFormat.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputFormat.ErrorMessage); return; } - start = DateTime.UtcNow; + _dumpStopwatch.Restart(); double imageWriteDuration = 0; - DumpHardwareType currentTry = null; - ExtentsULong extents = null; + DumpHardware currentTry = null; + ExtentsULong extents = null; - ResumeSupport.Process(true, _dev.IsRemovable, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial, - _dev.PlatformId, ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision, - _private, _force); + ResumeSupport.Process(true, + _dev.IsRemovable, + blocks, + _dev.Manufacturer, + _dev.Model, + _dev.Serial, + _dev.PlatformId, + ref _resume, + ref currentTry, + ref extents, + _dev.FirmwareRevision, + _private, + _force); - if(currentTry == null || - extents == null) + if(currentTry == null || extents == null) { - StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_process_resume_file_not_continuing); return; } - if(_resume.NextBlock > 0) - _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); + if(_resume.NextBlock > 0) _dumpLog.WriteLine(Localization.Core.Resuming_from_block_0, _resume.NextBlock); + + if(_createGraph) + { + Spiral.DiscParameters discSpiralParameters = Spiral.DiscParametersFromMediaType(dskType); + + if(discSpiralParameters is not null) + _mediaGraph = new Spiral((int)_dimensions, (int)_dimensions, discSpiralParameters, blocks); + else + _mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, blocks); + + if(_mediaGraph is not null) + { + foreach(Tuple e in extents.ToArray()) + _mediaGraph?.PaintSectorsGood(e.Item1, (uint)(e.Item2 - e.Item1 + 2)); + } + + _mediaGraph?.PaintSectorsBad(_resume.BadBlocks); + } var newTrim = false; - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _speedStopwatch.Restart(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead) @@ -186,114 +209,141 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(blocks - i < blocksToRead) - blocksToRead = (uint)(blocks - i); + if(blocks - i < blocksToRead) blocksToRead = (uint)(blocks - i); - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, blocks); + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, + blocks); - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0, - blocksToRead, false, _dev.Timeout, out double cmdDuration); + _speedStopwatch.Start(); + + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)i, + blockSize, + 0, + blocksToRead, + false, + _dev.Timeout, + out double cmdDuration); + + _speedStopwatch.Stop(); totalDuration += cmdDuration; - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, cmdDuration, blocksToRead); ibgLog.Write(i, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(readBuffer, i, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(i, blocksToRead, true); + _mediaGraph?.PaintSectorsGood(i, blocksToRead); } else { _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly - if(i + _skip > blocks) - _skip = (uint)(blocks - i); + if(i + _skip > blocks) _skip = (uint)(blocks - i); // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; - for(ulong b = i; b < i + _skip; b++) - _resume.BadBlocks.Add(b); + for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b); - mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); + mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip); ibgLog.Write(i, 0); - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i); i += _skip - blocksToRead; newTrim = true; } + _writeStopwatch.Stop(); sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } + _speedStopwatch.Stop(); _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); - end = DateTime.UtcNow; + _dumpStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), _devicePath); + ibgLog.Close(_dev, + blocks, + blockSize, + _dumpStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), + _devicePath); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - #region Trimming - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _trim && - newTrim) +#region Trimming + + if(_resume.BadBlocks.Count > 0 && !_aborted && _trim && newTrim) { - start = DateTime.UtcNow; - UpdateStatus?.Invoke("Trimming skipped sectors"); - _dumpLog.WriteLine("Trimming skipped sectors"); + _trimStopwatch.Restart(); + UpdateStatus?.Invoke(Localization.Core.Trimming_skipped_sectors); + _dumpLog.WriteLine(Localization.Core.Trimming_skipped_sectors); ulong[] tmpArray = _resume.BadBlocks.ToArray(); InitProgress?.Invoke(); @@ -303,16 +353,28 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke($"Trimming sector {badSector}"); + PulseProgress?.Invoke(string.Format(Localization.Core.Trimming_sector_0, badSector)); - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)badSector, - blockSize, 0, 1, false, _dev.Timeout, out double _); + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)badSector, + blockSize, + 0, + 1, + false, + _dev.Timeout, + out double _); if(sense || _dev.Error) { @@ -324,18 +386,21 @@ public partial class Dump _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(readBuffer, badSector); + _mediaGraph?.PaintSectorGood(badSector); } EndProgress?.Invoke(); - end = DateTime.UtcNow; - _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds); - } - #endregion Trimming + _trimStopwatch.Stop(); - #region Error handling - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _retryPasses > 0) + _dumpLog.WriteLine(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + } + +#endregion Trimming + +#region Error handling + + if(_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0) { var pass = 1; var forward = true; @@ -348,32 +413,47 @@ public partial class Dump { Modes.ModePage_01 pg; - sense = _dev.ModeSense6(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01, - _dev.Timeout, out _); + sense = _dev.ModeSense6(out readBuffer, + out _, + false, + ScsiModeSensePageControl.Current, + 0x01, + _dev.Timeout, + out _); - if(sense) + Modes.DecodedMode? dcMode6 = null; + if(!sense) dcMode6 = Modes.DecodeMode6(readBuffer, _dev.ScsiType); + + if(sense || dcMode6 is null) { - sense = _dev.ModeSense10(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01, - _dev.Timeout, out _); + sense = _dev.ModeSense10(out readBuffer, + out _, + false, + ScsiModeSensePageControl.Current, + 0x01, + _dev.Timeout, + out _); if(!sense) { Modes.DecodedMode? dcMode10 = Modes.DecodeMode10(readBuffer, _dev.ScsiType); if(dcMode10.HasValue) + { foreach(Modes.ModePage modePage in dcMode10.Value.Pages.Where(modePage => - modePage.Page == 0x01 && modePage.Subpage == 0x00)) + modePage is { Page: 0x01, Subpage: 0x00 })) currentModePage = modePage; + } } } else { - Modes.DecodedMode? dcMode6 = Modes.DecodeMode6(readBuffer, _dev.ScsiType); - if(dcMode6.HasValue) + { foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage => - modePage.Page == 0x01 && modePage.Subpage == 0x00)) + modePage is { Page: 0x01, Subpage: 0x00 })) currentModePage = modePage; + } } if(currentModePage == null) @@ -417,31 +497,32 @@ public partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { + Pages = + [ new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01(pg) } - } + ] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); - UpdateStatus?.Invoke("Sending MODE SELECT to drive (return damaged blocks)."); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks)."); + UpdateStatus?.Invoke(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); sense = _dev.ModeSelect(md6, out senseBuf, true, false, _dev.Timeout, out _); if(sense) { - UpdateStatus?. - Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + UpdateStatus?.Invoke(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); - AaruConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(Localization.Core.Error_0, Sense.PrettifySense(senseBuf)); - _dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + _dumpLog.WriteLine(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); } else runningPersistent = true; @@ -456,46 +537,76 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - _dumpLog.WriteLine("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass, - forward ? "forward" : "reverse", - runningPersistent ? "recovering partial data, " : "")); + if(forward) + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_forward, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_forward, + badSector, + pass)); + } + else + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_reverse, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_reverse, + badSector, + pass)); + } - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)badSector, - blockSize, 0, 1, false, _dev.Timeout, out double cmdDuration); + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)badSector, + blockSize, + 0, + 1, + false, + _dev.Timeout, + out double cmdDuration); totalDuration += cmdDuration; - if(sense || _dev.Error) - _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); + if(sense || _dev.Error) _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(readBuffer, badSector); - UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}."); - _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); + _mediaGraph?.PaintSectorGood(badSector); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_block_0_in_pass_1, + badSector, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_block_0_in_pass_1, badSector, pass); } - else if(runningPersistent) - outputFormat.WriteSector(readBuffer, badSector); + else if(runningPersistent) outputFormat.WriteSector(readBuffer, badSector); } - if(pass < _retryPasses && - !_aborted && - _resume.BadBlocks.Count > 0) + if(pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); - if(!forward) - _resume.BadBlocks.Reverse(); + if(!forward) _resume.BadBlocks.Reverse(); goto repeatRetry; } @@ -505,57 +616,60 @@ public partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { - currentModePage.Value - } + Pages = [currentModePage.Value] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); - UpdateStatus?.Invoke("Sending MODE SELECT to drive (return device to previous status)."); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status)."); + UpdateStatus?.Invoke(Localization.Core.Sending_MODE_SELECT_to_drive_return_device_to_previous_status); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_device_to_previous_status); _dev.ModeSelect(md6, out _, true, false, _dev.Timeout, out _); } EndProgress?.Invoke(); } - #endregion Error handling + +#endregion Error handling _resume.BadBlocks.Sort(); - foreach(ulong bad in _resume.BadBlocks) - _dumpLog.WriteLine("Sector {0} could not be read.", bad); + foreach(ulong bad in _resume.BadBlocks) _dumpLog.WriteLine(Localization.Core.Sector_0_could_not_be_read, bad); currentTry.Extents = ExtentsConverter.ToMetadata(extents); - var metadata = new ImageInfo + var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; - if(!outputFormat.SetMetadata(metadata)) - ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + + if(!outputFormat.SetImageInfo(metadata)) + { + ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + + Environment.NewLine + outputFormat.ErrorMessage); + } outputFormat.SetDumpHardware(_resume.Tries); - if(_preSidecar != null) - outputFormat.SetCicmMetadata(_preSidecar); + if(_preSidecar != null) outputFormat.SetMetadata(_preSidecar); - _dumpLog.WriteLine("Closing output file."); - UpdateStatus?.Invoke("Closing output file."); - DateTime closeStart = DateTime.Now; + _dumpLog.WriteLine(Localization.Core.Closing_output_file); + UpdateStatus?.Invoke(Localization.Core.Closing_output_file); + _imageCloseStopwatch.Restart(); outputFormat.Close(); - DateTime closeEnd = DateTime.Now; - UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); - _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); + _imageCloseStopwatch.Stop(); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); return; } @@ -564,21 +678,20 @@ public partial class Dump if(_metadata) { - UpdateStatus?.Invoke("Creating sidecar."); - _dumpLog.WriteLine("Creating sidecar."); - var filters = new FiltersList(); - IFilter filter = filters.GetFilter(_outputPath); + UpdateStatus?.Invoke(Localization.Core.Creating_sidecar); + _dumpLog.WriteLine(Localization.Core.Creating_sidecar); + IFilter filter = PluginRegister.Singleton.GetFilter(_outputPath); var inputPlugin = ImageFormat.Detect(filter) as IMediaImage; ErrorNumber opened = inputPlugin.Open(filter); if(opened != ErrorNumber.NoError) { - StoppingErrorMessage?.Invoke($"Error {opened} opening created image."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_0_opening_created_image, opened)); return; } - DateTime chkStart = DateTime.UtcNow; + _sidecarStopwatch.Restart(); _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); _sidecarClass.InitProgressEvent += InitProgress; _sidecarClass.UpdateProgressEvent += UpdateProgress; @@ -587,91 +700,125 @@ public partial class Dump _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; - CICMMetadataType sidecar = _sidecarClass.Create(); - end = DateTime.UtcNow; + Metadata sidecar = _sidecarClass.Create(); + _sidecarStopwatch.Stop(); if(!_aborted) { - totalChkDuration = (end - chkStart).TotalMilliseconds; - UpdateStatus?.Invoke($"Sidecar created in {(end - chkStart).TotalSeconds} seconds."); + totalChkDuration = _sidecarStopwatch.Elapsed.TotalMilliseconds; - UpdateStatus?. - Invoke($"Average checksum speed {blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); + _dumpLog.WriteLine(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); + + _dumpLog.WriteLine(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize()); if(_preSidecar != null) { - _preSidecar.BlockMedia = sidecar.BlockMedia; - sidecar = _preSidecar; + _preSidecar.BlockMedias = sidecar.BlockMedias; + sidecar = _preSidecar; } - List<(ulong start, string type)> filesystems = new(); + List<(ulong start, string type)> filesystems = []; - if(sidecar.BlockMedia[0].FileSystemInformation != null) - filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation - where partition.FileSystems != null from fileSystem in partition.FileSystems + if(sidecar.BlockMedias[0].FileSystemInformation != null) + { + filesystems.AddRange(from partition in sidecar.BlockMedias[0].FileSystemInformation + where partition.FileSystems != null + from fileSystem in partition.FileSystems select (partition.StartSector, fileSystem.Type)); + } if(filesystems.Count > 0) + { foreach(var filesystem in filesystems.Select(o => new - { - o.start, - o.type - }).Distinct()) + { + o.start, + o.type + }) + .Distinct()) { - UpdateStatus?.Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}"); - _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start); + UpdateStatus?.Invoke(string.Format(Localization.Core.Found_filesystem_0_at_sector_1, + filesystem.type, + filesystem.start)); + + _dumpLog.WriteLine(Localization.Core.Found_filesystem_0_at_sector_1, + filesystem.type, + filesystem.start); } + } - sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(dskType); + sidecar.BlockMedias[0].Dimensions = Dimensions.FromMediaType(dskType); (string type, string subType) xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType); - sidecar.BlockMedia[0].DiskType = xmlType.type; - sidecar.BlockMedia[0].DiskSubType = xmlType.subType; - sidecar.BlockMedia[0].Interface = "USB"; - sidecar.BlockMedia[0].LogicalBlocks = blocks; - sidecar.BlockMedia[0].PhysicalBlockSize = (int)blockSize; - sidecar.BlockMedia[0].LogicalBlockSize = (int)blockSize; - sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer; - sidecar.BlockMedia[0].Model = _dev.Model; + sidecar.BlockMedias[0].MediaType = xmlType.type; + sidecar.BlockMedias[0].MediaSubType = xmlType.subType; + sidecar.BlockMedias[0].Interface = "USB"; + sidecar.BlockMedias[0].LogicalBlocks = blocks; + sidecar.BlockMedias[0].PhysicalBlockSize = (int)blockSize; + sidecar.BlockMedias[0].LogicalBlockSize = (int)blockSize; + sidecar.BlockMedias[0].Manufacturer = _dev.Manufacturer; + sidecar.BlockMedias[0].Model = _dev.Model; - if(!_private) - sidecar.BlockMedia[0].Serial = _dev.Serial; + if(!_private) sidecar.BlockMedias[0].Serial = _dev.Serial; - sidecar.BlockMedia[0].Size = blocks * blockSize; + sidecar.BlockMedias[0].Size = blocks * blockSize; - if(_dev.IsRemovable) - sidecar.BlockMedia[0].DumpHardwareArray = _resume.Tries.ToArray(); + if(_dev.IsRemovable) sidecar.BlockMedias[0].DumpHardware = _resume.Tries; - UpdateStatus?.Invoke("Writing metadata sidecar"); + UpdateStatus?.Invoke(Localization.Core.Writing_metadata_sidecar); - var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); + var jsonFs = new FileStream(_outputPrefix + ".metadata.json", FileMode.Create); - var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); - xmlSer.Serialize(xmlFs, sidecar); - xmlFs.Close(); + JsonSerializer.Serialize(jsonFs, + new MetadataJson + { + AaruMetadata = sidecar + }, + typeof(MetadataJson), + MetadataJsonContext.Default); + + jsonFs.Close(); } } UpdateStatus?.Invoke(""); - UpdateStatus?. - Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second), + totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second), + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average speed: {blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); if(maxSpeed > 0) - UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0, + ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize())); + } - if(minSpeed > 0 && - minSpeed < double.MaxValue) - UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); + if(minSpeed is > 0 and < double.MaxValue) + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0, + ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize())); + } - UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); + UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_could_not_be_read, _resume.BadBlocks.Count)); UpdateStatus?.Invoke(""); Statistics.AddMedia(dskType, true); diff --git a/Aaru.Core/Devices/Dumping/PlayStationPortable/PlayStationPortable.cs b/Aaru.Core/Devices/Dumping/PlayStationPortable/PlayStationPortable.cs index c78ae9b91..3f231d5f4 100644 --- a/Aaru.Core/Devices/Dumping/PlayStationPortable/PlayStationPortable.cs +++ b/Aaru.Core/Devices/Dumping/PlayStationPortable/PlayStationPortable.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - using System; using System.Linq; using Aaru.CommonTypes; @@ -40,16 +38,12 @@ using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.SCSI; using Aaru.Devices; +namespace Aaru.Core.Devices.Dumping; + public partial class Dump { - static readonly byte[] _fatSignature = - { - 0x46, 0x41, 0x54, 0x31, 0x36, 0x20, 0x20, 0x20 - }; - static readonly byte[] _isoExtension = - { - 0x49, 0x53, 0x4F - }; + static readonly byte[] _fatSignature = "FAT16 "u8.ToArray(); + static readonly byte[] _isoExtension = "ISO"u8.ToArray(); /// Dumps a CFW PlayStation Portable UMD void PlayStationPortable() @@ -58,24 +52,30 @@ public partial class Dump !_outputPlugin.SupportedMediaTypes.Contains(MediaType.MemoryStickProDuo) && !_outputPlugin.SupportedMediaTypes.Contains(MediaType.UMD)) { - _dumpLog.WriteLine("Selected output plugin does not support MemoryStick Duo or UMD, cannot dump..."); + _dumpLog.WriteLine(Localization.Core + .Selected_output_format_does_not_support_MemoryStick_Duo_or_UMD_cannot_dump); - StoppingErrorMessage?. - Invoke("Selected output plugin does not support MemoryStick Duo or UMD, cannot dump..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Selected_output_format_does_not_support_MemoryStick_Duo_or_UMD_cannot_dump); return; } - UpdateStatus?.Invoke("Checking if media is UMD or MemoryStick..."); - _dumpLog.WriteLine("Checking if media is UMD or MemoryStick..."); + UpdateStatus?.Invoke(Localization.Core.Checking_if_media_is_UMD_or_MemoryStick); + _dumpLog.WriteLine(Localization.Core.Checking_if_media_is_UMD_or_MemoryStick); - bool sense = _dev.ModeSense6(out byte[] buffer, out _, false, ScsiModeSensePageControl.Current, 0, _dev.Timeout, + bool sense = _dev.ModeSense6(out byte[] buffer, + out _, + false, + ScsiModeSensePageControl.Current, + 0, + _dev.Timeout, out _); if(sense) { - _dumpLog.WriteLine("Could not get MODE SENSE..."); - StoppingErrorMessage?.Invoke("Could not get MODE SENSE..."); + _dumpLog.WriteLine(Localization.Core.Could_not_get_MODE_SENSE); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_get_MODE_SENSE); return; } @@ -84,8 +84,8 @@ public partial class Dump if(!decoded.HasValue) { - _dumpLog.WriteLine("Could not decode MODE SENSE..."); - StoppingErrorMessage?.Invoke("Could not decode MODE SENSE..."); + _dumpLog.WriteLine(Localization.Core.Could_not_decode_MODE_SENSE); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_decode_MODE_SENSE); return; } @@ -102,8 +102,8 @@ public partial class Dump if(sense) { - _dumpLog.WriteLine("Could not read..."); - StoppingErrorMessage?.Invoke("Could not read..."); + _dumpLog.WriteLine(Localization.Core.Could_not_read); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_read); return; } @@ -124,16 +124,28 @@ public partial class Dump var sectorsPerFat = (ushort)((buffer[0x17] << 8) + buffer[0x16]); var rootStart = (ushort)(sectorsPerFat * 2 + fatStart); - UpdateStatus?.Invoke($"Reading root directory in sector {rootStart}..."); - _dumpLog.WriteLine("Reading root directory in sector {0}...", rootStart); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_root_directory_in_sector_0, rootStart)); + _dumpLog.WriteLine(Localization.Core.Reading_root_directory_in_sector_0, rootStart); - sense = _dev.Read12(out buffer, out _, 0, false, true, false, false, rootStart, 512, 0, 1, false, _dev.Timeout, + sense = _dev.Read12(out buffer, + out _, + 0, + false, + true, + false, + false, + rootStart, + 512, + 0, + 1, + false, + _dev.Timeout, out _); if(sense) { - StoppingErrorMessage?.Invoke("Could not read..."); - _dumpLog.WriteLine("Could not read..."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_read); + _dumpLog.WriteLine(Localization.Core.Could_not_read); return; } @@ -148,11 +160,14 @@ public partial class Dump return; } - UpdateStatus?.Invoke($"FAT starts at sector {fatStart} and runs for {sectorsPerFat} sectors..."); - _dumpLog.WriteLine("FAT starts at sector {0} and runs for {1} sectors...", fatStart, sectorsPerFat); + UpdateStatus?.Invoke(string.Format(Localization.Core.FAT_starts_at_sector_0_and_runs_for_1_sectors, + fatStart, + sectorsPerFat)); - UpdateStatus?.Invoke("Reading FAT..."); - _dumpLog.WriteLine("Reading FAT..."); + _dumpLog.WriteLine(Localization.Core.FAT_starts_at_sector_0_and_runs_for_1_sectors, fatStart, sectorsPerFat); + + UpdateStatus?.Invoke(Localization.Core.Reading_FAT); + _dumpLog.WriteLine(Localization.Core.Reading_FAT); var fat = new byte[sectorsPerFat * 512]; @@ -162,16 +177,27 @@ public partial class Dump { uint transfer = 64; - if(transfer + position > sectorsPerFat) - transfer = sectorsPerFat - position; + if(transfer + position > sectorsPerFat) transfer = sectorsPerFat - position; - sense = _dev.Read12(out buffer, out _, 0, false, true, false, false, position + fatStart, 512, 0, transfer, - false, _dev.Timeout, out _); + sense = _dev.Read12(out buffer, + out _, + 0, + false, + true, + false, + false, + position + fatStart, + 512, + 0, + transfer, + false, + _dev.Timeout, + out _); if(sense) { - StoppingErrorMessage?.Invoke("Could not read..."); - _dumpLog.WriteLine("Could not read..."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_read); + _dumpLog.WriteLine(Localization.Core.Could_not_read); return; } @@ -181,8 +207,8 @@ public partial class Dump position += transfer; } - UpdateStatus?.Invoke("Traversing FAT..."); - _dumpLog.WriteLine("Traversing FAT..."); + UpdateStatus?.Invoke(Localization.Core.Traversing_FAT); + _dumpLog.WriteLine(Localization.Core.Traversing_FAT); var previousCluster = BitConverter.ToUInt16(fat, 4); @@ -197,8 +223,7 @@ public partial class Dump continue; } - if(nextCluster == 0xFFFF) - break; + if(nextCluster == 0xFFFF) break; DumpMs(); @@ -208,6 +233,6 @@ public partial class Dump if(_outputPlugin is IWritableOpticalImage) DumpUmd(); else - StoppingErrorMessage?.Invoke("The specified plugin does not support storing optical disc images."); + StoppingErrorMessage?.Invoke(Localization.Core.The_specified_image_format_cannot_represent_optical_discs); } } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs b/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs index aa1536467..2ad950a16 100644 --- a/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs +++ b/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs @@ -27,29 +27,32 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs; using Aaru.Console; +using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.SCSI; using Aaru.Devices; -using Schemas; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; +using Track = Aaru.CommonTypes.Structs.Track; using TrackType = Aaru.CommonTypes.Enums.TrackType; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Devices.Dumping; + public partial class Dump { [SuppressMessage("ReSharper", "JoinDeclarationAndInitializer")] @@ -62,24 +65,34 @@ public partial class Dump double currentSpeed = 0; double maxSpeed = double.MinValue; double minSpeed = double.MaxValue; - DateTime start; - DateTime end; byte[] senseBuf; if(_outputPlugin is not IWritableOpticalImage outputOptical) { - StoppingErrorMessage?.Invoke("Image is not writable, aborting..."); + StoppingErrorMessage?.Invoke(Localization.Core.Image_is_not_writable_aborting); return; } - bool sense = _dev.Read12(out byte[] readBuffer, out _, 0, false, true, false, false, 0, 512, 0, 1, false, - _dev.Timeout, out _); + bool sense = _dev.Read12(out byte[] readBuffer, + out _, + 0, + false, + true, + false, + false, + 0, + 512, + 0, + 1, + false, + _dev.Timeout, + out _); if(sense) { - _dumpLog.WriteLine("Could not read..."); - StoppingErrorMessage?.Invoke("Could not read..."); + _dumpLog.WriteLine(Localization.Core.Could_not_read); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_read); return; } @@ -90,16 +103,28 @@ public partial class Dump var rootSize = (ushort)(((readBuffer[0x12] << 8) + readBuffer[0x11]) * 32 / 512); var umdStart = (ushort)(rootStart + rootSize); - UpdateStatus?.Invoke($"Reading root directory in sector {rootStart}..."); - _dumpLog.WriteLine("Reading root directory in sector {0}...", rootStart); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_root_directory_in_sector_0, rootStart)); + _dumpLog.WriteLine(Localization.Core.Reading_root_directory_in_sector_0, rootStart); - sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, rootStart, 512, 0, 1, false, - _dev.Timeout, out _); + sense = _dev.Read12(out readBuffer, + out _, + 0, + false, + true, + false, + false, + rootStart, + 512, + 0, + 1, + false, + _dev.Timeout, + out _); if(sense) { - _dumpLog.WriteLine("Could not read..."); - StoppingErrorMessage?.Invoke("Could not read..."); + _dumpLog.WriteLine(Localization.Core.Could_not_read); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_read); return; } @@ -108,93 +133,119 @@ public partial class Dump ulong blocks = umdSizeInBytes / blockSize; string mediaPartNumber = Encoding.ASCII.GetString(readBuffer, 0, 11).Trim(); - ulong totalSize = blocks * blockSize; + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_has_0_blocks_of_1_bytes_each_for_a_total_of_2, + blocks, + blockSize, + ByteSize.FromBytes(blocks * blockSize).ToString("0.000"))); - if(totalSize > 1073741824) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1073741824d:F3} GiB)"); - else if(totalSize > 1048576) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1048576d:F3} MiB)"); - else if(totalSize > 1024) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1024d:F3} KiB)"); - else - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize} bytes)"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_blocks_1_bytes, + blocks, + blocks * blockSize)); - UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes)."); - UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time."); - UpdateStatus?.Invoke($"Device reports {blockSize} bytes per logical block."); - UpdateStatus?.Invoke($"Device reports {2048} bytes per physical block."); - UpdateStatus?.Invoke($"SCSI device type: {_dev.ScsiType}."); - UpdateStatus?.Invoke($"Media identified as {dskType}."); - UpdateStatus?.Invoke($"Media part number is {mediaPartNumber}."); - _dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize); - _dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead); - _dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize); - _dumpLog.WriteLine("Device reports {0} bytes per physical block.", 2048); - _dumpLog.WriteLine("SCSI device type: {0}.", _dev.ScsiType); - _dumpLog.WriteLine("Media identified as {0}.", dskType); - _dumpLog.WriteLine("Media part number is {0}.", mediaPartNumber); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_bytes_per_physical_block, blockSize)); + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_device_type_0, _dev.ScsiType)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_identified_as_0, dskType)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_part_number_is_0, mediaPartNumber)); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_blocks_1_bytes, blocks, blocks * blockSize); + _dumpLog.WriteLine(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_bytes_per_physical_block, blockSize); + _dumpLog.WriteLine(Localization.Core.SCSI_device_type_0, _dev.ScsiType); + _dumpLog.WriteLine(Localization.Core.Media_identified_as_0, dskType); + _dumpLog.WriteLine(Localization.Core.Media_part_number_is_0, mediaPartNumber); bool ret; - var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private); - var ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0010); + var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", + _dev, + blocks, + blockSize, + blocksToRead, + _private, + _dimensions); + + var ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0010); ret = outputOptical.Create(_outputPath, dskType, _formatOptions, blocks, blockSize); // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputOptical.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputOptical.ErrorMessage); return; } - start = DateTime.UtcNow; + _dumpStopwatch.Restart(); double imageWriteDuration = 0; - outputOptical.SetTracks(new List + outputOptical.SetTracks([ + new Track + { + BytesPerSector = (int)blockSize, + EndSector = blocks - 1, + Sequence = 1, + RawBytesPerSector = (int)blockSize, + SubchannelType = TrackSubchannelType.None, + Session = 1, + Type = TrackType.Data + } + ]); + + DumpHardware currentTry = null; + ExtentsULong extents = null; + + ResumeSupport.Process(true, + _dev.IsRemovable, + blocks, + _dev.Manufacturer, + _dev.Model, + _dev.Serial, + _dev.PlatformId, + ref _resume, + ref currentTry, + ref extents, + _dev.FirmwareRevision, + _private, + _force); + + if(currentTry == null || extents == null) { - new() - { - BytesPerSector = (int)blockSize, - EndSector = blocks - 1, - Sequence = 1, - RawBytesPerSector = (int)blockSize, - SubchannelType = TrackSubchannelType.None, - Session = 1, - Type = TrackType.Data - } - }); - - DumpHardwareType currentTry = null; - ExtentsULong extents = null; - - ResumeSupport.Process(true, _dev.IsRemovable, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial, - _dev.PlatformId, ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision, - _private, _force); - - if(currentTry == null || - extents == null) - { - StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_process_resume_file_not_continuing); return; } - if(_resume.NextBlock > 0) - _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); + if(_resume.NextBlock > 0) _dumpLog.WriteLine(Localization.Core.Resuming_from_block_0, _resume.NextBlock); + + if(_createGraph) + { + Spiral.DiscParameters discSpiralParameters = Spiral.DiscParametersFromMediaType(dskType); + + if(discSpiralParameters is not null) + _mediaGraph = new Spiral((int)_dimensions, (int)_dimensions, discSpiralParameters, blocks); + else + _mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, blocks); + + if(_mediaGraph is not null) + { + foreach(Tuple e in extents.ToArray()) + _mediaGraph?.PaintSectorsGood(e.Item1, (uint)(e.Item2 - e.Item1 + 2)); + } + + _mediaGraph?.PaintSectorsBad(_resume.BadBlocks); + } var newTrim = false; - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _speedStopwatch.Reset(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead) @@ -202,114 +253,139 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(blocks - i < blocksToRead) - blocksToRead = (uint)(blocks - i); + if(blocks - i < blocksToRead) blocksToRead = (uint)(blocks - i); - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)blocks); - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)(umdStart + i * 4), - 512, 0, blocksToRead * 4, false, _dev.Timeout, out double cmdDuration); + _speedStopwatch.Start(); + + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)(umdStart + i * 4), + 512, + 0, + blocksToRead * 4, + false, + _dev.Timeout, + out double cmdDuration); + + _speedStopwatch.Stop(); totalDuration += cmdDuration; - if(!sense && - !_dev.Error) + _writeStopwatch.Restart(); + + if(!sense && !_dev.Error) { - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, cmdDuration, blocksToRead); ibgLog.Write(i, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; outputOptical.WriteSectors(readBuffer, i, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(i, blocksToRead, true); + _mediaGraph?.PaintSectorsGood(i, blocksToRead); } else { _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly - if(i + _skip > blocks) - _skip = (uint)(blocks - i); + if(i + _skip > blocks) _skip = (uint)(blocks - i); // Write empty data - DateTime writeStart = DateTime.Now; outputOptical.WriteSectors(new byte[blockSize * _skip], i, _skip); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; - for(ulong b = i; b < i + _skip; b++) - _resume.BadBlocks.Add(b); + for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b); - mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); + mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip); ibgLog.Write(i, 0); - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i); i += _skip - blocksToRead; newTrim = true; } + _writeStopwatch.Stop(); sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); - end = DateTime.UtcNow; + _dumpStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), _devicePath); + ibgLog.Close(_dev, + blocks, + blockSize, + _dumpStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), + _devicePath); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - #region Trimming - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _trim && - newTrim) +#region Trimming + + if(_resume.BadBlocks.Count > 0 && !_aborted && _trim && newTrim) { - start = DateTime.UtcNow; - _dumpLog.WriteLine("Trimming skipped sectors"); + _trimStopwatch.Restart(); + _dumpLog.WriteLine(Localization.Core.Trimming_skipped_sectors); ulong[] tmpArray = _resume.BadBlocks.ToArray(); InitProgress?.Invoke(); @@ -319,15 +395,27 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - _dumpLog.WriteLine("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke($"Trimming sector {badSector}"); + PulseProgress?.Invoke(string.Format(Localization.Core.Trimming_sector_0, badSector)); - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, - (uint)(umdStart + badSector * 4), 512, 0, 4, false, _dev.Timeout, out double _); + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)(umdStart + badSector * 4), + 512, + 0, + 4, + false, + _dev.Timeout, + out double _); if(sense || _dev.Error) { @@ -339,18 +427,21 @@ public partial class Dump _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputOptical.WriteSector(readBuffer, badSector); + _mediaGraph?.PaintSectorGood(badSector); } EndProgress?.Invoke(); - end = DateTime.UtcNow; - _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds); - } - #endregion Trimming + _trimStopwatch.Stop(); - #region Error handling - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _retryPasses > 0) + _dumpLog.WriteLine(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + } + +#endregion Trimming + +#region Error handling + + if(_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0) { var pass = 1; var forward = true; @@ -363,17 +454,24 @@ public partial class Dump { Modes.ModePage_01 pg; - sense = _dev.ModeSense6(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01, - _dev.Timeout, out _); + sense = _dev.ModeSense6(out readBuffer, + out _, + false, + ScsiModeSensePageControl.Current, + 0x01, + _dev.Timeout, + out _); if(!sense) { Modes.DecodedMode? dcMode6 = Modes.DecodeMode6(readBuffer, _dev.ScsiType); if(dcMode6.HasValue) + { foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage => - modePage.Page == 0x01 && modePage.Subpage == 0x00)) + modePage is { Page: 0x01, Subpage: 0x00 })) currentModePage = modePage; + } } if(currentModePage == null) @@ -417,30 +515,31 @@ public partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { + Pages = + [ new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01(pg) } - } + ] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks)."); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); sense = _dev.ModeSelect(md6, out senseBuf, true, false, _dev.Timeout, out _); if(sense) { - UpdateStatus?. - Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + UpdateStatus?.Invoke(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); - AaruConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(Localization.Core.Error_0, Sense.PrettifySense(senseBuf)); - _dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + _dumpLog.WriteLine(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); } else runningPersistent = true; @@ -455,48 +554,76 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - _dumpLog.WriteLine("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?. - Invoke($"Retrying sector {badSector}, pass {pass}, {(runningPersistent ? "recovering partial data, " : "")}{(forward ? "forward" : "reverse")}"); + if(forward) + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_forward, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_forward, + badSector, + pass)); + } + else + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_reverse, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_reverse, + badSector, + pass)); + } - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, - (uint)(umdStart + badSector * 4), 512, 0, 4, false, _dev.Timeout, + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + true, + false, + false, + (uint)(umdStart + badSector * 4), + 512, + 0, + 4, + false, + _dev.Timeout, out double cmdDuration); totalDuration += cmdDuration; - if(sense || _dev.Error) - _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); + if(sense || _dev.Error) _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputOptical.WriteSector(readBuffer, badSector); + _mediaGraph?.PaintSectorGood(badSector); - UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_block_0_in_pass_1, + badSector, + pass)); - _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); + _dumpLog.WriteLine(Localization.Core.Correctly_retried_block_0_in_pass_1, badSector, pass); } - else if(runningPersistent) - outputOptical.WriteSector(readBuffer, badSector); + else if(runningPersistent) outputOptical.WriteSector(readBuffer, badSector); } - if(pass < _retryPasses && - !_aborted && - _resume.BadBlocks.Count > 0) + if(pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); - if(!forward) - _resume.BadBlocks.Reverse(); + if(!forward) _resume.BadBlocks.Reverse(); goto repeatRetry; } @@ -506,82 +633,94 @@ public partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { - currentModePage.Value - } + Pages = [currentModePage.Value] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status)."); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_device_to_previous_status); _dev.ModeSelect(md6, out _, true, false, _dev.Timeout, out _); } EndProgress?.Invoke(); AaruConsole.WriteLine(); } - #endregion Error handling + +#endregion Error handling _resume.BadBlocks.Sort(); - foreach(ulong bad in _resume.BadBlocks) - _dumpLog.WriteLine("Sector {0} could not be read.", bad); + foreach(ulong bad in _resume.BadBlocks) _dumpLog.WriteLine(Localization.Core.Sector_0_could_not_be_read, bad); currentTry.Extents = ExtentsConverter.ToMetadata(extents); - var metadata = new ImageInfo + var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion(), MediaPartNumber = mediaPartNumber }; - if(!outputOptical.SetMetadata(metadata)) - ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + + if(!outputOptical.SetImageInfo(metadata)) + { + ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + + Environment.NewLine + outputOptical.ErrorMessage); + } outputOptical.SetDumpHardware(_resume.Tries); - if(_preSidecar != null) - outputOptical.SetCicmMetadata(_preSidecar); + if(_preSidecar != null) outputOptical.SetMetadata(_preSidecar); - _dumpLog.WriteLine("Closing output file."); - UpdateStatus?.Invoke("Closing output file."); - DateTime closeStart = DateTime.Now; + _dumpLog.WriteLine(Localization.Core.Closing_output_file); + UpdateStatus?.Invoke(Localization.Core.Closing_output_file); + _imageCloseStopwatch.Restart(); outputOptical.Close(); - DateTime closeEnd = DateTime.Now; - _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); + _imageCloseStopwatch.Stop(); + + _dumpLog.WriteLine(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); return; } double totalChkDuration = 0; - if(_metadata) - WriteOpticalSidecar(blockSize, blocks, dskType, null, null, 1, out totalChkDuration, null); + if(_metadata) WriteOpticalSidecar(blockSize, blocks, dskType, null, null, 1, out totalChkDuration, null); UpdateStatus?.Invoke(""); - UpdateStatus?. - Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second), + totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second), + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average speed: {blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); if(maxSpeed > 0) - UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0, + ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize())); + } - if(minSpeed > 0 && - minSpeed < double.MaxValue) - UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); + if(minSpeed is > 0 and < double.MaxValue) + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0, + ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize())); + } - UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); + UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_could_not_be_read, _resume.BadBlocks.Count)); UpdateStatus?.Invoke(""); Statistics.AddMedia(dskType, true); diff --git a/Aaru.Core/Devices/Dumping/ResumeSupport.cs b/Aaru.Core/Devices/Dumping/ResumeSupport.cs index c507f9111..6b855e461 100644 --- a/Aaru.Core/Devices/Dumping/ResumeSupport.cs +++ b/Aaru.Core/Devices/Dumping/ResumeSupport.cs @@ -27,19 +27,18 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - using System; -using System.Collections.Generic; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Metadata; -using Schemas; using PlatformID = Aaru.CommonTypes.Interop.PlatformID; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Devices.Dumping; + /// Implements resume support static class ResumeSupport { @@ -64,65 +63,95 @@ static class ResumeSupport /// progress dump /// internal static void Process(bool isLba, bool removable, ulong blocks, string manufacturer, string model, - string serial, PlatformID platform, ref Resume resume, ref DumpHardwareType currentTry, + string serial, PlatformID platform, ref Resume resume, ref DumpHardware currentTry, ref ExtentsULong extents, string firmware, bool @private, bool force, bool isTape = false) { - if(@private) - serial = null; + if(@private) serial = null; if(resume != null) { if(!isLba) - throw new NotImplementedException("Resuming CHS devices is currently not supported."); + throw new NotImplementedException(Localization.Core.Resuming_CHS_devices_is_currently_not_supported); if(resume.Tape != isTape) - throw new - InvalidOperationException($"Resume file specifies a {(resume.Tape ? "tape" : "not tape")} device but you're requesting to dump a {(isTape ? "tape" : "not tape")} device, not continuing..."); - - if(resume.Removable != removable && - !force) - throw new - InvalidOperationException($"Resume file specifies a {(resume.Removable ? "removable" : "non removable")} device but you're requesting to dump a {(removable ? "removable" : "non removable")} device, not continuing..."); - - if(!isTape && - resume.LastBlock != blocks - 1 && - !force) - throw new - InvalidOperationException($"Resume file specifies a device with {resume.LastBlock + 1} blocks but you're requesting to dump one with {blocks} blocks, not continuing..."); - - foreach(DumpHardwareType oldTry in resume.Tries) { - if(!removable && - !force) + if(resume.Tape) + throw new InvalidOperationException(Localization.Core.Resume_specifies_tape_but_device_is_not_tape); + + throw new InvalidOperationException(Localization.Core.Resume_specifies_not_tape_but_device_is_tape); + } + + if(resume.Removable != removable && !force) + { + if(resume.Removable) + { + throw new InvalidOperationException(Localization.Core + .Resume_specifies_removable_but_device_is_non_removable); + } + + throw new InvalidOperationException(Localization.Core + .Resume_specifies_non_removable_but_device_is_removable); + } + + if(!isTape && resume.LastBlock != blocks - 1 && !force) + { + throw new InvalidOperationException(string.Format(Localization.Core + .Resume_file_different_number_of_blocks_not_continuing, + resume.LastBlock + 1, + blocks)); + } + + foreach(DumpHardware oldTry in resume.Tries) + { + if(!removable && !force) { if(oldTry.Manufacturer != manufacturer) - throw new - InvalidOperationException($"Resume file specifies a device manufactured by {oldTry.Manufacturer} but you're requesting to dump one by {manufacturer}, not continuing..."); + { + throw new InvalidOperationException(string.Format(Localization.Core + .Resume_file_different_manufacturer_not_continuing, + oldTry.Manufacturer, + manufacturer)); + } if(oldTry.Model != model) - throw new - InvalidOperationException($"Resume file specifies a device model {oldTry.Model} but you're requesting to dump model {model}, not continuing..."); + { + throw new InvalidOperationException(string.Format(Localization.Core + .Resume_file_different_model_not_continuing, + oldTry.Model, + model)); + } if(oldTry.Serial != serial) - throw new - InvalidOperationException($"Resume file specifies a device with serial {oldTry.Serial} but you're requesting to dump one with serial {serial}, not continuing..."); + { + throw new InvalidOperationException(string.Format(Localization.Core + .Resume_file_different_serial_number_not_continuing, + oldTry.Serial, + serial)); + } if(oldTry.Firmware != firmware) - throw new - InvalidOperationException($"Resume file specifies a device with firmware version {oldTry.Firmware} but you're requesting to dump one with firmware version {firmware}, not continuing..."); + { + throw new InvalidOperationException(string.Format(Localization.Core + .Resume_file_different_firmware_revision_not_continuing, + oldTry.Firmware, + firmware)); + } } if(oldTry.Software == null) - throw new InvalidOperationException("Found corrupt resume file, cannot continue..."); + throw new InvalidOperationException(Localization.Core.Found_corrupt_resume_file_cannot_continue); if(oldTry.Software.Name != "Aaru" || oldTry.Software.OperatingSystem != platform.ToString() || oldTry.Software.Version != Version.GetVersion()) continue; - if(removable && (oldTry.Manufacturer != manufacturer || oldTry.Model != model || - oldTry.Serial != serial || oldTry.Firmware != firmware)) + if(removable && + (oldTry.Manufacturer != manufacturer || + oldTry.Model != model || + oldTry.Serial != serial || + oldTry.Firmware != firmware)) continue; currentTry = oldTry; @@ -131,12 +160,11 @@ static class ResumeSupport break; } - if(currentTry != null) - return; + if(currentTry != null) return; - currentTry = new DumpHardwareType + currentTry = new DumpHardware { - Software = CommonTypes.Metadata.Version.GetSoftwareType(), + Software = CommonTypes.Metadata.Version.GetSoftware(), Manufacturer = manufacturer, Model = model, Serial = serial, @@ -150,16 +178,16 @@ static class ResumeSupport { resume = new Resume { - Tries = new List(), + Tries = [], CreationDate = DateTime.UtcNow, - BadBlocks = new List(), + BadBlocks = [], LastBlock = isTape ? 0 : blocks - 1, Tape = isTape }; - currentTry = new DumpHardwareType + currentTry = new DumpHardware { - Software = CommonTypes.Metadata.Version.GetSoftwareType(), + Software = CommonTypes.Metadata.Version.GetSoftware(), Manufacturer = manufacturer, Model = model, Serial = serial, diff --git a/Aaru.Core/Devices/Dumping/SCSI.cs b/Aaru.Core/Devices/Dumping/SCSI.cs index 6dce98819..5767fb3c9 100644 --- a/Aaru.Core/Devices/Dumping/SCSI.cs +++ b/Aaru.Core/Devices/Dumping/SCSI.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Dumping; - using System; using System.Threading; using Aaru.CommonTypes; @@ -39,6 +37,8 @@ using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.SCSI; +namespace Aaru.Core.Devices.Dumping; + /// Implements dumping SCSI and ATAPI devices public partial class Dump { @@ -60,92 +60,107 @@ public partial class Dump if(decSense.HasValue) { - ErrorMessage?. - Invoke($"Device not ready. Sense {decSense.Value.SenseKey} ASC {decSense.Value.ASC:X2}h ASCQ {decSense.Value.ASCQ:X2}h"); + ErrorMessage?.Invoke(string.Format(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ)); - _dumpLog.WriteLine("Device not ready. Sense {0} ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, - decSense.Value.ASC, decSense.Value.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); // Just retry, for 5 times if(decSense.Value.ASC == 0x29) { resets++; - if(resets < 5) - goto deviceGotReset; + if(resets < 5) goto deviceGotReset; } - if(decSense.Value.ASC == 0x3A) + switch(decSense.Value.ASC) { - var leftRetries = 5; - - while(leftRetries > 0) + case 0x3A: { - PulseProgress?.Invoke("Waiting for drive to become ready"); - Thread.Sleep(2000); - sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _); + var leftRetries = 5; - if(!sense) - break; - - decSense = Sense.Decode(senseBuf); - - if(decSense.HasValue) + while(leftRetries > 0) { - ErrorMessage?. - Invoke($"Device not ready. Sense {decSense.Value.SenseKey} ASC {decSense.Value.ASC:X2}h ASCQ {decSense.Value.ASCQ:X2}h"); + PulseProgress?.Invoke(Localization.Core.Waiting_for_drive_to_become_ready); + Thread.Sleep(2000); + sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _); - _dumpLog.WriteLine("Device not ready. Sense {0} ASC {1:X2}h ASCQ {2:X2}h", - decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ); + if(!sense) break; + + decSense = Sense.Decode(senseBuf); + + if(decSense.HasValue) + { + ErrorMessage?.Invoke(string.Format(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ)); + + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); + } + + leftRetries--; } - leftRetries--; - } - - if(sense) - { - StoppingErrorMessage?.Invoke("Please insert media in drive"); - - return; - } - } - else if(decSense.Value.ASC == 0x04 && - decSense.Value.ASCQ == 0x01) - { - var leftRetries = 50; - - while(leftRetries > 0) - { - PulseProgress?.Invoke("Waiting for drive to become ready"); - Thread.Sleep(2000); - sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _); - - if(!sense) - break; - - decSense = Sense.Decode(senseBuf); - - if(decSense.HasValue) + if(sense) { - ErrorMessage?. - Invoke($"Device not ready. Sense {decSense.Value.SenseKey} ASC {decSense.Value.ASC:X2}h ASCQ {decSense.Value.ASCQ:X2}h"); + StoppingErrorMessage?.Invoke(Localization.Core.Please_insert_media_in_drive); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", - decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ); + return; } - leftRetries--; + break; } - - if(sense) + case 0x04 when decSense.Value.ASCQ == 0x01: { - StoppingErrorMessage?. - Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}"); + var leftRetries = 50; - return; + while(leftRetries > 0) + { + PulseProgress?.Invoke(Localization.Core.Waiting_for_drive_to_become_ready); + Thread.Sleep(2000); + sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _); + + if(!sense) break; + + decSense = Sense.Decode(senseBuf); + + if(decSense.HasValue) + { + ErrorMessage?.Invoke(string.Format(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ)); + + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); + } + + leftRetries--; + } + + if(sense) + { + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Error_testing_unit_was_ready_0, + Sense.PrettifySense(senseBuf))); + + return; + } + + break; } - } - /*else if (decSense.Value.ASC == 0x29 && decSense.Value.ASCQ == 0x00) + /*else if (decSense.Value.ASC == 0x29 && decSense.Value.ASCQ == 0x00) { if (!deviceReset) { @@ -158,52 +173,58 @@ public partial class Dump Decoders.SCSI.Sense.PrettifySense(senseBuf))); return; }*/ - // These should be trapped by the OS but seems in some cases they're not - else if(decSense.Value.ASC == 0x28) - { - var leftRetries = 10; - - while(leftRetries > 0) + // These should be trapped by the OS but seems in some cases they're not + case 0x28: { - PulseProgress?.Invoke("Waiting for drive to become ready"); - Thread.Sleep(2000); - sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _); + var leftRetries = 10; - if(!sense) - break; - - decSense = Sense.Decode(senseBuf); - - if(decSense.HasValue) + while(leftRetries > 0) { - ErrorMessage?. - Invoke($"Device not ready. Sense {decSense.Value.SenseKey} ASC {decSense.Value.ASC:X2}h ASCQ {decSense.Value.ASCQ:X2}h"); + PulseProgress?.Invoke(Localization.Core.Waiting_for_drive_to_become_ready); + Thread.Sleep(2000); + sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", - decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ); + if(!sense) break; + + decSense = Sense.Decode(senseBuf); + + if(decSense.HasValue) + { + ErrorMessage?.Invoke(string.Format(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ)); + + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); + } + + leftRetries--; } - leftRetries--; - } + if(sense) + { + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Error_testing_unit_was_ready_0, + Sense.PrettifySense(senseBuf))); - if(sense) - { - StoppingErrorMessage?. - Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}"); + return; + } + + break; + } + default: + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_testing_unit_was_ready_0, + Sense.PrettifySense(senseBuf))); return; - } - } - else - { - StoppingErrorMessage?.Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}"); - - return; } } else { - StoppingErrorMessage?.Invoke("Unknown testing unit was ready."); + StoppingErrorMessage?.Invoke(Localization.Core.Unknown_sense_testing_unit_was_ready); return; } @@ -217,7 +238,7 @@ public partial class Dump case PeripheralDeviceTypes.SequentialAccess: if(_dumpRaw) { - StoppingErrorMessage?.Invoke("Tapes cannot be dumped raw."); + StoppingErrorMessage?.Invoke(Localization.Core.Tapes_cannot_be_dumped_raw); return; } @@ -225,15 +246,20 @@ public partial class Dump if(_outputPlugin is IWritableTapeImage) Ssc(); else - StoppingErrorMessage?. - Invoke("The specified plugin does not support storing streaming tape images."); + { + StoppingErrorMessage?.Invoke(Localization.Core + .The_specified_image_format_cannot_represent_streaming_tapes); + } return; case PeripheralDeviceTypes.MultiMediaDevice: if(_outputPlugin is IWritableOpticalImage) Mmc(); else - StoppingErrorMessage?.Invoke("The specified plugin does not support storing optical disc images."); + { + StoppingErrorMessage?.Invoke(Localization.Core + .The_specified_image_format_cannot_represent_optical_discs); + } return; case PeripheralDeviceTypes.BridgingExpander diff --git a/Aaru.Core/Devices/Dumping/SSC.cs b/Aaru.Core/Devices/Dumping/SSC.cs index 494edbf7d..e686e9684 100644 --- a/Aaru.Core/Devices/Dumping/SSC.cs +++ b/Aaru.Core/Devices/Dumping/SSC.cs @@ -27,34 +27,36 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable JoinDeclarationAndInitializer -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.Json; using System.Threading; -using System.Xml.Serialization; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Metadata; -using Aaru.CommonTypes.Structs; using Aaru.Core.Logging; using Aaru.Decoders.SCSI; using Aaru.Decoders.SCSI.SSC; using Aaru.Devices; using Aaru.Helpers; -using Schemas; -using MediaType = Aaru.CommonTypes.MediaType; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; +using TapeFile = Aaru.CommonTypes.Structs.TapeFile; +using TapePartition = Aaru.CommonTypes.Structs.TapePartition; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Devices.Dumping; + partial class Dump { /// Dumps the tape from a SCSI Streaming device @@ -65,8 +67,6 @@ partial class Dump uint blockSize; ulong blocks = 0; MediaType dskType; - DateTime start; - DateTime end; double totalDuration = 0; double currentSpeed = 0; double maxSpeed = double.MinValue; @@ -78,26 +78,28 @@ partial class Dump InitProgress?.Invoke(); - if(decSense.HasValue && - decSense.Value.SenseKey != SenseKeys.NoSense) + if(decSense.HasValue && decSense?.SenseKey != SenseKeys.NoSense) { - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, - decSense.Value.ASC, decSense.Value.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense?.SenseKey, + decSense?.ASC, + decSense?.ASCQ); - StoppingErrorMessage?.Invoke("Drive has status error, please correct. Sense follows..." + - Environment.NewLine + decSense.Value.Description); + StoppingErrorMessage?.Invoke(Localization.Core.Drive_has_status_error_please_correct_Sense_follows + + Environment.NewLine + + decSense?.Description); return; } // Not in BOM/P - if(decSense is { ASC: 0x00 } && - decSense.Value.ASCQ != 0x00 && - decSense.Value.ASCQ != 0x04 && - decSense.Value.SenseKey != SenseKeys.IllegalRequest) + if(decSense is { ASC: 0x00 } && + decSense?.ASCQ != 0x00 && + decSense?.ASCQ != 0x04 && + decSense?.SenseKey != SenseKeys.IllegalRequest) { - _dumpLog.WriteLine("Rewinding, please wait..."); - PulseProgress?.Invoke("Rewinding, please wait..."); + _dumpLog.WriteLine(Localization.Core.Rewinding_please_wait); + PulseProgress?.Invoke(Localization.Core.Rewinding_please_wait); // Rewind, let timeout apply _dev.Rewind(out senseBuf, _dev.Timeout, out duration); @@ -106,7 +108,7 @@ partial class Dump // TODO: Pause? do { - PulseProgress?.Invoke("Rewinding, please wait..."); + PulseProgress?.Invoke(Localization.Core.Rewinding_please_wait); _dev.RequestSense(out senseBuf, _dev.Timeout, out duration); decSense = Sense.Decode(senseBuf); } while(decSense is { ASC: 0x00, ASCQ: 0x1A or not (0x04 and 0x00) }); @@ -116,16 +118,18 @@ partial class Dump // And yet, did not rewind! if(decSense.HasValue && - (decSense.Value.ASC == 0x00 && decSense.Value.ASCQ != 0x04 && decSense.Value.ASCQ != 0x00 || - decSense.Value.ASC != 0x00)) + (decSense?.ASC == 0x00 && decSense?.ASCQ != 0x04 && decSense?.ASCQ != 0x00 || decSense?.ASC != 0x00)) { - StoppingErrorMessage?.Invoke("Drive could not rewind, please correct. Sense follows..." + - Environment.NewLine + decSense.Value.Description); + StoppingErrorMessage?.Invoke(Localization.Core.Drive_could_not_rewind_please_correct_Sense_follows + + Environment.NewLine + + decSense?.Description); - _dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows..."); + _dumpLog.WriteLine(Localization.Core.Drive_could_not_rewind_please_correct_Sense_follows); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, - decSense.Value.ASC, decSense.Value.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense?.SenseKey, + decSense?.ASC, + decSense?.ASCQ); return; } @@ -141,16 +145,19 @@ partial class Dump decSense = Sense.Decode(senseBuf); if(decSense.HasValue && - (decSense.Value.ASC == 0x20 && decSense.Value.ASCQ != 0x00 || decSense.Value.ASC != 0x20 && - decSense.Value.SenseKey != SenseKeys.IllegalRequest)) + (decSense?.ASC == 0x20 && decSense?.ASCQ != 0x00 || + decSense?.ASC != 0x20 && decSense?.SenseKey != SenseKeys.IllegalRequest)) { - StoppingErrorMessage?.Invoke("Could not get position. Sense follows..." + Environment.NewLine + - decSense.Value.Description); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_get_position_Sense_follows + + Environment.NewLine + + decSense?.Description); - _dumpLog.WriteLine("Could not get position. Sense follows..."); + _dumpLog.WriteLine(Localization.Core.Could_not_get_position_Sense_follows); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, - decSense.Value.ASC, decSense.Value.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense?.SenseKey, + decSense?.ASC, + decSense?.ASCQ); return; } @@ -160,21 +167,24 @@ partial class Dump // Not in partition 0 if(cmdBuf[1] != 0) { - UpdateStatus?.Invoke("Drive not in partition 0. Rewinding, please wait..."); - _dumpLog.WriteLine("Drive not in partition 0. Rewinding, please wait..."); + UpdateStatus?.Invoke(Localization.Core.Drive_not_in_partition_0_Rewinding_please_wait); + _dumpLog.WriteLine(Localization.Core.Drive_not_in_partition_0_Rewinding_please_wait); // Rewind, let timeout apply sense = _dev.Locate(out senseBuf, false, 0, 0, _dev.Timeout, out duration); if(sense) { - StoppingErrorMessage?.Invoke("Drive could not rewind, please correct. Sense follows..." + - Environment.NewLine + decSense?.Description); + StoppingErrorMessage?.Invoke(Localization.Core.Drive_could_not_rewind_please_correct_Sense_follows + + Environment.NewLine + + decSense?.Description); - _dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows..."); + _dumpLog.WriteLine(Localization.Core.Drive_could_not_rewind_please_correct_Sense_follows); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense?.SenseKey, - decSense?.ASC, decSense?.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense?.SenseKey, + decSense?.ASC, + decSense?.ASCQ); return; } @@ -184,24 +194,25 @@ partial class Dump do { Thread.Sleep(1000); - PulseProgress?.Invoke("Rewinding, please wait..."); + PulseProgress?.Invoke(Localization.Core.Rewinding_please_wait); _dev.RequestSense(out senseBuf, _dev.Timeout, out duration); decSense = Sense.Decode(senseBuf); - } while(decSense is { ASC: 0x00 } && - decSense.Value.ASCQ is 0x1A or 0x19); + } while(decSense is { ASC: 0x00, ASCQ: 0x1A or 0x19 }); // And yet, did not rewind! if(decSense.HasValue && - (decSense.Value.ASC == 0x00 && decSense.Value.ASCQ != 0x04 && decSense.Value.ASCQ != 0x00 || - decSense.Value.ASC != 0x00)) + (decSense?.ASC == 0x00 && decSense?.ASCQ != 0x04 && decSense?.ASCQ != 0x00 || decSense?.ASC != 0x00)) { - StoppingErrorMessage?.Invoke("Drive could not rewind, please correct. Sense follows..." + - Environment.NewLine + decSense.Value.Description); + StoppingErrorMessage?.Invoke(Localization.Core.Drive_could_not_rewind_please_correct_Sense_follows + + Environment.NewLine + + decSense?.Description); - _dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows..."); + _dumpLog.WriteLine(Localization.Core.Drive_could_not_rewind_please_correct_Sense_follows); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, - decSense.Value.ASC, decSense.Value.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense?.SenseKey, + decSense?.ASC, + decSense?.ASCQ); return; } @@ -212,13 +223,16 @@ partial class Dump { decSense = Sense.Decode(senseBuf); - StoppingErrorMessage?.Invoke("Drive could not rewind, please correct. Sense follows..." + - Environment.NewLine + decSense?.Description); + StoppingErrorMessage?.Invoke(Localization.Core.Drive_could_not_rewind_please_correct_Sense_follows + + Environment.NewLine + + decSense?.Description); - _dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows..."); + _dumpLog.WriteLine(Localization.Core.Drive_could_not_rewind_please_correct_Sense_follows); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense?.SenseKey, - decSense?.ASC, decSense?.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense?.SenseKey, + decSense?.ASC, + decSense?.ASCQ); return; } @@ -226,8 +240,10 @@ partial class Dump // Still not in partition 0!!!? if(cmdBuf[1] != 0) { - StoppingErrorMessage?.Invoke("Drive could not rewind to partition 0 but no error occurred..."); - _dumpLog.WriteLine("Drive could not rewind to partition 0 but no error occurred..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Drive_could_not_rewind_to_partition_0_but_no_error_occurred); + + _dumpLog.WriteLine(Localization.Core.Drive_could_not_rewind_to_partition_0_but_no_error_occurred); return; } @@ -241,51 +257,79 @@ partial class Dump byte[] mode6Data = null; byte[] mode10Data = null; - UpdateStatus?.Invoke("Requesting MODE SENSE (10)."); + UpdateStatus?.Invoke(Localization.Core.Requesting_MODE_SENSE_10); - sense = _dev.ModeSense10(out cmdBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F, 0xFF, 5, + sense = _dev.ModeSense10(out cmdBuf, + out senseBuf, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0xFF, + 5, out duration); - if(!sense || - _dev.Error) - sense = _dev.ModeSense10(out cmdBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F, - 0x00, 5, out duration); + if(!sense || _dev.Error) + { + sense = _dev.ModeSense10(out cmdBuf, + out senseBuf, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, + out duration); + } Modes.DecodedMode? decMode = null; - if(!sense && - !_dev.Error) - if(Modes.DecodeMode10(cmdBuf, _dev.ScsiType).HasValue) - decMode = Modes.DecodeMode10(cmdBuf, _dev.ScsiType); + if(!sense && !_dev.Error) + { + if(Modes.DecodeMode10(cmdBuf, _dev.ScsiType).HasValue) decMode = Modes.DecodeMode10(cmdBuf, _dev.ScsiType); + } - UpdateStatus?.Invoke("Requesting MODE SENSE (6)."); + UpdateStatus?.Invoke(Localization.Core.Requesting_MODE_SENSE_6); - sense = _dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, + sense = _dev.ModeSense6(out cmdBuf, + out senseBuf, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, out duration); if(sense || _dev.Error) - sense = _dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, + { + sense = _dev.ModeSense6(out cmdBuf, + out senseBuf, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, out duration); + } - if(sense || _dev.Error) - sense = _dev.ModeSense(out cmdBuf, out senseBuf, 5, out duration); + if(sense || _dev.Error) sense = _dev.ModeSense(out cmdBuf, out senseBuf, 5, out duration); - if(!sense && - !_dev.Error) - if(Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue) - decMode = Modes.DecodeMode6(cmdBuf, _dev.ScsiType); + if(!sense && !_dev.Error) + { + if(Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue) decMode = Modes.DecodeMode6(cmdBuf, _dev.ScsiType); + } // TODO: Check partitions page if(decMode.HasValue) { - scsiMediumTypeTape = (byte)decMode.Value.Header.MediumType; + scsiMediumTypeTape = (byte)(decMode?.Header.MediumType ?? default(MediumTypes)); - if(decMode.Value.Header.BlockDescriptors?.Length > 0) - scsiDensityCodeTape = (byte)decMode.Value.Header.BlockDescriptors[0].Density; + if(decMode?.Header.BlockDescriptors?.Length > 0) + scsiDensityCodeTape = (byte)(decMode?.Header.BlockDescriptors[0].Density ?? default(DensityType)); - blockSize = decMode.Value.Header.BlockDescriptors?[0].BlockLength ?? 0; + blockSize = decMode?.Header.BlockDescriptors?[0].BlockLength ?? 0; - UpdateStatus?.Invoke($"Device reports {blocks} blocks."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_blocks, blocks)); } else blockSize = 1; @@ -294,29 +338,32 @@ partial class Dump { BlockLimits.BlockLimitsData? blockLimits = BlockLimits.Decode(cmdBuf); - if(blockLimits?.minBlockLen > blockSize) - blockSize = blockLimits?.minBlockLen ?? 0; + if(blockLimits?.minBlockLen > blockSize) blockSize = blockLimits?.minBlockLen ?? 0; } - if(blockSize == 0) - blockSize = 1; + if(blockSize == 0) blockSize = 1; - dskType = MediaTypeFromDevice.GetFromScsi((byte)_dev.ScsiType, _dev.Manufacturer, _dev.Model, - scsiMediumTypeTape, scsiDensityCodeTape, blocks, blockSize, - _dev.IsUsb, false); + dskType = MediaTypeFromDevice.GetFromScsi((byte)_dev.ScsiType, + _dev.Manufacturer, + _dev.Model, + scsiMediumTypeTape, + scsiDensityCodeTape, + blocks, + blockSize, + _dev.IsUsb, + false); - if(dskType == MediaType.Unknown) - dskType = MediaType.UnknownTape; + if(dskType == MediaType.Unknown) dskType = MediaType.UnknownTape; - UpdateStatus?.Invoke($"SCSI device type: {_dev.ScsiType}."); - UpdateStatus?.Invoke($"SCSI medium type: {scsiMediumTypeTape}."); - UpdateStatus?.Invoke($"SCSI density type: {scsiDensityCodeTape}."); - UpdateStatus?.Invoke($"Media identified as {dskType}."); + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_device_type_0, _dev.ScsiType)); + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_medium_type_0, scsiMediumTypeTape)); + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_density_type_0, scsiDensityCodeTape)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_identified_as_0, dskType)); - _dumpLog.WriteLine("SCSI device type: {0}.", _dev.ScsiType); - _dumpLog.WriteLine("SCSI medium type: {0}.", scsiMediumTypeTape); - _dumpLog.WriteLine("SCSI density type: {0}.", scsiDensityCodeTape); - _dumpLog.WriteLine("Media identified as {0}.", dskType); + _dumpLog.WriteLine(Localization.Core.SCSI_device_type_0, _dev.ScsiType); + _dumpLog.WriteLine(Localization.Core.SCSI_medium_type_0, scsiMediumTypeTape); + _dumpLog.WriteLine(Localization.Core.SCSI_density_type_0, scsiDensityCodeTape); + _dumpLog.WriteLine(Localization.Core.Media_identified_as_0, dskType); var endOfMedia = false; ulong currentBlock = 0; @@ -328,7 +375,13 @@ partial class Dump firstRead: - sense = _dev.Read6(out cmdBuf, out senseBuf, false, fixedLen, transferLen, blockSize, _dev.Timeout, + sense = _dev.Read6(out cmdBuf, + out senseBuf, + false, + fixedLen, + transferLen, + blockSize, + _dev.Timeout, out duration); if(sense) @@ -336,131 +389,167 @@ partial class Dump decSense = Sense.Decode(senseBuf); if(decSense.HasValue) - if(decSense.Value.SenseKey == SenseKeys.IllegalRequest) + { + switch(decSense) { - sense = _dev.Space(out senseBuf, SscSpaceCodes.LogicalBlock, -1, _dev.Timeout, out duration); - - if(sense) + case { SenseKey: SenseKeys.IllegalRequest }: { - decSense = Sense.Decode(senseBuf); - - bool eom = decSense?.Fixed?.EOM == true; - - if(decSense?.Descriptor != null && - decSense.Value.Descriptor.Value.Descriptors.TryGetValue(4, out byte[] sscDescriptor)) - Sense.DecodeDescriptor04(sscDescriptor, out _, out eom, out _); - - if(!eom) - { - StoppingErrorMessage?.Invoke("Drive could not return back. Sense follows..." + - Environment.NewLine + decSense.Value.Description); - - _dumpLog.WriteLine("Drive could not return back. Sense follows..."); - - _dumpLog.WriteLine("Device not ready. Sense {0} ASC {1:X2}h ASCQ {2:X2}h", - decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ); - - return; - } - } - - fixedLen = true; - transferLen = 1; - - sense = _dev.Read6(out cmdBuf, out senseBuf, false, fixedLen, transferLen, blockSize, _dev.Timeout, - out duration); - - if(sense) - { - decSense = Sense.Decode(senseBuf); - - StoppingErrorMessage?.Invoke("Drive could not read. Sense follows..." + Environment.NewLine + - decSense.Value.Description); - - _dumpLog.WriteLine("Drive could not read. Sense follows..."); - - _dumpLog.WriteLine("Device not ready. Sense {0} ASC {1:X2}h ASCQ {2:X2}h", - decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ); - - return; - } - } - else if(decSense.Value.ASC == 0x00 && - decSense.Value.ASCQ == 0x00) - { - bool ili = decSense.Value.Fixed?.ILI == true; - bool valid = decSense.Value.Fixed?.InformationValid == true; - uint information = decSense.Value.Fixed?.Information ?? 0; - - if(decSense.Value.Descriptor.HasValue) - { - valid = decSense.Value.Descriptor.Value.Descriptors.TryGetValue(0, out byte[] desc00); - - if(valid) - information = (uint)Sense.DecodeDescriptor00(desc00); - - if(decSense.Value.Descriptor.Value.Descriptors.TryGetValue(4, out byte[] desc04)) - Sense.DecodeDescriptor04(desc04, out _, out _, out ili); - } - - if(ili && valid) - { - blockSize = (uint)((int)blockSize - - BitConverter.ToInt32(BitConverter.GetBytes(information), 0)); - - transferLen = blockSize; - - UpdateStatus?.Invoke($"Blocksize changed to {blockSize} bytes at block {currentBlock}"); - _dumpLog.WriteLine("Blocksize changed to {0} bytes at block {1}", blockSize, currentBlock); - sense = _dev.Space(out senseBuf, SscSpaceCodes.LogicalBlock, -1, _dev.Timeout, out duration); - totalDuration += duration; - if(sense) { decSense = Sense.Decode(senseBuf); - StoppingErrorMessage?.Invoke("Drive could not go back one block. Sense follows..." + - Environment.NewLine + decSense.Value.Description); + bool eom = decSense?.Fixed?.EOM == true; - _dumpLog.WriteLine("Drive could not go back one block. Sense follows..."); + if(decSense?.Descriptor != null && + decSense.Value.Descriptor.Value.Descriptors.TryGetValue(4, out byte[] sscDescriptor)) + Sense.DecodeDescriptor04(sscDescriptor, out _, out eom, out _); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", - decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ); + if(!eom) + { + StoppingErrorMessage?.Invoke(Localization.Core + .Drive_could_not_return_back_Sense_follows + + Environment.NewLine + + decSense.Value.Description); + + _dumpLog.WriteLine(Localization.Core.Drive_could_not_return_back_Sense_follows); + + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); + + return; + } + } + + fixedLen = true; + transferLen = 1; + + sense = _dev.Read6(out cmdBuf, + out senseBuf, + false, + fixedLen, + transferLen, + blockSize, + _dev.Timeout, + out duration); + + if(sense) + { + decSense = Sense.Decode(senseBuf); + + StoppingErrorMessage?.Invoke(Localization.Core.Drive_could_not_read_Sense_follows + + Environment.NewLine + + decSense.Value.Description); + + _dumpLog.WriteLine(Localization.Core.Drive_could_not_read_Sense_follows); + + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); return; } - goto firstRead; + break; } + case { ASC: 0x00, ASCQ: 0x00 }: + { + bool ili = decSense.Value.Fixed?.ILI == true; + bool valid = decSense.Value.Fixed?.InformationValid == true; + uint information = decSense.Value.Fixed?.Information ?? 0; - StoppingErrorMessage?.Invoke("Drive could not read. Sense follows..." + Environment.NewLine + - decSense.Value.Description); + if(decSense.Value.Descriptor.HasValue) + { + valid = decSense.Value.Descriptor.Value.Descriptors.TryGetValue(0, out byte[] desc00); - _dumpLog.WriteLine("Drive could not read. Sense follows..."); + if(valid) information = (uint)Sense.DecodeDescriptor00(desc00); - _dumpLog.WriteLine("Device not ready. Sense {0} ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, - decSense.Value.ASC, decSense.Value.ASCQ); + if(decSense.Value.Descriptor.Value.Descriptors.TryGetValue(4, out byte[] desc04)) + Sense.DecodeDescriptor04(desc04, out _, out _, out ili); + } - return; - } - else - { - StoppingErrorMessage?.Invoke("Drive could not read. Sense follows..." + Environment.NewLine + - decSense.Value.Description); - - _dumpLog.WriteLine("Drive could not read. Sense follows..."); - - _dumpLog.WriteLine("Device not ready. Sense {0} ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, - decSense.Value.ASC, decSense.Value.ASCQ); - - return; + if(ili && valid) + { + blockSize = (uint)((int)blockSize - + BitConverter.ToInt32(BitConverter.GetBytes(information), 0)); + + transferLen = blockSize; + + UpdateStatus?.Invoke(string.Format(Localization.Core + .Blocksize_changed_to_0_bytes_at_block_1, + blockSize, + currentBlock)); + + _dumpLog.WriteLine(Localization.Core.Blocksize_changed_to_0_bytes_at_block_1, + blockSize, + currentBlock); + + sense = _dev.Space(out senseBuf, + SscSpaceCodes.LogicalBlock, + -1, + _dev.Timeout, + out duration); + + totalDuration += duration; + + if(sense) + { + decSense = Sense.Decode(senseBuf); + + StoppingErrorMessage?.Invoke(Localization.Core + .Drive_could_not_go_back_one_block_Sense_follows + + Environment.NewLine + + decSense.Value.Description); + + _dumpLog.WriteLine(Localization.Core.Drive_could_not_go_back_one_block_Sense_follows); + + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); + + return; + } + + goto firstRead; + } + + StoppingErrorMessage?.Invoke(Localization.Core.Drive_could_not_read_Sense_follows + + Environment.NewLine + + decSense.Value.Description); + + _dumpLog.WriteLine(Localization.Core.Drive_could_not_read_Sense_follows); + + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); + + return; + } + default: + StoppingErrorMessage?.Invoke(Localization.Core.Drive_could_not_read_Sense_follows + + Environment.NewLine + + decSense.Value.Description); + + _dumpLog.WriteLine(Localization.Core.Drive_could_not_read_Sense_follows); + + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); + + return; } + } else { - StoppingErrorMessage?.Invoke("Cannot read device, don't know why, exiting..."); - _dumpLog.WriteLine("Cannot read device, don't know why, exiting..."); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_read_device_dont_know_why_exiting); + _dumpLog.WriteLine(Localization.Core.Cannot_read_device_dont_know_why_exiting); return; } @@ -480,29 +569,42 @@ partial class Dump if(!eom) { - StoppingErrorMessage?.Invoke("Drive could not return back. Sense follows..." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Drive_could_not_return_back_Sense_follows + + Environment.NewLine + decSense.Value.Description); - _dumpLog.WriteLine("Drive could not return back. Sense follows..."); + _dumpLog.WriteLine(Localization.Core.Drive_could_not_return_back_Sense_follows); - _dumpLog.WriteLine("Device not ready. Sense {0} ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, - decSense.Value.ASC, decSense.Value.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); return; } } - DumpHardwareType currentTry = null; - ExtentsULong extents = null; + DumpHardware currentTry = null; + ExtentsULong extents = null; - ResumeSupport.Process(true, _dev.IsRemovable, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial, - _dev.PlatformId, ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision, - _private, _force, true); + ResumeSupport.Process(true, + _dev.IsRemovable, + blocks, + _dev.Manufacturer, + _dev.Model, + _dev.Serial, + _dev.PlatformId, + ref _resume, + ref currentTry, + ref extents, + _dev.FirmwareRevision, + _private, + _force, + true); - if(currentTry == null || - extents == null) + if(currentTry == null || extents == null) { - StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_process_resume_file_not_continuing); return; } @@ -510,8 +612,8 @@ partial class Dump var canLocateLong = false; var canLocate = false; - UpdateStatus?.Invoke("Positioning tape to block 1."); - _dumpLog.WriteLine("Positioning tape to block 1"); + UpdateStatus?.Invoke(Localization.Core.Positioning_tape_to_block_1); + _dumpLog.WriteLine(Localization.Core.Positioning_tape_to_block_1); sense = _dev.Locate16(out senseBuf, 1, _dev.Timeout, out _); @@ -526,8 +628,8 @@ partial class Dump if(position == 1) { canLocateLong = true; - UpdateStatus?.Invoke("LOCATE LONG works."); - _dumpLog.WriteLine("LOCATE LONG works."); + UpdateStatus?.Invoke(Localization.Core.LOCATE_LONG_works); + _dumpLog.WriteLine(Localization.Core.LOCATE_LONG_works); } } } @@ -545,16 +647,16 @@ partial class Dump if(position == 1) { canLocate = true; - UpdateStatus?.Invoke("LOCATE works."); - _dumpLog.WriteLine("LOCATE works."); + UpdateStatus?.Invoke(Localization.Core.LOCATE_works); + _dumpLog.WriteLine(Localization.Core.LOCATE_works); } } } if(_resume.NextBlock > 0) { - UpdateStatus?.Invoke($"Positioning tape to block {_resume.NextBlock}."); - _dumpLog.WriteLine("Positioning tape to block {0}.", _resume.NextBlock); + UpdateStatus?.Invoke(string.Format(Localization.Core.Positioning_tape_to_block_0, _resume.NextBlock)); + _dumpLog.WriteLine(Localization.Core.Positioning_tape_to_block_0, _resume.NextBlock); if(canLocateLong) { @@ -568,20 +670,20 @@ partial class Dump { if(!_force) { - _dumpLog. - WriteLine("Could not check current position, unable to resume. If you want to continue use force."); + _dumpLog.WriteLine(Localization.Core + .Could_not_check_current_position_unable_to_resume_If_you_want_to_continue_use_force); - StoppingErrorMessage?. - Invoke("Could not check current position, unable to resume. If you want to continue use force."); + StoppingErrorMessage?.Invoke(Localization.Core + .Could_not_check_current_position_unable_to_resume_If_you_want_to_continue_use_force); return; } - _dumpLog. - WriteLine("Could not check current position, unable to resume. Dumping from the start."); + _dumpLog.WriteLine(Localization.Core + .Could_not_check_current_position_unable_to_resume_Dumping_from_the_start); - ErrorMessage?. - Invoke("Could not check current position, unable to resume. Dumping from the start."); + ErrorMessage?.Invoke(Localization.Core + .Could_not_check_current_position_unable_to_resume_Dumping_from_the_start); canLocateLong = false; } @@ -593,20 +695,20 @@ partial class Dump { if(!_force) { - _dumpLog. - WriteLine("Current position is not as expected, unable to resume. If you want to continue use force."); + _dumpLog.WriteLine(Localization.Core + .Current_position_is_not_as_expected_unable_to_resume_If_you_want_to_continue_use_force); - StoppingErrorMessage?. - Invoke("Current position is not as expected, unable to resume. If you want to continue use force."); + StoppingErrorMessage?.Invoke(Localization.Core + .Current_position_is_not_as_expected_unable_to_resume_If_you_want_to_continue_use_force); return; } - _dumpLog. - WriteLine("Current position is not as expected, unable to resume. Dumping from the start."); + _dumpLog.WriteLine(Localization.Core + .Current_position_is_not_as_expected_unable_to_resume_Dumping_from_the_start); - ErrorMessage?. - Invoke("Current position is not as expected, unable to resume. Dumping from the start."); + ErrorMessage?.Invoke(Localization.Core + .Current_position_is_not_as_expected_unable_to_resume_Dumping_from_the_start); canLocateLong = false; } @@ -616,17 +718,21 @@ partial class Dump { if(!_force) { - _dumpLog. - WriteLine("Cannot reposition tape, unable to resume. If you want to continue use force."); + _dumpLog.WriteLine(Localization.Core + .Cannot_reposition_tape_unable_to_resume_If_you_want_to_continue_use_force); - StoppingErrorMessage?. - Invoke("Cannot reposition tape, unable to resume. If you want to continue use force."); + StoppingErrorMessage?.Invoke(Localization.Core + .Cannot_reposition_tape_unable_to_resume_If_you_want_to_continue_use_force); return; } - _dumpLog.WriteLine("Cannot reposition tape, unable to resume. Dumping from the start."); - ErrorMessage?.Invoke("Cannot reposition tape, unable to resume. Dumping from the start."); + _dumpLog.WriteLine(Localization.Core + .Cannot_reposition_tape_unable_to_resume_Dumping_from_the_start); + + ErrorMessage?.Invoke(Localization.Core + .Cannot_reposition_tape_unable_to_resume_Dumping_from_the_start); + canLocateLong = false; } } @@ -642,20 +748,20 @@ partial class Dump { if(!_force) { - _dumpLog. - WriteLine("Could not check current position, unable to resume. If you want to continue use force."); + _dumpLog.WriteLine(Localization.Core + .Could_not_check_current_position_unable_to_resume_If_you_want_to_continue_use_force); - StoppingErrorMessage?. - Invoke("Could not check current position, unable to resume. If you want to continue use force."); + StoppingErrorMessage?.Invoke(Localization.Core + .Could_not_check_current_position_unable_to_resume_If_you_want_to_continue_use_force); return; } - _dumpLog. - WriteLine("Could not check current position, unable to resume. Dumping from the start."); + _dumpLog.WriteLine(Localization.Core + .Could_not_check_current_position_unable_to_resume_Dumping_from_the_start); - ErrorMessage?. - Invoke("Could not check current position, unable to resume. Dumping from the start."); + ErrorMessage?.Invoke(Localization.Core + .Could_not_check_current_position_unable_to_resume_Dumping_from_the_start); canLocate = false; } @@ -667,20 +773,20 @@ partial class Dump { if(!_force) { - _dumpLog. - WriteLine("Current position is not as expected, unable to resume. If you want to continue use force."); + _dumpLog.WriteLine(Localization.Core + .Current_position_is_not_as_expected_unable_to_resume_If_you_want_to_continue_use_force); - StoppingErrorMessage?. - Invoke("Current position is not as expected, unable to resume. If you want to continue use force."); + StoppingErrorMessage?.Invoke(Localization.Core + .Current_position_is_not_as_expected_unable_to_resume_If_you_want_to_continue_use_force); return; } - _dumpLog. - WriteLine("Current position is not as expected, unable to resume. Dumping from the start."); + _dumpLog.WriteLine(Localization.Core + .Current_position_is_not_as_expected_unable_to_resume_Dumping_from_the_start); - ErrorMessage?. - Invoke("Current position is not as expected, unable to resume. Dumping from the start."); + ErrorMessage?.Invoke(Localization.Core + .Current_position_is_not_as_expected_unable_to_resume_Dumping_from_the_start); canLocate = false; } @@ -690,17 +796,21 @@ partial class Dump { if(!_force) { - _dumpLog. - WriteLine("Cannot reposition tape, unable to resume. If you want to continue use force."); + _dumpLog.WriteLine(Localization.Core + .Cannot_reposition_tape_unable_to_resume_If_you_want_to_continue_use_force); - StoppingErrorMessage?. - Invoke("Cannot reposition tape, unable to resume. If you want to continue use force."); + StoppingErrorMessage?.Invoke(Localization.Core + .Cannot_reposition_tape_unable_to_resume_If_you_want_to_continue_use_force); return; } - _dumpLog.WriteLine("Cannot reposition tape, unable to resume. Dumping from the start."); - ErrorMessage?.Invoke("Cannot reposition tape, unable to resume. Dumping from the start."); + _dumpLog.WriteLine(Localization.Core + .Cannot_reposition_tape_unable_to_resume_Dumping_from_the_start); + + ErrorMessage?.Invoke(Localization.Core + .Cannot_reposition_tape_unable_to_resume_Dumping_from_the_start); + canLocate = false; } } @@ -708,45 +818,49 @@ partial class Dump { if(!_force) { - _dumpLog.WriteLine("Cannot reposition tape, unable to resume. If you want to continue use force."); + _dumpLog.WriteLine(Localization.Core + .Cannot_reposition_tape_unable_to_resume_If_you_want_to_continue_use_force); - StoppingErrorMessage?. - Invoke("Cannot reposition tape, unable to resume. If you want to continue use force."); + StoppingErrorMessage?.Invoke(Localization.Core + .Cannot_reposition_tape_unable_to_resume_If_you_want_to_continue_use_force); return; } - _dumpLog.WriteLine("Cannot reposition tape, unable to resume. Dumping from the start."); - ErrorMessage?.Invoke("Cannot reposition tape, unable to resume. Dumping from the start."); + _dumpLog.WriteLine(Localization.Core.Cannot_reposition_tape_unable_to_resume_Dumping_from_the_start); + ErrorMessage?.Invoke(Localization.Core.Cannot_reposition_tape_unable_to_resume_Dumping_from_the_start); canLocate = false; } } else { - _ = canLocateLong ? _dev.Locate16(out senseBuf, false, 0, 0, _dev.Timeout, out duration) + _ = canLocateLong + ? _dev.Locate16(out senseBuf, false, 0, 0, _dev.Timeout, out duration) : _dev.Locate(out senseBuf, false, 0, 0, _dev.Timeout, out duration); do { Thread.Sleep(1000); - PulseProgress?.Invoke("Rewinding, please wait..."); + PulseProgress?.Invoke(Localization.Core.Rewinding_please_wait); _dev.RequestSense(out senseBuf, _dev.Timeout, out duration); decSense = Sense.Decode(senseBuf); - } while(decSense is { ASC: 0x00 } && - decSense.Value.ASCQ is 0x1A or 0x19); + } while(decSense is { ASC: 0x00, ASCQ: 0x1A or 0x19 }); // And yet, did not rewind! if(decSense.HasValue && (decSense.Value.ASC == 0x00 && decSense.Value.ASCQ != 0x00 && decSense.Value.ASCQ != 0x04 || decSense.Value.ASC != 0x00)) { - StoppingErrorMessage?.Invoke("Drive could not rewind, please correct. Sense follows..." + - Environment.NewLine + decSense.Value.Description); + StoppingErrorMessage?.Invoke(Localization.Core.Drive_could_not_rewind_please_correct_Sense_follows + + Environment.NewLine + + decSense.Value.Description); - _dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows..."); + _dumpLog.WriteLine(Localization.Core.Drive_could_not_rewind_please_correct_Sense_follows); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, - decSense.Value.ASC, decSense.Value.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); return; } @@ -757,11 +871,12 @@ partial class Dump // Cannot set image to tape mode if(!ret) { - _dumpLog.WriteLine("Error setting output image in tape mode, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_setting_output_image_in_tape_mode_not_continuing); _dumpLog.WriteLine(outputTape.ErrorMessage); - StoppingErrorMessage?.Invoke("Error setting output image in tape mode, not continuing." + - Environment.NewLine + outputTape.ErrorMessage); + StoppingErrorMessage?.Invoke(Localization.Core.Error_setting_output_image_in_tape_mode_not_continuing + + Environment.NewLine + + outputTape.ErrorMessage); return; } @@ -771,16 +886,17 @@ partial class Dump // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputTape.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputTape.ErrorMessage); return; } - start = DateTime.UtcNow; + _dumpStopwatch.Restart(); var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, 1, _private); var ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0008); @@ -797,8 +913,7 @@ partial class Dump FirstBlock = currentBlock }; - if((canLocate || canLocateLong) && - _resume.NextBlock > 0) + if((canLocate || canLocateLong) && _resume.NextBlock > 0) { currentBlock = _resume.NextBlock; @@ -810,38 +925,36 @@ partial class Dump outputTape?.TapePartitions.Max(g => g.LastBlock)); } - if(mode6Data != null) - outputTape.WriteMediaTag(mode6Data, MediaTagType.SCSI_MODESENSE_6); + if(mode6Data != null) outputTape.WriteMediaTag(mode6Data, MediaTagType.SCSI_MODESENSE_6); - if(mode10Data != null) - outputTape.WriteMediaTag(mode10Data, MediaTagType.SCSI_MODESENSE_10); + if(mode10Data != null) outputTape.WriteMediaTag(mode10Data, MediaTagType.SCSI_MODESENSE_10); - DateTime timeSpeedStart = DateTime.UtcNow; - ulong currentSpeedSize = 0; - double imageWriteDuration = 0; + ulong currentSpeedSize = 0; + double imageWriteDuration = 0; InitProgress?.Invoke(); + _speedStopwatch.Reset(); + while(currentPartition < totalPartitions) { if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } if(endOfMedia) { - UpdateStatus?.Invoke($"Finished partition {currentPartition}"); - _dumpLog.WriteLine("Finished partition {0}", currentPartition); + UpdateStatus?.Invoke(string.Format(Localization.Core.Finished_partition_0, currentPartition)); + _dumpLog.WriteLine(Localization.Core.Finished_partition_0, currentPartition); currentTapeFile.LastBlock = currentBlock - 1; - if(currentTapeFile.LastBlock > currentTapeFile.FirstBlock) - outputTape.AddFile(currentTapeFile); + if(currentTapeFile.LastBlock > currentTapeFile.FirstBlock) outputTape.AddFile(currentTapeFile); currentTapePartition.LastBlock = currentBlock - 1; outputTape.AddPartition(currentTapePartition); @@ -865,7 +978,7 @@ partial class Dump FirstBlock = currentBlock }; - UpdateStatus?.Invoke($"Seeking to partition {currentPartition}"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Seeking_to_partition_0, currentPartition)); _dev.Locate(out senseBuf, false, currentPartition, 0, _dev.Timeout, out duration); totalDuration += duration; } @@ -873,24 +986,29 @@ partial class Dump continue; } - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - PulseProgress?.Invoke($"Reading block {currentBlock} ({currentSpeed:F3} MiB/sec.)"); + PulseProgress?.Invoke(string.Format(Localization.Core.Reading_block_0_1, + currentBlock, + ByteSize.FromBytes(currentSpeed).Per(_oneSecond).Humanize())); - sense = _dev.Read6(out cmdBuf, out senseBuf, false, fixedLen, transferLen, blockSize, _dev.Timeout, + _speedStopwatch.Start(); + + sense = _dev.Read6(out cmdBuf, + out senseBuf, + false, + fixedLen, + transferLen, + blockSize, + _dev.Timeout, out duration); + _speedStopwatch.Stop(); totalDuration += duration; - if(sense && - senseBuf?.Length != 0 && - !ArrayHelpers.ArrayIsNullOrEmpty(senseBuf)) + if(sense && senseBuf?.Length != 0 && !ArrayHelpers.ArrayIsNullOrEmpty(senseBuf)) { decSense = Sense.Decode(senseBuf); @@ -912,18 +1030,19 @@ partial class Dump Sense.DecodeDescriptor04(desc04, out filemark, out eom, out ili); } - if(decSense.Value.ASC == 0x00 && - decSense.Value.ASCQ == 0x00 && - ili && - valid) + if(decSense.Value is { ASC: 0x00, ASCQ: 0x00 } && ili && valid) { blockSize = (uint)((int)blockSize - BitConverter.ToInt32(BitConverter.GetBytes(information), 0)); - if(!fixedLen) - transferLen = blockSize; + if(!fixedLen) transferLen = blockSize; - UpdateStatus?.Invoke($"Blocksize changed to {blockSize} bytes at block {currentBlock}"); - _dumpLog.WriteLine("Blocksize changed to {0} bytes at block {1}", blockSize, currentBlock); + UpdateStatus?.Invoke(string.Format(Localization.Core.Blocksize_changed_to_0_bytes_at_block_1, + blockSize, + currentBlock)); + + _dumpLog.WriteLine(Localization.Core.Blocksize_changed_to_0_bytes_at_block_1, + blockSize, + currentBlock); sense = _dev.Space(out senseBuf, SscSpaceCodes.LogicalBlock, -1, _dev.Timeout, out duration); @@ -933,14 +1052,17 @@ partial class Dump { decSense = Sense.Decode(senseBuf); - StoppingErrorMessage?.Invoke("Drive could not go back one block. Sense follows..." + - Environment.NewLine + decSense.Value.Description); + StoppingErrorMessage?.Invoke(Localization.Core.Drive_could_not_go_back_one_block_Sense_follows + + Environment.NewLine + + decSense.Value.Description); outputTape.Close(); - _dumpLog.WriteLine("Drive could not go back one block. Sense follows..."); + _dumpLog.WriteLine(Localization.Core.Drive_could_not_go_back_one_block_Sense_follows); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", - decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); return; } @@ -951,9 +1073,9 @@ partial class Dump switch(decSense.Value.SenseKey) { case SenseKeys.BlankCheck when currentBlock == 0: - StoppingErrorMessage?.Invoke("Cannot dump a blank tape..."); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_dump_a_blank_tape); outputTape.Close(); - _dumpLog.WriteLine("Cannot dump a blank tape..."); + _dumpLog.WriteLine(Localization.Core.Cannot_dump_a_blank_tape); return; @@ -962,77 +1084,84 @@ partial class Dump (decSense.Value.ASCQ is 0x02 or 0x05 || eom): // TODO: Detect end of partition endOfMedia = true; - UpdateStatus?.Invoke("Found end-of-tape/partition..."); - _dumpLog.WriteLine("Found end-of-tape/partition..."); + UpdateStatus?.Invoke(Localization.Core.Found_end_of_tape_partition); + _dumpLog.WriteLine(Localization.Core.Found_end_of_tape_partition); continue; case SenseKeys.BlankCheck: - StoppingErrorMessage?.Invoke("Blank block found, end of tape?..."); + StoppingErrorMessage?.Invoke(Localization.Core.Blank_block_found_end_of_tape); endOfMedia = true; - _dumpLog.WriteLine("Blank block found, end of tape?..."); + _dumpLog.WriteLine(Localization.Core.Blank_block_found_end_of_tape); continue; } - if(decSense.Value.SenseKey is SenseKeys.NoSense or SenseKeys.RecoveredError && - (decSense.Value.ASCQ is 0x02 or 0x05 || eom)) + switch(decSense.Value.SenseKey) { - // TODO: Detect end of partition - endOfMedia = true; - UpdateStatus?.Invoke("Found end-of-tape/partition..."); - _dumpLog.WriteLine("Found end-of-tape/partition..."); + case SenseKeys.NoSense or SenseKeys.RecoveredError when decSense.Value.ASCQ is 0x02 or 0x05 || eom: + // TODO: Detect end of partition + endOfMedia = true; + UpdateStatus?.Invoke(Localization.Core.Found_end_of_tape_partition); + _dumpLog.WriteLine(Localization.Core.Found_end_of_tape_partition); - continue; - } + continue; + case SenseKeys.NoSense or SenseKeys.RecoveredError when decSense.Value.ASCQ == 0x01 || filemark: + currentTapeFile.LastBlock = currentBlock - 1; + outputTape.AddFile(currentTapeFile); - if(decSense.Value.SenseKey is SenseKeys.NoSense or SenseKeys.RecoveredError && - (decSense.Value.ASCQ == 0x01 || filemark)) - { - currentTapeFile.LastBlock = currentBlock - 1; - outputTape.AddFile(currentTapeFile); + currentFile++; - currentFile++; + currentTapeFile = new TapeFile + { + File = currentFile, + FirstBlock = currentBlock, + Partition = currentPartition + }; - currentTapeFile = new TapeFile - { - File = currentFile, - FirstBlock = currentBlock, - Partition = currentPartition - }; + UpdateStatus?.Invoke(string.Format(Localization.Core.Changed_to_file_0_at_block_1, + currentFile, + currentBlock)); - UpdateStatus?.Invoke($"Changed to file {currentFile} at block {currentBlock}"); - _dumpLog.WriteLine("Changed to file {0} at block {1}", currentFile, currentBlock); + _dumpLog.WriteLine(Localization.Core.Changed_to_file_0_at_block_1, currentFile, currentBlock); - continue; + continue; } if(decSense is null) { - StoppingErrorMessage?. - Invoke($"Drive could not read block ${currentBlock}. Sense cannot be decoded, look at log for dump..."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Drive_could_not_read_block_0_Sense_cannot_be_decoded_look_at_log_for_dump, + currentBlock)); + + _dumpLog.WriteLine(string.Format(Localization.Core.Drive_could_not_read_block_0_Sense_bytes_follow, + currentBlock)); - _dumpLog.WriteLine($"Drive could not read block ${currentBlock}. Sense bytes follow..."); _dumpLog.WriteLine(PrintHex.ByteArrayToHexArrayString(senseBuf, 32)); } else { - StoppingErrorMessage?. - Invoke($"Drive could not read block ${currentBlock}. Sense follows...\n{decSense.Value.SenseKey} {decSense.Value.Description}"); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Drive_could_not_read_block_0_Sense_follow_1_2, + currentBlock, + decSense.Value.SenseKey, + decSense.Value.Description)); - _dumpLog.WriteLine($"Drive could not read block ${currentBlock}. Sense follows..."); + _dumpLog.WriteLine(string.Format(Localization.Core.Drive_could_not_read_block_0_Sense_follows, + currentBlock)); - _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, - decSense.Value.ASC, decSense.Value.ASCQ); + _dumpLog.WriteLine(Localization.Core.Device_not_ready_Sense, + decSense.Value.SenseKey, + decSense.Value.ASC, + decSense.Value.ASCQ); } // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputTape.WriteSector(new byte[blockSize], currentBlock); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; mhddLog.Write(currentBlock, duration < 500 ? 65535 : duration); ibgLog.Write(currentBlock, 0); @@ -1042,29 +1171,30 @@ partial class Dump { mhddLog.Write(currentBlock, duration); ibgLog.Write(currentBlock, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputTape.WriteSector(cmdBuf, currentBlock); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(currentBlock, 1, true); } + _writeStopwatch.Stop(); currentBlock++; _resume.NextBlock++; currentSpeedSize += blockSize; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || currentSpeedSize < 524288) continue; currentSpeed = currentSpeedSize / (1048576 * elapsed); currentSpeedSize = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); blocks = currentBlock + 1; - end = DateTime.UtcNow; + _speedStopwatch.Stop(); + _dumpStopwatch.Stop(); // If not aborted this is added at the end of medium if(_aborted) @@ -1079,36 +1209,49 @@ partial class Dump EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), _devicePath); + ibgLog.Close(_dev, + blocks, + blockSize, + _dumpStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), + _devicePath); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - #region Error handling - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _retryPasses > 0 && - (canLocate || canLocateLong)) +#region Error handling + + if(_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0 && (canLocate || canLocateLong)) { - var pass = 1; - var forward = false; - var runningPersistent = false; + var pass = 1; + var forward = false; + const bool runningPersistent = false; - Modes.ModePage? currentModePage = null; + Modes.ModePage? currentModePage; if(_persistent) { @@ -1124,18 +1267,37 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke(string.Format("Retrying block {0}, pass {1}, {3}{2}", badBlock, pass, - forward ? "forward" : "reverse", - runningPersistent ? "recovering partial data, " : "")); + if(forward) + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_forward, + badBlock, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_forward, + badBlock, + pass)); + } + else + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_reverse, + badBlock, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_reverse, + badBlock, + pass)); + } - UpdateStatus?.Invoke($"Positioning tape to block {badBlock}."); - _dumpLog.WriteLine($"Positioning tape to block {badBlock}."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Positioning_tape_to_block_0, badBlock)); + _dumpLog.WriteLine(string.Format(Localization.Core.Positioning_tape_to_block_0, badBlock)); if(canLocateLong) { @@ -1147,8 +1309,8 @@ partial class Dump if(sense) { - _dumpLog.WriteLine("Could not check current position, continuing."); - StoppingErrorMessage?.Invoke("Could not check current position, continuing."); + _dumpLog.WriteLine(Localization.Core.Could_not_check_current_position_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_check_current_position_continuing); continue; } @@ -1157,16 +1319,20 @@ partial class Dump if(position != _resume.NextBlock) { - _dumpLog.WriteLine("Current position is not as expected, continuing."); - StoppingErrorMessage?.Invoke("Current position is not as expected, continuing."); + _dumpLog.WriteLine(Localization.Core.Current_position_is_not_as_expected_continuing); + + StoppingErrorMessage?.Invoke(Localization.Core + .Current_position_is_not_as_expected_continuing); continue; } } else { - _dumpLog.WriteLine($"Cannot position tape to block {badBlock}."); - ErrorMessage?.Invoke($"Cannot position tape to block {badBlock}."); + _dumpLog.WriteLine(string.Format(Localization.Core.Cannot_position_tape_to_block_0, badBlock)); + + ErrorMessage?.Invoke(string.Format(Localization.Core.Cannot_position_tape_to_block_0, + badBlock)); continue; } @@ -1181,8 +1347,8 @@ partial class Dump if(sense) { - _dumpLog.WriteLine("Could not check current position, continuing."); - StoppingErrorMessage?.Invoke("Could not check current position, continuing."); + _dumpLog.WriteLine(Localization.Core.Could_not_check_current_position_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_check_current_position_continuing); continue; } @@ -1191,49 +1357,58 @@ partial class Dump if(position != _resume.NextBlock) { - _dumpLog.WriteLine("Current position is not as expected, continuing."); - StoppingErrorMessage?.Invoke("Current position is not as expected, continuing."); + _dumpLog.WriteLine(Localization.Core.Current_position_is_not_as_expected_continuing); + + StoppingErrorMessage?.Invoke(Localization.Core + .Current_position_is_not_as_expected_continuing); continue; } } else { - _dumpLog.WriteLine($"Cannot position tape to block {badBlock}."); - ErrorMessage?.Invoke($"Cannot position tape to block {badBlock}."); + _dumpLog.WriteLine(string.Format(Localization.Core.Cannot_position_tape_to_block_0, badBlock)); + + ErrorMessage?.Invoke(string.Format(Localization.Core.Cannot_position_tape_to_block_0, + badBlock)); continue; } } - sense = _dev.Read6(out cmdBuf, out senseBuf, false, fixedLen, transferLen, blockSize, _dev.Timeout, + sense = _dev.Read6(out cmdBuf, + out senseBuf, + false, + fixedLen, + transferLen, + blockSize, + _dev.Timeout, out duration); totalDuration += duration; - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { _resume.BadBlocks.Remove(badBlock); extents.Add(badBlock); outputTape.WriteSector(cmdBuf, badBlock); - UpdateStatus?.Invoke($"Correctly retried block {badBlock} in pass {pass}."); - _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badBlock, pass); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_block_0_in_pass_1, + badBlock, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_block_0_in_pass_1, badBlock, pass); } - else if(runningPersistent) - outputTape.WriteSector(cmdBuf, badBlock); + else if(runningPersistent) outputTape.WriteSector(cmdBuf, badBlock); } - if(pass < _retryPasses && - !_aborted && - _resume.BadBlocks.Count > 0) + if(pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); - if(!forward) - _resume.BadBlocks.Reverse(); + if(!forward) _resume.BadBlocks.Reverse(); goto repeatRetry; } @@ -1245,51 +1420,57 @@ partial class Dump EndProgress?.Invoke(); } - #endregion Error handling + +#endregion Error handling _resume.BadBlocks.Sort(); - foreach(ulong bad in _resume.BadBlocks) - _dumpLog.WriteLine("Block {0} could not be read.", bad); + foreach(ulong bad in _resume.BadBlocks) _dumpLog.WriteLine(Localization.Core.Block_0_could_not_be_read, bad); currentTry.Extents = ExtentsConverter.ToMetadata(extents); outputTape.SetDumpHardware(_resume.Tries); // TODO: Media Serial Number - var metadata = new ImageInfo + var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; - if(!outputTape.SetMetadata(metadata)) - ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + + if(!outputTape.SetImageInfo(metadata)) + { + ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + + Environment.NewLine + outputTape.ErrorMessage); + } - if(_preSidecar != null) - outputTape.SetCicmMetadata(_preSidecar); + if(_preSidecar != null) outputTape.SetMetadata(_preSidecar); - _dumpLog.WriteLine("Closing output file."); - UpdateStatus?.Invoke("Closing output file."); - DateTime closeStart = DateTime.Now; + _dumpLog.WriteLine(Localization.Core.Closing_output_file); + UpdateStatus?.Invoke(Localization.Core.Closing_output_file); + _imageCloseStopwatch.Restart(); outputTape.Close(); - DateTime closeEnd = DateTime.Now; - UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); - _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); + _imageCloseStopwatch.Stop(); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); return; } if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); return; } @@ -1298,21 +1479,20 @@ partial class Dump if(_metadata) { - UpdateStatus?.Invoke("Creating sidecar."); - _dumpLog.WriteLine("Creating sidecar."); - var filters = new FiltersList(); - IFilter filter = filters.GetFilter(_outputPath); + UpdateStatus?.Invoke(Localization.Core.Creating_sidecar); + _dumpLog.WriteLine(Localization.Core.Creating_sidecar); + IFilter filter = PluginRegister.Singleton.GetFilter(_outputPath); var inputPlugin = ImageFormat.Detect(filter) as IMediaImage; ErrorNumber opened = inputPlugin.Open(filter); if(opened != ErrorNumber.NoError) { - StoppingErrorMessage?.Invoke($"Error {opened} opening created image."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_0_opening_created_image, opened)); return; } - DateTime chkStart = DateTime.UtcNow; + _sidecarStopwatch.Restart(); _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); _sidecarClass.InitProgressEvent += InitProgress; _sidecarClass.UpdateProgressEvent += UpdateProgress; @@ -1321,103 +1501,138 @@ partial class Dump _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; - CICMMetadataType sidecar = _sidecarClass.Create(); - end = DateTime.UtcNow; + Metadata sidecar = _sidecarClass.Create(); + _sidecarStopwatch.Stop(); if(!_aborted) { - totalChkDuration = (end - chkStart).TotalMilliseconds; - UpdateStatus?.Invoke($"Sidecar created in {(end - chkStart).TotalSeconds} seconds."); + totalChkDuration = _sidecarStopwatch.ElapsedMilliseconds; - UpdateStatus?. - Invoke($"Average checksum speed {blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); + _dumpLog.WriteLine(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); + + _dumpLog.WriteLine(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize()); if(_preSidecar != null) { - _preSidecar.BlockMedia = sidecar.BlockMedia; - sidecar = _preSidecar; + _preSidecar.BlockMedias = sidecar.BlockMedias; + sidecar = _preSidecar; } - List<(ulong start, string type)> filesystems = new(); + List<(ulong start, string type)> filesystems = []; - if(sidecar.BlockMedia[0].FileSystemInformation != null) - filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation - where partition.FileSystems != null from fileSystem in partition.FileSystems + if(sidecar.BlockMedias[0].FileSystemInformation != null) + { + filesystems.AddRange(from partition in sidecar.BlockMedias[0].FileSystemInformation + where partition.FileSystems != null + from fileSystem in partition.FileSystems select (partition.StartSector, fileSystem.Type)); + } if(filesystems.Count > 0) + { foreach(var filesystem in filesystems.Select(o => new - { - o.start, - o.type - }).Distinct()) + { + o.start, + o.type + }) + .Distinct()) { - UpdateStatus?.Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}"); - _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start); - } + UpdateStatus?.Invoke(string.Format(Localization.Core.Found_filesystem_0_at_sector_1, + filesystem.type, + filesystem.start)); - sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(dskType); + _dumpLog.WriteLine(Localization.Core.Found_filesystem_0_at_sector_1, + filesystem.type, + filesystem.start); + } + } + + sidecar.BlockMedias[0].Dimensions = Dimensions.FromMediaType(dskType); (string type, string subType) xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType); - sidecar.BlockMedia[0].DiskType = xmlType.type; - sidecar.BlockMedia[0].DiskSubType = xmlType.subType; + sidecar.BlockMedias[0].MediaType = xmlType.type; + sidecar.BlockMedias[0].MediaSubType = xmlType.subType; // TODO: Implement device firmware revision - if(!_dev.IsRemovable || - _dev.IsUsb) + if(!_dev.IsRemovable || _dev.IsUsb) + { if(_dev.Type == DeviceType.ATAPI) - sidecar.BlockMedia[0].Interface = "ATAPI"; + sidecar.BlockMedias[0].Interface = "ATAPI"; else if(_dev.IsUsb) - sidecar.BlockMedia[0].Interface = "USB"; + sidecar.BlockMedias[0].Interface = "USB"; else if(_dev.IsFireWire) - sidecar.BlockMedia[0].Interface = "FireWire"; + sidecar.BlockMedias[0].Interface = "FireWire"; else - sidecar.BlockMedia[0].Interface = "SCSI"; + sidecar.BlockMedias[0].Interface = "SCSI"; + } - sidecar.BlockMedia[0].LogicalBlocks = blocks; - sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer; - sidecar.BlockMedia[0].Model = _dev.Model; + sidecar.BlockMedias[0].LogicalBlocks = blocks; + sidecar.BlockMedias[0].Manufacturer = _dev.Manufacturer; + sidecar.BlockMedias[0].Model = _dev.Model; - if(!_private) - sidecar.BlockMedia[0].Serial = _dev.Serial; + if(!_private) sidecar.BlockMedias[0].Serial = _dev.Serial; - sidecar.BlockMedia[0].Size = blocks * blockSize; + sidecar.BlockMedias[0].Size = blocks * blockSize; - if(_dev.IsRemovable) - sidecar.BlockMedia[0].DumpHardwareArray = _resume.Tries.ToArray(); + if(_dev.IsRemovable) sidecar.BlockMedias[0].DumpHardware = _resume.Tries; - UpdateStatus?.Invoke("Writing metadata sidecar"); + UpdateStatus?.Invoke(Localization.Core.Writing_metadata_sidecar); - var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); + var jsonFs = new FileStream(_outputPrefix + ".metadata.json", FileMode.Create); - var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); - xmlSer.Serialize(xmlFs, sidecar); - xmlFs.Close(); + JsonSerializer.Serialize(jsonFs, + new MetadataJson + { + AaruMetadata = sidecar + }, + typeof(MetadataJson), + MetadataJsonContext.Default); + + jsonFs.Close(); } } UpdateStatus?.Invoke(""); - UpdateStatus?. - Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second), + totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second), + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average speed: {blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); if(maxSpeed > 0) - UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0, + ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize())); + } - if(minSpeed > 0 && - minSpeed < double.MaxValue) - UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); + if(minSpeed is > 0 and < double.MaxValue) + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0, + ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize())); + } - UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); + UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_could_not_be_read, _resume.BadBlocks.Count)); UpdateStatus?.Invoke(""); Statistics.AddMedia(dskType, true); diff --git a/Aaru.Core/Devices/Dumping/Sbc/Cache.cs b/Aaru.Core/Devices/Dumping/Sbc/Cache.cs new file mode 100644 index 000000000..7167c7a9c --- /dev/null +++ b/Aaru.Core/Devices/Dumping/Sbc/Cache.cs @@ -0,0 +1,209 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Cache.cs +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright © 2020-2024 Rebecca Wallander +// ****************************************************************************/ + +using System.Linq; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Extents; +using Aaru.CommonTypes.Interfaces; +using Aaru.Core.Logging; +using Aaru.Decryption.DVD; +using Humanizer; +using Humanizer.Bytes; + +// ReSharper disable JoinDeclarationAndInitializer +// ReSharper disable InlineOutVariableDeclaration +// ReSharper disable TooWideLocalVariableScope + +namespace Aaru.Core.Devices.Dumping; + +partial class Dump +{ + /// + /// Dumps data when dumping from a SCSI Block Commands compliant device, + /// and reads the data from the device cache + /// + /// Media blocks + /// Maximum number of blocks to read in a single command + /// Block size in bytes + /// Resume information + /// Correctly dump extents + /// Current speed + /// Minimum speed + /// Maximum speed + /// Total time spent in commands + /// SCSI reader + /// MHDD log + /// ImgBurn log + /// Total time spent writing to image + /// Set if we need to start a trim + /// The DVD disc key + void ReadCacheData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, DumpHardware currentTry, + ExtentsULong extents, ref double currentSpeed, ref double minSpeed, ref double maxSpeed, + ref double totalDuration, Reader scsiReader, MhddLog mhddLog, IbgLog ibgLog, + ref double imageWriteDuration, ref bool newTrim, byte[] discKey) + { + ulong sectorSpeedStart = 0; + bool sense; + byte[] buffer; + uint blocksToRead = maxBlocksToRead; + var outputFormat = _outputPlugin as IWritableImage; + + InitProgress?.Invoke(); + + if(scsiReader.HldtstReadRaw && _resume.NextBlock > 0) + + // The HL-DT-ST buffer is stored and read in 96-sector chunks. If we start to read at an LBA which is + // not modulo 96, the data will not be correctly fetched. Therefore, we begin every resume read with + // filling the buffer at a known offset. + // TODO: This is very ugly and there probably exist a more elegant way to solve this issue. + scsiReader.ReadBlock(out _, _resume.NextBlock - _resume.NextBlock % 96 + 1, out _, out _, out _); + + for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead) + { + if(_aborted) + { + currentTry.Extents = ExtentsConverter.ToMetadata(extents); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); + + break; + } + + if(blocks - i < blocksToRead) blocksToRead = (uint)(blocks - i); + + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; + + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; + + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, + (long)blocks); + + sense = scsiReader.ReadBlocks(out buffer, i, blocksToRead, out double cmdDuration, out _, out _); + totalDuration += cmdDuration; + + if(!sense && !_dev.Error) + { + mhddLog.Write(i, cmdDuration, blocksToRead); + ibgLog.Write(i, currentSpeed * 1024); + + _writeStopwatch.Restart(); + + byte[] tmpBuf; + var cmi = new byte[blocksToRead]; + + for(uint j = 0; j < blocksToRead; j++) + { + byte[] key = buffer.Skip((int)(2064 * j + 7)).Take(5).ToArray(); + + if(key.All(static k => k == 0)) + { + outputFormat.WriteSectorTag([0, 0, 0, 0, 0], i + j, SectorTagType.DvdTitleKeyDecrypted); + + _resume.MissingTitleKeys?.Remove(i + j); + + continue; + } + + CSS.DecryptTitleKey(discKey, key, out tmpBuf); + outputFormat.WriteSectorTag(tmpBuf, i + j, SectorTagType.DvdTitleKeyDecrypted); + _resume.MissingTitleKeys?.Remove(i + j); + + if(_storeEncrypted) continue; + + cmi[j] = buffer[2064 * j + 6]; + } + + // Todo: Flag in the outputFormat that a sector has been decrypted + if(!_storeEncrypted) + { + ErrorNumber errno = + outputFormat.ReadSectorsTag(i, + blocksToRead, + SectorTagType.DvdTitleKeyDecrypted, + out byte[] titleKey); + + if(errno != ErrorNumber.NoError) + { + ErrorMessage?.Invoke(string.Format(Localization.Core.Error_retrieving_title_key_for_sector_0, + i)); + } + else + buffer = CSS.DecryptSectorLong(buffer, titleKey, cmi, blocksToRead); + } + + outputFormat.WriteSectorsLong(buffer, i, blocksToRead); + + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + extents.Add(i, blocksToRead, true); + _mediaGraph?.PaintSectorsGood(i, blocksToRead); + } + else + { + // TODO: Reset device after X errors + if(_stopOnError) return; // TODO: Return more cleanly + + if(i + _skip > blocks) _skip = (uint)(blocks - i); + + // Write empty data + _writeStopwatch.Restart(); + outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip); + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + + for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b); + + mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip); + + ibgLog.Write(i, 0); + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i); + i += _skip - blocksToRead; + newTrim = true; + } + + _writeStopwatch.Stop(); + sectorSpeedStart += blocksToRead; + _resume.NextBlock = i + blocksToRead; + + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; + + if(elapsed <= 0) continue; + + currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); + sectorSpeedStart = 0; + _speedStopwatch.Restart(); + } + + _speedStopwatch.Stop(); + _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); + + EndProgress?.Invoke(); + } +} \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/Sbc/Data.cs b/Aaru.Core/Devices/Dumping/Sbc/Data.cs index 9a990cc2f..090d0748d 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Data.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Data.cs @@ -21,20 +21,13 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// Copyright © 2020-2022 Rebecca Wallander +// Copyright © 2011-2024 Natalia Portillo +// Copyright © 2020-2024 Rebecca Wallander // ****************************************************************************/ -using DVDDecryption = Aaru.Decryption.DVD.Dump; - -// ReSharper disable JoinDeclarationAndInitializer -// ReSharper disable InlineOutVariableDeclaration -// ReSharper disable TooWideLocalVariableScope - -namespace Aaru.Core.Devices.Dumping; - using System; using System.Linq; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; @@ -42,8 +35,15 @@ using Aaru.Core.Logging; using Aaru.Decoders.DVD; using Aaru.Decryption; using Aaru.Decryption.DVD; -using Aaru.Settings; -using Schemas; +using Humanizer; +using Humanizer.Bytes; +using DVDDecryption = Aaru.Decryption.DVD.Dump; + +// ReSharper disable JoinDeclarationAndInitializer +// ReSharper disable InlineOutVariableDeclaration +// ReSharper disable TooWideLocalVariableScope + +namespace Aaru.Core.Devices.Dumping; partial class Dump { @@ -64,59 +64,56 @@ partial class Dump /// Set if we need to start a trim /// DVD CSS decryption module /// The DVD disc key - void ReadSbcData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, DumpHardwareType currentTry, + void ReadSbcData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, DumpHardware currentTry, ExtentsULong extents, ref double currentSpeed, ref double minSpeed, ref double maxSpeed, - ref double totalDuration, Reader scsiReader, MhddLog mhddLog, IbgLog ibgLog, - ref double imageWriteDuration, ref bool newTrim, ref DVDDecryption dvdDecrypt, byte[] discKey) + ref double totalDuration, Reader scsiReader, MhddLog mhddLog, IbgLog ibgLog, + ref double imageWriteDuration, ref bool newTrim, ref DVDDecryption dvdDecrypt, byte[] discKey) { - ulong sectorSpeedStart = 0; - bool sense; - DateTime timeSpeedStart = DateTime.UtcNow; - byte[] buffer; - uint blocksToRead = maxBlocksToRead; - var outputFormat = _outputPlugin as IWritableImage; + ulong sectorSpeedStart = 0; + bool sense; + byte[] buffer; + uint blocksToRead = maxBlocksToRead; + var outputFormat = _outputPlugin as IWritableImage; InitProgress?.Invoke(); + _speedStopwatch.Reset(); for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead) { if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(blocks - i < blocksToRead) - blocksToRead = (uint)(blocks - i); + if(blocks - i < blocksToRead) blocksToRead = (uint)(blocks - i); - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)blocks); + _speedStopwatch.Start(); sense = scsiReader.ReadBlocks(out buffer, i, blocksToRead, out double cmdDuration, out _, out _); totalDuration += cmdDuration; + _speedStopwatch.Stop(); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { - if(Settings.Current.EnableDecryption && - discKey != null && - _titleKeys) + if(Settings.Settings.Current.EnableDecryption && discKey != null && _titleKeys) { for(ulong j = 0; j < blocksToRead; j++) { - if(_aborted) - break; + if(_aborted) break; if(!_resume.MissingTitleKeys.Contains(i + j)) @@ -125,65 +122,40 @@ partial class Dump byte[] tmpBuf; - bool tmpSense = dvdDecrypt.ReadTitleKey(out tmpBuf, out _, DvdCssKeyClass.DvdCssCppmOrCprm, - i + j, _dev.Timeout, out _); + bool tmpSense = dvdDecrypt.ReadTitleKey(out tmpBuf, + out _, + DvdCssKeyClass.DvdCssCppmOrCprm, + i + j, + _dev.Timeout, + out _); - if(!tmpSense) + if(tmpSense) continue; + + CSS_CPRM.TitleKey? titleKey = CSS.DecodeTitleKey(tmpBuf, dvdDecrypt.BusKey); + + if(titleKey.HasValue) + outputFormat.WriteSectorTag([titleKey.Value.CMI], i + j, SectorTagType.DvdSectorCmi); + else + continue; + + // According to libdvdcss, if the key is all zeroes, the sector is actually + // not encrypted even if the CMI says it is. + if(titleKey.Value.Key.All(static k => k == 0)) { - CSS_CPRM.TitleKey? titleKey = CSS.DecodeTitleKey(tmpBuf, dvdDecrypt.BusKey); + outputFormat.WriteSectorTag([0, 0, 0, 0, 0], i + j, SectorTagType.DvdSectorTitleKey); - if(titleKey.HasValue) - outputFormat.WriteSectorTag(new[] - { - titleKey.Value.CMI - }, i + j, SectorTagType.DvdCmi); - else - continue; + outputFormat.WriteSectorTag([0, 0, 0, 0, 0], i + j, SectorTagType.DvdTitleKeyDecrypted); - // If the CMI bit is 1, the sector is using copy protection, else it is not - if((titleKey.Value.CMI & 0x80) >> 7 == 0) - { - // The CMI indicates this sector is not encrypted. - outputFormat.WriteSectorTag(new byte[] - { - 0, 0, 0, 0, 0 - }, i + j, SectorTagType.DvdTitleKey); + _resume.MissingTitleKeys.Remove(i + j); - outputFormat.WriteSectorTag(new byte[] - { - 0, 0, 0, 0, 0 - }, i + j, SectorTagType.DvdTitleKeyDecrypted); - - _resume.MissingTitleKeys.Remove(i + j); - - continue; - } - - // According to libdvdcss, if the key is all zeroes, the sector is actually - // not encrypted even if the CMI says it is. - if(titleKey.Value.Key.All(k => k == 0)) - { - outputFormat.WriteSectorTag(new byte[] - { - 0, 0, 0, 0, 0 - }, i + j, SectorTagType.DvdTitleKey); - - outputFormat.WriteSectorTag(new byte[] - { - 0, 0, 0, 0, 0 - }, i + j, SectorTagType.DvdTitleKeyDecrypted); - - _resume.MissingTitleKeys.Remove(i + j); - - continue; - } - - outputFormat.WriteSectorTag(titleKey.Value.Key, i + j, SectorTagType.DvdTitleKey); - _resume.MissingTitleKeys.Remove(i + j); - - CSS.DecryptTitleKey(0, discKey, titleKey.Value.Key, out tmpBuf); - outputFormat.WriteSectorTag(tmpBuf, i + j, SectorTagType.DvdTitleKeyDecrypted); + continue; } + + outputFormat.WriteSectorTag(titleKey.Value.Key, i + j, SectorTagType.DvdSectorTitleKey); + _resume.MissingTitleKeys.Remove(i + j); + + CSS.DecryptTitleKey(discKey, titleKey.Value.Key, out tmpBuf); + outputFormat.WriteSectorTag(tmpBuf, i + j, SectorTagType.DvdTitleKeyDecrypted); } if(!_storeEncrypted) @@ -191,84 +163,89 @@ partial class Dump // Todo: Flag in the outputFormat that a sector has been decrypted { ErrorNumber errno = - outputFormat.ReadSectorsTag(i, blocksToRead, SectorTagType.DvdCmi, out byte[] cmi); + outputFormat.ReadSectorsTag(i, blocksToRead, SectorTagType.DvdSectorCmi, out byte[] cmi); if(errno != ErrorNumber.NoError) - ErrorMessage?.Invoke($"Error retrieving CMI for sector {i}"); + ErrorMessage?.Invoke(string.Format(Localization.Core.Error_retrieving_CMI_for_sector_0, i)); else { - errno = outputFormat.ReadSectorsTag(i, blocksToRead, SectorTagType.DvdTitleKeyDecrypted, + errno = outputFormat.ReadSectorsTag(i, + blocksToRead, + SectorTagType.DvdTitleKeyDecrypted, out byte[] titleKey); if(errno != ErrorNumber.NoError) - ErrorMessage?.Invoke($"Error retrieving title key for sector {i}"); + { + ErrorMessage?.Invoke(string.Format(Localization.Core + .Error_retrieving_title_key_for_sector_0, + i)); + } else - buffer = CSS.DecryptSector(buffer, cmi, titleKey, blocksToRead, blockSize); + buffer = CSS.DecryptSector(buffer, titleKey, cmi, blocksToRead, blockSize); } } } - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, cmdDuration, blocksToRead); ibgLog.Write(i, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(buffer, i, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(i, blocksToRead, true); + _mediaGraph?.PaintSectorsGood(i, blocksToRead); } else { - if(_dev.Manufacturer.ToLowerInvariant() == "insite") + if(_dev.Manufacturer.Equals("insite", StringComparison.InvariantCultureIgnoreCase)) { _resume.BadBlocks.Add(i); _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); _resume.NextBlock++; _aborted = true; - _dumpLog?. - WriteLine("INSITE floptical drives get crazy on the SCSI bus when an error is found, stopping so you can reboot the computer or reset the scsi bus appropriately."); + _dumpLog?.WriteLine(Localization.Core + .INSITE_floptical_drives_get_crazy_on_the_SCSI_bus_when_an_error_is_found); - UpdateStatus?. - Invoke("INSITE floptical drives get crazy on the SCSI bus when an error is found, stopping so you can reboot the computer or reset the scsi bus appropriately"); + UpdateStatus?.Invoke(Localization.Core + .INSITE_floptical_drives_get_crazy_on_the_SCSI_bus_when_an_error_is_found); continue; } // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly - if(i + _skip > blocks) - _skip = (uint)(blocks - i); + if(i + _skip > blocks) _skip = (uint)(blocks - i); // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; - for(ulong b = i; b < i + _skip; b++) - _resume.BadBlocks.Add(b); + for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b); - mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); + mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip); ibgLog.Write(i, 0); - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i); i += _skip - blocksToRead; newTrim = true; } + _writeStopwatch.Stop(); sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } + _speedStopwatch.Stop(); _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); EndProgress?.Invoke(); diff --git a/Aaru.Core/Devices/Dumping/Sbc/Dump.cs b/Aaru.Core/Devices/Dumping/Sbc/Dump.cs index acf4d4e3e..65d7a5599 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Dump.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Dump.cs @@ -27,42 +27,43 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// Copyright © 2020-2022 Rebecca Wallander +// Copyright © 2011-2024 Natalia Portillo +// Copyright © 2020-2024 Rebecca Wallander // ****************************************************************************/ -using DVDDecryption = Aaru.Decryption.DVD.Dump; - -// ReSharper disable JoinDeclarationAndInitializer - -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Xml.Serialization; +using System.Text.Json; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Metadata; -using Aaru.CommonTypes.Structs; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Console; +using Aaru.Core.Devices.Report; +using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Core.Media.Detection; +using Aaru.Decoders.Bluray; using Aaru.Decoders.DVD; using Aaru.Decoders.SCSI; using Aaru.Decoders.SCSI.MMC; using Aaru.Devices; -using Aaru.Settings; -using Schemas; -using DeviceReport = Aaru.Core.Devices.Report.DeviceReport; -using MediaType = Aaru.CommonTypes.MediaType; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; +using DVDDecryption = Aaru.Decryption.DVD.Dump; +using Track = Aaru.CommonTypes.Structs.Track; using TrackType = Aaru.CommonTypes.Enums.TrackType; using Version = Aaru.CommonTypes.Interop.Version; +// ReSharper disable JoinDeclarationAndInitializer + +namespace Aaru.Core.Devices.Dumping; + /// Implements dumping SCSI Block Commands and Reduced Block Commands devices partial class Dump { @@ -72,37 +73,32 @@ partial class Dump /// Disc type as detected in SCSI or MMC layer /// DVD CSS decryption module void Sbc(Dictionary mediaTags, MediaType dskType, bool opticalDisc, - DVDDecryption dvdDecrypt = null) + DVDDecryption dvdDecrypt = null) { bool sense; byte scsiMediumType = 0; byte scsiDensityCode = 0; var containsFloppyPage = false; const ushort sbcProfile = 0x0001; - DateTime start; - DateTime end; - double totalDuration = 0; - double currentSpeed = 0; - double maxSpeed = double.MinValue; - double minSpeed = double.MaxValue; - byte[] readBuffer; - Modes.DecodedMode? decMode = null; + double totalDuration = 0; + double currentSpeed = 0; + double maxSpeed = double.MinValue; + double minSpeed = double.MaxValue; + Modes.DecodedMode? decMode = null; bool ret; ExtentsULong blankExtents = null; var outputFormat = _outputPlugin as IWritableImage; if(opticalDisc) - switch(dskType) - { - case MediaType.REV35: - case MediaType.REV70: - case MediaType.REV120: - opticalDisc = false; + { + opticalDisc = dskType switch + { + MediaType.REV35 or MediaType.REV70 or MediaType.REV120 => false, + _ => true + }; + } - break; - } - - _dumpLog.WriteLine("Initializing reader."); + _dumpLog.WriteLine(Localization.Core.Initializing_reader); var scsiReader = new Reader(_dev, _dev.Timeout, null, _errorLog, _dumpRaw); ulong blocks = scsiReader.GetDeviceBlocks(); uint blockSize = scsiReader.LogicalBlockSize; @@ -111,85 +107,118 @@ partial class Dump { mediaTags = new Dictionary(); - if(_dev.IsUsb && - _dev.UsbDescriptors != null) - mediaTags.Add(MediaTagType.USB_Descriptors, null); + if(_dev.IsUsb && _dev.UsbDescriptors != null) mediaTags.Add(MediaTagType.USB_Descriptors, null); - if(_dev.Type == DeviceType.ATAPI) - mediaTags.Add(MediaTagType.ATAPI_IDENTIFY, null); + if(_dev.Type == DeviceType.ATAPI) mediaTags.Add(MediaTagType.ATAPI_IDENTIFY, null); - if(_dev.IsPcmcia && - _dev.Cis != null) - mediaTags.Add(MediaTagType.PCMCIA_CIS, null); + if(_dev.IsPcmcia && _dev.Cis != null) mediaTags.Add(MediaTagType.PCMCIA_CIS, null); sense = _dev.ScsiInquiry(out byte[] cmdBuf, out _); - if(_private) - cmdBuf = DeviceReport.ClearInquiry(cmdBuf); + if(_private) cmdBuf = DeviceReport.ClearInquiry(cmdBuf); mediaTags.Add(MediaTagType.SCSI_INQUIRY, cmdBuf); if(!sense) { - _dumpLog.WriteLine("Requesting MODE SENSE (10)."); - UpdateStatus?.Invoke("Requesting MODE SENSE (10)."); + _dumpLog.WriteLine(Localization.Core.Requesting_MODE_SENSE_10); + UpdateStatus?.Invoke(Localization.Core.Requesting_MODE_SENSE_10); - sense = _dev.ModeSense10(out cmdBuf, out _, false, true, ScsiModeSensePageControl.Current, 0x3F, 0xFF, - 5, out _); + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0xFF, + 5, + out _); - if(!sense || - _dev.Error) - sense = _dev.ModeSense10(out cmdBuf, out _, false, true, ScsiModeSensePageControl.Current, 0x3F, - 0x00, 5, out _); + if(!sense || _dev.Error) + { + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, + out _); + } - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) + { if(Modes.DecodeMode10(cmdBuf, _dev.ScsiType).HasValue) { mediaTags.Add(MediaTagType.SCSI_MODESENSE_10, cmdBuf); decMode = Modes.DecodeMode10(cmdBuf, _dev.ScsiType); } + } - _dumpLog.WriteLine("Requesting MODE SENSE (6)."); - UpdateStatus?.Invoke("Requesting MODE SENSE (6)."); + _dumpLog.WriteLine(Localization.Core.Requesting_MODE_SENSE_6); + UpdateStatus?.Invoke(Localization.Core.Requesting_MODE_SENSE_6); - sense = _dev.ModeSense6(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, + sense = _dev.ModeSense6(out cmdBuf, + out _, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, out _); if(sense || _dev.Error) - sense = _dev.ModeSense6(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, + { + sense = _dev.ModeSense6(out cmdBuf, + out _, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, out _); + } - if(sense || _dev.Error) - sense = _dev.ModeSense(out cmdBuf, out _, 5, out _); + if(sense || _dev.Error) sense = _dev.ModeSense(out cmdBuf, out _, 5, out _); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) + { if(Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue) { mediaTags.Add(MediaTagType.SCSI_MODESENSE_6, cmdBuf); decMode = Modes.DecodeMode6(cmdBuf, _dev.ScsiType); } + } if(decMode.HasValue) { - scsiMediumType = (byte)decMode.Value.Header.MediumType; + scsiMediumType = (byte)(decMode?.Header.MediumType ?? default(MediumTypes)); - if(decMode.Value.Header.BlockDescriptors?.Length > 0) - scsiDensityCode = (byte)decMode.Value.Header.BlockDescriptors[0].Density; + if(decMode?.Header.BlockDescriptors?.Length > 0) + scsiDensityCode = (byte)(decMode?.Header.BlockDescriptors[0].Density ?? default(DensityType)); // TODO: Fix this - containsFloppyPage = decMode.Value.Pages?.Aggregate(containsFloppyPage, - (current, modePage) => - current | (modePage.Page == 0x05)) == true; + containsFloppyPage = decMode?.Pages?.Aggregate(containsFloppyPage, + (current, modePage) => + current | modePage.Page == 0x05) == + true; } } } if(dskType == MediaType.Unknown) - dskType = MediaTypeFromDevice.GetFromScsi((byte)_dev.ScsiType, _dev.Manufacturer, _dev.Model, - scsiMediumType, scsiDensityCode, blocks + 1, blockSize, - _dev.IsUsb, opticalDisc); + { + dskType = MediaTypeFromDevice.GetFromScsi((byte)_dev.ScsiType, + _dev.Manufacturer, + _dev.Model, + scsiMediumType, + scsiDensityCode, + blocks + 1, + blockSize, + _dev.IsUsb, + opticalDisc); + } if(_dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice) MMC.DetectDiscType(ref dskType, 1, null, _dev, out _, out _, 0, blocks + 1); @@ -200,10 +229,11 @@ partial class Dump // SonicStage changes the device mode, so it is no longer a mass storage device, and can only read // tracks written by that same application ID (changes between computers). case MediaType.MD: - _dumpLog.WriteLine("MiniDisc albums, NetMD discs or user-written audio MiniDisc cannot be dumped."); + _dumpLog.WriteLine(Localization.Core + .MiniDisc_albums_NetMD_discs_or_user_written_audio_MiniDisc_cannot_be_dumped); - StoppingErrorMessage?. - Invoke("MiniDisc albums, NetMD discs or user-written audio MiniDisc cannot be dumped."); + StoppingErrorMessage?.Invoke(Localization.Core + .MiniDisc_albums_NetMD_discs_or_user_written_audio_MiniDisc_cannot_be_dumped); return; case MediaType.Unknown when _dev.IsUsb && containsFloppyPage: @@ -214,40 +244,26 @@ partial class Dump if(scsiReader.FindReadCommand()) { - _dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", scsiReader.ErrorMessage); - StoppingErrorMessage?.Invoke("Unable to read medium."); + _dumpLog.WriteLine(Localization.Core.ERROR_Cannot_find_correct_read_command_0, scsiReader.ErrorMessage); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_read_medium); return; } - if(blocks != 0 && - blockSize != 0) + if(blocks != 0 && blockSize != 0) { blocks++; - ulong totalSize = blocks * blockSize; - - if(totalSize > 1099511627776) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1099511627776d:F3} TiB)"); - else if(totalSize > 1073741824) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1073741824d:F3} GiB)"); - else if(totalSize > 1048576) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1048576d:F3} MiB)"); - else if(totalSize > 1024) - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1024d:F3} KiB)"); - else - UpdateStatus?. - Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize} bytes)"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_has_0_blocks_of_1_bytes_each_for_a_total_of_2, + blocks, + blockSize, + ByteSize.FromBytes(blocks * blockSize).ToString("0.000"))); } // Check how many blocks to read, if error show and return if(scsiReader.GetBlocksToRead(_maximumReadable)) { - _dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", scsiReader.ErrorMessage); + _dumpLog.WriteLine(Localization.Core.ERROR_Cannot_get_blocks_to_read_0, scsiReader.ErrorMessage); StoppingErrorMessage?.Invoke(scsiReader.ErrorMessage); return; @@ -259,94 +275,111 @@ partial class Dump if(blocks == 0) { - _dumpLog.WriteLine("ERROR: Unable to read medium or empty medium present..."); - StoppingErrorMessage?.Invoke("Unable to read medium or empty medium present..."); + _dumpLog.WriteLine(Localization.Core.ERROR_Unable_to_read_medium_or_empty_medium_present); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_read_medium_or_empty_medium_present); return; } - UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes)."); - UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time."); - UpdateStatus?.Invoke($"Device reports {blockSize} bytes per logical block."); - UpdateStatus?.Invoke($"Device reports {scsiReader.LongBlockSize} bytes per physical block."); - UpdateStatus?.Invoke($"SCSI device type: {_dev.ScsiType}."); - UpdateStatus?.Invoke($"SCSI medium type: {scsiMediumType}."); - UpdateStatus?.Invoke($"SCSI density type: {scsiDensityCode}."); - UpdateStatus?.Invoke($"SCSI floppy mode page present: {containsFloppyPage}."); - UpdateStatus?.Invoke($"Media identified as {dskType}"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_blocks_1_bytes, + blocks, + blocks * blockSize)); - _dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize); - _dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead); - _dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize); - _dumpLog.WriteLine("Device reports {0} bytes per physical block.", scsiReader.LongBlockSize); - _dumpLog.WriteLine("SCSI device type: {0}.", _dev.ScsiType); - _dumpLog.WriteLine("SCSI medium type: {0}.", scsiMediumType); - _dumpLog.WriteLine("SCSI density type: {0}.", scsiDensityCode); - _dumpLog.WriteLine("SCSI floppy mode page present: {0}.", containsFloppyPage); - _dumpLog.WriteLine("Media identified as {0}.", dskType); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize)); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_bytes_per_physical_block, + scsiReader.LongBlockSize)); + + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_device_type_0, _dev.ScsiType)); + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_medium_type_0, scsiMediumType)); + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_density_type_0, scsiDensityCode)); + UpdateStatus?.Invoke(string.Format(Localization.Core.SCSI_floppy_mode_page_present_0, containsFloppyPage)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Media_identified_as_0, dskType)); + + _dumpLog.WriteLine(Localization.Core.Device_reports_0_blocks_1_bytes, blocks, blocks * blockSize); + _dumpLog.WriteLine(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_bytes_per_logical_block, blockSize); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_bytes_per_physical_block, scsiReader.LongBlockSize); + _dumpLog.WriteLine(Localization.Core.SCSI_device_type_0, _dev.ScsiType); + _dumpLog.WriteLine(Localization.Core.SCSI_medium_type_0, scsiMediumType); + _dumpLog.WriteLine(Localization.Core.SCSI_density_type_0, scsiDensityCode); + _dumpLog.WriteLine(Localization.Core.SCSI_floppy_mode_page_present_0, containsFloppyPage); + _dumpLog.WriteLine(Localization.Core.Media_identified_as_0, dskType); uint longBlockSize = scsiReader.LongBlockSize; if(_dumpRaw) + { if(blockSize == longBlockSize) { ErrorMessage?.Invoke(!scsiReader.CanReadRaw - ? "Device doesn't seem capable of reading raw data from media." - : "Device is capable of reading raw data but I've been unable to guess correct sector size."); + ? Localization.Core.Device_doesnt_seem_capable_of_reading_raw_data_from_media + : Localization.Core + .Device_is_capable_of_reading_raw_data_but_Ive_been_unable_to_guess_correct_sector_size); if(!_force) { - StoppingErrorMessage?. - Invoke("Not continuing. If you want to continue reading cooked data when raw is not available use the force option."); + StoppingErrorMessage?.Invoke(Localization.Core + .If_you_want_to_continue_reading_cooked_data_when_raw_is_not_available_use_the_force_option); // TODO: Exit more gracefully return; } - ErrorMessage?.Invoke("Continuing dumping cooked data."); + ErrorMessage?.Invoke(Localization.Core.Continuing_dumping_cooked_data); } else { // Only a block will be read, but it contains 16 sectors and command expect sector number not block number blocksToRead = (uint)(longBlockSize == 37856 ? 16 : 1); - UpdateStatus?. - Invoke($"Reading {longBlockSize} raw bytes ({blockSize * blocksToRead} cooked bytes) per sector."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_raw_bytes_1_cooked_bytes_per_sector, + longBlockSize, + blockSize * blocksToRead)); physicalBlockSize = longBlockSize; blockSize = longBlockSize; } + } ret = true; foreach(MediaTagType tag in mediaTags.Keys.Where(tag => !outputFormat.SupportedMediaTags.Contains(tag))) { ret = false; - _dumpLog.WriteLine($"Output format does not support {tag}."); - ErrorMessage?.Invoke($"Output format does not support {tag}."); + _dumpLog.WriteLine(string.Format(Localization.Core.Output_format_does_not_support_0, tag)); + ErrorMessage?.Invoke(string.Format(Localization.Core.Output_format_does_not_support_0, tag)); } if(!ret) { if(_force) { - _dumpLog.WriteLine("Several media tags not supported, continuing..."); - ErrorMessage?.Invoke("Several media tags not supported, continuing..."); + _dumpLog.WriteLine(Localization.Core.Several_media_tags_not_supported_continuing); + ErrorMessage?.Invoke(Localization.Core.Several_media_tags_not_supported_continuing); } else { - _dumpLog.WriteLine("Several media tags not supported, not continuing..."); - StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Several_media_tags_not_supported_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Several_media_tags_not_supported_not_continuing); return; } } - UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time."); - _dumpLog.WriteLine("Reading {0} sectors at a time.", blocksToRead); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time, blocksToRead)); + _dumpLog.WriteLine(Localization.Core.Reading_0_sectors_at_a_time, blocksToRead); - var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private); - var ibgLog = new IbgLog(_outputPrefix + ".ibg", sbcProfile); + var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", + _dev, + blocks, + blockSize, + blocksToRead, + _private, + _dimensions); + + var ibgLog = new IbgLog(_outputPrefix + ".ibg", sbcProfile); var imageCreated = false; if(!opticalDisc) @@ -356,10 +389,11 @@ partial class Dump // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputFormat.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -368,7 +402,7 @@ partial class Dump imageCreated = true; } - start = DateTime.UtcNow; + _dumpStopwatch.Restart(); double imageWriteDuration = 0; var writeSingleOpticalTrack = true; @@ -376,8 +410,11 @@ partial class Dump { if(outputFormat is IWritableOpticalImage opticalPlugin) { - sense = _dev.ReadDiscInformation(out readBuffer, out _, MmcDiscInformationDataTypes.DiscInformation, - _dev.Timeout, out _); + sense = _dev.ReadDiscInformation(out byte[] readBuffer, + out _, + MmcDiscInformationDataTypes.DiscInformation, + _dev.Timeout, + out _); if(!sense) { @@ -395,24 +432,23 @@ partial class Dump { writeSingleOpticalTrack = false; - if(discInformation?.Sessions > 1 && - !canStoreNotCdSessions) + if(discInformation?.Sessions > 1 && !canStoreNotCdSessions) { if(_force) { - _dumpLog. - WriteLine("Image does not support multiple sessions in non Compact Disc dumps, continuing..."); + _dumpLog.WriteLine(Localization.Core + .Image_does_not_support_multiple_sessions_in_non_Compact_Disc_dumps_continuing); - ErrorMessage?. - Invoke("Image does not support multiple sessions in non Compact Disc dumps, continuing..."); + ErrorMessage?.Invoke(Localization.Core + .Image_does_not_support_multiple_sessions_in_non_Compact_Disc_dumps_continuing); } else { - _dumpLog. - WriteLine("Image does not support multiple sessions in non Compact Disc dumps, not continuing..."); + _dumpLog.WriteLine(Localization.Core + .Image_does_not_support_multiple_sessions_in_non_Compact_Disc_dumps_not_continuing); - StoppingErrorMessage?. - Invoke("Image does not support multiple sessions in non Compact Disc dumps, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Image_does_not_support_multiple_sessions_in_non_Compact_Disc_dumps_not_continuing); return; } @@ -424,51 +460,52 @@ partial class Dump { if(_force) { - _dumpLog. - WriteLine("Image does not support multiple tracks in non Compact Disc dumps, continuing..."); + _dumpLog.WriteLine(Localization.Core + .Image_does_not_support_multiple_tracks_in_non_Compact_Disc_dumps_continuing); - ErrorMessage?. - Invoke("Image does not support multiple tracks in non Compact Disc dumps, continuing..."); + ErrorMessage?.Invoke(Localization.Core + .Image_does_not_support_multiple_tracks_in_non_Compact_Disc_dumps_continuing); } else { - _dumpLog. - WriteLine("Image does not support multiple tracks in non Compact Disc dumps, not continuing..."); + _dumpLog.WriteLine(Localization.Core + .Image_does_not_support_multiple_tracks_in_non_Compact_Disc_dumps_not_continuing); - StoppingErrorMessage?. - Invoke("Image does not support multiple tracks in non Compact Disc dumps, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Image_does_not_support_multiple_tracks_in_non_Compact_Disc_dumps_not_continuing); return; } } - UpdateStatus?.Invoke("Building track map..."); - _dumpLog.WriteLine("Building track map..."); + UpdateStatus?.Invoke(Localization.Core.Building_track_map); + _dumpLog.WriteLine(Localization.Core.Building_track_map); - List tracks = new(); + List tracks = []; for(ushort tno = discInformation.Value.FirstTrackNumber; - tno <= discInformation?.LastTrackLastSession; tno++) + tno <= discInformation?.LastTrackLastSession; + tno++) { - sense = _dev.ReadTrackInformation(out readBuffer, out _, false, - TrackInformationType.LogicalTrackNumber, tno, - _dev.Timeout, out _); + sense = _dev.ReadTrackInformation(out readBuffer, + out _, + false, + TrackInformationType.LogicalTrackNumber, + tno, + _dev.Timeout, + out _); - if(sense) - continue; + if(sense) continue; var trkInfo = TrackInformation.Decode(readBuffer); - if(trkInfo is null) - continue; + if(trkInfo is null) continue; // Some drives return this invalid value with recordable discs - if(trkInfo.LogicalTrackNumber == 0) - continue; + if(trkInfo.LogicalTrackNumber == 0) continue; // Fixes a firmware bug in some DVD drives - if((int)trkInfo.LogicalTrackStartAddress < 0) - trkInfo.LogicalTrackStartAddress = 0; + if((int)trkInfo.LogicalTrackStartAddress < 0) trkInfo.LogicalTrackStartAddress = 0; // Some drives return this invalid value with recordable discs if(trkInfo.LogicalTrackSize == 0xFFFFFFFF) @@ -486,13 +523,13 @@ partial class Dump SubchannelType = TrackSubchannelType.None }; - if(track.EndSector >= blocks) - blocks = track.EndSector + 1; + if(track.EndSector >= blocks) blocks = track.EndSector + 1; tracks.Add(track); } if(tracks.Count == 0) + { tracks.Add(new Track { BytesPerSector = (int)blockSize, @@ -503,6 +540,7 @@ partial class Dump Session = 1, Type = TrackType.Data }); + } else tracks = tracks.OrderBy(t => t.Sequence).ToList(); @@ -511,22 +549,28 @@ partial class Dump // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputFormat.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + - Environment.NewLine + outputFormat.ErrorMessage); + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + + outputFormat.ErrorMessage); return; } imageCreated = true; - #if DEBUG +#if DEBUG foreach(Track trk in tracks) - UpdateStatus?. - Invoke($"Track {trk.Sequence} starts at LBA {trk.StartSector} and ends at LBA {trk.EndSector}"); - #endif + { + UpdateStatus?.Invoke(string.Format(Localization.Core + .Track_0_starts_at_LBA_1_and_ends_at_LBA_2, + trk.Sequence, + trk.StartSector, + trk.EndSector)); + } +#endif if(canStoreNotCdTracks) { @@ -534,36 +578,43 @@ partial class Dump if(!ret) { - _dumpLog.WriteLine("Error sending tracks to output image, not continuing."); + _dumpLog.WriteLine(Localization.Core + .Error_sending_tracks_to_output_image_not_continuing); + _dumpLog.WriteLine(opticalPlugin.ErrorMessage); - StoppingErrorMessage?.Invoke("Error sending tracks to output image, not continuing." + - Environment.NewLine + opticalPlugin.ErrorMessage); + StoppingErrorMessage?.Invoke(Localization.Core + .Error_sending_tracks_to_output_image_not_continuing + + Environment.NewLine + + opticalPlugin.ErrorMessage); return; } } else - opticalPlugin.SetTracks(new List - { - new() - { - BytesPerSector = (int)blockSize, - EndSector = blocks - 1, - Sequence = 1, - RawBytesPerSector = (int)blockSize, - SubchannelType = TrackSubchannelType.None, - Session = 1, - Type = TrackType.Data - } - }); + { + opticalPlugin.SetTracks([ + new Track + { + BytesPerSector = (int)blockSize, + EndSector = blocks - 1, + Sequence = 1, + RawBytesPerSector = (int)blockSize, + SubchannelType = TrackSubchannelType.None, + Session = 1, + Type = TrackType.Data + } + ]); + } } } } else { - _dumpLog.WriteLine("The specified plugin does not support storing optical disc images.."); - StoppingErrorMessage?.Invoke("The specified plugin does not support storing optical disc images."); + _dumpLog.WriteLine(Localization.Core.The_specified_image_format_cannot_represent_optical_discs); + + StoppingErrorMessage?.Invoke(Localization.Core + .The_specified_image_format_cannot_represent_optical_discs); return; } @@ -573,46 +624,65 @@ partial class Dump var setGeometry = false; foreach(Modes.ModePage page in decMode.Value.Pages) - if(page.Page == 0x04 && - page.Subpage == 0x00) + { + switch(page.Page) { - Modes.ModePage_04? rigidPage = Modes.DecodeModePage_04(page.PageResponse); + case 0x04 when page.Subpage == 0x00: + { + Modes.ModePage_04? rigidPage = Modes.DecodeModePage_04(page.PageResponse); - if(!rigidPage.HasValue || setGeometry) - continue; + if(!rigidPage.HasValue || setGeometry) continue; - _dumpLog.WriteLine("Setting geometry to {0} cylinders, {1} heads, {2} sectors per track", - rigidPage.Value.Cylinders, rigidPage.Value.Heads, - (uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))); + _dumpLog.WriteLine(Localization.Core + .Setting_geometry_to_0_cylinders_1_heads_2_sectors_per_track, + rigidPage.Value.Cylinders, + rigidPage.Value.Heads, + (uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))); - UpdateStatus?. - Invoke($"Setting geometry to {rigidPage.Value.Cylinders} cylinders, {rigidPage.Value.Heads} heads, {(uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))} sectors per track"); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Setting_geometry_to_0_cylinders_1_heads_2_sectors_per_track, + rigidPage.Value.Cylinders, + rigidPage.Value.Heads, + (uint)(blocks / + (rigidPage.Value.Cylinders * + rigidPage.Value.Heads)))); - outputFormat.SetGeometry(rigidPage.Value.Cylinders, rigidPage.Value.Heads, - (uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))); + outputFormat.SetGeometry(rigidPage.Value.Cylinders, + rigidPage.Value.Heads, + (uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))); - setGeometry = true; - } - else if(page.Page == 0x05 && - page.Subpage == 0x00) - { - Modes.ModePage_05? flexiblePage = Modes.DecodeModePage_05(page.PageResponse); - - if(!flexiblePage.HasValue) - continue; - - _dumpLog.WriteLine("Setting geometry to {0} cylinders, {1} heads, {2} sectors per track", - flexiblePage.Value.Cylinders, flexiblePage.Value.Heads, - flexiblePage.Value.SectorsPerTrack); - - UpdateStatus?. - Invoke($"Setting geometry to {flexiblePage.Value.Cylinders} cylinders, {flexiblePage.Value.Heads} heads, {flexiblePage.Value.SectorsPerTrack} sectors per track"); - - outputFormat.SetGeometry(flexiblePage.Value.Cylinders, flexiblePage.Value.Heads, - flexiblePage.Value.SectorsPerTrack); - - setGeometry = true; + setGeometry = true; + + break; + } + case 0x05 when page.Subpage == 0x00: + { + Modes.ModePage_05? flexiblePage = Modes.DecodeModePage_05(page.PageResponse); + + if(!flexiblePage.HasValue) continue; + + _dumpLog.WriteLine(Localization.Core + .Setting_geometry_to_0_cylinders_1_heads_2_sectors_per_track, + flexiblePage.Value.Cylinders, + flexiblePage.Value.Heads, + flexiblePage.Value.SectorsPerTrack); + + UpdateStatus?.Invoke(string.Format(Localization.Core + .Setting_geometry_to_0_cylinders_1_heads_2_sectors_per_track, + flexiblePage.Value.Cylinders, + flexiblePage.Value.Heads, + flexiblePage.Value.SectorsPerTrack)); + + outputFormat.SetGeometry(flexiblePage.Value.Cylinders, + flexiblePage.Value.Heads, + flexiblePage.Value.SectorsPerTrack); + + setGeometry = true; + + break; + } } + } } if(!imageCreated) @@ -622,10 +692,11 @@ partial class Dump // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputFormat.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -633,185 +704,295 @@ partial class Dump if(writeSingleOpticalTrack) { - _dumpLog.WriteLine("Creating single track as could not retrieve track list from drive."); + _dumpLog.WriteLine(Localization.Core.Creating_single_track_as_could_not_retrieve_track_list_from_drive); - UpdateStatus?.Invoke("Creating single track as could not retrieve track list from drive."); + UpdateStatus?.Invoke(Localization.Core + .Creating_single_track_as_could_not_retrieve_track_list_from_drive); - (outputFormat as IWritableOpticalImage)?.SetTracks(new List - { - new() - { - BytesPerSector = (int)blockSize, - EndSector = blocks - 1, - Sequence = 1, - RawBytesPerSector = (int)blockSize, - SubchannelType = TrackSubchannelType.None, - Session = 1, - Type = TrackType.Data - } - }); + (outputFormat as IWritableOpticalImage)?.SetTracks([ + new Track + { + BytesPerSector = (int)blockSize, + EndSector = blocks - 1, + Sequence = 1, + RawBytesPerSector = (int)blockSize, + SubchannelType = TrackSubchannelType.None, + Session = 1, + Type = TrackType.Data + } + ]); } } - DumpHardwareType currentTry = null; - ExtentsULong extents = null; + DumpHardware currentTry = null; + ExtentsULong extents = null; - ResumeSupport.Process(true, _dev.IsRemovable, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial, - _dev.PlatformId, ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision, - _private, _force); + ResumeSupport.Process(true, + _dev.IsRemovable, + blocks, + _dev.Manufacturer, + _dev.Model, + _dev.Serial, + _dev.PlatformId, + ref _resume, + ref currentTry, + ref extents, + _dev.FirmwareRevision, + _private, + _force); - if(currentTry == null || - extents == null) + if(_createGraph) { - StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); + bool discIs80Mm = + mediaTags?.TryGetValue(MediaTagType.DVD_PFI, out byte[] pfiBytes) == true && + PFI.Decode(pfiBytes, dskType)?.DiscSize == DVDSize.Eighty || + mediaTags?.TryGetValue(MediaTagType.BD_DI, out byte[] diBytes) == true && + DI.Decode(diBytes)?.Units?.Any(s => s.DiscSize == DI.BluSize.Eighty) == true; + + Spiral.DiscParameters discSpiralParameters = Spiral.DiscParametersFromMediaType(dskType, discIs80Mm); + + if(discSpiralParameters is not null) + _mediaGraph = new Spiral((int)_dimensions, (int)_dimensions, discSpiralParameters, blocks); + else + _mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, blocks); + + if(_mediaGraph is not null) + { + foreach(Tuple e in extents.ToArray()) + _mediaGraph?.PaintSectorsGood(e.Item1, (uint)(e.Item2 - e.Item1 + 2)); + } + + _mediaGraph?.PaintSectorsBad(_resume.BadBlocks); + } + + if(currentTry == null || extents == null) + { + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_process_resume_file_not_continuing); return; } if(_resume.NextBlock > 0) { - UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}."); - _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); + UpdateStatus?.Invoke(string.Format(Localization.Core.Resuming_from_block_0, _resume.NextBlock)); + _dumpLog.WriteLine(Localization.Core.Resuming_from_block_0, _resume.NextBlock); } // Set speed if(_speedMultiplier >= 0) { - _dumpLog.WriteLine($"Setting speed to {(_speed == 0 ? "MAX." : $"{_speed}x")}."); - UpdateStatus?.Invoke($"Setting speed to {(_speed == 0 ? "MAX." : $"{_speed}x")}."); + if(_speed == 0) + { + _dumpLog.WriteLine(Localization.Core.Setting_speed_to_MAX); + UpdateStatus?.Invoke(Localization.Core.Setting_speed_to_MAX); + } + else + { + _dumpLog.WriteLine(string.Format(Localization.Core.Setting_speed_to_0_x, _speed)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Setting_speed_to_0_x, _speed)); + } _speed *= _speedMultiplier; - if(_speed is 0 or > 0xFFFF) - _speed = 0xFFFF; + if(_speed is 0 or > 0xFFFF) _speed = 0xFFFF; _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _); } - if(_resume?.BlankExtents != null) - blankExtents = ExtentsConverter.FromMetadata(_resume.BlankExtents); + if(_resume?.BlankExtents != null) blankExtents = ExtentsConverter.FromMetadata(_resume.BlankExtents); var newTrim = false; if(mediaTags.TryGetValue(MediaTagType.DVD_CMI, out byte[] cmi) && - Settings.Current.EnableDecryption && + Settings.Settings.Current.EnableDecryption && _titleKeys && dskType == MediaType.DVDROM && (CopyrightType)cmi[0] == CopyrightType.CSS) { - UpdateStatus?.Invoke("Title keys dumping is enabled. This will be very slow."); - _resume.MissingTitleKeys ??= new List(Enumerable.Range(0, (int)blocks).Select(n => (ulong)n)); + UpdateStatus?.Invoke(Localization.Core.Title_keys_dumping_is_enabled_This_will_be_very_slow); + _resume.MissingTitleKeys ??= [..Enumerable.Range(0, (int)blocks).Select(n => (ulong)n)]; } if(_dev.ScsiType == PeripheralDeviceTypes.OpticalDevice) - ReadOpticalData(blocks, blocksToRead, blockSize, currentTry, extents, ref currentSpeed, ref minSpeed, - ref maxSpeed, ref totalDuration, scsiReader, mhddLog, ibgLog, ref imageWriteDuration, - ref newTrim, ref blankExtents); + { + ReadOpticalData(blocks, + blocksToRead, + blockSize, + currentTry, + extents, + ref currentSpeed, + ref minSpeed, + ref maxSpeed, + ref totalDuration, + scsiReader, + mhddLog, + ibgLog, + ref imageWriteDuration, + ref newTrim, + ref blankExtents); + } else - ReadSbcData(blocks, blocksToRead, blockSize, currentTry, extents, ref currentSpeed, ref minSpeed, - ref maxSpeed, ref totalDuration, scsiReader, mhddLog, ibgLog, ref imageWriteDuration, - ref newTrim, ref dvdDecrypt, - mediaTags.ContainsKey(MediaTagType.DVD_DiscKey_Decrypted) - ? mediaTags[MediaTagType.DVD_DiscKey_Decrypted] : null); + { + mediaTags.TryGetValue(MediaTagType.DVD_DiscKey_Decrypted, out byte[] discKey); - end = DateTime.UtcNow; + if(scsiReader.HldtstReadRaw) + { + ReadCacheData(blocks, + blocksToRead, + blockSize, + currentTry, + extents, + ref currentSpeed, + ref minSpeed, + ref maxSpeed, + ref totalDuration, + scsiReader, + mhddLog, + ibgLog, + ref imageWriteDuration, + ref newTrim, + discKey ?? null); + } + else + { + ReadSbcData(blocks, + blocksToRead, + blockSize, + currentTry, + extents, + ref currentSpeed, + ref minSpeed, + ref maxSpeed, + ref totalDuration, + scsiReader, + mhddLog, + ibgLog, + ref imageWriteDuration, + ref newTrim, + ref dvdDecrypt, + discKey ?? null); + } + } + + _dumpStopwatch.Stop(); mhddLog.Close(); - ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), _devicePath); + ibgLog.Close(_dev, + blocks, + blockSize, + _dumpStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), + _devicePath); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - #region Trimming - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _trim && - newTrim) +#region Trimming + + if(_resume.BadBlocks.Count > 0 && !_aborted && _trim && newTrim) { - start = DateTime.UtcNow; - UpdateStatus?.Invoke("Trimming skipped sectors"); - _dumpLog.WriteLine("Trimming skipped sectors"); + _trimStopwatch.Restart(); + UpdateStatus?.Invoke(Localization.Core.Trimming_skipped_sectors); + _dumpLog.WriteLine(Localization.Core.Trimming_skipped_sectors); InitProgress?.Invoke(); TrimSbcData(scsiReader, extents, currentTry, blankExtents); EndProgress?.Invoke(); - end = DateTime.UtcNow; - UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds."); - _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds); - } - #endregion Trimming + _trimStopwatch.Stop(); - #region Error handling - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _retryPasses > 0) + UpdateStatus?.Invoke(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _trimStopwatch.Stop(); + } + +#endregion Trimming + +#region Error handling + + if(_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0) RetrySbcData(scsiReader, currentTry, extents, ref totalDuration, blankExtents); - if(_resume.MissingTitleKeys?.Count > 0 && - !_aborted && - _retryPasses > 0 && - Settings.Current.EnableDecryption && - _titleKeys && - mediaTags.ContainsKey(MediaTagType.DVD_DiscKey_Decrypted)) - RetryTitleKeys(dvdDecrypt, mediaTags[MediaTagType.DVD_DiscKey_Decrypted], ref totalDuration); - #endregion Error handling + if(_resume.MissingTitleKeys?.Count > 0 && + !_aborted && + _retryPasses > 0 && + Settings.Settings.Current.EnableDecryption && + _titleKeys && + mediaTags.TryGetValue(MediaTagType.DVD_DiscKey_Decrypted, out byte[] mediaTag)) + RetryTitleKeys(dvdDecrypt, mediaTag, ref totalDuration); + +#endregion Error handling if(opticalDisc) + { foreach(KeyValuePair tag in mediaTags) { if(tag.Value is null) { - AaruConsole.ErrorWriteLine("Error: Tag type {0} is null, skipping...", tag.Key); + AaruConsole.ErrorWriteLine(Localization.Core.Error_Tag_type_0_is_null_skipping, tag.Key); continue; } ret = outputFormat.WriteMediaTag(tag.Value, tag.Key); - if(ret || _force) - continue; + if(ret || _force) continue; // Cannot write tag to image - StoppingErrorMessage?.Invoke($"Cannot write tag {tag.Key}."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Cannot_write_tag_0, tag.Key)); - _dumpLog.WriteLine($"Cannot write tag {tag.Key}." + Environment.NewLine + outputFormat.ErrorMessage); + _dumpLog.WriteLine(string.Format(Localization.Core.Cannot_write_tag_0, tag.Key) + + Environment.NewLine + + outputFormat.ErrorMessage); return; } + } else { - if(!_dev.IsRemovable || - _dev.IsUsb) + if(!_dev.IsRemovable || _dev.IsUsb) { - if(_dev.IsUsb && - _dev.UsbDescriptors != null) + if(_dev.IsUsb && _dev.UsbDescriptors != null) { - UpdateStatus?.Invoke("Reading USB descriptors."); - _dumpLog.WriteLine("Reading USB descriptors."); + UpdateStatus?.Invoke(Localization.Core.Reading_USB_descriptors); + _dumpLog.WriteLine(Localization.Core.Reading_USB_descriptors); ret = outputFormat.WriteMediaTag(_dev.UsbDescriptors, MediaTagType.USB_Descriptors); - if(!ret && - !_force) + if(!ret && !_force) { - _dumpLog.WriteLine("Cannot write USB descriptors."); + _dumpLog.WriteLine(Localization.Core.Cannot_write_USB_descriptors); - StoppingErrorMessage?.Invoke("Cannot write USB descriptors." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_write_USB_descriptors + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -822,24 +1003,23 @@ partial class Dump if(_dev.Type == DeviceType.ATAPI) { - UpdateStatus?.Invoke("Requesting ATAPI IDENTIFY PACKET DEVICE."); - _dumpLog.WriteLine("Requesting ATAPI IDENTIFY PACKET DEVICE."); + UpdateStatus?.Invoke(Localization.Core.Requesting_ATAPI_IDENTIFY_PACKET_DEVICE); + _dumpLog.WriteLine(Localization.Core.Requesting_ATAPI_IDENTIFY_PACKET_DEVICE); sense = _dev.AtapiIdentify(out cmdBuf, out _); if(!sense) { - if(_private) - cmdBuf = DeviceReport.ClearIdentify(cmdBuf); + if(_private) cmdBuf = DeviceReport.ClearIdentify(cmdBuf); ret = outputFormat.WriteMediaTag(cmdBuf, MediaTagType.ATAPI_IDENTIFY); - if(!ret && - !_force) + if(!ret && !_force) { - _dumpLog.WriteLine("Cannot write ATAPI IDENTIFY PACKET DEVICE."); + _dumpLog.WriteLine(Localization.Core.Cannot_write_ATAPI_IDENTIFY_PACKET_DEVICE); - StoppingErrorMessage?.Invoke("Cannot write ATAPI IDENTIFY PACKET DEVICE." + - Environment.NewLine + outputFormat.ErrorMessage); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_write_ATAPI_IDENTIFY_PACKET_DEVICE + + Environment.NewLine + + outputFormat.ErrorMessage); return; } @@ -850,88 +1030,117 @@ partial class Dump if(!sense) { - UpdateStatus?.Invoke("Requesting SCSI INQUIRY."); - _dumpLog.WriteLine("Requesting SCSI INQUIRY."); + UpdateStatus?.Invoke(Localization.Core.Requesting_SCSI_INQUIRY); + _dumpLog.WriteLine(Localization.Core.Requesting_SCSI_INQUIRY); ret = outputFormat.WriteMediaTag(cmdBuf, MediaTagType.SCSI_INQUIRY); - if(!ret && - !_force) + if(!ret && !_force) { - StoppingErrorMessage?.Invoke("Cannot write SCSI INQUIRY."); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_write_SCSI_INQUIRY); - _dumpLog.WriteLine("Cannot write SCSI INQUIRY." + Environment.NewLine + + _dumpLog.WriteLine(Localization.Core.Cannot_write_SCSI_INQUIRY + + Environment.NewLine + outputFormat.ErrorMessage); return; } - UpdateStatus?.Invoke("Requesting MODE SENSE (10)."); - _dumpLog.WriteLine("Requesting MODE SENSE (10)."); + UpdateStatus?.Invoke(Localization.Core.Requesting_MODE_SENSE_10); + _dumpLog.WriteLine(Localization.Core.Requesting_MODE_SENSE_10); - sense = _dev.ModeSense10(out cmdBuf, out _, false, true, ScsiModeSensePageControl.Current, 0x3F, - 0xFF, 5, out _); + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0xFF, + 5, + out _); - if(!sense || - _dev.Error) - sense = _dev.ModeSense10(out cmdBuf, out _, false, true, ScsiModeSensePageControl.Current, 0x3F, - 0x00, 5, out _); + if(!sense || _dev.Error) + { + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, + out _); + } - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) + { if(Modes.DecodeMode10(cmdBuf, _dev.ScsiType).HasValue) { ret = outputFormat.WriteMediaTag(cmdBuf, MediaTagType.SCSI_MODESENSE_10); - if(!ret && - !_force) + if(!ret && !_force) { - _dumpLog.WriteLine("Cannot write SCSI MODE SENSE (10)."); + _dumpLog.WriteLine(Localization.Core.Cannot_write_SCSI_MODE_SENSE_10); - StoppingErrorMessage?.Invoke("Cannot write SCSI MODE SENSE (10)." + - Environment.NewLine + outputFormat.ErrorMessage); - - return; - } - } - - UpdateStatus?.Invoke("Requesting MODE SENSE (6)."); - _dumpLog.WriteLine("Requesting MODE SENSE (6)."); - - sense = _dev.ModeSense6(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, - out _); - - if(sense || _dev.Error) - sense = _dev.ModeSense6(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, - 5, out _); - - if(sense || _dev.Error) - sense = _dev.ModeSense(out cmdBuf, out _, 5, out _); - - if(!sense && - !_dev.Error) - if(Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue) - { - ret = outputFormat.WriteMediaTag(cmdBuf, MediaTagType.SCSI_MODESENSE_6); - - if(!ret && - !_force) - { - _dumpLog.WriteLine("Cannot write SCSI MODE SENSE (6)."); - - StoppingErrorMessage?.Invoke("Cannot write SCSI MODE SENSE (6)." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_write_SCSI_MODE_SENSE_10 + + Environment.NewLine + outputFormat.ErrorMessage); return; } } + } + + UpdateStatus?.Invoke(Localization.Core.Requesting_MODE_SENSE_6); + _dumpLog.WriteLine(Localization.Core.Requesting_MODE_SENSE_6); + + sense = _dev.ModeSense6(out cmdBuf, + out _, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, + out _); + + if(sense || _dev.Error) + { + sense = _dev.ModeSense6(out cmdBuf, + out _, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, + out _); + } + + if(sense || _dev.Error) sense = _dev.ModeSense(out cmdBuf, out _, 5, out _); + + if(!sense && !_dev.Error) + { + if(Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue) + { + ret = outputFormat.WriteMediaTag(cmdBuf, MediaTagType.SCSI_MODESENSE_6); + + if(!ret && !_force) + { + _dumpLog.WriteLine(Localization.Core.Cannot_write_SCSI_MODE_SENSE_6); + + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_write_SCSI_MODE_SENSE_6 + + Environment.NewLine + + outputFormat.ErrorMessage); + + return; + } + } + } } } } _resume.BadBlocks.Sort(); - foreach(ulong bad in _resume.BadBlocks) - _dumpLog.WriteLine("Sector {0} could not be read.", bad); + foreach(ulong bad in _resume.BadBlocks) _dumpLog.WriteLine(Localization.Core.Sector_0_could_not_be_read, bad); currentTry.Extents = ExtentsConverter.ToMetadata(extents); @@ -939,31 +1148,37 @@ partial class Dump // TODO: Media Serial Number // TODO: Non-removable drive information - var metadata = new ImageInfo + var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; - if(!outputFormat.SetMetadata(metadata)) - ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + + if(!outputFormat.SetImageInfo(metadata)) + { + ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + + Environment.NewLine + outputFormat.ErrorMessage); + } - if(_preSidecar != null) - outputFormat.SetCicmMetadata(_preSidecar); + if(_preSidecar != null) outputFormat.SetMetadata(_preSidecar); - _dumpLog.WriteLine("Closing output file."); - UpdateStatus?.Invoke("Closing output file."); - DateTime closeStart = DateTime.Now; + _dumpLog.WriteLine(Localization.Core.Closing_output_file); + UpdateStatus?.Invoke(Localization.Core.Closing_output_file); + _imageCloseStopwatch.Restart(); outputFormat.Close(); - DateTime closeEnd = DateTime.Now; - UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); - _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); + _imageCloseStopwatch.Stop(); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); return; } @@ -977,21 +1192,21 @@ partial class Dump WriteOpticalSidecar(blockSize, blocks, dskType, null, mediaTags, 1, out totalChkDuration, null); else { - UpdateStatus?.Invoke("Creating sidecar."); - _dumpLog.WriteLine("Creating sidecar."); - var filters = new FiltersList(); - IFilter filter = filters.GetFilter(_outputPath); + UpdateStatus?.Invoke(Localization.Core.Creating_sidecar); + _dumpLog.WriteLine(Localization.Core.Creating_sidecar); + IFilter filter = PluginRegister.Singleton.GetFilter(_outputPath); var inputPlugin = ImageFormat.Detect(filter) as IMediaImage; ErrorNumber opened = inputPlugin.Open(filter); if(opened != ErrorNumber.NoError) { - StoppingErrorMessage?.Invoke(string.Format("Error {0} opening created image.", opened)); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_0_opening_created_image, + opened)); return; } - DateTime chkStart = DateTime.UtcNow; + _sidecarStopwatch.Restart(); _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); _sidecarClass.InitProgressEvent += InitProgress; _sidecarClass.UpdateProgressEvent += UpdateProgress; @@ -1000,46 +1215,55 @@ partial class Dump _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; - CICMMetadataType sidecar = _sidecarClass.Create(); - end = DateTime.UtcNow; + Metadata sidecar = _sidecarClass.Create(); + _sidecarStopwatch.Stop(); if(!_aborted) { - totalChkDuration = (end - chkStart).TotalMilliseconds; - UpdateStatus?.Invoke($"Sidecar created in {(end - chkStart).TotalSeconds} seconds."); + totalChkDuration = _sidecarStopwatch.Elapsed.TotalMilliseconds; - UpdateStatus?. - Invoke($"Average checksum speed {blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); + _dumpLog.WriteLine(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); + + _dumpLog.WriteLine(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize()); if(_preSidecar != null) { - _preSidecar.BlockMedia = sidecar.BlockMedia; - sidecar = _preSidecar; + _preSidecar.BlockMedias = sidecar.BlockMedias; + sidecar = _preSidecar; } // All USB flash drives report as removable, even if the media is not removable - if(!_dev.IsRemovable || - _dev.IsUsb) + if(!_dev.IsRemovable || _dev.IsUsb) { - if(_dev.IsUsb && - _dev.UsbDescriptors != null) + if(_dev.IsUsb && _dev.UsbDescriptors != null) + { if(outputFormat.SupportedMediaTags.Contains(MediaTagType.USB_Descriptors)) - sidecar.BlockMedia[0].USB = new USBType + { + sidecar.BlockMedias[0].Usb = new Usb { ProductID = _dev.UsbProductId, VendorID = _dev.UsbVendorId, - Descriptors = new DumpType + Descriptors = new CommonTypes.AaruMetadata.Dump { Image = _outputPath, Size = (ulong)_dev.UsbDescriptors.Length, - Checksums = Checksum.GetChecksums(_dev.UsbDescriptors).ToArray() + Checksums = Checksum.GetChecksums(_dev.UsbDescriptors) } }; + } + } byte[] cmdBuf; @@ -1048,16 +1272,20 @@ partial class Dump sense = _dev.AtapiIdentify(out cmdBuf, out _); if(!sense) + { if(outputFormat.SupportedMediaTags.Contains(MediaTagType.ATAPI_IDENTIFY)) - sidecar.BlockMedia[0].ATA = new ATAType + { + sidecar.BlockMedias[0].ATA = new ATA { - Identify = new DumpType + Identify = new CommonTypes.AaruMetadata.Dump { Image = _outputPath, Size = (ulong)cmdBuf.Length, - Checksums = Checksum.GetChecksums(cmdBuf).ToArray() + Checksums = Checksum.GetChecksums(cmdBuf) } }; + } + } } sense = _dev.ScsiInquiry(out cmdBuf, out _); @@ -1065,15 +1293,17 @@ partial class Dump if(!sense) { if(outputFormat.SupportedMediaTags.Contains(MediaTagType.SCSI_INQUIRY)) - sidecar.BlockMedia[0].SCSI = new SCSIType + { + sidecar.BlockMedias[0].SCSI = new SCSI { - Inquiry = new DumpType + Inquiry = new CommonTypes.AaruMetadata.Dump { Image = _outputPath, Size = (ulong)cmdBuf.Length, - Checksums = Checksum.GetChecksums(cmdBuf).ToArray() + Checksums = Checksum.GetChecksums(cmdBuf) } }; + } // TODO: SCSI Extended Vendor Page descriptors /* @@ -1086,157 +1316,221 @@ partial class Dump if(pages != null) { - List evpds = new List(); + List evpds = new(); foreach(byte page in pages) { dumpLog.WriteLine("Requesting page {0:X2}h.", page); sense = dev.ScsiInquiry(out cmdBuf, out _, page); if(sense) continue; - EVPDType evpd = new EVPDType + Evpd evpd = new() { Image = $"{outputPrefix}.evpd_{page:X2}h.bin", - Checksums = Checksum.GetChecksums(cmdBuf).ToArray(), + Checksums = Checksum.GetChecksums(cmdBuf), Size = cmdBuf.Length }; - evpd.Checksums = Checksum.GetChecksums(cmdBuf).ToArray(); + evpd.Checksums = Checksum.GetChecksums(cmdBuf); DataFile.WriteTo("SCSI Dump", evpd.Image, cmdBuf); evpds.Add(evpd); } - if(evpds.Count > 0) sidecar.BlockMedia[0].SCSI.EVPD = evpds.ToArray(); + if(evpds.Count > 0) sidecar.BlockMedias[0].SCSI.Evpds = evpds; } } */ - UpdateStatus?.Invoke("Requesting MODE SENSE (10)."); - _dumpLog.WriteLine("Requesting MODE SENSE (10)."); + UpdateStatus?.Invoke(Localization.Core.Requesting_MODE_SENSE_10); + _dumpLog.WriteLine(Localization.Core.Requesting_MODE_SENSE_10); - sense = _dev.ModeSense10(out cmdBuf, out _, false, true, ScsiModeSensePageControl.Current, - 0x3F, 0xFF, 5, out _); + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0xFF, + 5, + out _); - if(!sense || - _dev.Error) - sense = _dev.ModeSense10(out cmdBuf, out _, false, true, - ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out _); + if(!sense || _dev.Error) + { + sense = _dev.ModeSense10(out cmdBuf, + out _, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, + out _); + } - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) + { if(Modes.DecodeMode10(cmdBuf, _dev.ScsiType).HasValue) + { if(outputFormat.SupportedMediaTags.Contains(MediaTagType.SCSI_MODESENSE_10)) - sidecar.BlockMedia[0].SCSI.ModeSense10 = new DumpType + { + sidecar.BlockMedias[0].SCSI.ModeSense10 = new CommonTypes.AaruMetadata.Dump { Image = _outputPath, Size = (ulong)cmdBuf.Length, - Checksums = Checksum.GetChecksums(cmdBuf).ToArray() + Checksums = Checksum.GetChecksums(cmdBuf) }; + } + } + } - UpdateStatus?.Invoke("Requesting MODE SENSE (6)."); - _dumpLog.WriteLine("Requesting MODE SENSE (6)."); + UpdateStatus?.Invoke(Localization.Core.Requesting_MODE_SENSE_6); + _dumpLog.WriteLine(Localization.Core.Requesting_MODE_SENSE_6); - sense = _dev.ModeSense6(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, 0x3F, - 0x00, 5, out _); + sense = _dev.ModeSense6(out cmdBuf, + out _, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, + out _); if(sense || _dev.Error) - sense = _dev.ModeSense6(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, - 0x3F, 0x00, 5, out _); + { + sense = _dev.ModeSense6(out cmdBuf, + out _, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, + out _); + } - if(sense || _dev.Error) - sense = _dev.ModeSense(out cmdBuf, out _, 5, out _); + if(sense || _dev.Error) sense = _dev.ModeSense(out cmdBuf, out _, 5, out _); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) + { if(Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue) + { if(outputFormat.SupportedMediaTags.Contains(MediaTagType.SCSI_MODESENSE_6)) - sidecar.BlockMedia[0].SCSI.ModeSense = new DumpType + { + sidecar.BlockMedias[0].SCSI.ModeSense = new CommonTypes.AaruMetadata.Dump { Image = _outputPath, Size = (ulong)cmdBuf.Length, - Checksums = Checksum.GetChecksums(cmdBuf).ToArray() + Checksums = Checksum.GetChecksums(cmdBuf) }; + } + } + } } } - List<(ulong start, string type)> filesystems = new(); + List<(ulong start, string type)> filesystems = []; - if(sidecar.BlockMedia[0].FileSystemInformation != null) - filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation + if(sidecar.BlockMedias[0].FileSystemInformation != null) + { + filesystems.AddRange(from partition in sidecar.BlockMedias[0].FileSystemInformation where partition.FileSystems != null from fileSystem in partition.FileSystems select (partition.StartSector, fileSystem.Type)); + } if(filesystems.Count > 0) + { foreach(var filesystem in filesystems.Select(o => new - { - o.start, - o.type - }).Distinct()) + { + o.start, + o.type + }) + .Distinct()) { - UpdateStatus?.Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Found_filesystem_0_at_sector_1, + filesystem.type, + filesystem.start)); - _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start); + _dumpLog.WriteLine(Localization.Core.Found_filesystem_0_at_sector_1, + filesystem.type, + filesystem.start); } + } - sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(dskType); + sidecar.BlockMedias[0].Dimensions = Dimensions.FromMediaType(dskType); (string type, string subType) xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType); - sidecar.BlockMedia[0].DiskType = xmlType.type; - sidecar.BlockMedia[0].DiskSubType = xmlType.subType; + sidecar.BlockMedias[0].MediaType = xmlType.type; + sidecar.BlockMedias[0].MediaSubType = xmlType.subType; // TODO: Implement device firmware revision - if(!_dev.IsRemovable || - _dev.IsUsb) + if(!_dev.IsRemovable || _dev.IsUsb) + { if(_dev.Type == DeviceType.ATAPI) - sidecar.BlockMedia[0].Interface = "ATAPI"; + sidecar.BlockMedias[0].Interface = "ATAPI"; else if(_dev.IsUsb) - sidecar.BlockMedia[0].Interface = "USB"; + sidecar.BlockMedias[0].Interface = "USB"; else if(_dev.IsFireWire) - sidecar.BlockMedia[0].Interface = "FireWire"; + sidecar.BlockMedias[0].Interface = "FireWire"; else - sidecar.BlockMedia[0].Interface = "SCSI"; + sidecar.BlockMedias[0].Interface = "SCSI"; + } - sidecar.BlockMedia[0].LogicalBlocks = blocks; - sidecar.BlockMedia[0].PhysicalBlockSize = physicalBlockSize; - sidecar.BlockMedia[0].LogicalBlockSize = logicalBlockSize; - sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer; - sidecar.BlockMedia[0].Model = _dev.Model; + sidecar.BlockMedias[0].LogicalBlocks = blocks; + sidecar.BlockMedias[0].PhysicalBlockSize = physicalBlockSize; + sidecar.BlockMedias[0].LogicalBlockSize = logicalBlockSize; + sidecar.BlockMedias[0].Manufacturer = _dev.Manufacturer; + sidecar.BlockMedias[0].Model = _dev.Model; - if(!_private) - sidecar.BlockMedia[0].Serial = _dev.Serial; + if(!_private) sidecar.BlockMedias[0].Serial = _dev.Serial; - sidecar.BlockMedia[0].Size = blocks * blockSize; + sidecar.BlockMedias[0].Size = blocks * blockSize; - if(_dev.IsRemovable) - sidecar.BlockMedia[0].DumpHardwareArray = _resume.Tries.ToArray(); + if(_dev.IsRemovable) sidecar.BlockMedias[0].DumpHardware = _resume.Tries; - UpdateStatus?.Invoke("Writing metadata sidecar"); + UpdateStatus?.Invoke(Localization.Core.Writing_metadata_sidecar); - var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); + var jsonFs = new FileStream(_outputPrefix + ".metadata.json", FileMode.Create); - var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); - xmlSer.Serialize(xmlFs, sidecar); - xmlFs.Close(); + JsonSerializer.Serialize(jsonFs, + new MetadataJson + { + AaruMetadata = sidecar + }, + typeof(MetadataJson), + MetadataJsonContext.Default); + + jsonFs.Close(); } } } UpdateStatus?.Invoke(""); - UpdateStatus?. - Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second), + totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second), + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average speed: {blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds())) + .Humanize()); if(maxSpeed > 0) - UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0, + ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize())); + } - if(minSpeed > 0 && - minSpeed < double.MaxValue) - UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); + if(minSpeed is > 0 and < double.MaxValue) + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0, + ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize())); + } - UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); + UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_could_not_be_read, _resume.BadBlocks.Count)); UpdateStatus?.Invoke(""); Statistics.AddMedia(dskType, true); diff --git a/Aaru.Core/Devices/Dumping/Sbc/Error.cs b/Aaru.Core/Devices/Dumping/Sbc/Error.cs index ee3a79b8a..f80397326 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Error.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Error.cs @@ -21,19 +21,12 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// Copyright © 2020-2022 Rebecca Wallander +// Copyright © 2011-2024 Natalia Portillo +// Copyright © 2020-2024 Rebecca Wallander // ****************************************************************************/ -using DVDDecryption = Aaru.Decryption.DVD.Dump; - -// ReSharper disable JoinDeclarationAndInitializer -// ReSharper disable InlineOutVariableDeclaration -// ReSharper disable TooWideLocalVariableScope - -namespace Aaru.Core.Devices.Dumping; - using System.Linq; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; @@ -44,7 +37,13 @@ using Aaru.Decoders.SCSI; using Aaru.Decryption; using Aaru.Decryption.DVD; using Aaru.Devices; -using Schemas; +using DVDDecryption = Aaru.Decryption.DVD.Dump; + +// ReSharper disable JoinDeclarationAndInitializer +// ReSharper disable InlineOutVariableDeclaration +// ReSharper disable TooWideLocalVariableScope + +namespace Aaru.Core.Devices.Dumping; partial class Dump { @@ -54,7 +53,7 @@ partial class Dump /// Total time spent in commands /// SCSI reader /// Blank extents - void RetrySbcData(Reader scsiReader, DumpHardwareType currentTry, ExtentsULong extents, ref double totalDuration, + void RetrySbcData(Reader scsiReader, DumpHardware currentTry, ExtentsULong extents, ref double totalDuration, ExtentsULong blankExtents) { var pass = 1; @@ -75,12 +74,25 @@ partial class Dump Modes.ModePage_01_MMC pgMmc; Modes.ModePage_01 pg; - sense = _dev.ModeSense6(out buffer, out _, false, ScsiModeSensePageControl.Current, 0x01, _dev.Timeout, + sense = _dev.ModeSense6(out buffer, + out _, + false, + ScsiModeSensePageControl.Current, + 0x01, + _dev.Timeout, out _); - if(sense) + Modes.DecodedMode? dcMode6 = null; + if(!sense) dcMode6 = Modes.DecodeMode6(buffer, _dev.ScsiType); + + if(sense || dcMode6 is null) { - sense = _dev.ModeSense10(out buffer, out _, false, ScsiModeSensePageControl.Current, 0x01, _dev.Timeout, + sense = _dev.ModeSense10(out buffer, + out _, + false, + ScsiModeSensePageControl.Current, + 0x01, + _dev.Timeout, out _); if(!sense) @@ -88,19 +100,23 @@ partial class Dump Modes.DecodedMode? dcMode10 = Modes.DecodeMode10(buffer, _dev.ScsiType); if(dcMode10?.Pages != null) + { foreach(Modes.ModePage modePage in dcMode10.Value.Pages.Where(modePage => - modePage.Page == 0x01 && modePage.Subpage == 0x00)) + modePage is { Page: 0x01, Subpage: 0x00 })) currentModePage = modePage; + } } } else { - Modes.DecodedMode? dcMode6 = Modes.DecodeMode6(buffer, _dev.ScsiType); - - if(dcMode6?.Pages != null) - foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage => modePage.Page == 0x01 && - modePage.Subpage == 0x00)) + if(dcMode6.Value.Pages != null) + { + foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage => modePage is + { + Page: 0x01, Subpage: 0x00 + })) currentModePage = modePage; + } } if(currentModePage == null) @@ -158,15 +174,15 @@ partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { + Pages = + [ new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01_MMC(pgMmc) } - } + ] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); @@ -191,36 +207,36 @@ partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { + Pages = + [ new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01(pg) } - } + ] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); md10 = Modes.EncodeMode10(md, _dev.ScsiType); } - UpdateStatus?.Invoke("Sending MODE SELECT to drive (return damaged blocks)."); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks)."); + UpdateStatus?.Invoke(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); sense = _dev.ModeSelect(md6, out byte[] senseBuf, true, false, _dev.Timeout, out _); - if(sense) - sense = _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); + if(sense) sense = _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); if(sense) { - UpdateStatus?. - Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + UpdateStatus?.Invoke(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); - AaruConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(Localization.Core.Error_0, Sense.PrettifySense(senseBuf)); - _dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + _dumpLog.WriteLine(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); } else runningPersistent = true; @@ -235,17 +251,47 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass, - forward ? "forward" : "reverse", - runningPersistent ? "recovering partial data, " : "")); + if(forward) + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_forward, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_forward, + badSector, + pass)); + } + else + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_reverse, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_reverse, + badSector, + pass)); + } - sense = scsiReader.ReadBlock(out buffer, badSector, out double cmdDuration, out recoveredError, + if(scsiReader.HldtstReadRaw) + + // The HL-DT-ST buffer is stored and read in 96-sector chunks. If we start to read at an LBA which is + // not modulo 96, the data will not be correctly fetched. Therefore, we begin every recovery read with + // filling the buffer at a known offset. + // TODO: This is very ugly and there probably exist a more elegant way to solve this issue. + scsiReader.ReadBlock(out _, badSector - badSector % 96 + 1, out _, out _, out _); + + sense = scsiReader.ReadBlock(out buffer, + badSector, + out double cmdDuration, + out recoveredError, out blankCheck); totalDuration += cmdDuration; @@ -256,8 +302,8 @@ partial class Dump blankExtents.Add(badSector, badSector); newBlank = true; - UpdateStatus?.Invoke($"Found blank block {badSector} in pass {pass}."); - _dumpLog.WriteLine("Found blank block {0} in pass {1}.", badSector, pass); + UpdateStatus?.Invoke(string.Format(Localization.Core.Found_blank_block_0_in_pass_1, badSector, pass)); + _dumpLog.WriteLine(Localization.Core.Found_blank_block_0_in_pass_1, badSector, pass); continue; } @@ -267,23 +313,24 @@ partial class Dump _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(buffer, badSector); - UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}."); - _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); + _mediaGraph?.PaintSectorGood(badSector); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_block_0_in_pass_1, + badSector, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_block_0_in_pass_1, badSector, pass); } - else if(runningPersistent) - outputFormat.WriteSector(buffer, badSector); + else if(runningPersistent) outputFormat.WriteSector(buffer, badSector); } - if(pass < _retryPasses && - !_aborted && - _resume.BadBlocks.Count > 0) + if(pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); - if(!forward) - _resume.BadBlocks.Reverse(); + if(!forward) _resume.BadBlocks.Reverse(); goto repeatRetry; } @@ -293,25 +340,20 @@ partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { - currentModePage.Value - } + Pages = [currentModePage.Value] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); md10 = Modes.EncodeMode10(md, _dev.ScsiType); - UpdateStatus?.Invoke("Sending MODE SELECT to drive (return device to previous status)."); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status)."); + UpdateStatus?.Invoke(Localization.Core.Sending_MODE_SELECT_to_drive_return_device_to_previous_status); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_device_to_previous_status); sense = _dev.ModeSelect(md6, out _, true, false, _dev.Timeout, out _); - if(sense) - _dev.ModeSelect10(md10, out _, true, false, _dev.Timeout, out _); + if(sense) _dev.ModeSelect10(md10, out _, true, false, _dev.Timeout, out _); } - if(newBlank) - _resume.BlankExtents = ExtentsConverter.ToMetadata(blankExtents); + if(newBlank) _resume.BlankExtents = ExtentsConverter.ToMetadata(blankExtents).ToArray(); EndProgress?.Invoke(); } @@ -322,7 +364,8 @@ partial class Dump var forward = true; bool sense; byte[] buffer; - var outputFormat = _outputPlugin as IWritableImage; + + if(_outputPlugin is not IWritableImage outputFormat) return; InitProgress?.Invoke(); @@ -333,79 +376,79 @@ partial class Dump { if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke(string.Format("Retrying title key {0}, pass {1}, {2}", missingKey, pass, - forward ? "forward" : "reverse")); + PulseProgress?.Invoke(forward + ? string.Format(Localization.Core.Retrying_title_key_0_pass_1_forward, + missingKey, + pass) + : string.Format(Localization.Core.Retrying_title_key_0_pass_1_reverse, + missingKey, + pass)); - sense = dvdDecrypt.ReadTitleKey(out buffer, out _, DvdCssKeyClass.DvdCssCppmOrCprm, missingKey, - _dev.Timeout, out double cmdDuration); + sense = dvdDecrypt.ReadTitleKey(out buffer, + out _, + DvdCssKeyClass.DvdCssCppmOrCprm, + missingKey, + _dev.Timeout, + out double cmdDuration); totalDuration += cmdDuration; - if(!sense && - !_dev.Error) + if(sense || _dev.Error) continue; + + CSS_CPRM.TitleKey? titleKey = CSS.DecodeTitleKey(buffer, dvdDecrypt.BusKey); + + if(!titleKey.HasValue) continue; + + outputFormat.WriteSectorTag([titleKey.Value.CMI], missingKey, SectorTagType.DvdSectorCmi); + + // If the CMI bit is 1, the sector is using copy protection, else it is not + // If the decoded title key is zeroed, there should be no copy protection + if((titleKey.Value.CMI & 0x80) >> 7 == 0 || titleKey.Value.Key.All(k => k == 0)) { - CSS_CPRM.TitleKey? titleKey = CSS.DecodeTitleKey(buffer, dvdDecrypt.BusKey); + outputFormat.WriteSectorTag([0, 0, 0, 0, 0], missingKey, SectorTagType.DvdSectorTitleKey); - if(titleKey.HasValue) + outputFormat.WriteSectorTag([0, 0, 0, 0, 0], missingKey, SectorTagType.DvdTitleKeyDecrypted); + + _resume.MissingTitleKeys.Remove(missingKey); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_title_key_0_in_pass_1, + missingKey, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_title_key_0_in_pass_1, missingKey, pass); + } + else + { + outputFormat.WriteSectorTag(titleKey.Value.Key, missingKey, SectorTagType.DvdSectorTitleKey); + _resume.MissingTitleKeys.Remove(missingKey); + + if(discKey != null) { - outputFormat.WriteSectorTag(new[] - { - titleKey.Value.CMI - }, missingKey, SectorTagType.DvdCmi); - - // If the CMI bit is 1, the sector is using copy protection, else it is not - // If the decoded title key is zeroed, there should be no copy protection - if((titleKey.Value.CMI & 0x80) >> 7 == 0 || - titleKey.Value.Key.All(k => k == 0)) - { - outputFormat.WriteSectorTag(new byte[] - { - 0, 0, 0, 0, 0 - }, missingKey, SectorTagType.DvdTitleKey); - - outputFormat.WriteSectorTag(new byte[] - { - 0, 0, 0, 0, 0 - }, missingKey, SectorTagType.DvdTitleKeyDecrypted); - - _resume.MissingTitleKeys.Remove(missingKey); - UpdateStatus?.Invoke($"Correctly retried title key {missingKey} in pass {pass}."); - _dumpLog.WriteLine("Correctly retried title key {0} in pass {1}.", missingKey, pass); - } - else - { - outputFormat.WriteSectorTag(titleKey.Value.Key, missingKey, SectorTagType.DvdTitleKey); - _resume.MissingTitleKeys.Remove(missingKey); - - if(discKey != null) - { - CSS.DecryptTitleKey(0, discKey, titleKey.Value.Key, out buffer); - outputFormat.WriteSectorTag(buffer, missingKey, SectorTagType.DvdTitleKeyDecrypted); - } - - UpdateStatus?.Invoke($"Correctly retried title key {missingKey} in pass {pass}."); - _dumpLog.WriteLine("Correctly retried title key {0} in pass {1}.", missingKey, pass); - } + CSS.DecryptTitleKey(discKey, titleKey.Value.Key, out buffer); + outputFormat.WriteSectorTag(buffer, missingKey, SectorTagType.DvdTitleKeyDecrypted); } + + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_title_key_0_in_pass_1, + missingKey, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_title_key_0_in_pass_1, missingKey, pass); } } - if(pass < _retryPasses && - !_aborted && - _resume.MissingTitleKeys.Count > 0) + if(pass < _retryPasses && !_aborted && _resume.MissingTitleKeys.Count > 0) { pass++; forward = !forward; _resume.MissingTitleKeys.Sort(); - if(!forward) - _resume.MissingTitleKeys.Reverse(); + if(!forward) _resume.MissingTitleKeys.Reverse(); goto repeatRetry; } diff --git a/Aaru.Core/Devices/Dumping/Sbc/Optical.cs b/Aaru.Core/Devices/Dumping/Sbc/Optical.cs index 5b297f50b..21fe7dfee 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Optical.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Optical.cs @@ -1,20 +1,20 @@ - - // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - using System; using System.Linq; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Core.Logging; using Aaru.Decoders.SCSI; using Aaru.Helpers; -using Schemas; +using Humanizer; +using Humanizer.Bytes; + +namespace Aaru.Core.Devices.Dumping; partial class Dump { @@ -37,10 +37,10 @@ partial class Dump /// Total time spent writing to image /// Set if we need to start a trim /// Blank extents - void ReadOpticalData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, DumpHardwareType currentTry, + void ReadOpticalData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, DumpHardware currentTry, ExtentsULong extents, ref double currentSpeed, ref double minSpeed, ref double maxSpeed, - ref double totalDuration, Reader scsiReader, MhddLog mhddLog, IbgLog ibgLog, - ref double imageWriteDuration, ref bool newTrim, ref ExtentsULong blankExtents) + ref double totalDuration, Reader scsiReader, MhddLog mhddLog, IbgLog ibgLog, + ref double imageWriteDuration, ref bool newTrim, ref ExtentsULong blankExtents) { const uint maxBlocks = 256; var writtenExtents = new ExtentsULong(); @@ -53,7 +53,6 @@ partial class Dump bool sense; byte[] buffer; ulong sectorSpeedStart = 0; - DateTime timeSpeedStart = DateTime.UtcNow; var canMediumScan = true; var outputFormat = _outputPlugin as IWritableImage; @@ -63,40 +62,46 @@ partial class Dump { blankExtents = new ExtentsULong(); - written = _dev.MediumScan(out buffer, true, false, false, false, false, 0, 1, 1, out _, out _, - uint.MaxValue, out _); + written = _dev.MediumScan(out buffer, + true, + false, + false, + false, + false, + 0, + 1, + 1, + out _, + out _, + uint.MaxValue, + out _); DecodedSense? decodedSense = Sense.Decode(buffer); - if(_dev.LastError != 0 || - decodedSense?.SenseKey == SenseKeys.IllegalRequest) + if(_dev.LastError != 0 || decodedSense?.SenseKey == SenseKeys.IllegalRequest) { - UpdateStatus?. - Invoke("The current environment doesn't support the medium scan command, dump will take much longer than normal."); + UpdateStatus?.Invoke(Localization.Core.The_current_environment_doesn_t_support_the_medium_scan_command); canMediumScan = false; writtenExtents.Add(0, blocks - 1); } // TODO: Find a place where MEDIUM SCAN works properly - else if(buffer?.Length > 0 && - !ArrayHelpers.ArrayIsNullOrEmpty(buffer)) - AaruConsole. - WriteLine("Please open a bug report in github with the manufacturer and model of this device, as well as your operating system name and version and this message: This environment correctly supports MEDIUM SCAN command."); + else if(buffer?.Length > 0 && !ArrayHelpers.ArrayIsNullOrEmpty(buffer)) + AaruConsole.WriteLine(Localization.Core.MEDIUM_SCAN_github_plead_message); changingCounter = false; changingWritten = false; for(uint b = 0; b < blocks; b += c) { - if(!canMediumScan) - break; + if(!canMediumScan) break; if(_aborted) { _resume.BlankExtents = null; - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } @@ -114,15 +119,33 @@ partial class Dump changingCounter = false; } - if(b + c >= blocks) - c = (uint)(blocks - b); + if(b + c >= blocks) c = (uint)(blocks - b); - UpdateProgress?. - Invoke($"Scanning for {c} {(written ? "written" : "blank")} blocks starting in block {b}", b, - (long)blocks); + UpdateProgress?.Invoke(written + ? string.Format(Localization.Core + .Scanning_for_0_written_blocks_starting_in_block_1, + c, + b) + : string.Format(Localization.Core + .Scanning_for_0_blank_blocks_starting_in_block_1, + c, + b), + b, + (long)blocks); - conditionMet = _dev.MediumScan(out _, written, false, false, false, false, b, c, c, out _, out _, - uint.MaxValue, out _); + conditionMet = _dev.MediumScan(out _, + written, + false, + false, + false, + false, + b, + c, + c, + out _, + out _, + uint.MaxValue, + out _); if(conditionMet) { @@ -131,8 +154,7 @@ partial class Dump else blankExtents.Add(b, c, true); - if(c < maxBlocks) - changingWritten = true; + if(c < maxBlocks) changingWritten = true; } else { @@ -143,8 +165,7 @@ partial class Dump changingCounter = true; - if(c != 0) - continue; + if(c != 0) continue; written = !written; c = maxBlocks; @@ -152,7 +173,7 @@ partial class Dump } if(_resume != null && canMediumScan) - _resume.BlankExtents = ExtentsConverter.ToMetadata(blankExtents); + _resume.BlankExtents = ExtentsConverter.ToMetadata(blankExtents).ToArray(); EndProgress?.Invoke(); } @@ -167,8 +188,8 @@ partial class Dump if(writtenExtents.Count == 0) { - UpdateStatus?.Invoke("Cannot dump empty media!"); - _dumpLog.WriteLine("Cannot dump empty media!"); + UpdateStatus?.Invoke(Localization.Core.Cannot_dump_empty_media); + _dumpLog.WriteLine(Localization.Core.Cannot_dump_empty_media); return; } @@ -179,91 +200,87 @@ partial class Dump foreach(Tuple extent in extentsToDump) { - if(extent.Item2 < _resume.NextBlock) - continue; // Skip this extent + if(extent.Item2 < _resume.NextBlock) continue; // Skip this extent ulong nextBlock = extent.Item1; - if(extent.Item1 < _resume.NextBlock) - nextBlock = (uint)_resume.NextBlock; + if(extent.Item1 < _resume.NextBlock) nextBlock = (uint)_resume.NextBlock; + + _speedStopwatch.Restart(); for(ulong i = nextBlock; i <= extent.Item2; i += blocksToRead) { if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(extent.Item2 + 1 - i < blocksToRead) - blocksToRead = (uint)(extent.Item2 + 1 - i); + if(extent.Item2 + 1 - i < blocksToRead) blocksToRead = (uint)(extent.Item2 + 1 - i); - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)blocks); sense = scsiReader.ReadBlocks(out buffer, i, blocksToRead, out double cmdDuration, out _, out _); totalDuration += cmdDuration; - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, cmdDuration, blocksToRead); ibgLog.Write(i, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(buffer, i, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(i, blocksToRead, true); } else { // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly - if(i + _skip > extent.Item2 + 1) - _skip = (uint)(extent.Item2 + 1 - i); + if(i + _skip > extent.Item2 + 1) _skip = (uint)(extent.Item2 + 1 - i); // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; - for(ulong b = i; b < i + _skip; b++) - _resume.BadBlocks.Add(b); + for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b); - mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); + mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip); ibgLog.Write(i, 0); - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i); i += _skip - blocksToRead; newTrim = true; } + _writeStopwatch.Stop(); sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Restart(); } } + _speedStopwatch.Stop(); _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); EndProgress?.Invoke(); diff --git a/Aaru.Core/Devices/Dumping/Sbc/Trim.cs b/Aaru.Core/Devices/Dumping/Sbc/Trim.cs index 176a4d342..2c67ddae0 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Trim.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Trim.cs @@ -21,20 +21,18 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration // ReSharper disable TooWideLocalVariableScope -namespace Aaru.Core.Devices.Dumping; - +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Schemas; + +namespace Aaru.Core.Devices.Dumping; partial class Dump { @@ -43,18 +41,18 @@ partial class Dump /// Correctly dump extents /// Resume information /// Blank extents - void TrimSbcData(Reader scsiReader, ExtentsULong extents, DumpHardwareType currentTry, ExtentsULong blankExtents) + void TrimSbcData(Reader scsiReader, ExtentsULong extents, DumpHardware currentTry, ExtentsULong blankExtents) { ulong[] tmpArray = _resume.BadBlocks.ToArray(); bool sense; bool recoveredError; bool blankCheck; byte[] buffer; - var newBlank = false; + var newBlank = false; if(_outputPlugin is not IWritableImage outputFormat) { - StoppingErrorMessage?.Invoke("Image is not writable, aborting..."); + StoppingErrorMessage?.Invoke(Localization.Core.Image_is_not_writable_aborting); return; } @@ -64,13 +62,13 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke($"Trimming sector {badSector}"); + PulseProgress?.Invoke(string.Format(Localization.Core.Trimming_sector_0, badSector)); sense = scsiReader.ReadBlock(out buffer, badSector, out double _, out recoveredError, out blankCheck); @@ -80,22 +78,20 @@ partial class Dump newBlank = true; _resume.BadBlocks.Remove(badSector); - UpdateStatus?.Invoke($"Found blank block {badSector}."); - _dumpLog.WriteLine("Found blank block {0}.", badSector); + UpdateStatus?.Invoke(string.Format(Localization.Core.Found_blank_block_0, badSector)); + _dumpLog.WriteLine(Localization.Core.Found_blank_block_0, badSector); continue; } - if((sense || _dev.Error) && - !recoveredError) - continue; + if((sense || _dev.Error) && !recoveredError) continue; _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(buffer, badSector); + _mediaGraph?.PaintSectorGood(badSector); } - if(newBlank) - _resume.BlankExtents = ExtentsConverter.ToMetadata(blankExtents); + if(newBlank) _resume.BlankExtents = ExtentsConverter.ToMetadata(blankExtents).ToArray(); } } \ No newline at end of file diff --git a/Aaru.Core/Devices/Dumping/SecureDigital.cs b/Aaru.Core/Devices/Dumping/SecureDigital.cs index f9b15f1ab..7cbc51e79 100644 --- a/Aaru.Core/Devices/Dumping/SecureDigital.cs +++ b/Aaru.Core/Devices/Dumping/SecureDigital.cs @@ -27,36 +27,34 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable JoinDeclarationAndInitializer -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Xml.Serialization; +using System.Text.Json; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Metadata; -using Aaru.CommonTypes.Structs; +using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.MMC; using Aaru.Decoders.SecureDigital; -using Schemas; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; using CSD = Aaru.Decoders.MMC.CSD; -using Decoders = Aaru.Decoders.MMC.Decoders; using DeviceType = Aaru.CommonTypes.Enums.DeviceType; -using MediaType = Aaru.CommonTypes.MediaType; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Devices.Dumping; + /// Implements dumping a MultiMediaCard or SecureDigital flash card public partial class Dump { @@ -66,12 +64,11 @@ public partial class Dump if(_dumpRaw) { if(_force) - ErrorMessage?. - Invoke("Raw dumping is not supported in MultiMediaCard or SecureDigital devices. Continuing..."); + ErrorMessage?.Invoke(Localization.Core.Raw_dumping_is_not_supported_in_MMC_or_SD_devices_Continuing); else { - StoppingErrorMessage?. - Invoke("Raw dumping is not supported in MultiMediaCard or SecureDigital devices. Aborting..."); + StoppingErrorMessage?.Invoke(Localization.Core + .Raw_dumping_is_not_supported_in_MMC_or_SD_devices_Aborting); return; } @@ -100,13 +97,13 @@ public partial class Dump { case DeviceType.MMC: { - UpdateStatus?.Invoke("Reading CSD"); - _dumpLog.WriteLine("Reading CSD"); + UpdateStatus?.Invoke(Localization.Core.Reading_CSD); + _dumpLog.WriteLine(Localization.Core.Reading_CSD); sense = _dev.ReadCsd(out csd, out response, timeout, out duration); if(!sense) { - CSD csdDecoded = Decoders.DecodeCSD(csd); + CSD csdDecoded = Decoders.MMC.Decoders.DecodeCSD(csd); blocks = (ulong)((csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2)); blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength); @@ -117,25 +114,26 @@ public partial class Dump if(csdDecoded.Size == 0xFFF) { - UpdateStatus?.Invoke("Reading Extended CSD"); - _dumpLog.WriteLine("Reading Extended CSD"); + UpdateStatus?.Invoke(Localization.Core.Reading_Extended_CSD); + _dumpLog.WriteLine(Localization.Core.Reading_Extended_CSD); sense = _dev.ReadExtendedCsd(out ecsd, out response, timeout, out duration); if(!sense) { - ExtendedCSD ecsdDecoded = Decoders.DecodeExtendedCSD(ecsd); + ExtendedCSD ecsdDecoded = Decoders.MMC.Decoders.DecodeExtendedCSD(ecsd); blocks = ecsdDecoded.SectorCount; blockSize = (uint)(ecsdDecoded.SectorSize == 1 ? 4096 : 512); - if(ecsdDecoded.NativeSectorSize == 0) - physicalBlockSize = 512; - else if(ecsdDecoded.NativeSectorSize == 1) - physicalBlockSize = 4096; + physicalBlockSize = ecsdDecoded.NativeSectorSize switch + { + 0 => 512, + 1 => 4096, + _ => physicalBlockSize + }; blocksToRead = (ushort)(ecsdDecoded.OptimalReadSize * 4096 / blockSize); - if(blocksToRead == 0) - blocksToRead = 128; + if(blocksToRead == 0) blocksToRead = 128; // Supposing it's high-capacity MMC if it has Extended CSD... byteAddressed = false; @@ -154,8 +152,8 @@ public partial class Dump csd = null; } - UpdateStatus?.Invoke("Reading OCR"); - _dumpLog.WriteLine("Reading OCR"); + UpdateStatus?.Invoke(Localization.Core.Reading_OCR); + _dumpLog.WriteLine(Localization.Core.Reading_OCR); sense = _dev.ReadOcr(out ocr, out response, timeout, out duration); if(sense) @@ -171,13 +169,13 @@ public partial class Dump case DeviceType.SecureDigital: { - UpdateStatus?.Invoke("Reading CSD"); - _dumpLog.WriteLine("Reading CSD"); + UpdateStatus?.Invoke(Localization.Core.Reading_CSD); + _dumpLog.WriteLine(Localization.Core.Reading_CSD); sense = _dev.ReadCsd(out csd, out response, timeout, out duration); if(!sense) { - Aaru.Decoders.SecureDigital.CSD csdDecoded = Aaru.Decoders.SecureDigital.Decoders.DecodeCSD(csd); + Decoders.SecureDigital.CSD csdDecoded = Decoders.SecureDigital.Decoders.DecodeCSD(csd); blocks = (ulong)(csdDecoded.Structure == 0 ? (csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2) @@ -204,8 +202,8 @@ public partial class Dump csd = null; } - UpdateStatus?.Invoke("Reading OCR"); - _dumpLog.WriteLine("Reading OCR"); + UpdateStatus?.Invoke(Localization.Core.Reading_OCR); + _dumpLog.WriteLine(Localization.Core.Reading_OCR); sense = _dev.ReadSdocr(out ocr, out response, timeout, out duration); if(sense) @@ -216,8 +214,8 @@ public partial class Dump else mediaTags.Add(MediaTagType.SD_OCR, null); - UpdateStatus?.Invoke("Reading SCR"); - _dumpLog.WriteLine("Reading SCR"); + UpdateStatus?.Invoke(Localization.Core.Reading_SCR); + _dumpLog.WriteLine(Localization.Core.Reading_SCR); sense = _dev.ReadScr(out scr, out response, timeout, out duration); if(sense) @@ -227,8 +225,9 @@ public partial class Dump } else { - supportsCmd23 = Aaru.Decoders.SecureDigital.Decoders.DecodeSCR(scr)?.CommandSupport. - HasFlag(CommandSupport.SetBlockCount) ?? false; + supportsCmd23 = Decoders.SecureDigital.Decoders.DecodeSCR(scr) + ?.CommandSupport.HasFlag(CommandSupport.SetBlockCount) ?? + false; mediaTags.Add(MediaTagType.SD_SCR, null); } @@ -237,8 +236,8 @@ public partial class Dump } } - UpdateStatus?.Invoke("Reading CID"); - _dumpLog.WriteLine("Reading CID"); + UpdateStatus?.Invoke(Localization.Core.Reading_CID); + _dumpLog.WriteLine(Localization.Core.Reading_CID); sense = _dev.ReadCid(out byte[] cid, out response, timeout, out duration); if(sense) @@ -249,43 +248,39 @@ public partial class Dump else mediaTags.Add(_dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID : MediaTagType.MMC_CID, null); - DateTime start; - DateTime end; - double totalDuration = 0; - double currentSpeed = 0; - double maxSpeed = double.MinValue; - double minSpeed = double.MaxValue; + double totalDuration = 0; + double currentSpeed = 0; + double maxSpeed = double.MinValue; + double minSpeed = double.MaxValue; if(blocks == 0) { - _dumpLog.WriteLine("Unable to get device size."); - StoppingErrorMessage?.Invoke("Unable to get device size."); + _dumpLog.WriteLine(Localization.Core.Unable_to_get_device_size); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_get_device_size); return; } - UpdateStatus?.Invoke($"Device reports {blocks} blocks."); - _dumpLog.WriteLine("Device reports {0} blocks.", blocks); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_reports_0_blocks, blocks)); + _dumpLog.WriteLine(Localization.Core.Device_reports_0_blocks, blocks); byte[] cmdBuf; bool error; - if(blocksToRead > _maximumReadable) - blocksToRead = (ushort)_maximumReadable; + if(blocksToRead > _maximumReadable) blocksToRead = (ushort)_maximumReadable; if(supportsCmd23 && blocksToRead > 1) { sense = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, 1, byteAddressed, timeout, out duration); - if(sense || _dev.Error) - supportsCmd23 = false; + if(sense || _dev.Error) supportsCmd23 = false; // Need to restart device, otherwise is it just busy streaming data with no one listening sense = _dev.ReOpen(); if(sense) { - StoppingErrorMessage?.Invoke($"Error {_dev.LastError} reopening device."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_0_reopening_device, _dev.LastError)); return; } @@ -295,82 +290,83 @@ public partial class Dump { while(true) { - error = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed, timeout, + error = _dev.ReadWithBlockCount(out cmdBuf, + out _, + 0, + blockSize, + blocksToRead, + byteAddressed, + timeout, out duration); - if(error) - blocksToRead /= 2; + if(error) blocksToRead /= 2; - if(!error || - blocksToRead == 1) - break; + if(!error || blocksToRead == 1) break; } if(error) { - _dumpLog.WriteLine("ERROR: Cannot get blocks to read, device error {0}.", _dev.LastError); + _dumpLog.WriteLine(Localization.Core.ERROR_Cannot_get_blocks_to_read_device_error_0, _dev.LastError); - StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Device_error_0_trying_to_guess_ideal_transfer_length, + _dev.LastError)); return; } } - if(_useBufferedReads && - blocksToRead > 1 && - !supportsCmd23) + if(_useBufferedReads && blocksToRead > 1 && !supportsCmd23) { while(true) { error = _dev.BufferedOsRead(out cmdBuf, 0, blockSize * blocksToRead, out duration); - if(error) - blocksToRead /= 2; + if(error) blocksToRead /= 2; - if(!error || - blocksToRead == 1) - break; + if(!error || blocksToRead == 1) break; // Device is in timeout, reopen to reset - if(_dev.LastError == 110) - _dev.ReOpen(); + if(_dev.LastError == 110) _dev.ReOpen(); } if(error) { - UpdateStatus?.Invoke("Buffered OS reads are not working, trying direct commands."); - _dumpLog.WriteLine("Buffered OS reads are not working, trying direct commands."); + UpdateStatus?.Invoke(Localization.Core.DumBuffered_OS_reads_are_not_working_trying_direct_commands); + _dumpLog.WriteLine(Localization.Core.DumBuffered_OS_reads_are_not_working_trying_direct_commands); blocksToRead = 1; _useBufferedReads = false; } } - if(!_useBufferedReads && - blocksToRead > 1 && - !supportsCmd23) + if(!_useBufferedReads && blocksToRead > 1 && !supportsCmd23) { while(true) { - error = _dev.ReadMultipleUsingSingle(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed, - timeout, out duration); + error = _dev.ReadMultipleUsingSingle(out cmdBuf, + out _, + 0, + blockSize, + blocksToRead, + byteAddressed, + timeout, + out duration); - if(error) - blocksToRead /= 2; + if(error) blocksToRead /= 2; // Device is in timeout, reopen to reset - if(_dev.LastError == 110) - _dev.ReOpen(); + if(_dev.LastError == 110) _dev.ReOpen(); - if(!error || - blocksToRead == 1) - break; + if(!error || blocksToRead == 1) break; } if(error) { - _dumpLog.WriteLine("ERROR: Cannot get blocks to read, device error {0}.", _dev.LastError); + _dumpLog.WriteLine(Localization.Core.ERROR_Cannot_get_blocks_to_read_device_error_0, _dev.LastError); - StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Device_error_0_trying_to_guess_ideal_transfer_length, + _dev.LastError)); return; } @@ -382,9 +378,10 @@ public partial class Dump if(error) { - _dumpLog.WriteLine("ERROR: Could not read from device, device error {0}.", _dev.LastError); + _dumpLog.WriteLine(Localization.Core.ERROR_Could_not_read_from_device_device_error_0, _dev.LastError); - StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to read from device."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Device_error_0_trying_to_read_from_device, + _dev.LastError)); return; } @@ -392,33 +389,48 @@ public partial class Dump if(supportsCmd23 || blocksToRead == 1) { - UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time."); - _dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead)); + _dumpLog.WriteLine(Localization.Core.Device_can_read_0_blocks_at_a_time, blocksToRead); } else if(_useBufferedReads) { - UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time using OS buffered reads."); - _dumpLog.WriteLine("Device can read {0} blocks at a time using OS buffered reads.", blocksToRead); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Device_can_read_0_blocks_at_a_time_using_OS_buffered_reads, + blocksToRead)); + + _dumpLog.WriteLine(Localization.Core.Device_can_read_0_blocks_at_a_time_using_OS_buffered_reads, + blocksToRead); } else { - UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks using sequential commands."); - _dumpLog.WriteLine("Device can read {0} blocks using sequential commands.", blocksToRead); + UpdateStatus?.Invoke(string.Format(Localization.Core.Device_can_read_0_blocks_using_sequential_commands, + blocksToRead)); + + _dumpLog.WriteLine(Localization.Core.Device_can_read_0_blocks_using_sequential_commands, blocksToRead); } - if(_skip < blocksToRead) - _skip = blocksToRead; + if(_skip < blocksToRead) _skip = blocksToRead; - DumpHardwareType currentTry = null; - ExtentsULong extents = null; + DumpHardware currentTry = null; + ExtentsULong extents = null; - ResumeSupport.Process(true, false, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial, _dev.PlatformId, - ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision, _private, _force); + ResumeSupport.Process(true, + false, + blocks, + _dev.Manufacturer, + _dev.Model, + _dev.Serial, + _dev.PlatformId, + ref _resume, + ref currentTry, + ref extents, + _dev.FirmwareRevision, + _private, + _force); - if(currentTry == null || - extents == null) + if(currentTry == null || extents == null) { - StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_process_resume_file_not_continuing); return; } @@ -428,40 +440,50 @@ public partial class Dump foreach(MediaTagType tag in mediaTags.Keys.Where(tag => !outputFormat.SupportedMediaTags.Contains(tag))) { ret = false; - _dumpLog.WriteLine($"Output format does not support {tag}."); - ErrorMessage?.Invoke($"Output format does not support {tag}."); + _dumpLog.WriteLine(string.Format(Localization.Core.Output_format_does_not_support_0, tag)); + ErrorMessage?.Invoke(string.Format(Localization.Core.Output_format_does_not_support_0, tag)); } if(!ret) { if(_force) { - _dumpLog.WriteLine("Several media tags not supported, continuing..."); - ErrorMessage?.Invoke("Several media tags not supported, continuing..."); + _dumpLog.WriteLine(Localization.Core.Several_media_tags_not_supported_continuing); + ErrorMessage?.Invoke(Localization.Core.Several_media_tags_not_supported_continuing); } else { - _dumpLog.WriteLine("Several media tags not supported, not continuing..."); - StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Several_media_tags_not_supported_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Several_media_tags_not_supported_not_continuing); return; } } - var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private); - var ibgLog = new IbgLog(_outputPrefix + ".ibg", sdProfile); + var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", + _dev, + blocks, + blockSize, + blocksToRead, + _private, + _dimensions); + + var ibgLog = new IbgLog(_outputPrefix + ".ibg", sdProfile); ret = outputFormat.Create(_outputPath, _dev.Type == DeviceType.SecureDigital ? MediaType.SecureDigital : MediaType.MMC, - _formatOptions, blocks, blockSize); + _formatOptions, + blocks, + blockSize); // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputFormat.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -469,38 +491,41 @@ public partial class Dump if(cid != null) { - if(_dev.Type == DeviceType.SecureDigital && _private) + switch(_dev.Type) { - // Clear serial number and manufacturing date - cid[9] = 0; - cid[10] = 0; - cid[11] = 0; - cid[12] = 0; - cid[13] = 0; - cid[14] = 0; - } - else if(_dev.Type == DeviceType.MMC && _private) - { - // Clear serial number and manufacturing date - cid[10] = 0; - cid[11] = 0; - cid[12] = 0; - cid[13] = 0; - cid[14] = 0; + case DeviceType.SecureDigital when _private: + // Clear serial number and manufacturing date + cid[9] = 0; + cid[10] = 0; + cid[11] = 0; + cid[12] = 0; + cid[13] = 0; + cid[14] = 0; + + break; + case DeviceType.MMC when _private: + // Clear serial number and manufacturing date + cid[10] = 0; + cid[11] = 0; + cid[12] = 0; + cid[13] = 0; + cid[14] = 0; + + break; } - ret = - outputFormat.WriteMediaTag(cid, - _dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID - : MediaTagType.MMC_CID); + ret = outputFormat.WriteMediaTag(cid, + _dev.Type == DeviceType.SecureDigital + ? MediaTagType.SD_CID + : MediaTagType.MMC_CID); // Cannot write CID to image - if(!ret && - !_force) + if(!ret && !_force) { - _dumpLog.WriteLine("Cannot write CID to output image."); + _dumpLog.WriteLine(Localization.Core.Cannot_write_CID_to_output_image); - StoppingErrorMessage?.Invoke("Cannot write CID to output image." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_write_CID_to_output_image + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -509,18 +534,18 @@ public partial class Dump if(csd != null) { - ret = - outputFormat.WriteMediaTag(csd, - _dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CSD - : MediaTagType.MMC_CSD); + ret = outputFormat.WriteMediaTag(csd, + _dev.Type == DeviceType.SecureDigital + ? MediaTagType.SD_CSD + : MediaTagType.MMC_CSD); // Cannot write CSD to image - if(!ret && - !_force) + if(!ret && !_force) { - _dumpLog.WriteLine("Cannot write CSD to output image."); + _dumpLog.WriteLine(Localization.Core.Cannot_write_CSD_to_output_image); - StoppingErrorMessage?.Invoke("Cannot write CSD to output image." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_write_CSD_to_output_image + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -532,12 +557,12 @@ public partial class Dump ret = outputFormat.WriteMediaTag(ecsd, MediaTagType.MMC_ExtendedCSD); // Cannot write Extended CSD to image - if(!ret && - !_force) + if(!ret && !_force) { - _dumpLog.WriteLine("Cannot write Extended CSD to output image."); + _dumpLog.WriteLine(Localization.Core.Cannot_write_Extended_CSD_to_output_image); - StoppingErrorMessage?.Invoke("Cannot write Extended CSD to output image." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_write_Extended_CSD_to_output_image + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -546,18 +571,18 @@ public partial class Dump if(ocr != null) { - ret = - outputFormat.WriteMediaTag(ocr, - _dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_OCR - : MediaTagType.MMC_OCR); + ret = outputFormat.WriteMediaTag(ocr, + _dev.Type == DeviceType.SecureDigital + ? MediaTagType.SD_OCR + : MediaTagType.MMC_OCR); // Cannot write OCR to image - if(!ret && - !_force) + if(!ret && !_force) { - _dumpLog.WriteLine("Cannot write OCR to output image."); + _dumpLog.WriteLine(Localization.Core.Cannot_write_OCR_to_output_image); - StoppingErrorMessage?.Invoke("Cannot write OCR to output image." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_write_OCR_to_output_image + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -569,12 +594,12 @@ public partial class Dump ret = outputFormat.WriteMediaTag(scr, MediaTagType.SD_SCR); // Cannot write SCR to image - if(!ret && - !_force) + if(!ret && !_force) { - _dumpLog.WriteLine("Cannot write SCR to output image."); + _dumpLog.WriteLine(Localization.Core.Cannot_write_SCR_to_output_image); - StoppingErrorMessage?.Invoke("Cannot write SCR to output image." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_write_SCR_to_output_image + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -583,15 +608,36 @@ public partial class Dump if(_resume.NextBlock > 0) { - UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}."); - _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); + UpdateStatus?.Invoke(string.Format(Localization.Core.Resuming_from_block_0, _resume.NextBlock)); + _dumpLog.WriteLine(Localization.Core.Resuming_from_block_0, _resume.NextBlock); } - start = DateTime.UtcNow; - double imageWriteDuration = 0; - var newTrim = false; - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + if(_createGraph) + { + Spiral.DiscParameters discSpiralParameters = + Spiral.DiscParametersFromMediaType(_dev.Type == DeviceType.SecureDigital + ? MediaType.SecureDigital + : MediaType.MMC); + + if(discSpiralParameters is not null) + _mediaGraph = new Spiral((int)_dimensions, (int)_dimensions, discSpiralParameters, blocks); + else + _mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, blocks); + + if(_mediaGraph is not null) + { + foreach(Tuple e in extents.ToArray()) + _mediaGraph?.PaintSectorsGood(e.Item1, (uint)(e.Item2 - e.Item1 + 2)); + } + + _mediaGraph?.PaintSectorsBad(_resume.BadBlocks); + } + + _dumpStopwatch.Restart(); + _speedStopwatch.Reset(); + double imageWriteDuration = 0; + var newTrim = false; + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); @@ -600,115 +646,154 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(blocks - i < blocksToRead) - blocksToRead = (byte)(blocks - i); + if(blocks - i < blocksToRead) blocksToRead = (byte)(blocks - i); - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)blocks); + _speedStopwatch.Start(); + if(blocksToRead == 1) - error = _dev.ReadSingleBlock(out cmdBuf, out _, (uint)i, blockSize, byteAddressed, timeout, + { + error = _dev.ReadSingleBlock(out cmdBuf, + out _, + (uint)i, + blockSize, + byteAddressed, + timeout, out duration); + } else if(supportsCmd23) - error = _dev.ReadWithBlockCount(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed, - timeout, out duration); + { + error = _dev.ReadWithBlockCount(out cmdBuf, + out _, + (uint)i, + blockSize, + blocksToRead, + byteAddressed, + timeout, + out duration); + } else if(_useBufferedReads) error = _dev.BufferedOsRead(out cmdBuf, (long)(i * blockSize), blockSize * blocksToRead, out duration); else - error = _dev.ReadMultipleUsingSingle(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed, - timeout, out duration); + { + error = _dev.ReadMultipleUsingSingle(out cmdBuf, + out _, + (uint)i, + blockSize, + blocksToRead, + byteAddressed, + timeout, + out duration); + } + + _speedStopwatch.Stop(); if(!error) { - mhddLog.Write(i, duration); + mhddLog.Write(i, duration, blocksToRead); ibgLog.Write(i, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(cmdBuf, i, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(i, blocksToRead, true); + _mediaGraph?.PaintSectorsGood(i, blocksToRead); } else { _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, byteAddressed, response); - if(i + _skip > blocks) - _skip = (uint)(blocks - i); + if(i + _skip > blocks) _skip = (uint)(blocks - i); - for(ulong b = i; b < i + _skip; b++) - _resume.BadBlocks.Add(b); + for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b); - mhddLog.Write(i, duration < 500 ? 65535 : duration); + mhddLog.Write(i, duration < 500 ? 65535 : duration, _skip); ibgLog.Write(i, 0); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i); i += _skip - blocksToRead; newTrim = true; } + _writeStopwatch.Stop(); sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); - end = DateTime.Now; + _speedStopwatch.Stop(); + _dumpStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), _devicePath); + ibgLog.Close(_dev, + blocks, + blockSize, + _dumpStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), + _devicePath); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - #region Trimming - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _trim && - newTrim) +#region Trimming + + if(_resume.BadBlocks.Count > 0 && !_aborted && _trim && newTrim) { - start = DateTime.UtcNow; - UpdateStatus?.Invoke("Trimming skipped sectors"); - _dumpLog.WriteLine("Trimming skipped sectors"); + _trimStopwatch.Restart(); + UpdateStatus?.Invoke(Localization.Core.Trimming_skipped_sectors); + _dumpLog.WriteLine(Localization.Core.Trimming_skipped_sectors); ulong[] tmpArray = _resume.BadBlocks.ToArray(); InitProgress?.Invoke(); @@ -718,16 +803,21 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke($"Trimming sector {badSector}"); + PulseProgress?.Invoke(string.Format(Localization.Core.Trimming_sector_0, badSector)); - error = _dev.ReadSingleBlock(out cmdBuf, out response, (uint)badSector, blockSize, byteAddressed, - timeout, out duration); + error = _dev.ReadSingleBlock(out cmdBuf, + out response, + (uint)badSector, + blockSize, + byteAddressed, + timeout, + out duration); totalDuration += duration; @@ -741,23 +831,27 @@ public partial class Dump _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(cmdBuf, badSector); + _mediaGraph?.PaintSectorGood(badSector); } EndProgress?.Invoke(); - end = DateTime.UtcNow; - UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds."); - _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds); - } - #endregion Trimming + _trimStopwatch.Stop(); - #region Error handling - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _retryPasses > 0) + UpdateStatus?.Invoke(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + } + +#endregion Trimming + +#region Error handling + + if(_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0) { - var pass = 1; - var forward = true; - var runningPersistent = false; + var pass = 1; + var forward = true; InitProgress?.Invoke(); repeatRetryLba: @@ -768,84 +862,101 @@ public partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass, - forward ? "forward" : "reverse", - runningPersistent ? "recovering partial data, " : "")); + PulseProgress?.Invoke(forward + ? string.Format(Localization.Core.Retrying_sector_0_pass_1_forward, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_reverse, + badSector, + pass)); - error = _dev.ReadSingleBlock(out cmdBuf, out response, (uint)badSector, blockSize, byteAddressed, - timeout, out duration); + error = _dev.ReadSingleBlock(out cmdBuf, + out response, + (uint)badSector, + blockSize, + byteAddressed, + timeout, + out duration); totalDuration += duration; if(error) + { _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, byteAddressed, response); - if(!error) - { - _resume.BadBlocks.Remove(badSector); - extents.Add(badSector); - outputFormat.WriteSector(cmdBuf, badSector); - UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}."); - _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); + continue; } - else if(runningPersistent) - outputFormat.WriteSector(cmdBuf, badSector); + + _resume.BadBlocks.Remove(badSector); + extents.Add(badSector); + outputFormat.WriteSector(cmdBuf, badSector); + _mediaGraph?.PaintSectorGood(badSector); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_block_0_in_pass_1, + badSector, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_block_0_in_pass_1, badSector, pass); } - if(pass < _retryPasses && - !_aborted && - _resume.BadBlocks.Count > 0) + if(pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); - if(!forward) - _resume.BadBlocks.Reverse(); + if(!forward) _resume.BadBlocks.Reverse(); goto repeatRetryLba; } EndProgress?.Invoke(); } - #endregion Error handling + +#endregion Error handling currentTry.Extents = ExtentsConverter.ToMetadata(extents); outputFormat.SetDumpHardware(_resume.Tries); // TODO: Drive info - var metadata = new ImageInfo + var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; - if(!outputFormat.SetMetadata(metadata)) - ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + + if(!outputFormat.SetImageInfo(metadata)) + { + ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + + Environment.NewLine + outputFormat.ErrorMessage); + } - if(_preSidecar != null) - outputFormat.SetCicmMetadata(_preSidecar); + if(_preSidecar != null) outputFormat.SetMetadata(_preSidecar); - _dumpLog.WriteLine("Closing output file."); - UpdateStatus?.Invoke("Closing output file."); - DateTime closeStart = DateTime.Now; + _dumpLog.WriteLine(Localization.Core.Closing_output_file); + UpdateStatus?.Invoke(Localization.Core.Closing_output_file); + _imageCloseStopwatch.Restart(); outputFormat.Close(); - DateTime closeEnd = DateTime.Now; - UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); - _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); + _imageCloseStopwatch.Stop(); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); return; } @@ -854,17 +965,16 @@ public partial class Dump if(_metadata) { - UpdateStatus?.Invoke("Creating sidecar."); - _dumpLog.WriteLine("Creating sidecar."); - var filters = new FiltersList(); - IFilter filter = filters.GetFilter(_outputPath); + UpdateStatus?.Invoke(Localization.Core.Creating_sidecar); + _dumpLog.WriteLine(Localization.Core.Creating_sidecar); + IFilter filter = PluginRegister.Singleton.GetFilter(_outputPath); var inputPlugin = ImageFormat.Detect(filter) as IMediaImage; ErrorNumber opened = inputPlugin.Open(filter); if(opened != ErrorNumber.NoError) - StoppingErrorMessage?.Invoke($"Error {opened} opening created image."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_0_opening_created_image, opened)); - DateTime chkStart = DateTime.UtcNow; + _sidecarStopwatch.Restart(); _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); _sidecarClass.InitProgressEvent += InitProgress; _sidecarClass.UpdateProgressEvent += UpdateProgress; @@ -873,28 +983,34 @@ public partial class Dump _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; - CICMMetadataType sidecar = _sidecarClass.Create(); + Metadata sidecar = _sidecarClass.Create(); + _sidecarStopwatch.Stop(); if(!_aborted) { if(_preSidecar != null) { - _preSidecar.BlockMedia = sidecar.BlockMedia; - sidecar = _preSidecar; + _preSidecar.BlockMedias = sidecar.BlockMedias; + sidecar = _preSidecar; } - end = DateTime.UtcNow; + totalChkDuration = _sidecarStopwatch.Elapsed.TotalMilliseconds; - totalChkDuration = (end - chkStart).TotalMilliseconds; - UpdateStatus?.Invoke($"Sidecar created in {(end - chkStart).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average checksum speed {blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds); + _dumpLog.WriteLine(Localization.Core.Sidecar_created_in_0, + _sidecarStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); - _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); + _dumpLog.WriteLine(Localization.Core.Average_checksum_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalChkDuration.Milliseconds()) + .Humanize()); (string type, string subType) xmlType = (null, null); @@ -903,62 +1019,78 @@ public partial class Dump case DeviceType.MMC: xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.MMC); - sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(MediaType.MMC); + sidecar.BlockMedias[0].Dimensions = Dimensions.FromMediaType(MediaType.MMC); break; case DeviceType.SecureDigital: CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.SecureDigital); - sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(MediaType.SecureDigital); + sidecar.BlockMedias[0].Dimensions = Dimensions.FromMediaType(MediaType.SecureDigital); break; } - sidecar.BlockMedia[0].DiskType = xmlType.type; - sidecar.BlockMedia[0].DiskSubType = xmlType.subType; + sidecar.BlockMedias[0].MediaType = xmlType.type; + sidecar.BlockMedias[0].MediaSubType = xmlType.subType; // TODO: Implement device firmware revision - sidecar.BlockMedia[0].LogicalBlocks = blocks; - sidecar.BlockMedia[0].PhysicalBlockSize = physicalBlockSize > 0 ? physicalBlockSize : blockSize; - sidecar.BlockMedia[0].LogicalBlockSize = blockSize; - sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer; - sidecar.BlockMedia[0].Model = _dev.Model; + sidecar.BlockMedias[0].LogicalBlocks = blocks; + sidecar.BlockMedias[0].PhysicalBlockSize = physicalBlockSize > 0 ? physicalBlockSize : blockSize; + sidecar.BlockMedias[0].LogicalBlockSize = blockSize; + sidecar.BlockMedias[0].Manufacturer = _dev.Manufacturer; + sidecar.BlockMedias[0].Model = _dev.Model; - if(!_private) - sidecar.BlockMedia[0].Serial = _dev.Serial; + if(!_private) sidecar.BlockMedias[0].Serial = _dev.Serial; - sidecar.BlockMedia[0].Size = blocks * blockSize; + sidecar.BlockMedias[0].Size = blocks * blockSize; - UpdateStatus?.Invoke("Writing metadata sidecar"); + UpdateStatus?.Invoke(Localization.Core.Writing_metadata_sidecar); - var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); + var jsonFs = new FileStream(_outputPrefix + ".metadata.json", FileMode.Create); - var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); - xmlSer.Serialize(xmlFs, sidecar); - xmlFs.Close(); + JsonSerializer.Serialize(jsonFs, + new MetadataJson + { + AaruMetadata = sidecar + }, + typeof(MetadataJson), + MetadataJsonContext.Default); + + jsonFs.Close(); } } UpdateStatus?.Invoke(""); - UpdateStatus?. - Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second), + totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second), + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average speed: {blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); if(maxSpeed > 0) - UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0, + ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize())); + } - if(minSpeed > 0 && - minSpeed < double.MaxValue) - UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); + if(minSpeed is > 0 and < double.MaxValue) + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0, + ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize())); + } - UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); + UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_could_not_be_read, _resume.BadBlocks.Count)); UpdateStatus?.Invoke(""); - if(_resume.BadBlocks.Count > 0) - _resume.BadBlocks.Sort(); + if(_resume.BadBlocks.Count > 0) _resume.BadBlocks.Sort(); switch(_dev.Type) { diff --git a/Aaru.Core/Devices/Dumping/XGD.cs b/Aaru.Core/Devices/Dumping/XGD.cs index e198cf5db..6c08c076a 100644 --- a/Aaru.Core/Devices/Dumping/XGD.cs +++ b/Aaru.Core/Devices/Dumping/XGD.cs @@ -27,35 +27,40 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable JoinDeclarationAndInitializer -namespace Aaru.Core.Devices.Dumping; - using System; using System.Collections.Generic; using System.Linq; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Interop; -using Aaru.CommonTypes.Structs; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Console; +using Aaru.Core.Graphics; using Aaru.Core.Logging; using Aaru.Decoders.DVD; using Aaru.Decoders.SCSI; using Aaru.Decoders.Xbox; using Aaru.Devices; -using Schemas; +using Humanizer; +using Humanizer.Bytes; +using Humanizer.Localisation; using Device = Aaru.Devices.Remote.Device; +using Layers = Aaru.CommonTypes.AaruMetadata.Layers; using PlatformID = Aaru.CommonTypes.Interop.PlatformID; +using Track = Aaru.CommonTypes.Structs.Track; using TrackType = Aaru.CommonTypes.Enums.TrackType; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Devices.Dumping; + /// Implements dumping an Xbox Game Disc using a Kreon drive partial class Dump { @@ -65,10 +70,8 @@ partial class Dump void Xgd(Dictionary mediaTags, MediaType dskType) { bool sense; - const uint blockSize = 2048; - uint blocksToRead = 64; - DateTime start; - DateTime end; + const uint blockSize = 2048; + uint blocksToRead = 64; double totalDuration = 0; double currentSpeed = 0; double maxSpeed = double.MinValue; @@ -76,7 +79,7 @@ partial class Dump if(_outputPlugin is not IWritableImage outputFormat) { - StoppingErrorMessage?.Invoke("Image is not writable, aborting..."); + StoppingErrorMessage?.Invoke(Localization.Core.Image_is_not_writable_aborting); return; } @@ -87,64 +90,69 @@ partial class Dump if(!isAdmin) { - AaruConsole. - ErrorWriteLine("Because of the commands sent to a device, dumping XGD must be done with administrative privileges. Cannot continue."); + AaruConsole.ErrorWriteLine(Localization.Core + .Because_of_commands_sent_dumping_XGD_must_be_administrative_Cannot_continue); - _dumpLog.WriteLine("Cannot dump XGD without administrative privileges."); + _dumpLog.WriteLine(Localization.Core.Cannot_dump_XGD_without_administrative_privileges); return; } } - if(mediaTags.ContainsKey(MediaTagType.DVD_PFI)) - mediaTags.Remove(MediaTagType.DVD_PFI); + if(mediaTags.ContainsKey(MediaTagType.DVD_PFI)) mediaTags.Remove(MediaTagType.DVD_PFI); - if(mediaTags.ContainsKey(MediaTagType.DVD_DMI)) - mediaTags.Remove(MediaTagType.DVD_DMI); + if(mediaTags.ContainsKey(MediaTagType.DVD_DMI)) mediaTags.Remove(MediaTagType.DVD_DMI); // Drive shall move to lock state when a new disc is inserted. Old kreon versions do not lock correctly so save this sense = _dev.ReadCapacity(out byte[] coldReadCapacity, out byte[] senseBuf, _dev.Timeout, out _); if(sense) { - _dumpLog.WriteLine("Cannot get disc capacity."); - StoppingErrorMessage?.Invoke("Cannot get disc capacity."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_disc_capacity); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_disc_capacity); return; } // Drive shall move to lock state when a new disc is inserted. Old kreon versions do not lock correctly so save this - sense = _dev.ReadDiscStructure(out byte[] coldPfi, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); + sense = _dev.ReadDiscStructure(out byte[] coldPfi, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + 0, + out _); if(sense) { - _dumpLog.WriteLine("Cannot get PFI."); - StoppingErrorMessage?.Invoke("Cannot get PFI."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_PFI); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_PFI); return; } - UpdateStatus?.Invoke("Reading Xbox Security Sector."); - _dumpLog.WriteLine("Reading Xbox Security Sector."); + UpdateStatus?.Invoke(Localization.Core.Reading_Xbox_Security_Sector); + _dumpLog.WriteLine(Localization.Core.Reading_Xbox_Security_Sector); sense = _dev.KreonExtractSs(out byte[] ssBuf, out senseBuf, _dev.Timeout, out _); if(sense) { - _dumpLog.WriteLine("Cannot get Xbox Security Sector, not continuing."); - StoppingErrorMessage?.Invoke("Cannot get Xbox Security Sector, not continuing."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_Xbox_Security_Sector_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_Xbox_Security_Sector_not_continuing); return; } - _dumpLog.WriteLine("Decoding Xbox Security Sector."); - UpdateStatus?.Invoke("Decoding Xbox Security Sector."); + _dumpLog.WriteLine(Localization.Core.Decoding_Xbox_Security_Sector); + UpdateStatus?.Invoke(Localization.Core.Decoding_Xbox_Security_Sector); SS.SecuritySector? xboxSs = SS.Decode(ssBuf); if(!xboxSs.HasValue) { - _dumpLog.WriteLine("Cannot decode Xbox Security Sector, not continuing."); - StoppingErrorMessage?.Invoke("Cannot decode Xbox Security Sector, not continuing."); + _dumpLog.WriteLine(Localization.Core.Cannot_decode_Xbox_Security_Sector_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_decode_Xbox_Security_Sector_not_continuing); return; } @@ -154,29 +162,29 @@ partial class Dump mediaTags.Add(MediaTagType.Xbox_SecuritySector, tmpBuf); // Get video partition size - AaruConsole.DebugWriteLine("Dump-media command", "Getting video partition size"); - UpdateStatus?.Invoke("Locking drive."); - _dumpLog.WriteLine("Locking drive."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Getting_video_partition_size); + UpdateStatus?.Invoke(Localization.Core.Locking_drive); + _dumpLog.WriteLine(Localization.Core.Locking_drive); sense = _dev.KreonLock(out senseBuf, _dev.Timeout, out _); if(sense) { _errorLog?.WriteLine("Kreon lock", _dev.Error, _dev.LastError, senseBuf); - _dumpLog.WriteLine("Cannot lock drive, not continuing."); - StoppingErrorMessage?.Invoke("Cannot lock drive, not continuing."); + _dumpLog.WriteLine(Localization.Core.Cannot_lock_drive_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_lock_drive_not_continuing); return; } - UpdateStatus?.Invoke("Getting video partition size."); - _dumpLog.WriteLine("Getting video partition size."); + UpdateStatus?.Invoke(Localization.Core.Getting_video_partition_size); + _dumpLog.WriteLine(Localization.Core.Getting_video_partition_size); sense = _dev.ReadCapacity(out byte[] readBuffer, out senseBuf, _dev.Timeout, out _); if(sense) { - _dumpLog.WriteLine("Cannot get disc capacity."); - StoppingErrorMessage?.Invoke("Cannot get disc capacity."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_disc_capacity); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_disc_capacity); return; } @@ -184,16 +192,23 @@ partial class Dump ulong totalSize = (ulong)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + readBuffer[3]) & 0xFFFFFFFF; - UpdateStatus?.Invoke("Reading Physical Format Information."); - _dumpLog.WriteLine("Reading Physical Format Information."); + UpdateStatus?.Invoke(Localization.Core.Reading_Physical_Format_Information); + _dumpLog.WriteLine(Localization.Core.Reading_Physical_Format_Information); - sense = _dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); + sense = _dev.ReadDiscStructure(out readBuffer, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + 0, + out _); if(sense) { - _dumpLog.WriteLine("Cannot get PFI."); - StoppingErrorMessage?.Invoke("Cannot get PFI."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_PFI); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_PFI); return; } @@ -201,22 +216,31 @@ partial class Dump tmpBuf = new byte[readBuffer.Length - 4]; Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4); mediaTags.Add(MediaTagType.DVD_PFI, tmpBuf); - AaruConsole.DebugWriteLine("Dump-media command", "Video partition total size: {0} sectors", totalSize); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Video_partition_total_size_0_sectors, totalSize); ulong l0Video = (PFI.Decode(readBuffer, MediaType.DVDROM)?.Layer0EndPSN ?? 0) - - (PFI.Decode(readBuffer, MediaType.DVDROM)?.DataAreaStartPSN ?? 0) + 1; + (PFI.Decode(readBuffer, MediaType.DVDROM)?.DataAreaStartPSN ?? 0) + + 1; ulong l1Video = totalSize - l0Video + 1; - UpdateStatus?.Invoke("Reading Disc Manufacturing Information."); - _dumpLog.WriteLine("Reading Disc Manufacturing Information."); + UpdateStatus?.Invoke(Localization.Core.Reading_Disc_Manufacturing_Information); + _dumpLog.WriteLine(Localization.Core.Reading_Disc_Manufacturing_Information); - sense = _dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DiscManufacturingInformation, 0, 0, out _); + sense = _dev.ReadDiscStructure(out readBuffer, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DiscManufacturingInformation, + 0, + 0, + out _); if(sense) { - _dumpLog.WriteLine("Cannot get DMI."); - StoppingErrorMessage?.Invoke("Cannot get DMI."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_DMI); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_DMI); return; } @@ -228,90 +252,95 @@ partial class Dump // Should be a safe value to detect the lock command was ignored, and we're indeed getting the whole size and not the locked one if(totalSize > 300000) { - UpdateStatus?.Invoke("Video partition is too big, did lock work? Trying cold values."); - _dumpLog.WriteLine("Video partition is too big, did lock work? Trying cold values."); + UpdateStatus?.Invoke(Localization.Core.Video_partition_is_too_big_did_lock_work_Trying_cold_values); + _dumpLog.WriteLine(Localization.Core.Video_partition_is_too_big_did_lock_work_Trying_cold_values); - totalSize = (ulong)((coldReadCapacity[0] << 24) + (coldReadCapacity[1] << 16) + (coldReadCapacity[2] << 8) + - coldReadCapacity[3]) & 0xFFFFFFFF; + totalSize = (ulong)((coldReadCapacity[0] << 24) + + (coldReadCapacity[1] << 16) + + (coldReadCapacity[2] << 8) + + coldReadCapacity[3]) & + 0xFFFFFFFF; tmpBuf = new byte[coldPfi.Length - 4]; Array.Copy(coldPfi, 4, tmpBuf, 0, coldPfi.Length - 4); mediaTags.Remove(MediaTagType.DVD_PFI); mediaTags.Add(MediaTagType.DVD_PFI, tmpBuf); - AaruConsole.DebugWriteLine("Dump-media command", "Video partition total size: {0} sectors", totalSize); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Video_partition_total_size_0_sectors, totalSize); l0Video = (PFI.Decode(coldPfi, MediaType.DVDROM)?.Layer0EndPSN ?? 0) - - (PFI.Decode(coldPfi, MediaType.DVDROM)?.DataAreaStartPSN ?? 0) + 1; + (PFI.Decode(coldPfi, MediaType.DVDROM)?.DataAreaStartPSN ?? 0) + + 1; l1Video = totalSize - l0Video + 1; if(totalSize > 300000) { - _dumpLog.WriteLine("Cannot get video partition size, not continuing. Try to eject and reinsert the drive, if it keeps happening, contact support."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_video_partition_size_not_continuing); - StoppingErrorMessage?. - Invoke("Cannot get video partition size, not continuing. Try to eject and reinsert the drive, if it keeps happening, contact support."); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_video_partition_size_not_continuing); return; } } // Get game partition size - AaruConsole.DebugWriteLine("Dump-media command", "Getting game partition size"); - UpdateStatus?.Invoke("Unlocking drive (Xtreme)."); - _dumpLog.WriteLine("Unlocking drive (Xtreme)."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Getting_game_partition_size); + UpdateStatus?.Invoke(Localization.Core.Unlocking_drive_Xtreme_); + _dumpLog.WriteLine(Localization.Core.Unlocking_drive_Xtreme_); sense = _dev.KreonUnlockXtreme(out senseBuf, _dev.Timeout, out _); if(sense) { _errorLog?.WriteLine("Kreon Xtreme unlock", _dev.Error, _dev.LastError, senseBuf); - _dumpLog.WriteLine("Cannot unlock drive, not continuing."); - StoppingErrorMessage?.Invoke("Cannot unlock drive, not continuing."); + _dumpLog.WriteLine(Localization.Core.Cannot_unlock_drive_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_unlock_drive_not_continuing); return; } - UpdateStatus?.Invoke("Getting game partition size."); - _dumpLog.WriteLine("Getting game partition size."); + UpdateStatus?.Invoke(Localization.Core.Getting_game_partition_size); + _dumpLog.WriteLine(Localization.Core.Getting_game_partition_size); sense = _dev.ReadCapacity(out readBuffer, out senseBuf, _dev.Timeout, out _); if(sense) { - _dumpLog.WriteLine("Cannot get disc capacity."); - StoppingErrorMessage?.Invoke("Cannot get disc capacity."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_disc_capacity); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_disc_capacity); return; } ulong gameSize = ((ulong)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + readBuffer[3]) & - 0xFFFFFFFF) + 1; + 0xFFFFFFFF) + + 1; - AaruConsole.DebugWriteLine("Dump-media command", "Game partition total size: {0} sectors", gameSize); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Game_partition_total_size_0_sectors, gameSize); // Get middle zone size - AaruConsole.DebugWriteLine("Dump-media command", "Getting middle zone size"); - UpdateStatus?.Invoke("Unlocking drive (Wxripper)."); - _dumpLog.WriteLine("Unlocking drive (Wxripper)."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Getting_middle_zone_size); + UpdateStatus?.Invoke(Localization.Core.Unlocking_drive_Wxripper); + _dumpLog.WriteLine(Localization.Core.Unlocking_drive_Wxripper); sense = _dev.KreonUnlockWxripper(out senseBuf, _dev.Timeout, out _); if(sense) { _errorLog?.WriteLine("Kreon Wxripper unlock", _dev.Error, _dev.LastError, senseBuf); - _dumpLog.WriteLine("Cannot unlock drive, not continuing."); - StoppingErrorMessage?.Invoke("Cannot unlock drive, not continuing."); + _dumpLog.WriteLine(Localization.Core.Cannot_unlock_drive_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_unlock_drive_not_continuing); return; } - UpdateStatus?.Invoke("Getting disc size."); - _dumpLog.WriteLine("Getting disc size."); + UpdateStatus?.Invoke(Localization.Core.Getting_disc_size); + _dumpLog.WriteLine(Localization.Core.Getting_disc_size); sense = _dev.ReadCapacity(out readBuffer, out senseBuf, _dev.Timeout, out _); if(sense) { - _dumpLog.WriteLine("Cannot get disc capacity."); - StoppingErrorMessage?.Invoke("Cannot get disc capacity."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_disc_capacity); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_disc_capacity); return; } @@ -319,39 +348,54 @@ partial class Dump totalSize = (ulong)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + readBuffer[3]) & 0xFFFFFFFF; - UpdateStatus?.Invoke("Reading Physical Format Information."); - _dumpLog.WriteLine("Reading Physical Format Information."); + UpdateStatus?.Invoke(Localization.Core.Reading_Physical_Format_Information); + _dumpLog.WriteLine(Localization.Core.Reading_Physical_Format_Information); - sense = _dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); + sense = _dev.ReadDiscStructure(out readBuffer, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + 0, + out _); if(sense) { - _dumpLog.WriteLine("Cannot get PFI."); - StoppingErrorMessage?.Invoke("Cannot get PFI."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_PFI); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_PFI); return; } - AaruConsole.DebugWriteLine("Dump-media command", "Unlocked total size: {0} sectors", totalSize); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Unlocked_total_size_0_sectors, totalSize); ulong blocks = totalSize + 1; PFI.PhysicalFormatInformation? wxRipperPfiNullable = PFI.Decode(readBuffer, MediaType.DVDROM); if(wxRipperPfiNullable == null) { - _dumpLog.WriteLine("Cannot decode PFI."); - StoppingErrorMessage?.Invoke("Cannot decode PFI."); + _dumpLog.WriteLine(Localization.Core.Cannot_decode_PFI); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_decode_PFI); return; } - PFI.PhysicalFormatInformation wxRipperPfi = wxRipperPfiNullable.Value; + // Guaranteed to never fall into default + PFI.PhysicalFormatInformation wxRipperPfi = wxRipperPfiNullable ?? default(PFI.PhysicalFormatInformation); - UpdateStatus?.Invoke($"WxRipper PFI's Data Area Start PSN: {wxRipperPfi.DataAreaStartPSN} sectors"); - UpdateStatus?.Invoke($"WxRipper PFI's Layer 0 End PSN: {wxRipperPfi.Layer0EndPSN} sectors"); - _dumpLog.WriteLine($"WxRipper PFI's Data Area Start PSN: {wxRipperPfi.DataAreaStartPSN} sectors"); - _dumpLog.WriteLine($"WxRipper PFI's Layer 0 End PSN: {wxRipperPfi.Layer0EndPSN} sectors"); + UpdateStatus?.Invoke(string.Format(Localization.Core.WxRipper_PFI_Data_Area_Start_PSN_0_sectors, + wxRipperPfi.DataAreaStartPSN)); + + UpdateStatus?.Invoke(string.Format(Localization.Core.WxRipper_PFI_Layer_0_End_PSN_0_sectors, + wxRipperPfi.Layer0EndPSN)); + + _dumpLog.WriteLine(string.Format(Localization.Core.WxRipper_PFI_Data_Area_Start_PSN_0_sectors, + wxRipperPfi.DataAreaStartPSN)); + + _dumpLog.WriteLine(string.Format(Localization.Core.WxRipper_PFI_Layer_0_End_PSN_0_sectors, + wxRipperPfi.Layer0EndPSN)); ulong middleZone = totalSize - (wxRipperPfi.Layer0EndPSN - wxRipperPfi.DataAreaStartPSN + 1) - gameSize + 1; @@ -359,16 +403,23 @@ partial class Dump Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4); mediaTags.Add(MediaTagType.Xbox_PFI, tmpBuf); - UpdateStatus?.Invoke("Reading Disc Manufacturing Information."); - _dumpLog.WriteLine("Reading Disc Manufacturing Information."); + UpdateStatus?.Invoke(Localization.Core.Reading_Disc_Manufacturing_Information); + _dumpLog.WriteLine(Localization.Core.Reading_Disc_Manufacturing_Information); - sense = _dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DiscManufacturingInformation, 0, 0, out _); + sense = _dev.ReadDiscStructure(out readBuffer, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DiscManufacturingInformation, + 0, + 0, + out _); if(sense) { - _dumpLog.WriteLine("Cannot get DMI."); - StoppingErrorMessage?.Invoke("Cannot get DMI."); + _dumpLog.WriteLine(Localization.Core.Cannot_get_DMI); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_DMI); return; } @@ -380,160 +431,225 @@ partial class Dump totalSize = l0Video + l1Video + middleZone * 2 + gameSize; ulong layerBreak = l0Video + middleZone + gameSize / 2; - UpdateStatus?.Invoke($"Video layer 0 size: {l0Video} sectors"); - UpdateStatus?.Invoke($"Video layer 1 size: {l1Video} sectors"); - UpdateStatus?.Invoke($"Middle zone size: {middleZone} sectors"); - UpdateStatus?.Invoke($"Game data size: {gameSize} sectors"); - UpdateStatus?.Invoke($"Total size: {totalSize} sectors"); - UpdateStatus?.Invoke($"Real layer break: {layerBreak}"); + UpdateStatus?.Invoke(string.Format(Localization.Core.Video_layer_0_size_0_sectors, l0Video)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Video_layer_1_size_0_sectors, l1Video)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Middle_zone_size_0_sectors, middleZone)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Game_data_size_0_sectors, gameSize)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Total_size_0_sectors, totalSize)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Real_layer_break_0, layerBreak)); UpdateStatus?.Invoke(""); - _dumpLog.WriteLine("Video layer 0 size: {0} sectors", l0Video); - _dumpLog.WriteLine("Video layer 1 size: {0} sectors", l1Video); - _dumpLog.WriteLine("Middle zone 0 size: {0} sectors", middleZone); - _dumpLog.WriteLine("Game data 0 size: {0} sectors", gameSize); - _dumpLog.WriteLine("Total 0 size: {0} sectors", totalSize); - _dumpLog.WriteLine("Real layer break: {0}", layerBreak); + _dumpLog.WriteLine(Localization.Core.Video_layer_0_size_0_sectors, l0Video); + _dumpLog.WriteLine(Localization.Core.Video_layer_1_size_0_sectors, l1Video); + _dumpLog.WriteLine(Localization.Core.Middle_zone_size_0_sectors, middleZone); + _dumpLog.WriteLine(Localization.Core.Game_data_size_0_sectors, gameSize); + _dumpLog.WriteLine(Localization.Core.Total_size_0_sectors, totalSize); + _dumpLog.WriteLine(Localization.Core.Real_layer_break_0, layerBreak); - bool read12 = !_dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, - false, _dev.Timeout, out _); + bool read12 = !_dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + true, + false, + false, + 0, + blockSize, + 0, + 1, + false, + _dev.Timeout, + out _); if(!read12) { - _dumpLog.WriteLine("Cannot read medium, aborting scan..."); - StoppingErrorMessage?.Invoke("Cannot read medium, aborting scan..."); + _dumpLog.WriteLine(Localization.Core.Cannot_read_medium_aborting_scan); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_read_medium_aborting_scan); return; } - _dumpLog.WriteLine("Using SCSI READ (12) command."); - UpdateStatus?.Invoke("Using SCSI READ (12) command."); + _dumpLog.WriteLine(Localization.Core.Using_SCSI_READ_12_command); + UpdateStatus?.Invoke(Localization.Core.Using_SCSI_READ_12_command); // Set speed if(_speedMultiplier >= 0) { - _dumpLog.WriteLine($"Setting speed to {(_speed == 0 ? "MAX." : $"{_speed}x")}."); - UpdateStatus?.Invoke($"Setting speed to {(_speed == 0 ? "MAX." : $"{_speed}x")}."); + if(_speed == 0) + { + _dumpLog.WriteLine(Localization.Core.Setting_speed_to_MAX); + UpdateStatus?.Invoke(Localization.Core.Setting_speed_to_MAX); + } + else + { + _dumpLog.WriteLine(string.Format(Localization.Core.Setting_speed_to_0_x, _speed)); + UpdateStatus?.Invoke(string.Format(Localization.Core.Setting_speed_to_0_x, _speed)); + } _speed *= _speedMultiplier; - if(_speed is 0 or > 0xFFFF) - _speed = 0xFFFF; + if(_speed is 0 or > 0xFFFF) _speed = 0xFFFF; _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _); } while(true) { - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, 0, blockSize, 0, - blocksToRead, false, _dev.Timeout, out _); + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + false, + false, + false, + 0, + blockSize, + 0, + blocksToRead, + false, + _dev.Timeout, + out _); - if(sense || _dev.Error) - blocksToRead /= 2; + if(sense || _dev.Error) blocksToRead /= 2; - if(!_dev.Error || - blocksToRead == 1) - break; + if(!_dev.Error || blocksToRead == 1) break; } if(_dev.Error) { - _dumpLog.WriteLine("Device error {0} trying to guess ideal transfer length.", _dev.LastError); - StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length."); + _dumpLog.WriteLine(Localization.Core.Device_error_0_trying_to_guess_ideal_transfer_length, _dev.LastError); + + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Device_error_0_trying_to_guess_ideal_transfer_length, + _dev.LastError)); return; } - if(_skip < blocksToRead) - _skip = blocksToRead; + if(_skip < blocksToRead) _skip = blocksToRead; var ret = true; foreach(MediaTagType tag in mediaTags.Keys.Where(tag => !outputFormat.SupportedMediaTags.Contains(tag))) { ret = false; - _dumpLog.WriteLine($"Output format does not support {tag}."); - ErrorMessage?.Invoke($"Output format does not support {tag}."); + _dumpLog.WriteLine(string.Format(Localization.Core.Output_format_does_not_support_0, tag)); + ErrorMessage?.Invoke(string.Format(Localization.Core.Output_format_does_not_support_0, tag)); } if(!ret) { if(_force) { - _dumpLog.WriteLine("Several media tags not supported, continuing..."); - ErrorMessage?.Invoke("Several media tags not supported, continuing..."); + _dumpLog.WriteLine(Localization.Core.Several_media_tags_not_supported_continuing); + ErrorMessage?.Invoke(Localization.Core.Several_media_tags_not_supported_continuing); } else { - _dumpLog.WriteLine("Several media tags not supported, not continuing..."); - StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing..."); + _dumpLog.WriteLine(Localization.Core.Several_media_tags_not_supported_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Several_media_tags_not_supported_not_continuing); return; } } - _dumpLog.WriteLine("Reading {0} sectors at a time.", blocksToRead); - UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time."); + _dumpLog.WriteLine(Localization.Core.Reading_0_sectors_at_a_time, blocksToRead); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time, blocksToRead)); - var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private); - var ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0010); + var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", + _dev, + blocks, + blockSize, + blocksToRead, + _private, + _dimensions); + + var ibgLog = new IbgLog(_outputPrefix + ".ibg", 0x0010); ret = outputFormat.Create(_outputPath, dskType, _formatOptions, blocks, blockSize); // Cannot create image if(!ret) { - _dumpLog.WriteLine("Error creating output image, not continuing."); + _dumpLog.WriteLine(Localization.Core.Error_creating_output_image_not_continuing); _dumpLog.WriteLine(outputFormat.ErrorMessage); - StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + + StoppingErrorMessage?.Invoke(Localization.Core.Error_creating_output_image_not_continuing + + Environment.NewLine + outputFormat.ErrorMessage); return; } - start = DateTime.UtcNow; + _dumpStopwatch.Restart(); double imageWriteDuration = 0; - double cmdDuration = 0; - uint saveBlocksToRead = blocksToRead; - DumpHardwareType currentTry = null; - ExtentsULong extents = null; + double cmdDuration = 0; + uint saveBlocksToRead = blocksToRead; + DumpHardware currentTry = null; + ExtentsULong extents = null; - ResumeSupport.Process(true, true, totalSize, _dev.Manufacturer, _dev.Model, _dev.Serial, _dev.PlatformId, - ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision, _private, _force); + ResumeSupport.Process(true, + true, + totalSize, + _dev.Manufacturer, + _dev.Model, + _dev.Serial, + _dev.PlatformId, + ref _resume, + ref currentTry, + ref extents, + _dev.FirmwareRevision, + _private, + _force); - if(currentTry == null || - extents == null) - StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); + if(currentTry == null || extents == null) + StoppingErrorMessage?.Invoke(Localization.Core.Could_not_process_resume_file_not_continuing); - (outputFormat as IWritableOpticalImage).SetTracks(new List + if(_createGraph) { - new() + Spiral.DiscParameters discSpiralParameters = Spiral.DiscParametersFromMediaType(dskType); + + if(discSpiralParameters is not null) + _mediaGraph = new Spiral((int)_dimensions, (int)_dimensions, discSpiralParameters, blocks); + else + _mediaGraph = new BlockMap((int)_dimensions, (int)_dimensions, blocks); + + if(_mediaGraph is not null) { - BytesPerSector = (int)blockSize, - EndSector = blocks - 1, - Sequence = 1, - RawBytesPerSector = (int)blockSize, - SubchannelType = TrackSubchannelType.None, - Session = 1, - Type = TrackType.Data + foreach(Tuple e in extents.ToArray()) + _mediaGraph?.PaintSectorsGood(e.Item1, (uint)(e.Item2 - e.Item1 + 2)); } - }); + + _mediaGraph?.PaintSectorsBad(_resume.BadBlocks); + } + + (outputFormat as IWritableOpticalImage).SetTracks([ + new Track + { + BytesPerSector = (int)blockSize, + EndSector = blocks - 1, + Sequence = 1, + RawBytesPerSector = (int)blockSize, + SubchannelType = TrackSubchannelType.None, + Session = 1, + Type = TrackType.Data + } + ]); ulong currentSector = _resume.NextBlock; if(_resume.NextBlock > 0) { - UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}."); - _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); + UpdateStatus?.Invoke(string.Format(Localization.Core.Resuming_from_block_0, _resume.NextBlock)); + _dumpLog.WriteLine(Localization.Core.Resuming_from_block_0, _resume.NextBlock); } var newTrim = false; - _dumpLog.WriteLine("Reading game partition."); - UpdateStatus?.Invoke("Reading game partition."); - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _dumpLog.WriteLine(Localization.Core.Reading_game_partition); + UpdateStatus?.Invoke(Localization.Core.Reading_game_partition); + _speedStopwatch.Reset(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(var e = 0; e <= 16; e++) @@ -542,14 +658,13 @@ partial class Dump { _resume.NextBlock = currentSector; currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(currentSector >= blocks) - break; + if(currentSector >= blocks) break; ulong extentStart, extentEnd; @@ -559,14 +674,20 @@ partial class Dump if(xboxSs.Value.Extents[e].StartPSN <= xboxSs.Value.Layer0EndPSN) extentStart = xboxSs.Value.Extents[e].StartPSN - 0x30000; else + { extentStart = (xboxSs.Value.Layer0EndPSN + 1) * 2 - - ((xboxSs.Value.Extents[e].StartPSN ^ 0xFFFFFF) + 1) - 0x30000; + ((xboxSs.Value.Extents[e].StartPSN ^ 0xFFFFFF) + 1) - + 0x30000; + } if(xboxSs.Value.Extents[e].EndPSN <= xboxSs.Value.Layer0EndPSN) extentEnd = xboxSs.Value.Extents[e].EndPSN - 0x30000; else + { extentEnd = (xboxSs.Value.Layer0EndPSN + 1) * 2 - - ((xboxSs.Value.Extents[e].EndPSN ^ 0xFFFFFF) + 1) - 0x30000; + ((xboxSs.Value.Extents[e].EndPSN ^ 0xFFFFFF) + 1) - + 0x30000; + } } // After last extent @@ -576,8 +697,7 @@ partial class Dump extentEnd = blocks; } - if(currentSector > extentEnd) - continue; + if(currentSector > extentEnd) continue; for(ulong i = currentSector; i < extentStart; i += blocksToRead) { @@ -586,94 +706,108 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(extentStart - i < blocksToRead) - blocksToRead = (uint)(extentStart - i); + if(extentStart - i < blocksToRead) blocksToRead = (uint)(extentStart - i); - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {totalSize} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)totalSize); - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)i, blockSize, 0, - blocksToRead, false, _dev.Timeout, out cmdDuration); + _speedStopwatch.Start(); + + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + false, + false, + false, + (uint)i, + blockSize, + 0, + blocksToRead, + false, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); totalDuration += cmdDuration; - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, cmdDuration, blocksToRead); ibgLog.Write(i, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(readBuffer, i, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(i, blocksToRead, true); + _mediaGraph?.PaintSectorsGood(i, blocksToRead); } else { _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly - if(i + _skip > blocks) - _skip = (uint)(blocks - i); + if(i + _skip > blocks) _skip = (uint)(blocks - i); // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(new byte[blockSize * _skip], i, _skip); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; - for(ulong b = i; b < i + _skip; b++) - _resume.BadBlocks.Add(b); + for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b); - AaruConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf)); - mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_error_0, + Sense.PrettifySense(senseBuf)); + + mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip); ibgLog.Write(i, 0); - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i); i += _skip - blocksToRead; - string[] senseLines = Sense.PrettifySense(senseBuf).Split(new[] - { - Environment.NewLine - }, StringSplitOptions.RemoveEmptyEntries); + string[] senseLines = Sense.PrettifySense(senseBuf) + .Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries); - foreach(string senseLine in senseLines) - _dumpLog.WriteLine(senseLine); + foreach(string senseLine in senseLines) _dumpLog.WriteLine(senseLine); newTrim = true; } + _writeStopwatch.Stop(); blocksToRead = saveBlocksToRead; currentSector = i + 1; _resume.NextBlock = currentSector; sectorSpeedStart += blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } + _speedStopwatch.Stop(); + for(ulong i = extentStart; i <= extentEnd; i += blocksToRead) { saveBlocksToRead = blocksToRead; @@ -681,39 +815,39 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(extentEnd - i < blocksToRead) - blocksToRead = (uint)(extentEnd - i) + 1; + if(extentEnd - i < blocksToRead) blocksToRead = (uint)(extentEnd - i) + 1; - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, cmdDuration, blocksToRead); ibgLog.Write(i, currentSpeed * 1024); // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(new byte[blockSize * blocksToRead], i, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; blocksToRead = saveBlocksToRead; extents.Add(i, blocksToRead, true); currentSector = i + 1; _resume.NextBlock = currentSector; + _mediaGraph?.PaintSectorsGood(i, blocksToRead); } - if(!_aborted) - currentSector = extentEnd + 1; + if(!_aborted) currentSector = extentEnd + 1; } + _writeStopwatch.Stop(); _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList(); EndProgress?.Invoke(); // Middle Zone D - UpdateStatus?.Invoke("Writing Middle Zone D (empty)."); - _dumpLog.WriteLine("Writing Middle Zone D (empty)."); + UpdateStatus?.Invoke(Localization.Core.Writing_Middle_Zone_D_empty); + _dumpLog.WriteLine(Localization.Core.Writing_Middle_Zone_D_empty); InitProgress?.Invoke(); for(ulong middle = currentSector - blocks - 1; middle < middleZone - 1; middle += blocksToRead) @@ -721,27 +855,30 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(middleZone - 1 - middle < blocksToRead) - blocksToRead = (uint)(middleZone - 1 - middle); + if(middleZone - 1 - middle < blocksToRead) blocksToRead = (uint)(middleZone - 1 - middle); - UpdateProgress?. - Invoke($"Reading sector {middle + currentSector} of {totalSize} ({currentSpeed:F3} MiB/sec.)", - (long)(middle + currentSector), (long)totalSize); + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + middle + currentSector, + totalSize, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)(middle + currentSector), + (long)totalSize); - mhddLog.Write(middle + currentSector, cmdDuration); + mhddLog.Write(middle + currentSector, cmdDuration, blocksToRead); ibgLog.Write(middle + currentSector, currentSpeed * 1024); // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(new byte[blockSize * blocksToRead], middle + currentSector, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(currentSector, blocksToRead, true); + _writeStopwatch.Stop(); currentSector += blocksToRead; _resume.NextBlock = currentSector; @@ -751,14 +888,14 @@ partial class Dump blocksToRead = saveBlocksToRead; - UpdateStatus?.Invoke("Locking drive."); - _dumpLog.WriteLine("Locking drive."); + UpdateStatus?.Invoke(Localization.Core.Locking_drive); + _dumpLog.WriteLine(Localization.Core.Locking_drive); sense = _dev.KreonLock(out senseBuf, _dev.Timeout, out _); if(sense) { - _dumpLog.WriteLine("Cannot lock drive, not continuing."); - StoppingErrorMessage?.Invoke("Cannot lock drive, not continuing."); + _dumpLog.WriteLine(Localization.Core.Cannot_lock_drive_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_lock_drive_not_continuing); return; } @@ -767,14 +904,14 @@ partial class Dump if(sense) { - StoppingErrorMessage?.Invoke("Cannot get disc capacity."); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_disc_capacity); return; } // Video Layer 1 - _dumpLog.WriteLine("Reading Video Layer 1."); - UpdateStatus?.Invoke("Reading Video Layer 1."); + _dumpLog.WriteLine(Localization.Core.Reading_Video_Layer_1); + UpdateStatus?.Invoke(Localization.Core.Reading_Video_Layer_1); InitProgress?.Invoke(); for(ulong l1 = currentSector - blocks - middleZone + l0Video; l1 < l0Video + l1Video; l1 += blocksToRead) @@ -782,98 +919,110 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - if(l0Video + l1Video - l1 < blocksToRead) - blocksToRead = (uint)(l0Video + l1Video - l1); + if(l0Video + l1Video - l1 < blocksToRead) blocksToRead = (uint)(l0Video + l1Video - l1); - if(currentSpeed > maxSpeed && - currentSpeed > 0) - maxSpeed = currentSpeed; + if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed; - if(currentSpeed < minSpeed && - currentSpeed > 0) - minSpeed = currentSpeed; + if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {currentSector} of {totalSize} ({currentSpeed:F3} MiB/sec.)", - (long)currentSector, (long)totalSize); + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + currentSector, + totalSize, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)currentSector, + (long)totalSize); - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)l1, blockSize, 0, - blocksToRead, false, _dev.Timeout, out cmdDuration); + _speedStopwatch.Start(); + + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + false, + false, + false, + (uint)l1, + blockSize, + 0, + blocksToRead, + false, + _dev.Timeout, + out cmdDuration); + + _speedStopwatch.Stop(); totalDuration += cmdDuration; - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { - mhddLog.Write(currentSector, cmdDuration); + mhddLog.Write(currentSector, cmdDuration, blocksToRead); ibgLog.Write(currentSector, currentSpeed * 1024); - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(readBuffer, currentSector, blocksToRead); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; extents.Add(currentSector, blocksToRead, true); + _mediaGraph?.PaintSectorsGood(currentSector, blocksToRead); } else { _errorLog?.WriteLine(currentSector, _dev.Error, _dev.LastError, senseBuf); // TODO: Reset device after X errors - if(_stopOnError) - return; // TODO: Return more cleanly + if(_stopOnError) return; // TODO: Return more cleanly // Write empty data - DateTime writeStart = DateTime.Now; + _writeStopwatch.Restart(); outputFormat.WriteSectors(new byte[blockSize * _skip], currentSector, _skip); - imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; + imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds; // TODO: Handle errors in video partition //errored += blocksToRead; //resume.BadBlocks.Add(l1); - AaruConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf)); - mhddLog.Write(l1, cmdDuration < 500 ? 65535 : cmdDuration); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.READ_error_0, Sense.PrettifySense(senseBuf)); + mhddLog.Write(l1, cmdDuration < 500 ? 65535 : cmdDuration, _skip); ibgLog.Write(l1, 0); - _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, l1); + _dumpLog.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, l1); l1 += _skip - blocksToRead; - string[] senseLines = Sense.PrettifySense(senseBuf).Split(new[] - { - Environment.NewLine - }, StringSplitOptions.RemoveEmptyEntries); + string[] senseLines = Sense.PrettifySense(senseBuf) + .Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries); - foreach(string senseLine in senseLines) - _dumpLog.WriteLine(senseLine); + foreach(string senseLine in senseLines) _dumpLog.WriteLine(senseLine); } + _writeStopwatch.Stop(); + currentSector += blocksToRead; _resume.NextBlock = currentSector; sectorSpeedStart += blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0 || sectorSpeedStart * blockSize < 524288) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Reset(); } EndProgress?.Invoke(); - UpdateStatus?.Invoke("Unlocking drive (Wxripper)."); - _dumpLog.WriteLine("Unlocking drive (Wxripper)."); + UpdateStatus?.Invoke(Localization.Core.Unlocking_drive_Wxripper); + _dumpLog.WriteLine(Localization.Core.Unlocking_drive_Wxripper); sense = _dev.KreonUnlockWxripper(out senseBuf, _dev.Timeout, out _); if(sense) { _errorLog?.WriteLine("Kreon Wxripper unlock", _dev.Error, _dev.LastError, senseBuf); - _dumpLog.WriteLine("Cannot unlock drive, not continuing."); - StoppingErrorMessage?.Invoke("Cannot unlock drive, not continuing."); + _dumpLog.WriteLine(Localization.Core.Cannot_unlock_drive_not_continuing); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_unlock_drive_not_continuing); return; } @@ -882,43 +1031,56 @@ partial class Dump if(sense) { - StoppingErrorMessage?.Invoke("Cannot get disc capacity."); + StoppingErrorMessage?.Invoke(Localization.Core.Cannot_get_disc_capacity); return; } - end = DateTime.UtcNow; + _dumpStopwatch.Stop(); AaruConsole.WriteLine(); mhddLog.Close(); - ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), _devicePath); + ibgLog.Close(_dev, + blocks, + blockSize, + _dumpStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), + _devicePath); - UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average dump speed {blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000):F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - UpdateStatus?. - Invoke($"Average write speed {blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration:F3} KiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); + _dumpLog.WriteLine(string.Format(Localization.Core.Dump_finished_in_0, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_dump_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); - _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", - blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); + _dumpLog.WriteLine(string.Format(Localization.Core.Average_write_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(imageWriteDuration.Seconds()) + .Humanize())); - #region Trimming - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _trim && - newTrim) +#region Trimming + + if(_resume.BadBlocks.Count > 0 && !_aborted && _trim && newTrim) { - start = DateTime.UtcNow; - UpdateStatus?.Invoke("Trimming skipped sectors"); - _dumpLog.WriteLine("Trimming skipped sectors"); + _trimStopwatch.Restart(); + UpdateStatus?.Invoke(Localization.Core.Trimming_skipped_sectors); + _dumpLog.WriteLine(Localization.Core.Trimming_skipped_sectors); ulong[] tmpArray = _resume.BadBlocks.ToArray(); InitProgress?.Invoke(); @@ -928,15 +1090,27 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - _dumpLog.WriteLine("Aborted!"); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke($"Trimming sector {badSector}"); + PulseProgress?.Invoke(string.Format(Localization.Core.Trimming_sector_0, badSector)); - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)badSector, - blockSize, 0, 1, false, _dev.Timeout, out cmdDuration); + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + false, + false, + false, + (uint)badSector, + blockSize, + 0, + 1, + false, + _dev.Timeout, + out cmdDuration); totalDuration += cmdDuration; @@ -950,21 +1124,26 @@ partial class Dump _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(readBuffer, badSector); + _mediaGraph?.PaintSectorGood(badSector); } EndProgress?.Invoke(); - end = DateTime.UtcNow; - UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds."); - _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds); - } - #endregion Trimming + _trimStopwatch.Stop(); - #region Error handling - if(_resume.BadBlocks.Count > 0 && - !_aborted && - _retryPasses > 0) + UpdateStatus?.Invoke(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(string.Format(Localization.Core.Trimming_finished_in_0, + _trimStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + } + +#endregion Trimming + +#region Error handling + + if(_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0) { - var tmpList = new List(); + List tmpList = []; foreach(ulong ur in _resume.BadBlocks) for(ulong i = ur; i < ur + blocksToRead; i++) @@ -985,13 +1164,26 @@ partial class Dump { Modes.ModePage_01_MMC pgMmc; - sense = _dev.ModeSense6(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01, - _dev.Timeout, out _); + sense = _dev.ModeSense6(out readBuffer, + out _, + false, + ScsiModeSensePageControl.Current, + 0x01, + _dev.Timeout, + out _); - if(sense) + Modes.DecodedMode? dcMode6 = null; + if(!sense) dcMode6 = Modes.DecodeMode6(readBuffer, PeripheralDeviceTypes.MultiMediaDevice); + + if(sense || dcMode6 is null) { - sense = _dev.ModeSense10(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01, - _dev.Timeout, out _); + sense = _dev.ModeSense10(out readBuffer, + out _, + false, + ScsiModeSensePageControl.Current, + 0x01, + _dev.Timeout, + out _); if(!sense) { @@ -999,19 +1191,21 @@ partial class Dump Modes.DecodeMode10(readBuffer, PeripheralDeviceTypes.MultiMediaDevice); if(dcMode10.HasValue) + { foreach(Modes.ModePage modePage in dcMode10.Value.Pages.Where(modePage => - modePage.Page == 0x01 && modePage.Subpage == 0x00)) + modePage is { Page: 0x01, Subpage: 0x00 })) currentModePage = modePage; + } } } else { - Modes.DecodedMode? dcMode6 = Modes.DecodeMode6(readBuffer, PeripheralDeviceTypes.MultiMediaDevice); - if(dcMode6.HasValue) + { foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage => - modePage.Page == 0x01 && modePage.Subpage == 0x00)) + modePage is { Page: 0x01, Subpage: 0x00 })) currentModePage = modePage; + } } if(currentModePage == null) @@ -1041,35 +1235,35 @@ partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { + Pages = + [ new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01_MMC(pgMmc) } - } + ] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); md10 = Modes.EncodeMode10(md, _dev.ScsiType); - UpdateStatus?.Invoke("Sending MODE SELECT to drive (return damaged blocks)."); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks)."); + UpdateStatus?.Invoke(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_damaged_blocks); sense = _dev.ModeSelect(md6, out senseBuf, true, false, _dev.Timeout, out _); - if(sense) - sense = _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); + if(sense) sense = _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); if(sense) { - UpdateStatus?. - Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + UpdateStatus?.Invoke(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); - AaruConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(Localization.Core.Error_0, Sense.PrettifySense(senseBuf)); - _dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); + _dumpLog.WriteLine(Localization.Core + .Drive_did_not_accept_MODE_SELECT_command_for_persistent_error_reading); } else runningPersistent = true; @@ -1084,47 +1278,77 @@ partial class Dump if(_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); break; } - PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass, - forward ? "forward" : "reverse", - runningPersistent ? "recovering partial data, " : "")); + if(forward) + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_forward, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_forward, + badSector, + pass)); + } + else + { + PulseProgress?.Invoke(runningPersistent + ? string.Format(Localization.Core + .Retrying_sector_0_pass_1_recovering_partial_data_reverse, + badSector, + pass) + : string.Format(Localization.Core.Retrying_sector_0_pass_1_reverse, + badSector, + pass)); + } - sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)badSector, - blockSize, 0, 1, false, _dev.Timeout, out cmdDuration); + sense = _dev.Read12(out readBuffer, + out senseBuf, + 0, + false, + false, + false, + false, + (uint)badSector, + blockSize, + 0, + 1, + false, + _dev.Timeout, + out cmdDuration); totalDuration += cmdDuration; - if(sense || _dev.Error) - _errorLog?.WriteLine(currentSector, _dev.Error, _dev.LastError, senseBuf); + if(sense || _dev.Error) _errorLog?.WriteLine(currentSector, _dev.Error, _dev.LastError, senseBuf); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { _resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputFormat.WriteSector(readBuffer, badSector); - UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}."); - _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); + _mediaGraph?.PaintSectorGood(badSector); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_block_0_in_pass_1, + badSector, + pass)); + + _dumpLog.WriteLine(Localization.Core.Correctly_retried_block_0_in_pass_1, badSector, pass); } - else if(runningPersistent) - outputFormat.WriteSector(readBuffer, badSector); + else if(runningPersistent) outputFormat.WriteSector(readBuffer, badSector); } - if(pass < _retryPasses && - !_aborted && - _resume.BadBlocks.Count > 0) + if(pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); - if(!forward) - _resume.BadBlocks.Reverse(); + if(!forward) _resume.BadBlocks.Reverse(); goto repeatRetry; } @@ -1134,26 +1358,23 @@ partial class Dump var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), - Pages = new[] - { - currentModePage.Value - } + Pages = [currentModePage.Value] }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); md10 = Modes.EncodeMode10(md, _dev.ScsiType); - UpdateStatus?.Invoke("Sending MODE SELECT to drive (return device to previous status)."); - _dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status)."); + UpdateStatus?.Invoke(Localization.Core.Sending_MODE_SELECT_to_drive_return_device_to_previous_status); + _dumpLog.WriteLine(Localization.Core.Sending_MODE_SELECT_to_drive_return_device_to_previous_status); sense = _dev.ModeSelect(md6, out senseBuf, true, false, _dev.Timeout, out _); - if(sense) - _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); + if(sense) _dev.ModeSelect10(md10, out senseBuf, true, false, _dev.Timeout, out _); } EndProgress?.Invoke(); } - #endregion Error handling + +#endregion Error handling _resume.BadBlocks.Sort(); currentTry.Extents = ExtentsConverter.ToMetadata(extents); @@ -1162,20 +1383,20 @@ partial class Dump { if(tag.Value is null) { - AaruConsole.ErrorWriteLine("Error: Tag type {0} is null, skipping...", tag.Key); + AaruConsole.ErrorWriteLine(Localization.Core.Error_Tag_type_0_is_null_skipping, tag.Key); continue; } ret = outputFormat.WriteMediaTag(tag.Value, tag.Key); - if(ret || _force) - continue; + if(ret || _force) continue; // Cannot write tag to image - _dumpLog.WriteLine($"Cannot write tag {tag.Key}."); + _dumpLog.WriteLine(string.Format(Localization.Core.Cannot_write_tag_0, tag.Key)); - StoppingErrorMessage?.Invoke($"Cannot write tag {tag.Key}." + Environment.NewLine + + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Cannot_write_tag_0, tag.Key) + + Environment.NewLine + outputFormat.ErrorMessage); return; @@ -1183,38 +1404,43 @@ partial class Dump _resume.BadBlocks.Sort(); - foreach(ulong bad in _resume.BadBlocks) - _dumpLog.WriteLine("Sector {0} could not be read.", bad); + foreach(ulong bad in _resume.BadBlocks) _dumpLog.WriteLine(Localization.Core.Sector_0_could_not_be_read, bad); currentTry.Extents = ExtentsConverter.ToMetadata(extents); outputFormat.SetDumpHardware(_resume.Tries); - var metadata = new ImageInfo + var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; - if(!outputFormat.SetMetadata(metadata)) - ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + + if(!outputFormat.SetImageInfo(metadata)) + { + ErrorMessage?.Invoke(Localization.Core.Error_0_setting_metadata + + Environment.NewLine + outputFormat.ErrorMessage); + } - if(_preSidecar != null) - outputFormat.SetCicmMetadata(_preSidecar); + if(_preSidecar != null) outputFormat.SetMetadata(_preSidecar); - _dumpLog.WriteLine("Closing output file."); - UpdateStatus?.Invoke("Closing output file."); - DateTime closeStart = DateTime.Now; + _dumpLog.WriteLine(Localization.Core.Closing_output_file); + UpdateStatus?.Invoke(Localization.Core.Closing_output_file); + _imageCloseStopwatch.Restart(); outputFormat.Close(); - DateTime closeEnd = DateTime.Now; - UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); - _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); + _imageCloseStopwatch.Stop(); + + UpdateStatus?.Invoke(string.Format(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); + + _dumpLog.WriteLine(Localization.Core.Closed_in_0, + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second)); if(_aborted) { - UpdateStatus?.Invoke("Aborted!"); - _dumpLog.WriteLine("Aborted!"); + UpdateStatus?.Invoke(Localization.Core.Aborted); + _dumpLog.WriteLine(Localization.Core.Aborted); return; } @@ -1223,16 +1449,16 @@ partial class Dump if(_metadata) { - var layers = new LayersType + var layers = new Layers { - type = LayersTypeType.OTP, - typeSpecified = true, - Sectors = new SectorsType[1] - }; - - layers.Sectors[0] = new SectorsType - { - Value = layerBreak + Type = LayerType.OTP, + Sectors = + [ + new Sectors + { + Value = layerBreak + } + ] }; WriteOpticalSidecar(blockSize, blocks, dskType, layers, mediaTags, 1, out totalChkDuration, null); @@ -1240,20 +1466,32 @@ partial class Dump UpdateStatus?.Invoke(""); - UpdateStatus?. - Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Took_a_total_of_0_1_processing_commands_2_checksumming_3_writing_4_closing, + _dumpStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second), + totalDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + totalChkDuration.Milliseconds().Humanize(minUnit: TimeUnit.Second), + imageWriteDuration.Seconds().Humanize(minUnit: TimeUnit.Second), + _imageCloseStopwatch.Elapsed.Humanize(minUnit: TimeUnit.Second))); - UpdateStatus?. - Invoke($"Average speed: {blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Average_speed_0, + ByteSize.FromBytes(blockSize * (blocks + 1)) + .Per(totalDuration.Milliseconds()) + .Humanize())); if(maxSpeed > 0) - UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Fastest_speed_burst_0, + ByteSize.FromMegabytes(maxSpeed).Per(_oneSecond).Humanize())); + } - if(minSpeed > 0 && - minSpeed < double.MaxValue) - UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); + if(minSpeed is > 0 and < double.MaxValue) + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Slowest_speed_burst_0, + ByteSize.FromMegabytes(minSpeed).Per(_oneSecond).Humanize())); + } - UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); + UpdateStatus?.Invoke(string.Format(Localization.Core._0_sectors_could_not_be_read, _resume.BadBlocks.Count)); UpdateStatus?.Invoke(""); Statistics.AddMedia(dskType, true); diff --git a/Aaru.Core/Devices/Info/DeviceInfo.cs b/Aaru.Core/Devices/Info/DeviceInfo.cs index 7d7cd3620..1c76d0f9d 100644 --- a/Aaru.Core/Devices/Info/DeviceInfo.cs +++ b/Aaru.Core/Devices/Info/DeviceInfo.cs @@ -27,14 +27,10 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// Copyright © 2021-2022 Rebecca Wallander +// Copyright © 2011-2024 Natalia Portillo +// Copyright © 2021-2024 Rebecca Wallander // ****************************************************************************/ -using DVDDecryption = Aaru.Decryption.DVD.Dump; - -namespace Aaru.Core.Devices.Info; - using System; using System.Collections.Generic; using Aaru.CommonTypes.Enums; @@ -46,11 +42,16 @@ using Aaru.Decoders.SCSI; using Aaru.Decryption; using Aaru.Devices; using Aaru.Helpers; +using DVDDecryption = Aaru.Decryption.DVD.Dump; using Inquiry = Aaru.CommonTypes.Structs.Devices.SCSI.Inquiry; +namespace Aaru.Core.Devices.Info; + /// Obtains and contains information about a device public partial class DeviceInfo { + const string MODULE_NAME = "Device information"; + /// Initializes an instance of this class for the specified device /// Device public DeviceInfo(Device dev) @@ -87,28 +88,27 @@ public partial class DeviceInfo if(sense) { - AaruConsole.DebugWriteLine("Device-Info command", "STATUS = 0x{0:X2}", errorRegisters.Status); - AaruConsole.DebugWriteLine("Device-Info command", "ERROR = 0x{0:X2}", errorRegisters.Error); + AaruConsole.DebugWriteLine(MODULE_NAME, "STATUS = 0x{0:X2}", errorRegisters.Status); + AaruConsole.DebugWriteLine(MODULE_NAME, "ERROR = 0x{0:X2}", errorRegisters.Error); - AaruConsole.DebugWriteLine("Device-Info command", "NSECTOR = 0x{0:X2}", errorRegisters.SectorCount); + AaruConsole.DebugWriteLine(MODULE_NAME, "NSECTOR = 0x{0:X2}", errorRegisters.SectorCount); - AaruConsole.DebugWriteLine("Device-Info command", "SECTOR = 0x{0:X2}", errorRegisters.Sector); + AaruConsole.DebugWriteLine(MODULE_NAME, "SECTOR = 0x{0:X2}", errorRegisters.Sector); - AaruConsole.DebugWriteLine("Device-Info command", "CYLHIGH = 0x{0:X2}", - errorRegisters.CylinderHigh); + AaruConsole.DebugWriteLine(MODULE_NAME, "CYLHIGH = 0x{0:X2}", errorRegisters.CylinderHigh); - AaruConsole.DebugWriteLine("Device-Info command", "CYLLOW = 0x{0:X2}", errorRegisters.CylinderLow); + AaruConsole.DebugWriteLine(MODULE_NAME, "CYLLOW = 0x{0:X2}", errorRegisters.CylinderLow); - AaruConsole.DebugWriteLine("Device-Info command", "DEVICE = 0x{0:X2}", errorRegisters.DeviceHead); + AaruConsole.DebugWriteLine(MODULE_NAME, "DEVICE = 0x{0:X2}", errorRegisters.DeviceHead); - AaruConsole.DebugWriteLine("Device-Info command", "Error code = {0}", dev.LastError); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Error_code_equals_0, dev.LastError); break; } if(dev.Error) { - AaruConsole.ErrorWriteLine("Error {0} querying ATA IDENTIFY", dev.LastError); + AaruConsole.ErrorWriteLine(Localization.Core.Error_0_querying_ATA_IDENTIFY, dev.LastError); break; } @@ -117,9 +117,7 @@ public partial class DeviceInfo dev.EnableMediaCardPassThrough(out errorRegisters, dev.Timeout, out _); - if(errorRegisters.Sector == 0xAA && - errorRegisters.SectorCount == 0x55) - AtaMcptError = errorRegisters; + if(errorRegisters is { Sector: 0xAA, SectorCount: 0x55 }) AtaMcptError = errorRegisters; break; } @@ -130,21 +128,20 @@ public partial class DeviceInfo if(sense) { - AaruConsole.DebugWriteLine("Device-Info command", "STATUS = 0x{0:X2}", errorRegisters.Status); - AaruConsole.DebugWriteLine("Device-Info command", "ERROR = 0x{0:X2}", errorRegisters.Error); + AaruConsole.DebugWriteLine(MODULE_NAME, "STATUS = 0x{0:X2}", errorRegisters.Status); + AaruConsole.DebugWriteLine(MODULE_NAME, "ERROR = 0x{0:X2}", errorRegisters.Error); - AaruConsole.DebugWriteLine("Device-Info command", "NSECTOR = 0x{0:X2}", errorRegisters.SectorCount); + AaruConsole.DebugWriteLine(MODULE_NAME, "NSECTOR = 0x{0:X2}", errorRegisters.SectorCount); - AaruConsole.DebugWriteLine("Device-Info command", "SECTOR = 0x{0:X2}", errorRegisters.Sector); + AaruConsole.DebugWriteLine(MODULE_NAME, "SECTOR = 0x{0:X2}", errorRegisters.Sector); - AaruConsole.DebugWriteLine("Device-Info command", "CYLHIGH = 0x{0:X2}", - errorRegisters.CylinderHigh); + AaruConsole.DebugWriteLine(MODULE_NAME, "CYLHIGH = 0x{0:X2}", errorRegisters.CylinderHigh); - AaruConsole.DebugWriteLine("Device-Info command", "CYLLOW = 0x{0:X2}", errorRegisters.CylinderLow); + AaruConsole.DebugWriteLine(MODULE_NAME, "CYLLOW = 0x{0:X2}", errorRegisters.CylinderLow); - AaruConsole.DebugWriteLine("Device-Info command", "DEVICE = 0x{0:X2}", errorRegisters.DeviceHead); + AaruConsole.DebugWriteLine(MODULE_NAME, "DEVICE = 0x{0:X2}", errorRegisters.DeviceHead); - AaruConsole.DebugWriteLine("Device-Info command", "Error code = {0}", dev.LastError); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Error_code_equals_0, dev.LastError); break; } @@ -152,7 +149,7 @@ public partial class DeviceInfo if(!dev.Error) AtapiIdentify = ataBuf; else - AaruConsole.ErrorWriteLine("Error {0} querying ATA PACKET IDENTIFY", dev.LastError); + AaruConsole.ErrorWriteLine(Localization.Core.Error_0_querying_ATA_PACKET_IDENTIFY, dev.LastError); // ATAPI devices are also SCSI devices goto case DeviceType.SCSI; @@ -164,7 +161,7 @@ public partial class DeviceInfo if(sense) { - AaruConsole.ErrorWriteLine("SCSI error:\n{0}", Sense.PrettifySense(senseBuf)); + AaruConsole.ErrorWriteLine(Localization.Core.SCSI_error_0, Sense.PrettifySense(senseBuf)); break; } @@ -181,72 +178,84 @@ public partial class DeviceInfo byte[] pages = EVPD.DecodePage00(inqBuf); if(pages != null) + { foreach(byte page in pages) { sense = dev.ScsiInquiry(out inqBuf, out senseBuf, page); - if(sense) - continue; + if(sense) continue; ScsiEvpdPages.Add(page, inqBuf); } + } } var devType = (PeripheralDeviceTypes)ScsiInquiry.Value.PeripheralDeviceType; - sense = dev.ModeSense10(out byte[] modeBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, - 0x3F, 0xFF, 5, out _); + sense = dev.ModeSense10(out byte[] modeBuf, + out senseBuf, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0xFF, + 5, + out _); - if(!sense && - !dev.Error) - ScsiModeSense10 = modeBuf; + if(!sense && !dev.Error) ScsiModeSense10 = modeBuf; if(sense || dev.Error) { - sense = dev.ModeSense10(out modeBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, - 0x3F, 0x00, 5, out _); + sense = dev.ModeSense10(out modeBuf, + out senseBuf, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, + out _); - if(!sense && - !dev.Error) - ScsiModeSense10 = modeBuf; + if(!sense && !dev.Error) ScsiModeSense10 = modeBuf; } - if(!sense && - !dev.Error) - ScsiMode = Modes.DecodeMode10(modeBuf, devType); + if(!sense && !dev.Error) ScsiMode = Modes.DecodeMode10(modeBuf, devType); bool useMode10 = !(sense || dev.Error || !ScsiMode.HasValue); - sense = dev.ModeSense6(out modeBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0xFF, - 5, out _); + sense = dev.ModeSense6(out modeBuf, + out senseBuf, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0xFF, + 5, + out _); - if(!sense && - !dev.Error) - ScsiModeSense6 = modeBuf; + if(!sense && !dev.Error) ScsiModeSense6 = modeBuf; if(sense || dev.Error) { - sense = dev.ModeSense6(out modeBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, - 0x00, 5, out _); + sense = dev.ModeSense6(out modeBuf, + out senseBuf, + false, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + 5, + out _); - if(!sense && - !dev.Error) - ScsiModeSense6 = modeBuf; + if(!sense && !dev.Error) ScsiModeSense6 = modeBuf; } if(sense || dev.Error) { sense = dev.ModeSense(out modeBuf, out senseBuf, 5, out _); - if(!sense && - !dev.Error) - ScsiModeSense6 = modeBuf; + if(!sense && !dev.Error) ScsiModeSense6 = modeBuf; } - if(!sense && - !dev.Error && - !useMode10) - ScsiMode = Modes.DecodeMode6(modeBuf, devType); + if(!sense && !dev.Error && !useMode10) ScsiMode = Modes.DecodeMode6(modeBuf, devType); switch(devType) { @@ -254,21 +263,22 @@ public partial class DeviceInfo { sense = dev.GetConfiguration(out byte[] confBuf, out senseBuf, dev.Timeout, out _); - if(!sense) - MmcConfiguration = confBuf; + if(!sense) MmcConfiguration = confBuf; var dvdDecrypt = new DVDDecryption(dev); - sense = dvdDecrypt.ReadRpc(out byte[] cmdBuf, out _, DvdCssKeyClass.DvdCssCppmOrCprm, - dev.Timeout, out _); + sense = dvdDecrypt.ReadRpc(out byte[] cmdBuf, + out _, + DvdCssKeyClass.DvdCssCppmOrCprm, + dev.Timeout, + out _); if(!sense) { CSS_CPRM.RegionalPlaybackControlState? rpc = CSS_CPRM.DecodeRegionalPlaybackControlState(cmdBuf); - if(rpc.HasValue) - RPC = rpc; + if(rpc.HasValue) RPC = rpc; } // TODO: DVD drives respond correctly to BD status. @@ -316,7 +326,8 @@ public partial class DeviceInfo } */ - #region Plextor +#region Plextor + if(dev.Manufacturer == "PLEXTOR") { var plxtSense = true; @@ -343,11 +354,14 @@ public partial class DeviceInfo for(byte i = 0; i < 4; i++) { - plxtSense = dev.PlextorReadEepromBlock(out byte[] plxtBufSmall, out senseBuf, i, - 256, dev.Timeout, out _); + plxtSense = dev.PlextorReadEepromBlock(out byte[] plxtBufSmall, + out senseBuf, + i, + 256, + dev.Timeout, + out _); - if(plxtSense) - break; + if(plxtSense) break; Array.Copy(plxtBufSmall, 0, plxtBuf, i * 256, 256); } @@ -360,8 +374,12 @@ public partial class DeviceInfo default: { if(dev.Model.StartsWith("CD-R ", StringComparison.Ordinal)) - plxtSense = dev.PlextorReadEepromCdr(out plxtBuf, out senseBuf, dev.Timeout, + { + plxtSense = dev.PlextorReadEepromCdr(out plxtBuf, + out senseBuf, + dev.Timeout, out _); + } break; } @@ -392,8 +410,11 @@ public partial class DeviceInfo } } - plxtSense = dev.PlextorGetPoweRec(out senseBuf, out bool plxtPwrRecEnabled, - out ushort plxtPwrRecSpeed, dev.Timeout, out _); + plxtSense = dev.PlextorGetPoweRec(out senseBuf, + out bool plxtPwrRecEnabled, + out ushort plxtPwrRecSpeed, + dev.Timeout, + out _); if(!plxtSense) { @@ -404,9 +425,12 @@ public partial class DeviceInfo PlextorFeatures.PoweRecEnabled = true; PlextorFeatures.PoweRecRecommendedSpeed = plxtPwrRecSpeed; - plxtSense = dev.PlextorGetSpeeds(out senseBuf, out ushort plxtPwrRecSelected, + plxtSense = dev.PlextorGetSpeeds(out senseBuf, + out ushort plxtPwrRecSelected, out ushort plxtPwrRecMax, - out ushort plxtPwrRecLast, dev.Timeout, out _); + out ushort plxtPwrRecLast, + dev.Timeout, + out _); if(!plxtSense) { @@ -421,6 +445,7 @@ public partial class DeviceInfo plxtSense = dev.PlextorGetSilentMode(out plxtBuf, out senseBuf, dev.Timeout, out _); if(!plxtSense) + { if(plxtBuf[0] == 1) { PlextorFeatures.SilentModeEnabled = true; @@ -440,16 +465,15 @@ public partial class DeviceInfo plxtBuf[7] - 47); */ } + } plxtSense = dev.PlextorGetGigaRec(out plxtBuf, out senseBuf, dev.Timeout, out _); - if(!plxtSense) - PlextorFeatures.GigaRec = true; + if(!plxtSense) PlextorFeatures.GigaRec = true; plxtSense = dev.PlextorGetSecuRec(out plxtBuf, out senseBuf, dev.Timeout, out _); - if(!plxtSense) - PlextorFeatures.SecuRec = true; + if(!plxtSense) PlextorFeatures.SecuRec = true; plxtSense = dev.PlextorGetSpeedRead(out plxtBuf, out senseBuf, dev.Timeout, out _); @@ -457,8 +481,7 @@ public partial class DeviceInfo { PlextorFeatures.SpeedRead = true; - if((plxtBuf[2] & 0x01) == 0x01) - PlextorFeatures.SpeedReadEnabled = true; + if((plxtBuf[2] & 0x01) == 0x01) PlextorFeatures.SpeedReadEnabled = true; } plxtSense = dev.PlextorGetHiding(out plxtBuf, out senseBuf, dev.Timeout, out _); @@ -467,49 +490,53 @@ public partial class DeviceInfo { PlextorFeatures.Hiding = true; - if((plxtBuf[2] & 0x02) == 0x02) - PlextorFeatures.HidesRecordables = true; + if((plxtBuf[2] & 0x02) == 0x02) PlextorFeatures.HidesRecordables = true; - if((plxtBuf[2] & 0x01) == 0x01) - PlextorFeatures.HidesSessions = true; + if((plxtBuf[2] & 0x01) == 0x01) PlextorFeatures.HidesSessions = true; } plxtSense = dev.PlextorGetVariRec(out plxtBuf, out senseBuf, false, dev.Timeout, out _); - if(!plxtSense) - PlextorFeatures.VariRec = true; + if(!plxtSense) PlextorFeatures.VariRec = true; if(plxtDvd) { plxtSense = dev.PlextorGetVariRec(out plxtBuf, out senseBuf, true, dev.Timeout, out _); - if(!plxtSense) - PlextorFeatures.VariRecDvd = true; + if(!plxtSense) PlextorFeatures.VariRecDvd = true; - plxtSense = dev.PlextorGetBitsetting(out plxtBuf, out senseBuf, false, dev.Timeout, + plxtSense = dev.PlextorGetBitsetting(out plxtBuf, + out senseBuf, + false, + dev.Timeout, out _); - if(!plxtSense) - PlextorFeatures.BitSetting = true; + if(!plxtSense) PlextorFeatures.BitSetting = true; - plxtSense = dev.PlextorGetBitsetting(out plxtBuf, out senseBuf, true, dev.Timeout, + plxtSense = dev.PlextorGetBitsetting(out plxtBuf, + out senseBuf, + true, + dev.Timeout, out _); - if(!plxtSense) - PlextorFeatures.BitSettingDl = true; + if(!plxtSense) PlextorFeatures.BitSettingDl = true; - plxtSense = dev.PlextorGetTestWriteDvdPlus(out plxtBuf, out senseBuf, dev.Timeout, + plxtSense = dev.PlextorGetTestWriteDvdPlus(out plxtBuf, + out senseBuf, + dev.Timeout, out _); - if(!plxtSense) - PlextorFeatures.DvdPlusWriteTest = true; + if(!plxtSense) PlextorFeatures.DvdPlusWriteTest = true; } } - #endregion Plextor + +#endregion Plextor if(ScsiInquiry.Value.KreonPresent) + { if(!dev.KreonGetFeatureList(out senseBuf, out KreonFeatures krFeatures, dev.Timeout, out _)) KreonFeatures = krFeatures; + } break; } @@ -536,8 +563,10 @@ public partial class DeviceInfo sense = dev.ReportDensitySupport(out seqBuf, out senseBuf, true, false, dev.Timeout, out _); if(sense) + { AaruConsole.ErrorWriteLine("REPORT DENSITY SUPPORT (MEDIUM):\n{0}", Sense.PrettifySense(senseBuf)); + } else { MediumDensitySupport = seqBuf; @@ -555,24 +584,19 @@ public partial class DeviceInfo { bool sense = dev.ReadCid(out byte[] mmcBuf, out _, dev.Timeout, out _); - if(!sense) - CID = mmcBuf; + if(!sense) CID = mmcBuf; sense = dev.ReadCsd(out mmcBuf, out _, dev.Timeout, out _); - if(!sense) - CSD = mmcBuf; + if(!sense) CSD = mmcBuf; sense = dev.ReadOcr(out mmcBuf, out _, dev.Timeout, out _); - if(!sense) - OCR = mmcBuf; + if(!sense) OCR = mmcBuf; sense = dev.ReadExtendedCsd(out mmcBuf, out _, dev.Timeout, out _); - if(!sense && - !ArrayHelpers.ArrayIsNullOrEmpty(mmcBuf)) - ExtendedCSD = mmcBuf; + if(!sense && !ArrayHelpers.ArrayIsNullOrEmpty(mmcBuf)) ExtendedCSD = mmcBuf; } break; @@ -580,28 +604,24 @@ public partial class DeviceInfo { bool sense = dev.ReadCid(out byte[] sdBuf, out _, dev.Timeout, out _); - if(!sense) - CID = sdBuf; + if(!sense) CID = sdBuf; sense = dev.ReadCsd(out sdBuf, out _, dev.Timeout, out _); - if(!sense) - CSD = sdBuf; + if(!sense) CSD = sdBuf; sense = dev.ReadSdocr(out sdBuf, out _, dev.Timeout, out _); - if(!sense) - OCR = sdBuf; + if(!sense) OCR = sdBuf; sense = dev.ReadScr(out sdBuf, out _, dev.Timeout, out _); - if(!sense) - SCR = sdBuf; + if(!sense) SCR = sdBuf; } break; default: - AaruConsole.ErrorWriteLine("Unknown device type {0}, cannot get information.", dev.Type); + AaruConsole.ErrorWriteLine(Localization.Core.Unknown_device_type_0_cannot_get_information, dev.Type); break; } diff --git a/Aaru.Core/Devices/Info/Plextor.cs b/Aaru.Core/Devices/Info/Plextor.cs index f8da7d5ee..bb2295c73 100644 --- a/Aaru.Core/Devices/Info/Plextor.cs +++ b/Aaru.Core/Devices/Info/Plextor.cs @@ -27,7 +27,7 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Core.Devices.Info; diff --git a/Aaru.Core/Devices/Info/Properties.cs b/Aaru.Core/Devices/Info/Properties.cs index 8a0d04188..f9771be8a 100644 --- a/Aaru.Core/Devices/Info/Properties.cs +++ b/Aaru.Core/Devices/Info/Properties.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Info; - using System.Collections.Generic; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Structs.Devices.SCSI; @@ -42,98 +40,145 @@ using Aaru.Decoders.SCSI.SSC; using Aaru.Devices; using Inquiry = Aaru.CommonTypes.Structs.Devices.SCSI.Inquiry; +namespace Aaru.Core.Devices.Info; + public partial class DeviceInfo { /// Raw IDENTIFY DEVICE response public byte[] AtaIdentify { get; } + /// Raw IDENTIFY PACKET DEVICE response public byte[] AtapiIdentify { get; } + /// Raw INQUIRY response public byte[] ScsiInquiryData { get; } + /// Decoded INQUIRY response public Inquiry? ScsiInquiry { get; } + /// Response for ATA Memory Card Pass Through public AtaErrorRegistersChs? AtaMcptError { get; } + /// List of raw EVPD page indexed by page number public Dictionary ScsiEvpdPages { get; } + /// Decoded MODE SENSE response public Modes.DecodedMode? ScsiMode { get; } + /// Raw MODE SENSE(6) response public byte[] ScsiModeSense6 { get; } + /// Raw MODE SENSE(10) response public byte[] ScsiModeSense10 { get; } + /// Raw GET CONFIGURATION response public byte[] MmcConfiguration { get; } + /// Decoded Plextor features public Plextor PlextorFeatures { get; } + /// Decoded Kreon features public KreonFeatures KreonFeatures { get; } + /// Raw GET BLOCK LIMITS support public byte[] BlockLimits { get; } + /// Raw density support public byte[] DensitySupport { get; } + /// Decoded density support public DensitySupport.DensitySupportHeader? DensitySupportHeader { get; } + /// Raw medium density support public byte[] MediumDensitySupport { get; } + /// Decoded medium density support public DensitySupport.MediaTypeSupportHeader? MediaTypeSupportHeader { get; } + /// Raw CID registers public byte[] CID { get; } + /// Raw CSD public byte[] CSD { get; } + /// Raw extended CSD public byte[] ExtendedCSD { get; } + /// Raw SCR registers public byte[] SCR { get; } + /// Raw OCR registers public byte[] OCR { get; } + /// Aaru's device type public DeviceType Type { get; } + /// Device manufacturer public string Manufacturer { get; } + /// Device model public string Model { get; } + /// Device firmware version or revision public string FirmwareRevision { get; } + /// Device serial number public string Serial { get; } + /// SCSI Peripheral Device Type public PeripheralDeviceTypes ScsiType { get; } + /// Is media removable from device? public bool IsRemovable { get; } + /// Is device attached via USB? public bool IsUsb { get; } + /// USB vendor ID public ushort UsbVendorId { get; } + /// USB product ID public ushort UsbProductId { get; } + /// Raw USB descriptors public byte[] UsbDescriptors { get; } + /// USB manufacturer string public string UsbManufacturerString { get; } + /// USB product string public string UsbProductString { get; } + /// USB serial number string public string UsbSerialString { get; } + /// Is device attached via FireWire? public bool IsFireWire { get; } + /// FireWire's device GUID public ulong FireWireGuid { get; } + /// FireWire's device model ID public uint FireWireModel { get; } + /// FireWire's device model name public string FireWireModelName { get; } + /// FireWire's device vendor ID public uint FireWireVendor { get; } + /// FireWire's device vendor name public string FireWireVendorName { get; } + /// Is device a CompactFlash device? public bool IsCompactFlash { get; } + /// Is device a PCMCIA or CardBus device? public bool IsPcmcia { get; } + /// PCMCIA/CardBus CIS public byte[] Cis { get; } + /// MMC device CSS/CPRM Region Protection Code public CSS_CPRM.RegionalPlaybackControlState? RPC { get; } } \ No newline at end of file diff --git a/Aaru.Core/Devices/Reader.cs b/Aaru.Core/Devices/Reader.cs index 1240f79bc..859209d4a 100644 --- a/Aaru.Core/Devices/Reader.cs +++ b/Aaru.Core/Devices/Reader.cs @@ -27,20 +27,24 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices; - using System; +using System.Diagnostics.CodeAnalysis; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Structs.Devices.ATA; using Aaru.Core.Logging; using Aaru.Devices; +namespace Aaru.Core.Devices; + /// Reduces common code used for scanning and dumping +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] sealed partial class Reader { + const string ATA_MODULE_NAME = "ATA Reader"; + const string SCSI_MODULE_NAME = "SCSI Reader"; readonly Device _dev; readonly ErrorLog _errorLog; readonly uint _timeout; @@ -58,11 +62,11 @@ sealed partial class Reader case DeviceType.ATA: Identify.IdentifyDevice? ataIdNullable = Identify.Decode(identification); - if(ataIdNullable.HasValue) - _ataId = ataIdNullable.Value; + if(ataIdNullable.HasValue) _ataId = ataIdNullable.Value; break; - case DeviceType.NVMe: throw new NotImplementedException("NVMe devices not yet supported."); + case DeviceType.NVMe: + throw new NotImplementedException(Localization.Core.NVMe_devices_not_yet_supported); } } @@ -80,11 +84,13 @@ sealed partial class Reader { switch(_dev.Type) { - case DeviceType.ATA: return AtaGetBlocks(); + case DeviceType.ATA: + return AtaGetBlocks(); case DeviceType.ATAPI: - case DeviceType.SCSI: return ScsiGetBlocks(); + case DeviceType.SCSI: + return ScsiGetBlocks(); default: - ErrorMessage = $"Unknown device type {_dev.Type}."; + ErrorMessage = string.Format(Localization.Core.Unknown_device_type_0, _dev.Type); return 0; } @@ -94,11 +100,13 @@ sealed partial class Reader { switch(_dev.Type) { - case DeviceType.ATA: return AtaFindReadCommand(); + case DeviceType.ATA: + return AtaFindReadCommand(); case DeviceType.ATAPI: - case DeviceType.SCSI: return ScsiFindReadCommand(); + case DeviceType.SCSI: + return ScsiFindReadCommand(); default: - ErrorMessage = $"Unknown device type {_dev.Type}."; + ErrorMessage = string.Format(Localization.Core.Unknown_device_type_0, _dev.Type); return true; } @@ -108,11 +116,13 @@ sealed partial class Reader { switch(_dev.Type) { - case DeviceType.ATA: return AtaGetBlockSize(); + case DeviceType.ATA: + return AtaGetBlockSize(); case DeviceType.ATAPI: - case DeviceType.SCSI: return ScsiGetBlockSize(); + case DeviceType.SCSI: + return ScsiGetBlockSize(); default: - ErrorMessage = $"Unknown device type {_dev.Type}."; + ErrorMessage = string.Format(Localization.Core.Unknown_device_type_0, _dev.Type); return true; } @@ -122,26 +132,24 @@ sealed partial class Reader { switch(_dev.Type) { - case DeviceType.ATA: return AtaGetBlocksToRead(startWithBlocks); + case DeviceType.ATA: + return AtaGetBlocksToRead(startWithBlocks); case DeviceType.ATAPI: - case DeviceType.SCSI: return ScsiGetBlocksToRead(startWithBlocks); + case DeviceType.SCSI: + return ScsiGetBlocksToRead(startWithBlocks); default: - ErrorMessage = $"Unknown device type {_dev.Type}."; + ErrorMessage = string.Format(Localization.Core.Unknown_device_type_0, _dev.Type); return true; } } internal bool ReadBlock(out byte[] buffer, ulong block, out double duration, out bool recoveredError, - out bool blankCheck) => + out bool blankCheck) => ReadBlocks(out buffer, block, 1, out duration, out recoveredError, out blankCheck); - internal bool ReadBlocks(out byte[] buffer, ulong block, out double duration, out bool recoveredError, - out bool blankCheck) => ReadBlocks(out buffer, block, BlocksToRead, out duration, - out recoveredError, out blankCheck); - internal bool ReadBlocks(out byte[] buffer, ulong block, uint count, out double duration, out bool recoveredError, - out bool blankCheck) + out bool blankCheck) { switch(_dev.Type) { @@ -163,7 +171,7 @@ sealed partial class Reader } internal bool ReadChs(out byte[] buffer, ushort cylinder, byte head, byte sector, out double duration, - out bool recoveredError) + out bool recoveredError) { switch(_dev.Type) { @@ -182,9 +190,11 @@ sealed partial class Reader { switch(_dev.Type) { - case DeviceType.ATA: return AtaSeek(block, out duration); + case DeviceType.ATA: + return AtaSeek(block, out duration); case DeviceType.ATAPI: - case DeviceType.SCSI: return ScsiSeek(block, out duration); + case DeviceType.SCSI: + return ScsiSeek(block, out duration); default: duration = 0d; @@ -196,7 +206,8 @@ sealed partial class Reader { switch(_dev.Type) { - case DeviceType.ATA: return AtaSeekChs(cylinder, head, sector, out duration); + case DeviceType.ATA: + return AtaSeekChs(cylinder, head, sector, out duration); default: duration = 0; diff --git a/Aaru.Core/Devices/ReaderATA.cs b/Aaru.Core/Devices/ReaderATA.cs index d24ab9c07..3e0da4d21 100644 --- a/Aaru.Core/Devices/ReaderATA.cs +++ b/Aaru.Core/Devices/ReaderATA.cs @@ -27,17 +27,17 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices; - using System; using Aaru.CommonTypes.Enums; using Aaru.Console; using Aaru.Decoders.ATA; using Identify = Aaru.CommonTypes.Structs.Devices.ATA.Identify; +namespace Aaru.Core.Devices; + sealed partial class Reader { Identify.IdentifyDevice _ataId; @@ -61,12 +61,9 @@ sealed partial class Reader void GetDeviceChs() { - if(_dev.Type != DeviceType.ATA) - return; + if(_dev.Type != DeviceType.ATA) return; - if(_ataId.CurrentCylinders > 0 && - _ataId.CurrentHeads > 0 && - _ataId.CurrentSectorsPerTrack > 0) + if(_ataId.CurrentCylinders > 0 && _ataId is { CurrentHeads: > 0, CurrentSectorsPerTrack: > 0 }) { Cylinders = _ataId.CurrentCylinders; Heads = (byte)_ataId.CurrentHeads; @@ -96,8 +93,7 @@ sealed partial class Reader IsLba = true; } - if(!_ataId.CommandSet2.HasFlag(Identify.CommandSetBit2.LBA48)) - return Blocks; + if(!_ataId.CommandSet2.HasFlag(Identify.CommandSetBit2.LBA48)) return Blocks; Blocks = _ataId.LBA48Sectors; IsLba = true; @@ -107,8 +103,7 @@ sealed partial class Reader bool AtaFindReadCommand() { - if(Blocks == 0) - GetDeviceBlocks(); + if(Blocks == 0) GetDeviceBlocks(); bool sense; var tries = 0; @@ -159,10 +154,10 @@ sealed partial class Reader _ataReadDmaLba48) break; - lba = (uint)rnd.Next(1, (int)Blocks); + lba = (uint)rnd.Next(1, (int)Blocks); cyl = (ushort)rnd.Next(0, Cylinders); - head = (byte)rnd.Next(0, Heads); - sector = (byte)rnd.Next(1, Sectors); + head = (byte)rnd.Next(0, Heads); + sector = (byte)rnd.Next(1, Sectors); tries++; } @@ -173,61 +168,53 @@ sealed partial class Reader if(IsLba) { - if(Blocks > 0xFFFFFFF && - !_ataReadLba48 && - !_ataReadDmaLba48) + if(Blocks > 0xFFFFFFF && !_ataReadLba48 && !_ataReadDmaLba48) { - ErrorMessage = "Device needs 48-bit LBA commands but I can't issue them... Aborting."; + ErrorMessage = Localization.Core.Device_needs_48_bit_LBA_commands_but_I_cant_issue_them_Aborting; return true; } - if(!_ataReadLba && - !_ataReadRetryLba && - !_ataReadDmaLba && - !_ataReadDmaRetryLba) + if(!_ataReadLba && !_ataReadRetryLba && !_ataReadDmaLba && !_ataReadDmaRetryLba) { - ErrorMessage = "Device needs 28-bit LBA commands but I can't issue them... Aborting."; + ErrorMessage = Localization.Core.Device_needs_28_bit_LBA_commands_but_I_cant_issue_them_Aborting; return true; } } else { - if(!_ataRead && - !_ataReadRetry && - !_ataReadDma && - !_ataReadDmaRetry) + if(!_ataRead && !_ataReadRetry && !_ataReadDma && !_ataReadDmaRetry) { - ErrorMessage = "Device needs CHS commands but I can't issue them... Aborting."; + ErrorMessage = Localization.Core.Device_needs_CHS_commands_but_I_cant_issue_them_Aborting; return true; } } if(_ataReadDmaLba48) - AaruConsole.WriteLine("Using ATA READ DMA EXT command."); + AaruConsole.WriteLine(Localization.Core.Using_ATA_READ_DMA_EXT_command); else if(_ataReadLba48) - AaruConsole.WriteLine("Using ATA READ EXT command."); + AaruConsole.WriteLine(Localization.Core.Using_ATA_READ_EXT_command); else if(_ataReadDmaRetryLba) - AaruConsole.WriteLine("Using ATA READ DMA command with retries (LBA)."); + AaruConsole.WriteLine(Localization.Core.Using_ATA_READ_DMA_command_with_retries_LBA); else if(_ataReadDmaLba) - AaruConsole.WriteLine("Using ATA READ DMA command (LBA)."); + AaruConsole.WriteLine(Localization.Core.Using_ATA_READ_DMA_command_LBA); else if(_ataReadRetryLba) - AaruConsole.WriteLine("Using ATA READ command with retries (LBA)."); + AaruConsole.WriteLine(Localization.Core.Using_ATA_READ_command_with_retries_LBA); else if(_ataReadLba) - AaruConsole.WriteLine("Using ATA READ command (LBA)."); + AaruConsole.WriteLine(Localization.Core.Using_ATA_READ_command_LBA); else if(_ataReadDmaRetry) - AaruConsole.WriteLine("Using ATA READ DMA command with retries (CHS)."); + AaruConsole.WriteLine(Localization.Core.Using_ATA_READ_DMA_command_with_retries_CHS); else if(_ataReadDma) - AaruConsole.WriteLine("Using ATA READ DMA command (CHS)."); + AaruConsole.WriteLine(Localization.Core.Using_ATA_READ_DMA_command_CHS); else if(_ataReadRetry) - AaruConsole.WriteLine("Using ATA READ command with retries (CHS)."); + AaruConsole.WriteLine(Localization.Core.Using_ATA_READ_command_with_retries_CHS); else if(_ataRead) - AaruConsole.WriteLine("Using ATA READ command (CHS)."); + AaruConsole.WriteLine(Localization.Core.Using_ATA_READ_command_CHS); else { - ErrorMessage = "Could not get a working read command!"; + ErrorMessage = Localization.Core.Could_not_get_a_working_read_command; return true; } @@ -237,15 +224,15 @@ sealed partial class Reader bool AtaGetBlockSize() { - if((_ataId.PhysLogSectorSize & 0x8000) == 0x0000 && - (_ataId.PhysLogSectorSize & 0x4000) == 0x4000) + if((_ataId.PhysLogSectorSize & 0x8000) == 0x0000 && (_ataId.PhysLogSectorSize & 0x4000) == 0x4000) { if((_ataId.PhysLogSectorSize & 0x1000) == 0x1000) - if(_ataId.LogicalSectorWords <= 255 || - _ataId.LogicalAlignment == 0xFFFF) + { + if(_ataId.LogicalSectorWords <= 255 || _ataId.LogicalAlignment == 0xFFFF) LogicalBlockSize = 512; else LogicalBlockSize = _ataId.LogicalSectorWords * 2; + } else LogicalBlockSize = 512; @@ -321,20 +308,17 @@ sealed partial class Reader } } - if(error) - BlocksToRead /= 2; + if(error) BlocksToRead /= 2; - if(!error || - BlocksToRead == 1) - break; + if(!error || BlocksToRead == 1) break; } - if(!error || - !IsLba) - return false; + if(!error || !IsLba) return false; BlocksToRead = 1; - ErrorMessage = $"Device error {_dev.LastError} trying to guess ideal transfer length."; + + ErrorMessage = string.Format(Localization.Core.Device_error_0_trying_to_guess_ideal_transfer_length, + _dev.LastError); return true; } @@ -357,8 +341,7 @@ sealed partial class Reader status = errorLba48.Status; errorByte = errorLba48.Error; - if(error) - _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba48); + if(error) _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba48); } else if(_ataReadLba48) { @@ -367,8 +350,7 @@ sealed partial class Reader status = errorLba48.Status; errorByte = errorLba48.Error; - if(error) - _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba48); + if(error) _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba48); } else if(_ataReadDmaRetryLba) { @@ -378,8 +360,7 @@ sealed partial class Reader status = errorLba.Status; errorByte = errorLba.Error; - if(error) - _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); + if(error) _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); } else if(_ataReadDmaLba) { @@ -389,8 +370,7 @@ sealed partial class Reader status = errorLba.Status; errorByte = errorLba.Error; - if(error) - _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); + if(error) _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); } else if(_ataReadRetryLba) { @@ -399,8 +379,7 @@ sealed partial class Reader status = errorLba.Status; errorByte = errorLba.Error; - if(error) - _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); + if(error) _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); } else if(_ataReadLba) { @@ -409,23 +388,20 @@ sealed partial class Reader status = errorLba.Status; errorByte = errorLba.Error; - if(error) - _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); + if(error) _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); } - if(!error) - return false; + if(!error) return false; - if((status & 0x04) == 0x04) - recoveredError = true; + if((status & 0x04) == 0x04) recoveredError = true; - AaruConsole.DebugWriteLine("ATA Reader", "ATA ERROR: {0} STATUS: {1}", errorByte, status); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.Core.ATA_ERROR_0_STATUS_1, errorByte, status); return true; } bool AtaReadChs(out byte[] buffer, ushort cylinder, byte head, byte sector, out double duration, - out bool recoveredError) + out bool recoveredError) { var error = true; bool sense; @@ -443,8 +419,7 @@ sealed partial class Reader status = errorChs.Status; errorByte = errorChs.Error; - if(error) - _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); + if(error) _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); } else if(_ataReadDma) { @@ -454,8 +429,7 @@ sealed partial class Reader status = errorChs.Status; errorByte = errorChs.Error; - if(error) - _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); + if(error) _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); } else if(_ataReadRetry) { @@ -464,8 +438,7 @@ sealed partial class Reader status = errorChs.Status; errorByte = errorChs.Error; - if(error) - _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); + if(error) _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); } else if(_ataRead) { @@ -474,17 +447,14 @@ sealed partial class Reader status = errorChs.Status; errorByte = errorChs.Error; - if(error) - _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); + if(error) _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); } - if(!error) - return false; + if(!error) return false; - if((status & 0x04) == 0x04) - recoveredError = true; + if((status & 0x04) == 0x04) recoveredError = true; - AaruConsole.DebugWriteLine("ATA Reader", "ATA ERROR: {0} STATUS: {1}", errorByte, status); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.Core.ATA_ERROR_0_STATUS_1, errorByte, status); return true; } diff --git a/Aaru.Core/Devices/ReaderSCSI.cs b/Aaru.Core/Devices/ReaderSCSI.cs index 209226b5a..75ac61190 100644 --- a/Aaru.Core/Devices/ReaderSCSI.cs +++ b/Aaru.Core/Devices/ReaderSCSI.cs @@ -27,20 +27,18 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices; - using System; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Console; using Aaru.Decoders.SCSI; +namespace Aaru.Core.Devices; + sealed partial class Reader { - // TODO: Raw reading - bool _hldtstReadRaw; bool _plextorReadRaw; bool _read10; bool _read12; @@ -54,15 +52,16 @@ sealed partial class Reader bool _syqReadLong10; bool _syqReadLong6; + // TODO: Raw reading + public bool HldtstReadRaw; + ulong ScsiGetBlocks() => ScsiGetBlockSize() ? 0 : Blocks; bool ScsiFindReadCommand() { - if(Blocks == 0) - GetDeviceBlocks(); + if(Blocks == 0) GetDeviceBlocks(); - if(Blocks == 0) - return true; + if(Blocks == 0) return true; byte[] senseBuf; var tries = 0; @@ -71,11 +70,21 @@ sealed partial class Reader if(_dev.ScsiType == PeripheralDeviceTypes.OpticalDevice) { - mediumScan = !_dev.MediumScan(out _, true, false, false, false, false, lba, 1, (uint)Blocks, - out uint foundLba, out _, _timeout, out _); + mediumScan = !_dev.MediumScan(out _, + true, + false, + false, + false, + false, + lba, + 1, + (uint)Blocks, + out uint foundLba, + out _, + _timeout, + out _); - if(mediumScan) - lba = foundLba; + if(mediumScan) lba = foundLba; } var rnd = new Random(); @@ -84,74 +93,112 @@ sealed partial class Reader { _read6 = !_dev.Read6(out _, out senseBuf, lba, LogicalBlockSize, _timeout, out _); - _read10 = !_dev.Read10(out _, out senseBuf, 0, false, false, false, false, lba, LogicalBlockSize, 0, 1, - _timeout, out _); + _read10 = !_dev.Read10(out _, + out senseBuf, + 0, + false, + false, + false, + false, + lba, + LogicalBlockSize, + 0, + 1, + _timeout, + out _); - _read12 = !_dev.Read12(out _, out senseBuf, 0, false, false, false, false, lba, LogicalBlockSize, 0, 1, - false, _timeout, out _); + _read12 = !_dev.Read12(out _, + out senseBuf, + 0, + false, + false, + false, + false, + lba, + LogicalBlockSize, + 0, + 1, + false, + _timeout, + out _); - _read16 = !_dev.Read16(out _, out senseBuf, 0, false, false, false, lba, LogicalBlockSize, 0, 1, false, - _timeout, out _); + _read16 = !_dev.Read16(out _, + out senseBuf, + 0, + false, + false, + false, + lba, + LogicalBlockSize, + 0, + 1, + false, + _timeout, + out _); - if(_read6 || - _read10 || - _read12 || - _read16) - break; + if(_read6 || _read10 || _read12 || _read16) break; lba = (uint)rnd.Next(1, (int)Blocks); if(mediumScan) { - mediumScan = !_dev.MediumScan(out _, true, false, false, false, false, lba, 1, (uint)Blocks, - out uint foundLba, out _, _timeout, out _); + mediumScan = !_dev.MediumScan(out _, + true, + false, + false, + false, + false, + lba, + 1, + (uint)Blocks, + out uint foundLba, + out _, + _timeout, + out _); - if(mediumScan) - lba = foundLba; + if(mediumScan) lba = foundLba; } tries++; } - if(!_read6 && - !_read10 && - !_read12 && - !_read16) + switch(_read6) { - // Magneto-opticals may have empty LBA 0 but we know they work with READ(12) - if(_dev.ScsiType == PeripheralDeviceTypes.OpticalDevice) + case false when !_read10 && !_read12 && !_read16: { - ErrorMessage = "Cannot read medium, aborting scan..."; + // Magneto-opticals may have empty LBA 0 but we know they work with READ(12) + if(_dev.ScsiType == PeripheralDeviceTypes.OpticalDevice) + { + ErrorMessage = Localization.Core.Cannot_read_medium_aborting_scan; + + return true; + } + + _read12 = true; + + break; + } + case true when !_read10 && !_read12 && !_read16 && Blocks > 0x001FFFFF + 1: + ErrorMessage = + string.Format(Localization.Core + .Device_only_supports_SCSI_READ_6_but_has_more_than_0_blocks_1_blocks_total, + 0x001FFFFF + 1, + Blocks); return true; - } - - _read12 = true; } - if(_read6 && - !_read10 && - !_read12 && - !_read16 && - Blocks > 0x001FFFFF + 1) + if(Blocks > 0x001FFFFF + 1) _read6 = false; + + if(_read10) _read12 = false; + + if(!_read16 && Blocks > 0xFFFFFFFF + (long)1) { ErrorMessage = - $"Device only supports SCSI READ (6) but has more than {0x001FFFFF + 1} blocks ({Blocks} blocks total)"; - - return true; - } - - if(Blocks > 0x001FFFFF + 1) - _read6 = false; - - if(_read10) - _read12 = false; - - if(!_read16 && - Blocks > 0xFFFFFFFF + (long)1) - { - ErrorMessage = - $"Device only supports SCSI READ (10) but has more than {0xFFFFFFFF + (long)1} blocks ({Blocks} blocks total)"; + string.Format(Localization.Core + .Device_only_supports_SCSI_READ_10_but_has_more_than_0_blocks_1_blocks_total, + 0xFFFFFFFF + (long)1, + Blocks); return true; } @@ -199,9 +246,7 @@ sealed partial class Reader { decSense = Sense.Decode(senseBuf); - if(decSense?.SenseKey == SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && - decSense.Value.ASCQ == 0x00) + if(decSense is { SenseKey: SenseKeys.IllegalRequest, ASC: 0x24, ASCQ: 0x00 }) { CanReadRaw = true; @@ -224,13 +269,20 @@ sealed partial class Reader { LongBlockSize = 0xFFFF - (information & 0xFFFF); - _readLong10 = !_dev.ReadLong10(out _, out senseBuf, false, false, 0, (ushort)LongBlockSize, - _timeout, out _); + _readLong10 = !_dev.ReadLong10(out _, + out senseBuf, + false, + false, + 0, + (ushort)LongBlockSize, + _timeout, + out _); } } } if(CanReadRaw && LongBlockSize == LogicalBlockSize) + { switch(LogicalBlockSize) { case 512: @@ -249,8 +301,7 @@ sealed partial class Reader { testSense = _dev.ReadLong16(out _, out senseBuf, false, 0, testSize, _timeout, out _); - if(!testSense && - !_dev.Error) + if(!testSense && !_dev.Error) { _readLong16 = true; LongBlockSize = testSize; @@ -259,11 +310,16 @@ sealed partial class Reader break; } - testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, testSize, _timeout, + testSense = _dev.ReadLong10(out _, + out senseBuf, + false, + false, + 0, + testSize, + _timeout, out _); - if(testSense || _dev.Error) - continue; + if(testSense || _dev.Error) continue; _readLong10 = true; LongBlockSize = testSize; @@ -287,8 +343,7 @@ sealed partial class Reader { testSense = _dev.ReadLong16(out _, out senseBuf, false, 0, testSize, _timeout, out _); - if(!testSense && - !_dev.Error) + if(!testSense && !_dev.Error) { _readLong16 = true; LongBlockSize = testSize; @@ -297,11 +352,16 @@ sealed partial class Reader break; } - testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, testSize, _timeout, + testSense = _dev.ReadLong10(out _, + out senseBuf, + false, + false, + 0, + testSize, + _timeout, out _); - if(testSense || _dev.Error) - continue; + if(testSense || _dev.Error) continue; _readLong10 = true; LongBlockSize = testSize; @@ -316,8 +376,7 @@ sealed partial class Reader { testSense = _dev.ReadLong16(out _, out senseBuf, false, 0, 2380, _timeout, out _); - if(!testSense && - !_dev.Error) + if(!testSense && !_dev.Error) { _readLong16 = true; LongBlockSize = 2380; @@ -325,11 +384,16 @@ sealed partial class Reader } else { - testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, 2380, _timeout, + testSense = _dev.ReadLong10(out _, + out senseBuf, + false, + false, + 0, + 2380, + _timeout, out _); - if(!testSense && - !_dev.Error) + if(!testSense && !_dev.Error) { _readLong10 = true; LongBlockSize = 2380; @@ -343,8 +407,7 @@ sealed partial class Reader { testSense = _dev.ReadLong16(out _, out senseBuf, false, 0, 4760, _timeout, out _); - if(!testSense && - !_dev.Error) + if(!testSense && !_dev.Error) { _readLong16 = true; LongBlockSize = 4760; @@ -352,11 +415,16 @@ sealed partial class Reader } else { - testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, 4760, _timeout, + testSense = _dev.ReadLong10(out _, + out senseBuf, + false, + false, + 0, + 4760, + _timeout, out _); - if(!testSense && - !_dev.Error) + if(!testSense && !_dev.Error) { _readLong10 = true; LongBlockSize = 4760; @@ -370,8 +438,7 @@ sealed partial class Reader { testSense = _dev.ReadLong16(out _, out senseBuf, false, 0, 9424, _timeout, out _); - if(!testSense && - !_dev.Error) + if(!testSense && !_dev.Error) { _readLong16 = true; LongBlockSize = 9424; @@ -379,11 +446,16 @@ sealed partial class Reader } else { - testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, 9424, _timeout, + testSense = _dev.ReadLong10(out _, + out senseBuf, + false, + false, + 0, + 9424, + _timeout, out _); - if(!testSense && - !_dev.Error) + if(!testSense && !_dev.Error) { _readLong10 = true; LongBlockSize = 9424; @@ -394,9 +466,9 @@ sealed partial class Reader break; } } + } - if(!CanReadRaw && - _dev.Manufacturer == "SYQUEST") + if(!CanReadRaw && _dev.Manufacturer == "SYQUEST") { testSense = _dev.SyQuestReadLong10(out _, out senseBuf, 0, 0xFFFF, _timeout, out _); @@ -405,9 +477,8 @@ sealed partial class Reader decSense = Sense.Decode(senseBuf); if(decSense.HasValue) - if(decSense.Value.SenseKey == SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && - decSense.Value.ASCQ == 0x00) + { + if(decSense is { SenseKey: SenseKeys.IllegalRequest, ASC: 0x24, ASCQ: 0x00 }) { CanReadRaw = true; @@ -442,9 +513,7 @@ sealed partial class Reader { decSense = Sense.Decode(senseBuf); - if(decSense?.SenseKey == SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && - decSense.Value.ASCQ == 0x00) + if(decSense is { SenseKey: SenseKeys.IllegalRequest, ASC: 0x24, ASCQ: 0x00 }) { CanReadRaw = true; @@ -453,15 +522,15 @@ sealed partial class Reader uint information = decSense?.Fixed?.Information ?? 0; if(decSense.Value.Descriptor.HasValue && - decSense.Value.Descriptor.Value.Descriptors. - TryGetValue(0, out byte[] desc00)) + decSense.Value.Descriptor.Value.Descriptors + .TryGetValue(0, out byte[] desc00)) { valid = true; ili = true; information = (uint)Sense.DecodeDescriptor00(desc00); - if(decSense.Value.Descriptor.Value.Descriptors. - TryGetValue(4, out byte[] desc04)) + if(decSense.Value.Descriptor.Value.Descriptors.TryGetValue(4, + out byte[] desc04)) Sense.DecodeDescriptor04(desc04, out _, out _, out ili); } @@ -470,21 +539,24 @@ sealed partial class Reader LongBlockSize = 0xFFFF - (information & 0xFFFF); _syqReadLong6 = - !_dev.SyQuestReadLong6(out _, out senseBuf, 0, LongBlockSize, _timeout, + !_dev.SyQuestReadLong6(out _, + out senseBuf, + 0, + LongBlockSize, + _timeout, out _); } } } } + } } - if(!CanReadRaw && - LogicalBlockSize == 256) + if(!CanReadRaw && LogicalBlockSize == 256) { testSense = _dev.SyQuestReadLong6(out _, out senseBuf, 0, 262, _timeout, out _); - if(!testSense && - !_dev.Error) + if(!testSense && !_dev.Error) { _syqReadLong6 = true; LongBlockSize = 262; @@ -498,7 +570,7 @@ sealed partial class Reader switch(_dev.Manufacturer) { case "HL-DT-ST": - _hldtstReadRaw = !_dev.HlDtStReadRawDvd(out _, out senseBuf, 0, 1, _timeout, out _); + HldtstReadRaw = !_dev.HlDtStReadRawDvd(out _, out senseBuf, 0, 1, _timeout, out _); break; case "PLEXTOR": @@ -507,20 +579,18 @@ sealed partial class Reader break; } - if(_hldtstReadRaw || _plextorReadRaw) + if(HldtstReadRaw || _plextorReadRaw) { CanReadRaw = true; LongBlockSize = 2064; } // READ LONG (10) for some DVD drives - if(!CanReadRaw && - _dev.Manufacturer == "MATSHITA") + if(!CanReadRaw && _dev.Manufacturer == "MATSHITA") { testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, 37856, _timeout, out _); - if(!testSense && - !_dev.Error) + if(!testSense && !_dev.Error) { _readLongDvd = true; LongBlockSize = 37856; @@ -533,26 +603,24 @@ sealed partial class Reader if(CanReadRaw) { if(_readLong16) - AaruConsole.WriteLine("Using SCSI READ LONG (16) command."); + AaruConsole.WriteLine(Localization.Core.Using_SCSI_READ_LONG_16_command); else if(_readLong10 || _readLongDvd) - AaruConsole.WriteLine("Using SCSI READ LONG (10) command."); + AaruConsole.WriteLine(Localization.Core.Using_SCSI_READ_LONG_10_command); else if(_syqReadLong10) - AaruConsole.WriteLine("Using SyQuest READ LONG (10) command."); + AaruConsole.WriteLine(Localization.Core.Using_SyQuest_READ_LONG_10_command); else if(_syqReadLong6) - AaruConsole.WriteLine("Using SyQuest READ LONG (6) command."); - else if(_hldtstReadRaw) - AaruConsole.WriteLine("Using HL-DT-ST raw DVD reading."); - else if(_plextorReadRaw) - AaruConsole.WriteLine("Using Plextor raw DVD reading."); + AaruConsole.WriteLine(Localization.Core.Using_SyQuest_READ_LONG_6_command); + else if(HldtstReadRaw) + AaruConsole.WriteLine(Localization.Core.Using_HL_DT_ST_raw_DVD_reading); + else if(_plextorReadRaw) AaruConsole.WriteLine(Localization.Core.Using_Plextor_raw_DVD_reading); } else if(_read6) - AaruConsole.WriteLine("Using SCSI READ (6) command."); + AaruConsole.WriteLine(Localization.Core.Using_SCSI_READ_6_command); else if(_read10) - AaruConsole.WriteLine("Using SCSI READ (10) command."); + AaruConsole.WriteLine(Localization.Core.Using_SCSI_READ_10_command); else if(_read12) - AaruConsole.WriteLine("Using SCSI READ (12) command."); - else if(_read16) - AaruConsole.WriteLine("Using SCSI READ (16) command."); + AaruConsole.WriteLine(Localization.Core.Using_SCSI_READ_12_command); + else if(_read16) AaruConsole.WriteLine(Localization.Core.Using_SCSI_READ_16_command); return false; } @@ -573,22 +641,24 @@ sealed partial class Reader { sense = _dev.ReadCapacity16(out cmdBuf, out senseBuf, _timeout, out _); - if(sense && Blocks == 0) - if(_dev.ScsiType != PeripheralDeviceTypes.MultiMediaDevice) - { - ErrorMessage = "Unable to get media capacity\n" + $"{Sense.PrettifySense(senseBuf)}"; + switch(sense) + { + case true when Blocks == 0 && _dev.ScsiType != PeripheralDeviceTypes.MultiMediaDevice: + ErrorMessage = string.Format(Localization.Core.Unable_to_get_media_capacity, + Sense.PrettifySense(senseBuf)); return true; + case false: + { + var temp = new byte[8]; + + Array.Copy(cmdBuf, 0, temp, 0, 8); + Array.Reverse(temp); + Blocks = BitConverter.ToUInt64(temp, 0); + LogicalBlockSize = (uint)((cmdBuf[8] << 24) + (cmdBuf[9] << 16) + (cmdBuf[10] << 8) + cmdBuf[11]); + + break; } - - if(!sense) - { - var temp = new byte[8]; - - Array.Copy(cmdBuf, 0, temp, 0, 8); - Array.Reverse(temp); - Blocks = BitConverter.ToUInt64(temp, 0); - LogicalBlockSize = (uint)((cmdBuf[8] << 24) + (cmdBuf[9] << 16) + (cmdBuf[10] << 8) + cmdBuf[11]); } } @@ -604,45 +674,74 @@ sealed partial class Reader while(true) { - if(_read6) + if(HldtstReadRaw) + BlocksToRead = 1; + else if(_read6) { _dev.Read6(out _, out _, 0, LogicalBlockSize, (byte)BlocksToRead, _timeout, out _); - if(_dev.Error) - BlocksToRead /= 2; + if(_dev.Error) BlocksToRead /= 2; } else if(_read10) { - _dev.Read10(out _, out _, 0, false, true, false, false, 0, LogicalBlockSize, 0, (ushort)BlocksToRead, - _timeout, out _); + _dev.Read10(out _, + out _, + 0, + false, + true, + false, + false, + 0, + LogicalBlockSize, + 0, + (ushort)BlocksToRead, + _timeout, + out _); - if(_dev.Error) - BlocksToRead /= 2; + if(_dev.Error) BlocksToRead /= 2; } else if(_read12) { - _dev.Read12(out _, out _, 0, false, false, false, false, 0, LogicalBlockSize, 0, BlocksToRead, false, - _timeout, out _); + _dev.Read12(out _, + out _, + 0, + false, + false, + false, + false, + 0, + LogicalBlockSize, + 0, + BlocksToRead, + false, + _timeout, + out _); - if(_dev.Error) - BlocksToRead /= 2; + if(_dev.Error) BlocksToRead /= 2; } else if(_read16) { - _dev.Read16(out _, out _, 0, false, true, false, 0, LogicalBlockSize, 0, BlocksToRead, false, _timeout, + _dev.Read16(out _, + out _, + 0, + false, + true, + false, + 0, + LogicalBlockSize, + 0, + BlocksToRead, + false, + _timeout, out _); - if(_dev.Error) - BlocksToRead /= 2; + if(_dev.Error) BlocksToRead /= 2; } - if(!_dev.Error || - BlocksToRead == 1) - break; + if(!_dev.Error || BlocksToRead == 1) break; } - if(!_dev.Error) - return false; + if(!_dev.Error) return false; // Magneto-opticals may have LBA 0 empty, we can hard code the value to a safe one if(_dev.ScsiType == PeripheralDeviceTypes.OpticalDevice) @@ -653,13 +752,15 @@ sealed partial class Reader } BlocksToRead = 1; - ErrorMessage = $"Device error {_dev.LastError} trying to guess ideal transfer length."; + + ErrorMessage = string.Format(Localization.Core.Device_error_0_trying_to_guess_ideal_transfer_length, + _dev.LastError); return true; } bool ScsiReadBlocks(out byte[] buffer, ulong block, uint count, out double duration, out bool recoveredError, - out bool blankCheck) + out bool blankCheck) { bool sense; byte[] senseBuf; @@ -669,55 +770,145 @@ sealed partial class Reader blankCheck = false; if(CanReadRaw) + { if(_readLong16) sense = _dev.ReadLong16(out buffer, out senseBuf, false, block, LongBlockSize, _timeout, out duration); else if(_readLong10) - sense = _dev.ReadLong10(out buffer, out senseBuf, false, false, (uint)block, (ushort)LongBlockSize, - _timeout, out duration); + { + sense = _dev.ReadLong10(out buffer, + out senseBuf, + false, + false, + (uint)block, + (ushort)LongBlockSize, + _timeout, + out duration); + } else if(_syqReadLong10) - sense = _dev.SyQuestReadLong10(out buffer, out senseBuf, (uint)block, LongBlockSize, _timeout, + { + sense = _dev.SyQuestReadLong10(out buffer, + out senseBuf, + (uint)block, + LongBlockSize, + _timeout, out duration); + } else if(_syqReadLong6) - sense = _dev.SyQuestReadLong6(out buffer, out senseBuf, (uint)block, LongBlockSize, _timeout, - out duration); - else if(_hldtstReadRaw) - sense = _dev.HlDtStReadRawDvd(out buffer, out senseBuf, (uint)block, LongBlockSize, _timeout, + { + sense = _dev.SyQuestReadLong6(out buffer, + out senseBuf, + (uint)block, + LongBlockSize, + _timeout, out duration); + } + else if(HldtstReadRaw) + { + // We need to fill the buffer before reading it with the HL-DT-ST command. We don't care about sense, + // because the data can be wrong anyway, so we need to check the buffer data instead. + _dev.Read12(out buffer, + out senseBuf, + 0, + false, + false, + false, + false, + (uint)block, + LogicalBlockSize, + 0, + 16, + false, + _timeout, + out duration); + + sense = _dev.HlDtStReadRawDvd(out buffer, out senseBuf, (uint)block, count, _timeout, out duration); + } else if(_plextorReadRaw) - sense = _dev.PlextorReadRawDvd(out buffer, out senseBuf, (uint)block, LongBlockSize, _timeout, + { + sense = _dev.PlextorReadRawDvd(out buffer, + out senseBuf, + (uint)block, + LongBlockSize, + _timeout, out duration); + } else return true; + } else { if(_read6) - sense = _dev.Read6(out buffer, out senseBuf, (uint)block, LogicalBlockSize, (byte)count, _timeout, + { + sense = _dev.Read6(out buffer, + out senseBuf, + (uint)block, + LogicalBlockSize, + (byte)count, + _timeout, out duration); + } else if(_read10) - sense = _dev.Read10(out buffer, out senseBuf, 0, false, false, false, false, (uint)block, - LogicalBlockSize, 0, (ushort)count, _timeout, out duration); + { + sense = _dev.Read10(out buffer, + out senseBuf, + 0, + false, + false, + false, + false, + (uint)block, + LogicalBlockSize, + 0, + (ushort)count, + _timeout, + out duration); + } else if(_read12) - sense = _dev.Read12(out buffer, out senseBuf, 0, false, false, false, false, (uint)block, - LogicalBlockSize, 0, count, false, _timeout, out duration); + { + sense = _dev.Read12(out buffer, + out senseBuf, + 0, + false, + false, + false, + false, + (uint)block, + LogicalBlockSize, + 0, + count, + false, + _timeout, + out duration); + } else if(_read16) - sense = _dev.Read16(out buffer, out senseBuf, 0, false, false, false, block, LogicalBlockSize, 0, count, - false, _timeout, out duration); + { + sense = _dev.Read16(out buffer, + out senseBuf, + 0, + false, + false, + false, + block, + LogicalBlockSize, + 0, + count, + false, + _timeout, + out duration); + } else return true; } - if(sense || _dev.Error) - _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, senseBuf); + if(sense || _dev.Error) _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, senseBuf); - if(!sense && - !_dev.Error) - return false; + if(!sense && !_dev.Error) return false; recoveredError = Sense.Decode(senseBuf)?.SenseKey == SenseKeys.RecoveredError; blankCheck = Sense.Decode(senseBuf)?.SenseKey == SenseKeys.BlankCheck; - AaruConsole.DebugWriteLine("SCSI Reader", "READ error:\n{0}", Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.READ_error_0, Sense.PrettifySense(senseBuf)); return sense; } @@ -728,9 +919,8 @@ sealed partial class Reader duration = 0; if(_seek6) - sense = _dev.Seek6(out _, (uint)block, _timeout, out duration); - else if(_seek10) - sense = _dev.Seek10(out _, (uint)block, _timeout, out duration); + sense = _dev.Seek6(out _, (uint)block, _timeout, out duration); + else if(_seek10) sense = _dev.Seek10(out _, (uint)block, _timeout, out duration); return sense; } diff --git a/Aaru.Core/Devices/Report/ATA.cs b/Aaru.Core/Devices/Report/ATA.cs index 2fd70d43e..3705b480d 100644 --- a/Aaru.Core/Devices/Report/ATA.cs +++ b/Aaru.Core/Devices/Report/ATA.cs @@ -27,19 +27,19 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Report; - using System; using Aaru.CommonTypes.Metadata; using Aaru.Console; using Aaru.Decoders.ATA; using Aaru.Devices; -using global::Spectre.Console; +using Spectre.Console; using Identify = Aaru.CommonTypes.Structs.Devices.ATA.Identify; +namespace Aaru.Core.Devices.Report; + public sealed partial class DeviceReport { /// Creates a report for media inserted into an ATA device @@ -50,19 +50,19 @@ public sealed partial class DeviceReport AtaErrorRegistersChs errorChs = new(); AtaErrorRegistersLba28 errorLba = new(); AtaErrorRegistersLba48 errorLba48 = new(); - byte[] buffer = Array.Empty(); - byte[] readBuf = Array.Empty(); + byte[] buffer = []; + byte[] readBuf = []; var mediaTest = new TestedMedia { - MediumTypeName = AnsiConsole.Ask("Please write a description of the media type and press enter: "), - Model = AnsiConsole.Ask("Please write the media model and press enter: "), + MediumTypeName = AnsiConsole.Ask(Localization.Core.Please_write_description_of_media_type), + Model = AnsiConsole.Ask(Localization.Core.Please_write_media_model), MediaIsRecognized = true }; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying ATA IDENTIFY...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_ATA_IDENTIFY).IsIndeterminate(); _dev.AtaIdentify(out buffer, out _, _dev.Timeout, out _); }); @@ -73,15 +73,11 @@ public sealed partial class DeviceReport { Identify.IdentifyDevice ataId = mediaTest.IdentifyDevice.Value; - if(ataId.UnformattedBPT != 0) - mediaTest.UnformattedBPT = ataId.UnformattedBPT; + if(ataId.UnformattedBPT != 0) mediaTest.UnformattedBPT = ataId.UnformattedBPT; - if(ataId.UnformattedBPS != 0) - mediaTest.UnformattedBPS = ataId.UnformattedBPS; + if(ataId.UnformattedBPS != 0) mediaTest.UnformattedBPS = ataId.UnformattedBPS; - if(ataId.Cylinders > 0 && - ataId.Heads > 0 && - ataId.SectorsPerTrack > 0) + if(ataId.Cylinders > 0 && ataId is { Heads: > 0, SectorsPerTrack: > 0 }) { mediaTest.CHS = new Chs { @@ -93,9 +89,7 @@ public sealed partial class DeviceReport mediaTest.Blocks = (ulong)(ataId.Cylinders * ataId.Heads * ataId.SectorsPerTrack); } - if(ataId.CurrentCylinders > 0 && - ataId.CurrentHeads > 0 && - ataId.CurrentSectorsPerTrack > 0) + if(ataId.CurrentCylinders > 0 && ataId is { CurrentHeads: > 0, CurrentSectorsPerTrack: > 0 }) { mediaTest.CurrentCHS = new Chs { @@ -105,8 +99,10 @@ public sealed partial class DeviceReport }; if(mediaTest.Blocks == 0) + { mediaTest.Blocks = (ulong)(ataId.CurrentCylinders * ataId.CurrentHeads * ataId.CurrentSectorsPerTrack); + } } if(ataId.Capabilities.HasFlag(Identify.CapabilitiesBit.LBASupport)) @@ -121,8 +117,8 @@ public sealed partial class DeviceReport mediaTest.Blocks = ataId.LBA48Sectors; } - if(ataId.NominalRotationRate != 0x0000 && - ataId.NominalRotationRate != 0xFFFF) + if(ataId.NominalRotationRate != 0x0000 && ataId.NominalRotationRate != 0xFFFF) + { if(ataId.NominalRotationRate == 0x0001) mediaTest.SolidStateDevice = true; else @@ -130,24 +126,25 @@ public sealed partial class DeviceReport mediaTest.SolidStateDevice = false; mediaTest.NominalRotationRate = ataId.NominalRotationRate; } + } uint logicalSectorSize; uint physicalSectorSize; - if((ataId.PhysLogSectorSize & 0x8000) == 0x0000 && - (ataId.PhysLogSectorSize & 0x4000) == 0x4000) + if((ataId.PhysLogSectorSize & 0x8000) == 0x0000 && (ataId.PhysLogSectorSize & 0x4000) == 0x4000) { if((ataId.PhysLogSectorSize & 0x1000) == 0x1000) - if(ataId.LogicalSectorWords <= 255 || - ataId.LogicalAlignment == 0xFFFF) + { + if(ataId.LogicalSectorWords <= 255 || ataId.LogicalAlignment == 0xFFFF) logicalSectorSize = 512; else logicalSectorSize = ataId.LogicalSectorWords * 2; + } else logicalSectorSize = 512; if((ataId.PhysLogSectorSize & 0x2000) == 0x2000) - physicalSectorSize = (uint)(logicalSectorSize * ((1 << ataId.PhysLogSectorSize) & 0xF)); + physicalSectorSize = (uint)(logicalSectorSize * (1 << ataId.PhysLogSectorSize & 0xF)); else physicalSectorSize = logicalSectorSize; } @@ -163,13 +160,11 @@ public sealed partial class DeviceReport { mediaTest.PhysicalBlockSize = physicalSectorSize; - if((ataId.LogicalAlignment & 0x8000) == 0x0000 && - (ataId.LogicalAlignment & 0x4000) == 0x4000) + if((ataId.LogicalAlignment & 0x8000) == 0x0000 && (ataId.LogicalAlignment & 0x4000) == 0x4000) mediaTest.LogicalAlignment = (ushort)(ataId.LogicalAlignment & 0x3FFF); } - if(ataId.EccBytes != 0x0000 && - ataId.EccBytes != 0xFFFF) + if(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) mediaTest.LongBlockSize = logicalSectorSize + ataId.EccBytes; if(ataId.UnformattedBPS > logicalSectorSize && @@ -190,163 +185,209 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ SECTOR(S) in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_SECTORS_in_CHS_mode).IsIndeterminate(); sense = _dev.Read(out readBuf, out errorChs, false, 0, 0, 1, 1, _dev.Timeout, out _); }); - mediaTest.SupportsReadSectors = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0; + mediaTest.SupportsReadSectors = + !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadSectorsData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ SECTOR(S) RETRY in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_SECTORS_RETRY_in_CHS_mode).IsIndeterminate(); sense = _dev.Read(out readBuf, out errorChs, true, 0, 0, 1, 1, _dev.Timeout, out _); }); - mediaTest.SupportsReadRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0; + mediaTest.SupportsReadRetry = + !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadSectorsRetryData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ DMA in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_DMA_in_CHS_mode).IsIndeterminate(); sense = _dev.ReadDma(out readBuf, out errorChs, false, 0, 0, 1, 1, _dev.Timeout, out _); }); - mediaTest.SupportsReadDma = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0; + mediaTest.SupportsReadDma = + !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadDmaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ DMA RETRY in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_DMA_RETRY_in_CHS_mode).IsIndeterminate(); sense = _dev.ReadDma(out readBuf, out errorChs, true, 0, 0, 1, 1, _dev.Timeout, out _); }); - mediaTest.SupportsReadDmaRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0; + mediaTest.SupportsReadDmaRetry = + !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadDmaRetryData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SEEK in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SEEK_in_CHS_mode).IsIndeterminate(); sense = _dev.Seek(out errorChs, 0, 0, 1, _dev.Timeout, out _); }); mediaTest.SupportsSeek = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}", sense, - errorChs.Status, errorChs.Error); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2, + sense, + errorChs.Status, + errorChs.Error); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ SECTOR(S) in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_SECTORS_in_LBA_mode).IsIndeterminate(); sense = _dev.Read(out readBuf, out errorLba, false, 0, 1, _dev.Timeout, out _); }); - mediaTest.SupportsReadLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0; + mediaTest.SupportsReadLba = + !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadLbaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ SECTOR(S) RETRY in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_SECTORS_RETRY_in_LBA_mode).IsIndeterminate(); sense = _dev.Read(out readBuf, out errorLba, true, 0, 1, _dev.Timeout, out _); }); - mediaTest.SupportsReadRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0; + mediaTest.SupportsReadRetryLba = + !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadRetryLbaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ DMA in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_DMA_in_LBA_mode).IsIndeterminate(); sense = _dev.ReadDma(out readBuf, out errorLba, false, 0, 1, _dev.Timeout, out _); }); - mediaTest.SupportsReadDmaLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0; + mediaTest.SupportsReadDmaLba = + !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadDmaLbaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ DMA RETRY in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_DMA_RETRY_in_LBA_mode).IsIndeterminate(); sense = _dev.ReadDma(out readBuf, out errorLba, true, 0, 1, _dev.Timeout, out _); }); - mediaTest.SupportsReadDmaRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0; + mediaTest.SupportsReadDmaRetryLba = + !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadDmaRetryLbaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SEEK in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SEEK_in_LBA_mode).IsIndeterminate(); sense = _dev.Seek(out errorLba, 0, _dev.Timeout, out _); }); mediaTest.SupportsSeekLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}", sense, - errorChs.Status, errorChs.Error); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2, + sense, + errorChs.Status, + errorChs.Error); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ SECTOR(S) in LBA48 mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_SECTORS_in_LBA48_mode).IsIndeterminate(); sense = _dev.Read(out readBuf, out AtaErrorRegistersLba28 _, 0, 1, _dev.Timeout, out _); }); - mediaTest.SupportsReadLba48 = !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && - readBuf.Length > 0; + mediaTest.SupportsReadLba48 = + !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadLba48Data = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ DMA in LBA48 mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_DMA_in_LBA48_mode).IsIndeterminate(); sense = _dev.ReadDma(out readBuf, out errorLba48, 0, 1, _dev.Timeout, out _); }); - mediaTest.SupportsReadDmaLba48 = !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && - readBuf.Length > 0; + mediaTest.SupportsReadDmaLba48 = + !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadDmaLba48Data = readBuf; @@ -361,8 +402,7 @@ public sealed partial class DeviceReport { ataId = Identify.Decode(buffer).Value; - if(ataId.EccBytes != 0x0000 && - ataId.EccBytes != 0xFFFF) + if(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) mediaTest.LongBlockSize = logicalSectorSize + ataId.EccBytes; if(ataId.UnformattedBPS > logicalSectorSize && @@ -372,67 +412,117 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ LONG in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_LONG_in_CHS_mode).IsIndeterminate(); - sense = _dev.ReadLong(out readBuf, out errorChs, false, 0, 0, 1, mediaTest.LongBlockSize ?? 0, - _dev.Timeout, out _); + sense = _dev.ReadLong(out readBuf, + out errorChs, + false, + 0, + 0, + 1, + mediaTest.LongBlockSize ?? 0, + _dev.Timeout, + out _); }); - mediaTest.SupportsReadLong = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0 && BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + mediaTest.SupportsReadLong = !sense && + (errorChs.Status & 0x01) != 0x01 && + errorChs.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadLongData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ LONG RETRY in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_LONG_RETRY_in_CHS_mode).IsIndeterminate(); - sense = _dev.ReadLong(out readBuf, out errorChs, true, 0, 0, 1, mediaTest.LongBlockSize ?? 0, - _dev.Timeout, out _); + sense = _dev.ReadLong(out readBuf, + out errorChs, + true, + 0, + 0, + 1, + mediaTest.LongBlockSize ?? 0, + _dev.Timeout, + out _); }); - mediaTest.SupportsReadLongRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0 && BitConverter.ToUInt64(readBuf, 0) != - checkCorrectRead; + mediaTest.SupportsReadLongRetry = !sense && + (errorChs.Status & 0x01) != 0x01 && + errorChs.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadLongRetryData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ LONG in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_LONG_in_LBA_mode).IsIndeterminate(); - sense = _dev.ReadLong(out readBuf, out errorLba, false, 0, mediaTest.LongBlockSize ?? 0, _dev.Timeout, + sense = _dev.ReadLong(out readBuf, + out errorLba, + false, + 0, + mediaTest.LongBlockSize ?? 0, + _dev.Timeout, out _); }); - mediaTest.SupportsReadLongLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0 && BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + mediaTest.SupportsReadLongLba = !sense && + (errorLba.Status & 0x01) != 0x01 && + errorLba.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadLongLbaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ LONG RETRY in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_LONG_RETRY_in_LBA_mode).IsIndeterminate(); - sense = _dev.ReadLong(out readBuf, out errorLba, true, 0, mediaTest.LongBlockSize ?? 0, _dev.Timeout, + sense = _dev.ReadLong(out readBuf, + out errorLba, + true, + 0, + mediaTest.LongBlockSize ?? 0, + _dev.Timeout, out _); }); - mediaTest.SupportsReadLongRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0 && BitConverter.ToUInt64(readBuf, 0) != - checkCorrectRead; + mediaTest.SupportsReadLongRetryLba = !sense && + (errorLba.Status & 0x01) != 0x01 && + errorLba.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); mediaTest.ReadLongRetryLbaData = readBuf; } @@ -446,21 +536,17 @@ public sealed partial class DeviceReport public TestedMedia ReportAta(Identify.IdentifyDevice ataId) { var sense = true; - byte[] readBuf = Array.Empty(); + byte[] readBuf = []; AtaErrorRegistersChs errorChs = new(); AtaErrorRegistersLba28 errorLba = new(); AtaErrorRegistersLba48 errorLba48 = new(); var capabilities = new TestedMedia(); - if(ataId.UnformattedBPT != 0) - capabilities.UnformattedBPT = ataId.UnformattedBPT; + if(ataId.UnformattedBPT != 0) capabilities.UnformattedBPT = ataId.UnformattedBPT; - if(ataId.UnformattedBPS != 0) - capabilities.UnformattedBPS = ataId.UnformattedBPS; + if(ataId.UnformattedBPS != 0) capabilities.UnformattedBPS = ataId.UnformattedBPS; - if(ataId.Cylinders > 0 && - ataId.Heads > 0 && - ataId.SectorsPerTrack > 0) + if(ataId.Cylinders > 0 && ataId is { Heads: > 0, SectorsPerTrack: > 0 }) { capabilities.CHS = new Chs { @@ -472,9 +558,7 @@ public sealed partial class DeviceReport capabilities.Blocks = (ulong)(ataId.Cylinders * ataId.Heads * ataId.SectorsPerTrack); } - if(ataId.CurrentCylinders > 0 && - ataId.CurrentHeads > 0 && - ataId.CurrentSectorsPerTrack > 0) + if(ataId.CurrentCylinders > 0 && ataId is { CurrentHeads: > 0, CurrentSectorsPerTrack: > 0 }) { capabilities.CurrentCHS = new Chs { @@ -498,8 +582,8 @@ public sealed partial class DeviceReport capabilities.Blocks = ataId.LBA48Sectors; } - if(ataId.NominalRotationRate != 0x0000 && - ataId.NominalRotationRate != 0xFFFF) + if(ataId.NominalRotationRate != 0x0000 && ataId.NominalRotationRate != 0xFFFF) + { if(ataId.NominalRotationRate == 0x0001) capabilities.SolidStateDevice = true; else @@ -507,19 +591,20 @@ public sealed partial class DeviceReport capabilities.SolidStateDevice = false; capabilities.NominalRotationRate = ataId.NominalRotationRate; } + } uint logicalSectorSize; uint physicalSectorSize; - if((ataId.PhysLogSectorSize & 0x8000) == 0x0000 && - (ataId.PhysLogSectorSize & 0x4000) == 0x4000) + if((ataId.PhysLogSectorSize & 0x8000) == 0x0000 && (ataId.PhysLogSectorSize & 0x4000) == 0x4000) { if((ataId.PhysLogSectorSize & 0x1000) == 0x1000) - if(ataId.LogicalSectorWords <= 255 || - ataId.LogicalAlignment == 0xFFFF) + { + if(ataId.LogicalSectorWords <= 255 || ataId.LogicalAlignment == 0xFFFF) logicalSectorSize = 512; else logicalSectorSize = ataId.LogicalSectorWords * 2; + } else logicalSectorSize = 512; @@ -540,13 +625,11 @@ public sealed partial class DeviceReport { capabilities.PhysicalBlockSize = physicalSectorSize; - if((ataId.LogicalAlignment & 0x8000) == 0x0000 && - (ataId.LogicalAlignment & 0x4000) == 0x4000) + if((ataId.LogicalAlignment & 0x8000) == 0x0000 && (ataId.LogicalAlignment & 0x4000) == 0x4000) capabilities.LogicalAlignment = (ushort)(ataId.LogicalAlignment & 0x3FFF); } - if(ataId.EccBytes != 0x0000 && - ataId.EccBytes != 0xFFFF) + if(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) capabilities.LongBlockSize = logicalSectorSize + ataId.EccBytes; if(ataId.UnformattedBPS > logicalSectorSize && @@ -559,171 +642,216 @@ public sealed partial class DeviceReport { capabilities.CanReadMediaSerial = true; - if(!string.IsNullOrWhiteSpace(ataId.MediaManufacturer)) - capabilities.Manufacturer = ataId.MediaManufacturer; + if(!string.IsNullOrWhiteSpace(ataId.MediaManufacturer)) capabilities.Manufacturer = ataId.MediaManufacturer; } - ulong checkCorrectRead = 0; + const ulong checkCorrectRead = 0; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ SECTOR(S) in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_SECTORS_in_CHS_mode).IsIndeterminate(); sense = _dev.Read(out readBuf, out errorChs, false, 0, 0, 1, 1, _dev.Timeout, out _); }); - capabilities.SupportsReadSectors = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0; + capabilities.SupportsReadSectors = + !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); capabilities.ReadSectorsData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ SECTOR(S) RETRY in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_SECTORS_RETRY_in_CHS_mode).IsIndeterminate(); sense = _dev.Read(out readBuf, out errorChs, true, 0, 0, 1, 1, _dev.Timeout, out _); }); capabilities.SupportsReadRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); capabilities.ReadSectorsRetryData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ DMA in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_DMA_in_CHS_mode).IsIndeterminate(); sense = _dev.ReadDma(out readBuf, out errorChs, false, 0, 0, 1, 1, _dev.Timeout, out _); }); capabilities.SupportsReadDma = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); capabilities.ReadDmaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ DMA RETRY in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_DMA_RETRY_in_CHS_mode).IsIndeterminate(); sense = _dev.ReadDma(out readBuf, out errorChs, true, 0, 0, 1, 1, _dev.Timeout, out _); }); - capabilities.SupportsReadDmaRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0; + capabilities.SupportsReadDmaRetry = + !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); capabilities.ReadDmaRetryData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SEEK in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SEEK_in_CHS_mode).IsIndeterminate(); sense = _dev.Seek(out errorChs, 0, 0, 1, _dev.Timeout, out _); }); capabilities.SupportsSeek = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}", sense, - errorChs.Status, errorChs.Error); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2, + sense, + errorChs.Status, + errorChs.Error); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ SECTOR(S) in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_SECTORS_in_LBA_mode).IsIndeterminate(); sense = _dev.Read(out readBuf, out errorLba, false, 0, 1, _dev.Timeout, out _); }); capabilities.SupportsReadLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorLba.Status, errorLba.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorLba.Status, + errorLba.Error, + readBuf.Length); capabilities.ReadLbaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ SECTOR(S) RETRY in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_SECTORS_RETRY_in_LBA_mode).IsIndeterminate(); sense = _dev.Read(out readBuf, out errorLba, true, 0, 1, _dev.Timeout, out _); }); - capabilities.SupportsReadRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0; + capabilities.SupportsReadRetryLba = + !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorLba.Status, errorLba.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorLba.Status, + errorLba.Error, + readBuf.Length); capabilities.ReadRetryLbaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ DMA in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_DMA_in_LBA_mode).IsIndeterminate(); sense = _dev.ReadDma(out readBuf, out errorLba, false, 0, 1, _dev.Timeout, out _); }); - capabilities.SupportsReadDmaLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0; + capabilities.SupportsReadDmaLba = + !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorLba.Status, errorLba.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorLba.Status, + errorLba.Error, + readBuf.Length); capabilities.ReadDmaLbaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ DMA RETRY in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_DMA_RETRY_in_LBA_mode).IsIndeterminate(); sense = _dev.ReadDma(out readBuf, out errorLba, true, 0, 1, _dev.Timeout, out _); }); capabilities.SupportsReadDmaRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorLba.Status, errorLba.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorLba.Status, + errorLba.Error, + readBuf.Length); capabilities.ReadDmaRetryLbaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SEEK in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SEEK_in_LBA_mode).IsIndeterminate(); sense = _dev.Seek(out errorLba, 0, _dev.Timeout, out _); }); capabilities.SupportsSeekLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}", sense, - errorLba.Status, errorLba.Error); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2, + sense, + errorLba.Status, + errorLba.Error); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ SECTOR(S) in LBA48 mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_SECTORS_in_LBA48_mode).IsIndeterminate(); sense = _dev.Read(out readBuf, out errorLba48, 0, 1, _dev.Timeout, out _); }); - capabilities.SupportsReadLba48 = !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && - readBuf.Length > 0; + capabilities.SupportsReadLba48 = + !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorLba48.Status, errorLba48.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorLba48.Status, + errorLba48.Error, + readBuf.Length); capabilities.ReadLba48Data = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ DMA in LBA48 mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_DMA_in_LBA48_mode).IsIndeterminate(); sense = _dev.ReadDma(out readBuf, out errorLba48, 0, 1, _dev.Timeout, out _); }); - capabilities.SupportsReadDmaLba48 = !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && - readBuf.Length > 0; + capabilities.SupportsReadDmaLba48 = + !sense && (errorLba48.Status & 0x01) != 0x01 && errorLba48.Error == 0 && readBuf.Length > 0; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorLba48.Status, errorLba48.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorLba48.Status, + errorLba48.Error, + readBuf.Length); capabilities.ReadDmaLba48Data = readBuf; @@ -738,8 +866,7 @@ public sealed partial class DeviceReport { ataId = Identify.Decode(buffer).Value; - if(ataId.EccBytes != 0x0000 && - ataId.EccBytes != 0xFFFF) + if(ataId.EccBytes != 0x0000 && ataId.EccBytes != 0xFFFF) capabilities.LongBlockSize = logicalSectorSize + ataId.EccBytes; if(ataId.UnformattedBPS > logicalSectorSize && @@ -749,67 +876,117 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ LONG in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_LONG_in_CHS_mode).IsIndeterminate(); - sense = _dev.ReadLong(out readBuf, out errorChs, false, 0, 0, 1, capabilities.LongBlockSize ?? 0, - _dev.Timeout, out _); + sense = _dev.ReadLong(out readBuf, + out errorChs, + false, + 0, + 0, + 1, + capabilities.LongBlockSize ?? 0, + _dev.Timeout, + out _); }); - capabilities.SupportsReadLong = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0 && BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + capabilities.SupportsReadLong = !sense && + (errorChs.Status & 0x01) != 0x01 && + errorChs.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); capabilities.ReadLongData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ LONG RETRY in CHS mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_LONG_RETRY_in_CHS_mode).IsIndeterminate(); - sense = _dev.ReadLong(out readBuf, out errorChs, true, 0, 0, 1, capabilities.LongBlockSize ?? 0, - _dev.Timeout, out _); + sense = _dev.ReadLong(out readBuf, + out errorChs, + true, + 0, + 0, + 1, + capabilities.LongBlockSize ?? 0, + _dev.Timeout, + out _); }); - capabilities.SupportsReadLongRetry = !sense && (errorChs.Status & 0x01) != 0x01 && errorChs.Error == 0 && - readBuf.Length > 0 && - BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + capabilities.SupportsReadLongRetry = !sense && + (errorChs.Status & 0x01) != 0x01 && + errorChs.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorChs.Status, errorChs.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorChs.Status, + errorChs.Error, + readBuf.Length); capabilities.ReadLongRetryData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ LONG in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_LONG_in_LBA_mode).IsIndeterminate(); - sense = _dev.ReadLong(out readBuf, out errorLba, false, 0, capabilities.LongBlockSize ?? 0, _dev.Timeout, + sense = _dev.ReadLong(out readBuf, + out errorLba, + false, + 0, + capabilities.LongBlockSize ?? 0, + _dev.Timeout, out _); }); - capabilities.SupportsReadLongLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0 && BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; + capabilities.SupportsReadLongLba = !sense && + (errorLba.Status & 0x01) != 0x01 && + errorLba.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorLba.Status, errorLba.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorLba.Status, + errorLba.Error, + readBuf.Length); capabilities.ReadLongLbaData = readBuf; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying READ LONG RETRY in LBA mode...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_READ_LONG_RETRY_in_LBA_mode).IsIndeterminate(); - sense = _dev.ReadLong(out readBuf, out errorLba, true, 0, capabilities.LongBlockSize ?? 0, _dev.Timeout, + sense = _dev.ReadLong(out readBuf, + out errorLba, + true, + 0, + capabilities.LongBlockSize ?? 0, + _dev.Timeout, out _); }); - capabilities.SupportsReadLongRetryLba = !sense && (errorLba.Status & 0x01) != 0x01 && errorLba.Error == 0 && - readBuf.Length > 0 && BitConverter.ToUInt64(readBuf, 0) != - checkCorrectRead; + capabilities.SupportsReadLongRetryLba = !sense && + (errorLba.Status & 0x01) != 0x01 && + errorLba.Error == 0 && + readBuf.Length > 0 && + BitConverter.ToUInt64(readBuf, 0) != checkCorrectRead; - AaruConsole.DebugWriteLine("ATA Report", "Sense = {0}, Status = 0x{1:X2}, Error = 0x{2:X2}, Length = {3}", - sense, errorLba.Status, errorLba.Error, readBuf.Length); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, + Localization.Core.Sense_0_Status_1_Error_2_Length_3, + sense, + errorLba.Status, + errorLba.Error, + readBuf.Length); capabilities.ReadLongRetryLbaData = readBuf; @@ -823,7 +1000,7 @@ public sealed partial class DeviceReport { var empty = new byte[512]; - Array.Copy(empty, 0, buffer, 20, 20); + Array.Copy(empty, 0, buffer, 20, 20); Array.Copy(empty, 0, buffer, 216, 8); Array.Copy(empty, 0, buffer, 224, 8); Array.Copy(empty, 0, buffer, 352, 40); diff --git a/Aaru.Core/Devices/Report/DeviceReport.cs b/Aaru.Core/Devices/Report/DeviceReport.cs index 09b02bb94..98e53f8bf 100644 --- a/Aaru.Core/Devices/Report/DeviceReport.cs +++ b/Aaru.Core/Devices/Report/DeviceReport.cs @@ -27,15 +27,18 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Report; - using Aaru.Devices; +namespace Aaru.Core.Devices.Report; + public sealed partial class DeviceReport { + const string GDROM_MODULE_NAME = "GD-ROM reporter"; + const string ATA_MODULE_NAME = "ATA Report"; + const string SCSI_MODULE_NAME = "SCSI Report"; readonly Device _dev; /// Initializes a device report for the specified device (must be opened) diff --git a/Aaru.Core/Devices/Report/FireWire.cs b/Aaru.Core/Devices/Report/FireWire.cs index 1f3597dd8..5ec3c7a08 100644 --- a/Aaru.Core/Devices/Report/FireWire.cs +++ b/Aaru.Core/Devices/Report/FireWire.cs @@ -27,13 +27,13 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Report; - using Aaru.CommonTypes.Metadata; +namespace Aaru.Core.Devices.Report; + /// Implements creating a report for a FireWire device public sealed partial class DeviceReport { diff --git a/Aaru.Core/Devices/Report/GdRomSwapTrick.cs b/Aaru.Core/Devices/Report/GdRomSwapTrick.cs index ada2f79f3..7bff75228 100644 --- a/Aaru.Core/Devices/Report/GdRomSwapTrick.cs +++ b/Aaru.Core/Devices/Report/GdRomSwapTrick.cs @@ -27,15 +27,11 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable InlineOutVariableDeclaration -namespace Aaru.Core.Devices.Report; - using System; using System.Linq; using System.Threading; @@ -45,23 +41,24 @@ using Aaru.Decoders.CD; using Aaru.Decoders.SCSI; using Aaru.Devices; +namespace Aaru.Core.Devices.Report; + public sealed partial class DeviceReport { /// Tries and checks reading a GD-ROM disc using the swap disc trick and adds the result to a device report /// Device report - public void ReportGdRomSwapTrick(ref DeviceReportV2 report) + public void ReportGdRomSwapTrick(ref CommonTypes.Metadata.DeviceReport report) { report.GdRomSwapDiscCapabilities = new GdRomSwapDiscCapabilities(); var pressedKey = new ConsoleKeyInfo(); - while(pressedKey.Key != ConsoleKey.Y && - pressedKey.Key != ConsoleKey.N) + while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) { - AaruConsole. - Write("Have you previously tried with a GD-ROM disc and did the computer hang or crash? (Y/N): "); + AaruConsole.Write(Localization.Core + .Have_you_previously_tried_with_a_GD_ROM_disc_and_did_the_computer_hang_or_crash_Q); - pressedKey = Console.ReadKey(); + pressedKey = System.Console.ReadKey(); AaruConsole.WriteLine(); } @@ -72,16 +69,16 @@ public sealed partial class DeviceReport return; } - AaruConsole.WriteLine("Ejecting disc..."); + AaruConsole.WriteLine(Localization.Core.Ejecting_disc); _dev.AllowMediumRemoval(out _, _dev.Timeout, out _); _dev.EjectTray(out _, _dev.Timeout, out _); - AaruConsole.WriteLine("Please insert trap disc inside..."); - AaruConsole.WriteLine("Press any key to continue..."); - Console.ReadLine(); + AaruConsole.WriteLine(Localization.Core.Please_insert_trap_disc_inside); + AaruConsole.WriteLine(Localization.Core.Press_any_key_to_continue); + System.Console.ReadLine(); - AaruConsole.WriteLine("Sending READ FULL TOC to the device..."); + AaruConsole.WriteLine(Localization.Core.Sending_READ_FULL_TOC_to_the_device); var retries = 0; bool sense; @@ -93,16 +90,11 @@ public sealed partial class DeviceReport retries++; sense = _dev.ScsiTestUnitReady(out senseBuffer, _dev.Timeout, out _); - if(!sense) - break; + if(!sense) break; DecodedSense? decodedSense = Sense.Decode(senseBuffer); - if(decodedSense?.ASC != 0x04) - break; - - if(decodedSense?.ASCQ != 0x01) - break; + if(decodedSense is not { ASC: 0x04, ASCQ: 0x01 }) break; Thread.Sleep(2000); } while(retries < 25); @@ -111,8 +103,8 @@ public sealed partial class DeviceReport if(sense) { - AaruConsole.WriteLine("READ FULL TOC failed..."); - AaruConsole.DebugWriteLine("GD-ROM reporter", "{0}", Sense.PrettifySense(senseBuffer)); + AaruConsole.WriteLine(Localization.Core.READ_FULL_TOC_failed); + AaruConsole.DebugWriteLine(GDROM_MODULE_NAME, "{0}", Sense.PrettifySense(senseBuffer)); report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false; report.GdRomSwapDiscCapabilities.TestCrashed = false; @@ -124,7 +116,7 @@ public sealed partial class DeviceReport if(decodedToc is null) { - AaruConsole.WriteLine("Could not decode TOC..."); + AaruConsole.WriteLine(Localization.Core.Could_not_decode_TOC); report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false; report.GdRomSwapDiscCapabilities.TestCrashed = false; @@ -132,13 +124,14 @@ public sealed partial class DeviceReport return; } - FullTOC.CDFullTOC toc = decodedToc.Value; + // Guaranteed to never fall into default + FullTOC.CDFullTOC toc = decodedToc ?? default(FullTOC.CDFullTOC); FullTOC.TrackDataDescriptor leadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2); if(leadOutTrack.POINT != 0xA2) { - AaruConsole.WriteLine("Cannot find lead-out..."); + AaruConsole.WriteLine(Localization.Core.Cannot_find_lead_out); report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false; report.GdRomSwapDiscCapabilities.TestCrashed = false; @@ -153,14 +146,17 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.SwapDiscLeadOutPSEC = leadOutTrack.PSEC; report.GdRomSwapDiscCapabilities.SwapDiscLeadOutPFRAM = leadOutTrack.PFRAME; - if(leadOutTrack.PMIN == 122) - tocIsNotBcd = true; - - if(leadOutTrack.PMIN >= 0xA0 && - !tocIsNotBcd) + switch(leadOutTrack.PMIN) { - min += 90; - leadOutTrack.PMIN -= 0x90; + case 122: + tocIsNotBcd = true; + + break; + case >= 0xA0: + min += 90; + leadOutTrack.PMIN -= 0x90; + + break; } if(tocIsNotBcd) @@ -178,11 +174,11 @@ public sealed partial class DeviceReport int sectors = min * 60 * 75 + sec * 75 + frame - 150; - AaruConsole.WriteLine("Trap disc shows {0} sectors...", sectors); + AaruConsole.WriteLine(Localization.Core.Trap_disc_shows_0_sectors, sectors); if(sectors < 450000) { - AaruConsole.WriteLine("Trap disc doesn't have enough sectors..."); + AaruConsole.WriteLine(Localization.Core.Trap_disc_doesnt_have_enough_sectors); report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false; report.GdRomSwapDiscCapabilities.TestCrashed = false; @@ -192,18 +188,18 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = true; - AaruConsole.WriteLine("Stopping motor..."); + AaruConsole.WriteLine(Localization.Core.Stopping_motor); _dev.StopUnit(out _, _dev.Timeout, out _); - AaruConsole.WriteLine("Please MANUALLY get the trap disc out and put the GD-ROM disc inside..."); - AaruConsole.WriteLine("Press any key to continue..."); - Console.ReadLine(); + AaruConsole.WriteLine(Localization.Core.Please_MANUALLY_get_the_trap_disc_out_and_put_the_GD_ROM_disc_inside); + AaruConsole.WriteLine(Localization.Core.Press_any_key_to_continue); + System.Console.ReadLine(); - AaruConsole.WriteLine("Waiting 5 seconds..."); + AaruConsole.WriteLine(Localization.Core.Waiting_5_seconds); Thread.Sleep(5000); - AaruConsole.WriteLine("Sending READ FULL TOC to the device..."); + AaruConsole.WriteLine(Localization.Core.Sending_READ_FULL_TOC_to_the_device); retries = 0; @@ -212,22 +208,17 @@ public sealed partial class DeviceReport retries++; sense = _dev.ReadRawToc(out buffer, out senseBuffer, 1, _dev.Timeout, out _); - if(!sense) - break; + if(!sense) break; DecodedSense? decodedSense = Sense.Decode(senseBuffer); - if(decodedSense?.ASC != 0x04) - break; - - if(decodedSense?.ASCQ != 0x01) - break; + if(decodedSense is not { ASC: 0x04, ASCQ: 0x01 }) break; } while(retries < 25); if(sense) { - AaruConsole.WriteLine("READ FULL TOC failed..."); - AaruConsole.DebugWriteLine("GD-ROM reporter", "{0}", Sense.PrettifySense(senseBuffer)); + AaruConsole.WriteLine(Localization.Core.READ_FULL_TOC_failed); + AaruConsole.DebugWriteLine(GDROM_MODULE_NAME, "{0}", Sense.PrettifySense(senseBuffer)); report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false; report.GdRomSwapDiscCapabilities.TestCrashed = false; @@ -239,7 +230,7 @@ public sealed partial class DeviceReport if(decodedToc is null) { - AaruConsole.WriteLine("Could not decode TOC..."); + AaruConsole.WriteLine(Localization.Core.Could_not_decode_TOC); report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false; report.GdRomSwapDiscCapabilities.TestCrashed = false; @@ -247,13 +238,14 @@ public sealed partial class DeviceReport return; } - toc = decodedToc.Value; + // Guaranteed to never fall into default + toc = decodedToc ?? default(FullTOC.CDFullTOC); FullTOC.TrackDataDescriptor newLeadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2); if(newLeadOutTrack.POINT != 0xA2) { - AaruConsole.WriteLine("Cannot find lead-out..."); + AaruConsole.WriteLine(Localization.Core.Cannot_find_lead_out); report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false; report.GdRomSwapDiscCapabilities.TestCrashed = false; @@ -261,15 +253,14 @@ public sealed partial class DeviceReport return; } - if(newLeadOutTrack.PMIN >= 0xA0 && - !tocIsNotBcd) - newLeadOutTrack.PMIN -= 0x90; + if(newLeadOutTrack.PMIN >= 0xA0 && !tocIsNotBcd) newLeadOutTrack.PMIN -= 0x90; if(newLeadOutTrack.PMIN != leadOutTrack.PMIN || newLeadOutTrack.PSEC != leadOutTrack.PSEC || newLeadOutTrack.PFRAME != leadOutTrack.PFRAME) { - AaruConsole.WriteLine("Lead-out has changed, this drive does not support hot swapping discs..."); + AaruConsole.WriteLine(Localization.Core + .Lead_out_has_changed_this_drive_does_not_support_hot_swapping_discs); report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false; report.GdRomSwapDiscCapabilities.TestCrashed = false; @@ -279,47 +270,81 @@ public sealed partial class DeviceReport _dev.SetCdSpeed(out _, RotationalControl.PureCav, 170, 0, _dev.Timeout, out _); - AaruConsole.Write("Reading LBA 0... "); + AaruConsole.Write(Localization.Core.Reading_LBA_zero); - report.GdRomSwapDiscCapabilities.Lba0Readable = !_dev.ReadCd(out byte[] lba0Buffer, out byte[] lba0Sense, 0, - 2352, 1, MmcSectorTypes.AllTypes, false, false, - true, MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + report.GdRomSwapDiscCapabilities.Lba0Readable = !_dev.ReadCd(out byte[] lba0Buffer, + out byte[] lba0Sense, + 0, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba0Data = lba0Buffer; report.GdRomSwapDiscCapabilities.Lba0Sense = lba0Sense; report.GdRomSwapDiscCapabilities.Lba0DecodedSense = Sense.PrettifySense(lba0Sense); - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba0Readable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba0Readable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 0 as audio (scrambled)... "); + AaruConsole.Write(Localization.Core.Reading_LBA_zero_as_audio_scrambled); report.GdRomSwapDiscCapabilities.Lba0ScrambledReadable = !_dev.ReadCd(out byte[] lba0ScrambledBuffer, - out byte[] lba0ScrambledSense, 0, 2352, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + out byte[] lba0ScrambledSense, + 0, + 2352, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba0ScrambledData = lba0ScrambledBuffer; report.GdRomSwapDiscCapabilities.Lba0ScrambledSense = lba0ScrambledSense; report.GdRomSwapDiscCapabilities.Lba0ScrambledDecodedSense = Sense.PrettifySense(lba0ScrambledSense); - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba0ScrambledReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba0ScrambledReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 100000 as audio... "); + AaruConsole.Write(Localization.Core.Reading_LBA_100000_as_audio); uint cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba100000AudioReadable = !_dev.ReadCd(out byte[] lba100000AudioBuffer, out byte[] lba100000AudioSenseBuffer, - 100000, 2352, cluster, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + 100000, + 2352, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba100000AudioData = lba100000AudioBuffer; report.GdRomSwapDiscCapabilities.Lba100000AudioSense = lba100000AudioSenseBuffer; @@ -329,28 +354,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba100000AudioReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba100000AudioReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba100000AudioReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000AudioReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000AudioReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 50000 as audio... "); + AaruConsole.Write(Localization.Core.Reading_LBA_50000_as_audio); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba50000AudioReadable = !_dev.ReadCd(out byte[] lba50000AudioBuffer, out byte[] lba50000AudioSenseBuffer, - 50000, 2352, cluster, MmcSectorTypes.Cdda, - false, false, false, MmcHeaderCodes.None, - true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); + 50000, + 2352, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba50000AudioData = lba50000AudioBuffer; report.GdRomSwapDiscCapabilities.Lba50000AudioSense = lba50000AudioSenseBuffer; @@ -359,29 +394,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba50000AudioReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba50000AudioReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba50000AudioReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000AudioReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000AudioReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 450000 as audio... "); + AaruConsole.Write(Localization.Core.Reading_LBA_450000_as_audio); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba450000AudioReadable = !_dev.ReadCd(out byte[] lba450000AudioBuffer, out byte[] lba450000AudioSenseBuffer, - 450000, 2352, cluster, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + 450000, + 2352, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba450000AudioData = lba450000AudioBuffer; report.GdRomSwapDiscCapabilities.Lba450000AudioSense = lba450000AudioSenseBuffer; @@ -391,29 +435,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba450000AudioReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba450000AudioReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba450000AudioReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000AudioReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000AudioReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 400000 as audio... "); + AaruConsole.Write(Localization.Core.Reading_LBA_400000_as_audio); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba400000AudioReadable = !_dev.ReadCd(out byte[] lba400000AudioBuffer, out byte[] lba400000AudioSenseBuffer, - 400000, 2352, cluster, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + 400000, + 2352, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba400000AudioData = lba400000AudioBuffer; report.GdRomSwapDiscCapabilities.Lba400000AudioSense = lba400000AudioSenseBuffer; @@ -423,28 +476,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba400000AudioReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba400000AudioReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba400000AudioReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000AudioReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000AudioReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 45000 as audio... "); + AaruConsole.Write(Localization.Core.Reading_LBA_45000_as_audio); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba45000AudioReadable = !_dev.ReadCd(out byte[] lba45000AudioBuffer, out byte[] lba45000AudioSenseBuffer, - 45000, 2352, cluster, MmcSectorTypes.Cdda, - false, false, false, MmcHeaderCodes.None, - true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); + 45000, + 2352, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba45000AudioData = lba45000AudioBuffer; report.GdRomSwapDiscCapabilities.Lba45000AudioSense = lba45000AudioSenseBuffer; @@ -453,28 +516,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba45000AudioReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba45000AudioReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba45000AudioReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000AudioReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000AudioReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 44990 as audio... "); + AaruConsole.Write(Localization.Core.Reading_LBA_44990_as_audio); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba44990AudioReadable = !_dev.ReadCd(out byte[] lba44990AudioBuffer, out byte[] lba44990AudioSenseBuffer, - 44990, 2352, cluster, MmcSectorTypes.Cdda, - false, false, false, MmcHeaderCodes.None, - true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); + 44990, + 2352, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba44990AudioData = lba44990AudioBuffer; report.GdRomSwapDiscCapabilities.Lba44990AudioSense = lba44990AudioSenseBuffer; @@ -483,29 +556,37 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba44990AudioReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba44990AudioReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba44990AudioReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990AudioReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990AudioReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 100000 as audio with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_100000_as_audio_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable = !_dev.ReadCd(out byte[] lba100000AudioPqBuffer, out byte[] lba100000AudioPqSenseBuffer, - 100000, 2368, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, - MmcSubchannel.Q16, _dev.Timeout, + 100000, + 2368, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba100000AudioPqData = lba100000AudioPqBuffer; @@ -516,29 +597,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 50000 as audio with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_50000_as_audio_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable = !_dev.ReadCd(out byte[] lba50000AudioPqBuffer, out byte[] lba50000AudioPqSenseBuffer, - 50000, 2368, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.Q16, - _dev.Timeout, out _); + 50000, + 2368, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba50000AudioPqData = lba50000AudioPqBuffer; report.GdRomSwapDiscCapabilities.Lba50000AudioPqSense = lba50000AudioPqSenseBuffer; @@ -548,29 +638,37 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 450000 as audio with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_450000_as_audio_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable = !_dev.ReadCd(out byte[] lba450000AudioPqBuffer, out byte[] lba450000AudioPqSenseBuffer, - 450000, 2368, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, - MmcSubchannel.Q16, _dev.Timeout, + 450000, + 2368, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba450000AudioPqData = lba450000AudioPqBuffer; @@ -581,29 +679,37 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 400000 as audio with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_400000_as_audio_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable = !_dev.ReadCd(out byte[] lba400000AudioPqBuffer, out byte[] lba400000AudioPqSenseBuffer, - 400000, 2368, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, - MmcSubchannel.Q16, _dev.Timeout, + 400000, + 2368, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba400000AudioPqData = lba400000AudioPqBuffer; @@ -614,29 +720,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 45000 as audio with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_45000_as_audio_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable = !_dev.ReadCd(out byte[] lba45000AudioPqBuffer, out byte[] lba45000AudioPqSenseBuffer, - 45000, 2368, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.Q16, - _dev.Timeout, out _); + 45000, + 2368, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba45000AudioPqData = lba45000AudioPqBuffer; report.GdRomSwapDiscCapabilities.Lba45000AudioPqSense = lba45000AudioPqSenseBuffer; @@ -646,29 +761,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 44990 as audio with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_44990_as_audio_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba44990AudioPqReadable = !_dev.ReadCd(out byte[] lba44990AudioPqBuffer, out byte[] lba44990AudioPqSenseBuffer, - 44990, 2368, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.Q16, - _dev.Timeout, out _); + 44990, + 2368, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba44990AudioPqData = lba44990AudioPqBuffer; report.GdRomSwapDiscCapabilities.Lba44990AudioPqSense = lba44990AudioPqSenseBuffer; @@ -678,29 +802,37 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba44990AudioPqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba44990AudioPqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba44990AudioPqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990AudioPqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990AudioPqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 100000 as audio with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_100000_as_audio_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadable = !_dev.ReadCd(out byte[] lba100000AudioRwBuffer, out byte[] lba100000AudioRwSenseBuffer, - 100000, 2448, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, - MmcSubchannel.Raw, _dev.Timeout, + 100000, + 2448, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba100000AudioRwData = lba100000AudioRwBuffer; @@ -711,29 +843,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 50000 as audio with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_50000_as_audio_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadable = !_dev.ReadCd(out byte[] lba50000AudioRwBuffer, out byte[] lba50000AudioRwSenseBuffer, - 50000, 2448, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.Raw, - _dev.Timeout, out _); + 50000, + 2448, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba50000AudioRwData = lba50000AudioRwBuffer; report.GdRomSwapDiscCapabilities.Lba50000AudioRwSense = lba50000AudioRwSenseBuffer; @@ -743,29 +884,37 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 450000 as audio with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_450000_as_audio_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadable = !_dev.ReadCd(out byte[] lba450000AudioRwBuffer, out byte[] lba450000AudioRwSenseBuffer, - 450000, 2448, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, - MmcSubchannel.Raw, _dev.Timeout, + 450000, + 2448, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba450000AudioRwData = lba450000AudioRwBuffer; @@ -776,29 +925,37 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 400000 as audio with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_400000_as_audio_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadable = !_dev.ReadCd(out byte[] lba400000AudioRwBuffer, out byte[] lba400000AudioRwSenseBuffer, - 400000, 2448, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, - MmcSubchannel.Raw, _dev.Timeout, + 400000, + 2448, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba400000AudioRwData = lba400000AudioRwBuffer; @@ -809,29 +966,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 45000 as audio with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_45000_as_audio_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadable = !_dev.ReadCd(out byte[] lba45000AudioRwBuffer, out byte[] lba45000AudioRwSenseBuffer, - 45000, 2448, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.Raw, - _dev.Timeout, out _); + 45000, + 2448, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba45000AudioRwData = lba45000AudioRwBuffer; report.GdRomSwapDiscCapabilities.Lba45000AudioRwSense = lba45000AudioRwSenseBuffer; @@ -841,29 +1007,38 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 44990 as audio with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_44990_as_audio_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba44990AudioRwReadable = !_dev.ReadCd(out byte[] lba44990AudioRwBuffer, out byte[] lba44990AudioRwSenseBuffer, - 44990, 2448, cluster, - MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.Raw, - _dev.Timeout, out _); + 44990, + 2448, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba44990AudioRwData = lba44990AudioRwBuffer; report.GdRomSwapDiscCapabilities.Lba44990AudioRwSense = lba44990AudioRwSenseBuffer; @@ -873,204 +1048,265 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba44990AudioRwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba44990AudioRwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba44990AudioRwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990AudioRwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990AudioRwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 100000... "); + AaruConsole.Write(Localization.Core.Reading_LBA_100000); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba100000Readable = !_dev.ReadCd(out byte[] lba100000Buffer, - out byte[] lba100000SenseBuffer, 100000, - 2352, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + out byte[] lba100000SenseBuffer, + 100000, + 2352, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba100000Data = lba100000Buffer; report.GdRomSwapDiscCapabilities.Lba100000Sense = lba100000SenseBuffer; report.GdRomSwapDiscCapabilities.Lba100000DecodedSense = Sense.PrettifySense(lba100000SenseBuffer); report.GdRomSwapDiscCapabilities.Lba100000ReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba100000Readable) - break; + if(report.GdRomSwapDiscCapabilities.Lba100000Readable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000Readable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000Readable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 50000... "); + AaruConsole.Write(Localization.Core.Reading_LBA_50000); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba50000Readable = !_dev.ReadCd(out byte[] lba50000Buffer, - out byte[] lba50000SenseBuffer, 50000, - 2352, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + out byte[] lba50000SenseBuffer, + 50000, + 2352, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba50000Data = lba50000Buffer; report.GdRomSwapDiscCapabilities.Lba50000Sense = lba50000SenseBuffer; report.GdRomSwapDiscCapabilities.Lba50000DecodedSense = Sense.PrettifySense(lba50000SenseBuffer); report.GdRomSwapDiscCapabilities.Lba50000ReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba50000Readable) - break; + if(report.GdRomSwapDiscCapabilities.Lba50000Readable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000Readable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000Readable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 450000... "); + AaruConsole.Write(Localization.Core.Reading_LBA_450000); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba450000Readable = !_dev.ReadCd(out byte[] lba450000Buffer, - out byte[] lba450000SenseBuffer, 450000, - 2352, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + out byte[] lba450000SenseBuffer, + 450000, + 2352, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba450000Data = lba450000Buffer; report.GdRomSwapDiscCapabilities.Lba450000Sense = lba450000SenseBuffer; report.GdRomSwapDiscCapabilities.Lba450000DecodedSense = Sense.PrettifySense(lba450000SenseBuffer); report.GdRomSwapDiscCapabilities.Lba450000ReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba450000Readable) - break; + if(report.GdRomSwapDiscCapabilities.Lba450000Readable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000Readable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000Readable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 400000... "); + AaruConsole.Write(Localization.Core.Reading_LBA_400000); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba400000Readable = !_dev.ReadCd(out byte[] lba400000Buffer, - out byte[] lba400000SenseBuffer, 400000, - 2352, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + out byte[] lba400000SenseBuffer, + 400000, + 2352, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba400000Data = lba400000Buffer; report.GdRomSwapDiscCapabilities.Lba400000Sense = lba400000SenseBuffer; report.GdRomSwapDiscCapabilities.Lba400000DecodedSense = Sense.PrettifySense(lba400000SenseBuffer); report.GdRomSwapDiscCapabilities.Lba400000ReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba400000Readable) - break; + if(report.GdRomSwapDiscCapabilities.Lba400000Readable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000Readable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000Readable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 45000... "); + AaruConsole.Write(Localization.Core.Reading_LBA_45000); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba45000Readable = !_dev.ReadCd(out byte[] lba45000Buffer, - out byte[] lba45000SenseBuffer, 45000, - 2352, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + out byte[] lba45000SenseBuffer, + 45000, + 2352, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba45000Data = lba45000Buffer; report.GdRomSwapDiscCapabilities.Lba45000Sense = lba45000SenseBuffer; report.GdRomSwapDiscCapabilities.Lba45000DecodedSense = Sense.PrettifySense(lba45000SenseBuffer); report.GdRomSwapDiscCapabilities.Lba45000ReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba45000Readable) - break; + if(report.GdRomSwapDiscCapabilities.Lba45000Readable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000Readable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000Readable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 44990... "); + AaruConsole.Write(Localization.Core.Reading_LBA_44990); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba44990Readable = !_dev.ReadCd(out byte[] lba44990Buffer, - out byte[] lba44990SenseBuffer, 44990, - 2352, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + out byte[] lba44990SenseBuffer, + 44990, + 2352, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba44990Data = lba44990Buffer; report.GdRomSwapDiscCapabilities.Lba44990Sense = lba44990SenseBuffer; report.GdRomSwapDiscCapabilities.Lba44990DecodedSense = Sense.PrettifySense(lba44990SenseBuffer); report.GdRomSwapDiscCapabilities.Lba44990ReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba44990Readable) - break; + if(report.GdRomSwapDiscCapabilities.Lba44990Readable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990Readable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990Readable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 100000 with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_100000_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba100000PqReadable = !_dev.ReadCd(out byte[] lba100000PqBuffer, out byte[] lba100000PqSenseBuffer, - 100000, 2368, cluster, - MmcSectorTypes.AllTypes, false, - false, true, - MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, - MmcSubchannel.Q16, _dev.Timeout, + 100000, + 2368, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba100000PqData = lba100000PqBuffer; @@ -1078,59 +1314,75 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba100000PqDecodedSense = Sense.PrettifySense(lba100000PqSenseBuffer); report.GdRomSwapDiscCapabilities.Lba100000PqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba100000PqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba100000PqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000PqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000PqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 50000 with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_50000_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba50000PqReadable = !_dev.ReadCd(out byte[] lba50000PqBuffer, - out byte[] lba50000PqSenseBuffer, 50000, - 2368, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.Q16, - _dev.Timeout, out _); + out byte[] lba50000PqSenseBuffer, + 50000, + 2368, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba50000PqData = lba50000PqBuffer; report.GdRomSwapDiscCapabilities.Lba50000PqSense = lba50000PqSenseBuffer; report.GdRomSwapDiscCapabilities.Lba50000PqDecodedSense = Sense.PrettifySense(lba50000PqSenseBuffer); report.GdRomSwapDiscCapabilities.Lba50000PqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba50000PqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba50000PqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000PqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000PqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 450000 with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_450000_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba450000PqReadable = !_dev.ReadCd(out byte[] lba450000PqBuffer, out byte[] lba450000PqSenseBuffer, - 450000, 2368, cluster, - MmcSectorTypes.AllTypes, false, - false, true, - MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, - MmcSubchannel.Q16, _dev.Timeout, + 450000, + 2368, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba450000PqData = lba450000PqBuffer; @@ -1138,30 +1390,37 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba450000PqDecodedSense = Sense.PrettifySense(lba450000PqSenseBuffer); report.GdRomSwapDiscCapabilities.Lba450000PqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba450000PqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba450000PqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000PqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000PqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 400000 with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_400000_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba400000PqReadable = !_dev.ReadCd(out byte[] lba400000PqBuffer, out byte[] lba400000PqSenseBuffer, - 400000, 2368, cluster, - MmcSectorTypes.AllTypes, false, - false, true, - MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, - MmcSubchannel.Q16, _dev.Timeout, + 400000, + 2368, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba400000PqData = lba400000PqBuffer; @@ -1169,88 +1428,113 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba400000PqDecodedSense = Sense.PrettifySense(lba400000PqSenseBuffer); report.GdRomSwapDiscCapabilities.Lba400000PqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba400000PqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba400000PqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000PqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000PqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 45000 with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_45000_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba45000PqReadable = !_dev.ReadCd(out byte[] lba45000PqBuffer, - out byte[] lba45000PqSenseBuffer, 45000, - 2368, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.Q16, - _dev.Timeout, out _); + out byte[] lba45000PqSenseBuffer, + 45000, + 2368, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba45000PqData = lba45000PqBuffer; report.GdRomSwapDiscCapabilities.Lba45000PqSense = lba45000PqSenseBuffer; report.GdRomSwapDiscCapabilities.Lba45000PqDecodedSense = Sense.PrettifySense(lba45000PqSenseBuffer); report.GdRomSwapDiscCapabilities.Lba45000PqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba45000PqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba45000PqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000PqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000PqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 44990 with PQ subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_44990_with_PQ_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba44990PqReadable = !_dev.ReadCd(out byte[] lba44990PqBuffer, - out byte[] lba44990PqSenseBuffer, 44990, - 2368, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.Q16, - _dev.Timeout, out _); + out byte[] lba44990PqSenseBuffer, + 44990, + 2368, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba44990PqData = lba44990PqBuffer; report.GdRomSwapDiscCapabilities.Lba44990PqSense = lba44990PqSenseBuffer; report.GdRomSwapDiscCapabilities.Lba44990PqDecodedSense = Sense.PrettifySense(lba44990PqSenseBuffer); report.GdRomSwapDiscCapabilities.Lba44990PqReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba44990PqReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba44990PqReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990PqReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990PqReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 100000 with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_100000_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba100000RwReadable = !_dev.ReadCd(out byte[] lba100000RwBuffer, out byte[] lba100000RwSenseBuffer, - 100000, 2448, cluster, - MmcSectorTypes.AllTypes, false, - false, true, - MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, - MmcSubchannel.Raw, _dev.Timeout, + 100000, + 2448, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba100000RwData = lba100000RwBuffer; @@ -1258,59 +1542,75 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba100000RwDecodedSense = Sense.PrettifySense(lba100000RwSenseBuffer); report.GdRomSwapDiscCapabilities.Lba100000RwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba100000RwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba100000RwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000RwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000RwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 50000 with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_50000_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba50000RwReadable = !_dev.ReadCd(out byte[] lba50000RwBuffer, - out byte[] lba50000RwSenseBuffer, 50000, - 2448, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.Raw, - _dev.Timeout, out _); + out byte[] lba50000RwSenseBuffer, + 50000, + 2448, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba50000RwData = lba50000RwBuffer; report.GdRomSwapDiscCapabilities.Lba50000RwSense = lba50000RwSenseBuffer; report.GdRomSwapDiscCapabilities.Lba50000RwDecodedSense = Sense.PrettifySense(lba50000RwSenseBuffer); report.GdRomSwapDiscCapabilities.Lba50000RwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba50000RwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba50000RwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000RwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000RwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 450000 with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_450000_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba450000RwReadable = !_dev.ReadCd(out byte[] lba450000RwBuffer, out byte[] lba450000RwSenseBuffer, - 450000, 2448, cluster, - MmcSectorTypes.AllTypes, false, - false, true, - MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, - MmcSubchannel.Raw, _dev.Timeout, + 450000, + 2448, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba450000RwData = lba450000RwBuffer; @@ -1318,30 +1618,37 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba450000RwDecodedSense = Sense.PrettifySense(lba450000RwSenseBuffer); report.GdRomSwapDiscCapabilities.Lba450000RwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba450000RwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba450000RwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000RwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000RwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 400000 with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_400000_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba400000RwReadable = !_dev.ReadCd(out byte[] lba400000RwBuffer, out byte[] lba400000RwSenseBuffer, - 400000, 2448, cluster, - MmcSectorTypes.AllTypes, false, - false, true, - MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, - MmcSubchannel.Raw, _dev.Timeout, + 400000, + 2448, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, out _); report.GdRomSwapDiscCapabilities.Lba400000RwData = lba400000RwBuffer; @@ -1349,74 +1656,92 @@ public sealed partial class DeviceReport report.GdRomSwapDiscCapabilities.Lba400000RwDecodedSense = Sense.PrettifySense(lba400000RwSenseBuffer); report.GdRomSwapDiscCapabilities.Lba400000RwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba400000RwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba400000RwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000RwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000RwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 45000 with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_45000_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba45000RwReadable = !_dev.ReadCd(out byte[] lba45000RwBuffer, - out byte[] lba45000RwSenseBuffer, 45000, - 2448, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.Raw, - _dev.Timeout, out _); + out byte[] lba45000RwSenseBuffer, + 45000, + 2448, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba45000RwData = lba45000RwBuffer; report.GdRomSwapDiscCapabilities.Lba45000RwSense = lba45000RwSenseBuffer; report.GdRomSwapDiscCapabilities.Lba45000RwDecodedSense = Sense.PrettifySense(lba45000RwSenseBuffer); report.GdRomSwapDiscCapabilities.Lba45000RwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba45000RwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba45000RwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000RwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000RwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); - AaruConsole.Write("Reading LBA 44990 with RW subchannel... "); + AaruConsole.Write(Localization.Core.Reading_LBA_44990_with_RW_subchannel); cluster = 16; while(true) { report.GdRomSwapDiscCapabilities.Lba44990RwReadable = !_dev.ReadCd(out byte[] lba44990RwBuffer, - out byte[] lba44990RwSenseBuffer, 44990, - 2448, cluster, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.Raw, - _dev.Timeout, out _); + out byte[] lba44990RwSenseBuffer, + 44990, + 2448, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, + out _); report.GdRomSwapDiscCapabilities.Lba44990RwData = lba44990RwBuffer; report.GdRomSwapDiscCapabilities.Lba44990RwSense = lba44990RwSenseBuffer; report.GdRomSwapDiscCapabilities.Lba44990RwDecodedSense = Sense.PrettifySense(lba44990RwSenseBuffer); report.GdRomSwapDiscCapabilities.Lba44990RwReadableCluster = (int)cluster; - if(report.GdRomSwapDiscCapabilities.Lba44990RwReadable) - break; + if(report.GdRomSwapDiscCapabilities.Lba44990RwReadable) break; - if(cluster == 1) - break; + if(cluster == 1) break; cluster /= 2; } - AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990RwReadable ? "Success!" : "FAIL!"); + AaruConsole.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990RwReadable + ? Localization.Core.Success + : Localization.Core.FAIL); if(report.GdRomSwapDiscCapabilities.Lba45000Readable == false && report.GdRomSwapDiscCapabilities.Lba50000Readable == false && @@ -1432,19 +1757,15 @@ public sealed partial class DeviceReport pressedKey = new ConsoleKeyInfo(); - while(pressedKey.Key != ConsoleKey.Y && - pressedKey.Key != ConsoleKey.N) + while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) { - AaruConsole. - Write("The next part of the test will read the whole high density area of a GD-ROM from the smallest known readable sector until the first error happens\n" + - "Do you want to proceed? (Y/N): "); + AaruConsole.Write(Localization.Core.Test_read_whole_high_density_area_proceed_Q); - pressedKey = Console.ReadKey(); + pressedKey = System.Console.ReadKey(); AaruConsole.WriteLine(); } - if(pressedKey.Key == ConsoleKey.N) - return; + if(pressedKey.Key == ConsoleKey.N) return; uint startingSector = 45000; var readAsAudio = false; @@ -1459,9 +1780,8 @@ public sealed partial class DeviceReport cluster = (uint)report.GdRomSwapDiscCapabilities.Lba45000ReadableCluster; if(report.GdRomSwapDiscCapabilities.Lba45000RwReadable) - subchannel = MmcSubchannel.Raw; - else if(report.GdRomSwapDiscCapabilities.Lba45000PqReadable) - subchannel = MmcSubchannel.Q16; + subchannel = MmcSubchannel.Raw; + else if(report.GdRomSwapDiscCapabilities.Lba45000PqReadable) subchannel = MmcSubchannel.Q16; } else if(report.GdRomSwapDiscCapabilities.Lba50000Readable == false) { @@ -1470,9 +1790,8 @@ public sealed partial class DeviceReport cluster = (uint)report.GdRomSwapDiscCapabilities.Lba50000ReadableCluster; if(report.GdRomSwapDiscCapabilities.Lba50000RwReadable) - subchannel = MmcSubchannel.Raw; - else if(report.GdRomSwapDiscCapabilities.Lba50000PqReadable) - subchannel = MmcSubchannel.Q16; + subchannel = MmcSubchannel.Raw; + else if(report.GdRomSwapDiscCapabilities.Lba50000PqReadable) subchannel = MmcSubchannel.Q16; } else if(report.GdRomSwapDiscCapabilities.Lba100000Readable == false) { @@ -1481,9 +1800,8 @@ public sealed partial class DeviceReport cluster = (uint)report.GdRomSwapDiscCapabilities.Lba100000ReadableCluster; if(report.GdRomSwapDiscCapabilities.Lba100000RwReadable) - subchannel = MmcSubchannel.Raw; - else if(report.GdRomSwapDiscCapabilities.Lba100000PqReadable) - subchannel = MmcSubchannel.Q16; + subchannel = MmcSubchannel.Raw; + else if(report.GdRomSwapDiscCapabilities.Lba100000PqReadable) subchannel = MmcSubchannel.Q16; } else if(report.GdRomSwapDiscCapabilities.Lba400000Readable == false) { @@ -1492,9 +1810,8 @@ public sealed partial class DeviceReport cluster = (uint)report.GdRomSwapDiscCapabilities.Lba400000ReadableCluster; if(report.GdRomSwapDiscCapabilities.Lba400000RwReadable) - subchannel = MmcSubchannel.Raw; - else if(report.GdRomSwapDiscCapabilities.Lba400000PqReadable) - subchannel = MmcSubchannel.Q16; + subchannel = MmcSubchannel.Raw; + else if(report.GdRomSwapDiscCapabilities.Lba400000PqReadable) subchannel = MmcSubchannel.Q16; } else if(report.GdRomSwapDiscCapabilities.Lba450000Readable == false) { @@ -1503,9 +1820,8 @@ public sealed partial class DeviceReport cluster = (uint)report.GdRomSwapDiscCapabilities.Lba450000ReadableCluster; if(report.GdRomSwapDiscCapabilities.Lba450000RwReadable) - subchannel = MmcSubchannel.Raw; - else if(report.GdRomSwapDiscCapabilities.Lba450000PqReadable) - subchannel = MmcSubchannel.Q16; + subchannel = MmcSubchannel.Raw; + else if(report.GdRomSwapDiscCapabilities.Lba450000PqReadable) subchannel = MmcSubchannel.Q16; } else if(report.GdRomSwapDiscCapabilities.Lba45000AudioReadable == false) { @@ -1514,9 +1830,8 @@ public sealed partial class DeviceReport cluster = (uint)report.GdRomSwapDiscCapabilities.Lba45000AudioReadableCluster; if(report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadable) - subchannel = MmcSubchannel.Raw; - else if(report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable) - subchannel = MmcSubchannel.Q16; + subchannel = MmcSubchannel.Raw; + else if(report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable) subchannel = MmcSubchannel.Q16; } else if(report.GdRomSwapDiscCapabilities.Lba50000AudioReadable == false) { @@ -1525,9 +1840,8 @@ public sealed partial class DeviceReport cluster = (uint)report.GdRomSwapDiscCapabilities.Lba50000AudioReadableCluster; if(report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadable) - subchannel = MmcSubchannel.Raw; - else if(report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable) - subchannel = MmcSubchannel.Q16; + subchannel = MmcSubchannel.Raw; + else if(report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable) subchannel = MmcSubchannel.Q16; } else if(report.GdRomSwapDiscCapabilities.Lba100000AudioReadable == false) { @@ -1536,9 +1850,8 @@ public sealed partial class DeviceReport cluster = (uint)report.GdRomSwapDiscCapabilities.Lba100000AudioReadableCluster; if(report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadable) - subchannel = MmcSubchannel.Raw; - else if(report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable) - subchannel = MmcSubchannel.Q16; + subchannel = MmcSubchannel.Raw; + else if(report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable) subchannel = MmcSubchannel.Q16; } else if(report.GdRomSwapDiscCapabilities.Lba400000AudioReadable == false) { @@ -1547,9 +1860,8 @@ public sealed partial class DeviceReport cluster = (uint)report.GdRomSwapDiscCapabilities.Lba400000AudioReadableCluster; if(report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadable) - subchannel = MmcSubchannel.Raw; - else if(report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable) - subchannel = MmcSubchannel.Q16; + subchannel = MmcSubchannel.Raw; + else if(report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable) subchannel = MmcSubchannel.Q16; } else if(report.GdRomSwapDiscCapabilities.Lba450000AudioReadable == false) { @@ -1558,12 +1870,11 @@ public sealed partial class DeviceReport cluster = (uint)report.GdRomSwapDiscCapabilities.Lba450000AudioReadableCluster; if(report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadable) - subchannel = MmcSubchannel.Raw; - else if(report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable) - subchannel = MmcSubchannel.Q16; + subchannel = MmcSubchannel.Raw; + else if(report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable) subchannel = MmcSubchannel.Q16; } - Console.CancelKeyPress += (_, e) => + System.Console.CancelKeyPress += (_, e) => { e.Cancel = true; aborted = true; @@ -1594,34 +1905,55 @@ public sealed partial class DeviceReport if(aborted) { AaruConsole.WriteLine(); - AaruConsole.WriteLine("Aborted!"); + AaruConsole.WriteLine(Localization.Core.Aborted); break; } - AaruConsole.Write("\rReading LBA {0} of {1}", lba, sectors); + AaruConsole.Write("\r"); + AaruConsole.Write(Localization.Core.Reading_LBA_0_of_1, lba, sectors); sense = readAsAudio - ? _dev.ReadCd(out buffer, out senseBuffer, lba, blockSize, cluster, MmcSectorTypes.Cdda, false, - false, false, MmcHeaderCodes.None, true, false, MmcErrorField.None, subchannel, - _dev.Timeout, out _) : _dev.ReadCd(out buffer, out senseBuffer, lba, blockSize, - cluster, MmcSectorTypes.AllTypes, false, false, - true, MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, subchannel, _dev.Timeout, - out _); + ? _dev.ReadCd(out buffer, + out senseBuffer, + lba, + blockSize, + cluster, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + subchannel, + _dev.Timeout, + out _) + : _dev.ReadCd(out buffer, + out senseBuffer, + lba, + blockSize, + cluster, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + subchannel, + _dev.Timeout, + out _); if(sense) { - if(trackModeChange) - break; + if(trackModeChange) break; DecodedSense? decoded = Sense.Decode(senseBuffer); - if(decoded?.ASC != 0x64) - break; - - if(decoded?.ASCQ != 0x00) - break; + if(decoded is not { ASC: 0x64, ASCQ: 0x00 }) break; trackModeChange = true; readAsAudio = !readAsAudio; diff --git a/Aaru.Core/Devices/Report/MMC.cs b/Aaru.Core/Devices/Report/MMC.cs index dc0979c80..1d15385cf 100644 --- a/Aaru.Core/Devices/Report/MMC.cs +++ b/Aaru.Core/Devices/Report/MMC.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Report; - using System; using System.Linq; using System.Text; @@ -42,7 +40,9 @@ using Aaru.Decoders.SCSI; using Aaru.Decoders.SCSI.MMC; using Aaru.Devices; using Aaru.Helpers; -using global::Spectre.Console; +using Spectre.Console; + +namespace Aaru.Core.Devices.Report; public sealed partial class DeviceReport { @@ -62,8 +62,7 @@ public sealed partial class DeviceReport continue; } - if(data.Length + offset > response.Length) - data = new byte[response.Length - offset]; + if(data.Length + offset > response.Length) data = new byte[response.Length - offset]; Array.Copy(data, 4, response, offset + 4, data.Length - 4); offset += (uint)data.Length; @@ -77,22 +76,19 @@ public sealed partial class DeviceReport public MmcFeatures ReportMmcFeatures() { var sense = true; - byte[] buffer = Array.Empty(); + byte[] buffer = []; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying MMC GET CONFIGURATION...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_MMC_GET_CONFIGURATION).IsIndeterminate(); sense = _dev.GetConfiguration(out buffer, out _, _dev.Timeout, out _); }); - if(sense) - return null; + if(sense) return null; Features.SeparatedFeatures ftr = Features.Separate(buffer); - if(ftr.Descriptors == null || - ftr.Descriptors.Length <= 0) - return null; + if(ftr.Descriptors is not { Length: > 0 }) return null; var report = new MmcFeatures { @@ -100,6 +96,7 @@ public sealed partial class DeviceReport }; foreach(Features.FeatureDescriptor desc in ftr.Descriptors) + { switch(desc.Code) { case 0x0001: @@ -151,11 +148,9 @@ public sealed partial class DeviceReport if(ftr0010.HasValue) { - if(ftr0010.Value.LogicalBlockSize > 0) - report.LogicalBlockSize = ftr0010.Value.LogicalBlockSize; + if(ftr0010.Value.LogicalBlockSize > 0) report.LogicalBlockSize = ftr0010.Value.LogicalBlockSize; - if(ftr0010.Value.Blocking > 0) - report.BlocksPerReadableUnit = ftr0010.Value.Blocking; + if(ftr0010.Value.Blocking > 0) report.BlocksPerReadableUnit = ftr0010.Value.Blocking; report.ErrorRecoveryPage = ftr0010.Value.PP; } @@ -242,8 +237,7 @@ public sealed partial class DeviceReport report.CanReadDVDPlusRW = true; Feature_002A? ftr002A = Features.Decode_002A(desc.Data); - if(ftr002A.HasValue) - report.CanWriteDVDPlusRW = ftr002A.Value.Write; + if(ftr002A.HasValue) report.CanWriteDVDPlusRW = ftr002A.Value.Write; } break; @@ -252,8 +246,7 @@ public sealed partial class DeviceReport report.CanReadDVDPlusR = true; Feature_002B? ftr002B = Features.Decode_002B(desc.Data); - if(ftr002B.HasValue) - report.CanWriteDVDPlusR = ftr002B.Value.Write; + if(ftr002B.HasValue) report.CanWriteDVDPlusR = ftr002B.Value.Write; } break; @@ -315,8 +308,7 @@ public sealed partial class DeviceReport report.CanWriteDDCDR = true; Feature_0031? ftr0031 = Features.Decode_0031(desc.Data); - if(ftr0031.HasValue) - report.CanTestWriteDDCDR = ftr0031.Value.TestWrite; + if(ftr0031.HasValue) report.CanTestWriteDDCDR = ftr0031.Value.TestWrite; } break; @@ -337,8 +329,7 @@ public sealed partial class DeviceReport report.CanReadDVDPlusRWDL = true; Feature_003A? ftr003A = Features.Decode_003A(desc.Data); - if(ftr003A.HasValue) - report.CanWriteDVDPlusRWDL = ftr003A.Value.Write; + if(ftr003A.HasValue) report.CanWriteDVDPlusRWDL = ftr003A.Value.Write; } break; @@ -347,8 +338,7 @@ public sealed partial class DeviceReport report.CanReadDVDPlusRDL = true; Feature_003B? ftr003B = Features.Decode_003B(desc.Data); - if(ftr003B.HasValue) - report.CanWriteDVDPlusRDL = ftr003B.Value.Write; + if(ftr003B.HasValue) report.CanWriteDVDPlusRDL = ftr003B.Value.Write; } break; @@ -446,8 +436,7 @@ public sealed partial class DeviceReport report.CanMuteSeparateChannels = ftr0103.Value.SCM; report.SupportsSeparateVolume = ftr0103.Value.SV; - if(ftr0103.Value.VolumeLevels > 0) - report.VolumeLevels = ftr0103.Value.VolumeLevels; + if(ftr0103.Value.VolumeLevels > 0) report.VolumeLevels = ftr0103.Value.VolumeLevels; } } @@ -461,8 +450,7 @@ public sealed partial class DeviceReport report.SupportsCSS = true; Feature_0106? ftr0106 = Features.Decode_0106(desc.Data); - if(ftr0106?.CSSVersion > 0) - report.CSSVersion = ftr0106.Value.CSSVersion; + if(ftr0106?.CSSVersion > 0) report.CSSVersion = ftr0106.Value.CSSVersion; } break; @@ -479,8 +467,7 @@ public sealed partial class DeviceReport report.SupportsCPRM = true; Feature_010B? ftr010B = Features.Decode_010B(desc.Data); - if(ftr010B?.CPRMVersion > 0) - report.CPRMVersion = ftr010B.Value.CPRMVersion; + if(ftr010B?.CPRMVersion > 0) report.CPRMVersion = ftr010B.Value.CPRMVersion; } break; @@ -519,16 +506,20 @@ public sealed partial class DeviceReport try { - report.FirmwareDate = new DateTime(int.Parse(syear), int.Parse(smonth), int.Parse(sday), - int.Parse(shour), int.Parse(sminute), int.Parse(ssecond), + report.FirmwareDate = new DateTime(int.Parse(syear), + int.Parse(smonth), + int.Parse(sday), + int.Parse(shour), + int.Parse(sminute), + int.Parse(ssecond), DateTimeKind.Utc); } - #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch { // ignored } - #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body } } @@ -546,14 +537,11 @@ public sealed partial class DeviceReport report.SupportsBusEncryption = ftr010D.Value.BEC; report.CanGenerateBindingNonce = ftr010D.Value.BNG; - if(ftr010D.Value.BindNonceBlocks > 0) - report.BindingNonceBlocks = ftr010D.Value.BindNonceBlocks; + if(ftr010D.Value.BindNonceBlocks > 0) report.BindingNonceBlocks = ftr010D.Value.BindNonceBlocks; - if(ftr010D.Value.AGIDs > 0) - report.AGIDs = ftr010D.Value.AGIDs; + if(ftr010D.Value.AGIDs > 0) report.AGIDs = ftr010D.Value.AGIDs; - if(ftr010D.Value.AACSVersion > 0) - report.AACSVersion = ftr010D.Value.AACSVersion; + if(ftr010D.Value.AACSVersion > 0) report.AACSVersion = ftr010D.Value.AACSVersion; } } @@ -575,6 +563,7 @@ public sealed partial class DeviceReport break; } + } return report; } @@ -588,38 +577,37 @@ public sealed partial class DeviceReport /// Try MediaTek vendor commands /// public TestedMedia ReportMmcMedia(string mediaType, bool tryPlextor, bool tryPioneer, bool tryNec, bool tryHldtst, - bool tryMediaTekF106) + bool tryMediaTekF106) { var sense = true; - byte[] buffer = Array.Empty(); - byte[] senseBuffer = Array.Empty(); + byte[] buffer = []; + byte[] senseBuffer = []; var mediaTest = new TestedMedia(); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI READ CAPACITY...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_READ_CAPACITY).IsIndeterminate(); sense = _dev.ReadCapacity(out buffer, out senseBuffer, _dev.Timeout, out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { mediaTest.SupportsReadCapacity = true; mediaTest.Blocks = ((ulong)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]) & - 0xFFFFFFFF) + 1; + 0xFFFFFFFF) + + 1; mediaTest.BlockSize = (uint)((buffer[5] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + buffer[7]); } Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI READ CAPACITY (16)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_READ_CAPACITY_16).IsIndeterminate(); sense = _dev.ReadCapacity16(out buffer, out buffer, _dev.Timeout, out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { mediaTest.SupportsReadCapacity16 = true; var temp = new byte[8]; @@ -633,14 +621,20 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI MODE SENSE (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_MODE_SENSE_10).IsIndeterminate(); - sense = _dev.ModeSense10(out buffer, out senseBuffer, false, true, ScsiModeSensePageControl.Current, 0x3F, - 0x00, _dev.Timeout, out _); + sense = _dev.ModeSense10(out buffer, + out senseBuffer, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + _dev.Timeout, + out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { decMode = Modes.DecodeMode10(buffer, _dev.ScsiType); @@ -649,12 +643,11 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI MODE SENSE...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_MODE_SENSE).IsIndeterminate(); sense = _dev.ModeSense(out buffer, out senseBuffer, _dev.Timeout, out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { decMode ??= Modes.DecodeMode6(buffer, _dev.ScsiType); @@ -669,85 +662,95 @@ public sealed partial class DeviceReport mediaTest.Density = (byte?)decMode?.Header.BlockDescriptors?[0].Density; } - if(mediaType.StartsWith("CD-", StringComparison.Ordinal) || + if(mediaType.StartsWith("CD-", StringComparison.Ordinal) || mediaType.StartsWith("DDCD-", StringComparison.Ordinal) || mediaType == "Audio CD") { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying CD TOC...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_CD_TOC).IsIndeterminate(); mediaTest.CanReadTOC = !_dev.ReadTocPmaAtip(out buffer, out senseBuffer, false, 0, 0, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadTOC); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadTOC); mediaTest.TocData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying CD Full TOC...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_CD_Full_TOC).IsIndeterminate(); mediaTest.CanReadFullTOC = !_dev.ReadRawToc(out buffer, out senseBuffer, 1, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadFullTOC); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadFullTOC); mediaTest.FullTocData = buffer; } - if(mediaType.StartsWith("CD-R", StringComparison.Ordinal) || + if(mediaType.StartsWith("CD-R", StringComparison.Ordinal) || mediaType.StartsWith("DDCD-R", StringComparison.Ordinal)) { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying CD ATIP...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_CD_ATIP).IsIndeterminate(); mediaTest.CanReadATIP = !_dev.ReadAtip(out buffer, out senseBuffer, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadATIP); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadATIP); mediaTest.AtipData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying CD PMA...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_CD_PMA).IsIndeterminate(); mediaTest.CanReadPMA = !_dev.ReadPma(out buffer, out senseBuffer, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPMA); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadPMA); mediaTest.PmaData = buffer; } - if(mediaType.StartsWith("DVD-", StringComparison.Ordinal) || - mediaType.StartsWith("DVD+", StringComparison.Ordinal) || + if(mediaType.StartsWith("DVD-", StringComparison.Ordinal) || + mediaType.StartsWith("DVD+", StringComparison.Ordinal) || mediaType.StartsWith("HD DVD-", StringComparison.Ordinal) || - mediaType.StartsWith("PD-", StringComparison.Ordinal)) + mediaType.StartsWith("PD-", StringComparison.Ordinal)) { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD PFI...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_PFI).IsIndeterminate(); - mediaTest.CanReadPFI = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, - _dev.Timeout, out _); + mediaTest.CanReadPFI = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPFI); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadPFI); mediaTest.PfiData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD DMI...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_DMI).IsIndeterminate(); - mediaTest.CanReadDMI = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DiscManufacturingInformation, 0, - _dev.Timeout, out _); + mediaTest.CanReadDMI = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DiscManufacturingInformation, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadDMI); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadDMI); mediaTest.DmiData = buffer; } @@ -756,15 +759,20 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD CMI...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_CMI).IsIndeterminate(); - mediaTest.CanReadCMI = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.CopyrightInformation, 0, - _dev.Timeout, out _); + mediaTest.CanReadCMI = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.CopyrightInformation, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadCMI); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadCMI); mediaTest.CmiData = buffer; } @@ -775,29 +783,39 @@ public sealed partial class DeviceReport case "HD DVD-ROM": Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD BCA...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_BCA).IsIndeterminate(); - mediaTest.CanReadBCA = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.BurstCuttingArea, 0, - _dev.Timeout, out _); + mediaTest.CanReadBCA = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.BurstCuttingArea, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadBCA); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadBCA); mediaTest.DvdBcaData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD AACS...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_AACS).IsIndeterminate(); - mediaTest.CanReadAACS = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdAacs, 0, _dev.Timeout, + mediaTest.CanReadAACS = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdAacs, + 0, + _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadAACS); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadAACS); mediaTest.DvdAacsData = buffer; @@ -806,43 +824,58 @@ public sealed partial class DeviceReport case "Nintendo Wii game": Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD BCA...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_BCA).IsIndeterminate(); - mediaTest.CanReadBCA = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.BurstCuttingArea, 0, - _dev.Timeout, out _); + mediaTest.CanReadBCA = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.BurstCuttingArea, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadBCA); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadBCA); mediaTest.DvdBcaData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD PFI...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_PFI).IsIndeterminate(); - mediaTest.CanReadPFI = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, - _dev.Timeout, out _); + mediaTest.CanReadPFI = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPFI); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadPFI); mediaTest.PfiData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD DMI...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_DMI).IsIndeterminate(); - mediaTest.CanReadDMI = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, + mediaTest.CanReadDMI = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, MmcDiscStructureFormat.DiscManufacturingInformation, - 0, _dev.Timeout, out _); + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadDMI); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadDMI); mediaTest.DmiData = buffer; @@ -856,15 +889,20 @@ public sealed partial class DeviceReport case "Nintendo Wii U game": Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying BD BCA...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_BD_BCA).IsIndeterminate(); - mediaTest.CanReadBCA = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.BdBurstCuttingArea, 0, - _dev.Timeout, out _); + mediaTest.CanReadBCA = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.BdBurstCuttingArea, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadBCA); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadBCA); mediaTest.BluBcaData = buffer; @@ -875,61 +913,88 @@ public sealed partial class DeviceReport case "PD-650": Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying Disc Definition Structure...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_Disc_Definition_Structure).IsIndeterminate(); - mediaTest.CanReadDDS = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdramDds, 0, _dev.Timeout, + mediaTest.CanReadDDS = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdramDds, + 0, + _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadDDS); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadDDS); mediaTest.DvdDdsData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying Spare Area Information...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_Spare_Area_Information).IsIndeterminate(); mediaTest.CanReadSpareAreaInformation = - !_dev.ReadDiscStructure(out buffer, out senseBuffer, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdramSpareAreaInformation, 0, _dev.Timeout, + !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdramSpareAreaInformation, + 0, + _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadSpareAreaInformation); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadSpareAreaInformation); mediaTest.DvdSaiData = buffer; break; } - if(mediaType.StartsWith("BD-R", StringComparison.Ordinal) && - mediaType != "BD-ROM") + if(mediaType.StartsWith("BD-R", StringComparison.Ordinal) && mediaType != "BD-ROM") { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying BD DDS...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_BD_DDS).IsIndeterminate(); - mediaTest.CanReadDDS = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.BdDds, 0, _dev.Timeout, out _); + mediaTest.CanReadDDS = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.BdDds, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadDDS); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadDDS); mediaTest.BluDdsData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying BD SAI...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_BD_SAI).IsIndeterminate(); mediaTest.CanReadSpareAreaInformation = - !_dev.ReadDiscStructure(out buffer, out senseBuffer, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.BdSpareAreaInformation, 0, _dev.Timeout, out _); + !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.BdSpareAreaInformation, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadSpareAreaInformation); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadSpareAreaInformation); mediaTest.BluSaiData = buffer; } @@ -938,15 +1003,20 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD PRI...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_PRI).IsIndeterminate(); - mediaTest.CanReadPRI = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PreRecordedInfo, 0, _dev.Timeout, + mediaTest.CanReadPRI = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PreRecordedInfo, + 0, + _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPRI); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadPRI); mediaTest.PriData = buffer; } @@ -955,57 +1025,80 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD Media ID...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_Media_ID).IsIndeterminate(); - mediaTest.CanReadMediaID = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdrMediaIdentifier, 0, - _dev.Timeout, out _); + mediaTest.CanReadMediaID = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdrMediaIdentifier, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadMediaID); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadMediaID); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD Embossed PFI...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_Embossed_PFI).IsIndeterminate(); - mediaTest.CanReadRecordablePFI = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, + mediaTest.CanReadRecordablePFI = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, MmcDiscStructureFormat.DvdrPhysicalInformation, - 0, _dev.Timeout, out _); + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadRecordablePFI); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadRecordablePFI); mediaTest.EmbossedPfiData = buffer; } - if(mediaType.StartsWith("DVD+R", StringComparison.Ordinal) || - mediaType == "DVD+MRW") + if(mediaType.StartsWith("DVD+R", StringComparison.Ordinal) || mediaType == "DVD+MRW") { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD ADIP...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_ADIP).IsIndeterminate(); - mediaTest.CanReadADIP = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.Adip, 0, _dev.Timeout, out _); + mediaTest.CanReadADIP = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.Adip, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadADIP); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadADIP); mediaTest.AdipData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD DCB...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_DCB).IsIndeterminate(); - mediaTest.CanReadDCB = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.Dcb, 0, _dev.Timeout, out _); + mediaTest.CanReadDCB = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.Dcb, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadDCB); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadDCB); mediaTest.DcbData = buffer; } @@ -1014,15 +1107,20 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying HD DVD CMI...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_HD_DVD_CMI).IsIndeterminate(); - mediaTest.CanReadHDCMI = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.HddvdCopyrightInformation, 0, - _dev.Timeout, out _); + mediaTest.CanReadHDCMI = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.HddvdCopyrightInformation, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadHDCMI); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadHDCMI); mediaTest.HdCmiData = buffer; } @@ -1031,47 +1129,71 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying DVD Layer Capacity...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_DVD_Layer_Capacity).IsIndeterminate(); - mediaTest.CanReadLayerCapacity = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdrLayerCapacity, 0, - _dev.Timeout, out _); + mediaTest.CanReadLayerCapacity = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdrLayerCapacity, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadLayerCapacity); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadLayerCapacity); mediaTest.DvdLayerData = buffer; } if(mediaType.StartsWith("BD-R", StringComparison.Ordinal) || - mediaType is "Ultra HD Blu-ray movie" or "PlayStation 3 game" or "PlayStation 4 game" or "PlayStation 5 game" - or "Xbox One game" or "Nintendo Wii game") + mediaType is "Ultra HD Blu-ray movie" + or "PlayStation 3 game" + or "PlayStation 4 game" + or "PlayStation 5 game" + or "Xbox One game" + or "Nintendo Wii game") { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying BD Disc Information...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_BD_Disc_Information).IsIndeterminate(); - mediaTest.CanReadDiscInformation = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.DiscInformation, 0, - _dev.Timeout, out _); + mediaTest.CanReadDiscInformation = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.DiscInformation, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadDiscInformation); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadDiscInformation); mediaTest.BluDiData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying BD PAC...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_BD_PAC).IsIndeterminate(); - mediaTest.CanReadPAC = !_dev.ReadDiscStructure(out buffer, out senseBuffer, - MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.Pac, 0, _dev.Timeout, out _); + mediaTest.CanReadPAC = !_dev.ReadDiscStructure(out buffer, + out senseBuffer, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.Pac, + 0, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPAC); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadPAC); mediaTest.BluPacData = buffer; } @@ -1080,12 +1202,24 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ CD scrambled...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_CD_scrambled).IsIndeterminate(); - mediaTest.CanReadCdScrambled = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2352, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); + mediaTest.CanReadCdScrambled = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2352, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); }); mediaTest.ReadCdScrambledData = buffer; @@ -1095,47 +1229,81 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (6)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_6).IsIndeterminate(); mediaTest.SupportsRead6 = !_dev.Read6(out buffer, out senseBuffer, 16, 512, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead6); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead6); mediaTest.Read6Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_10).IsIndeterminate(); - mediaTest.SupportsRead10 = !_dev.Read10(out buffer, out senseBuffer, 0, false, true, false, false, 16, - 512, 0, 1, _dev.Timeout, out _); + mediaTest.SupportsRead10 = !_dev.Read10(out buffer, + out senseBuffer, + 0, + false, + true, + false, + false, + 16, + 512, + 0, + 1, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead10); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead10); mediaTest.Read10Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (12)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_12).IsIndeterminate(); - mediaTest.SupportsRead12 = !_dev.Read12(out buffer, out senseBuffer, 0, false, true, false, false, 16, - 512, 0, 1, false, _dev.Timeout, out _); + mediaTest.SupportsRead12 = !_dev.Read12(out buffer, + out senseBuffer, + 0, + false, + true, + false, + false, + 16, + 512, + 0, + 1, + false, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead12); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead12); mediaTest.Read12Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (16)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_16).IsIndeterminate(); - mediaTest.SupportsRead16 = !_dev.Read16(out buffer, out senseBuffer, 0, false, true, false, 16, 512, 0, - 1, false, _dev.Timeout, out _); + mediaTest.SupportsRead16 = !_dev.Read16(out buffer, + out senseBuffer, + 0, + false, + true, + false, + 16, + 512, + 0, + 1, + false, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead16); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead16); mediaTest.Read16Data = buffer; } @@ -1143,52 +1311,86 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (6)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_6).IsIndeterminate(); mediaTest.SupportsRead6 = !_dev.Read6(out buffer, out senseBuffer, 16, 2048, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead6); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead6); mediaTest.Read6Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_10).IsIndeterminate(); - mediaTest.SupportsRead10 = !_dev.Read10(out buffer, out senseBuffer, 0, false, true, false, false, 16, - 2048, 0, 1, _dev.Timeout, out _); + mediaTest.SupportsRead10 = !_dev.Read10(out buffer, + out senseBuffer, + 0, + false, + true, + false, + false, + 16, + 2048, + 0, + 1, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead10); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead10); mediaTest.Read10Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (12)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_12).IsIndeterminate(); - mediaTest.SupportsRead12 = !_dev.Read12(out buffer, out senseBuffer, 0, false, true, false, false, 16, - 2048, 0, 1, false, _dev.Timeout, out _); + mediaTest.SupportsRead12 = !_dev.Read12(out buffer, + out senseBuffer, + 0, + false, + true, + false, + false, + 16, + 2048, + 0, + 1, + false, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead12); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead12); mediaTest.Read12Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (16)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_16).IsIndeterminate(); - mediaTest.SupportsRead16 = !_dev.Read16(out buffer, out senseBuffer, 0, false, true, false, 16, 2048, 0, - 1, false, _dev.Timeout, out _); + mediaTest.SupportsRead16 = !_dev.Read16(out buffer, + out senseBuffer, + 0, + false, + true, + false, + 16, + 2048, + 0, + 1, + false, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead16); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead16); mediaTest.Read16Data = buffer; } - if(mediaType.StartsWith("CD-", StringComparison.Ordinal) || + if(mediaType.StartsWith("CD-", StringComparison.Ordinal) || mediaType.StartsWith("DDCD-", StringComparison.Ordinal) || mediaType == "Audio CD") { @@ -1196,29 +1398,56 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ CD...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_CD).IsIndeterminate(); - mediaTest.SupportsReadCd = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2352, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); + mediaTest.SupportsReadCd = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2352, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsReadCd); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsReadCd); mediaTest.ReadCdFullData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ CD MSF...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_CD_MSF).IsIndeterminate(); - mediaTest.SupportsReadCdMsf = !_dev.ReadCdMsf(out buffer, out senseBuffer, 0x00000210, 0x00000211, - 2352, MmcSectorTypes.Cdda, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); + mediaTest.SupportsReadCdMsf = !_dev.ReadCdMsf(out buffer, + out senseBuffer, + 0x00000210, + 0x00000211, + 2352, + MmcSectorTypes.Cdda, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsReadCdMsf); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsReadCdMsf); mediaTest.ReadCdMsfFullData = buffer; } @@ -1226,90 +1455,170 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ CD...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_CD).IsIndeterminate(); - mediaTest.SupportsReadCd = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2048, 1, - MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); + mediaTest.SupportsReadCd = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2048, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsReadCd); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsReadCd); mediaTest.ReadCdData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ CD MSF...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_CD_MSF).IsIndeterminate(); - mediaTest.SupportsReadCdMsf = !_dev.ReadCdMsf(out buffer, out senseBuffer, 0x00000210, 0x00000211, - 2048, MmcSectorTypes.AllTypes, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); + mediaTest.SupportsReadCdMsf = !_dev.ReadCdMsf(out buffer, + out senseBuffer, + 0x00000210, + 0x00000211, + 2048, + MmcSectorTypes.AllTypes, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsReadCdMsf); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsReadCdMsf); mediaTest.ReadCdMsfData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ CD full sector...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_CD_full_sector).IsIndeterminate(); - mediaTest.SupportsReadCdRaw = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2352, 1, - MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, _dev.Timeout, + mediaTest.SupportsReadCdRaw = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsReadCdRaw); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsReadCdRaw); mediaTest.ReadCdFullData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ CD MSF full sector...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_CD_MSF_full_sector).IsIndeterminate(); - mediaTest.SupportsReadCdMsfRaw = !_dev.ReadCdMsf(out buffer, out senseBuffer, 0x00000210, - 0x00000211, 2352, MmcSectorTypes.AllTypes, false, - false, MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + mediaTest.SupportsReadCdMsfRaw = !_dev.ReadCdMsf(out buffer, + out senseBuffer, + 0x00000210, + 0x00000211, + 2352, + MmcSectorTypes.AllTypes, + false, + false, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsReadCdMsfRaw); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsReadCdMsfRaw); mediaTest.ReadCdMsfFullData = buffer; } - if(mediaTest.SupportsReadCdRaw == true || - mediaType == "Audio CD") + if(mediaTest.SupportsReadCdRaw == true || mediaType == "Audio CD") { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read CD Track 1 pre-gap...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_read_CD_Track_1_pre_gap).IsIndeterminate(); for(int i = -10; i < 0; i++) { // ReSharper disable IntVariableOverflowInUncheckedContext if(mediaType == "Audio CD") - sense = _dev.ReadCd(out buffer, out senseBuffer, (uint)i, 2352, 1, MmcSectorTypes.Cdda, - false, false, false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.None, _dev.Timeout, out _); + { + sense = _dev.ReadCd(out buffer, + out senseBuffer, + (uint)i, + 2352, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); + } else - sense = _dev.ReadCd(out buffer, out senseBuffer, (uint)i, 2352, 1, MmcSectorTypes.AllTypes, - false, false, true, MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, _dev.Timeout, out _); + { + sense = _dev.ReadCd(out buffer, + out senseBuffer, + (uint)i, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); + } // ReSharper restore IntVariableOverflowInUncheckedContext - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", sense); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, sense); mediaTest.Track1PregapData = buffer; - if(sense) - continue; + if(sense) continue; mediaTest.CanReadFirstTrackPreGap = true; @@ -1321,7 +1630,7 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read CD Lead-In...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_read_CD_Lead_In).IsIndeterminate(); foreach(int i in new[] { @@ -1329,20 +1638,49 @@ public sealed partial class DeviceReport }) { if(mediaType == "Audio CD") - sense = _dev.ReadCd(out buffer, out senseBuffer, (uint)i, 2352, 1, MmcSectorTypes.Cdda, - false, false, false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.None, _dev.Timeout, out _); + { + sense = _dev.ReadCd(out buffer, + out senseBuffer, + (uint)i, + 2352, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); + } else - sense = _dev.ReadCd(out buffer, out senseBuffer, (uint)i, 2352, 1, MmcSectorTypes.AllTypes, - false, false, true, MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, _dev.Timeout, out _); + { + sense = _dev.ReadCd(out buffer, + out senseBuffer, + (uint)i, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", sense); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, sense); mediaTest.LeadInData = buffer; - if(sense) - continue; + if(sense) continue; mediaTest.CanReadLeadIn = true; @@ -1354,24 +1692,51 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read CD Lead-Out...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_read_CD_Lead_Out).IsIndeterminate(); if(mediaType == "Audio CD") - mediaTest.CanReadLeadOut = !_dev.ReadCd(out buffer, out senseBuffer, - (uint)(mediaTest.Blocks + 1), 2352, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); - else - mediaTest.CanReadLeadOut = !_dev.ReadCd(out buffer, out senseBuffer, - (uint)(mediaTest.Blocks + 1), 2352, 1, - MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, _dev.Timeout, + { + mediaTest.CanReadLeadOut = !_dev.ReadCd(out buffer, + out senseBuffer, + (uint)((mediaTest.Blocks ?? 0) + 1), + 2352, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, out _); + } + else + { + mediaTest.CanReadLeadOut = !_dev.ReadCd(out buffer, + out senseBuffer, + (uint)((mediaTest.Blocks ?? 0) + 1), + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); + } }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadLeadOut); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadLeadOut); mediaTest.LeadOutData = buffer; } @@ -1380,28 +1745,53 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read C2 Pointers...").IsIndeterminate(); - mediaTest.CanReadPMA = !_dev.ReadPma(out buffer, out senseBuffer, _dev.Timeout, out _); + ctx.AddTask(Localization.Core.Trying_to_read_C2_Pointers).IsIndeterminate(); // They return OK, but then all following commands make the drive fail miserably. if(_dev.Model.StartsWith("iHOS104", StringComparison.Ordinal)) mediaTest.CanReadC2Pointers = false; else { - mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, out senseBuffer, 11, 2646, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.C2Pointers, MmcSubchannel.None, - _dev.Timeout, out _); + mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2646, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.C2Pointers, + MmcSubchannel.None, + _dev.Timeout, + out _); if(!mediaTest.CanReadC2Pointers == true) - mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, out senseBuffer, 11, 2648, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, + { + mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2648, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.None, _dev.Timeout, out _); + MmcSubchannel.None, + _dev.Timeout, + out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadC2Pointers); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadC2Pointers); mediaTest.C2PointersData = buffer; } @@ -1409,41 +1799,87 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read subchannels...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_read_subchannels).IsIndeterminate(); - mediaTest.CanReadPQSubchannel = !_dev.ReadCd(out buffer, out senseBuffer, 11, 2368, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.Q16, _dev.Timeout, out _); + mediaTest.CanReadPQSubchannel = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2368, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, + out _); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPQSubchannel); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadPQSubchannel); mediaTest.PQSubchannelData = buffer; - mediaTest.CanReadRWSubchannel = !_dev.ReadCd(out buffer, out senseBuffer, 11, 2448, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.Raw, _dev.Timeout, out _); + mediaTest.CanReadRWSubchannel = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2448, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, + out _); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadRWSubchannel); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadRWSubchannel); mediaTest.RWSubchannelData = buffer; - mediaTest.CanReadCorrectedSubchannel = !_dev.ReadCd(out buffer, out senseBuffer, 11, 2448, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.Rw, - _dev.Timeout, out _); + // AccessTek/Optorite DD0203 returns OK but then the firmware dies + if(_dev.Model.StartsWith("DVD RW 4XMax", StringComparison.Ordinal)) + mediaTest.CanReadCorrectedSubchannel = false; + else + { + mediaTest.CanReadCorrectedSubchannel = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2448, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Rw, + _dev.Timeout, + out _); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadCorrectedSubchannel); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadCorrectedSubchannel); - mediaTest.CorrectedSubchannelData = buffer; + mediaTest.CorrectedSubchannelData = buffer; + } }); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read subchannels with C2 Pointers...").IsIndeterminate(); - mediaTest.CanReadPMA = !_dev.ReadPma(out buffer, out senseBuffer, _dev.Timeout, out _); + ctx.AddTask(Localization.Core.Trying_to_read_subchannels_with_C2_Pointers).IsIndeterminate(); // They return OK, but then all following commands make the drive fail miserably. if(_dev.Model.StartsWith("iHOS104", StringComparison.Ordinal)) @@ -1454,56 +1890,131 @@ public sealed partial class DeviceReport } else { - mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 11, 2662, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.C2Pointers, MmcSubchannel.Q16, - _dev.Timeout, out _); + mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2662, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.C2Pointers, + MmcSubchannel.Q16, + _dev.Timeout, + out _); if(mediaTest.CanReadPQSubchannelWithC2 == false) - mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 11, 2664, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, + { + mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2664, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.Q16, _dev.Timeout, out _); + MmcSubchannel.Q16, + _dev.Timeout, + out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPQSubchannelWithC2); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadPQSubchannelWithC2); mediaTest.PQSubchannelWithC2Data = buffer; - mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 11, 2712, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.C2Pointers, MmcSubchannel.Raw, - _dev.Timeout, out _); + mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2712, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.C2Pointers, + MmcSubchannel.Raw, + _dev.Timeout, + out _); if(mediaTest.CanReadRWSubchannelWithC2 == false) - mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 11, 2714, 1, - MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, + { + mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2714, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.Raw, _dev.Timeout, out _); + MmcSubchannel.Raw, + _dev.Timeout, + out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadRWSubchannelWithC2); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadRWSubchannelWithC2); mediaTest.RWSubchannelWithC2Data = buffer; - mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 11, 2712, - 1, MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, false, + mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2712, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, MmcErrorField.C2Pointers, - MmcSubchannel.Rw, _dev.Timeout, out _); + MmcSubchannel.Rw, + _dev.Timeout, + out _); if(mediaTest.CanReadCorrectedSubchannelWithC2 == false) - mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 11, - 2714, 1, MmcSectorTypes.Cdda, false, - false, false, MmcHeaderCodes.None, - true, false, + { + mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 11, + 2714, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.Rw, _dev.Timeout, + MmcSubchannel.Rw, + _dev.Timeout, out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, !mediaTest.CanReadCorrectedSubchannelWithC2); mediaTest.CorrectedSubchannelWithC2Data = buffer; @@ -1514,27 +2025,53 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read C2 Pointers...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_read_C2_Pointers).IsIndeterminate(); // They return OK, but then all following commands make the drive fail miserably. if(_dev.Model.StartsWith("iHOS104", StringComparison.Ordinal)) mediaTest.CanReadC2Pointers = false; else { - mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2646, 1, - MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.C2Pointers, MmcSubchannel.None, - _dev.Timeout, out _); + mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2646, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.C2Pointers, + MmcSubchannel.None, + _dev.Timeout, + out _); if(mediaTest.CanReadC2Pointers == false) - mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2648, 1, - MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, + { + mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2648, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.None, _dev.Timeout, out _); + MmcSubchannel.None, + _dev.Timeout, + out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadC2Pointers); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadC2Pointers); mediaTest.C2PointersData = buffer; } @@ -1542,42 +2079,87 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read subchannels...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_read_subchannels).IsIndeterminate(); - mediaTest.CanReadPQSubchannel = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2368, 1, - MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.Q16, _dev.Timeout, + mediaTest.CanReadPQSubchannel = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2368, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, out _); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPQSubchannel); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadPQSubchannel); mediaTest.PQSubchannelData = buffer; - mediaTest.CanReadRWSubchannel = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2448, 1, - MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.Raw, _dev.Timeout, + mediaTest.CanReadRWSubchannel = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2448, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, out _); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadRWSubchannel); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadRWSubchannel); mediaTest.RWSubchannelData = buffer; - mediaTest.CanReadCorrectedSubchannel = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2448, 1, - MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.Rw, - _dev.Timeout, out _); + // AccessTek/Optorite DD0203 returns OK but then the firmware dies + if(_dev.Model.StartsWith("DVD RW 4XMax", StringComparison.Ordinal)) + mediaTest.CanReadCorrectedSubchannel = false; + else + { + mediaTest.CanReadCorrectedSubchannel = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2448, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.Rw, + _dev.Timeout, + out _); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadCorrectedSubchannel); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadCorrectedSubchannel); - mediaTest.CorrectedSubchannelData = buffer; + mediaTest.CorrectedSubchannelData = buffer; + } }); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read subchannels with C2 Pointers...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_read_subchannels_with_C2_Pointers).IsIndeterminate(); if(_dev.Model.StartsWith("iHOS104", StringComparison.Ordinal)) { @@ -1587,59 +2169,140 @@ public sealed partial class DeviceReport } else { - mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2662, 1, - MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.C2Pointers, MmcSubchannel.Q16, - _dev.Timeout, out _); + mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2662, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.C2Pointers, + MmcSubchannel.Q16, + _dev.Timeout, + out _); if(mediaTest.CanReadPQSubchannelWithC2 == false) - mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2664, 1, - MmcSectorTypes.AllTypes, false, false, - true, MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.Q16, _dev.Timeout, out _); + { + mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2664, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.C2PointersAndBlock, + MmcSubchannel.Q16, + _dev.Timeout, + out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPQSubchannelWithC2); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadPQSubchannelWithC2); mediaTest.PQSubchannelWithC2Data = buffer; - mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2712, 1, - MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.C2Pointers, MmcSubchannel.Raw, - _dev.Timeout, out _); + mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2712, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.C2Pointers, + MmcSubchannel.Raw, + _dev.Timeout, + out _); if(mediaTest.CanReadRWSubchannelWithC2 == false) - mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2714, 1, - MmcSectorTypes.AllTypes, false, false, - true, MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.Raw, _dev.Timeout, out _); + { + mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2714, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.C2PointersAndBlock, + MmcSubchannel.Raw, + _dev.Timeout, + out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadRWSubchannelWithC2); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadRWSubchannelWithC2); mediaTest.RWSubchannelWithC2Data = buffer; - mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2712, - 1, MmcSectorTypes.AllTypes, false, false, - true, MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.C2Pointers, - MmcSubchannel.Rw, _dev.Timeout, out _); + mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2712, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.C2Pointers, + MmcSubchannel.Rw, + _dev.Timeout, + out _); - if(mediaTest.CanReadCorrectedSubchannelWithC2 == false) - mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, - 2714, 1, MmcSectorTypes.AllTypes, - false, false, true, - MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.C2PointersAndBlock, - MmcSubchannel.Rw, _dev.Timeout, - out _); + // AccessTek/Optorite DD0203 returns OK but then the firmware dies + if(_dev.Model.StartsWith("DVD RW 4XMax", StringComparison.Ordinal)) + mediaTest.CanReadCorrectedSubchannel = false; + else + { + if(mediaTest.CanReadCorrectedSubchannelWithC2 == false) + { + mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2714, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.C2PointersAndBlock, + MmcSubchannel.Rw, + _dev.Timeout, + out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", - !mediaTest.CanReadCorrectedSubchannelWithC2); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadCorrectedSubchannelWithC2); - mediaTest.CorrectedSubchannelWithC2Data = buffer; + mediaTest.CorrectedSubchannelWithC2Data = buffer; + } } }); } @@ -1651,64 +2314,136 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read C2 Pointers...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_read_C2_Pointers).IsIndeterminate(); - mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2342, 1, - MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.C2Pointers, MmcSubchannel.None, - _dev.Timeout, out _); + mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2342, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.C2Pointers, + MmcSubchannel.None, + _dev.Timeout, + out _); if(mediaTest.CanReadC2Pointers == false) - mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2344, 1, - MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, true, false, + { + mediaTest.CanReadC2Pointers = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2344, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.None, _dev.Timeout, out _); + MmcSubchannel.None, + _dev.Timeout, + out _); + } }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadC2Pointers); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadC2Pointers); mediaTest.C2PointersData = buffer; } Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read subchannels...").IsIndeterminate(); - mediaTest.CanReadPMA = !_dev.ReadPma(out buffer, out senseBuffer, _dev.Timeout, out _); + ctx.AddTask(Localization.Core.Trying_to_read_subchannels).IsIndeterminate(); - mediaTest.CanReadPQSubchannel = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2064, 1, - MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.Q16, _dev.Timeout, out _); + mediaTest.CanReadPQSubchannel = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2064, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, + out _); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPQSubchannel); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadPQSubchannel); mediaTest.PQSubchannelData = buffer; - mediaTest.CanReadRWSubchannel = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2144, 1, - MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.Raw, _dev.Timeout, out _); + mediaTest.CanReadRWSubchannel = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2144, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, + out _); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadRWSubchannel); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadRWSubchannel); mediaTest.RWSubchannelData = buffer; - mediaTest.CanReadCorrectedSubchannel = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2144, 1, - MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.Rw, - _dev.Timeout, out _); + // AccessTek/Optorite DD0203 returns OK but then the firmware dies + if(_dev.Model.StartsWith("DVD RW 4XMax", StringComparison.Ordinal)) + mediaTest.CanReadCorrectedSubchannel = false; + else + { + mediaTest.CanReadCorrectedSubchannel = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2144, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.Rw, + _dev.Timeout, + out _); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadCorrectedSubchannel); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadCorrectedSubchannel); - mediaTest.CorrectedSubchannelData = buffer; + mediaTest.CorrectedSubchannelData = buffer; + } }); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to read subchannels with C2 Pointers...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_read_subchannels_with_C2_Pointers).IsIndeterminate(); if(_dev.Model.StartsWith("iHOS104", StringComparison.Ordinal)) { @@ -1718,56 +2453,131 @@ public sealed partial class DeviceReport } else { - mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2358, 1, - MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.C2Pointers, MmcSubchannel.Q16, - _dev.Timeout, out _); + mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2358, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.C2Pointers, + MmcSubchannel.Q16, + _dev.Timeout, + out _); if(mediaTest.CanReadPQSubchannelWithC2 == false) - mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2360, 1, - MmcSectorTypes.AllTypes, false, false, - false, MmcHeaderCodes.None, true, false, + { + mediaTest.CanReadPQSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2360, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.Q16, _dev.Timeout, out _); + MmcSubchannel.Q16, + _dev.Timeout, + out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadPQSubchannelWithC2); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadPQSubchannelWithC2); mediaTest.PQSubchannelWithC2Data = buffer; - mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2438, 1, - MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, true, false, - MmcErrorField.C2Pointers, MmcSubchannel.Raw, - _dev.Timeout, out _); + mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2438, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.C2Pointers, + MmcSubchannel.Raw, + _dev.Timeout, + out _); if(mediaTest.CanReadRWSubchannelWithC2 == false) - mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2440, 1, - MmcSectorTypes.AllTypes, false, false, - false, MmcHeaderCodes.None, true, false, + { + mediaTest.CanReadRWSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2440, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.Raw, _dev.Timeout, out _); + MmcSubchannel.Raw, + _dev.Timeout, + out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadRWSubchannelWithC2); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadRWSubchannelWithC2); mediaTest.RWSubchannelWithC2Data = buffer; - mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, 2438, - 1, MmcSectorTypes.AllTypes, false, false, - false, MmcHeaderCodes.None, true, false, + mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2438, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, MmcErrorField.C2Pointers, - MmcSubchannel.Rw, _dev.Timeout, out _); + MmcSubchannel.Rw, + _dev.Timeout, + out _); if(mediaTest.CanReadCorrectedSubchannelWithC2 == false) - mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, out senseBuffer, 16, - 2440, 1, MmcSectorTypes.AllTypes, - false, false, false, - MmcHeaderCodes.None, true, false, + { + mediaTest.CanReadCorrectedSubchannelWithC2 = !_dev.ReadCd(out buffer, + out senseBuffer, + 16, + 2440, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, MmcErrorField.C2PointersAndBlock, - MmcSubchannel.Rw, _dev.Timeout, + MmcSubchannel.Rw, + _dev.Timeout, out _); + } - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, !mediaTest.CanReadCorrectedSubchannelWithC2); mediaTest.CorrectedSubchannelWithC2Data = buffer; @@ -1779,14 +2589,22 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying Plextor READ CD-DA...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Plextor_READ_CD_DA).IsIndeterminate(); mediaTest.SupportsPlextorReadCDDA = - !_dev.PlextorReadCdDa(out buffer, out senseBuffer, 16, 2352, 1, PlextorSubchannel.None, - _dev.Timeout, out _); + !_dev.PlextorReadCdDa(out buffer, + out senseBuffer, + 16, + 2352, + 1, + PlextorSubchannel.None, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsPlextorReadCDDA); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsPlextorReadCDDA); mediaTest.PlextorReadCddaData = buffer; } @@ -1795,27 +2613,43 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying Pioneer READ CD-DA...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_Pioneer_READ_CD_DA).IsIndeterminate(); mediaTest.SupportsPioneerReadCDDA = - !_dev.PioneerReadCdDa(out buffer, out senseBuffer, 16, 2352, 1, PioneerSubchannel.None, - _dev.Timeout, out _); + !_dev.PioneerReadCdDa(out buffer, + out senseBuffer, + 16, + 2352, + 1, + PioneerSubchannel.None, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsPioneerReadCDDA); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsPioneerReadCDDA); mediaTest.PioneerReadCddaData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying Pioneer READ CD-DA MSF...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_Pioneer_READ_CD_DA_MSF).IsIndeterminate(); mediaTest.SupportsPioneerReadCDDAMSF = - !_dev.PioneerReadCdDaMsf(out buffer, out senseBuffer, 0x00000210, 0x00000211, 2352, - PioneerSubchannel.None, _dev.Timeout, out _); + !_dev.PioneerReadCdDaMsf(out buffer, + out senseBuffer, + 0x00000210, + 0x00000211, + 2352, + PioneerSubchannel.None, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsPioneerReadCDDAMSF); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsPioneerReadCDDAMSF); mediaTest.PioneerReadCddaMsfData = buffer; } @@ -1824,13 +2658,15 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying NEC READ CD-DA...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_NEC_READ_CD_DA).IsIndeterminate(); mediaTest.SupportsNECReadCDDA = !_dev.NecReadCdDa(out buffer, out senseBuffer, 16, 1, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsNECReadCDDA); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsNECReadCDDA); mediaTest.NecReadCddaData = buffer; } @@ -1840,7 +2676,7 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ LONG (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_LONG_10).IsIndeterminate(); sense = _dev.ReadLong10(out buffer, out senseBuffer, false, false, 16, 0xFFFF, _dev.Timeout, out _); }); @@ -1848,9 +2684,7 @@ public sealed partial class DeviceReport { DecodedSense? decSense = Sense.Decode(senseBuffer); - if(decSense?.SenseKey == SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && - decSense.Value.ASCQ == 0x00) + if(decSense is { SenseKey: SenseKeys.IllegalRequest, ASC: 0x24, ASCQ: 0x00 }) { mediaTest.SupportsReadLong = true; @@ -1866,19 +2700,16 @@ public sealed partial class DeviceReport information = (uint)Sense.DecodeDescriptor00(desc00); } - if(valid && ili) - mediaTest.LongBlockSize = 0xFFFF - (information & 0xFFFF); + if(valid && ili) mediaTest.LongBlockSize = 0xFFFF - (information & 0xFFFF); } } - if(mediaTest.SupportsReadLong == true && - mediaTest.LongBlockSize == mediaTest.BlockSize) + if(mediaTest.SupportsReadLong == true && mediaTest.LongBlockSize == mediaTest.BlockSize) { // DVDs sense = _dev.ReadLong10(out buffer, out senseBuffer, false, false, 16, 37856, _dev.Timeout, out _); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { mediaTest.ReadLong10Data = buffer; mediaTest.SupportsReadLong = true; @@ -1890,38 +2721,40 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying Plextor trick to raw read DVDs...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_Plextor_trick_to_raw_read_DVDs).IsIndeterminate(); mediaTest.SupportsPlextorReadRawDVD = !_dev.PlextorReadRawDvd(out buffer, out senseBuffer, 16, 1, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsPlextorReadRawDVD); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsPlextorReadRawDVD); if(mediaTest.SupportsPlextorReadRawDVD == true) mediaTest.SupportsPlextorReadRawDVD = !ArrayHelpers.ArrayIsNullOrEmpty(buffer); - if(mediaTest.SupportsPlextorReadRawDVD == true) - mediaTest.PlextorReadRawDVDData = buffer; + if(mediaTest.SupportsPlextorReadRawDVD == true) mediaTest.PlextorReadRawDVDData = buffer; } if(tryHldtst) { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying HL-DT-ST (aka LG) trick to raw read DVDs...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_HL_DT_ST_aka_LG_trick_to_raw_read_DVDs).IsIndeterminate(); mediaTest.SupportsHLDTSTReadRawDVD = !_dev.HlDtStReadRawDvd(out buffer, out senseBuffer, 16, 1, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsHLDTSTReadRawDVD); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.SupportsHLDTSTReadRawDVD); if(mediaTest.SupportsHLDTSTReadRawDVD == true) mediaTest.SupportsHLDTSTReadRawDVD = !ArrayHelpers.ArrayIsNullOrEmpty(buffer); - if(mediaTest.SupportsHLDTSTReadRawDVD == true) - mediaTest.HLDTSTReadRawDVDData = buffer; + if(mediaTest.SupportsHLDTSTReadRawDVD == true) mediaTest.HLDTSTReadRawDVDData = buffer; } if(tryMediaTekF106) @@ -1931,13 +2764,26 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying MediaTek READ DRAM command...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_MediaTek_READ_DRAM_command).IsIndeterminate(); - if(mediaType == "Audio CD" && - mediaTest.SupportsReadCd == true) + if(mediaType == "Audio CD" && mediaTest.SupportsReadCd == true) { - _dev.ReadCd(out _, out _, 0, 2352, 1, MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, - true, false, MmcErrorField.None, MmcSubchannel.None, _dev.Timeout, out _); + _dev.ReadCd(out _, + out _, + 0, + 2352, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); triedLba0 = true; } @@ -1945,9 +2791,22 @@ public sealed partial class DeviceReport mediaType == "Enhanced CD (aka E-CD, CD-Plus or CD+)") && mediaTest.SupportsReadCdRaw == true) { - _dev.ReadCd(out _, out _, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + _dev.ReadCd(out _, + out _, + 0, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); triedLba0 = true; } @@ -1955,8 +2814,21 @@ public sealed partial class DeviceReport mediaType == "Enhanced CD (aka E-CD, CD-Plus or CD+)") && mediaTest.SupportsReadCd == true) { - _dev.ReadCd(out _, out _, 0, 2048, 1, MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, _dev.Timeout, + _dev.ReadCd(out _, + out _, + 0, + 2048, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, out _); triedLba0 = true; @@ -1983,98 +2855,169 @@ public sealed partial class DeviceReport triedLba0 = true; } - if(!triedLba0) - return; + if(!triedLba0) return; mediaTest.CanReadF1_06 = !_dev.MediaTekReadDram(out buffer, out senseBuffer, 0, 0xB00, _dev.Timeout, out _); mediaTest.ReadF1_06Data = mediaTest.CanReadF1_06 == true ? buffer : senseBuffer; - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadF1_06); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadF1_06); }); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying MediaTek READ DRAM command for Lead-Out...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_MediaTek_READ_DRAM_command_for_Lead_Out).IsIndeterminate(); - if(mediaTest.Blocks > 0) + if(!(mediaTest.Blocks > 0)) return; + + if(mediaType == "Audio CD" && mediaTest.SupportsReadCd == true) { - if(mediaType == "Audio CD" && - mediaTest.SupportsReadCd == true) - { - _dev.ReadCd(out _, out _, (uint)(mediaTest.Blocks + 1), 2352, 1, MmcSectorTypes.Cdda, false, - false, false, MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); + _dev.ReadCd(out _, + out _, + (uint)(mediaTest.Blocks + 1), + 2352, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); - triedLeadOut = true; - } - else if((mediaType.StartsWith("CD", StringComparison.OrdinalIgnoreCase) || - mediaType == "Enhanced CD (aka E-CD, CD-Plus or CD+)") && - mediaTest.SupportsReadCdRaw == true) - { - _dev.ReadCd(out _, out _, (uint)(mediaTest.Blocks + 1), 2352, 1, MmcSectorTypes.AllTypes, false, - false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); - - triedLeadOut = true; - } - else if((mediaType.StartsWith("CD", StringComparison.OrdinalIgnoreCase) || - mediaType == "Enhanced CD (aka E-CD, CD-Plus or CD+)") && - mediaTest.SupportsReadCd == true) - { - _dev.ReadCd(out _, out _, (uint)(mediaTest.Blocks + 1), 2048, 1, MmcSectorTypes.AllTypes, false, - false, false, MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); - - triedLeadOut = true; - } - else if(mediaTest.SupportsRead6 == true) - { - _dev.Read6(out _, out _, (uint)(mediaTest.Blocks + 1), 2048, _dev.Timeout, out _); - triedLeadOut = true; - } - else if(mediaTest.SupportsRead10 == true) - { - _dev.Read10(out _, out _, 0, false, true, false, false, (uint)(mediaTest.Blocks + 1), 2048, 0, - 1, _dev.Timeout, out _); - - triedLeadOut = true; - } - else if(mediaTest.SupportsRead12 == true) - { - _dev.Read12(out _, out _, 0, false, true, false, false, (uint)(mediaTest.Blocks + 1), 2048, 0, - 1, false, _dev.Timeout, out _); - - triedLeadOut = true; - } - else if(mediaTest.SupportsRead16 == true) - { - _dev.Read16(out _, out _, 0, false, true, false, (ulong)(mediaTest.Blocks + 1), 2048, 0, 1, - false, _dev.Timeout, out _); - - triedLeadOut = true; - } - - if(triedLeadOut) - { - mediaTest.CanReadF1_06LeadOut = - !_dev.MediaTekReadDram(out buffer, out senseBuffer, 0, 0xB00, _dev.Timeout, out _); - - mediaTest.ReadF1_06LeadOutData = mediaTest.CanReadF1_06LeadOut == true ? buffer : senseBuffer; - - // This means it has returned the same as previous read, so not really lead-out. - if(mediaTest.CanReadF1_06 == true && - mediaTest.CanReadF1_06LeadOut == true && - mediaTest.ReadF1_06Data.SequenceEqual(mediaTest.ReadF1_06LeadOutData)) - { - mediaTest.CanReadF1_06LeadOut = false; - mediaTest.ReadF1_06LeadOutData = senseBuffer; - } - - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadF1_06LeadOut); - } + triedLeadOut = true; } + else if((mediaType.StartsWith("CD", StringComparison.OrdinalIgnoreCase) || + mediaType == "Enhanced CD (aka E-CD, CD-Plus or CD+)") && + mediaTest.SupportsReadCdRaw == true) + { + _dev.ReadCd(out _, + out _, + (uint)(mediaTest.Blocks + 1), + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); + + triedLeadOut = true; + } + else if((mediaType.StartsWith("CD", StringComparison.OrdinalIgnoreCase) || + mediaType == "Enhanced CD (aka E-CD, CD-Plus or CD+)") && + mediaTest.SupportsReadCd == true) + { + _dev.ReadCd(out _, + out _, + (uint)(mediaTest.Blocks + 1), + 2048, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); + + triedLeadOut = true; + } + else if(mediaTest.SupportsRead6 == true) + { + _dev.Read6(out _, out _, (uint)(mediaTest.Blocks + 1), 2048, _dev.Timeout, out _); + triedLeadOut = true; + } + else if(mediaTest.SupportsRead10 == true) + { + _dev.Read10(out _, + out _, + 0, + false, + true, + false, + false, + (uint)(mediaTest.Blocks + 1), + 2048, + 0, + 1, + _dev.Timeout, + out _); + + triedLeadOut = true; + } + else if(mediaTest.SupportsRead12 == true) + { + _dev.Read12(out _, + out _, + 0, + false, + true, + false, + false, + (uint)(mediaTest.Blocks + 1), + 2048, + 0, + 1, + false, + _dev.Timeout, + out _); + + triedLeadOut = true; + } + else if(mediaTest.SupportsRead16 == true) + { + _dev.Read16(out _, + out _, + 0, + false, + true, + false, + (ulong)(mediaTest.Blocks + 1), + 2048, + 0, + 1, + false, + _dev.Timeout, + out _); + + triedLeadOut = true; + } + + if(!triedLeadOut) return; + + mediaTest.CanReadF1_06LeadOut = + !_dev.MediaTekReadDram(out buffer, out senseBuffer, 0, 0xB00, _dev.Timeout, out _); + + mediaTest.ReadF1_06LeadOutData = mediaTest.CanReadF1_06LeadOut == true ? buffer : senseBuffer; + + // This means it has returned the same as previous read, so not really lead-out. + if(mediaTest.CanReadF1_06 == true && + mediaTest.CanReadF1_06LeadOut == true && + mediaTest.ReadF1_06Data.SequenceEqual(mediaTest.ReadF1_06LeadOutData)) + { + mediaTest.CanReadF1_06LeadOut = false; + mediaTest.ReadF1_06LeadOutData = senseBuffer; + } + + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadF1_06LeadOut); }); } @@ -2083,11 +3026,11 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying CD Full TOC...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_CD_Full_TOC).IsIndeterminate(); mediaTest.CanReadFullTOC = !_dev.ReadRawToc(out buffer, out senseBuffer, 1, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadFullTOC); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.CanReadFullTOC); mediaTest.FullTocData = buffer; @@ -2103,113 +3046,181 @@ public sealed partial class DeviceReport if(!decodedToc.TrackDescriptors.Any(t => t.SessionNumber > 1)) { - AaruConsole. - ErrorWriteLine("Could not find second session. Have you inserted the correct type of disc?"); + AaruConsole.ErrorWriteLine(Localization.Core + .Could_not_find_second_session_Have_you_inserted_the_correct_type_of_disc); return null; } FullTOC.TrackDataDescriptor firstSessionLeadOutTrack = - decodedToc.TrackDescriptors.FirstOrDefault(t => t.SessionNumber == 1 && t.POINT == 0xA2); + decodedToc.TrackDescriptors.FirstOrDefault(t => t is { SessionNumber: 1, POINT: 0xA2 }); FullTOC.TrackDataDescriptor secondSessionFirstTrack = - decodedToc.TrackDescriptors.FirstOrDefault(t => t.SessionNumber > 1 && t.POINT <= 99); + decodedToc.TrackDescriptors.FirstOrDefault(t => t is { SessionNumber: > 1, POINT: <= 99 }); - if(firstSessionLeadOutTrack.SessionNumber == 0 || - secondSessionFirstTrack.SessionNumber == 0) + if(firstSessionLeadOutTrack.SessionNumber == 0 || secondSessionFirstTrack.SessionNumber == 0) { - AaruConsole. - ErrorWriteLine("Could not find second session. Have you inserted the correct type of disc?"); + AaruConsole.ErrorWriteLine(Localization.Core + .Could_not_find_second_session_Have_you_inserted_the_correct_type_of_disc); return null; } - AaruConsole.DebugWriteLine("SCSI Report", "First session Lead-Out starts at {0:D2}:{1:D2}:{2:D2}", - firstSessionLeadOutTrack.PMIN, firstSessionLeadOutTrack.PSEC, + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.First_session_Lead_Out_starts_at_0_1_2, + firstSessionLeadOutTrack.PMIN, + firstSessionLeadOutTrack.PSEC, firstSessionLeadOutTrack.PFRAME); - AaruConsole.DebugWriteLine("SCSI Report", "Second session starts at {0:D2}:{1:D2}:{2:D2}", - secondSessionFirstTrack.PMIN, secondSessionFirstTrack.PSEC, + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Second_session_starts_at_0_1_2, + secondSessionFirstTrack.PMIN, + secondSessionFirstTrack.PSEC, secondSessionFirstTrack.PFRAME); // Skip Lead-Out pre-gap var firstSessionLeadOutLba = (uint)(firstSessionLeadOutTrack.PMIN * 60 * 75 + firstSessionLeadOutTrack.PSEC * 75 + - firstSessionLeadOutTrack.PFRAME + 150); + firstSessionLeadOutTrack.PFRAME + + 150); // Skip second session track pre-gap var secondSessionLeadInLba = (uint)(secondSessionFirstTrack.PMIN * 60 * 75 + secondSessionFirstTrack.PSEC * 75 + - secondSessionFirstTrack.PFRAME - 300); + secondSessionFirstTrack.PFRAME - + 300); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ CD in first session Lead-Out...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_CD_in_first_session_Lead_Out).IsIndeterminate(); - mediaTest.CanReadingIntersessionLeadOut = !_dev.ReadCd(out buffer, out senseBuffer, - firstSessionLeadOutLba, 2448, 1, - MmcSectorTypes.AllTypes, false, false, - false, MmcHeaderCodes.AllHeaders, true, - false, MmcErrorField.None, - MmcSubchannel.Raw, _dev.Timeout, out _); + mediaTest.CanReadingIntersessionLeadOut = !_dev.ReadCd(out buffer, + out senseBuffer, + firstSessionLeadOutLba, + 2448, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.AllHeaders, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, + out _); + + if(mediaTest.CanReadingIntersessionLeadOut != false) return; + + mediaTest.CanReadingIntersessionLeadOut = !_dev.ReadCd(out buffer, + out senseBuffer, + firstSessionLeadOutLba, + 2368, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.AllHeaders, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, + out _); if(mediaTest.CanReadingIntersessionLeadOut == false) { - mediaTest.CanReadingIntersessionLeadOut = !_dev.ReadCd(out buffer, out senseBuffer, - firstSessionLeadOutLba, 2368, 1, - MmcSectorTypes.AllTypes, false, false, - false, MmcHeaderCodes.AllHeaders, true, - false, MmcErrorField.None, - MmcSubchannel.Q16, _dev.Timeout, out _); - - if(mediaTest.CanReadingIntersessionLeadOut == false) - mediaTest.CanReadingIntersessionLeadOut = !_dev.ReadCd(out buffer, out senseBuffer, - firstSessionLeadOutLba, 2352, 1, - MmcSectorTypes.AllTypes, false, - false, false, - MmcHeaderCodes.AllHeaders, true, - false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, - out _); + mediaTest.CanReadingIntersessionLeadOut = !_dev.ReadCd(out buffer, + out senseBuffer, + firstSessionLeadOutLba, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.AllHeaders, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); } }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadingIntersessionLeadOut); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadingIntersessionLeadOut); mediaTest.IntersessionLeadOutData = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ CD in second session Lead-In...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_CD_in_second_session_Lead_In).IsIndeterminate(); - mediaTest.CanReadingIntersessionLeadIn = !_dev.ReadCd(out buffer, out senseBuffer, - secondSessionLeadInLba, 2448, 1, - MmcSectorTypes.AllTypes, false, false, - false, MmcHeaderCodes.AllHeaders, true, - false, MmcErrorField.None, - MmcSubchannel.Raw, _dev.Timeout, out _); + mediaTest.CanReadingIntersessionLeadIn = !_dev.ReadCd(out buffer, + out senseBuffer, + secondSessionLeadInLba, + 2448, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.AllHeaders, + true, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + _dev.Timeout, + out _); + + if(mediaTest.CanReadingIntersessionLeadIn != false) return; + + mediaTest.CanReadingIntersessionLeadIn = !_dev.ReadCd(out buffer, + out senseBuffer, + secondSessionLeadInLba, + 2368, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.AllHeaders, + true, + false, + MmcErrorField.None, + MmcSubchannel.Q16, + _dev.Timeout, + out _); if(mediaTest.CanReadingIntersessionLeadIn == false) { - mediaTest.CanReadingIntersessionLeadIn = !_dev.ReadCd(out buffer, out senseBuffer, - secondSessionLeadInLba, 2368, 1, - MmcSectorTypes.AllTypes, false, false, - false, MmcHeaderCodes.AllHeaders, true, - false, MmcErrorField.None, - MmcSubchannel.Q16, _dev.Timeout, out _); - - if(mediaTest.CanReadingIntersessionLeadIn == false) - mediaTest.CanReadingIntersessionLeadIn = !_dev.ReadCd(out buffer, out senseBuffer, - secondSessionLeadInLba, 2352, 1, - MmcSectorTypes.AllTypes, false, false, - false, MmcHeaderCodes.AllHeaders, - true, false, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, - out _); + mediaTest.CanReadingIntersessionLeadIn = !_dev.ReadCd(out buffer, + out senseBuffer, + secondSessionLeadInLba, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.AllHeaders, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); } }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.CanReadingIntersessionLeadIn); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.Core.Sense_equals_0, + !mediaTest.CanReadingIntersessionLeadIn); mediaTest.IntersessionLeadInData = buffer; } diff --git a/Aaru.Core/Devices/Report/PCMCIA.cs b/Aaru.Core/Devices/Report/PCMCIA.cs index a948466c9..2cf60f102 100644 --- a/Aaru.Core/Devices/Report/PCMCIA.cs +++ b/Aaru.Core/Devices/Report/PCMCIA.cs @@ -27,14 +27,14 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Report; - using Aaru.CommonTypes.Metadata; using Aaru.Decoders.PCMCIA; +namespace Aaru.Core.Devices.Report; + /// Implements creating a report for a PCMCIA device public sealed partial class DeviceReport { @@ -48,10 +48,10 @@ public sealed partial class DeviceReport Tuple[] tuples = CIS.GetTuples(_dev.Cis); - if(tuples == null) - return pcmciaReport; + if(tuples == null) return pcmciaReport; foreach(Tuple tuple in tuples) + { switch(tuple.Code) { case TupleCodes.CISTPL_MANFID: @@ -77,6 +77,7 @@ public sealed partial class DeviceReport break; } + } return pcmciaReport; } diff --git a/Aaru.Core/Devices/Report/SSC.cs b/Aaru.Core/Devices/Report/SSC.cs index 853e8ef47..f1eb8fadb 100644 --- a/Aaru.Core/Devices/Report/SSC.cs +++ b/Aaru.Core/Devices/Report/SSC.cs @@ -27,18 +27,17 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Report; - -using System; using System.Linq; using Aaru.CommonTypes.Metadata; using Aaru.Decoders.SCSI; using Aaru.Decoders.SCSI.SSC; using Aaru.Devices; -using global::Spectre.Console; +using Spectre.Console; + +namespace Aaru.Core.Devices.Report; public sealed partial class DeviceReport { @@ -48,11 +47,11 @@ public sealed partial class DeviceReport { var report = new Ssc(); var sense = true; - byte[] buffer = Array.Empty(); + byte[] buffer = []; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI READ BLOCK LIMITS...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_READ_BLOCK_LIMITS).IsIndeterminate(); sense = _dev.ReadBlockLimits(out buffer, out _, _dev.Timeout, out _); }); @@ -60,19 +59,16 @@ public sealed partial class DeviceReport { BlockLimits.BlockLimitsData? decBl = BlockLimits.Decode(buffer); - if(decBl?.granularity > 0) - report.BlockSizeGranularity = decBl.Value.granularity; + if(decBl?.granularity > 0) report.BlockSizeGranularity = decBl.Value.granularity; - if(decBl?.maxBlockLen > 0) - report.MaxBlockLength = decBl.Value.maxBlockLen; + if(decBl?.maxBlockLen > 0) report.MaxBlockLength = decBl.Value.maxBlockLen; - if(decBl?.minBlockLen > 0) - report.MinBlockLength = decBl.Value.minBlockLen; + if(decBl?.minBlockLen > 0) report.MinBlockLength = decBl.Value.minBlockLen; } Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI REPORT DENSITY SUPPORT...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_REPORT_DENSITY_SUPPORT).IsIndeterminate(); sense = _dev.ReportDensitySupport(out buffer, out _, false, false, _dev.Timeout, out _); }); @@ -85,6 +81,7 @@ public sealed partial class DeviceReport var array = new SupportedDensity[dsh.Value.descriptors.Length]; for(var i = 0; i < dsh.Value.descriptors.Length; i++) + { array[i] = new SupportedDensity { BitsPerMm = dsh.Value.descriptors[i].bpmm, @@ -100,6 +97,7 @@ public sealed partial class DeviceReport Width = dsh.Value.descriptors[i].width, Writable = dsh.Value.descriptors[i].writable }; + } report.SupportedDensities = array.ToList(); } @@ -107,17 +105,15 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI REPORT DENSITY SUPPORT for medium types...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_REPORT_DENSITY_SUPPORT_for_medium_types).IsIndeterminate(); sense = _dev.ReportDensitySupport(out buffer, out _, true, false, _dev.Timeout, out _); }); - if(sense) - return report; + if(sense) return report; DensitySupport.MediaTypeSupportHeader? mtsh = DensitySupport.DecodeMediumType(buffer); - if(!mtsh.HasValue) - return report; + if(!mtsh.HasValue) return report; var array2 = new SscSupportedMedia[mtsh.Value.descriptors.Length]; @@ -133,16 +129,17 @@ public sealed partial class DeviceReport Width = mtsh.Value.descriptors[i].width }; - if(mtsh.Value.descriptors[i].densityCodes == null) - continue; + if(mtsh.Value.descriptors[i].densityCodes == null) continue; var array3 = new DensityCode[mtsh.Value.descriptors[i].densityCodes.Length]; for(var j = 0; j < mtsh.Value.descriptors[i].densityCodes.Length; j++) + { array3[j] = new DensityCode { Code = mtsh.Value.descriptors[i].densityCodes[j] }; + } array2[i].DensityCodes = array3.Distinct().ToList(); } @@ -158,20 +155,26 @@ public sealed partial class DeviceReport { var seqTest = new TestedSequentialMedia(); var sense = true; - byte[] buffer = Array.Empty(); + byte[] buffer = []; Modes.DecodedMode? decMode = null; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI MODE SENSE (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_MODE_SENSE_10).IsIndeterminate(); - sense = _dev.ModeSense10(out buffer, out _, false, true, ScsiModeSensePageControl.Current, 0x3F, 0x00, - _dev.Timeout, out _); + sense = _dev.ModeSense10(out buffer, + out _, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + _dev.Timeout, + out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { decMode = Modes.DecodeMode10(buffer, _dev.ScsiType); seqTest.ModeSense10Data = buffer; @@ -179,12 +182,11 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI MODE SENSE...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_MODE_SENSE).IsIndeterminate(); sense = _dev.ModeSense(out buffer, out _, _dev.Timeout, out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { decMode ??= Modes.DecodeMode6(buffer, _dev.ScsiType); @@ -196,12 +198,12 @@ public sealed partial class DeviceReport seqTest.MediumType = (byte)decMode.Value.Header.MediumType; if(decMode.Value.Header.BlockDescriptors?.Length > 0) - seqTest.Density = (byte)decMode.Value.Header.BlockDescriptors?[0].Density; + seqTest.Density = (byte)(decMode.Value.Header.BlockDescriptors?[0].Density ?? default(DensityType)); } Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI REPORT DENSITY SUPPORT for current media...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_REPORT_DENSITY_SUPPORT_for_current_media).IsIndeterminate(); sense = _dev.ReportDensitySupport(out buffer, out _, false, true, _dev.Timeout, out _); }); @@ -214,6 +216,7 @@ public sealed partial class DeviceReport var array = new SupportedDensity[dsh.Value.descriptors.Length]; for(var i = 0; i < dsh.Value.descriptors.Length; i++) + { array[i] = new SupportedDensity { BitsPerMm = dsh.Value.descriptors[i].bpmm, @@ -229,6 +232,7 @@ public sealed partial class DeviceReport Width = dsh.Value.descriptors[i].width, Writable = dsh.Value.descriptors[i].writable }; + } seqTest.SupportedDensities = array.ToList(); } @@ -236,7 +240,8 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI REPORT DENSITY SUPPORT for medium types for current media...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_REPORT_DENSITY_SUPPORT_for_medium_types_for_current_media) + .IsIndeterminate(); sense = _dev.ReportDensitySupport(out buffer, out _, true, true, _dev.Timeout, out _); }); @@ -261,16 +266,17 @@ public sealed partial class DeviceReport Width = mtsh.Value.descriptors[i].width }; - if(mtsh.Value.descriptors[i].densityCodes == null) - continue; + if(mtsh.Value.descriptors[i].densityCodes == null) continue; var array2 = new DensityCode[mtsh.Value.descriptors[i].densityCodes.Length]; for(var j = 0; j < mtsh.Value.descriptors[i].densityCodes.Length; j++) + { array2[j] = new DensityCode { Code = mtsh.Value.descriptors[i].densityCodes[j] }; + } array[i].DensityCodes = array2.Distinct().ToList(); } @@ -281,7 +287,7 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ MEDIA SERIAL NUMBER...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_MEDIA_SERIAL_NUMBER).IsIndeterminate(); seqTest.CanReadMediaSerial = !_dev.ReadMediaSerialNumber(out buffer, out _, _dev.Timeout, out _); }); diff --git a/Aaru.Core/Devices/Report/Scsi.cs b/Aaru.Core/Devices/Report/Scsi.cs index ed9acb518..ecaad2690 100644 --- a/Aaru.Core/Devices/Report/Scsi.cs +++ b/Aaru.Core/Devices/Report/Scsi.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Report; - using System; using System.Collections.Generic; using System.Linq; @@ -41,9 +39,11 @@ using Aaru.Console; using Aaru.Decoders.SCSI; using Aaru.Devices; using Aaru.Helpers; -using global::Spectre.Console; +using Spectre.Console; using Inquiry = Aaru.CommonTypes.Structs.Devices.SCSI.Inquiry; +namespace Aaru.Core.Devices.Report; + public sealed partial class DeviceReport { /// Creates a report for the SCSI INQUIRY response @@ -51,23 +51,21 @@ public sealed partial class DeviceReport public Scsi ReportScsiInquiry() { var sense = true; - byte[] buffer = Array.Empty(); + byte[] buffer = []; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI INQUIRY...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_INQUIRY).IsIndeterminate(); sense = _dev.ScsiInquiry(out buffer, out _); }); var report = new Scsi(); - if(sense) - return null; + if(sense) return null; Inquiry? decodedNullable = Inquiry.Decode(buffer); - if(!decodedNullable.HasValue) - return null; + if(!decodedNullable.HasValue) return null; report.InquiryData = ClearInquiry(buffer); @@ -78,8 +76,7 @@ public sealed partial class DeviceReport { Inquiry? decodedNullable = Inquiry.Decode(inquiry); - if(!decodedNullable.HasValue) - return inquiry; + if(!decodedNullable.HasValue) return inquiry; Inquiry decoded = decodedNullable.Value; @@ -88,8 +85,7 @@ public sealed partial class DeviceReport return inquiry; // Clear Seagate serial number - for(var i = 36; i <= 43; i++) - inquiry[i] = 0; + for(var i = 36; i <= 43; i++) inquiry[i] = 0; return inquiry; } @@ -100,39 +96,35 @@ public sealed partial class DeviceReport public List ReportEvpdPages(string vendor) { var sense = false; - byte[] buffer = Array.Empty(); + byte[] buffer = []; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying list of SCSI EVPDs...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_list_of_SCSI_EVPDs).IsIndeterminate(); sense = _dev.ScsiInquiry(out buffer, out _, 0x00); }); - if(sense) - return null; + if(sense) return null; byte[] evpdPages = EVPD.DecodePage00(buffer); - if(evpdPages == null || - evpdPages.Length <= 0) - return null; + if(evpdPages is not { Length: > 0 }) return null; - List evpds = new(); + List evpds = []; Spectre.ProgressSingleSpinner(ctx => { - ProgressTask task = ctx. - AddTask("Querying SCSI EVPD pages...", maxValue: evpdPages.Count(page => page != 0x80)). - IsIndeterminate(); + ProgressTask task = ctx.AddTask(Localization.Core.Querying_SCSI_EVPD_pages, + maxValue: evpdPages.Count(page => page != 0x80)) + .IsIndeterminate(); foreach(byte page in evpdPages.Where(page => page != 0x80)) { - task.Description = $"Querying SCSI EVPD {page:X2}h..."; + task.Description = string.Format(Localization.Core.Querying_SCSI_EVPD_0, page); task.Increment(1); sense = _dev.ScsiInquiry(out buffer, out _, page); - if(sense) - continue; + if(sense) continue; byte[] empty; @@ -157,7 +149,7 @@ public sealed partial class DeviceReport break; case 0xC1 when vendor == "ibm": empty = new byte[12]; - Array.Copy(empty, 0, buffer, 4, 12); + Array.Copy(empty, 0, buffer, 4, 12); Array.Copy(empty, 0, buffer, 16, 12); break; @@ -184,16 +176,13 @@ public sealed partial class DeviceReport return evpds.Count > 0 ? evpds : null; } - byte[] ClearPage83(byte[] pageResponse) + static byte[] ClearPage83(byte[] pageResponse) { - if(pageResponse?[1] != 0x83) - return null; + if(pageResponse?[1] != 0x83) return null; - if(pageResponse[3] + 4 != pageResponse.Length) - return null; + if(pageResponse[3] + 4 != pageResponse.Length) return null; - if(pageResponse.Length < 6) - return null; + if(pageResponse.Length < 6) return null; var position = 4; @@ -201,8 +190,7 @@ public sealed partial class DeviceReport { byte length = pageResponse[position + 3]; - if(length + position + 4 >= pageResponse.Length) - length = (byte)(pageResponse.Length - position - 4); + if(length + position + 4 >= pageResponse.Length) length = (byte)(pageResponse.Length - position - 4); var empty = new byte[length]; Array.Copy(empty, 0, pageResponse, position + 4, length); @@ -217,20 +205,20 @@ public sealed partial class DeviceReport /// Device report /// Returns raw MODE SENSE page 2Ah, aka CD-ROM page /// Returns decoded list of supported media types response - public void ReportScsiModes(ref DeviceReportV2 report, out byte[] cdromMode, out MediumTypes mediumType) + public void ReportScsiModes(ref CommonTypes.Metadata.DeviceReport report, out byte[] cdromMode, + out MediumTypes mediumType) { Modes.DecodedMode? decMode = null; PeripheralDeviceTypes devType = _dev.ScsiType; - byte[] mode10Buffer; - byte[] mode6Buffer; bool sense; mediumType = 0; - DeviceReportV2 v2 = report; + CommonTypes.Metadata.DeviceReport v2 = report; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying all mode pages and subpages using SCSI MODE SENSE (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_all_mode_pages_and_subpages_using_SCSI_MODE_SENSE_10) + .IsIndeterminate(); foreach(ScsiModeSensePageControl pageControl in new[] { @@ -240,26 +228,53 @@ public sealed partial class DeviceReport { var saveBuffer = false; - sense = _dev.ModeSense10(out mode10Buffer, out _, false, true, pageControl, 0x3F, 0xFF, _dev.Timeout, + sense = _dev.ModeSense10(out byte[] mode10Buffer, + out _, + false, + true, + pageControl, + 0x3F, + 0xFF, + _dev.Timeout, out _); if(sense || _dev.Error) { - sense = _dev.ModeSense10(out mode10Buffer, out _, false, false, pageControl, 0x3F, 0xFF, - _dev.Timeout, out _); + sense = _dev.ModeSense10(out mode10Buffer, + out _, + false, + false, + pageControl, + 0x3F, + 0xFF, + _dev.Timeout, + out _); if(sense || _dev.Error) { - sense = _dev.ModeSense10(out mode10Buffer, out _, false, true, pageControl, 0x3F, 0x00, - _dev.Timeout, out _); + sense = _dev.ModeSense10(out mode10Buffer, + out _, + false, + true, + pageControl, + 0x3F, + 0x00, + _dev.Timeout, + out _); if(sense || _dev.Error) { - sense = _dev.ModeSense10(out mode10Buffer, out _, false, false, pageControl, 0x3F, 0x00, - _dev.Timeout, out _); + sense = _dev.ModeSense10(out mode10Buffer, + out _, + false, + false, + pageControl, + 0x3F, + 0x00, + _dev.Timeout, + out _); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { v2.SCSI.SupportsModeSense10 = true; decMode ??= Modes.DecodeMode10(mode10Buffer, devType); @@ -289,8 +304,7 @@ public sealed partial class DeviceReport saveBuffer = true; } - if(!saveBuffer) - continue; + if(!saveBuffer) continue; switch(pageControl) { @@ -312,7 +326,8 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying all mode pages and subpages using SCSI MODE SENSE (6)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_all_mode_pages_and_subpages_using_SCSI_MODE_SENSE_6) + .IsIndeterminate(); foreach(ScsiModeSensePageControl pageControl in new[] { @@ -321,35 +336,72 @@ public sealed partial class DeviceReport }) { var saveBuffer = false; - sense = _dev.ModeSense6(out mode6Buffer, out _, true, pageControl, 0x3F, 0xFF, _dev.Timeout, out _); + + sense = _dev.ModeSense6(out byte[] mode6Buffer, + out _, + true, + pageControl, + 0x3F, + 0xFF, + _dev.Timeout, + out _); if(sense || _dev.Error) { - sense = _dev.ModeSense6(out mode6Buffer, out _, false, pageControl, 0x3F, 0xFF, _dev.Timeout, + sense = _dev.ModeSense6(out mode6Buffer, + out _, + false, + pageControl, + 0x3F, + 0xFF, + _dev.Timeout, out _); if(sense || _dev.Error) { - sense = _dev.ModeSense6(out mode6Buffer, out _, true, pageControl, 0x3F, 0x00, _dev.Timeout, + sense = _dev.ModeSense6(out mode6Buffer, + out _, + true, + pageControl, + 0x3F, + 0x00, + _dev.Timeout, out _); if(sense || _dev.Error) { - sense = _dev.ModeSense6(out mode6Buffer, out _, false, pageControl, 0x3F, 0x00, - _dev.Timeout, out _); + sense = _dev.ModeSense6(out mode6Buffer, + out _, + false, + pageControl, + 0x3F, + 0x00, + _dev.Timeout, + out _); if(sense || _dev.Error) { - sense = _dev.ModeSense6(out mode6Buffer, out _, true, pageControl, 0x00, 0x00, - _dev.Timeout, out _); + sense = _dev.ModeSense6(out mode6Buffer, + out _, + true, + pageControl, + 0x00, + 0x00, + _dev.Timeout, + out _); if(sense || _dev.Error) { - sense = _dev.ModeSense6(out mode6Buffer, out _, false, pageControl, 0x00, 0x00, - _dev.Timeout, out _); + sense = _dev.ModeSense6(out mode6Buffer, + out _, + false, + pageControl, + 0x00, + 0x00, + _dev.Timeout, + out _); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { v2.SCSI.SupportsModeSense6 = true; decMode ??= Modes.DecodeMode6(mode6Buffer, devType); @@ -393,8 +445,7 @@ public sealed partial class DeviceReport saveBuffer = true; } - if(!saveBuffer) - continue; + if(!saveBuffer) continue; switch(pageControl) { @@ -418,8 +469,7 @@ public sealed partial class DeviceReport cdromMode = null; - if(decMode == null) - return; + if(decMode == null) return; mediumType = decMode.Value.Header.MediumType; @@ -433,13 +483,11 @@ public sealed partial class DeviceReport if(decMode.Value.Header.BufferedMode > 0) report.SCSI.ModeSense.BufferedMode = decMode.Value.Header.BufferedMode; - if(decMode.Value.Header.Speed > 0) - report.SCSI.ModeSense.Speed = decMode.Value.Header.Speed; + if(decMode.Value.Header.Speed > 0) report.SCSI.ModeSense.Speed = decMode.Value.Header.Speed; - if(decMode.Value.Pages == null) - return; + if(decMode.Value.Pages == null) return; - List modePages = new(); + List modePages = []; foreach(Modes.ModePage page in decMode.Value.Pages) { @@ -452,13 +500,10 @@ public sealed partial class DeviceReport modePages.Add(modePage); - if(modePage.page == 0x2A && - modePage.subpage == 0x00) - cdromMode = page.PageResponse; + if(modePage.page == 0x2A && modePage.subpage == 0x00) cdromMode = page.PageResponse; } - if(modePages.Count > 0) - report.SCSI.ModeSense.ModePages = modePages; + if(modePages.Count > 0) report.SCSI.ModeSense.ModePages = modePages; } /// Creates a report for media inserted into a SCSI device @@ -467,34 +512,33 @@ public sealed partial class DeviceReport { var mediaTest = new TestedMedia(); var sense = true; - byte[] buffer = Array.Empty(); - byte[] senseBuffer = Array.Empty(); + byte[] buffer = []; + byte[] senseBuffer = []; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI READ CAPACITY...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_READ_CAPACITY).IsIndeterminate(); sense = _dev.ReadCapacity(out buffer, out senseBuffer, _dev.Timeout, out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { mediaTest.SupportsReadCapacity = true; mediaTest.Blocks = ((ulong)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]) & - 0xFFFFFFFF) + 1; + 0xFFFFFFFF) + + 1; mediaTest.BlockSize = (uint)((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + buffer[7]); } Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI READ CAPACITY (16)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_READ_CAPACITY_16).IsIndeterminate(); sense = _dev.ReadCapacity16(out buffer, out buffer, _dev.Timeout, out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { mediaTest.SupportsReadCapacity16 = true; var temp = new byte[8]; @@ -508,14 +552,20 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI MODE SENSE (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_MODE_SENSE_10).IsIndeterminate(); - sense = _dev.ModeSense10(out buffer, out senseBuffer, false, true, ScsiModeSensePageControl.Current, 0x3F, - 0x00, _dev.Timeout, out _); + sense = _dev.ModeSense10(out buffer, + out senseBuffer, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + _dev.Timeout, + out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { decMode = Modes.DecodeMode10(buffer, _dev.ScsiType); mediaTest.ModeSense10Data = buffer; @@ -523,12 +573,11 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI MODE SENSE...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_MODE_SENSE).IsIndeterminate(); sense = _dev.ModeSense(out buffer, out senseBuffer, _dev.Timeout, out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { decMode ??= Modes.DecodeMode6(buffer, _dev.ScsiType); @@ -545,53 +594,87 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (6)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_6).IsIndeterminate(); - mediaTest.SupportsRead6 = !_dev.Read6(out buffer, out senseBuffer, 0, mediaTest.BlockSize ?? 512, - _dev.Timeout, out _); + mediaTest.SupportsRead6 = + !_dev.Read6(out buffer, out senseBuffer, 0, mediaTest.BlockSize ?? 512, _dev.Timeout, out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead6); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead6); mediaTest.Read6Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_10).IsIndeterminate(); - mediaTest.SupportsRead10 = !_dev.Read10(out buffer, out senseBuffer, 0, false, false, false, false, 0, - mediaTest.BlockSize ?? 512, 0, 1, _dev.Timeout, out _); + mediaTest.SupportsRead10 = !_dev.Read10(out buffer, + out senseBuffer, + 0, + false, + false, + false, + false, + 0, + mediaTest.BlockSize ?? 512, + 0, + 1, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead10); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead10); mediaTest.Read10Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (12)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_12).IsIndeterminate(); - mediaTest.SupportsRead12 = !_dev.Read12(out buffer, out senseBuffer, 0, false, false, false, false, 0, - mediaTest.BlockSize ?? 512, 0, 1, false, _dev.Timeout, out _); + mediaTest.SupportsRead12 = !_dev.Read12(out buffer, + out senseBuffer, + 0, + false, + false, + false, + false, + 0, + mediaTest.BlockSize ?? 512, + 0, + 1, + false, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead12); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead12); mediaTest.Read12Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (16)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_16).IsIndeterminate(); - mediaTest.SupportsRead16 = !_dev.Read16(out buffer, out senseBuffer, 0, false, false, false, 0, - mediaTest.BlockSize ?? 512, 0, 1, false, _dev.Timeout, out _); + mediaTest.SupportsRead16 = !_dev.Read16(out buffer, + out senseBuffer, + 0, + false, + false, + false, + 0, + mediaTest.BlockSize ?? 512, + 0, + 1, + false, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead16); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !mediaTest.SupportsRead16); mediaTest.Read16Data = buffer; mediaTest.LongBlockSize = mediaTest.BlockSize; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ LONG (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_LONG_10).IsIndeterminate(); sense = _dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 0xFFFF, _dev.Timeout, out _); }); @@ -599,9 +682,7 @@ public sealed partial class DeviceReport { DecodedSense? decSense = Sense.Decode(senseBuffer); - if(decSense?.SenseKey == SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && - decSense.Value.ASCQ == 0x00) + if(decSense is { SenseKey: SenseKeys.IllegalRequest, ASC: 0x24, ASCQ: 0x00 }) { mediaTest.SupportsReadLong = true; @@ -617,23 +698,20 @@ public sealed partial class DeviceReport information = (uint)Sense.DecodeDescriptor00(desc00); } - if(valid && ili) - mediaTest.LongBlockSize = 0xFFFF - (information & 0xFFFF); + if(valid && ili) mediaTest.LongBlockSize = 0xFFFF - (information & 0xFFFF); } } Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ LONG (16)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_LONG_16).IsIndeterminate(); sense = _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 0xFFFF, _dev.Timeout, out _); if(sense && !_dev.Error) { DecodedSense? decSense = Sense.Decode(senseBuffer); - if(decSense?.SenseKey == SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && - decSense.Value.ASCQ == 0x00) + if(decSense is { SenseKey: SenseKeys.IllegalRequest, ASC: 0x24, ASCQ: 0x00 }) { mediaTest.SupportsReadLong16 = true; @@ -649,115 +727,150 @@ public sealed partial class DeviceReport information = (uint)Sense.DecodeDescriptor00(desc00); } - if(valid && ili) - mediaTest.LongBlockSize = 0xFFFF - (information & 0xFFFF); + if(valid && ili) mediaTest.LongBlockSize = 0xFFFF - (information & 0xFFFF); } } - if((mediaTest.SupportsReadLong == true || mediaTest.SupportsReadLong16 == true) && - mediaTest.LongBlockSize == mediaTest.BlockSize) - switch(mediaTest.BlockSize) + if(mediaTest.SupportsReadLong != true && mediaTest.SupportsReadLong16 != true || + mediaTest.LongBlockSize != mediaTest.BlockSize) + return; + + switch(mediaTest.BlockSize) + { + case 512: { - case 512: - { - foreach(ushort testSize in new ushort[] - { - // Long sector sizes for floppies - 514, + foreach(ushort testSize in new ushort[] + { + // Long sector sizes for floppies + 514, - // Long sector sizes for SuperDisk - 536, 558, + // Long sector sizes for SuperDisk + 536, 558, - // Long sector sizes for 512-byte magneto-opticals - 600, 610, 630 - }) - { - sense = mediaTest.SupportsReadLong16 == true - ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, testSize, _dev.Timeout, - out _) : _dev.ReadLong10(out buffer, out senseBuffer, false, - false, 0, testSize, _dev.Timeout, out _); - - if(sense || _dev.Error) - continue; - - mediaTest.LongBlockSize = testSize; - - break; - } - - break; - } - case 1024: - { - foreach(ushort testSize in new ushort[] - { - // Long sector sizes for floppies - 1026, - - // Long sector sizes for 1024-byte magneto-opticals - 1200 - }) - { - sense = mediaTest.SupportsReadLong16 == true - ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, testSize, _dev.Timeout, - out _) : _dev.ReadLong10(out buffer, out senseBuffer, false, - false, 0, testSize, _dev.Timeout, out _); - - if(sense || _dev.Error) - continue; - - mediaTest.LongBlockSize = testSize; - - break; - } - - break; - } - case 2048: + // Long sector sizes for 512-byte magneto-opticals + 600, 610, 630 + }) { sense = mediaTest.SupportsReadLong16 == true - ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 2380, _dev.Timeout, out _) - : _dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 2380, _dev.Timeout, + ? _dev.ReadLong16(out buffer, + out senseBuffer, + false, + 0, + testSize, + _dev.Timeout, + out _) + : _dev.ReadLong10(out buffer, + out senseBuffer, + false, + false, + 0, + testSize, + _dev.Timeout, out _); - if(!sense && - !_dev.Error) - mediaTest.LongBlockSize = 2380; + if(sense || _dev.Error) continue; + + mediaTest.LongBlockSize = testSize; break; } - case 4096: - { - sense = mediaTest.SupportsReadLong16 == true - ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 4760, _dev.Timeout, out _) - : _dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 4760, _dev.Timeout, - out _); - if(!sense && - !_dev.Error) - mediaTest.LongBlockSize = 4760; - - break; - } - case 8192: - { - sense = mediaTest.SupportsReadLong16 == true - ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 9424, _dev.Timeout, out _) - : _dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 9424, _dev.Timeout, - out _); - - if(!sense && - !_dev.Error) - mediaTest.LongBlockSize = 9424; - - break; - } + break; } + case 1024: + { + foreach(ushort testSize in new ushort[] + { + // Long sector sizes for floppies + 1026, + + // Long sector sizes for 1024-byte magneto-opticals + 1200 + }) + { + sense = mediaTest.SupportsReadLong16 == true + ? _dev.ReadLong16(out buffer, + out senseBuffer, + false, + 0, + testSize, + _dev.Timeout, + out _) + : _dev.ReadLong10(out buffer, + out senseBuffer, + false, + false, + 0, + testSize, + _dev.Timeout, + out _); + + if(sense || _dev.Error) continue; + + mediaTest.LongBlockSize = testSize; + + break; + } + + break; + } + case 2048: + { + sense = mediaTest.SupportsReadLong16 == true + ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 2380, _dev.Timeout, out _) + : _dev.ReadLong10(out buffer, + out senseBuffer, + false, + false, + 0, + 2380, + _dev.Timeout, + out _); + + if(!sense && !_dev.Error) mediaTest.LongBlockSize = 2380; + + break; + } + case 4096: + { + sense = mediaTest.SupportsReadLong16 == true + ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 4760, _dev.Timeout, out _) + : _dev.ReadLong10(out buffer, + out senseBuffer, + false, + false, + 0, + 4760, + _dev.Timeout, + out _); + + if(!sense && !_dev.Error) mediaTest.LongBlockSize = 4760; + + break; + } + case 8192: + { + sense = mediaTest.SupportsReadLong16 == true + ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 9424, _dev.Timeout, out _) + : _dev.ReadLong10(out buffer, + out senseBuffer, + false, + false, + 0, + 9424, + _dev.Timeout, + out _); + + if(!sense && !_dev.Error) mediaTest.LongBlockSize = 9424; + + break; + } + } }); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ MEDIA SERIAL NUMBER...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_MEDIA_SERIAL_NUMBER).IsIndeterminate(); mediaTest.CanReadMediaSerial = !_dev.ReadMediaSerialNumber(out buffer, out senseBuffer, _dev.Timeout, out _); @@ -771,8 +884,8 @@ public sealed partial class DeviceReport public TestedMedia ReportScsi() { var sense = true; - byte[] buffer = Array.Empty(); - byte[] senseBuffer = Array.Empty(); + byte[] buffer = []; + byte[] senseBuffer = []; var capabilities = new TestedMedia { @@ -781,29 +894,28 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI READ CAPACITY...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_READ_CAPACITY).IsIndeterminate(); sense = _dev.ReadCapacity(out buffer, out senseBuffer, _dev.Timeout, out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { capabilities.SupportsReadCapacity = true; capabilities.Blocks = ((ulong)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]) & - 0xFFFFFFFF) + 1; + 0xFFFFFFFF) + + 1; capabilities.BlockSize = (uint)((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + buffer[7]); } Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI READ CAPACITY (16)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_READ_CAPACITY_16).IsIndeterminate(); sense = _dev.ReadCapacity16(out buffer, out buffer, _dev.Timeout, out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { capabilities.SupportsReadCapacity16 = true; var temp = new byte[8]; @@ -817,14 +929,20 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI MODE SENSE (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_MODE_SENSE_10).IsIndeterminate(); - sense = _dev.ModeSense10(out buffer, out senseBuffer, false, true, ScsiModeSensePageControl.Current, 0x3F, - 0x00, _dev.Timeout, out _); + sense = _dev.ModeSense10(out buffer, + out senseBuffer, + false, + true, + ScsiModeSensePageControl.Current, + 0x3F, + 0x00, + _dev.Timeout, + out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { decMode = Modes.DecodeMode10(buffer, _dev.ScsiType); capabilities.ModeSense10Data = buffer; @@ -832,12 +950,11 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Querying SCSI MODE SENSE...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Querying_SCSI_MODE_SENSE).IsIndeterminate(); sense = _dev.ModeSense(out buffer, out senseBuffer, _dev.Timeout, out _); }); - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { decMode ??= Modes.DecodeMode6(buffer, _dev.ScsiType); @@ -854,53 +971,91 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (6)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_6).IsIndeterminate(); - capabilities.SupportsRead6 = !_dev.Read6(out buffer, out senseBuffer, 0, capabilities.BlockSize ?? 512, - _dev.Timeout, out _); + capabilities.SupportsRead6 = !_dev.Read6(out buffer, + out senseBuffer, + 0, + capabilities.BlockSize ?? 512, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead6); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !capabilities.SupportsRead6); capabilities.Read6Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_10).IsIndeterminate(); - capabilities.SupportsRead10 = !_dev.Read10(out buffer, out senseBuffer, 0, false, false, false, false, 0, - capabilities.BlockSize ?? 512, 0, 1, _dev.Timeout, out _); + capabilities.SupportsRead10 = !_dev.Read10(out buffer, + out senseBuffer, + 0, + false, + false, + false, + false, + 0, + capabilities.BlockSize ?? 512, + 0, + 1, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead10); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !capabilities.SupportsRead10); capabilities.Read10Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (12)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_12).IsIndeterminate(); - capabilities.SupportsRead12 = !_dev.Read12(out buffer, out senseBuffer, 0, false, false, false, false, 0, - capabilities.BlockSize ?? 512, 0, 1, false, _dev.Timeout, out _); + capabilities.SupportsRead12 = !_dev.Read12(out buffer, + out senseBuffer, + 0, + false, + false, + false, + false, + 0, + capabilities.BlockSize ?? 512, + 0, + 1, + false, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead12); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !capabilities.SupportsRead12); capabilities.Read12Data = buffer; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ (16)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_16).IsIndeterminate(); - capabilities.SupportsRead16 = !_dev.Read16(out buffer, out senseBuffer, 0, false, false, false, 0, - capabilities.BlockSize ?? 512, 0, 1, false, _dev.Timeout, out _); + capabilities.SupportsRead16 = !_dev.Read16(out buffer, + out senseBuffer, + 0, + false, + false, + false, + 0, + capabilities.BlockSize ?? 512, + 0, + 1, + false, + _dev.Timeout, + out _); }); - AaruConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead16); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Core.Sense_equals_0, !capabilities.SupportsRead16); capabilities.Read16Data = buffer; capabilities.LongBlockSize = capabilities.BlockSize; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ LONG (10)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_LONG_10).IsIndeterminate(); sense = _dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 0xFFFF, _dev.Timeout, out _); }); @@ -908,9 +1063,7 @@ public sealed partial class DeviceReport { DecodedSense? decSense = Sense.Decode(senseBuffer); - if(decSense?.SenseKey == SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && - decSense.Value.ASCQ == 0x00) + if(decSense is { SenseKey: SenseKeys.IllegalRequest, ASC: 0x24, ASCQ: 0x00 }) { capabilities.SupportsReadLong = true; @@ -926,14 +1079,13 @@ public sealed partial class DeviceReport information = (uint)Sense.DecodeDescriptor00(desc00); } - if(valid && ili) - capabilities.LongBlockSize = 0xFFFF - (information & 0xFFFF); + if(valid && ili) capabilities.LongBlockSize = 0xFFFF - (information & 0xFFFF); } } Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying SCSI READ LONG (16)...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_SCSI_READ_LONG_16).IsIndeterminate(); sense = _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 0xFFFF, _dev.Timeout, out _); }); @@ -942,9 +1094,7 @@ public sealed partial class DeviceReport capabilities.SupportsReadLong16 = true; DecodedSense? decSense = Sense.Decode(senseBuffer); - if(decSense?.SenseKey == SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && - decSense.Value.ASCQ == 0x00) + if(decSense is { SenseKey: SenseKeys.IllegalRequest, ASC: 0x24, ASCQ: 0x00 }) { capabilities.SupportsReadLong16 = true; @@ -960,8 +1110,7 @@ public sealed partial class DeviceReport information = (uint)Sense.DecodeDescriptor00(desc00); } - if(valid && ili) - capabilities.LongBlockSize = 0xFFFF - (information & 0xFFFF); + if(valid && ili) capabilities.LongBlockSize = 0xFFFF - (information & 0xFFFF); } } @@ -971,8 +1120,10 @@ public sealed partial class DeviceReport Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask(capabilities.SupportsReadLong16 == true ? "Trying SCSI READ LONG (16)..." - : "Trying SCSI READ LONG (10)...").IsIndeterminate(); + ctx.AddTask(capabilities.SupportsReadLong16 == true + ? Localization.Core.Trying_SCSI_READ_LONG_16 + : Localization.Core.Trying_SCSI_READ_LONG_10) + .IsIndeterminate(); switch(capabilities.BlockSize) { @@ -991,12 +1142,23 @@ public sealed partial class DeviceReport }) { sense = capabilities.SupportsReadLong16 == true - ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, testSize, _dev.Timeout, - out _) : _dev.ReadLong10(out buffer, out senseBuffer, false, - false, 0, testSize, _dev.Timeout, out _); + ? _dev.ReadLong16(out buffer, + out senseBuffer, + false, + 0, + testSize, + _dev.Timeout, + out _) + : _dev.ReadLong10(out buffer, + out senseBuffer, + false, + false, + 0, + testSize, + _dev.Timeout, + out _); - if(sense || _dev.Error) - continue; + if(sense || _dev.Error) continue; capabilities.SupportsReadLong = true; capabilities.LongBlockSize = testSize; @@ -1018,12 +1180,23 @@ public sealed partial class DeviceReport }) { sense = capabilities.SupportsReadLong16 == true - ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, testSize, _dev.Timeout, - out _) : _dev.ReadLong10(out buffer, out senseBuffer, false, - false, 0, testSize, _dev.Timeout, out _); + ? _dev.ReadLong16(out buffer, + out senseBuffer, + false, + 0, + testSize, + _dev.Timeout, + out _) + : _dev.ReadLong10(out buffer, + out senseBuffer, + false, + false, + 0, + testSize, + _dev.Timeout, + out _); - if(sense || _dev.Error) - continue; + if(sense || _dev.Error) continue; capabilities.SupportsReadLong = true; capabilities.LongBlockSize = testSize; @@ -1037,11 +1210,16 @@ public sealed partial class DeviceReport { sense = capabilities.SupportsReadLong16 == true ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 2380, _dev.Timeout, out _) - : _dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 2380, _dev.Timeout, + : _dev.ReadLong10(out buffer, + out senseBuffer, + false, + false, + 0, + 2380, + _dev.Timeout, out _); - if(sense || _dev.Error) - return; + if(sense || _dev.Error) return; capabilities.SupportsReadLong = true; capabilities.LongBlockSize = 2380; @@ -1052,11 +1230,16 @@ public sealed partial class DeviceReport { sense = capabilities.SupportsReadLong16 == true ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 4760, _dev.Timeout, out _) - : _dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 4760, _dev.Timeout, + : _dev.ReadLong10(out buffer, + out senseBuffer, + false, + false, + 0, + 4760, + _dev.Timeout, out _); - if(sense || _dev.Error) - return; + if(sense || _dev.Error) return; capabilities.SupportsReadLong = true; capabilities.LongBlockSize = 4760; @@ -1067,11 +1250,16 @@ public sealed partial class DeviceReport { sense = capabilities.SupportsReadLong16 == true ? _dev.ReadLong16(out buffer, out senseBuffer, false, 0, 9424, _dev.Timeout, out _) - : _dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 9424, _dev.Timeout, + : _dev.ReadLong10(out buffer, + out senseBuffer, + false, + false, + 0, + 9424, + _dev.Timeout, out _); - if(sense || _dev.Error) - return; + if(sense || _dev.Error) return; capabilities.SupportsReadLong = true; capabilities.LongBlockSize = 9424; diff --git a/Aaru.Core/Devices/Report/SecureDigital.cs b/Aaru.Core/Devices/Report/SecureDigital.cs index 884bcbbb0..9f7241d30 100644 --- a/Aaru.Core/Devices/Report/SecureDigital.cs +++ b/Aaru.Core/Devices/Report/SecureDigital.cs @@ -27,16 +27,15 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Report; - -using System; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Metadata; using Aaru.Console; -using global::Spectre.Console; +using Spectre.Console; + +namespace Aaru.Core.Devices.Report; /// Implements creating a device report for a SecureDigital or MultiMediaCard flash card public sealed partial class DeviceReport @@ -46,20 +45,20 @@ public sealed partial class DeviceReport { var report = new MmcSd(); var sense = true; - byte[] cid = Array.Empty(); - byte[] csd = Array.Empty(); - byte[] ecsd = Array.Empty(); - byte[] scr = Array.Empty(); + byte[] cid = []; + byte[] csd = []; + byte[] ecsd = []; + byte[] scr = []; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to get CID...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_get_CID).IsIndeterminate(); sense = _dev.ReadCid(out cid, out _, _dev.Timeout, out _); }); if(!sense) { - AaruConsole.WriteLine("CID obtained correctly..."); + AaruConsole.WriteLine(Localization.Core.CID_obtained_correctly); switch(_dev.Type) { @@ -87,53 +86,44 @@ public sealed partial class DeviceReport report.CID = cid; } else - AaruConsole.WriteLine("Could not read CID..."); + AaruConsole.WriteLine(Localization.Core.Could_not_read_CID); Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to get CSD...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_get_CSD).IsIndeterminate(); sense = _dev.ReadCsd(out csd, out _, _dev.Timeout, out _); }); if(!sense) { - AaruConsole.WriteLine("CSD obtained correctly..."); + AaruConsole.WriteLine(Localization.Core.CSD_obtained_correctly); report.CSD = csd; } else - AaruConsole.WriteLine("Could not read CSD..."); + AaruConsole.WriteLine(Localization.Core.Could_not_read_CSD); sense = true; byte[] ocr = null; Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to get OCR...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_get_OCR).IsIndeterminate(); - switch(_dev.Type) - { - case DeviceType.MMC: - { - sense = _dev.ReadOcr(out ocr, out _, _dev.Timeout, out _); - - break; - } - case DeviceType.SecureDigital: - { - sense = _dev.ReadSdocr(out ocr, out _, _dev.Timeout, out _); - - break; - } - } + sense = _dev.Type switch + { + DeviceType.MMC => _dev.ReadOcr(out ocr, out _, _dev.Timeout, out _), + DeviceType.SecureDigital => _dev.ReadSdocr(out ocr, out _, _dev.Timeout, out _), + _ => sense + }; }); if(!sense) { - AaruConsole.WriteLine("OCR obtained correctly..."); + AaruConsole.WriteLine(Localization.Core.OCR_obtained_correctly); report.OCR = ocr; } else - AaruConsole.WriteLine("Could not read OCR..."); + AaruConsole.WriteLine(Localization.Core.Could_not_read_OCR); switch(_dev.Type) { @@ -141,17 +131,17 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to get Extended CSD...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_get_Extended_CSD).IsIndeterminate(); sense = _dev.ReadExtendedCsd(out ecsd, out _, _dev.Timeout, out _); }); if(!sense) { - AaruConsole.WriteLine("Extended CSD obtained correctly..."); + AaruConsole.WriteLine(Localization.Core.Extended_CSD_obtained_correctly); report.ExtendedCSD = ecsd; } else - AaruConsole.WriteLine("Could not read Extended CSD..."); + AaruConsole.WriteLine(Localization.Core.Could_not_read_Extended_CSD); break; } @@ -159,17 +149,17 @@ public sealed partial class DeviceReport { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Trying to get SCR...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Trying_to_get_SCR).IsIndeterminate(); sense = _dev.ReadScr(out scr, out _, _dev.Timeout, out _); }); if(!sense) { - AaruConsole.WriteLine("SCR obtained correctly..."); + AaruConsole.WriteLine(Localization.Core.SCR_obtained_correctly); report.SCR = scr; } else - AaruConsole.WriteLine("Could not read SCR..."); + AaruConsole.WriteLine(Localization.Core.Could_not_read_SCR); break; } diff --git a/Aaru.Core/Devices/Report/USB.cs b/Aaru.Core/Devices/Report/USB.cs index 8cd4d8c6e..ff864ee06 100644 --- a/Aaru.Core/Devices/Report/USB.cs +++ b/Aaru.Core/Devices/Report/USB.cs @@ -27,13 +27,13 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Report; - using Aaru.CommonTypes.Metadata; +namespace Aaru.Core.Devices.Report; + /// Implements creating a report for a USB device public sealed partial class DeviceReport { diff --git a/Aaru.Core/Devices/Scanning/ATA.cs b/Aaru.Core/Devices/Scanning/ATA.cs index 747fd2ec6..92e92814a 100644 --- a/Aaru.Core/Devices/Scanning/ATA.cs +++ b/Aaru.Core/Devices/Scanning/ATA.cs @@ -27,15 +27,16 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Scanning; - using System; -using System.Collections.Generic; using Aaru.CommonTypes.Structs.Devices.ATA; using Aaru.Core.Logging; +using Humanizer; +using Humanizer.Bytes; + +namespace Aaru.Core.Devices.Scanning; /// Implements scanning the media from an ATA device public sealed partial class MediaScan @@ -54,8 +55,7 @@ public sealed partial class MediaScan bool sense = _dev.AtaIdentify(out byte[] cmdBuf, out _); - if(!sense && - Identify.Decode(cmdBuf).HasValue) + if(!sense && Identify.Decode(cmdBuf).HasValue) { // Initialize reader var ataReader = new Reader(_dev, timeout, cmdBuf, null); @@ -93,20 +93,18 @@ public sealed partial class MediaScan byte heads = ataReader.Heads; byte sectors = ataReader.Sectors; - results.A = 0; // <3ms - results.B = 0; // >=3ms, <10ms - results.C = 0; // >=10ms, <50ms - results.D = 0; // >=50ms, <150ms - results.E = 0; // >=150ms, <500ms - results.F = 0; // >=500ms - results.Errored = 0; - DateTime start; - DateTime end; + results.A = 0; // <3ms + results.B = 0; // >=3ms, <10ms + results.C = 0; // >=10ms, <50ms + results.D = 0; // >=50ms, <150ms + results.E = 0; // >=150ms, <500ms + results.F = 0; // >=500ms + results.Errored = 0; results.ProcessingTime = 0; double currentSpeed = 0; results.MaxSpeed = double.MinValue; results.MinSpeed = double.MaxValue; - results.UnreadableSectors = new List(); + results.UnreadableSectors = []; results.SeekMax = double.MinValue; results.SeekMin = double.MaxValue; results.SeekTotal = 0; @@ -122,52 +120,67 @@ public sealed partial class MediaScan if(ataReader.IsLba) { - UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time, blocksToRead)); InitBlockMap?.Invoke(results.Blocks, blockSize, blocksToRead, ataProfile); mhddLog = new MhddLog(_mhddLogPath, _dev, results.Blocks, blockSize, blocksToRead, false); ibgLog = new IbgLog(_ibgLogPath, ataProfile); - start = DateTime.UtcNow; - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _scanStopwatch.Restart(); + _speedStopwatch.Restart(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ulong i = 0; i < results.Blocks; i += blocksToRead) { - if(_aborted) - break; + if(_aborted) break; - if(results.Blocks - i < blocksToRead) - blocksToRead = (byte)(results.Blocks - i); + if(results.Blocks - i < blocksToRead) blocksToRead = (byte)(results.Blocks - i); - if(currentSpeed > results.MaxSpeed && - currentSpeed > 0) - results.MaxSpeed = currentSpeed; + if(currentSpeed > results.MaxSpeed && currentSpeed > 0) results.MaxSpeed = currentSpeed; - if(currentSpeed < results.MinSpeed && - currentSpeed > 0) - results.MinSpeed = currentSpeed; + if(currentSpeed < results.MinSpeed && currentSpeed > 0) results.MinSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)", - (long)i, (long)results.Blocks); + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + results.Blocks, + ByteSize.FromMegabytes(currentSpeed) + .Per(_oneSecond) + .Humanize()), + (long)i, + (long)results.Blocks); bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration, out _, out _); if(!error) { - if(duration >= 500) - results.F += blocksToRead; - else if(duration >= 150) - results.E += blocksToRead; - else if(duration >= 50) - results.D += blocksToRead; - else if(duration >= 10) - results.C += blocksToRead; - else if(duration >= 3) - results.B += blocksToRead; - else - results.A += blocksToRead; + switch(duration) + { + case >= 500: + results.F += blocksToRead; + + break; + case >= 150: + results.E += blocksToRead; + + break; + case >= 50: + results.D += blocksToRead; + + break; + case >= 10: + results.C += blocksToRead; + + break; + case >= 3: + results.B += blocksToRead; + + break; + default: + results.A += blocksToRead; + + break; + } ScanTime?.Invoke(i, duration); mhddLog.Write(i, duration); @@ -178,8 +191,7 @@ public sealed partial class MediaScan ScanUnreadable?.Invoke(i); results.Errored += blocksToRead; - for(ulong b = i; b < i + blocksToRead; b++) - results.UnreadableSectors.Add(b); + for(ulong b = i; b < i + blocksToRead; b++) results.UnreadableSectors.Add(b); mhddLog.Write(i, duration < 500 ? 65535 : duration); @@ -188,50 +200,51 @@ public sealed partial class MediaScan sectorSpeedStart += blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); ScanSpeed?.Invoke(i, currentSpeed * 1024); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Restart(); } - end = DateTime.UtcNow; + _speedStopwatch.Stop(); + _scanStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, results.Blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, + ibgLog.Close(_dev, + results.Blocks, + blockSize, + _scanStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, blockSize * (double)(results.Blocks + 1) / 1024 / (results.ProcessingTime / 1000), _devicePath); InitProgress?.Invoke(); if(ataReader.CanSeekLba && _seekTest) + { for(var i = 0; i < seekTimes; i++) { - if(_aborted) - break; + if(_aborted) break; var seekPos = (uint)rnd.Next((int)results.Blocks); - PulseProgress?.Invoke($"Seeking to sector {seekPos}...\t\t"); + PulseProgress?.Invoke(string.Format(Localization.Core.Seeking_to_sector_0, seekPos)); ataReader.Seek(seekPos, out seekCur); - if(seekCur > results.SeekMax && - seekCur > 0) - results.SeekMax = seekCur; + if(seekCur > results.SeekMax && seekCur > 0) results.SeekMax = seekCur; - if(seekCur < results.SeekMin && - seekCur > 0) - results.SeekMin = seekCur; + if(seekCur < results.SeekMin && seekCur > 0) results.SeekMin = seekCur; results.SeekTotal += seekCur; GC.Collect(); } + } EndProgress?.Invoke(); } @@ -243,9 +256,9 @@ public sealed partial class MediaScan ulong currentBlock = 0; results.Blocks = (ulong)(cylinders * heads * sectors); - start = DateTime.UtcNow; - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _scanStopwatch.Restart(); + _speedStopwatch.Restart(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ushort cy = 0; cy < cylinders; cy++) @@ -254,36 +267,51 @@ public sealed partial class MediaScan { for(byte sc = 1; sc < sectors; sc++) { - if(_aborted) - break; + if(_aborted) break; - if(currentSpeed > results.MaxSpeed && - currentSpeed > 0) - results.MaxSpeed = currentSpeed; + if(currentSpeed > results.MaxSpeed && currentSpeed > 0) results.MaxSpeed = currentSpeed; - if(currentSpeed < results.MinSpeed && - currentSpeed > 0) - results.MinSpeed = currentSpeed; + if(currentSpeed < results.MinSpeed && currentSpeed > 0) results.MinSpeed = currentSpeed; - PulseProgress?. - Invoke($"Reading cylinder {cy} head {hd} sector {sc} ({currentSpeed:F3} MiB/sec.)"); + PulseProgress?.Invoke(string.Format(Localization.Core.Reading_cylinder_0_head_1_sector_2_3, + cy, + hd, + sc, + ByteSize.FromMegabytes(currentSpeed) + .Per(_oneSecond) + .Humanize())); bool error = ataReader.ReadChs(out cmdBuf, cy, hd, sc, out duration, out _); if(!error) { - if(duration >= 500) - results.F += blocksToRead; - else if(duration >= 150) - results.E += blocksToRead; - else if(duration >= 50) - results.D += blocksToRead; - else if(duration >= 10) - results.C += blocksToRead; - else if(duration >= 3) - results.B += blocksToRead; - else - results.A += blocksToRead; + switch(duration) + { + case >= 500: + results.F += blocksToRead; + + break; + case >= 150: + results.E += blocksToRead; + + break; + case >= 50: + results.D += blocksToRead; + + break; + case >= 10: + results.C += blocksToRead; + + break; + case >= 3: + results.B += blocksToRead; + + break; + default: + results.A += blocksToRead; + + break; + } ScanTime?.Invoke(currentBlock, duration); mhddLog.Write(currentBlock, duration); @@ -302,67 +330,71 @@ public sealed partial class MediaScan sectorSpeedStart++; currentBlock++; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); ScanSpeed?.Invoke(currentBlock, currentSpeed * 1024); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Restart(); } } } - end = DateTime.UtcNow; + _speedStopwatch.Stop(); + _scanStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, results.Blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, + ibgLog.Close(_dev, + results.Blocks, + blockSize, + _scanStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, blockSize * (double)(results.Blocks + 1) / 1024 / (results.ProcessingTime / 1000), _devicePath); InitProgress?.Invoke(); if(ataReader.CanSeek) + { for(var i = 0; i < seekTimes; i++) { - if(_aborted) - break; + if(_aborted) break; var seekCy = (ushort)rnd.Next(cylinders); var seekHd = (byte)rnd.Next(heads); var seekSc = (byte)rnd.Next(sectors); - PulseProgress?.Invoke($"\rSeeking to cylinder {seekCy}, head {seekHd}, sector {seekSc}...\t\t"); + PulseProgress?.Invoke(string.Format(Localization.Core.Seeking_to_cylinder_0_head_1_sector_2, + seekCy, + seekHd, + seekSc)); ataReader.SeekChs(seekCy, seekHd, seekSc, out seekCur); - if(seekCur > results.SeekMax && - seekCur > 0) - results.SeekMax = seekCur; + if(seekCur > results.SeekMax && seekCur > 0) results.SeekMax = seekCur; - if(seekCur < results.SeekMin && - seekCur > 0) - results.SeekMin = seekCur; + if(seekCur < results.SeekMin && seekCur > 0) results.SeekMin = seekCur; results.SeekTotal += seekCur; GC.Collect(); } + } EndProgress?.Invoke(); } results.ProcessingTime /= 1000; - results.TotalTime = (end - start).TotalSeconds; + results.TotalTime = _scanStopwatch.Elapsed.TotalSeconds; results.AvgSpeed = blockSize * (double)(results.Blocks + 1) / 1048576 / results.ProcessingTime; results.SeekTimes = seekTimes; return results; } - StoppingErrorMessage?.Invoke("Unable to communicate with ATA device."); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_communicate_with_ATA_device); return results; } diff --git a/Aaru.Core/Devices/Scanning/MediaScan.cs b/Aaru.Core/Devices/Scanning/MediaScan.cs index 87355e90e..8905aa54f 100644 --- a/Aaru.Core/Devices/Scanning/MediaScan.cs +++ b/Aaru.Core/Devices/Scanning/MediaScan.cs @@ -27,25 +27,31 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Scanning; - using System; +using System.Diagnostics; using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.Devices; +using Humanizer; + +namespace Aaru.Core.Devices.Scanning; public sealed partial class MediaScan { - readonly Device _dev; - readonly string _devicePath; - readonly string _ibgLogPath; - readonly string _mhddLogPath; - readonly bool _seekTest; - readonly bool _useBufferedReads; - bool _aborted; + const string MODULE_NAME = "Media scanning"; + static readonly TimeSpan _oneSecond = 1.Seconds(); + readonly Device _dev; + readonly string _devicePath; + readonly string _ibgLogPath; + readonly string _mhddLogPath; + readonly Stopwatch _scanStopwatch; + readonly bool _seekTest; + readonly Stopwatch _speedStopwatch; + readonly bool _useBufferedReads; + bool _aborted; /// Path to a MHDD log file /// Path to a IMGBurn log file @@ -57,7 +63,7 @@ public sealed partial class MediaScan /// commands /// public MediaScan(string mhddLogPath, string ibgLogPath, string devicePath, Device dev, bool useBufferedReads, - bool seekTest = true) + bool seekTest = true) { _mhddLogPath = mhddLogPath; _ibgLogPath = ibgLogPath; @@ -66,6 +72,8 @@ public sealed partial class MediaScan _aborted = false; _seekTest = seekTest; _useBufferedReads = useBufferedReads; + _scanStopwatch = new Stopwatch(); + _speedStopwatch = new Stopwatch(); } /// Starts a media scan @@ -73,16 +81,14 @@ public sealed partial class MediaScan /// Unknown device type public ScanResults Scan() { - switch(_dev.Type) - { - case DeviceType.ATA: return Ata(); - case DeviceType.MMC: - case DeviceType.SecureDigital: return SecureDigital(); - case DeviceType.NVMe: return Nvme(); - case DeviceType.ATAPI: - case DeviceType.SCSI: return Scsi(); - default: throw new NotSupportedException("Unknown device type."); - } + return _dev.Type switch + { + DeviceType.ATA => Ata(), + DeviceType.MMC or DeviceType.SecureDigital => SecureDigital(), + DeviceType.NVMe => Nvme(), + DeviceType.ATAPI or DeviceType.SCSI => Scsi(), + _ => throw new NotSupportedException(Localization.Core.Unknown_device_type) + }; } /// Aborts the running media scan @@ -90,22 +96,31 @@ public sealed partial class MediaScan /// Event raised when the progress bar is not longer needed public event EndProgressHandler EndProgress; + /// Event raised when a progress bar is needed public event InitProgressHandler InitProgress; + /// Event raised to report status updates public event UpdateStatusHandler UpdateStatus; + /// Event raised to report a fatal error that stops the dumping operation and should call user's attention public event ErrorMessageHandler StoppingErrorMessage; + /// Event raised to update the values of a determinate progress bar public event UpdateProgressHandler UpdateProgress; + /// Event raised to update the status of an indeterminate progress bar public event PulseProgressHandler PulseProgress; + /// Updates lists of time taken on scanning from the specified sector public event ScanTimeHandler ScanTime; + /// Specified a number of blocks could not be read on scan public event ScanUnreadableHandler ScanUnreadable; + /// Initializes a block map that's going to be filled with a media scan public event InitBlockMapHandler InitBlockMap; + /// Sends the speed of scanning a specific sector public event ScanSpeedHandler ScanSpeed; } \ No newline at end of file diff --git a/Aaru.Core/Devices/Scanning/NVMe.cs b/Aaru.Core/Devices/Scanning/NVMe.cs index 3015c3743..7ab351315 100644 --- a/Aaru.Core/Devices/Scanning/NVMe.cs +++ b/Aaru.Core/Devices/Scanning/NVMe.cs @@ -27,7 +27,7 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Core.Devices.Scanning; @@ -36,7 +36,7 @@ public sealed partial class MediaScan { ScanResults Nvme() { - StoppingErrorMessage?.Invoke("NVMe devices not yet supported."); + StoppingErrorMessage?.Invoke(Localization.Core.NVMe_devices_not_yet_supported); return default(ScanResults); } diff --git a/Aaru.Core/Devices/Scanning/SCSI.cs b/Aaru.Core/Devices/Scanning/SCSI.cs index d05281b5a..8f07c0cdc 100644 --- a/Aaru.Core/Devices/Scanning/SCSI.cs +++ b/Aaru.Core/Devices/Scanning/SCSI.cs @@ -27,13 +27,10 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Scanning; - using System; -using System.Collections.Generic; using System.Threading; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Console; @@ -42,6 +39,10 @@ using Aaru.Decoders.CD; using Aaru.Decoders.SCSI; using Aaru.Decoders.SCSI.MMC; using Aaru.Devices; +using Humanizer; +using Humanizer.Bytes; + +namespace Aaru.Core.Devices.Scanning; /// Implements scanning the media from an SCSI device public sealed partial class MediaScan @@ -70,6 +71,7 @@ public sealed partial class MediaScan DecodedSense? decSense = Sense.Decode(senseBuf); if(decSense.HasValue) + { switch(decSense.Value.ASC) { case 0x3A: @@ -78,19 +80,18 @@ public sealed partial class MediaScan while(leftRetries > 0) { - PulseProgress?.Invoke("Waiting for drive to become ready"); + PulseProgress?.Invoke(Localization.Core.Waiting_for_drive_to_become_ready); Thread.Sleep(2000); sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _); - if(!sense) - break; + if(!sense) break; leftRetries--; } if(sense) { - StoppingErrorMessage?.Invoke("Please insert media in drive"); + StoppingErrorMessage?.Invoke(Localization.Core.Please_insert_media_in_drive); return results; } @@ -103,20 +104,20 @@ public sealed partial class MediaScan while(leftRetries > 0) { - PulseProgress?.Invoke("Waiting for drive to become ready"); + PulseProgress?.Invoke(Localization.Core.Waiting_for_drive_to_become_ready); Thread.Sleep(2000); sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _); - if(!sense) - break; + if(!sense) break; leftRetries--; } if(sense) { - StoppingErrorMessage?. - Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}"); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Error_testing_unit_was_ready_0, + Sense.PrettifySense(senseBuf))); return results; } @@ -131,20 +132,20 @@ public sealed partial class MediaScan while(leftRetries > 0) { - PulseProgress?.Invoke("Waiting for drive to become ready"); + PulseProgress?.Invoke(Localization.Core.Waiting_for_drive_to_become_ready); Thread.Sleep(2000); sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _); - if(!sense) - break; + if(!sense) break; leftRetries--; } if(sense) { - StoppingErrorMessage?. - Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}"); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Error_testing_unit_was_ready_0, + Sense.PrettifySense(senseBuf))); return results; } @@ -152,14 +153,15 @@ public sealed partial class MediaScan break; } default: - StoppingErrorMessage?. - Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}"); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_testing_unit_was_ready_0, + Sense.PrettifySense(senseBuf))); return results; } + } else { - StoppingErrorMessage?.Invoke("Unknown testing unit was ready."); + StoppingErrorMessage?.Invoke(Localization.Core.Unknown_sense_testing_unit_was_ready); return results; } @@ -182,52 +184,37 @@ public sealed partial class MediaScan results.Blocks = scsiReader.GetDeviceBlocks(); foundReadCommand = !scsiReader.FindReadCommand(); - if(!foundReadCommand && - _dev.ScsiType != PeripheralDeviceTypes.MultiMediaDevice) + if(!foundReadCommand && _dev.ScsiType != PeripheralDeviceTypes.MultiMediaDevice) { - StoppingErrorMessage?.Invoke("Unable to read medium."); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_read_medium); return results; } blockSize = scsiReader.LogicalBlockSize; - if(results.Blocks != 0 && - blockSize != 0) + if(results.Blocks != 0 && blockSize != 0) { results.Blocks++; - ulong totalSize = results.Blocks * blockSize; - - if(totalSize > 1099511627776) - UpdateStatus?. - Invoke($"Media has {results.Blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1099511627776d:F3} TiB)"); - else if(totalSize > 1073741824) - UpdateStatus?. - Invoke($"Media has {results.Blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1073741824d:F3} GiB)"); - else if(totalSize > 1048576) - UpdateStatus?. - Invoke($"Media has {results.Blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1048576d:F3} MiB)"); - else if(totalSize > 1024) - UpdateStatus?. - Invoke($"Media has {results.Blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1024d:F3} KiB)"); - else - UpdateStatus?. - Invoke($"Media has {results.Blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize} bytes)"); + UpdateStatus?.Invoke(string.Format(Localization.Core + .Media_has_0_blocks_of_1_bytes_each_for_a_total_of_2, + results.Blocks, + blockSize, + ByteSize.FromBytes(results.Blocks * blockSize) + .ToString("0.000"))); } break; case PeripheralDeviceTypes.SequentialAccess: - StoppingErrorMessage?.Invoke("Scanning will never be supported on SCSI Streaming Devices." + - Environment.NewLine + - "It has no sense to do it, and it will put too much strain on the tape."); + StoppingErrorMessage?.Invoke(Localization.Core.Scanning_never_supported_in_SSC); return results; } if(results.Blocks == 0) { - StoppingErrorMessage?.Invoke("Unable to read medium or empty medium present..."); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_read_medium_or_empty_medium_present); return results; } @@ -237,8 +224,12 @@ public sealed partial class MediaScan if(_dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice) { - sense = _dev.GetConfiguration(out byte[] cmdBuf, out senseBuf, 0, MmcGetConfigurationRt.Current, - _dev.Timeout, out _); + sense = _dev.GetConfiguration(out byte[] cmdBuf, + out senseBuf, + 0, + MmcGetConfigurationRt.Current, + _dev.Timeout, + out _); if(!sense) { @@ -254,7 +245,8 @@ public sealed partial class MediaScan case 0x000A: case 0x0020: case 0x0021: - case 0x0022: break; + case 0x0022: + break; default: compactDisc = false; @@ -270,8 +262,7 @@ public sealed partial class MediaScan // No TOC, no CD (or an empty one) bool tocSense = _dev.ReadRawToc(out cmdBuf, out senseBuf, 1, _dev.Timeout, out _); - if(!tocSense) - toc = FullTOC.Decode(cmdBuf); + if(!tocSense) toc = FullTOC.Decode(cmdBuf); } } else @@ -280,21 +271,19 @@ public sealed partial class MediaScan scsiReader.GetBlocksToRead(); uint blocksToRead; - results.A = 0; // <3ms - results.B = 0; // >=3ms, <10ms - results.C = 0; // >=10ms, <50ms - results.D = 0; // >=50ms, <150ms - results.E = 0; // >=150ms, <500ms - results.F = 0; // >=500ms - results.Errored = 0; - DateTime start; - DateTime end; + results.A = 0; // <3ms + results.B = 0; // >=3ms, <10ms + results.C = 0; // >=10ms, <50ms + results.D = 0; // >=50ms, <150ms + results.E = 0; // >=150ms, <500ms + results.F = 0; // >=500ms + results.Errored = 0; results.ProcessingTime = 0; results.TotalTime = 0; double currentSpeed = 0; results.MaxSpeed = double.MinValue; results.MinSpeed = double.MaxValue; - results.UnreadableSectors = new List(); + results.UnreadableSectors = []; if(compactDisc) { @@ -302,83 +291,123 @@ public sealed partial class MediaScan if(toc == null) { - StoppingErrorMessage?.Invoke("Error trying to decode TOC..."); + StoppingErrorMessage?.Invoke(Localization.Core.Error_trying_to_decode_TOC); return results; } - readcd = !_dev.ReadCd(out _, out senseBuf, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, - _dev.Timeout, out _); + readcd = !_dev.ReadCd(out _, + out senseBuf, + 0, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); if(readcd) - UpdateStatus?.Invoke("Using MMC READ CD command."); + UpdateStatus?.Invoke(Localization.Core.Using_MMC_READ_CD_command); else if(!foundReadCommand) { - StoppingErrorMessage?.Invoke("Unable to read medium."); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_read_medium); return results; } - start = DateTime.UtcNow; + _scanStopwatch.Restart(); if(readcd) + { while(true) { - sense = _dev.ReadCd(out _, out senseBuf, 0, 2352, blocksToRead, MmcSectorTypes.AllTypes, false, - false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out _); + sense = _dev.ReadCd(out _, + out senseBuf, + 0, + 2352, + blocksToRead, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out _); - if(_dev.Error || sense) - blocksToRead /= 2; + if(_dev.Error || sense) blocksToRead /= 2; - if(!_dev.Error || - blocksToRead == 1) - break; + if(!_dev.Error || blocksToRead == 1) break; } + } if(_dev.Error) { - StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Device_error_0_trying_to_guess_ideal_transfer_length, + _dev.LastError)); return results; } - UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time, blocksToRead)); InitBlockMap?.Invoke(results.Blocks, blockSize, blocksToRead, currentProfile); mhddLog = new MhddLog(_mhddLogPath, _dev, results.Blocks, blockSize, blocksToRead, false); ibgLog = new IbgLog(_ibgLogPath, currentProfile); - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _speedStopwatch.Restart(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ulong i = 0; i < results.Blocks; i += blocksToRead) { - if(_aborted) - break; + if(_aborted) break; double cmdDuration; - if(results.Blocks - i < blocksToRead) - blocksToRead = (uint)(results.Blocks - i); + if(results.Blocks - i < blocksToRead) blocksToRead = (uint)(results.Blocks - i); - if(currentSpeed > results.MaxSpeed && - currentSpeed > 0) - results.MaxSpeed = currentSpeed; + if(currentSpeed > results.MaxSpeed && currentSpeed > 0) results.MaxSpeed = currentSpeed; - if(currentSpeed < results.MinSpeed && - currentSpeed > 0) - results.MinSpeed = currentSpeed; + if(currentSpeed < results.MinSpeed && currentSpeed > 0) results.MinSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + results.Blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)results.Blocks); if(readcd) - sense = _dev.ReadCd(out _, out senseBuf, (uint)i, 2352, blocksToRead, MmcSectorTypes.AllTypes, - false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, _dev.Timeout, out cmdDuration); + { + sense = _dev.ReadCd(out _, + out senseBuf, + (uint)i, + 2352, + blocksToRead, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, + out cmdDuration); + } else sense = scsiReader.ReadBlocks(out _, i, blocksToRead, out cmdDuration, out _, out _); @@ -386,18 +415,33 @@ public sealed partial class MediaScan if(!sense) { - if(cmdDuration >= 500) - results.F += blocksToRead; - else if(cmdDuration >= 150) - results.E += blocksToRead; - else if(cmdDuration >= 50) - results.D += blocksToRead; - else if(cmdDuration >= 10) - results.C += blocksToRead; - else if(cmdDuration >= 3) - results.B += blocksToRead; - else - results.A += blocksToRead; + switch(cmdDuration) + { + case >= 500: + results.F += blocksToRead; + + break; + case >= 150: + results.E += blocksToRead; + + break; + case >= 50: + results.D += blocksToRead; + + break; + case >= 10: + results.C += blocksToRead; + + break; + case >= 3: + results.B += blocksToRead; + + break; + default: + results.A += blocksToRead; + + break; + } ScanTime?.Invoke(i, cmdDuration); mhddLog.Write(i, cmdDuration); @@ -409,7 +453,9 @@ public sealed partial class MediaScan if(readcd) { - AaruConsole.DebugWriteLine("Media-Scan", "READ CD error:\n{0}", Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_CD_error_0, + Sense.PrettifySense(senseBuf)); senseDecoded = Sense.Decode(senseBuf); @@ -417,6 +463,7 @@ public sealed partial class MediaScan // TODO: This error happens when changing from track type afaik. Need to solve that more cleanly // LOGICAL BLOCK ADDRESS OUT OF RANGE + { if((senseDecoded.Value.ASC != 0x21 || senseDecoded.Value.ASCQ != 0x00) && // ILLEGAL MODE FOR THIS TRACK (requesting sectors as-is, this is a firmware misconception when audio sectors @@ -425,14 +472,14 @@ public sealed partial class MediaScan { results.Errored += blocksToRead; - for(ulong b = i; b < i + blocksToRead; b++) - results.UnreadableSectors.Add(b); + for(ulong b = i; b < i + blocksToRead; b++) results.UnreadableSectors.Add(b); ScanUnreadable?.Invoke(i); mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); ibgLog.Write(i, 0); } + } } if(!senseDecoded.HasValue) @@ -440,8 +487,7 @@ public sealed partial class MediaScan ScanUnreadable?.Invoke(i); results.Errored += blocksToRead; - for(ulong b = i; b < i + blocksToRead; b++) - results.UnreadableSectors.Add(b); + for(ulong b = i; b < i + blocksToRead; b++) results.UnreadableSectors.Add(b); mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); @@ -451,88 +497,102 @@ public sealed partial class MediaScan sectorSpeedStart += blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); ScanSpeed?.Invoke(i, currentSpeed * 1024); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Restart(); } - end = DateTime.UtcNow; + _speedStopwatch.Stop(); + _scanStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - currentSpeed = sectorSpeedStart * blockSize / (1048576 * (end - timeSpeedStart).TotalSeconds); + currentSpeed = sectorSpeedStart * blockSize / (1048576 * _speedStopwatch.Elapsed.TotalSeconds); // ReSharper disable once CompareOfFloatsByEqualityOperator - if(results.MaxSpeed == double.MinValue) - results.MaxSpeed = currentSpeed; + if(results.MaxSpeed == double.MinValue) results.MaxSpeed = currentSpeed; // ReSharper disable once CompareOfFloatsByEqualityOperator - if(results.MinSpeed == double.MaxValue) - results.MinSpeed = currentSpeed; + if(results.MinSpeed == double.MaxValue) results.MinSpeed = currentSpeed; - ibgLog.Close(_dev, results.Blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, + ibgLog.Close(_dev, + results.Blocks, + blockSize, + _scanStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, blockSize * (double)(results.Blocks + 1) / 1024 / (results.ProcessingTime / 1000), _devicePath); } else { - start = DateTime.UtcNow; + _scanStopwatch.Restart(); - UpdateStatus?.Invoke($"Reading {scsiReader.BlocksToRead} sectors at a time."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time, scsiReader.BlocksToRead)); InitBlockMap?.Invoke(results.Blocks, blockSize, scsiReader.BlocksToRead, currentProfile); mhddLog = new MhddLog(_mhddLogPath, _dev, results.Blocks, blockSize, scsiReader.BlocksToRead, false); ibgLog = new IbgLog(_ibgLogPath, currentProfile); - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _speedStopwatch.Restart(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ulong i = 0; i < results.Blocks; i += scsiReader.BlocksToRead) { - if(_aborted) - break; + if(_aborted) break; blocksToRead = scsiReader.BlocksToRead; - if(results.Blocks - i < blocksToRead) - blocksToRead = (uint)(results.Blocks - i); + if(results.Blocks - i < blocksToRead) blocksToRead = (uint)(results.Blocks - i); - if(currentSpeed > results.MaxSpeed && - currentSpeed > 0) - results.MaxSpeed = currentSpeed; + if(currentSpeed > results.MaxSpeed && currentSpeed > 0) results.MaxSpeed = currentSpeed; - if(currentSpeed < results.MinSpeed && - currentSpeed > 0) - results.MinSpeed = currentSpeed; + if(currentSpeed < results.MinSpeed && currentSpeed > 0) results.MinSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + results.Blocks, + ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)results.Blocks); sense = scsiReader.ReadBlocks(out _, i, blocksToRead, out double cmdDuration, out _, out _); results.ProcessingTime += cmdDuration; - if(!sense && - !_dev.Error) + if(!sense && !_dev.Error) { - if(cmdDuration >= 500) - results.F += blocksToRead; - else if(cmdDuration >= 150) - results.E += blocksToRead; - else if(cmdDuration >= 50) - results.D += blocksToRead; - else if(cmdDuration >= 10) - results.C += blocksToRead; - else if(cmdDuration >= 3) - results.B += blocksToRead; - else - results.A += blocksToRead; + switch(cmdDuration) + { + case >= 500: + results.F += blocksToRead; + + break; + case >= 150: + results.E += blocksToRead; + + break; + case >= 50: + results.D += blocksToRead; + + break; + case >= 10: + results.C += blocksToRead; + + break; + case >= 3: + results.B += blocksToRead; + + break; + default: + results.A += blocksToRead; + + break; + } ScanTime?.Invoke(i, cmdDuration); mhddLog.Write(i, cmdDuration); @@ -545,8 +605,7 @@ public sealed partial class MediaScan ScanUnreadable?.Invoke(i); results.Errored += blocksToRead; - for(ulong b = i; b < i + blocksToRead; b++) - results.UnreadableSectors.Add(b); + for(ulong b = i; b < i + blocksToRead; b++) results.UnreadableSectors.Add(b); mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); ibgLog.Write(i, 0); @@ -554,22 +613,26 @@ public sealed partial class MediaScan sectorSpeedStart += blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); ScanSpeed?.Invoke(i, currentSpeed * 1024); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Restart(); } - end = DateTime.UtcNow; + _speedStopwatch.Stop(); + _scanStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, results.Blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, + ibgLog.Close(_dev, + results.Blocks, + blockSize, + _scanStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, blockSize * (double)(results.Blocks + 1) / 1024 / (results.ProcessingTime / 1000), _devicePath); } @@ -585,31 +648,41 @@ public sealed partial class MediaScan for(var i = 0; i < seekTimes; i++) { - if(_aborted || !_seekTest) - break; + if(_aborted || !_seekTest) break; var seekPos = (uint)rnd.Next((int)results.Blocks); - PulseProgress?.Invoke($"Seeking to sector {seekPos}...\t\t"); + PulseProgress?.Invoke(string.Format(Localization.Core.Seeking_to_sector_0, seekPos)); double seekCur; if(scsiReader.CanSeek) scsiReader.Seek(seekPos, out seekCur); else if(readcd) - _dev.ReadCd(out _, out _, seekPos, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, _dev.Timeout, + { + _dev.ReadCd(out _, + out _, + seekPos, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + _dev.Timeout, out seekCur); + } else scsiReader.ReadBlock(out _, seekPos, out seekCur, out _, out _); - if(seekCur > results.SeekMax && - seekCur > 0) - results.SeekMax = seekCur; + if(seekCur > results.SeekMax && seekCur > 0) results.SeekMax = seekCur; - if(seekCur < results.SeekMin && - seekCur > 0) - results.SeekMin = seekCur; + if(seekCur < results.SeekMin && seekCur > 0) results.SeekMin = seekCur; results.SeekTotal += seekCur; GC.Collect(); @@ -618,7 +691,7 @@ public sealed partial class MediaScan EndProgress?.Invoke(); results.ProcessingTime /= 1000; - results.TotalTime = (end - start).TotalSeconds; + results.TotalTime = _scanStopwatch.Elapsed.TotalSeconds; results.AvgSpeed = blockSize * (double)(results.Blocks + 1) / 1048576 / results.ProcessingTime; results.SeekTimes = seekTimes; diff --git a/Aaru.Core/Devices/Scanning/ScanResults.cs b/Aaru.Core/Devices/Scanning/ScanResults.cs index b6f266833..5e810b7ca 100644 --- a/Aaru.Core/Devices/Scanning/ScanResults.cs +++ b/Aaru.Core/Devices/Scanning/ScanResults.cs @@ -27,13 +27,13 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Devices.Scanning; - using System.Collections.Generic; +namespace Aaru.Core.Devices.Scanning; + /// Contains the results of a media scan public struct ScanResults { diff --git a/Aaru.Core/Devices/Scanning/SecureDigital.cs b/Aaru.Core/Devices/Scanning/SecureDigital.cs index 2fc6f9c64..c55f4f76b 100644 --- a/Aaru.Core/Devices/Scanning/SecureDigital.cs +++ b/Aaru.Core/Devices/Scanning/SecureDigital.cs @@ -27,24 +27,22 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable JoinDeclarationAndInitializer -namespace Aaru.Core.Devices.Scanning; - using System; -using System.Collections.Generic; using Aaru.Core.Logging; using Aaru.Decoders.MMC; using Aaru.Decoders.SecureDigital; +using Humanizer; +using Humanizer.Bytes; using CSD = Aaru.Decoders.MMC.CSD; -using Decoders = Aaru.Decoders.MMC.Decoders; using DeviceType = Aaru.CommonTypes.Enums.DeviceType; +namespace Aaru.Core.Devices.Scanning; + /// Implements scanning a SecureDigital or MultiMediaCard flash card public sealed partial class MediaScan { @@ -70,7 +68,7 @@ public sealed partial class MediaScan if(!sense) { - CSD csd = Decoders.DecodeCSD(cmdBuf); + CSD csd = Decoders.MMC.Decoders.DecodeCSD(cmdBuf); results.Blocks = (ulong)((csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2)); blockSize = (uint)Math.Pow(2, csd.ReadBlockLength); @@ -83,14 +81,13 @@ public sealed partial class MediaScan if(!sense) { - ExtendedCSD ecsd = Decoders.DecodeExtendedCSD(cmdBuf); + ExtendedCSD ecsd = Decoders.MMC.Decoders.DecodeExtendedCSD(cmdBuf); results.Blocks = ecsd.SectorCount; blockSize = (uint)(ecsd.SectorSize == 1 ? 4096 : 512); blocksToRead = (ushort)(ecsd.OptimalReadSize * 4096 / blockSize); - if(blocksToRead == 0) - blocksToRead = 128; + if(blocksToRead == 0) blocksToRead = 128; // Supposing it's high-capacity MMC if it has Extended CSD... byteAddressed = false; @@ -107,10 +104,11 @@ public sealed partial class MediaScan if(!sense) { - Aaru.Decoders.SecureDigital.CSD csd = Aaru.Decoders.SecureDigital.Decoders.DecodeCSD(cmdBuf); + Decoders.SecureDigital.CSD csd = Decoders.SecureDigital.Decoders.DecodeCSD(cmdBuf); - results.Blocks = (ulong)(csd.Structure == 0 ? (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2) - : (csd.Size + 1) * 1024); + results.Blocks = (ulong)(csd.Structure == 0 + ? (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2) + : (csd.Size + 1) * 1024); blockSize = (uint)Math.Pow(2, csd.ReadBlockLength); @@ -127,8 +125,11 @@ public sealed partial class MediaScan sense = _dev.ReadScr(out cmdBuf, out _, timeout, out _); if(!sense) - supportsCmd23 = Aaru.Decoders.SecureDigital.Decoders.DecodeSCR(cmdBuf)?.CommandSupport. - HasFlag(CommandSupport.SetBlockCount) ?? false; + { + supportsCmd23 = Decoders.SecureDigital.Decoders.DecodeSCR(cmdBuf) + ?.CommandSupport.HasFlag(CommandSupport.SetBlockCount) ?? + false; + } } break; @@ -137,7 +138,7 @@ public sealed partial class MediaScan if(results.Blocks == 0) { - StoppingErrorMessage?.Invoke("Unable to get device size."); + StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_get_device_size); return results; } @@ -148,7 +149,8 @@ public sealed partial class MediaScan if(sense || _dev.Error) { - UpdateStatus?.Invoke("Environment does not support setting block count, downgrading to OS reading."); + UpdateStatus?.Invoke(Localization.Core + .Environment_does_not_support_setting_block_count_downgrading_to_OS_reading); supportsCmd23 = false; } @@ -158,7 +160,7 @@ public sealed partial class MediaScan if(sense) { - StoppingErrorMessage?.Invoke($"Error {_dev.LastError} reopening device."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core.Error_0_reopening_device, _dev.LastError)); return results; } @@ -168,39 +170,42 @@ public sealed partial class MediaScan { while(true) { - sense = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed, timeout, + sense = _dev.ReadWithBlockCount(out cmdBuf, + out _, + 0, + blockSize, + blocksToRead, + byteAddressed, + timeout, out duration); - if(sense) - blocksToRead /= 2; + if(sense) blocksToRead /= 2; - if(!sense || - blocksToRead == 1) - break; + if(!sense || blocksToRead == 1) break; } if(sense) { - StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length."); + StoppingErrorMessage?.Invoke(string.Format(Localization.Core + .Device_error_0_trying_to_guess_ideal_transfer_length, + _dev.LastError)); return results; } } - results.A = 0; // <3ms - results.B = 0; // >=3ms, <10ms - results.C = 0; // >=10ms, <50ms - results.D = 0; // >=50ms, <150ms - results.E = 0; // >=150ms, <500ms - results.F = 0; // >=500ms - results.Errored = 0; - DateTime start; - DateTime end; + results.A = 0; // <3ms + results.B = 0; // >=3ms, <10ms + results.C = 0; // >=10ms, <50ms + results.D = 0; // >=50ms, <150ms + results.E = 0; // >=150ms, <500ms + results.F = 0; // >=500ms + results.Errored = 0; results.ProcessingTime = 0; double currentSpeed = 0; results.MaxSpeed = double.MinValue; results.MinSpeed = double.MaxValue; - results.UnreadableSectors = new List(); + results.UnreadableSectors = []; results.SeekMax = double.MinValue; results.SeekMin = double.MaxValue; results.SeekTotal = 0; @@ -209,68 +214,110 @@ public sealed partial class MediaScan var rnd = new Random(); if(supportsCmd23 || blocksToRead == 1) - UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time."); + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time, blocksToRead)); else if(_useBufferedReads) - UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time using OS buffered reads."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_at_a_time_using_OS_buffered_reads, + blocksToRead)); + } else - UpdateStatus?.Invoke($"Reading {blocksToRead} sectors using sequential single commands."); + { + UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_sectors_using_sequential_single_commands, + blocksToRead)); + } InitBlockMap?.Invoke(results.Blocks, blockSize, blocksToRead, sdProfile); var mhddLog = new MhddLog(_mhddLogPath, _dev, results.Blocks, blockSize, blocksToRead, false); var ibgLog = new IbgLog(_ibgLogPath, sdProfile); - start = DateTime.UtcNow; - DateTime timeSpeedStart = DateTime.UtcNow; - ulong sectorSpeedStart = 0; + _scanStopwatch.Restart(); + _speedStopwatch.Restart(); + ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for(ulong i = 0; i < results.Blocks; i += blocksToRead) { - if(_aborted) - break; + if(_aborted) break; - if(results.Blocks - i < blocksToRead) - blocksToRead = (byte)(results.Blocks - i); + if(results.Blocks - i < blocksToRead) blocksToRead = (byte)(results.Blocks - i); - if(currentSpeed > results.MaxSpeed && - currentSpeed > 0) - results.MaxSpeed = currentSpeed; + if(currentSpeed > results.MaxSpeed && currentSpeed > 0) results.MaxSpeed = currentSpeed; - if(currentSpeed < results.MinSpeed && - currentSpeed > 0) - results.MinSpeed = currentSpeed; + if(currentSpeed < results.MinSpeed && currentSpeed > 0) results.MinSpeed = currentSpeed; - UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, + UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2, + i, + results.Blocks, + ByteSize.FromBytes(currentSpeed).Per(_oneSecond).Humanize()), + (long)i, (long)results.Blocks); bool error; if(blocksToRead == 1) - error = _dev.ReadSingleBlock(out cmdBuf, out _, (uint)i, blockSize, byteAddressed, timeout, + { + error = _dev.ReadSingleBlock(out cmdBuf, + out _, + (uint)i, + blockSize, + byteAddressed, + timeout, out duration); + } else if(supportsCmd23) - error = _dev.ReadWithBlockCount(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed, - timeout, out duration); + { + error = _dev.ReadWithBlockCount(out cmdBuf, + out _, + (uint)i, + blockSize, + blocksToRead, + byteAddressed, + timeout, + out duration); + } else if(_useBufferedReads) error = _dev.BufferedOsRead(out cmdBuf, (long)(i * blockSize), blockSize * blocksToRead, out duration); else - error = _dev.ReadMultipleUsingSingle(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed, - timeout, out duration); + { + error = _dev.ReadMultipleUsingSingle(out cmdBuf, + out _, + (uint)i, + blockSize, + blocksToRead, + byteAddressed, + timeout, + out duration); + } if(!error) { - if(duration >= 500) - results.F += blocksToRead; - else if(duration >= 150) - results.E += blocksToRead; - else if(duration >= 50) - results.D += blocksToRead; - else if(duration >= 10) - results.C += blocksToRead; - else if(duration >= 3) - results.B += blocksToRead; - else - results.A += blocksToRead; + switch(duration) + { + case >= 500: + results.F += blocksToRead; + + break; + case >= 150: + results.E += blocksToRead; + + break; + case >= 50: + results.D += blocksToRead; + + break; + case >= 10: + results.C += blocksToRead; + + break; + case >= 3: + results.B += blocksToRead; + + break; + default: + results.A += blocksToRead; + + break; + } ScanTime?.Invoke(i, duration); mhddLog.Write(i, duration); @@ -281,8 +328,7 @@ public sealed partial class MediaScan ScanUnreadable?.Invoke(i); results.Errored += blocksToRead; - for(ulong b = i; b < i + blocksToRead; b++) - results.UnreadableSectors.Add(b); + for(ulong b = i; b < i + blocksToRead; b++) results.UnreadableSectors.Add(b); mhddLog.Write(i, duration < 500 ? 65535 : duration); @@ -291,44 +337,44 @@ public sealed partial class MediaScan sectorSpeedStart += blocksToRead; - double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; + double elapsed = _speedStopwatch.Elapsed.TotalSeconds; - if(elapsed <= 0) - continue; + if(elapsed <= 0) continue; currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed); ScanSpeed?.Invoke(i, currentSpeed * 1024); sectorSpeedStart = 0; - timeSpeedStart = DateTime.UtcNow; + _speedStopwatch.Restart(); } - end = DateTime.UtcNow; + _speedStopwatch.Stop(); + _scanStopwatch.Stop(); EndProgress?.Invoke(); mhddLog.Close(); - ibgLog.Close(_dev, results.Blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - blockSize * (double)(results.Blocks + 1) / 1024 / (results.ProcessingTime / 1000), _devicePath); + ibgLog.Close(_dev, + results.Blocks, + blockSize, + _scanStopwatch.Elapsed.TotalSeconds, + currentSpeed * 1024, + blockSize * (double)(results.Blocks + 1) / 1024 / (results.ProcessingTime / 1000), + _devicePath); InitProgress?.Invoke(); for(var i = 0; i < seekTimes; i++) { - if(_aborted || !_seekTest) - break; + if(_aborted || !_seekTest) break; var seekPos = (uint)rnd.Next((int)results.Blocks); - PulseProgress?.Invoke($"Seeking to sector {seekPos}...\t\t"); + PulseProgress?.Invoke(string.Format(Localization.Core.Seeking_to_sector_0, seekPos)); _dev.ReadSingleBlock(out cmdBuf, out _, seekPos, blockSize, byteAddressed, timeout, out double seekCur); - if(seekCur > results.SeekMax && - seekCur > 0) - results.SeekMax = seekCur; + if(seekCur > results.SeekMax && seekCur > 0) results.SeekMax = seekCur; - if(seekCur < results.SeekMin && - seekCur > 0) - results.SeekMin = seekCur; + if(seekCur < results.SeekMin && seekCur > 0) results.SeekMin = seekCur; results.SeekTotal += seekCur; GC.Collect(); @@ -337,7 +383,7 @@ public sealed partial class MediaScan EndProgress?.Invoke(); results.ProcessingTime /= 1000; - results.TotalTime = (end - start).TotalSeconds; + results.TotalTime = _scanStopwatch.Elapsed.TotalSeconds; results.AvgSpeed = blockSize * (double)(results.Blocks + 1) / 1048576 / results.ProcessingTime; results.SeekTimes = seekTimes; diff --git a/Aaru.Core/DiscImageChef.Core.csproj.DotSettings b/Aaru.Core/DiscImageChef.Core.csproj.DotSettings deleted file mode 100644 index 827beb421..000000000 --- a/Aaru.Core/DiscImageChef.Core.csproj.DotSettings +++ /dev/null @@ -1,2 +0,0 @@ - - Experimental \ No newline at end of file diff --git a/Aaru.Core/Entropy.cs b/Aaru.Core/Entropy.cs index cd5b37839..4210427f9 100644 --- a/Aaru.Core/Entropy.cs +++ b/Aaru.Core/Entropy.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; using System.Collections.Generic; using System.Linq; @@ -42,6 +40,8 @@ using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; +namespace Aaru.Core; + /// Media image entropy operations public sealed class Entropy { @@ -59,14 +59,19 @@ public sealed class Entropy /// Event raised when a progress bar is needed public event InitProgressHandler InitProgressEvent; + /// Event raised to update the values of a determinate progress bar public event UpdateProgressHandler UpdateProgressEvent; + /// Event raised when the progress bar is not longer needed public event EndProgressHandler EndProgressEvent; + /// Event raised when a progress bar is needed public event InitProgressHandler InitProgress2Event; + /// Event raised to update the values of a determinate progress bar public event UpdateProgressHandler UpdateProgress2Event; + /// Event raised when the progress bar is not longer needed public event EndProgressHandler EndProgress2Event; @@ -75,11 +80,11 @@ public sealed class Entropy /// Calculated entropy public EntropyResults[] CalculateTracksEntropy(bool duplicatedSectors) { - List entropyResults = new(); + List entropyResults = []; if(_inputFormat is not IOpticalMediaImage opticalMediaImage) { - AaruConsole.ErrorWriteLine("The selected image does not support tracks."); + AaruConsole.ErrorWriteLine(Localization.Core.The_selected_image_does_not_support_tracks); return entropyResults.ToArray(); } @@ -98,30 +103,40 @@ public sealed class Entropy Entropy = 0 }; - UpdateProgressEvent?. - Invoke($"Entropying track {currentTrack.Sequence} of {inputTracks.Max(t => t.Sequence)}", - currentTrack.Sequence, inputTracks.Max(t => t.Sequence)); + UpdateProgressEvent?.Invoke(string.Format(Localization.Core.Entropying_track_0_of_1, + currentTrack.Sequence, + inputTracks.Max(t => t.Sequence)), + currentTrack.Sequence, + inputTracks.Max(t => t.Sequence)); var entTable = new ulong[256]; ulong trackSize = 0; - List uniqueSectorsPerTrack = new(); + List uniqueSectorsPerTrack = []; trackEntropy.Sectors = currentTrack.EndSector - currentTrack.StartSector + 1; - AaruConsole.VerboseWriteLine("Track {0} has {1} sectors", currentTrack.Sequence, trackEntropy.Sectors); + AaruConsole.VerboseWriteLine(Localization.Core.Track_0_has_1_sectors, + currentTrack.Sequence, + trackEntropy.Sectors); InitProgress2Event?.Invoke(); for(ulong i = 0; i < trackEntropy.Sectors; i++) { - UpdateProgress2Event?.Invoke($"Entropying sector {i + 1} of track {currentTrack.Sequence}", - (long)(i + 1), (long)currentTrack.EndSector); + UpdateProgress2Event?.Invoke(string.Format(Localization.Core.Entropying_sector_0_of_track_1, + i + 1, + currentTrack.Sequence), + (long)(i + 1), + (long)currentTrack.EndSector); ErrorNumber errno = opticalMediaImage.ReadSector(i, currentTrack.Sequence, out byte[] sector); if(errno != ErrorNumber.NoError) { - AaruConsole.ErrorWriteLine($"Error {errno} while reading sector {i}, continuing..."); + AaruConsole.ErrorWriteLine(string.Format(Localization.Core + .Error_0_while_reading_sector_1_continuing, + errno, + i)); continue; } @@ -130,23 +145,21 @@ public sealed class Entropy { string sectorHash = Sha1Context.Data(sector, out _); - if(!uniqueSectorsPerTrack.Contains(sectorHash)) - uniqueSectorsPerTrack.Add(sectorHash); + if(!uniqueSectorsPerTrack.Contains(sectorHash)) uniqueSectorsPerTrack.Add(sectorHash); } - foreach(byte b in sector) - entTable[b]++; + foreach(byte b in sector) entTable[b]++; trackSize += (ulong)sector.LongLength; } EndProgress2Event?.Invoke(); - trackEntropy.Entropy += entTable.Select(l => l / (double)trackSize). - Select(frequency => -(frequency * Math.Log(frequency, 2))).Sum(); + trackEntropy.Entropy += entTable.Select(l => l / (double)trackSize) + .Select(frequency => -(frequency * Math.Log(frequency, 2))) + .Sum(); - if(duplicatedSectors) - trackEntropy.UniqueSectors = uniqueSectorsPerTrack.Count; + if(duplicatedSectors) trackEntropy.UniqueSectors = uniqueSectorsPerTrack.Count; entropyResults.Add(trackEntropy); } @@ -156,9 +169,15 @@ public sealed class Entropy catch(Exception ex) { if(_debug) - AaruConsole.DebugWriteLine("Could not get tracks because {0}", ex.Message); + { + AaruConsole.DebugWriteLine(Localization.Core.Could_not_get_tracks_because_0, ex.Message); + AaruConsole.WriteException(ex); + } else - AaruConsole.ErrorWriteLine("Unable to get separate tracks, not calculating their entropy"); + { + AaruConsole.ErrorWriteLine(Localization.Core + .Unable_to_get_separate_tracks_not_calculating_their_entropy); + } } return entropyResults.ToArray(); @@ -174,25 +193,29 @@ public sealed class Entropy Entropy = 0 }; - if(_inputFormat is not IMediaImage mediaImage) - return entropy; + if(_inputFormat is not IMediaImage mediaImage) return entropy; var entTable = new ulong[256]; ulong diskSize = 0; - List uniqueSectors = new(); + List uniqueSectors = []; entropy.Sectors = mediaImage.Info.Sectors; - AaruConsole.WriteLine("Sectors {0}", entropy.Sectors); + AaruConsole.WriteLine(Localization.Core.Sectors_0, entropy.Sectors); InitProgressEvent?.Invoke(); for(ulong i = 0; i < entropy.Sectors; i++) { - UpdateProgressEvent?.Invoke($"Entropying sector {i + 1}", (long)(i + 1), (long)entropy.Sectors); + UpdateProgressEvent?.Invoke(string.Format(Localization.Core.Entropying_sector_0, i + 1), + (long)(i + 1), + (long)entropy.Sectors); + ErrorNumber errno = mediaImage.ReadSector(i, out byte[] sector); if(errno != ErrorNumber.NoError) { - AaruConsole.ErrorWriteLine($"Error {errno} while reading sector {i}, continuing..."); + AaruConsole.ErrorWriteLine(string.Format(Localization.Core.Error_0_while_reading_sector_1_continuing, + errno, + i)); continue; } @@ -201,23 +224,21 @@ public sealed class Entropy { string sectorHash = Sha1Context.Data(sector, out _); - if(!uniqueSectors.Contains(sectorHash)) - uniqueSectors.Add(sectorHash); + if(!uniqueSectors.Contains(sectorHash)) uniqueSectors.Add(sectorHash); } - foreach(byte b in sector) - entTable[b]++; + foreach(byte b in sector) entTable[b]++; diskSize += (ulong)sector.LongLength; } EndProgressEvent?.Invoke(); - entropy.Entropy += entTable.Select(l => l / (double)diskSize). - Select(frequency => -(frequency * Math.Log(frequency, 2))).Sum(); + entropy.Entropy += entTable.Select(l => l / (double)diskSize) + .Select(frequency => -(frequency * Math.Log(frequency, 2))) + .Sum(); - if(duplicatedSectors) - entropy.UniqueSectors = uniqueSectors.Count; + if(duplicatedSectors) entropy.UniqueSectors = uniqueSectors.Count; return entropy; } @@ -231,21 +252,21 @@ public sealed class Entropy Entropy = 0 }; - if(_inputFormat is not IByteAddressableImage byteAddressableImage) - return entropy; + if(_inputFormat is not IByteAddressableImage byteAddressableImage) return entropy; var entTable = new ulong[256]; var data = new byte[byteAddressableImage.Info.Sectors]; entropy.Sectors = _inputFormat.Info.Sectors; - AaruConsole.WriteLine("{0} bytes", entropy.Sectors); + AaruConsole.WriteLine(Localization.Core._0_bytes, entropy.Sectors); InitProgressEvent?.Invoke(); ErrorNumber errno = byteAddressableImage.ReadBytes(data, 0, data.Length, out int bytesRead); if(errno != ErrorNumber.NoError) { - AaruConsole.ErrorWriteLine($"Error {errno} while reading data, not continuing..."); + AaruConsole.ErrorWriteLine(string.Format(Localization.Core.Error_0_while_reading_data__not_continuing, + errno)); return entropy; } @@ -257,13 +278,13 @@ public sealed class Entropy data = tmp; } - foreach(byte b in data) - entTable[b]++; + foreach(byte b in data) entTable[b]++; EndProgressEvent?.Invoke(); - entropy.Entropy += entTable.Select(l => l / (double)data.Length). - Select(frequency => -(frequency * Math.Log(frequency, 2))).Sum(); + entropy.Entropy += entTable.Select(l => l / (double)data.Length) + .Select(frequency => -(frequency * Math.Log(frequency, 2))) + .Sum(); return entropy; } diff --git a/Aaru.Core/Error.cs b/Aaru.Core/Error.cs index a452f9ebd..273a20d64 100644 --- a/Aaru.Core/Error.cs +++ b/Aaru.Core/Error.cs @@ -27,13 +27,13 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using Aaru.CommonTypes.Interop; +namespace Aaru.Core; + /// Prints the description of a system error number. public static class Error { @@ -42,85 +42,85 @@ public static class Error /// Error description. public static string Print(int errno) { - switch(DetectOS.GetRealPlatformID()) - { - case PlatformID.Win32S: - case PlatformID.Win32Windows: - case PlatformID.Win32NT: - case PlatformID.WinCE: - case PlatformID.WindowsPhone: - case PlatformID.Xbox: return PrintWin32Error(errno); - case PlatformID.Unix: - case PlatformID.MacOSX: - case PlatformID.iOS: - case PlatformID.Linux: - case PlatformID.Solaris: - case PlatformID.NetBSD: - case PlatformID.OpenBSD: - case PlatformID.FreeBSD: - case PlatformID.DragonFly: - case PlatformID.Android: - case PlatformID.Tizen: - case PlatformID.Hurd: - case PlatformID.Haiku: - case PlatformID.HPUX: - case PlatformID.AIX: - case PlatformID.OS400: - case PlatformID.IRIX: - case PlatformID.Minix: - case PlatformID.QNX: - case PlatformID.SINIX: - case PlatformID.Tru64: - case PlatformID.Ultrix: - case PlatformID.OpenServer: - case PlatformID.UnixWare: - case PlatformID.zOS: return PrintUnixError(errno); - case PlatformID.Wii: return $"Unknown error code {errno}"; - case PlatformID.WiiU: return $"Unknown error code {errno}"; - case PlatformID.PlayStation3: return $"Unknown error code {errno}"; - case PlatformID.PlayStation4: return $"Unknown error code {errno}"; - case PlatformID.NonStop: return $"Unknown error code {errno}"; - case PlatformID.Unknown: return $"Unknown error code {errno}"; - default: return $"Unknown error code {errno}"; - } + return DetectOS.GetRealPlatformID() switch + { + PlatformID.Win32S + or PlatformID.Win32Windows + or PlatformID.Win32NT + or PlatformID.WinCE + or PlatformID.WindowsPhone + or PlatformID.Xbox => PrintWin32Error(errno), + PlatformID.Unix + or PlatformID.MacOSX + or PlatformID.iOS + or PlatformID.Linux + or PlatformID.Solaris + or PlatformID.NetBSD + or PlatformID.OpenBSD + or PlatformID.FreeBSD + or PlatformID.DragonFly + or PlatformID.Android + or PlatformID.Tizen + or PlatformID.Hurd + or PlatformID.Haiku + or PlatformID.HPUX + or PlatformID.AIX + or PlatformID.OS400 + or PlatformID.IRIX + or PlatformID.Minix + or PlatformID.QNX + or PlatformID.SINIX + or PlatformID.Tru64 + or PlatformID.Ultrix + or PlatformID.OpenServer + or PlatformID.UnixWare + or PlatformID.zOS => PrintUnixError(errno), + PlatformID.Wii => string.Format(Localization.Core.error_code_0, errno), + PlatformID.WiiU => string.Format(Localization.Core.error_code_0, errno), + PlatformID.PlayStation3 => string.Format(Localization.Core.error_code_0, errno), + PlatformID.PlayStation4 => string.Format(Localization.Core.error_code_0, errno), + PlatformID.NonStop => string.Format(Localization.Core.error_code_0, errno), + PlatformID.Unknown => string.Format(Localization.Core.error_code_0, errno), + _ => string.Format(Localization.Core.error_code_0, errno) + }; } static string PrintUnixError(int errno) { - switch(errno) - { - case 2: // ENOENT - case 19: // ENODEV - return "The specified device cannot be found."; - case 13: // EACCESS - return "Not enough permissions to open the device."; - case 16: // EBUSY - return "The specified device is in use by another process."; - case 30: // EROFS - return "Cannot open the device in writable mode, as needed by some commands."; - default: return $"Unknown error code {errno}"; - } + return errno switch + { + 2 or 19 => // ENODEV + // ENOENT + Localization.Core.The_specified_device_cannot_be_found, + 13 => // EACCESS + Localization.Core.Not_enough_permissions_to_open_the_device, + 16 => // EBUSY + Localization.Core.The_specified_device_is_in_use_by_another_process, + 30 => // EROFS + Localization.Core.Cannot_open_the_device_in_writable_mode_as_needed_by_some_commands, + _ => string.Format(Localization.Core.error_code_0, errno) + }; } static string PrintWin32Error(int errno) { - switch(errno) - { - case 2: // ERROR_FILE_NOT_FOUND - case 3: // ERROR_PATH_NOT_FOUND - return "The specified device cannot be found."; - case 5: // ERROR_ACCESS_DENIED - return "Not enough permissions to open the device."; - case 19: // ERROR_WRITE_PROTECT - return "Cannot open the device in writable mode, as needed by some commands."; - case 32: // ERROR_SHARING_VIOLATION - case 33: // ERROR_LOCK_VIOLATION - case 108: // ERROR_DRIVE_LOCKED - case 170: // ERROR_BUSY - return "The specified device is in use by another process."; - case 130: // ERROR_DIRECT_ACCESS_HANDLE - return "Tried to open a file instead of a device."; - default: return $"Unknown error code {errno}"; - } + return errno switch + { + 2 or 3 => // ERROR_PATH_NOT_FOUND + // ERROR_FILE_NOT_FOUND + Localization.Core.The_specified_device_cannot_be_found, + 5 => // ERROR_ACCESS_DENIED + Localization.Core.Not_enough_permissions_to_open_the_device, + 19 => // ERROR_WRITE_PROTECT + Localization.Core.Cannot_open_the_device_in_writable_mode_as_needed_by_some_commands, + 32 or 33 or 108 or 170 => // ERROR_BUSY + // ERROR_DRIVE_LOCKED + // ERROR_LOCK_VIOLATION + // ERROR_SHARING_VIOLATION + Localization.Core.The_specified_device_is_in_use_by_another_process, + 130 => // ERROR_DIRECT_ACCESS_HANDLE + Localization.Core.Tried_to_open_a_file_instead_of_a_device, + _ => string.Format(Localization.Core.error_code_0, errno) + }; } } \ No newline at end of file diff --git a/Aaru.Core/Filesystems.cs b/Aaru.Core/Filesystems.cs index ece142203..fb4de5280 100644 --- a/Aaru.Core/Filesystems.cs +++ b/Aaru.Core/Filesystems.cs @@ -27,15 +27,17 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - +using System; using System.Collections.Generic; using System.Linq; using Aaru.CommonTypes; using Aaru.CommonTypes.Interfaces; +using Aaru.Console; + +namespace Aaru.Core; /// Core filesystem operations public static class Filesystems @@ -49,11 +51,27 @@ public static class Filesystems /// Partition /// Gets plugin GUID public static void Identify(IMediaImage imagePlugin, out List idPlugins, Partition partition, - bool getGuid = false) + bool getGuid = false) { - PluginBase plugins = GetPluginBase.Instance; + PluginRegister plugins = PluginRegister.Singleton; - idPlugins = (from plugin in plugins.PluginsList.Values where plugin.Identify(imagePlugin, partition) - select getGuid ? plugin.Id.ToString() : plugin.Name.ToLower()).ToList(); + idPlugins = []; + + foreach(IFilesystem plugin in plugins.Filesystems.Values.Where(p => p is not null)) + { + try + { + if(plugin.Identify(imagePlugin, partition)) + idPlugins.Add(getGuid ? plugin.Id.ToString() : plugin.Name.ToLower()); + } + catch(Exception ex) + { + AaruConsole + .ErrorWriteLine("Error identifying filesystem {0}. Please open a report with the following line in a Github issue.", + plugin.Name); + + AaruConsole.WriteException(ex); + } + } } } \ No newline at end of file diff --git a/Aaru.Core/Graphics/BlockMap.cs b/Aaru.Core/Graphics/BlockMap.cs new file mode 100644 index 000000000..efe3cb15c --- /dev/null +++ b/Aaru.Core/Graphics/BlockMap.cs @@ -0,0 +1,321 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : BlockMap.cs +// Author(s) : Natalia Portillo +// +// Component : Core algorithms. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General public License for more details. +// +// You should have received a copy of the GNU General public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Aaru.CommonTypes.Interfaces; +using SkiaSharp; + +namespace Aaru.Core.Graphics; + +public class BlockMap : IMediaGraph +{ + readonly SKBitmap _bitmap; + readonly SKCanvas _canvas; + readonly int _columns; + readonly int _sectorsPerSquare; + readonly int _squareSize; + + public BlockMap(int width, int height, ulong maxSectors) + { + _squareSize = 8; + _columns = (width - 1) / (_squareSize + 1); + int rows = (height - 1) / (_squareSize + 1); + int squares = _columns * rows; + + // Check if we can get bigger squares + while(squares - _columns > (long)maxSectors) + { + _squareSize++; + + _columns = (width - 1) / (_squareSize + 1); + rows = (height - 1) / (_squareSize + 1); + squares = _columns * rows; + } + + _sectorsPerSquare = (int)((long)maxSectors / squares); + + while(_sectorsPerSquare > 0 && _squareSize > 4) + { + _squareSize--; + + _columns = (width - 1) / (_squareSize + 1); + rows = (height - 1) / (_squareSize + 1); + squares = _columns * rows; + + _sectorsPerSquare = (int)((long)maxSectors / squares); + } + + var removeSquaresAtLastRow = 0; + var removeRows = 0; + + // If we have spare squares, remove them + if(squares > (long)maxSectors) + { + var removeSquares = (int)(squares - (long)maxSectors); + removeRows = removeSquares / _columns; + removeSquaresAtLastRow = removeSquares % _columns; + } + + float w = _columns * (_squareSize + 1) + 1; + float h = rows * (_squareSize + 1) + 1; + + _bitmap = new SKBitmap((int)w, (int)h); + _canvas = new SKCanvas(_bitmap); + + // Paint background white + _canvas.DrawRect(0, + 0, + w, + h, + new SKPaint + { + Style = SKPaintStyle.StrokeAndFill, + Color = SKColors.White + }); + + // Paint undumped sectors + _canvas.DrawRect(0, + 0, + w, + h - removeRows * (_squareSize + 1) - _squareSize - 2, + new SKPaint + { + Style = SKPaintStyle.StrokeAndFill, + Color = SKColors.Gray + }); + + _canvas.DrawRect(0, + h - removeRows * (_squareSize + 1) - _squareSize - 2, + (_columns - removeSquaresAtLastRow) * (_squareSize + 1), + _squareSize + 2, + new SKPaint + { + Style = SKPaintStyle.StrokeAndFill, + Color = SKColors.Gray + }); + + // Draw grid + for(float y = 0; y < h - removeRows * (_squareSize + 1); y += _squareSize + 1) + { + if(y > h - removeRows * (_squareSize + 1) - (_squareSize + 2)) + { + int cw = _columns - removeSquaresAtLastRow; + + _canvas.DrawLine(0f, + y, + cw * (_squareSize + 1), + y, + new SKPaint + { + StrokeWidth = 1f, + Color = SKColors.Black + }); + } + else + { + _canvas.DrawLine(0f, + y, + w, + y, + new SKPaint + { + StrokeWidth = 1f, + Color = SKColors.Black + }); + } + } + + for(float x = 0; x < w; x += _squareSize + 1) + { + float currentColumn = x / (_squareSize + 1); + + if(_columns - currentColumn + 1 > removeSquaresAtLastRow) + { + _canvas.DrawLine(x, + 0, + x, + h - removeRows * (_squareSize + 1), + new SKPaint + { + StrokeWidth = 1f, + Color = SKColors.Black + }); + } + else + { + _canvas.DrawLine(x, + 0, + x, + h - removeRows * (_squareSize + 1) - _squareSize - 2, + new SKPaint + { + StrokeWidth = 1f, + Color = SKColors.Black + }); + } + } + } + +#region IMediaGraph Members + + /// + public void PaintSectorGood(ulong sector) => PaintSector(sector, SKColors.Green); + + /// + public void PaintSectorBad(ulong sector) => PaintSector(sector, SKColors.Red); + + /// + public void PaintSectorUnknown(ulong sector) => PaintSector(sector, SKColors.Yellow); + + /// + public void PaintSectorUndumped(ulong sector) => PaintSector(sector, SKColors.Gray); + + /// + public void PaintSector(ulong sector, byte red, byte green, byte blue, byte opacity = 255) => + PaintSector(sector, new SKColor(red, green, blue, opacity)); + + /// + public void PaintSectorsUndumped(ulong startingSector, uint length) => + PaintSectors(startingSector, length, SKColors.Gray); + + /// + public void PaintSectorsGood(ulong startingSector, uint length) => + PaintSectors(startingSector, length, SKColors.Green); + + /// + public void PaintSectorsBad(ulong startingSector, uint length) => + PaintSectors(startingSector, length, SKColors.Red); + + /// + public void PaintSectorsUnknown(ulong startingSector, uint length) => + PaintSectors(startingSector, length, SKColors.Yellow); + + /// + public void PaintSectors(ulong startingSector, uint length, byte red, byte green, byte blue, byte opacity = 255) => + PaintSectors(startingSector, length, new SKColor(red, green, blue, opacity)); + + /// + public void PaintSectorsUndumped(IEnumerable sectors) => PaintSectors(sectors, SKColors.Gray); + + /// + public void PaintSectorsGood(IEnumerable sectors) => PaintSectors(sectors, SKColors.Green); + + /// + public void PaintSectorsBad(IEnumerable sectors) => PaintSectors(sectors, SKColors.Red); + + /// + public void PaintSectorsUnknown(IEnumerable sectors) => PaintSectors(sectors, SKColors.Yellow); + + /// + public void PaintSectorsUnknown(IEnumerable sectors, byte red, byte green, byte blue, byte opacity = 255) => + PaintSectors(sectors, new SKColor(red, green, blue, opacity)); + + /// + public void PaintRecordableInformationGood() + { + // Do nothing + } + + /// + public void WriteTo(Stream stream) + { + var image = SKImage.FromBitmap(_bitmap); + SKData data = image.Encode(); + data.SaveTo(stream); + } + + /// + public void WriteTo(string path) + { + using var fs = new FileStream(path, FileMode.Create); + WriteTo(fs); + fs.Close(); + } + +#endregion + + void PaintSector(ulong sector, SKColor color) + { + SKRect rect = + GetSquareRectangle(_sectorsPerSquare == 0 ? (int)sector : (int)(sector / (ulong)_sectorsPerSquare)); + + _canvas.DrawRect(rect, + new SKPaint + { + Style = SKPaintStyle.StrokeAndFill, + Color = color + }); + } + + void PaintSectors(ulong startingSector, uint length, SKColor color) + { + for(ulong sector = startingSector; sector < startingSector + length; sector++) + { + SKRect rect = + GetSquareRectangle(_sectorsPerSquare == 0 ? (int)sector : (int)(sector / (ulong)_sectorsPerSquare)); + + _canvas.DrawRect(rect, + new SKPaint + { + Style = SKPaintStyle.StrokeAndFill, + Color = color + }); + } + } + + void PaintSectors(IEnumerable sectors, SKColor color) + { + foreach(SKRect rect in sectors.Select(sector => GetSquareRectangle(_sectorsPerSquare == 0 + ? (int)sector + : (int)(sector / + (ulong)_sectorsPerSquare)))) + { + _canvas.DrawRect(rect, + new SKPaint + { + Style = SKPaintStyle.StrokeAndFill, + Color = color + }); + } + } + + SKRect GetSquareRectangle(int square) + { + int row = square / _columns; + int column = square % _columns; + + float x = 1 + column * (_squareSize + 1); + float y = 1 + row * (_squareSize + 1); + float xp = x + _squareSize; + float yp = y + _squareSize; + + return new SKRect(x, y, xp, yp); + } +} \ No newline at end of file diff --git a/Aaru.Core/Graphics/Spiral.cs b/Aaru.Core/Graphics/Spiral.cs new file mode 100644 index 000000000..3c09ccc2c --- /dev/null +++ b/Aaru.Core/Graphics/Spiral.cs @@ -0,0 +1,683 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Spiral.cs +// Author(s) : Natalia Portillo +// +// Component : Core algorithms. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General public License for more details. +// +// You should have received a copy of the GNU General public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using Aaru.CommonTypes; +using Aaru.CommonTypes.Interfaces; +using SkiaSharp; + +namespace Aaru.Core.Graphics; + +// TODO: HD DVD sectors are a guess +public sealed class Spiral : IMediaGraph +{ + static readonly DiscParameters _cdParameters = new(120, 15, 33, 46, 50, 116, 0, 0, 360000, SKColors.Silver); + static readonly DiscParameters _cdRecordableParameters = + new(120, 15, 33, 46, 50, 116, 45, 46, 360000, new SKColor(0xBD, 0xA0, 0x00)); + static readonly DiscParameters _cdRewritableParameters = + new(120, 15, 33, 46, 50, 116, 45, 46, 360000, new SKColor(0x50, 0x50, 0x50)); + static readonly DiscParameters _ddcdParameters = new(120, 15, 33, 46, 50, 116, 0, 0, 666000, SKColors.Silver); + static readonly DiscParameters _ddcdRecordableParameters = + new(120, 15, 33, 46, 50, 116, 45, 46, 666000, new SKColor(0xBD, 0xA0, 0x00)); + static readonly DiscParameters _ddcdRewritableParameters = + new(120, 15, 33, 46, 50, 116, 45, 46, 666000, new SKColor(0x50, 0x50, 0x50)); + static readonly DiscParameters _dvdPlusRParameters = + new(120, 15, 33, 46.8f, 48, 116, 46.586f, 46.8f, 2295104, new SKColor(0x6f, 0x0A, 0xCA)); + static readonly DiscParameters _dvdPlusRParameters80 = + new(80, 15, 33, 46.8f, 48, 76, 46.586f, 46.8f, 714544, new SKColor(0x6f, 0x0A, 0xCA)); + static readonly DiscParameters _dvdPlusRwParameters = + new(120, 15, 33, 44, 48, 116, 47.792f, 48, 2295104, new SKColor(0x38, 0x38, 0x38)); + static readonly DiscParameters _dvdPlusRwParameters80 = + new(80, 15, 33, 44, 48, 76, 47.792f, 48, 714544, new SKColor(0x38, 0x38, 0x38)); + static readonly DiscParameters _ps1CdParameters = new(120, 15, 33, 46, 50, 116, 0, 0, 360000, SKColors.Black); + static readonly DiscParameters _ps2CdParameters = + new(120, 15, 33, 46, 50, 116, 0, 0, 360000, new SKColor(0x0c, 0x08, 0xc3)); + static readonly DiscParameters _dvdParameters = new(120, 15, 33, 44, 48, 116, 0, 0, 2294922, SKColors.Silver); + static readonly DiscParameters _dvdParameters80 = new(120, 15, 33, 44, 48, 76, 0, 0, 714544, SKColors.Silver); + static readonly DiscParameters _dvdRParameters = + new(120, 15, 33, 46, 48, 116, 44, 46, 2294922, new SKColor(0x6f, 0x0A, 0xCA)); + static readonly DiscParameters _dvdRParameters80 = + new(80, 15, 33, 46, 48, 76, 44, 46, 712891, new SKColor(0x6f, 0x0A, 0xCA)); + static readonly DiscParameters _dvdRwParameters = + new(120, 15, 33, 46, 48, 116, 44, 46, 2294922, new SKColor(0x38, 0x38, 0x38)); + static readonly DiscParameters _dvdRwParameters80 = + new(80, 15, 33, 46, 48, 76, 44, 46, 712891, new SKColor(0x38, 0x38, 0x38)); + static readonly DiscParameters _bdParameters = + new(120, 15, 33, 44, 48, 116, 0, 0, 12219392, new SKColor(0x80, 0x80, 0x80)); + static readonly DiscParameters _bdRParameters = + new(120, 15, 33, 46, 48, 116, 44, 46, 12219392, new SKColor(0x40, 0x40, 0x40)); + static readonly DiscParameters _bdReParameters = + new(120, 15, 33, 46, 48, 116, 44, 46, 11826176, new SKColor(0x20, 0x20, 0x20)); + static readonly DiscParameters _bdRxlParameters = + new(120, 15, 33, 46, 48, 116, 44, 46, 48878592, new SKColor(0x20, 0x20, 0x20)); + static readonly DiscParameters _hddvdParameters = + new(120, 15, 33, 44, 48, 116, 0, 0, 7864320, new SKColor(0x6f, 0x0A, 0xCA)); + static readonly DiscParameters _hddvdRParameters = + new(120, 15, 33, 46, 48, 116, 44, 46, 7864320, new SKColor(0xff, 0x91, 0x00)); + static readonly DiscParameters _hddvdRwParameters = + new(120, 15, 33, 46, 48, 116, 44, 46, 7864320, new SKColor(0x30, 0x30, 0x30)); + static readonly DiscParameters _umdParameters = + new(60, 11.025f, 16.2f, 28, 32, 56, 0, 0, 471872, new SKColor(0x6f, 0x0A, 0xCA)); + static readonly DiscParameters _gdParameters = new(120, 15, 33, 46, 50, 116, 0, 0, 550000, SKColors.Silver); + static readonly DiscParameters _gdRecordableParameters = + new(120, 15, 33, 46, 50, 116, 45, 46, 550000, new SKColor(0xBD, 0xA0, 0x00)); + readonly SKCanvas _canvas; + readonly bool _gdrom; + readonly List _leadInPoints; + readonly long _maxSector; + readonly List _points; + readonly List _pointsLowDensity; + readonly List _recordableInformationPoints; + + /// Initializes a spiral + /// Width in pixels for the underlying bitmap + /// Height in pixels for the underlying bitmap + /// Disc parameters + /// Last sector that will be drawn into the spiral + public Spiral(int width, int height, DiscParameters parameters, ulong lastSector) + { + if(parameters == _gdParameters || parameters == _gdRecordableParameters) _gdrom = true; + + // GD-ROM LD area ends at 29mm, HD area starts at 30mm radius + + Bitmap = new SKBitmap(width, height); + _canvas = new SKCanvas(Bitmap); + + var center = new SKPoint(width / 2f, height / 2f); + + int smallerDimension = Math.Min(width, height) - 8; + + // Get other diameters + float centerHoleDiameter = smallerDimension * parameters.CenterHole / parameters.DiscDiameter; + float clampingDiameter = smallerDimension * parameters.ClampingMinimum / parameters.DiscDiameter; + + float informationAreaStartDiameter = + smallerDimension * parameters.InformationAreaStart / parameters.DiscDiameter; + + float leadInEndDiameter = smallerDimension * parameters.LeadInEnd / parameters.DiscDiameter; + float informationAreaEndDiameter = smallerDimension * parameters.InformationAreaEnd / parameters.DiscDiameter; + + float recordableAreaStartDiameter = + smallerDimension * parameters.RecordableInformationStart / parameters.DiscDiameter; + + float recordableAreaEndDiameter = + smallerDimension * parameters.RecordableInformationEnd / parameters.DiscDiameter; + + _maxSector = parameters.NominalMaxSectors; + var lastSector1 = (long)lastSector; + + // If the dumped media is overburnt + if(lastSector1 > _maxSector) _maxSector = lastSector1; + + // Ensure the disc hole is not painted over + var clipPath = new SKPath(); + clipPath.AddCircle(center.X, center.Y, centerHoleDiameter / 2); + _canvas.ClipPath(clipPath, SKClipOperation.Difference); + + // Paint CD + _canvas.DrawCircle(center, + smallerDimension / 2f, + new SKPaint + { + Style = SKPaintStyle.StrokeAndFill, + Color = parameters.DiscColor + }); + + // Draw out border of disc + _canvas.DrawCircle(center, + smallerDimension / 2f, + new SKPaint + { + Style = SKPaintStyle.Stroke, + Color = SKColors.Black, + StrokeWidth = 4 + }); + + // Draw disc hole border + _canvas.DrawCircle(center, + centerHoleDiameter / 2f, + new SKPaint + { + Style = SKPaintStyle.Stroke, + Color = SKColors.Black, + StrokeWidth = 4 + }); + + // Draw clamping area + _canvas.DrawCircle(center, + clampingDiameter / 2f, + new SKPaint + { + Style = SKPaintStyle.Stroke, + Color = SKColors.Gray, + StrokeWidth = 4 + }); + + // Some trigonometry thing I do not understand fully but it controls the space between the spiral turns + const float a = 1f; + + // Draw the Lead-In + _leadInPoints = GetSpiralPoints(center, + informationAreaStartDiameter / 2, + leadInEndDiameter / 2, + _gdrom ? a : a * 1.5f); + + var path = new SKPath(); + + path.MoveTo(_leadInPoints[0]); + + foreach(SKPoint point in _leadInPoints) path.LineTo(point); + + _canvas.DrawPath(path, + new SKPaint + { + Style = SKPaintStyle.Stroke, + Color = SKColors.LightGray, + StrokeWidth = 2 + }); + + // If there's a recordable information area, get its points + if(recordableAreaEndDiameter > 0 && recordableAreaStartDiameter > 0) + { + _recordableInformationPoints = GetSpiralPoints(center, + recordableAreaStartDiameter / 2, + recordableAreaEndDiameter / 2, + _gdrom ? a : a * 1.5f); + } + + if(_gdrom) + { + float lowDensityEndDiameter = smallerDimension * 29 * 2 / parameters.DiscDiameter; + float highDensityStartDiameter = smallerDimension * 30 * 2 / parameters.DiscDiameter; + + _pointsLowDensity = GetSpiralPoints(center, leadInEndDiameter / 2, lowDensityEndDiameter / 2, a * 1.5f); + _points = GetSpiralPoints(center, highDensityStartDiameter / 2, informationAreaEndDiameter / 2, a); + } + else + _points = GetSpiralPoints(center, leadInEndDiameter / 2, informationAreaEndDiameter / 2, a); + + path = new SKPath(); + + if(_gdrom && _pointsLowDensity is not null) + { + path.MoveTo(_pointsLowDensity[0]); + + foreach(SKPoint point in _pointsLowDensity) path.LineTo(point); + + _canvas.DrawPath(path, + new SKPaint + { + Style = SKPaintStyle.Stroke, + Color = SKColors.Gray, + StrokeWidth = 2 + }); + } + + path.MoveTo(_points[0]); + + long pointsPerSector; + long sectorsPerPoint; + + if(_gdrom) + { + pointsPerSector = _points.Count / (_maxSector - 45000); + sectorsPerPoint = (_maxSector - 45000) / _points.Count; + + if((_maxSector - 45000) % _points.Count > 0) sectorsPerPoint++; + } + else + { + pointsPerSector = _points.Count / _maxSector; + sectorsPerPoint = _maxSector / _points.Count; + + if(_maxSector % _points.Count > 0) sectorsPerPoint++; + } + + long lastPoint; + + if(_gdrom) lastSector1 -= 45000; + + if(pointsPerSector > 0) + lastPoint = lastSector1 * pointsPerSector; + else + lastPoint = lastSector1 / sectorsPerPoint; + + for(var index = 0; index < lastPoint; index++) + { + SKPoint point = _points[index]; + path.LineTo(point); + } + + _canvas.DrawPath(path, + new SKPaint + { + Style = SKPaintStyle.Stroke, + Color = SKColors.Gray, + StrokeWidth = 2 + }); + } + + public SKBitmap Bitmap { get; } + +#region IMediaGraph Members + + /// + /// Paints the segment of the spiral that corresponds to the specified sector in green + /// Sector + public void PaintSectorGood(ulong sector) => PaintSector(sector, SKColors.Green); + + /// + /// Paints the segment of the spiral that corresponds to the specified sector in red + /// Sector + public void PaintSectorBad(ulong sector) => PaintSector(sector, SKColors.Red); + + /// + /// Paints the segment of the spiral that corresponds to the specified sector in yellow + /// Sector + public void PaintSectorUnknown(ulong sector) => PaintSector(sector, SKColors.Yellow); + + /// + /// Paints the segment of the spiral that corresponds to the specified sector in gray + /// Sector + public void PaintSectorUndumped(ulong sector) => PaintSector(sector, SKColors.Gray); + + /// + public void PaintSector(ulong sector, byte red, byte green, byte blue, byte opacity = 255) => + PaintSector(sector, new SKColor(red, green, blue, opacity)); + + /// + public void PaintSectorsUndumped(ulong startingSector, uint length) => + PaintSectors(startingSector, length, SKColors.Gray); + + /// + public void PaintSectorsGood(ulong startingSector, uint length) => + PaintSectors(startingSector, length, SKColors.Green); + + /// + public void PaintSectorsBad(ulong startingSector, uint length) => + PaintSectors(startingSector, length, SKColors.Red); + + /// + public void PaintSectorsUnknown(ulong startingSector, uint length) => + PaintSectors(startingSector, length, SKColors.Yellow); + + /// + public void PaintSectors(ulong startingSector, uint length, byte red, byte green, byte blue, byte opacity = 255) => + PaintSectors(startingSector, length, new SKColor(red, green, blue, opacity)); + + /// + public void PaintSectorsUndumped(IEnumerable sectors) => PaintSectors(sectors, SKColors.Gray); + + /// + public void PaintSectorsGood(IEnumerable sectors) => PaintSectors(sectors, SKColors.Green); + + /// + public void PaintSectorsBad(IEnumerable sectors) => PaintSectors(sectors, SKColors.Red); + + /// + public void PaintSectorsUnknown(IEnumerable sectors) => PaintSectors(sectors, SKColors.Yellow); + + /// + public void PaintSectorsUnknown(IEnumerable sectors, byte red, byte green, byte blue, byte opacity = 255) => + PaintSectors(sectors, new SKColor(red, green, blue, opacity)); + + /// + /// Paints the segment of the spiral that corresponds to the information specific to recordable discs in green + public void PaintRecordableInformationGood() + { + if(_recordableInformationPoints is null) return; + + var path = new SKPath(); + + path.MoveTo(_recordableInformationPoints[0]); + + foreach(SKPoint point in _recordableInformationPoints) path.LineTo(point); + + _canvas.DrawPath(path, + new SKPaint + { + Style = SKPaintStyle.Stroke, + Color = SKColors.Green, + StrokeWidth = 2 + }); + } + + /// + public void WriteTo(string path) + { + using var fs = new FileStream(path, FileMode.Create); + WriteTo(fs); + fs.Close(); + } + + /// + /// Writes the spiral bitmap as a PNG into the specified stream + /// Stream that will receive the spiral bitmap + public void WriteTo(Stream stream) + { + var image = SKImage.FromBitmap(Bitmap); + SKData data = image.Encode(); + data.SaveTo(stream); + } + +#endregion + + public static DiscParameters DiscParametersFromMediaType(MediaType mediaType, bool smallDisc = false) => + mediaType switch + { + MediaType.CD => _cdParameters, + MediaType.CDDA => _cdParameters, + MediaType.CDG => _cdParameters, + MediaType.CDEG => _cdParameters, + MediaType.CDI => _cdParameters, + MediaType.CDIREADY => _cdParameters, + MediaType.CDROM => _cdParameters, + MediaType.CDROMXA => _cdParameters, + MediaType.CDPLUS => _cdParameters, + MediaType.CDMO => _cdParameters, + MediaType.VCD => _cdParameters, + MediaType.SVCD => _cdParameters, + MediaType.PCD => _cdParameters, + MediaType.DTSCD => _cdParameters, + MediaType.CDMIDI => _cdParameters, + MediaType.CDV => _cdParameters, + MediaType.CDR => _cdRecordableParameters, + MediaType.CDRW => _cdRewritableParameters, + MediaType.CDMRW => _cdRewritableParameters, + MediaType.SACD => _dvdParameters, + MediaType.DVDROM => smallDisc ? _dvdParameters : _dvdParameters80, + MediaType.DVDR => smallDisc ? _dvdRParameters : _dvdRParameters80, + MediaType.DVDRW => smallDisc ? _dvdRwParameters : _dvdRwParameters80, + MediaType.DVDPR => smallDisc ? _dvdPlusRParameters : _dvdPlusRParameters80, + MediaType.DVDPRW => smallDisc ? _dvdPlusRwParameters : _dvdPlusRwParameters80, + MediaType.DVDPRWDL => smallDisc ? _dvdPlusRwParameters : _dvdPlusRwParameters80, + MediaType.DVDRDL => smallDisc ? _dvdRParameters : _dvdRParameters80, + MediaType.DVDPRDL => smallDisc ? _dvdPlusRParameters : _dvdPlusRParameters80, + MediaType.DVDRWDL => smallDisc ? _dvdRwParameters : _dvdRwParameters80, + MediaType.PS1CD => _ps1CdParameters, + MediaType.PS2CD => _ps2CdParameters, + MediaType.PS2DVD => _dvdParameters, + MediaType.PS3DVD => _dvdParameters, + MediaType.XGD => _dvdParameters, + MediaType.XGD2 => _dvdParameters, + MediaType.XGD3 => _dvdParameters, + MediaType.XGD4 => _bdParameters, + MediaType.MEGACD => _cdParameters, + MediaType.SATURNCD => _cdParameters, + MediaType.MilCD => _cdParameters, + MediaType.SuperCDROM2 => _cdParameters, + MediaType.JaguarCD => _cdParameters, + MediaType.ThreeDO => _cdParameters, + MediaType.PCFX => _cdParameters, + MediaType.NeoGeoCD => _cdParameters, + MediaType.CDTV => _cdParameters, + MediaType.CD32 => _cdParameters, + MediaType.Nuon => _dvdParameters, + MediaType.GOD => _dvdParameters80, + MediaType.WOD => _dvdParameters, + MediaType.Pippin => _cdParameters, + MediaType.DDCD => _ddcdParameters, + MediaType.DDCDR => _ddcdRecordableParameters, + MediaType.DDCDRW => _ddcdRewritableParameters, + MediaType.BDROM => _bdParameters, + MediaType.BDR => _bdRParameters, + MediaType.BDRE => _bdReParameters, + MediaType.BDRXL => _bdRxlParameters, + MediaType.PS3BD => _bdParameters, + MediaType.PS4BD => _bdParameters, + MediaType.PS5BD => _bdParameters, + MediaType.HDDVDROM => _hddvdParameters, + MediaType.HDDVDR => _hddvdRParameters, + MediaType.HDDVDRDL => _hddvdRParameters, + MediaType.HDDVDRW => _hddvdRwParameters, + MediaType.HDDVDRWDL => _hddvdRwParameters, + MediaType.CBHD => _hddvdParameters, + MediaType.FMTOWNS => _cdParameters, + MediaType.DVDDownload => _dvdParameters, + MediaType.CVD => _cdParameters, + MediaType.Playdia => _cdParameters, + MediaType.WUOD => _bdParameters, + MediaType.UMD => _umdParameters, + MediaType.GDROM => _gdParameters, + MediaType.GDR => _gdRecordableParameters, + _ => null + }; + + void PaintSectors(ulong startingSector, uint length, SKColor color) + { + for(uint i = 0; i < length; i++) PaintSector(startingSector + i, color); + } + + void PaintSectors(IEnumerable sectors, SKColor color) + { + foreach(ulong sector in sectors) PaintSector(sector, color); + } + + /// Paints the segment of the spiral that corresponds to the specified sector in the specified color + /// Sector + /// Color to paint the segment + void PaintSector(ulong sector, SKColor color) + { + long pointsPerSector; + long sectorsPerPoint; + List points = _gdrom && sector <= 45000 ? _pointsLowDensity : _points; + + if(_gdrom) + { + if(sector <= 45000) + { + pointsPerSector = points.Count / 45000; + sectorsPerPoint = 45000 / points.Count; + + if(45000 % points.Count > 0) sectorsPerPoint++; + } + else + { + sector -= 45000; + pointsPerSector = points.Count / (_maxSector - 45000); + sectorsPerPoint = (_maxSector - 45000) / points.Count; + + if((_maxSector - 45000) % points.Count > 0) sectorsPerPoint++; + } + } + else + { + pointsPerSector = points.Count / _maxSector; + sectorsPerPoint = _maxSector / points.Count; + + if(_maxSector % points.Count > 0) sectorsPerPoint++; + } + + var paint = new SKPaint + { + Style = SKPaintStyle.Stroke, + Color = color, + StrokeWidth = 2 + }; + + var path = new SKPath(); + + if(pointsPerSector > 0) + { + long firstPoint = (long)sector * pointsPerSector; + + path.MoveTo(points[(int)firstPoint]); + + for(var i = (int)firstPoint; i < firstPoint + pointsPerSector; i++) path.LineTo(points[i]); + + _canvas.DrawPath(path, paint); + + return; + } + + long point = (long)sector / sectorsPerPoint; + + if(point == 0) + { + path.MoveTo(points[0]); + path.LineTo(points[1]); + } + else if(point >= points.Count - 1) + { + path.MoveTo(points[^2]); + path.LineTo(points[^1]); + } + else + { + path.MoveTo(points[(int)point]); + path.LineTo(points[(int)point + 1]); + } + + _canvas.DrawPath(path, paint); + } + + /// + /// Paints the segment of the spiral that corresponds to the specified sector of the Lead-In in the specified + /// color + /// + /// Sector + /// Color to paint the segment in + /// Total size of the lead-in in sectors + public void PaintLeadInSector(ulong sector, SKColor color, int leadInSize) + { + long pointsPerSector = _leadInPoints.Count / leadInSize; + long sectorsPerPoint = leadInSize / _leadInPoints.Count; + + if(leadInSize % _leadInPoints.Count > 0) sectorsPerPoint++; + + var paint = new SKPaint + { + Style = SKPaintStyle.Stroke, + Color = color, + StrokeWidth = 2 + }; + + var path = new SKPath(); + + if(pointsPerSector > 0) + { + long firstPoint = (long)sector * pointsPerSector; + + path.MoveTo(_leadInPoints[(int)firstPoint]); + + for(var i = (int)firstPoint; i < firstPoint + pointsPerSector; i++) path.LineTo(_leadInPoints[i]); + + _canvas.DrawPath(path, paint); + + return; + } + + long point = (long)sector / sectorsPerPoint; + + if(point == 0) + { + path.MoveTo(_leadInPoints[0]); + path.LineTo(_leadInPoints[1]); + } + else if(point >= _leadInPoints.Count - 1) + { + path.MoveTo(_leadInPoints[^2]); + path.LineTo(_leadInPoints[^1]); + } + else + { + path.MoveTo(_leadInPoints[(int)point]); + path.LineTo(_leadInPoints[(int)point + 1]); + } + + _canvas.DrawPath(path, paint); + } + + /// Gets all the points that are needed to draw a spiral with the specified parameters + /// Center of the spiral start + /// Minimum radius before which the spiral must have no points + /// Radius at which the spiral will end + /// A constant that decides the position of a point on the spiral + /// List of points to draw the specified spiral + static List GetSpiralPoints(SKPoint center, float minRadius, float maxRadius, float a) + { + // Initialize a list to store the points of the spiral. + List points = []; + const float dtheta = (float)(0.5f * Math.PI / 180); + + for(float theta = 0;; theta += dtheta) + { + // Calculate r. + float r = a * theta; + + if(r < minRadius) continue; + + // Converts polar coordinates (r,theta) to Cartesian (x,y) + var x = (float)(r * Math.Cos(theta)); + var y = (float)(r * Math.Sin(theta)); + + // Adjusts x and y by center coordinates + x += center.X; + y += center.Y; + + // Adds the newly calculated point to the list + points.Add(new SKPoint(x, y)); + + // Terminate the loop if we have reached the end of the spiral + if(r > maxRadius) break; + } + + return points; + } + +#region Nested type: DiscParameters + + /// Defines the physical disc parameters + /// Diameter of the whole disc + /// Diameter of the hole at the center + /// Diameter of the clamping area + /// Diameter at which the information area starts + /// Diameter at which the Lead-In starts + /// Diameter at which the information area ends + /// Diameter at which the information specific to recordable media starts + /// Diameter at which the information specific to recordable media starts + /// Number of maximum sectors, for discs following the specifications + /// Typical disc color + public sealed record DiscParameters + ( + float DiscDiameter, + float CenterHole, + float ClampingMinimum, + float InformationAreaStart, + float LeadInEnd, + float InformationAreaEnd, + float RecordableInformationStart, + float RecordableInformationEnd, + int NominalMaxSectors, + SKColor DiscColor + ); + +#endregion +} \ No newline at end of file diff --git a/Aaru.Core/ImageFormat.cs b/Aaru.Core/ImageFormat.cs index 08d1aefea..839c06a15 100644 --- a/Aaru.Core/ImageFormat.cs +++ b/Aaru.Core/ImageFormat.cs @@ -27,20 +27,21 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; -using System.Linq; using Aaru.CommonTypes; using Aaru.CommonTypes.Interfaces; using Aaru.Console; +namespace Aaru.Core; + /// Core media image format operations public static class ImageFormat { + const string MODULE_NAME = "Format detection"; + /// Detects the image plugin that recognizes the data inside a filter /// Filter /// Detected image plugin @@ -48,75 +49,85 @@ public static class ImageFormat { try { - PluginBase plugins = GetPluginBase.Instance; + PluginRegister plugins = PluginRegister.Singleton; IBaseImage imageFormat = null; // Check all but RAW plugin - foreach(IMediaImage imagePlugin in plugins.ImagePluginsList.Values.Where(imagePlugin => - imagePlugin.Id != new Guid("12345678-AAAA-BBBB-CCCC-123456789000"))) + foreach(IMediaImage imagePlugin in plugins.MediaImages.Values) + { + if(imagePlugin is null) continue; + + if(imagePlugin.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000")) continue; + try { - AaruConsole.DebugWriteLine("Format detection", "Trying plugin {0}", imagePlugin.Name); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Trying_plugin_0, imagePlugin.Name); - if(!imagePlugin.Identify(imageFilter)) - continue; + if(!imagePlugin.Identify(imageFilter)) continue; imageFormat = imagePlugin; break; } - #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch { // ignored } + } - if(imageFormat != null) - return imageFormat; + if(imageFormat != null) return imageFormat; // Check all but RAW plugin - foreach(IByteAddressableImage imagePlugin in plugins.ByteAddressableImages.Values.Where(imagePlugin => - imagePlugin.Id != new Guid("12345678-AAAA-BBBB-CCCC-123456789000"))) + foreach(IByteAddressableImage imagePlugin in plugins.ByteAddressableImages.Values) + { try { - AaruConsole.DebugWriteLine("Format detection", "Trying plugin {0}", imagePlugin.Name); + if(imagePlugin is null) continue; - if(!imagePlugin.Identify(imageFilter)) - continue; + if(imagePlugin.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000")) continue; + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Trying_plugin_0, imagePlugin.Name); + + if(!imagePlugin.Identify(imageFilter)) continue; imageFormat = imagePlugin; break; } - #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch { // ignored } + } - if(imageFormat != null) - return imageFormat; + if(imageFormat != null) return imageFormat; // Check only RAW plugin - foreach(IMediaImage imagePlugin in plugins.ImagePluginsList.Values.Where(imagePlugin => - imagePlugin.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000"))) + foreach(IMediaImage imagePlugin in plugins.MediaImages.Values) + { + if(imagePlugin is null) continue; + + if(imagePlugin.Id != new Guid("12345678-AAAA-BBBB-CCCC-123456789000")) continue; + try { - AaruConsole.DebugWriteLine("Format detection", "Trying plugin {0}", imagePlugin.Name); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Trying_plugin_0, imagePlugin.Name); - if(!imagePlugin.Identify(imageFilter)) - continue; + if(!imagePlugin.Identify(imageFilter)) continue; imageFormat = imagePlugin; break; } - #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch { // ignored } + } // Still not recognized return imageFormat; diff --git a/Aaru.Core/ImageInfo.cs b/Aaru.Core/ImageInfo.cs index 8e228994b..842563af6 100644 --- a/Aaru.Core/ImageInfo.cs +++ b/Aaru.Core/ImageInfo.cs @@ -27,17 +27,16 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; @@ -49,130 +48,167 @@ using Aaru.Decoders.CD; using Aaru.Decoders.DVD; using Aaru.Decoders.PCMCIA; using Aaru.Decoders.SCSI; -using Aaru.Decoders.SecureDigital; using Aaru.Decoders.Xbox; using Aaru.Helpers; -using global::Spectre.Console; -using Schemas; +using Humanizer; +using Humanizer.Bytes; +using Spectre.Console; using DDS = Aaru.Decoders.DVD.DDS; using DMI = Aaru.Decoders.Xbox.DMI; using Inquiry = Aaru.Decoders.SCSI.Inquiry; using Session = Aaru.CommonTypes.Structs.Session; +using Track = Aaru.CommonTypes.Structs.Track; using Tuple = Aaru.Decoders.PCMCIA.Tuple; +namespace Aaru.Core; + /// Image information operations public static class ImageInfo { - const string MANUFACTURER_STRING = "Manufacturer"; - const string MODEL_STRING = "Model"; - const string SERIAL_STRING = "Serial"; - const string SOFTWARE_STRING = "Software"; - const string VERSION_STRING = "Version"; - const string OS_STRING = "Operating system"; - const string START_STRING = "Start"; - const string END_STRING = "End"; + const string MODULE_NAME = "Image information"; /// Prints image information to console /// Media image public static void PrintImageInfo(IBaseImage imageFormat) { - Table table; - - AaruConsole.WriteLine("[bold]Image information:[/]"); + AaruConsole.WriteLine(Localization.Core.Image_information_WithMarkup); if(!string.IsNullOrWhiteSpace(imageFormat.Info.Version)) - AaruConsole.WriteLine("[bold]Format:[/] [italic]{0}[/] version {1}", Markup.Escape(imageFormat.Format), + { + AaruConsole.WriteLine(Localization.Core.Format_0_version_1_WithMarkup, + Markup.Escape(imageFormat.Format), Markup.Escape(imageFormat.Info.Version)); + } else - AaruConsole.WriteLine("[bold]Format:[/] [italic]{0}[/]", Markup.Escape(imageFormat.Format)); + AaruConsole.WriteLine(Localization.Core.Format_0_WithMarkup, Markup.Escape(imageFormat.Format)); - if(!string.IsNullOrWhiteSpace(imageFormat.Info.Application) && - !string.IsNullOrWhiteSpace(imageFormat.Info.ApplicationVersion)) - AaruConsole.WriteLine("Was created with [italic]{0}[/] version [italic]{1}[/]", - Markup.Escape(imageFormat.Info.Application), - Markup.Escape(imageFormat.Info.ApplicationVersion)); - else if(!string.IsNullOrWhiteSpace(imageFormat.Info.Application)) - AaruConsole.WriteLine("Was created with [italic]{0}[/]", Markup.Escape(imageFormat.Info.Application)); + switch(string.IsNullOrWhiteSpace(imageFormat.Info.Application)) + { + case false when !string.IsNullOrWhiteSpace(imageFormat.Info.ApplicationVersion): + AaruConsole.WriteLine(Localization.Core.Was_created_with_0_version_1_WithMarkup, + Markup.Escape(imageFormat.Info.Application), + Markup.Escape(imageFormat.Info.ApplicationVersion)); - AaruConsole.WriteLine("Image without headers is {0} bytes long", imageFormat.Info.ImageSize); + break; + case false: + AaruConsole.WriteLine(Localization.Core.Was_created_with_0_WithMarkup, + Markup.Escape(imageFormat.Info.Application)); - AaruConsole. - WriteLine("Contains a media of {0} sectors with a maximum sector size of {1} bytes (if all sectors are of the same size this would be {2} bytes)", - imageFormat.Info.Sectors, imageFormat.Info.SectorSize, - imageFormat.Info.Sectors * imageFormat.Info.SectorSize); + break; + } + + AaruConsole.WriteLine(Localization.Core.Image_without_headers_is_0_bytes_long, imageFormat.Info.ImageSize); + + AaruConsole.WriteLine(Localization.Core.Contains_a_media_of_0_sectors_with_a_maximum_sector_size_of_1_bytes_etc, + imageFormat.Info.Sectors, + imageFormat.Info.SectorSize, + ByteSize.FromBytes(imageFormat.Info.Sectors * imageFormat.Info.SectorSize).Humanize()); if(!string.IsNullOrWhiteSpace(imageFormat.Info.Creator)) - AaruConsole.WriteLine("[bold]Created by:[/] {0}", Markup.Escape(imageFormat.Info.Creator)); + AaruConsole.WriteLine(Localization.Core.Created_by_0_WithMarkup, Markup.Escape(imageFormat.Info.Creator)); if(imageFormat.Info.CreationTime != DateTime.MinValue) - AaruConsole.WriteLine("Created on {0}", imageFormat.Info.CreationTime); + AaruConsole.WriteLine(Localization.Core.Created_on_0, imageFormat.Info.CreationTime); if(imageFormat.Info.LastModificationTime != DateTime.MinValue) - AaruConsole.WriteLine("Last modified on {0}", imageFormat.Info.LastModificationTime); + AaruConsole.WriteLine(Localization.Core.Last_modified_on_0, imageFormat.Info.LastModificationTime); - AaruConsole.WriteLine("Contains a media of type [italic]{0}[/] and XML type [italic]{1}[/]", - imageFormat.Info.MediaType, imageFormat.Info.XmlMediaType); + AaruConsole.WriteLine(Localization.Core.Contains_a_media_of_type_0_and_XML_type_1_WithMarkup, + imageFormat.Info.MediaType, + imageFormat.Info.MetadataMediaType); - AaruConsole.WriteLine("{0} partitions", imageFormat.Info.HasPartitions ? "Has" : "Doesn't have"); - AaruConsole.WriteLine("{0} sessions", imageFormat.Info.HasSessions ? "Has" : "Doesn't have"); + AaruConsole.WriteLine(imageFormat.Info.HasPartitions + ? Localization.Core.Has_partitions + : Localization.Core.Doesnt_have_partitions); + + AaruConsole.WriteLine(imageFormat.Info.HasSessions + ? Localization.Core.Has_sessions + : Localization.Core.Doesnt_have_sessions); if(!string.IsNullOrWhiteSpace(imageFormat.Info.Comments)) - AaruConsole.WriteLine("[bold]Comments:[/] {0}", Markup.Escape(imageFormat.Info.Comments)); + AaruConsole.WriteLine(Localization.Core.Comments_0_WithMarkup, Markup.Escape(imageFormat.Info.Comments)); - if(imageFormat.Info.MediaSequence != 0 && - imageFormat.Info.LastMediaSequence != 0) - AaruConsole.WriteLine("Media is number {0} on a set of {1} medias", imageFormat.Info.MediaSequence, + if(imageFormat.Info.MediaSequence != 0 && imageFormat.Info.LastMediaSequence != 0) + { + AaruConsole.WriteLine(Localization.Core.Media_is_number_0_on_a_set_of_1_medias, + imageFormat.Info.MediaSequence, imageFormat.Info.LastMediaSequence); + } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaTitle)) - AaruConsole.WriteLine("[bold]Media title:[/] [italic]{0}[/]", Markup.Escape(imageFormat.Info.MediaTitle)); + { + AaruConsole.WriteLine(Localization.Core.Media_title_0_WithMarkup, + Markup.Escape(imageFormat.Info.MediaTitle)); + } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaManufacturer)) - AaruConsole.WriteLine("[bold]Media manufacturer:[/] [italic]{0}[/]", + { + AaruConsole.WriteLine(Localization.Core.Media_manufacturer_0_WithMarkup, Markup.Escape(imageFormat.Info.MediaManufacturer)); + } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaModel)) - AaruConsole.WriteLine("[bold]Media model:[/] [italic]{0}[/]", Markup.Escape(imageFormat.Info.MediaModel)); + { + AaruConsole.WriteLine(Localization.Core.Media_model_0_WithMarkup, + Markup.Escape(imageFormat.Info.MediaModel)); + } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaSerialNumber)) - AaruConsole.WriteLine("[bold]Media serial number:[/] [italic]{0}[/]", + { + AaruConsole.WriteLine(Localization.Core.Media_serial_number_0_WithMarkup, Markup.Escape(imageFormat.Info.MediaSerialNumber)); + } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaBarcode)) - AaruConsole.WriteLine("[bold]Media barcode:[/] [italic]{0}[/]", + { + AaruConsole.WriteLine(Localization.Core.Media_barcode_0_WithMarkup, Markup.Escape(imageFormat.Info.MediaBarcode)); + } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaPartNumber)) - AaruConsole.WriteLine("[bold]Media part number:[/] [italic]{0}[/]", + { + AaruConsole.WriteLine(Localization.Core.Media_part_number_0_WithMarkup, Markup.Escape(imageFormat.Info.MediaPartNumber)); + } if(!string.IsNullOrWhiteSpace(imageFormat.Info.DriveManufacturer)) - AaruConsole.WriteLine("[bold]Drive manufacturer:[/] [italic]{0}[/]", + { + AaruConsole.WriteLine(Localization.Core.Drive_manufacturer_0_WithMarkup, Markup.Escape(imageFormat.Info.DriveManufacturer)); + } if(!string.IsNullOrWhiteSpace(imageFormat.Info.DriveModel)) - AaruConsole.WriteLine("[bold]Drive model:[/] [italic]{0}[/]", Markup.Escape(imageFormat.Info.DriveModel)); + { + AaruConsole.WriteLine(Localization.Core.Drive_model_0_WithMarkup, + Markup.Escape(imageFormat.Info.DriveModel)); + } if(!string.IsNullOrWhiteSpace(imageFormat.Info.DriveSerialNumber)) - AaruConsole.WriteLine("[bold]Drive serial number:[/] [italic]{0}[/]", + { + AaruConsole.WriteLine(Localization.Core.Drive_serial_number_0_WithMarkup, Markup.Escape(imageFormat.Info.DriveSerialNumber)); + } if(!string.IsNullOrWhiteSpace(imageFormat.Info.DriveFirmwareRevision)) - AaruConsole.WriteLine("[bold]Drive firmware info:[/] [italic]{0}[/]", - Markup.Escape(imageFormat.Info.DriveFirmwareRevision)); - - if(imageFormat.Info.Cylinders > 0 && - imageFormat.Info.Heads > 0 && - imageFormat.Info.SectorsPerTrack > 0 && - imageFormat.Info.XmlMediaType != XmlMediaType.OpticalDisc && - (!(imageFormat is ITapeImage tapeImage) || !tapeImage.IsTape)) - AaruConsole.WriteLine("[bold]Media geometry:[/] [italic]{0} cylinders, {1} heads, {2} sectors per track[/]", - imageFormat.Info.Cylinders, imageFormat.Info.Heads, imageFormat.Info.SectorsPerTrack); - - if(imageFormat.Info.ReadableMediaTags != null && - imageFormat.Info.ReadableMediaTags.Count > 0) { - AaruConsole.WriteLine("[bold]Contains {0} readable media tags:[/]", + AaruConsole.WriteLine(Localization.Core.Drive_firmware_info_0_WithMarkup, + Markup.Escape(imageFormat.Info.DriveFirmwareRevision)); + } + + if(imageFormat.Info.Cylinders > 0 && + imageFormat.Info is { Heads: > 0, SectorsPerTrack: > 0 } && + imageFormat.Info.MetadataMediaType != MetadataMediaType.OpticalDisc && + imageFormat is not ITapeImage { IsTape: true }) + { + AaruConsole.WriteLine(Localization.Core.Media_geometry_0_cylinders_1_heads_2_sectors_per_track_WithMarkup, + imageFormat.Info.Cylinders, + imageFormat.Info.Heads, + imageFormat.Info.SectorsPerTrack); + } + + if(imageFormat.Info.ReadableMediaTags is { Count: > 0 }) + { + AaruConsole.WriteLine(Localization.Core.Contains_0_readable_media_tags_WithMarkup, imageFormat.Info.ReadableMediaTags.Count); foreach(MediaTagType tag in imageFormat.Info.ReadableMediaTags.OrderBy(t => t)) @@ -181,10 +217,9 @@ public static class ImageInfo AaruConsole.WriteLine(); } - if(imageFormat.Info.ReadableSectorTags != null && - imageFormat.Info.ReadableSectorTags.Count > 0) + if(imageFormat.Info.ReadableSectorTags is { Count: > 0 }) { - AaruConsole.WriteLine("[bold]Contains {0} readable sector tags:[/]", + AaruConsole.WriteLine(Localization.Core.Contains_0_readable_sector_tags_WithMarkup, imageFormat.Info.ReadableSectorTags.Count); foreach(SectorTagType tag in imageFormat.Info.ReadableSectorTags.OrderBy(t => t)) @@ -195,74 +230,70 @@ public static class ImageInfo AaruConsole.WriteLine(); - if(imageFormat.Info.XmlMediaType == XmlMediaType.LinearMedia) + if(imageFormat.Info.MetadataMediaType == MetadataMediaType.LinearMedia) PrintByteAddressableImageInfo(imageFormat as IByteAddressableImage); else PrintBlockImageInfo(imageFormat as IMediaImage); - if(imageFormat.DumpHardware == null) - return; + if(imageFormat.DumpHardware == null) return; - int manufacturerLen = MANUFACTURER_STRING.Length; - int modelLen = MODEL_STRING.Length; - int serialLen = SERIAL_STRING.Length; - int softwareLen = SOFTWARE_STRING.Length; - int versionLen = VERSION_STRING.Length; - int osLen = OS_STRING.Length; - int sectorLen = START_STRING.Length; + int manufacturerLen = Localization.Core.Title_Manufacturer.Length; + int modelLen = Localization.Core.Title_Model.Length; + int serialLen = Localization.Core.Title_Serial.Length; + int softwareLen = Localization.Core.Title_Software.Length; + int versionLen = Localization.Core.Title_Version.Length; + int osLen = Localization.Core.Title_Operating_system.Length; + int sectorLen = Localization.Core.Title_Start.Length; - foreach(DumpHardwareType dump in imageFormat.DumpHardware) + foreach(DumpHardware dump in imageFormat.DumpHardware) { - if(dump.Manufacturer?.Length > manufacturerLen) - manufacturerLen = dump.Manufacturer.Length; + if(dump.Manufacturer?.Length > manufacturerLen) manufacturerLen = dump.Manufacturer.Length; - if(dump.Model?.Length > modelLen) - modelLen = dump.Model.Length; + if(dump.Model?.Length > modelLen) modelLen = dump.Model.Length; - if(dump.Serial?.Length > serialLen) - serialLen = dump.Serial.Length; + if(dump.Serial?.Length > serialLen) serialLen = dump.Serial.Length; - if(dump.Software?.Name?.Length > softwareLen) - softwareLen = dump.Software.Name.Length; + if(dump.Software?.Name?.Length > softwareLen) softwareLen = dump.Software.Name.Length; - if(dump.Software?.Version?.Length > versionLen) - versionLen = dump.Software.Version.Length; + if(dump.Software?.Version?.Length > versionLen) versionLen = dump.Software.Version.Length; - if(dump.Software?.OperatingSystem?.Length > osLen) - osLen = dump.Software.OperatingSystem.Length; + if(dump.Software?.OperatingSystem?.Length > osLen) osLen = dump.Software.OperatingSystem.Length; - foreach(ExtentType extent in dump.Extents) + foreach(Extent extent in dump.Extents) { - if($"{extent.Start}".Length > sectorLen) - sectorLen = $"{extent.Start}".Length; + if($"{extent.Start}".Length > sectorLen) sectorLen = $"{extent.Start}".Length; - if($"{extent.End}".Length > sectorLen) - sectorLen = $"{extent.End}".Length; + if($"{extent.End}".Length > sectorLen) sectorLen = $"{extent.End}".Length; } } - table = new Table + var table = new Table { - Title = new TableTitle("Dump hardware information") + Title = new TableTitle(Localization.Core.Title_Dump_hardware_information) }; - table.AddColumn(MANUFACTURER_STRING); - table.AddColumn(MODEL_STRING); - table.AddColumn(SERIAL_STRING); - table.AddColumn(SOFTWARE_STRING); - table.AddColumn(VERSION_STRING); - table.AddColumn(OS_STRING); - table.AddColumn(START_STRING); - table.AddColumn(END_STRING); + table.AddColumn(Localization.Core.Title_Manufacturer); + table.AddColumn(Localization.Core.Title_Model); + table.AddColumn(Localization.Core.Title_Serial); + table.AddColumn(Localization.Core.Title_Software); + table.AddColumn(Localization.Core.Title_Version); + table.AddColumn(Localization.Core.Title_Operating_system); + table.AddColumn(Localization.Core.Title_Start); + table.AddColumn(Localization.Core.Title_End); - foreach(DumpHardwareType dump in imageFormat.DumpHardware) + foreach(DumpHardware dump in imageFormat.DumpHardware) { - foreach(ExtentType extent in dump.Extents) - table.AddRow(Markup.Escape(dump.Manufacturer ?? ""), Markup.Escape(dump.Model ?? ""), - Markup.Escape(dump.Serial ?? ""), Markup.Escape(dump.Software.Name ?? ""), - Markup.Escape(dump.Software.Version ?? ""), - Markup.Escape(dump.Software.OperatingSystem ?? ""), extent.Start.ToString(), + foreach(Extent extent in dump.Extents) + { + table.AddRow(Markup.Escape(dump.Manufacturer ?? ""), + Markup.Escape(dump.Model ?? ""), + Markup.Escape(dump.Serial ?? ""), + Markup.Escape(dump.Software.Name ?? ""), + Markup.Escape(dump.Software.Version ?? ""), + Markup.Escape(dump.Software.OperatingSystem ?? ""), + extent.Start.ToString(), extent.End.ToString()); + } } AaruConsole.WriteLine(); @@ -272,20 +303,22 @@ public static class ImageInfo { ErrorNumber errno = imageFormat.GetMappings(out LinearMemoryMap mappings); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; - AaruConsole.WriteLine("[bold]Mapping:[/]"); + AaruConsole.WriteLine(Localization.Core.Mapping_WithMarkup); - AaruConsole.WriteLine("{0}", Markup.Escape(JsonSerializer.Serialize(mappings, new JsonSerializerOptions - { - WriteIndented = true, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - Converters = - { - new JsonStringEnumConverter() - } - }))); + AaruConsole.WriteLine("{0}", + Markup.Escape(JsonSerializer.Serialize(mappings, + new JsonSerializerOptions + { + WriteIndented = true, + DefaultIgnoreCondition = + JsonIgnoreCondition.WhenWritingNull, + Converters = + { + new JsonStringEnumConverter() + } + }))); } static void PrintBlockImageInfo(IMediaImage imageFormat) @@ -308,7 +341,7 @@ public static class ImageInfo Array.Copy(inquiry, 8, scsiVendorId, 0, 8); } - AaruConsole.WriteLine("[bold]SCSI INQUIRY contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.SCSI_INQUIRY_contained_in_image_WithMarkup); AaruConsole.Write("{0}", Inquiry.Prettify(inquiry)); AaruConsole.WriteLine(); } @@ -321,7 +354,7 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]ATA IDENTIFY contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.ATA_IDENTIFY_contained_in_image_WithMarkup); AaruConsole.Write("{0}", Identify.Prettify(identify)); AaruConsole.WriteLine(); } @@ -334,7 +367,7 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]ATAPI IDENTIFY contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.ATAPI_IDENTIFY_contained_in_image_WithMarkup); AaruConsole.Write("{0}", Identify.Prettify(identify)); AaruConsole.WriteLine(); } @@ -351,7 +384,7 @@ public static class ImageInfo if(decMode.HasValue) { - AaruConsole.WriteLine("[bold]SCSI MODE SENSE (10) contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.SCSI_MODE_SENSE_10_contained_in_image_WithMarkup); PrintScsiModePages.Print(decMode.Value, scsiDeviceType, scsiVendorId); AaruConsole.WriteLine(); } @@ -367,7 +400,7 @@ public static class ImageInfo if(decMode.HasValue) { - AaruConsole.WriteLine("[bold]SCSI MODE SENSE (6) contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.SCSI_MODE_SENSE_6_contained_in_image_WithMarkup); PrintScsiModePages.Print(decMode.Value, scsiDeviceType, scsiVendorId); AaruConsole.WriteLine(); } @@ -388,8 +421,7 @@ public static class ImageInfo { errno = imageFormat.ReadMediaTag(MediaTagType.CD_FullTOC, out byte[] toc); - if(errno == ErrorNumber.NoError && - toc.Length > 0) + if(errno == ErrorNumber.NoError && toc.Length > 0) { ushort dataLen = Swapping.Swap(BitConverter.ToUInt16(toc, 0)); @@ -402,7 +434,7 @@ public static class ImageInfo toc = tmp; } - AaruConsole.WriteLine("[bold]CompactDisc Table of Contents contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.CompactDisc_Table_of_Contents_contained_in_image_WithMarkup); AaruConsole.Write("{0}", FullTOC.Prettify(toc)); AaruConsole.WriteLine(); } @@ -412,8 +444,7 @@ public static class ImageInfo { errno = imageFormat.ReadMediaTag(MediaTagType.CD_PMA, out byte[] pma); - if(errno == ErrorNumber.NoError && - pma.Length > 0) + if(errno == ErrorNumber.NoError && pma.Length > 0) { ushort dataLen = Swapping.Swap(BitConverter.ToUInt16(pma, 0)); @@ -426,7 +457,9 @@ public static class ImageInfo pma = tmp; } - AaruConsole.WriteLine("[bold]CompactDisc Power Management Area contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core + .CompactDisc_Power_Management_Area_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", PMA.Prettify(pma)); AaruConsole.WriteLine(); } @@ -451,7 +484,9 @@ public static class ImageInfo atip = tmp; } - AaruConsole.WriteLine("[bold]CompactDisc Absolute Time In Pregroove (ATIP) contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core + .CompactDisc_Absolute_Time_In_Pregroove_ATIP_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", ATIP.Prettify(atip)); AaruConsole.WriteLine(); } @@ -476,7 +511,7 @@ public static class ImageInfo cdtext = tmp; } - AaruConsole.WriteLine("[bold]CompactDisc Lead-in's CD-Text contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.CompactDisc_Lead_in_CD_Text_contained_in_image_WithMarkup); AaruConsole.Write("{0}", CDTextOnLeadIn.Prettify(cdtext)); AaruConsole.WriteLine(); } @@ -488,7 +523,8 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]CompactDisc Media Catalogue Number contained in image:[/] {0}", + AaruConsole.WriteLine(Localization.Core + .CompactDisc_Media_Catalogue_Number_contained_in_image_0_WithMarkup, Encoding.UTF8.GetString(mcn)); AaruConsole.WriteLine(); @@ -501,7 +537,7 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]DVD-R(W) Pre-Recorded Information:[/]"); + AaruConsole.WriteLine(Localization.Core.DVD_RW_Pre_Recorded_Information_WithMarkup); AaruConsole.Write("{0}", PRI.Prettify(pri)); AaruConsole.WriteLine(); } @@ -513,7 +549,7 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]DVD Physical Format Information contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.DVD_Physical_Format_Information_contained_in_image_WithMarkup); AaruConsole.Write("{0}", PFI.Prettify(pfi, imageFormat.Info.MediaType)); AaruConsole.WriteLine(); } @@ -525,7 +561,9 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]DVD-RAM Disc Definition Structure contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core + .DVD_RAM_Disc_Definition_Structure_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", DDS.Prettify(dds)); AaruConsole.WriteLine(); } @@ -537,7 +575,9 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]DVD-R Physical Format Information contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core + .DVD_R_Physical_Format_Information_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", PFI.Prettify(pfi, imageFormat.Info.MediaType)); AaruConsole.WriteLine(); } @@ -549,7 +589,7 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]Bluray Disc Information contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.Bluray_Disc_Information_contained_in_image_WithMarkup); AaruConsole.Write("{0}", DI.Prettify(di)); AaruConsole.WriteLine(); } @@ -561,8 +601,8 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]Bluray Disc Definition Structure contained in image:[/]"); - AaruConsole.Write("{0}", Aaru.Decoders.Bluray.DDS.Prettify(dds)); + AaruConsole.WriteLine(Localization.Core.Bluray_Disc_Definition_Structure_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", Decoders.Bluray.DDS.Prettify(dds)); AaruConsole.WriteLine(); } } @@ -573,15 +613,18 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]PCMCIA CIS:[/]"); + AaruConsole.WriteLine(Localization.Core.PCMCIA_CIS_WithMarkup); Tuple[] tuples = CIS.GetTuples(cis); if(tuples != null) + { foreach(Tuple tuple in tuples) + { switch(tuple.Code) { case TupleCodes.CISTPL_NULL: - case TupleCodes.CISTPL_END: break; + case TupleCodes.CISTPL_END: + break; case TupleCodes.CISTPL_DEVICEGEO: case TupleCodes.CISTPL_DEVICEGEO_A: AaruConsole.WriteLine("{0}", CIS.PrettifyDeviceGeometryTuple(tuple)); @@ -629,18 +672,22 @@ public static class ImageInfo case TupleCodes.CISTPL_SPCL: case TupleCodes.CISTPL_SWIL: case TupleCodes.CISTPL_VERS_2: - AaruConsole.DebugWriteLine("Device-Info command", "Found undecoded tuple ID {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Invoke_Found_undecoded_tuple_ID_0, tuple.Code); break; default: - AaruConsole.DebugWriteLine("Device-Info command", "Found unknown tuple ID 0x{0:X2}", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_unknown_tuple_ID_0, (byte)tuple.Code); break; } + } + } else - AaruConsole.DebugWriteLine("Device-Info command", "Could not get tuples"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Could_not_get_tuples); } } @@ -650,8 +697,8 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]SecureDigital CID contained in image:[/]"); - AaruConsole.Write("{0}", Decoders.PrettifyCID(cid)); + AaruConsole.WriteLine(Localization.Core.SecureDigital_CID_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", Decoders.SecureDigital.Decoders.PrettifyCID(cid)); AaruConsole.WriteLine(); } } @@ -662,8 +709,8 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]SecureDigital CSD contained in image:[/]"); - AaruConsole.Write("{0}", Decoders.PrettifyCSD(csd)); + AaruConsole.WriteLine(Localization.Core.SecureDigital_CSD_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", Decoders.SecureDigital.Decoders.PrettifyCSD(csd)); AaruConsole.WriteLine(); } } @@ -674,8 +721,8 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]SecureDigital SCR contained in image:[/]"); - AaruConsole.Write("{0}", Decoders.PrettifySCR(scr)); + AaruConsole.WriteLine(Localization.Core.SecureDigital_SCR_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", Decoders.SecureDigital.Decoders.PrettifySCR(scr)); AaruConsole.WriteLine(); } } @@ -686,8 +733,8 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]SecureDigital OCR contained in image:[/]"); - AaruConsole.Write("{0}", Decoders.PrettifyOCR(ocr)); + AaruConsole.WriteLine(Localization.Core.SecureDigital_OCR_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", Decoders.SecureDigital.Decoders.PrettifyOCR(ocr)); AaruConsole.WriteLine(); } } @@ -698,8 +745,8 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]MultiMediaCard CID contained in image:[/]"); - AaruConsole.Write("{0}", Aaru.Decoders.MMC.Decoders.PrettifyCID(cid)); + AaruConsole.WriteLine(Localization.Core.MultiMediaCard_CID_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", Decoders.MMC.Decoders.PrettifyCID(cid)); AaruConsole.WriteLine(); } } @@ -710,8 +757,8 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]MultiMediaCard CSD contained in image:[/]"); - AaruConsole.Write("{0}", Aaru.Decoders.MMC.Decoders.PrettifyCSD(csd)); + AaruConsole.WriteLine(Localization.Core.MultiMediaCard_CSD_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", Decoders.MMC.Decoders.PrettifyCSD(csd)); AaruConsole.WriteLine(); } } @@ -722,8 +769,8 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]MultiMediaCard ExtendedCSD contained in image:[/]"); - AaruConsole.Write("{0}", Aaru.Decoders.MMC.Decoders.PrettifyExtendedCSD(ecsd)); + AaruConsole.WriteLine(Localization.Core.MultiMediaCard_Extended_CSD_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", Decoders.MMC.Decoders.PrettifyExtendedCSD(ecsd)); AaruConsole.WriteLine(); } } @@ -734,8 +781,8 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]MultiMediaCard OCR contained in image:[/]"); - AaruConsole.Write("{0}", Aaru.Decoders.MMC.Decoders.PrettifyOCR(ocr)); + AaruConsole.WriteLine(Localization.Core.MultiMediaCard_OCR_contained_in_image_WithMarkup); + AaruConsole.Write("{0}", Decoders.MMC.Decoders.PrettifyOCR(ocr)); AaruConsole.WriteLine(); } } @@ -746,7 +793,7 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]Xbox Physical Format Information contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.Xbox_Physical_Format_Information_contained_in_image_WithMarkup); AaruConsole.Write("{0}", PFI.Prettify(xpfi, imageFormat.Info.MediaType)); AaruConsole.WriteLine(); } @@ -764,7 +811,7 @@ public static class ImageInfo if(xmi.HasValue) { - AaruConsole.WriteLine("[bold]Xbox DMI contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.Xbox_DMI_contained_in_image_WithMarkup); AaruConsole.Write("{0}", DMI.PrettifyXbox(xmi)); AaruConsole.WriteLine(); } @@ -776,7 +823,7 @@ public static class ImageInfo if(xmi.HasValue) { - AaruConsole.WriteLine("[bold]Xbox 360 DMI contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.Xbox_360_DMI_contained_in_image_WithMarkup); AaruConsole.Write("{0}", DMI.PrettifyXbox360(xmi)); AaruConsole.WriteLine(); } @@ -790,35 +837,39 @@ public static class ImageInfo if(errno == ErrorNumber.NoError) { - AaruConsole.WriteLine("[bold]Xbox Security Sectors contained in image:[/]"); + AaruConsole.WriteLine(Localization.Core.Xbox_Security_Sectors_contained_in_image_WithMarkup); AaruConsole.Write("{0}", SS.Prettify(toc)); AaruConsole.WriteLine(); } } - if(imageFormat is not IOpticalMediaImage opticalImage) - return; + if(imageFormat is IFluxImage) AaruConsole.WriteLine(Localization.Core.Image_flux_captures); + + if(imageFormat is not IOpticalMediaImage opticalImage) return; try { - if(opticalImage.Sessions != null && - opticalImage.Sessions.Count > 0) + if(opticalImage.Sessions is { Count: > 0 }) { var table = new Table { - Title = new TableTitle("Image sessions") + Title = new TableTitle(Localization.Core.Title_Image_sessions) }; - table.AddColumn("Session"); - table.AddColumn("First track"); - table.AddColumn("Last track"); - table.AddColumn("Start"); - table.AddColumn("End"); + table.AddColumn(Localization.Core.Title_Session); + table.AddColumn(Localization.Core.Title_First_track); + table.AddColumn(Localization.Core.Title_Last_track); + table.AddColumn(Localization.Core.Title_Start); + table.AddColumn(Localization.Core.Title_End); foreach(Session session in opticalImage.Sessions) - table.AddRow(session.Sequence.ToString(), session.StartTrack.ToString(), - session.EndTrack.ToString(), session.StartSector.ToString(), + { + table.AddRow(session.Sequence.ToString(), + session.StartTrack.ToString(), + session.EndTrack.ToString(), + session.StartSector.ToString(), session.EndSector.ToString()); + } AnsiConsole.Write(table); AaruConsole.WriteLine(); @@ -831,47 +882,54 @@ public static class ImageInfo try { - if(opticalImage.Tracks is not { Count: > 0 }) - return; + if(opticalImage.Tracks is not { Count: > 0 }) return; var table = new Table { - Title = new TableTitle("Image tracks") + Title = new TableTitle(Localization.Core.Title_Image_tracks) }; - table.AddColumn("Track"); - table.AddColumn("Type"); - table.AddColumn("Bps"); - table.AddColumn("Raw bps"); - table.AddColumn("Subchannel"); - table.AddColumn("Pregap"); - table.AddColumn("Start"); - table.AddColumn("End"); + table.AddColumn(Localization.Core.Title_Track); + table.AddColumn(Localization.Core.Title_Type_for_media); + table.AddColumn(Localization.Core.Title_Bps); + table.AddColumn(Localization.Core.Title_Raw_bps); + table.AddColumn(Localization.Core.Title_Subchannel); + table.AddColumn(Localization.Core.Title_Pregap); + table.AddColumn(Localization.Core.Title_Start); + table.AddColumn(Localization.Core.Title_End); foreach(Track track in opticalImage.Tracks) - table.AddRow(track.Sequence.ToString(), track.Type.ToString(), track.BytesPerSector.ToString(), - track.RawBytesPerSector.ToString(), track.SubchannelType.ToString(), - track.Pregap.ToString(), track.StartSector.ToString(), track.EndSector.ToString()); + { + table.AddRow(track.Sequence.ToString(), + track.Type.ToString(), + track.BytesPerSector.ToString(), + track.RawBytesPerSector.ToString(), + track.SubchannelType.ToString(), + track.Pregap.ToString(), + track.StartSector.ToString(), + track.EndSector.ToString()); + } AnsiConsole.Write(table); - if(!opticalImage.Tracks.Any(t => t.Indexes.Any())) - return; + if(!opticalImage.Tracks.Any(t => t.Indexes.Any())) return; AaruConsole.WriteLine(); table = new Table { - Title = new TableTitle("Image indexes") + Title = new TableTitle(Localization.Core.Title_Image_indexes) }; - table.AddColumn("Track"); - table.AddColumn("Index"); - table.AddColumn("Start"); + table.AddColumn(Localization.Core.Title_Track); + table.AddColumn(Localization.Core.Title_Index); + table.AddColumn(Localization.Core.Title_Start); foreach(Track track in opticalImage.Tracks) + { foreach(KeyValuePair index in track.Indexes) table.AddRow(track.Sequence.ToString(), index.Key.ToString(), index.Value.ToString()); + } AnsiConsole.Write(table); } diff --git a/Aaru.Core/Logging/DumpLog.cs b/Aaru.Core/Logging/DumpLog.cs index 6184b888e..c3765c440 100644 --- a/Aaru.Core/Logging/DumpLog.cs +++ b/Aaru.Core/Logging/DumpLog.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Logging; - using System; using System.IO; using System.Reflection; @@ -41,6 +39,8 @@ using Aaru.Devices; using PlatformID = Aaru.CommonTypes.Interop.PlatformID; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Core.Logging; + /// Creates a dump log public sealed class DumpLog { @@ -52,12 +52,11 @@ public sealed class DumpLog /// Disable saving paths or serial numbers in log public DumpLog(string outputFile, Device dev, bool @private) { - if(string.IsNullOrEmpty(outputFile)) - return; + if(string.IsNullOrEmpty(outputFile)) return; _logSw = new StreamWriter(outputFile, true); - _logSw.WriteLine("Start logging at {0}", DateTime.Now); + _logSw.WriteLine(Localization.Core.Start_logging_at_0, DateTime.Now); PlatformID platId = DetectOS.GetRealPlatformID(); string platVer = DetectOS.GetVersion(); @@ -66,9 +65,11 @@ public sealed class DumpLog Attribute.GetCustomAttribute(typeof(DumpLog).Assembly, typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute; - _logSw.WriteLine("################# System information #################"); + _logSw.WriteLine(Localization.Core.System_information); - _logSw.WriteLine("{0} {1} ({2}-bit)", DetectOS.GetPlatformName(platId, platVer), platVer, + _logSw.WriteLine("{0} {1} ({2}-bit)", + DetectOS.GetPlatformName(platId, platVer), + platVer, Environment.Is64BitOperatingSystem ? 64 : 32); if(DetectOS.IsMono) @@ -80,20 +81,23 @@ public sealed class DumpLog _logSw.WriteLine(); - _logSw.WriteLine("################# Program information ################"); - _logSw.WriteLine("Aaru {0}", assemblyVersion?.InformationalVersion); - _logSw.WriteLine("Running in {0}-bit", Environment.Is64BitProcess ? 64 : 32); - _logSw.WriteLine("Running as superuser: {0}", DetectOS.IsAdmin ? "Yes" : "No"); - #if DEBUG - _logSw.WriteLine("DEBUG version"); - #endif + _logSw.WriteLine(Localization.Core.Program_information); + _logSw.WriteLine("Aaru {0}", assemblyVersion?.InformationalVersion); + _logSw.WriteLine(Localization.Core.Running_in_0_bit, Environment.Is64BitProcess ? 64 : 32); + + _logSw.WriteLine(DetectOS.IsAdmin + ? Localization.Core.Running_as_superuser_Yes + : Localization.Core.Running_as_superuser_No); +#if DEBUG + _logSw.WriteLine(Localization.Core.DEBUG_version); +#endif if(@private) { string[] args = Environment.GetCommandLineArgs(); for(var i = 0; i < args.Length; i++) { - if(args[i].StartsWith("/dev", StringComparison.OrdinalIgnoreCase) || + if(args[i].StartsWith("/dev", StringComparison.OrdinalIgnoreCase) || args[i].StartsWith("aaru://", StringComparison.OrdinalIgnoreCase)) continue; @@ -107,72 +111,74 @@ public sealed class DumpLog } } - _logSw.WriteLine("Command line: {0}", string.Join(" ", args)); + _logSw.WriteLine(Localization.Core.Command_line_0, string.Join(" ", args)); } else - _logSw.WriteLine("Command line: {0}", Environment.CommandLine); + _logSw.WriteLine(Localization.Core.Command_line_0, Environment.CommandLine); _logSw.WriteLine(); if(dev is Aaru.Devices.Remote.Device remoteDev) { - _logSw.WriteLine("################# Remote information #################"); - _logSw.WriteLine("Server: {0}", remoteDev.RemoteApplication); - _logSw.WriteLine("Version: {0}", remoteDev.RemoteVersion); + _logSw.WriteLine(Localization.Core.Remote_information); + _logSw.WriteLine(Localization.Core.Server_0, remoteDev.RemoteApplication); + _logSw.WriteLine(Localization.Core.Version_0, remoteDev.RemoteVersion); - _logSw.WriteLine("Operating system: {0} {1}", remoteDev.RemoteOperatingSystem, + _logSw.WriteLine(Localization.Core.Operating_system_0_1, + remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion); - _logSw.WriteLine("Architecture: {0}", remoteDev.RemoteArchitecture); - _logSw.WriteLine("Protocol version: {0}", remoteDev.RemoteProtocolVersion); - _logSw.WriteLine("Running as superuser: {0}", remoteDev.IsAdmin ? "Yes" : "No"); - _logSw.WriteLine("######################################################"); + _logSw.WriteLine(Localization.Core.Architecture_0, remoteDev.RemoteArchitecture); + _logSw.WriteLine(Localization.Core.Protocol_version_0, remoteDev.RemoteProtocolVersion); + + _logSw.WriteLine(DetectOS.IsAdmin + ? Localization.Core.Running_as_superuser_Yes + : Localization.Core.Running_as_superuser_No); + + _logSw.WriteLine(Localization.Core.Log_section_separator); } - _logSw.WriteLine("################# Device information #################"); - _logSw.WriteLine("Manufacturer: {0}", dev.Manufacturer); - _logSw.WriteLine("Model: {0}", dev.Model); - _logSw.WriteLine("Firmware revision: {0}", dev.FirmwareRevision); + _logSw.WriteLine(Localization.Core.Device_information); + _logSw.WriteLine(Localization.Core.Manufacturer_0, dev.Manufacturer); + _logSw.WriteLine(Localization.Core.Model_0, dev.Model); + _logSw.WriteLine(Localization.Core.Firmware_revision_0, dev.FirmwareRevision); - if(!@private) - _logSw.WriteLine("Serial number: {0}", dev.Serial); + if(!@private) _logSw.WriteLine(Localization.Core.Serial_number_0, dev.Serial); - _logSw.WriteLine("Removable device: {0}", dev.IsRemovable); - _logSw.WriteLine("Device type: {0}", dev.Type); - _logSw.WriteLine("CompactFlash device: {0}", dev.IsCompactFlash); - _logSw.WriteLine("PCMCIA device: {0}", dev.IsPcmcia); - _logSw.WriteLine("USB device: {0}", dev.IsUsb); + _logSw.WriteLine(Localization.Core.Removable_device_0, dev.IsRemovable); + _logSw.WriteLine(Localization.Core.Device_type_0, dev.Type); + _logSw.WriteLine(Localization.Core.CompactFlash_device_0, dev.IsCompactFlash); + _logSw.WriteLine(Localization.Core.PCMCIA_device_0, dev.IsPcmcia); + _logSw.WriteLine(Localization.Core.USB_device_0, dev.IsUsb); if(dev.IsUsb) { - _logSw.WriteLine("USB manufacturer: {0}", dev.UsbManufacturerString); - _logSw.WriteLine("USB product: {0}", dev.UsbProductString); + _logSw.WriteLine(Localization.Core.USB_manufacturer_0, dev.UsbManufacturerString); + _logSw.WriteLine(Localization.Core.USB_product_0, dev.UsbProductString); - if(!@private) - _logSw.WriteLine("USB serial: {0}", dev.UsbSerialString); + if(!@private) _logSw.WriteLine(Localization.Core.USB_serial_0, dev.UsbSerialString); - _logSw.WriteLine("USB vendor ID: {0:X4}h", dev.UsbVendorId); - _logSw.WriteLine("USB product ID: {0:X4}h", dev.UsbProductId); + _logSw.WriteLine(Localization.Core.USB_vendor_ID_0, dev.UsbVendorId); + _logSw.WriteLine(Localization.Core.USB_product_ID_0, dev.UsbProductId); } - _logSw.WriteLine("FireWire device: {0}", dev.IsFireWire); + _logSw.WriteLine(Localization.Core.FireWire_device_0, dev.IsFireWire); if(dev.IsFireWire) { - _logSw.WriteLine("FireWire vendor: {0}", dev.FireWireVendorName); - _logSw.WriteLine("FireWire model: {0}", dev.FireWireModelName); + _logSw.WriteLine(Localization.Core.FireWire_vendor_0, dev.FireWireVendorName); + _logSw.WriteLine(Localization.Core.FireWire_model_0, dev.FireWireModelName); - if(!@private) - _logSw.WriteLine("FireWire GUID: 0x{0:X16}", dev.FireWireGuid); + if(!@private) _logSw.WriteLine(Localization.Core.FireWire_GUID_0, dev.FireWireGuid); - _logSw.WriteLine("FireWire vendor ID: 0x{0:X8}", dev.FireWireVendor); - _logSw.WriteLine("FireWire product ID: 0x{0:X8}", dev.FireWireModel); + _logSw.WriteLine(Localization.Core.FireWire_vendor_ID_0, dev.FireWireVendor); + _logSw.WriteLine(Localization.Core.FireWire_product_ID_0, dev.FireWireModel); } - _logSw.WriteLine("######################################################"); + _logSw.WriteLine(Localization.Core.Log_section_separator); _logSw.WriteLine(); - _logSw.WriteLine("################ Dumping progress log ################"); + _logSw.WriteLine(Localization.Core.Dumping_progress_log); _logSw.Flush(); } @@ -181,8 +187,7 @@ public sealed class DumpLog /// Arguments public void WriteLine(string format, params object[] args) { - if(_logSw == null) - return; + if(_logSw == null) return; var text = string.Format(format, args); _logSw.WriteLine("{0:s} {1}", DateTime.Now, text); @@ -192,8 +197,8 @@ public sealed class DumpLog /// Finishes and closes the dump log public void Close() { - _logSw?.WriteLine("######################################################"); - _logSw?.WriteLine("End logging at {0}", DateTime.Now); + _logSw?.WriteLine(Localization.Core.Log_section_separator); + _logSw?.WriteLine(Localization.Core.End_logging_on_0, DateTime.Now); _logSw?.Close(); } } \ No newline at end of file diff --git a/Aaru.Core/Logging/ErrorLog.cs b/Aaru.Core/Logging/ErrorLog.cs index d9d697adf..5ea7b7119 100644 --- a/Aaru.Core/Logging/ErrorLog.cs +++ b/Aaru.Core/Logging/ErrorLog.cs @@ -23,11 +23,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Logging; - using System; using System.Collections.Generic; using System.IO; @@ -35,6 +33,8 @@ using System.Linq; using Aaru.Decoders.ATA; using Aaru.Decoders.SCSI; +namespace Aaru.Core.Logging; + /// Logs errors public sealed class ErrorLog { @@ -44,21 +44,20 @@ public sealed class ErrorLog /// Output log file public ErrorLog(string outputFile) { - if(string.IsNullOrEmpty(outputFile)) - return; + if(string.IsNullOrEmpty(outputFile)) return; _logSw = new StreamWriter(outputFile, true); - _logSw.WriteLine("Start error logging at {0}", DateTime.Now); - _logSw.WriteLine("######################################################"); + _logSw.WriteLine(Localization.Core.Start_error_logging_on_0, DateTime.Now); + _logSw.WriteLine(Localization.Core.Log_section_separator); _logSw.Flush(); } /// Finishes and closes the error log public void Close() { - _logSw.WriteLine("######################################################"); - _logSw.WriteLine("End logging at {0}", DateTime.Now); + _logSw.WriteLine(Localization.Core.Log_section_separator); + _logSw.WriteLine(Localization.Core.End_logging_on_0, DateTime.Now); _logSw.Close(); } @@ -71,63 +70,49 @@ public sealed class ErrorLog { if(osError) { - _logSw.WriteLine("ATA command {0} operating system error: {1}.", command, errno); + _logSw.WriteLine(Localization.Core.ATA_command_0_operating_system_error_1, command, errno); _logSw.Flush(); } else { - var error = new List(); - var status = new List(); + List error = []; + List status = []; - if((registers.Status & 0x01) == 0x01) - status.Add("ERR"); + if((registers.Status & 0x01) == 0x01) status.Add("ERR"); - if((registers.Status & 0x02) == 0x02) - status.Add("IDX"); + if((registers.Status & 0x02) == 0x02) status.Add("IDX"); - if((registers.Status & 0x04) == 0x04) - status.Add("CORR"); + if((registers.Status & 0x04) == 0x04) status.Add("CORR"); - if((registers.Status & 0x08) == 0x08) - status.Add("DRQ"); + if((registers.Status & 0x08) == 0x08) status.Add("DRQ"); - if((registers.Status & 0x10) == 0x10) - status.Add("SRV"); + if((registers.Status & 0x10) == 0x10) status.Add("SRV"); - if((registers.Status & 0x20) == 0x20) - status.Add("DF"); + if((registers.Status & 0x20) == 0x20) status.Add("DF"); - if((registers.Status & 0x40) == 0x40) - status.Add("RDY"); + if((registers.Status & 0x40) == 0x40) status.Add("RDY"); - if((registers.Status & 0x80) == 0x80) - status.Add("BSY"); + if((registers.Status & 0x80) == 0x80) status.Add("BSY"); - if((registers.Error & 0x01) == 0x01) - error.Add("AMNF"); + if((registers.Error & 0x01) == 0x01) error.Add("AMNF"); - if((registers.Error & 0x02) == 0x02) - error.Add("T0NF"); + if((registers.Error & 0x02) == 0x02) error.Add("T0NF"); - if((registers.Error & 0x04) == 0x04) - error.Add("ABRT"); + if((registers.Error & 0x04) == 0x04) error.Add("ABRT"); - if((registers.Error & 0x08) == 0x08) - error.Add("MCR"); + if((registers.Error & 0x08) == 0x08) error.Add("MCR"); - if((registers.Error & 0x10) == 0x10) - error.Add("IDNF"); + if((registers.Error & 0x10) == 0x10) error.Add("IDNF"); - if((registers.Error & 0x20) == 0x20) - error.Add("MC"); + if((registers.Error & 0x20) == 0x20) error.Add("MC"); - if((registers.Error & 0x40) == 0x40) - error.Add("UNC"); + if((registers.Error & 0x40) == 0x40) error.Add("UNC"); - if((registers.Error & 0x80) == 0x80) - error.Add("BBK"); + if((registers.Error & 0x80) == 0x80) error.Add("BBK"); - _logSw.WriteLine("ATA command {0} error: status = {1}, error = {2}.", command, string.Join(' ', status), + _logSw.WriteLine(Localization.Core.ATA_command_0_error_status_1_error_2, + command, + string.Join(' ', status), string.Join(' ', error)); _logSw.Flush(); @@ -141,71 +126,62 @@ public sealed class ErrorLog /// true if operating system returned an error status instead of the device /// Operating system error number /// Error registers - public void WriteLine(ushort cylinder, byte head, byte sector, bool osError, int errno, + public void WriteLine(ushort cylinder, byte head, byte sector, bool osError, int errno, AtaErrorRegistersChs registers) { if(osError) { - _logSw.WriteLine("ATA reading C/H/S {0}/{1}/{2} operating system error: {3}.", cylinder, head, sector, + _logSw.WriteLine(Localization.Core.ATA_reading_CHS_0_1_2_operating_system_error_3, + cylinder, + head, + sector, errno); _logSw.Flush(); } else { - var error = new List(); - var status = new List(); + List error = []; + List status = []; - if((registers.Status & 0x01) == 0x01) - status.Add("ERR"); + if((registers.Status & 0x01) == 0x01) status.Add("ERR"); - if((registers.Status & 0x02) == 0x02) - status.Add("IDX"); + if((registers.Status & 0x02) == 0x02) status.Add("IDX"); - if((registers.Status & 0x04) == 0x04) - status.Add("CORR"); + if((registers.Status & 0x04) == 0x04) status.Add("CORR"); - if((registers.Status & 0x08) == 0x08) - status.Add("DRQ"); + if((registers.Status & 0x08) == 0x08) status.Add("DRQ"); - if((registers.Status & 0x10) == 0x10) - status.Add("SRV"); + if((registers.Status & 0x10) == 0x10) status.Add("SRV"); - if((registers.Status & 0x20) == 0x20) - status.Add("DF"); + if((registers.Status & 0x20) == 0x20) status.Add("DF"); - if((registers.Status & 0x40) == 0x40) - status.Add("RDY"); + if((registers.Status & 0x40) == 0x40) status.Add("RDY"); - if((registers.Status & 0x80) == 0x80) - status.Add("BSY"); + if((registers.Status & 0x80) == 0x80) status.Add("BSY"); - if((registers.Error & 0x01) == 0x01) - error.Add("AMNF"); + if((registers.Error & 0x01) == 0x01) error.Add("AMNF"); - if((registers.Error & 0x02) == 0x02) - error.Add("T0NF"); + if((registers.Error & 0x02) == 0x02) error.Add("T0NF"); - if((registers.Error & 0x04) == 0x04) - error.Add("ABRT"); + if((registers.Error & 0x04) == 0x04) error.Add("ABRT"); - if((registers.Error & 0x08) == 0x08) - error.Add("MCR"); + if((registers.Error & 0x08) == 0x08) error.Add("MCR"); - if((registers.Error & 0x10) == 0x10) - error.Add("IDNF"); + if((registers.Error & 0x10) == 0x10) error.Add("IDNF"); - if((registers.Error & 0x20) == 0x20) - error.Add("MC"); + if((registers.Error & 0x20) == 0x20) error.Add("MC"); - if((registers.Error & 0x40) == 0x40) - error.Add("UNC"); + if((registers.Error & 0x40) == 0x40) error.Add("UNC"); - if((registers.Error & 0x80) == 0x80) - error.Add("BBK"); + if((registers.Error & 0x80) == 0x80) error.Add("BBK"); - _logSw.WriteLine("ATA reading C/H/S {0}/{1}/{2} error: status = {3}, error = {4}.", cylinder, head, sector, - string.Join(' ', status), string.Join(' ', error)); + _logSw.WriteLine(Localization.Core.ATA_reading_CHS_0_1_2_error_status_3_error_4, + cylinder, + head, + sector, + string.Join(' ', status), + string.Join(' ', error)); _logSw.Flush(); } @@ -220,63 +196,49 @@ public sealed class ErrorLog { if(osError) { - _logSw.WriteLine("ATA reading LBA {0} operating system error: {1}.", block, errno); + _logSw.WriteLine(Localization.Core.ATA_reading_LBA_0_operating_system_error_1, block, errno); _logSw.Flush(); } else { - var error = new List(); - var status = new List(); + List error = []; + List status = []; - if((registers.Status & 0x01) == 0x01) - status.Add("ERR"); + if((registers.Status & 0x01) == 0x01) status.Add("ERR"); - if((registers.Status & 0x02) == 0x02) - status.Add("IDX"); + if((registers.Status & 0x02) == 0x02) status.Add("IDX"); - if((registers.Status & 0x04) == 0x04) - status.Add("CORR"); + if((registers.Status & 0x04) == 0x04) status.Add("CORR"); - if((registers.Status & 0x08) == 0x08) - status.Add("DRQ"); + if((registers.Status & 0x08) == 0x08) status.Add("DRQ"); - if((registers.Status & 0x10) == 0x10) - status.Add("SRV"); + if((registers.Status & 0x10) == 0x10) status.Add("SRV"); - if((registers.Status & 0x20) == 0x20) - status.Add("DF"); + if((registers.Status & 0x20) == 0x20) status.Add("DF"); - if((registers.Status & 0x40) == 0x40) - status.Add("RDY"); + if((registers.Status & 0x40) == 0x40) status.Add("RDY"); - if((registers.Status & 0x80) == 0x80) - status.Add("BSY"); + if((registers.Status & 0x80) == 0x80) status.Add("BSY"); - if((registers.Error & 0x01) == 0x01) - error.Add("AMNF"); + if((registers.Error & 0x01) == 0x01) error.Add("AMNF"); - if((registers.Error & 0x02) == 0x02) - error.Add("T0NF"); + if((registers.Error & 0x02) == 0x02) error.Add("T0NF"); - if((registers.Error & 0x04) == 0x04) - error.Add("ABRT"); + if((registers.Error & 0x04) == 0x04) error.Add("ABRT"); - if((registers.Error & 0x08) == 0x08) - error.Add("MCR"); + if((registers.Error & 0x08) == 0x08) error.Add("MCR"); - if((registers.Error & 0x10) == 0x10) - error.Add("IDNF"); + if((registers.Error & 0x10) == 0x10) error.Add("IDNF"); - if((registers.Error & 0x20) == 0x20) - error.Add("MC"); + if((registers.Error & 0x20) == 0x20) error.Add("MC"); - if((registers.Error & 0x40) == 0x40) - error.Add("UNC"); + if((registers.Error & 0x40) == 0x40) error.Add("UNC"); - if((registers.Error & 0x80) == 0x80) - error.Add("BBK"); + if((registers.Error & 0x80) == 0x80) error.Add("BBK"); - _logSw.WriteLine("ATA reading LBA {0} error: status = {1}, error = {2}.", block, string.Join(' ', status), + _logSw.WriteLine(Localization.Core.ATA_reading_LBA_0_error_status_1_error_2, + block, + string.Join(' ', status), string.Join(' ', error)); _logSw.Flush(); @@ -292,63 +254,49 @@ public sealed class ErrorLog { if(osError) { - _logSw.WriteLine("ATA reading LBA {0} operating system error: {1}.", block, errno); + _logSw.WriteLine(Localization.Core.ATA_reading_LBA_0_operating_system_error_1, block, errno); _logSw.Flush(); } else { - var error = new List(); - var status = new List(); + List error = []; + List status = []; - if((registers.Status & 0x01) == 0x01) - status.Add("ERR"); + if((registers.Status & 0x01) == 0x01) status.Add("ERR"); - if((registers.Status & 0x02) == 0x02) - status.Add("IDX"); + if((registers.Status & 0x02) == 0x02) status.Add("IDX"); - if((registers.Status & 0x04) == 0x04) - status.Add("CORR"); + if((registers.Status & 0x04) == 0x04) status.Add("CORR"); - if((registers.Status & 0x08) == 0x08) - status.Add("DRQ"); + if((registers.Status & 0x08) == 0x08) status.Add("DRQ"); - if((registers.Status & 0x10) == 0x10) - status.Add("SRV"); + if((registers.Status & 0x10) == 0x10) status.Add("SRV"); - if((registers.Status & 0x20) == 0x20) - status.Add("DF"); + if((registers.Status & 0x20) == 0x20) status.Add("DF"); - if((registers.Status & 0x40) == 0x40) - status.Add("RDY"); + if((registers.Status & 0x40) == 0x40) status.Add("RDY"); - if((registers.Status & 0x80) == 0x80) - status.Add("BSY"); + if((registers.Status & 0x80) == 0x80) status.Add("BSY"); - if((registers.Error & 0x01) == 0x01) - error.Add("AMNF"); + if((registers.Error & 0x01) == 0x01) error.Add("AMNF"); - if((registers.Error & 0x02) == 0x02) - error.Add("T0NF"); + if((registers.Error & 0x02) == 0x02) error.Add("T0NF"); - if((registers.Error & 0x04) == 0x04) - error.Add("ABRT"); + if((registers.Error & 0x04) == 0x04) error.Add("ABRT"); - if((registers.Error & 0x08) == 0x08) - error.Add("MCR"); + if((registers.Error & 0x08) == 0x08) error.Add("MCR"); - if((registers.Error & 0x10) == 0x10) - error.Add("IDNF"); + if((registers.Error & 0x10) == 0x10) error.Add("IDNF"); - if((registers.Error & 0x20) == 0x20) - error.Add("MC"); + if((registers.Error & 0x20) == 0x20) error.Add("MC"); - if((registers.Error & 0x40) == 0x40) - error.Add("UNC"); + if((registers.Error & 0x40) == 0x40) error.Add("UNC"); - if((registers.Error & 0x80) == 0x80) - error.Add("BBK"); + if((registers.Error & 0x80) == 0x80) error.Add("BBK"); - _logSw.WriteLine("ATA reading LBA {0} error: status = {1}, error = {2}.", block, string.Join(' ', status), + _logSw.WriteLine(Localization.Core.ATA_reading_LBA_0_error_status_1_error_2, + block, + string.Join(' ', status), string.Join(' ', error)); _logSw.Flush(); @@ -364,7 +312,7 @@ public sealed class ErrorLog { if(osError) { - _logSw.WriteLine("SCSI command {0} operating system error: {1}.", command, errno); + _logSw.WriteLine(Localization.Core.SCSI_command_0_operating_system_error_1, command, errno); _logSw.Flush(); return; @@ -378,39 +326,44 @@ public sealed class ErrorLog { if(prettySense != null) { - if(prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal)) - prettySense = prettySense.Substring(12); + if(prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal)) prettySense = prettySense[12..]; - if(prettySense.EndsWith('\n')) - prettySense = prettySense.Substring(0, prettySense.Length - 1); + if(prettySense.EndsWith('\n')) prettySense = prettySense[..^1]; prettySense = prettySense.Replace("\n", " - "); - _logSw.WriteLine("SCSI command {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}, {5}.", command, - decodedSense.Value.SenseKey, decodedSense.Value.ASC, decodedSense.Value.ASCQ, hexSense, + _logSw.WriteLine(Localization.Core.SCSI_command_0_error_SENSE_1_ASC_2_ASCQ_3_4_5, + command, + decodedSense.Value.SenseKey, + decodedSense.Value.ASC, + decodedSense.Value.ASCQ, + hexSense, prettySense); } else - _logSw.WriteLine("SCSI command {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}.", command, - decodedSense.Value.SenseKey, decodedSense.Value.ASC, decodedSense.Value.ASCQ, + { + _logSw.WriteLine(Localization.Core.SCSI_command_0_error_SENSE_1_ASC_2_ASCQ_3_4, + command, + decodedSense.Value.SenseKey, + decodedSense.Value.ASC, + decodedSense.Value.ASCQ, hexSense); + } } else { if(prettySense != null) { - if(prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal)) - prettySense = prettySense.Substring(12); + if(prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal)) prettySense = prettySense[12..]; - if(prettySense.EndsWith('\n')) - prettySense = prettySense.Substring(0, prettySense.Length - 1); + if(prettySense.EndsWith('\n')) prettySense = prettySense[..^1]; prettySense = prettySense.Replace("\n", " - "); - _logSw.WriteLine("SCSI command {0} error: {1}, {2}.", command, hexSense, prettySense); + _logSw.WriteLine(Localization.Core.SCSI_command_0_error_1_2, command, hexSense, prettySense); } else - _logSw.WriteLine("SCSI command {0} error: {1}", command, hexSense); + _logSw.WriteLine(Localization.Core.SCSI_command_0_error_1, command, hexSense); } _logSw.Flush(); @@ -425,13 +378,10 @@ public sealed class ErrorLog { if(osError) { - _logSw.WriteLine("SCSI reading LBA {0} operating system error: {1}.", block, errno); + _logSw.WriteLine(Localization.Core.SCSI_reading_LBA_0_operating_system_error_1, block, errno); _logSw.Flush(); - if(senseBuffer is null || - senseBuffer.Length == 0 || - senseBuffer.All(s => s == 0)) - return; + if(senseBuffer is null || senseBuffer.Length == 0 || senseBuffer.All(s => s == 0)) return; } DecodedSense? decodedSense = Sense.Decode(senseBuffer); @@ -442,39 +392,44 @@ public sealed class ErrorLog { if(prettySense != null) { - if(prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal)) - prettySense = prettySense.Substring(12); + if(prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal)) prettySense = prettySense[12..]; - if(prettySense.EndsWith('\n')) - prettySense = prettySense.Substring(0, prettySense.Length - 1); + if(prettySense.EndsWith('\n')) prettySense = prettySense[..^1]; prettySense = prettySense.Replace("\n", " - "); - _logSw.WriteLine("SCSI reading LBA {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}, {5}.", block, - decodedSense.Value.SenseKey, decodedSense.Value.ASC, decodedSense.Value.ASCQ, hexSense, + _logSw.WriteLine(Localization.Core.SCSI_reading_LBA_0_error_SENSE_1_ASC_2_ASCQ_3_4_5, + block, + decodedSense.Value.SenseKey, + decodedSense.Value.ASC, + decodedSense.Value.ASCQ, + hexSense, prettySense); } else - _logSw.WriteLine("SCSI reading LBA {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}.", block, - decodedSense.Value.SenseKey, decodedSense.Value.ASC, decodedSense.Value.ASCQ, + { + _logSw.WriteLine(Localization.Core.SCSI_reading_LBA_0_error_SENSE_1_ASC_2_ASCQ_3_4, + block, + decodedSense.Value.SenseKey, + decodedSense.Value.ASC, + decodedSense.Value.ASCQ, hexSense); + } } else { if(prettySense != null) { - if(prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal)) - prettySense = prettySense.Substring(12); + if(prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal)) prettySense = prettySense[12..]; - if(prettySense.EndsWith('\n')) - prettySense = prettySense.Substring(0, prettySense.Length - 1); + if(prettySense.EndsWith('\n')) prettySense = prettySense[..^1]; prettySense = prettySense.Replace("\n", " - "); - _logSw.WriteLine("SCSI reading LBA {0} error: {1}, {2}.", block, hexSense, prettySense); + _logSw.WriteLine(Localization.Core.SCSI_reading_LBA_0_error_1_2, block, hexSense, prettySense); } else - _logSw.WriteLine("SCSI reading LBA {0} error: {1}", block, hexSense); + _logSw.WriteLine(Localization.Core.SCSI_reading_LBA_0_error_1, block, hexSense); } _logSw.Flush(); @@ -489,14 +444,15 @@ public sealed class ErrorLog { if(osError) { - _logSw.WriteLine("SD/MMC command {0} operating system error: {1}.", command, errno); + _logSw.WriteLine(Localization.Core.SD_MMC_command_0_operating_system_error_1, command, errno); _logSw.Flush(); return; } // TODO: Decode response - _logSw.WriteLine("SD/MMC command {0} error: {1}", command, + _logSw.WriteLine(Localization.Core.SD_MMC_command_0_error_1, + command, string.Join(" - ", response.Select(r => $"0x{r:X8}"))); _logSw.Flush(); @@ -513,15 +469,21 @@ public sealed class ErrorLog { if(osError) { - _logSw.WriteLine("SD/MMC reading LBA {0} ({1}-addressed) operating system error: {2}.", block, - byteAddressed ? "byte" : "block", errno); + _logSw.WriteLine(byteAddressed + ? Localization.Core.SD_MMC_reading_LBA_0_byte_addressed_operating_system_error_1 + : Localization.Core.SD_MMC_reading_LBA_0_block_addressed_operating_system_error_1, + block, + errno); _logSw.Flush(); return; } - _logSw.WriteLine("SD/MMC reading LBA {0} ({1}-addressed) error: {2}", block, byteAddressed ? "byte" : "block", + _logSw.WriteLine(byteAddressed + ? Localization.Core.SD_MMC_reading_LBA_0_byte_addressed_error_1 + : Localization.Core.SD_MMC_reading_LBA_0_block_addressed_error_1, + block, string.Join(" - ", response.Select(r => $"0x{r:X8}"))); throw new NotImplementedException(); diff --git a/Aaru.Core/Logging/IBGLog.cs b/Aaru.Core/Logging/IBGLog.cs index 43ccc4abc..dc23acdd2 100644 --- a/Aaru.Core/Logging/IBGLog.cs +++ b/Aaru.Core/Logging/IBGLog.cs @@ -27,17 +27,18 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Logging; - using System; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Text; using Aaru.Devices; +namespace Aaru.Core.Logging; + /// Implements a log in the format used by IMGBurn sealed class IbgLog { @@ -45,8 +46,8 @@ sealed class IbgLog readonly double _ibgDivider; readonly string _ibgMediaType; readonly StringBuilder _ibgSb; + readonly Stopwatch _ibgStopwatch; readonly string _logFile; - DateTime _ibgDatePoint; ulong _ibgIntSector; double _ibgIntSpeed; double _ibgMaxSpeed; @@ -60,12 +61,11 @@ sealed class IbgLog /// Profile as defined by SCSI MultiMedia Commands specification internal IbgLog(string outputFile, ushort currentProfile) { - if(string.IsNullOrEmpty(outputFile)) - return; + if(string.IsNullOrEmpty(outputFile)) return; _logFile = outputFile; _ibgSb = new StringBuilder(); - _ibgDatePoint = DateTime.Now; + _ibgStopwatch = new Stopwatch(); _ibgCulture = new CultureInfo("en-US"); _ibgStartSet = false; _ibgMaxSpeed = 0; @@ -73,6 +73,8 @@ sealed class IbgLog _ibgSnaps = 0; _ibgIntSector = 0; + _ibgStopwatch.Start(); + switch(currentProfile) { case 0x0001: @@ -236,30 +238,26 @@ sealed class IbgLog /// Current speed at the snapshot internal void Write(ulong sector, double currentSpeed) { - if(_logFile == null) - return; + if(_logFile == null) return; _ibgIntSpeed += currentSpeed; - _ibgSampleRate += (int)Math.Floor((DateTime.Now - _ibgDatePoint).TotalMilliseconds); + _ibgSampleRate += (int)Math.Floor(_ibgStopwatch.Elapsed.TotalMilliseconds); _ibgSnaps++; - if(_ibgSampleRate < 100) - return; + if(_ibgSampleRate < 100) return; - if(_ibgIntSpeed > 0 && - !_ibgStartSet) + if(_ibgIntSpeed > 0 && !_ibgStartSet) { _ibgStartSpeed = _ibgIntSpeed / _ibgSnaps / _ibgDivider; _ibgStartSet = true; } - _ibgSb.AppendFormat("{0:0.00},{1},{2:0},0", _ibgIntSpeed / _ibgSnaps / _ibgDivider, _ibgIntSector, - _ibgSampleRate).AppendLine(); + _ibgSb.Append($"{_ibgIntSpeed / _ibgSnaps / _ibgDivider:0.00},{_ibgIntSector},{_ibgSampleRate:0},0") + .AppendLine(); - if(_ibgIntSpeed / _ibgSnaps / _ibgDivider > _ibgMaxSpeed) - _ibgMaxSpeed = _ibgIntSpeed / _ibgDivider; + if(_ibgIntSpeed / _ibgSnaps / _ibgDivider > _ibgMaxSpeed) _ibgMaxSpeed = _ibgIntSpeed / _ibgDivider; - _ibgDatePoint = DateTime.Now; + _ibgStopwatch.Restart(); _ibgIntSpeed = 0; _ibgSampleRate = 0; _ibgSnaps = 0; @@ -274,11 +272,12 @@ sealed class IbgLog /// Speed at the end /// Average speed /// Device path - internal void Close(Device dev, ulong blocks, ulong blockSize, double totalSeconds, double currentSpeed, + internal void Close(Device dev, ulong blocks, ulong blockSize, double totalSeconds, double currentSpeed, double averageSpeed, string devicePath) { - if(_logFile == null) - return; + if(_logFile == null) return; + + _ibgStopwatch.Stop(); var ibgFs = new FileStream(_logFile, FileMode.Create); var ibgHeader = new StringBuilder(); @@ -296,42 +295,41 @@ sealed class IbgLog ibgHeader.AppendLine("[START_CONFIGURATION]"); ibgHeader.AppendLine("IBGD_VERSION=2"); ibgHeader.AppendLine(); - ibgHeader.AppendFormat("DATE={0}", DateTime.Now).AppendLine(); + ibgHeader.Append($"DATE={DateTime.Now}").AppendLine(); ibgHeader.AppendLine(); - ibgHeader.AppendFormat("SAMPLE_RATE={0}", 100).AppendLine(); + ibgHeader.Append($"SAMPLE_RATE={100}").AppendLine(); ibgHeader.AppendLine(); - ibgHeader.AppendFormat("DEVICE=[0:0:0] {0} {1} ({2}) ({3})", dev.Manufacturer, dev.Model, devicePath, - ibgBusType).AppendLine(); + ibgHeader.Append($"DEVICE=[0:0:0] {dev.Manufacturer} {dev.Model} ({devicePath}) ({ibgBusType})").AppendLine(); ibgHeader.AppendLine("DEVICE_ADDRESS=0:0:0"); - ibgHeader.AppendFormat("DEVICE_MAKEMODEL={0} {1}", dev.Manufacturer, dev.Model).AppendLine(); - ibgHeader.AppendFormat("DEVICE_FIRMWAREVERSION={0}", dev.FirmwareRevision).AppendLine(); - ibgHeader.AppendFormat("DEVICE_DRIVELETTER={0}", devicePath).AppendLine(); - ibgHeader.AppendFormat("DEVICE_BUSTYPE={0}", ibgBusType).AppendLine(); + ibgHeader.Append($"DEVICE_MAKEMODEL={dev.Manufacturer} {dev.Model}").AppendLine(); + ibgHeader.Append($"DEVICE_FIRMWAREVERSION={dev.FirmwareRevision}").AppendLine(); + ibgHeader.Append($"DEVICE_DRIVELETTER={devicePath}").AppendLine(); + ibgHeader.Append($"DEVICE_BUSTYPE={ibgBusType}").AppendLine(); ibgHeader.AppendLine(); - ibgHeader.AppendFormat("MEDIA_TYPE={0}", _ibgMediaType).AppendLine(); + ibgHeader.Append($"MEDIA_TYPE={_ibgMediaType}").AppendLine(); ibgHeader.AppendLine("MEDIA_BOOKTYPE=Unknown"); ibgHeader.AppendLine("MEDIA_ID=N/A"); ibgHeader.AppendLine("MEDIA_TRACKPATH=PTP"); ibgHeader.AppendLine("MEDIA_SPEEDS=N/A"); - ibgHeader.AppendFormat("MEDIA_CAPACITY={0}", blocks).AppendLine(); + ibgHeader.Append($"MEDIA_CAPACITY={blocks}").AppendLine(); ibgHeader.AppendLine("MEDIA_LAYER_BREAK=0"); ibgHeader.AppendLine(); ibgHeader.AppendLine("DATA_IMAGEFILE=/dev/null"); - ibgHeader.AppendFormat("DATA_SECTORS={0}", blocks).AppendLine(); - ibgHeader.AppendFormat("DATA_TYPE=MODE1/{0}", blockSize).AppendLine(); + ibgHeader.Append($"DATA_SECTORS={blocks}").AppendLine(); + ibgHeader.Append($"DATA_TYPE=MODE1/{blockSize}").AppendLine(); ibgHeader.AppendLine("DATA_VOLUMEIDENTIFIER="); ibgHeader.AppendLine(); - ibgHeader.AppendFormat(_ibgCulture, "VERIFY_SPEED_START={0:0.00}", _ibgStartSpeed).AppendLine(); - ibgHeader.AppendFormat(_ibgCulture, "VERIFY_SPEED_END={0:0.00}", currentSpeed / _ibgDivider).AppendLine(); + ibgHeader.Append(_ibgCulture, $"VERIFY_SPEED_START={_ibgStartSpeed:0.00}").AppendLine(); + ibgHeader.Append(_ibgCulture, $"VERIFY_SPEED_END={currentSpeed / _ibgDivider:0.00}").AppendLine(); - ibgHeader.AppendFormat(_ibgCulture, "VERIFY_SPEED_AVERAGE={0:0.00}", averageSpeed / _ibgDivider).AppendLine(); + ibgHeader.Append(_ibgCulture, $"VERIFY_SPEED_AVERAGE={averageSpeed / _ibgDivider:0.00}").AppendLine(); - ibgHeader.AppendFormat(_ibgCulture, "VERIFY_SPEED_MAX={0:0.00}", _ibgMaxSpeed).AppendLine(); - ibgHeader.AppendFormat(_ibgCulture, "VERIFY_TIME_TAKEN={0:0}", Math.Floor(totalSeconds)).AppendLine(); + ibgHeader.Append(_ibgCulture, $"VERIFY_SPEED_MAX={_ibgMaxSpeed:0.00}").AppendLine(); + ibgHeader.Append(_ibgCulture, $"VERIFY_TIME_TAKEN={Math.Floor(totalSeconds):0}").AppendLine(); ibgHeader.AppendLine("[END_CONFIGURATION]"); ibgHeader.AppendLine(); ibgHeader.AppendLine("HRPC=True"); diff --git a/Aaru.Core/Logging/MHDDLog.cs b/Aaru.Core/Logging/MHDDLog.cs index 5b796d8dd..4cefcfcdd 100644 --- a/Aaru.Core/Logging/MHDDLog.cs +++ b/Aaru.Core/Logging/MHDDLog.cs @@ -27,23 +27,26 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Logging; - using System; using System.Globalization; using System.IO; using System.Text; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Core.Graphics; using Aaru.Devices; +namespace Aaru.Core.Logging; + /// Implements a log in the format used by MHDD sealed class MhddLog { const string MHDD_VER = "VER:2 "; readonly string _logFile; + readonly IMediaGraph _mediaGraph; readonly MemoryStream _mhddFs; /// Initializes the MHDD log @@ -53,50 +56,32 @@ sealed class MhddLog /// Bytes per block /// How many blocks read at once /// Disable saving paths or serial numbers in log - internal MhddLog(string outputFile, Device dev, ulong blocks, ulong blockSize, ulong blocksToRead, bool @private) + /// Dimensions in pixel for a square that would contain the block map graph + internal MhddLog(string outputFile, Device dev, ulong blocks, ulong blockSize, ulong blocksToRead, bool @private, + uint mediaGraphDimensions = 0) { - if(dev == null || - string.IsNullOrEmpty(outputFile)) - return; + if(dev == null || string.IsNullOrEmpty(outputFile)) return; + + if(mediaGraphDimensions > 0) + _mediaGraph = new BlockMap((int)mediaGraphDimensions, (int)mediaGraphDimensions, blocks); _mhddFs = new MemoryStream(); _logFile = outputFile; - string mode; - - switch(dev.Type) - { - case DeviceType.ATA: - case DeviceType.ATAPI: - mode = "MODE: IDE"; - - break; - case DeviceType.SCSI: - mode = "MODE: SCSI"; - - break; - case DeviceType.MMC: - mode = "MODE: MMC"; - - break; - case DeviceType.NVMe: - mode = "MODE: NVMe"; - - break; - case DeviceType.SecureDigital: - mode = "MODE: SD"; - - break; - default: - mode = "MODE: IDE"; - - break; - } + string mode = dev.Type switch + { + DeviceType.ATA or DeviceType.ATAPI => "MODE: IDE", + DeviceType.SCSI => "MODE: SCSI", + DeviceType.MMC => "MODE: MMC", + DeviceType.NVMe => "MODE: NVMe", + DeviceType.SecureDigital => "MODE: SD", + _ => "MODE: IDE" + }; var device = $"DEVICE: {dev.Manufacturer} {dev.Model}"; var fw = $"F/W: {dev.FirmwareRevision}"; var sn = $"S/N: {(@private ? "" : dev.Serial)}"; - var sectors = string.Format(new CultureInfo("en-US"), "SECTORS: {0:n0}", blocks); + var sectors = string.Format(new CultureInfo("en-US"), "SECTORS: {0:n0}", blocks); var sectorSize = string.Format(new CultureInfo("en-US"), "SECTOR SIZE: {0:n0} bytes", blockSize); var scanBlockSize = string.Format(new CultureInfo("en-US"), "SCAN BLOCK SIZE: {0:n0} sectors", blocksToRead); @@ -110,59 +95,94 @@ sealed class MhddLog byte[] scanBlockSizeBytes = Encoding.ASCII.GetBytes(scanBlockSize); byte[] verBytes = Encoding.ASCII.GetBytes(MHDD_VER); - var pointer = (uint)(deviceBytes.Length + modeBytes.Length + fwBytes.Length + snBytes.Length + - sectorsBytes.Length + sectorSizeBytes.Length + scanBlockSizeBytes.Length + - verBytes.Length + 2 * 9 + // New lines - 4); // Pointer + var pointer = (uint)(deviceBytes.Length + + modeBytes.Length + + fwBytes.Length + + snBytes.Length + + sectorsBytes.Length + + sectorSizeBytes.Length + + scanBlockSizeBytes.Length + + verBytes.Length + + 2 * 9 + // New lines + 4); // Pointer var newLine = new byte[2]; newLine[0] = 0x0D; newLine[1] = 0x0A; _mhddFs.Write(BitConverter.GetBytes(pointer), 0, 4); - _mhddFs.Write(newLine, 0, 2); - _mhddFs.Write(verBytes, 0, verBytes.Length); - _mhddFs.Write(newLine, 0, 2); - _mhddFs.Write(modeBytes, 0, modeBytes.Length); - _mhddFs.Write(newLine, 0, 2); - _mhddFs.Write(deviceBytes, 0, deviceBytes.Length); - _mhddFs.Write(newLine, 0, 2); - _mhddFs.Write(fwBytes, 0, fwBytes.Length); - _mhddFs.Write(newLine, 0, 2); - _mhddFs.Write(snBytes, 0, snBytes.Length); - _mhddFs.Write(newLine, 0, 2); - _mhddFs.Write(sectorsBytes, 0, sectorsBytes.Length); - _mhddFs.Write(newLine, 0, 2); - _mhddFs.Write(sectorSizeBytes, 0, sectorSizeBytes.Length); - _mhddFs.Write(newLine, 0, 2); - _mhddFs.Write(scanBlockSizeBytes, 0, scanBlockSizeBytes.Length); - _mhddFs.Write(newLine, 0, 2); + _mhddFs.Write(newLine, 0, 2); + _mhddFs.Write(verBytes, 0, verBytes.Length); + _mhddFs.Write(newLine, 0, 2); + _mhddFs.Write(modeBytes, 0, modeBytes.Length); + _mhddFs.Write(newLine, 0, 2); + _mhddFs.Write(deviceBytes, 0, deviceBytes.Length); + _mhddFs.Write(newLine, 0, 2); + _mhddFs.Write(fwBytes, 0, fwBytes.Length); + _mhddFs.Write(newLine, 0, 2); + _mhddFs.Write(snBytes, 0, snBytes.Length); + _mhddFs.Write(newLine, 0, 2); + _mhddFs.Write(sectorsBytes, 0, sectorsBytes.Length); + _mhddFs.Write(newLine, 0, 2); + _mhddFs.Write(sectorSizeBytes, 0, sectorSizeBytes.Length); + _mhddFs.Write(newLine, 0, 2); + _mhddFs.Write(scanBlockSizeBytes, 0, scanBlockSizeBytes.Length); + _mhddFs.Write(newLine, 0, 2); } /// Logs a new read /// Starting sector /// Duration in milliseconds - internal void Write(ulong sector, double duration) + /// How many sectors where read at once + internal void Write(ulong sector, double duration, uint length = 1) { - if(_logFile == null) - return; + if(_logFile == null) return; byte[] sectorBytes = BitConverter.GetBytes(sector); byte[] durationBytes = BitConverter.GetBytes((ulong)(duration * 1000)); - _mhddFs.Write(sectorBytes, 0, 8); + _mhddFs.Write(sectorBytes, 0, 8); _mhddFs.Write(durationBytes, 0, 8); + + switch(duration) + { + case < 3: + _mediaGraph?.PaintSectors(sector, length, 0x00, 0xFF, 0x00); + + break; + case >= 3 and < 10: + _mediaGraph?.PaintSectors(sector, length, 0x80, 0xFF, 0x00); + + break; + case >= 10 and < 50: + _mediaGraph?.PaintSectors(sector, length, 0xFF, 0xFF, 0x00); + + break; + case >= 50 and < 150: + _mediaGraph?.PaintSectors(sector, length, 0xFF, 0xAB, 0x00); + + break; + case >= 150 and < 500: + _mediaGraph?.PaintSectors(sector, length, 0xFF, 0x56, 0x00); + + break; + case >= 500: + _mediaGraph?.PaintSectors(sector, length, 0xFF, 0x00, 0x00); + + break; + } } /// Closes and writes to file the MHDD log internal void Close() { - if(_logFile == null) - return; + if(_logFile == null) return; var fs = new FileStream(_logFile, FileMode.Create); _mhddFs.WriteTo(fs); _mhddFs.Close(); fs.Close(); + + _mediaGraph?.WriteTo(Path.GetFileNameWithoutExtension(_logFile) + ".png"); } } \ No newline at end of file diff --git a/Aaru.Core/Logging/SubchannelLog.cs b/Aaru.Core/Logging/SubchannelLog.cs index d72c86dc4..f49e0553f 100644 --- a/Aaru.Core/Logging/SubchannelLog.cs +++ b/Aaru.Core/Logging/SubchannelLog.cs @@ -23,15 +23,15 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Logging; - using System; using System.IO; using Aaru.Decoders.CD; +namespace Aaru.Core.Logging; + /// Logs subchannel data public class SubchannelLog { @@ -44,23 +44,22 @@ public class SubchannelLog /// Drive returns subchannel in BCD format public SubchannelLog(string outputFile, bool bcd) { - if(string.IsNullOrEmpty(outputFile)) - return; + if(string.IsNullOrEmpty(outputFile)) return; _bcd = bcd; _logSw = new StreamWriter(outputFile, true); - _logSw.WriteLine("Start subchannel logging at {0}", DateTime.Now); - _logSw.WriteLine("######################################################"); + _logSw.WriteLine(Localization.Core.Start_subchannel_logging_at_0, DateTime.Now); + _logSw.WriteLine(Localization.Core.Log_section_separator); _logSw.Flush(); } /// Finishes and closes the subchannel log public void Close() { - _logSw.WriteLine("######################################################"); - _logSw.WriteLine("End logging at {0}", DateTime.Now); + _logSw.WriteLine(Localization.Core.Log_section_separator); + _logSw.WriteLine(Localization.Core.End_logging_on_0, DateTime.Now); _logSw.Close(); } @@ -75,7 +74,7 @@ public class SubchannelLog { if(subchannel.Length / SUB_SIZE != blocks) { - _logSw.WriteLine("Data length is invalid!"); + _logSw.WriteLine(Localization.Core.Data_length_is_invalid); _logSw.Flush(); return; @@ -170,6 +169,7 @@ public class SubchannelLog var rwEmpty = true; if(raw) + { for(uint i = 12 * block; i < 12 * block + 12; i++) { if(r[i] == 0 && s[i] == 0 && t[i] == 0 && u[i] == 0 && v[i] == 0 && w[i] == 0 || @@ -180,23 +180,21 @@ public class SubchannelLog break; } + } var corruptedPause = false; var pause = false; for(var i = 0; i < 12; i++) { - if(p[i] == 0 || - p[i] == 0xFF) - continue; + if(p[i] == 0 || p[i] == 0xFF) continue; corruptedPause = true; break; } - if(!corruptedPause) - pause = p[0] == 1; + if(!corruptedPause) pause = p[0] == 1; var subBuf = new byte[12]; subBuf[0] = (byte)q[0 + block * 12]; @@ -212,13 +210,16 @@ public class SubchannelLog subBuf[10] = (byte)q[10 + block * 12]; subBuf[11] = (byte)q[11 + block * 12]; - string prettyQ = Subchannel.PrettifyQ(subBuf, generated || _bcd, startingLba + block, corruptedPause, pause, + string prettyQ = Subchannel.PrettifyQ(subBuf, + generated || _bcd, + startingLba + block, + corruptedPause, + pause, rwEmpty); if(generated) - prettyQ += " (GENERATED)"; - else if(@fixed) - prettyQ += " (FIXED)"; + prettyQ += Localization.Core._GENERATED; + else if(@fixed) prettyQ += Localization.Core._FIXED; _logSw.WriteLine(prettyQ); } @@ -228,53 +229,63 @@ public class SubchannelLog /// Logs message indicating the P subchannel has been fixed /// LBA fix belongs to - public void WritePFix(long lba) => WriteMessageWithPosition(lba, "fixed P subchannel using weight average."); + public void WritePFix(long lba) => + WriteMessageWithPosition(lba, Localization.Core.fixed_P_subchannel_using_weight_average); /// Logs message indicating the R-W subchannels have been fixed /// LBA fix belongs to - public void WriteRwFix(long lba) => WriteMessageWithPosition(lba, "fixed R-W subchannels writing empty data."); + public void WriteRwFix(long lba) => + WriteMessageWithPosition(lba, Localization.Core.fixed_R_W_subchannels_writing_empty_data); /// Logs message indicating the ADR field of the Q subchannel has been fixed /// LBA fix belongs to - public void WriteQAdrFix(long lba) => WriteMessageWithPosition(lba, "fixed Q subchannel with correct ADR."); + public void WriteQAdrFix(long lba) => + WriteMessageWithPosition(lba, Localization.Core.fixed_Q_subchannel_with_correct_ADR); /// Logs message indicating the CONTROL field of the Q subchannel has been fixed /// LBA fix belongs to - public void WriteQCtrlFix(long lba) => WriteMessageWithPosition(lba, "fixed Q subchannel with correct CONTROL."); + public void WriteQCtrlFix(long lba) => + WriteMessageWithPosition(lba, Localization.Core.fixed_Q_subchannel_with_correct_CONTROL); /// Logs message indicating the ZERO field of the Q subchannel has been fixed /// LBA fix belongs to - public void WriteQZeroFix(long lba) => WriteMessageWithPosition(lba, "fixed Q subchannel with correct ZERO."); + public void WriteQZeroFix(long lba) => + WriteMessageWithPosition(lba, Localization.Core.fixed_Q_subchannel_with_correct_ZERO); /// Logs message indicating the TNO field of the Q subchannel has been fixed /// LBA fix belongs to - public void WriteQTnoFix(long lba) => WriteMessageWithPosition(lba, "fixed Q subchannel with correct TNO."); + public void WriteQTnoFix(long lba) => + WriteMessageWithPosition(lba, Localization.Core.fixed_Q_subchannel_with_correct_TNO); /// Logs message indicating the INDEX field of the Q subchannel has been fixed /// LBA fix belongs to - public void WriteQIndexFix(long lba) => WriteMessageWithPosition(lba, "fixed Q subchannel with correct INDEX."); + public void WriteQIndexFix(long lba) => + WriteMessageWithPosition(lba, Localization.Core.fixed_Q_subchannel_with_correct_INDEX); /// Logs message indicating the relative position of the Q subchannel has been fixed /// LBA fix belongs to public void WriteQRelPosFix(long lba) => - WriteMessageWithPosition(lba, "fixed Q subchannel with correct RELATIVE POSITION."); + WriteMessageWithPosition(lba, Localization.Core.fixed_Q_subchannel_with_correct_RELATIVE_POSITION); /// Logs message indicating the absolute position of the Q subchannel has been fixed /// LBA fix belongs to public void WriteQAbsPosFix(long lba) => - WriteMessageWithPosition(lba, "fixed Q subchannel with correct ABSOLUTE POSITION."); + WriteMessageWithPosition(lba, Localization.Core.fixed_Q_subchannel_with_correct_ABSOLUTE_POSITION); /// Logs message indicating the CRC of the Q subchannel has been fixed /// LBA fix belongs to - public void WriteQCrcFix(long lba) => WriteMessageWithPosition(lba, "fixed Q subchannel with correct CRC."); + public void WriteQCrcFix(long lba) => + WriteMessageWithPosition(lba, Localization.Core.fixed_Q_subchannel_with_correct_CRC); /// Logs message indicating the the Q subchannel has been fixed with a known good MCN /// LBA fix belongs to - public void WriteQMcnFix(long lba) => WriteMessageWithPosition(lba, "fixed Q subchannel with known good MCN."); + public void WriteQMcnFix(long lba) => + WriteMessageWithPosition(lba, Localization.Core.fixed_Q_subchannel_with_known_good_MCN); /// Logs message indicating the the Q subchannel has been fixed with a known good ISRC /// LBA fix belongs to - public void WriteQIsrcFix(long lba) => WriteMessageWithPosition(lba, "fixed Q subchannel with known good ISRC."); + public void WriteQIsrcFix(long lba) => + WriteMessageWithPosition(lba, Localization.Core.fixed_Q_subchannel_with_known_good_ISRC); /// Logs a message with a specified position /// LBA position @@ -284,9 +295,9 @@ public class SubchannelLog long minute = (lba + 150) / 4500; long second = (lba + 150) % 4500 / 75; long frame = (lba + 150) % 4500 % 75; - string area = lba < 0 ? "Lead-In" : "Program"; + string area = lba < 0 ? Localization.Core.Lead_In : Localization.Core.Program; - _logSw.WriteLine($"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {message}"); + _logSw.WriteLine(Localization.Core._0_1_2_LBA_3_4_area_5, minute, second, frame, lba, area, message); _logSw.Flush(); } } \ No newline at end of file diff --git a/Aaru.Core/Media/CompactDisc.cs b/Aaru.Core/Media/CompactDisc.cs index b7a04d0e6..8e10d81e7 100644 --- a/Aaru.Core/Media/CompactDisc.cs +++ b/Aaru.Core/Media/CompactDisc.cs @@ -23,11 +23,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Media; - using System; using System.Collections.Generic; using System.Linq; @@ -41,6 +39,8 @@ using Aaru.Decoders.CD; using Aaru.Devices; using Aaru.Helpers; +namespace Aaru.Core.Media; + /// Operations over CD based media public static class CompactDisc { @@ -64,6 +64,10 @@ public static class CompactDisc /// Status update callback /// List of smallest known pregap per track /// Set if we are dumping, otherwise converting + /// + /// Gets a list of the new sectors that should be considered part of a pregap, and then + /// re-read + /// /// true if indexes have changed, false otherwise public static bool WriteSubchannelToImage(MmcSubchannel supportedSubchannel, MmcSubchannel desiredSubchannel, byte[] sub, ulong sectorAddress, uint length, SubchannelLog subLog, @@ -76,25 +80,29 @@ public static class CompactDisc out List newPregapSectors) { // We need to work in PW raw subchannels - if(supportedSubchannel == MmcSubchannel.Q16) - sub = Subchannel.ConvertQToRaw(sub); + if(supportedSubchannel == MmcSubchannel.Q16) sub = Subchannel.ConvertQToRaw(sub); // If not desired to fix, or to save, the subchannel, just save as is (or none) - if(!fixSubchannelPosition && - desiredSubchannel != MmcSubchannel.None) + if(!fixSubchannelPosition && desiredSubchannel != MmcSubchannel.None) outputPlugin.WriteSectorsTag(sub, sectorAddress, length, SectorTagType.CdSectorSubchannel); subLog?.WriteEntry(sub, supportedSubchannel == MmcSubchannel.Raw, (long)sectorAddress, length, false, false); byte[] deSub = Subchannel.Deinterleave(sub); - bool indexesChanged = CheckIndexesFromSubchannel(deSub, isrcs, currentTrack, ref mcn, tracks, dumpLog, - updateStatus, smallestPregapLbaPerTrack, dumping, - out newPregapSectors, sectorAddress); + bool indexesChanged = CheckIndexesFromSubchannel(deSub, + isrcs, + currentTrack, + ref mcn, + tracks, + dumpLog, + updateStatus, + smallestPregapLbaPerTrack, + dumping, + out newPregapSectors, + sectorAddress); - if(!fixSubchannelPosition || - desiredSubchannel == MmcSubchannel.None) - return indexesChanged; + if(!fixSubchannelPosition || desiredSubchannel == MmcSubchannel.None) return indexesChanged; int prePos = int.MinValue; @@ -111,7 +119,7 @@ public static class CompactDisc Array.Copy(deSub, subPos + 12, q, 0, 12); // Check Q CRC - CRC16CCITTContext.Data(q, 10, out byte[] crc); + CRC16CcittContext.Data(q, 10, out byte[] crc); bool crcOk = crc[0] == q[10] && crc[1] == q[11]; // Start considering P to be OK @@ -121,12 +129,10 @@ public static class CompactDisc // Check P and weight for(int p = subPos; p < subPos + 12; p++) { - if(deSub[p] != 0 && - deSub[p] != 255) - pOk = false; + if(deSub[p] != 0 && deSub[p] != 255) pOk = false; for(var w = 0; w < 8; w++) - if(((deSub[p] >> w) & 1) > 0) + if((deSub[p] >> w & 1) > 0) pWeight++; } @@ -162,11 +168,9 @@ public static class CompactDisc DetectRwPackets(sectorSub, out _, out rwPacket, out cdtextPacket); // TODO: CD+G reed solomon - if(rwPacket && !cdtextPacket) - rwOk = true; + if(rwPacket && !cdtextPacket) rwOk = true; - if(cdtextPacket) - rwOk = CheckCdTextPackets(sectorSub); + if(cdtextPacket) rwOk = CheckCdTextPackets(sectorSub); } // Fix P @@ -186,13 +190,9 @@ public static class CompactDisc } // RW is not a known pattern or packet, fix it - if(!rwOk && - !rwPacket && - !cdtextPacket && - fixSubchannel) + if(!rwOk && !rwPacket && !cdtextPacket && fixSubchannel) { - for(int rw = subPos + 24; rw < subPos + 96; rw++) - deSub[rw] = 0; + for(int rw = subPos + 24; rw < subPos + 96; rw++) deSub[rw] = 0; rwOk = true; @fixed = true; @@ -200,20 +200,28 @@ public static class CompactDisc subLog.WriteRwFix(lba); } - byte smin, ssec, amin, asec, aframe; - int aPos; + int aPos; // Fix Q - if(!crcOk && - fixSubchannel && - subPos > 0 && - subPos < deSub.Length - 96) + if(!crcOk && fixSubchannel && subPos > 0 && subPos < deSub.Length - 96) { isrcs.TryGetValue(currentTrack, out string knownGoodIsrc); - crcOk = FixQSubchannel(deSub, q, subPos, mcn, knownGoodIsrc, fixSubchannelCrc, out bool fixedAdr, - out bool controlFix, out bool fixedZero, out bool fixedTno, out bool fixedIndex, - out bool fixedRelPos, out bool fixedAbsPos, out bool fixedCrc, out bool fixedMcn, + crcOk = FixQSubchannel(deSub, + q, + subPos, + mcn, + knownGoodIsrc, + fixSubchannelCrc, + out bool fixedAdr, + out bool controlFix, + out bool fixedZero, + out bool fixedTno, + out bool fixedIndex, + out bool fixedRelPos, + out bool fixedAbsPos, + out bool fixedCrc, + out bool fixedMcn, out bool fixedIsrc); if(crcOk) @@ -221,68 +229,53 @@ public static class CompactDisc Array.Copy(q, 0, deSub, subPos + 12, 12); @fixed = true; - if(fixedAdr) - subLog?.WriteQAdrFix(lba); + if(fixedAdr) subLog?.WriteQAdrFix(lba); - if(controlFix) - subLog?.WriteQCtrlFix(lba); + if(controlFix) subLog?.WriteQCtrlFix(lba); - if(fixedZero) - subLog?.WriteQZeroFix(lba); + if(fixedZero) subLog?.WriteQZeroFix(lba); - if(fixedTno) - subLog?.WriteQTnoFix(lba); + if(fixedTno) subLog?.WriteQTnoFix(lba); - if(fixedIndex) - subLog?.WriteQIndexFix(lba); + if(fixedIndex) subLog?.WriteQIndexFix(lba); - if(fixedRelPos) - subLog?.WriteQRelPosFix(lba); + if(fixedRelPos) subLog?.WriteQRelPosFix(lba); - if(fixedAbsPos) - subLog?.WriteQAbsPosFix(lba); + if(fixedAbsPos) subLog?.WriteQAbsPosFix(lba); - if(fixedCrc) - subLog?.WriteQCrcFix(lba); + if(fixedCrc) subLog?.WriteQCrcFix(lba); - if(fixedMcn) - subLog?.WriteQMcnFix(lba); + if(fixedMcn) subLog?.WriteQMcnFix(lba); - if(fixedIsrc) - subLog?.WriteQIsrcFix(lba); + if(fixedIsrc) subLog?.WriteQIsrcFix(lba); } } - if(!pOk || - !crcOk || - !rwOk) - continue; + if(!pOk || !crcOk || !rwOk) continue; - aframe = (byte)(q[9] / 16 * 10 + (q[9] & 0x0F)); + var aframe = (byte)(q[9] / 16 * 10 + (q[9] & 0x0F)); if((q[0] & 0x3) == 1) { - amin = (byte)(q[7] / 16 * 10 + (q[7] & 0x0F)); - asec = (byte)(q[8] / 16 * 10 + (q[8] & 0x0F)); + var amin = (byte)(q[7] / 16 * 10 + (q[7] & 0x0F)); + var asec = (byte)(q[8] / 16 * 10 + (q[8] & 0x0F)); aPos = amin * 60 * 75 + asec * 75 + aframe - 150; } else { ulong expectedSectorAddress = sectorAddress + (ulong)(subPos / 96) + 150; - smin = (byte)(expectedSectorAddress / 60 / 75); - expectedSectorAddress -= (ulong)(smin * 60 * 75); - ssec = (byte)(expectedSectorAddress / 75); + var smin = (byte)(expectedSectorAddress / 60 / 75); + expectedSectorAddress -= (ulong)(smin * 60 * 75); + var ssec = (byte)(expectedSectorAddress / 75); aPos = smin * 60 * 75 + ssec * 75 + aframe - 150; // Next second - if(aPos < prePos) - aPos += 75; + if(aPos < prePos) aPos += 75; } // TODO: Negative sectors - if(aPos < 0) - continue; + if(aPos < 0) continue; prePos = aPos; @@ -293,8 +286,7 @@ public static class CompactDisc subchannelExtents.Remove(aPos); - if(@fixed) - subLog?.WriteEntry(posSub, supportedSubchannel == MmcSubchannel.Raw, lba, 1, false, true); + if(@fixed) subLog?.WriteEntry(posSub, supportedSubchannel == MmcSubchannel.Raw, lba, 1, false, true); } return indexesChanged; @@ -310,6 +302,11 @@ public static class CompactDisc /// Status update callback /// List of smallest known pregap per track /// Set if we are dumping, otherwise converting + /// + /// Gets a list of the new sectors that should be considered part of a pregap, and then + /// re-read + /// + /// Sector address the subchannel was read from /// true if indexes have changed, false otherwise static bool CheckIndexesFromSubchannel(byte[] deSub, Dictionary isrcs, byte currentTrackNumber, ref string mcn, Track[] tracks, DumpLog dumpLog, @@ -318,7 +315,7 @@ public static class CompactDisc out List newPregapSectors, ulong sectorAddress) { var status = false; - newPregapSectors = new List(); + newPregapSectors = []; // Check subchannel for(var subPos = 0; subPos < deSub.Length; subPos += 96) @@ -326,7 +323,7 @@ public static class CompactDisc var q = new byte[12]; Array.Copy(deSub, subPos + 12, q, 0, 12); - CRC16CCITTContext.Data(q, 10, out byte[] crc); + CRC16CcittContext.Data(q, 10, out byte[] crc); bool crcOk = crc[0] == q[10] && crc[1] == q[11]; switch(q[0] & 0x3) @@ -336,16 +333,19 @@ public static class CompactDisc { string isrc = Subchannel.DecodeIsrc(q); - if(isrc is null or "000000000000") - continue; + if(isrc is null or "000000000000") continue; - if(!crcOk) - continue; + if(!crcOk) continue; if(!isrcs.ContainsKey(currentTrackNumber)) { - dumpLog?.WriteLine($"Found new ISRC {isrc} for track {currentTrackNumber}."); - updateStatus?.Invoke($"Found new ISRC {isrc} for track {currentTrackNumber}."); + dumpLog?.WriteLine(string.Format(Localization.Core.Found_new_ISRC_0_for_track_1, + isrc, + currentTrackNumber)); + + updateStatus?.Invoke(string.Format(Localization.Core.Found_new_ISRC_0_for_track_1, + isrc, + currentTrackNumber)); isrcs[currentTrackNumber] = isrc; } @@ -356,11 +356,15 @@ public static class CompactDisc if(currentTrack?.Sequence == currentTrackNumber) { - dumpLog?. - WriteLine($"ISRC for track {currentTrackNumber} changed from {isrcs[currentTrackNumber]} to {isrc}."); + dumpLog?.WriteLine(string.Format(Localization.Core.ISRC_for_track_0_changed_from_1_to_2, + currentTrackNumber, + isrcs[currentTrackNumber], + isrc)); - updateStatus?. - Invoke($"ISRC for track {currentTrackNumber} changed from {isrcs[currentTrackNumber]} to {isrc}."); + updateStatus?.Invoke(string.Format(Localization.Core.ISRC_for_track_0_changed_from_1_to_2, + currentTrackNumber, + isrcs[currentTrackNumber], + isrc)); isrcs[currentTrackNumber] = isrc; } @@ -374,21 +378,19 @@ public static class CompactDisc { string newMcn = Subchannel.DecodeMcn(q); - if(newMcn is null or "0000000000000") - continue; + if(newMcn is null or "0000000000000") continue; - if(!crcOk) - continue; + if(!crcOk) continue; if(mcn is null) { - dumpLog?.WriteLine($"Found new MCN {newMcn}."); - updateStatus?.Invoke($"Found new MCN {newMcn}."); + dumpLog?.WriteLine(string.Format(Localization.Core.Found_new_MCN_0, newMcn)); + updateStatus?.Invoke(string.Format(Localization.Core.Found_new_MCN_0, newMcn)); } else if(mcn != newMcn) { - dumpLog?.WriteLine($"MCN changed from {mcn} to {newMcn}."); - updateStatus?.Invoke($"MCN changed from {mcn} to {newMcn}."); + dumpLog?.WriteLine(string.Format(Localization.Core.MCN_changed_from_0_to_1, mcn, newMcn)); + updateStatus?.Invoke(string.Format(Localization.Core.MCN_changed_from_0_to_1, mcn, newMcn)); } mcn = newMcn; @@ -397,19 +399,18 @@ public static class CompactDisc } // Positioning - case 1 when !crcOk: continue; + case 1 when !crcOk: + continue; case 1: { var trackNo = (byte)(q[1] / 16 * 10 + (q[1] & 0x0F)); for(var i = 0; i < tracks.Length; i++) { - if(tracks[i].Sequence != trackNo) - continue; + if(tracks[i].Sequence != trackNo) continue; // Pregap - if(q[2] == 0 && - trackNo > 1) + if(q[2] == 0 && trackNo > 1) { var pmin = (byte)(q[3] / 16 * 10 + (q[3] & 0x0F)); var psec = (byte)(q[4] / 16 * 10 + (q[4] & 0x0F)); @@ -418,15 +419,12 @@ public static class CompactDisc // When we are dumping we calculate the pregap in reverse from index 1 back. // When we are not, we go from index 0. - if(!smallestPregapLbaPerTrack.ContainsKey(trackNo)) - smallestPregapLbaPerTrack[trackNo] = dumping ? 1 : 0; + smallestPregapLbaPerTrack.TryAdd(trackNo, dumping ? 1 : 0); - uint firstTrackNumberInSameSession = tracks. - Where(t => t.Session == tracks[i].Session). - Min(t => t.Sequence); + uint firstTrackNumberInSameSession = + tracks.Where(t => t.Session == tracks[i].Session).Min(t => t.Sequence); - if(tracks[i].Sequence == firstTrackNumberInSameSession) - continue; + if(tracks[i].Sequence == firstTrackNumberInSameSession) continue; if(qPos < smallestPregapLbaPerTrack[trackNo]) { @@ -435,35 +433,40 @@ public static class CompactDisc tracks[i].StartSector -= (ulong)dif; smallestPregapLbaPerTrack[trackNo] = qPos; - if(i > 0 && - tracks[i - 1].EndSector >= tracks[i].StartSector) - tracks[i - 1].EndSector = tracks[i].StartSector - 1; + if(i > 0 && tracks[i - 1].EndSector >= tracks[i].StartSector) + tracks[i - 1].EndSector = tracks[i].StartSector - 1; - dumpLog?.WriteLine($"Pregap for track {trackNo} set to {tracks[i].Pregap} sectors."); + dumpLog?.WriteLine(string.Format(Localization.Core.Pregap_for_track_0_set_to_1_sectors, + trackNo, + tracks[i].Pregap)); - updateStatus?.Invoke($"Pregap for track {trackNo} set to {tracks[i].Pregap} sectors."); + updateStatus?.Invoke(string.Format(Localization.Core + .Pregap_for_track_0_set_to_1_sectors, + trackNo, + tracks[i].Pregap)); - for(var p = 0; p < dif; p++) - newPregapSectors.Add(tracks[i].StartSector + (ulong)p); + for(var p = 0; p < dif; p++) newPregapSectors.Add(tracks[i].StartSector + (ulong)p); status = true; } - if(tracks[i].Pregap >= (ulong)qPos) - continue; + if(tracks[i].Pregap >= (ulong)qPos) continue; ulong oldPregap = tracks[i].Pregap; tracks[i].Pregap = (ulong)qPos; tracks[i].StartSector -= tracks[i].Pregap - oldPregap; - if(i > 0 && - tracks[i - 1].EndSector >= tracks[i].StartSector) - tracks[i - 1].EndSector = tracks[i].StartSector - 1; + if(i > 0 && tracks[i - 1].EndSector >= tracks[i].StartSector) + tracks[i - 1].EndSector = tracks[i].StartSector - 1; - dumpLog?.WriteLine($"Pregap for track {trackNo} set to {tracks[i].Pregap} sectors."); + dumpLog?.WriteLine(string.Format(Localization.Core.Pregap_for_track_0_set_to_1_sectors, + trackNo, + tracks[i].Pregap)); - updateStatus?.Invoke($"Pregap for track {trackNo} set to {tracks[i].Pregap} sectors."); + updateStatus?.Invoke(string.Format(Localization.Core.Pregap_for_track_0_set_to_1_sectors, + trackNo, + tracks[i].Pregap)); for(var p = 0; p < (int)(tracks[i].Pregap - oldPregap); p++) newPregapSectors.Add(tracks[i].StartSector + (ulong)p); @@ -473,8 +476,7 @@ public static class CompactDisc continue; } - if(q[2] == 0) - continue; + if(q[2] == 0) continue; var amin = (byte)(q[7] / 16 * 10 + (q[7] & 0x0F)); var asec = (byte)(q[8] / 16 * 10 + (q[8] & 0x0F)); @@ -482,16 +484,19 @@ public static class CompactDisc int aPos = amin * 60 * 75 + asec * 75 + aframe - 150; // Do not set INDEX 1 to a value higher than what the TOC already said. - if(q[2] == 1 && - aPos > (int)tracks[i].StartSector) - continue; + if(q[2] == 1 && aPos > (int)tracks[i].StartSector) continue; - if(tracks[i].Indexes.ContainsKey(q[2]) && - aPos >= tracks[i].Indexes[q[2]]) - continue; + if(tracks[i].Indexes.ContainsKey(q[2]) && aPos >= tracks[i].Indexes[q[2]]) continue; - dumpLog?.WriteLine($"Setting index {q[2]} for track {trackNo} to LBA {aPos}."); - updateStatus?.Invoke($"Setting index {q[2]} for track {trackNo} to LBA {aPos}."); + dumpLog?.WriteLine(string.Format(Localization.Core.Setting_index_0_for_track_1_to_LBA_2, + q[2], + trackNo, + aPos)); + + updateStatus?.Invoke(string.Format(Localization.Core.Setting_index_0_for_track_1_to_LBA_2, + q[2], + trackNo, + aPos)); tracks[i].Indexes[q[2]] = aPos; @@ -530,93 +535,73 @@ public static class CompactDisc for(var j = 0; j < 18; j++) { - cdTextPack1[j] = (byte)(cdTextPack1[j] | ((subchannel[i++] & 0x3F) << 2)); + cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x3F) << 2); - cdTextPack1[j] = (byte)(cdTextPack1[j++] | ((subchannel[i] & 0xC0) >> 4)); + cdTextPack1[j] = (byte)(cdTextPack1[j++] | (subchannel[i] & 0xC0) >> 4); - if(j < 18) - cdTextPack1[j] = (byte)(cdTextPack1[j] | ((subchannel[i++] & 0x0F) << 4)); + if(j < 18) cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x0F) << 4); - if(j < 18) - cdTextPack1[j] = (byte)(cdTextPack1[j++] | ((subchannel[i] & 0x3C) >> 2)); + if(j < 18) cdTextPack1[j] = (byte)(cdTextPack1[j++] | (subchannel[i] & 0x3C) >> 2); - if(j < 18) - cdTextPack1[j] = (byte)(cdTextPack1[j] | ((subchannel[i++] & 0x03) << 6)); + if(j < 18) cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x03) << 6); - if(j < 18) - cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x3F)); + if(j < 18) cdTextPack1[j] = (byte)(cdTextPack1[j] | subchannel[i++] & 0x3F); } for(var j = 0; j < 18; j++) { - cdTextPack2[j] = (byte)(cdTextPack2[j] | ((subchannel[i++] & 0x3F) << 2)); + cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x3F) << 2); - cdTextPack2[j] = (byte)(cdTextPack2[j++] | ((subchannel[i] & 0xC0) >> 4)); + cdTextPack2[j] = (byte)(cdTextPack2[j++] | (subchannel[i] & 0xC0) >> 4); - if(j < 18) - cdTextPack2[j] = (byte)(cdTextPack2[j] | ((subchannel[i++] & 0x0F) << 4)); + if(j < 18) cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x0F) << 4); - if(j < 18) - cdTextPack2[j] = (byte)(cdTextPack2[j++] | ((subchannel[i] & 0x3C) >> 2)); + if(j < 18) cdTextPack2[j] = (byte)(cdTextPack2[j++] | (subchannel[i] & 0x3C) >> 2); - if(j < 18) - cdTextPack2[j] = (byte)(cdTextPack2[j] | ((subchannel[i++] & 0x03) << 6)); + if(j < 18) cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x03) << 6); - if(j < 18) - cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x3F)); + if(j < 18) cdTextPack2[j] = (byte)(cdTextPack2[j] | subchannel[i++] & 0x3F); } for(var j = 0; j < 18; j++) { - cdTextPack3[j] = (byte)(cdTextPack3[j] | ((subchannel[i++] & 0x3F) << 2)); + cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x3F) << 2); - cdTextPack3[j] = (byte)(cdTextPack3[j++] | ((subchannel[i] & 0xC0) >> 4)); + cdTextPack3[j] = (byte)(cdTextPack3[j++] | (subchannel[i] & 0xC0) >> 4); - if(j < 18) - cdTextPack3[j] = (byte)(cdTextPack3[j] | ((subchannel[i++] & 0x0F) << 4)); + if(j < 18) cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x0F) << 4); - if(j < 18) - cdTextPack3[j] = (byte)(cdTextPack3[j++] | ((subchannel[i] & 0x3C) >> 2)); + if(j < 18) cdTextPack3[j] = (byte)(cdTextPack3[j++] | (subchannel[i] & 0x3C) >> 2); - if(j < 18) - cdTextPack3[j] = (byte)(cdTextPack3[j] | ((subchannel[i++] & 0x03) << 6)); + if(j < 18) cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x03) << 6); - if(j < 18) - cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x3F)); + if(j < 18) cdTextPack3[j] = (byte)(cdTextPack3[j] | subchannel[i++] & 0x3F); } for(var j = 0; j < 18; j++) { - cdTextPack4[j] = (byte)(cdTextPack4[j] | ((subchannel[i++] & 0x3F) << 2)); + cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x3F) << 2); - cdTextPack4[j] = (byte)(cdTextPack4[j++] | ((subchannel[i] & 0xC0) >> 4)); + cdTextPack4[j] = (byte)(cdTextPack4[j++] | (subchannel[i] & 0xC0) >> 4); - if(j < 18) - cdTextPack4[j] = (byte)(cdTextPack4[j] | ((subchannel[i++] & 0x0F) << 4)); + if(j < 18) cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x0F) << 4); - if(j < 18) - cdTextPack4[j] = (byte)(cdTextPack4[j++] | ((subchannel[i] & 0x3C) >> 2)); + if(j < 18) cdTextPack4[j] = (byte)(cdTextPack4[j++] | (subchannel[i] & 0x3C) >> 2); - if(j < 18) - cdTextPack4[j] = (byte)(cdTextPack4[j] | ((subchannel[i++] & 0x03) << 6)); + if(j < 18) cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x03) << 6); - if(j < 18) - cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x3F)); + if(j < 18) cdTextPack4[j] = (byte)(cdTextPack4[j] | subchannel[i++] & 0x3F); } i = 0; - for(var j = 0; j < 24; j++) - cdSubRwPack1[j] = (byte)(subchannel[i++] & 0x3F); + for(var j = 0; j < 24; j++) cdSubRwPack1[j] = (byte)(subchannel[i++] & 0x3F); - for(var j = 0; j < 24; j++) - cdSubRwPack2[j] = (byte)(subchannel[i++] & 0x3F); + for(var j = 0; j < 24; j++) cdSubRwPack2[j] = (byte)(subchannel[i++] & 0x3F); - for(var j = 0; j < 24; j++) - cdSubRwPack3[j] = (byte)(subchannel[i++] & 0x3F); + for(var j = 0; j < 24; j++) cdSubRwPack3[j] = (byte)(subchannel[i++] & 0x3F); - for(var j = 0; j < 24; j++) - cdSubRwPack4[j] = (byte)(subchannel[i++] & 0x3F); + for(var j = 0; j < 24; j++) cdSubRwPack4[j] = (byte)(subchannel[i++] & 0x3F); switch(cdSubRwPack1[0]) { @@ -698,17 +683,13 @@ public static class CompactDisc break; } - if((cdTextPack1[0] & 0x80) == 0x80) - cdtextPacket = true; + if((cdTextPack1[0] & 0x80) == 0x80) cdtextPacket = true; - if((cdTextPack2[0] & 0x80) == 0x80) - cdtextPacket = true; + if((cdTextPack2[0] & 0x80) == 0x80) cdtextPacket = true; - if((cdTextPack3[0] & 0x80) == 0x80) - cdtextPacket = true; + if((cdTextPack3[0] & 0x80) == 0x80) cdtextPacket = true; - if((cdTextPack4[0] & 0x80) == 0x80) - cdtextPacket = true; + if((cdTextPack4[0] & 0x80) == 0x80) cdtextPacket = true; } /// Checks if subchannel contains a TEXT packet @@ -725,78 +706,62 @@ public static class CompactDisc for(var j = 0; j < 18; j++) { - cdTextPack1[j] = (byte)(cdTextPack1[j] | ((subchannel[i++] & 0x3F) << 2)); + cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x3F) << 2); - cdTextPack1[j] = (byte)(cdTextPack1[j++] | ((subchannel[i] & 0xC0) >> 4)); + cdTextPack1[j] = (byte)(cdTextPack1[j++] | (subchannel[i] & 0xC0) >> 4); - if(j < 18) - cdTextPack1[j] = (byte)(cdTextPack1[j] | ((subchannel[i++] & 0x0F) << 4)); + if(j < 18) cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x0F) << 4); - if(j < 18) - cdTextPack1[j] = (byte)(cdTextPack1[j++] | ((subchannel[i] & 0x3C) >> 2)); + if(j < 18) cdTextPack1[j] = (byte)(cdTextPack1[j++] | (subchannel[i] & 0x3C) >> 2); - if(j < 18) - cdTextPack1[j] = (byte)(cdTextPack1[j] | ((subchannel[i++] & 0x03) << 6)); + if(j < 18) cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x03) << 6); - if(j < 18) - cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x3F)); + if(j < 18) cdTextPack1[j] = (byte)(cdTextPack1[j] | subchannel[i++] & 0x3F); } for(var j = 0; j < 18; j++) { - cdTextPack2[j] = (byte)(cdTextPack2[j] | ((subchannel[i++] & 0x3F) << 2)); + cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x3F) << 2); - cdTextPack2[j] = (byte)(cdTextPack2[j++] | ((subchannel[i] & 0xC0) >> 4)); + cdTextPack2[j] = (byte)(cdTextPack2[j++] | (subchannel[i] & 0xC0) >> 4); - if(j < 18) - cdTextPack2[j] = (byte)(cdTextPack2[j] | ((subchannel[i++] & 0x0F) << 4)); + if(j < 18) cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x0F) << 4); - if(j < 18) - cdTextPack2[j] = (byte)(cdTextPack2[j++] | ((subchannel[i] & 0x3C) >> 2)); + if(j < 18) cdTextPack2[j] = (byte)(cdTextPack2[j++] | (subchannel[i] & 0x3C) >> 2); - if(j < 18) - cdTextPack2[j] = (byte)(cdTextPack2[j] | ((subchannel[i++] & 0x03) << 6)); + if(j < 18) cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x03) << 6); - if(j < 18) - cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x3F)); + if(j < 18) cdTextPack2[j] = (byte)(cdTextPack2[j] | subchannel[i++] & 0x3F); } for(var j = 0; j < 18; j++) { - cdTextPack3[j] = (byte)(cdTextPack3[j] | ((subchannel[i++] & 0x3F) << 2)); + cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x3F) << 2); - cdTextPack3[j] = (byte)(cdTextPack3[j++] | ((subchannel[i] & 0xC0) >> 4)); + cdTextPack3[j] = (byte)(cdTextPack3[j++] | (subchannel[i] & 0xC0) >> 4); - if(j < 18) - cdTextPack3[j] = (byte)(cdTextPack3[j] | ((subchannel[i++] & 0x0F) << 4)); + if(j < 18) cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x0F) << 4); - if(j < 18) - cdTextPack3[j] = (byte)(cdTextPack3[j++] | ((subchannel[i] & 0x3C) >> 2)); + if(j < 18) cdTextPack3[j] = (byte)(cdTextPack3[j++] | (subchannel[i] & 0x3C) >> 2); - if(j < 18) - cdTextPack3[j] = (byte)(cdTextPack3[j] | ((subchannel[i++] & 0x03) << 6)); + if(j < 18) cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x03) << 6); - if(j < 18) - cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x3F)); + if(j < 18) cdTextPack3[j] = (byte)(cdTextPack3[j] | subchannel[i++] & 0x3F); } for(var j = 0; j < 18; j++) { - cdTextPack4[j] = (byte)(cdTextPack4[j] | ((subchannel[i++] & 0x3F) << 2)); + cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x3F) << 2); - cdTextPack4[j] = (byte)(cdTextPack4[j++] | ((subchannel[i] & 0xC0) >> 4)); + cdTextPack4[j] = (byte)(cdTextPack4[j++] | (subchannel[i] & 0xC0) >> 4); - if(j < 18) - cdTextPack4[j] = (byte)(cdTextPack4[j] | ((subchannel[i++] & 0x0F) << 4)); + if(j < 18) cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x0F) << 4); - if(j < 18) - cdTextPack4[j] = (byte)(cdTextPack4[j++] | ((subchannel[i] & 0x3C) >> 2)); + if(j < 18) cdTextPack4[j] = (byte)(cdTextPack4[j++] | (subchannel[i] & 0x3C) >> 2); - if(j < 18) - cdTextPack4[j] = (byte)(cdTextPack4[j] | ((subchannel[i++] & 0x03) << 6)); + if(j < 18) cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x03) << 6); - if(j < 18) - cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x3F)); + if(j < 18) cdTextPack4[j] = (byte)(cdTextPack4[j] | subchannel[i++] & 0x3F); } var status = true; @@ -806,11 +771,9 @@ public static class CompactDisc var cdTextPack1Crc = BigEndianBitConverter.ToUInt16(cdTextPack1, 16); var cdTextPack1ForCrc = new byte[16]; Array.Copy(cdTextPack1, 0, cdTextPack1ForCrc, 0, 16); - ushort calculatedCdtp1Crc = CRC16CCITTContext.Calculate(cdTextPack1ForCrc); + ushort calculatedCdtp1Crc = CRC16CcittContext.Calculate(cdTextPack1ForCrc); - if(cdTextPack1Crc != calculatedCdtp1Crc && - cdTextPack1Crc != 0) - status = false; + if(cdTextPack1Crc != calculatedCdtp1Crc && cdTextPack1Crc != 0) status = false; } if((cdTextPack2[0] & 0x80) == 0x80) @@ -818,11 +781,9 @@ public static class CompactDisc var cdTextPack2Crc = BigEndianBitConverter.ToUInt16(cdTextPack2, 16); var cdTextPack2ForCrc = new byte[16]; Array.Copy(cdTextPack2, 0, cdTextPack2ForCrc, 0, 16); - ushort calculatedCdtp2Crc = CRC16CCITTContext.Calculate(cdTextPack2ForCrc); + ushort calculatedCdtp2Crc = CRC16CcittContext.Calculate(cdTextPack2ForCrc); - if(cdTextPack2Crc != calculatedCdtp2Crc && - cdTextPack2Crc != 0) - status = false; + if(cdTextPack2Crc != calculatedCdtp2Crc && cdTextPack2Crc != 0) status = false; } if((cdTextPack3[0] & 0x80) == 0x80) @@ -830,24 +791,19 @@ public static class CompactDisc var cdTextPack3Crc = BigEndianBitConverter.ToUInt16(cdTextPack3, 16); var cdTextPack3ForCrc = new byte[16]; Array.Copy(cdTextPack3, 0, cdTextPack3ForCrc, 0, 16); - ushort calculatedCdtp3Crc = CRC16CCITTContext.Calculate(cdTextPack3ForCrc); + ushort calculatedCdtp3Crc = CRC16CcittContext.Calculate(cdTextPack3ForCrc); - if(cdTextPack3Crc != calculatedCdtp3Crc && - cdTextPack3Crc != 0) - status = false; + if(cdTextPack3Crc != calculatedCdtp3Crc && cdTextPack3Crc != 0) status = false; } - if((cdTextPack4[0] & 0x80) != 0x80) - return status; + if((cdTextPack4[0] & 0x80) != 0x80) return status; var cdTextPack4Crc = BigEndianBitConverter.ToUInt16(cdTextPack4, 16); var cdTextPack4ForCrc = new byte[16]; Array.Copy(cdTextPack4, 0, cdTextPack4ForCrc, 0, 16); - ushort calculatedCdtp4Crc = CRC16CCITTContext.Calculate(cdTextPack4ForCrc); + ushort calculatedCdtp4Crc = CRC16CcittContext.Calculate(cdTextPack4ForCrc); - if(cdTextPack4Crc == calculatedCdtp4Crc || - cdTextPack4Crc == 0) - return status; + if(cdTextPack4Crc == calculatedCdtp4Crc || cdTextPack4Crc == 0) return status; return false; } @@ -870,14 +826,13 @@ public static class CompactDisc /// Set to true if we fixed the MCN, false otherwise /// Set to true if we fixed the ISRC, false otherwise /// true if it was fixed correctly, false otherwise - static bool FixQSubchannel(byte[] deSub, byte[] q, int subPos, string mcn, string isrc, bool fixCrc, - out bool fixedAdr, out bool controlFix, out bool fixedZero, out bool fixedTno, + static bool FixQSubchannel(byte[] deSub, byte[] q, int subPos, string mcn, string isrc, bool fixCrc, + out bool fixedAdr, out bool controlFix, out bool fixedZero, out bool fixedTno, out bool fixedIndex, out bool fixedRelPos, out bool fixedAbsPos, out bool fixedCrc, - out bool fixedMcn, out bool fixedIsrc) + out bool fixedMcn, out bool fixedIsrc) { - byte amin, asec, aframe, pmin, psec, pframe; - byte rmin, rsec, rframe; - int aPos, rPos, pPos, dPos; + byte aframe; + byte rframe; controlFix = false; fixedZero = false; fixedTno = false; @@ -890,14 +845,13 @@ public static class CompactDisc var preQ = new byte[12]; var nextQ = new byte[12]; - Array.Copy(deSub, subPos + 12 - 96, preQ, 0, 12); + Array.Copy(deSub, subPos + 12 - 96, preQ, 0, 12); Array.Copy(deSub, subPos + 12 + 96, nextQ, 0, 12); - bool status; - CRC16CCITTContext.Data(preQ, 10, out byte[] preCrc); + CRC16CcittContext.Data(preQ, 10, out byte[] preCrc); bool preCrcOk = preCrc[0] == preQ[10] && preCrc[1] == preQ[11]; - CRC16CCITTContext.Data(nextQ, 10, out byte[] nextCrc); + CRC16CcittContext.Data(nextQ, 10, out byte[] nextCrc); bool nextCrcOk = nextCrc[0] == nextQ[10] && nextCrc[1] == nextQ[11]; fixedAdr = false; @@ -909,17 +863,16 @@ public static class CompactDisc fixedAdr = true; } - CRC16CCITTContext.Data(q, 10, out byte[] qCrc); - status = qCrc[0] == q[10] && qCrc[1] == q[11]; + CRC16CcittContext.Data(q, 10, out byte[] qCrc); + bool status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(fixedAdr && status) - return true; + if(fixedAdr && status) return true; int oldAdr = q[0] & 0x3; // Try Q-Mode 1 q[0] = (byte)((q[0] & 0xF0) + 1); - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; if(status) @@ -931,7 +884,7 @@ public static class CompactDisc // Try Q-Mode 2 q[0] = (byte)((q[0] & 0xF0) + 2); - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; if(status) @@ -943,7 +896,7 @@ public static class CompactDisc // Try Q-Mode 3 q[0] = (byte)((q[0] & 0xF0) + 3); - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; if(status) @@ -962,7 +915,7 @@ public static class CompactDisc { q[0] = (byte)((q[0] & 0x03) + (preQ[0] & 0xF0)); - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; if(status) @@ -980,7 +933,7 @@ public static class CompactDisc { q[0] = (byte)((q[0] & 0x03) + (nextQ[0] & 0xF0)); - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; if(status) @@ -993,10 +946,7 @@ public static class CompactDisc q[0] = (byte)oldAdr; } - if(preCrcOk && - nextCrcOk && - (nextQ[0] & 0xF0) == (preQ[0] & 0xF0) && - (q[0] & 0xF0) != (nextQ[0] & 0xF0)) + if(preCrcOk && nextCrcOk && (nextQ[0] & 0xF0) == (preQ[0] & 0xF0) && (q[0] & 0xF0) != (nextQ[0] & 0xF0)) { q[0] = (byte)((q[0] & 0x03) + (nextQ[0] & 0xF0)); @@ -1014,53 +964,60 @@ public static class CompactDisc q[6] = 0; fixedZero = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } if(preCrcOk && nextCrcOk) - if(preQ[1] == nextQ[1] && - preQ[1] != q[1]) + { + if(preQ[1] == nextQ[1] && preQ[1] != q[1]) { q[1] = preQ[1]; fixedTno = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } + } if(preCrcOk && nextCrcOk) - if(preQ[2] == nextQ[2] && - preQ[2] != q[2]) + { + if(preQ[2] == nextQ[2] && preQ[2] != q[2]) { q[2] = preQ[2]; fixedIndex = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } + } - amin = (byte)(q[7] / 16 * 10 + (q[7] & 0x0F)); - asec = (byte)(q[8] / 16 * 10 + (q[8] & 0x0F)); - aframe = (byte)(q[9] / 16 * 10 + (q[9] & 0x0F)); - aPos = amin * 60 * 75 + asec * 75 + aframe - 150; + var amin = (byte)(q[7] / 16 * 10 + (q[7] & 0x0F)); + var asec = (byte)(q[8] / 16 * 10 + (q[8] & 0x0F)); + aframe = (byte)(q[9] / 16 * 10 + (q[9] & 0x0F)); + int aPos = amin * 60 * 75 + asec * 75 + aframe - 150; - pmin = (byte)(q[3] / 16 * 10 + (q[3] & 0x0F)); - psec = (byte)(q[4] / 16 * 10 + (q[4] & 0x0F)); - pframe = (byte)(q[5] / 16 * 10 + (q[5] & 0x0F)); - pPos = pmin * 60 * 75 + psec * 75 + pframe; + var pmin = (byte)(q[3] / 16 * 10 + (q[3] & 0x0F)); + var psec = (byte)(q[4] / 16 * 10 + (q[4] & 0x0F)); + var pframe = (byte)(q[5] / 16 * 10 + (q[5] & 0x0F)); + int pPos = pmin * 60 * 75 + psec * 75 + pframe; // TODO: pregap // Not pregap + byte rmin; + + byte rsec; + + int rPos; + + int dPos; + if(q[2] > 0) { // Previous was not pregap either @@ -1110,18 +1067,15 @@ public static class CompactDisc fixedRelPos = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } } // Next is not pregap and we didn't fix relative position with previous - if(nextQ[2] > 0 && - nextCrcOk && - !fixedRelPos) + if(nextQ[2] > 0 && nextCrcOk && !fixedRelPos) { rmin = (byte)(nextQ[3] / 16 * 10 + (nextQ[3] & 0x0F)); rsec = (byte)(nextQ[4] / 16 * 10 + (nextQ[4] & 0x0F)); @@ -1171,11 +1125,10 @@ public static class CompactDisc fixedRelPos = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } } } @@ -1227,18 +1180,15 @@ public static class CompactDisc fixedAbsPos = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } } // Next is not pregap and we didn't fix relative position with previous - if(nextQ[2] > 0 && - nextCrcOk && - !fixedAbsPos) + if(nextQ[2] > 0 && nextCrcOk && !fixedAbsPos) { rmin = (byte)(nextQ[7] / 16 * 10 + (nextQ[7] & 0x0F)); rsec = (byte)(nextQ[8] / 16 * 10 + (nextQ[8] & 0x0F)); @@ -1288,20 +1238,18 @@ public static class CompactDisc fixedAbsPos = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } } - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; // Game Over - if(!fixCrc || status) - return false; + if(!fixCrc || status) return false; // Previous Q's CRC is correct if(preCrcOk) @@ -1324,15 +1272,10 @@ public static class CompactDisc bool relOk = dPos == 1; - if(q[0] != preQ[0] || - q[1] != preQ[1] || - q[2] != preQ[2] || - q[6] != 0 || - !absOk || - !relOk) + if(q[0] != preQ[0] || q[1] != preQ[1] || q[2] != preQ[2] || q[6] != 0 || !absOk || !relOk) return false; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); q[10] = qCrc[0]; q[11] = qCrc[1]; @@ -1362,15 +1305,10 @@ public static class CompactDisc bool relOk = dPos == 1; - if(q[0] != nextQ[0] || - q[1] != nextQ[1] || - q[2] != nextQ[2] || - q[6] != 0 || - !absOk || - !relOk) + if(q[0] != nextQ[0] || q[1] != nextQ[1] || q[2] != nextQ[2] || q[6] != 0 || !absOk || !relOk) return false; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); q[10] = qCrc[0]; q[11] = qCrc[1]; @@ -1401,16 +1339,14 @@ public static class CompactDisc else q[9]++; - if(q[9] >= 0x74) - q[9] = 0; + if(q[9] >= 0x74) q[9] = 0; fixedAbsPos = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } } @@ -1433,41 +1369,36 @@ public static class CompactDisc fixedAbsPos = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } } // We know the MCN if(mcn != null) { - q[1] = (byte)(((mcn[0] - 0x30) & 0x0F) * 16 + ((mcn[1] - 0x30) & 0x0F)); - q[2] = (byte)(((mcn[2] - 0x30) & 0x0F) * 16 + ((mcn[3] - 0x30) & 0x0F)); - q[3] = (byte)(((mcn[4] - 0x30) & 0x0F) * 16 + ((mcn[5] - 0x30) & 0x0F)); - q[4] = (byte)(((mcn[6] - 0x30) & 0x0F) * 16 + ((mcn[7] - 0x30) & 0x0F)); - q[5] = (byte)(((mcn[8] - 0x30) & 0x0F) * 16 + ((mcn[9] - 0x30) & 0x0F)); - q[6] = (byte)(((mcn[10] - 0x30) & 0x0F) * 16 + ((mcn[11] - 0x30) & 0x0F)); - q[7] = (byte)(((mcn[12] - 0x30) & 0x0F) * 8); + q[1] = (byte)((mcn[0] - 0x30 & 0x0F) * 16 + (mcn[1] - 0x30 & 0x0F)); + q[2] = (byte)((mcn[2] - 0x30 & 0x0F) * 16 + (mcn[3] - 0x30 & 0x0F)); + q[3] = (byte)((mcn[4] - 0x30 & 0x0F) * 16 + (mcn[5] - 0x30 & 0x0F)); + q[4] = (byte)((mcn[6] - 0x30 & 0x0F) * 16 + (mcn[7] - 0x30 & 0x0F)); + q[5] = (byte)((mcn[8] - 0x30 & 0x0F) * 16 + (mcn[9] - 0x30 & 0x0F)); + q[6] = (byte)((mcn[10] - 0x30 & 0x0F) * 16 + (mcn[11] - 0x30 & 0x0F)); + q[7] = (byte)((mcn[12] - 0x30 & 0x0F) * 8); q[8] = 0; fixedMcn = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } - if(!fixCrc || - !nextCrcOk || - !preCrcOk) - return false; + if(!fixCrc || !nextCrcOk || !preCrcOk) return false; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); q[10] = qCrc[0]; q[11] = qCrc[1]; @@ -1494,16 +1425,14 @@ public static class CompactDisc else q[9]++; - if(q[9] >= 0x74) - q[9] = 0; + if(q[9] >= 0x74) q[9] = 0; fixedAbsPos = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } } @@ -1526,11 +1455,10 @@ public static class CompactDisc fixedAbsPos = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } } @@ -1547,26 +1475,22 @@ public static class CompactDisc q[2] = (byte)(((i2 & 0xF) << 4) + (i3 >> 2)); q[3] = (byte)(((i3 & 0x3) << 6) + i4); q[4] = (byte)(i5 << 2); - q[5] = (byte)(((isrc[5] - 0x30) & 0x0F) * 16 + ((isrc[6] - 0x30) & 0x0F)); - q[6] = (byte)(((isrc[7] - 0x30) & 0x0F) * 16 + ((isrc[8] - 0x30) & 0x0F)); - q[7] = (byte)(((isrc[9] - 0x30) & 0x0F) * 16 + ((isrc[10] - 0x30) & 0x0F)); - q[8] = (byte)(((isrc[11] - 0x30) & 0x0F) * 16); + q[5] = (byte)((isrc[5] - 0x30 & 0x0F) * 16 + (isrc[6] - 0x30 & 0x0F)); + q[6] = (byte)((isrc[7] - 0x30 & 0x0F) * 16 + (isrc[8] - 0x30 & 0x0F)); + q[7] = (byte)((isrc[9] - 0x30 & 0x0F) * 16 + (isrc[10] - 0x30 & 0x0F)); + q[8] = (byte)((isrc[11] - 0x30 & 0x0F) * 16); fixedIsrc = true; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); status = qCrc[0] == q[10] && qCrc[1] == q[11]; - if(status) - return true; + if(status) return true; } - if(!fixCrc || - !nextCrcOk || - !preCrcOk) - return false; + if(!fixCrc || !nextCrcOk || !preCrcOk) return false; - CRC16CCITTContext.Data(q, 10, out qCrc); + CRC16CcittContext.Data(q, 10, out qCrc); q[10] = qCrc[0]; q[11] = qCrc[1]; @@ -1590,24 +1514,22 @@ public static class CompactDisc /// Progress update callback /// Progress finalization callback /// Output image - public static void GenerateSubchannels(HashSet subchannelExtents, Track[] tracks, - Dictionary trackFlags, ulong blocks, SubchannelLog subLog, - DumpLog dumpLog, InitProgressHandler initProgress, - UpdateProgressHandler updateProgress, EndProgressHandler endProgress, - IWritableImage outputPlugin) + public static void GenerateSubchannels(HashSet subchannelExtents, Track[] tracks, + Dictionary trackFlags, ulong blocks, SubchannelLog subLog, + DumpLog dumpLog, InitProgressHandler initProgress, + UpdateProgressHandler updateProgress, EndProgressHandler endProgress, + IWritableImage outputPlugin) { initProgress?.Invoke(); foreach(int sector in subchannelExtents) { Track track = tracks.LastOrDefault(t => (int)t.StartSector <= sector); - byte trkFlags; byte flags; ulong trackStart; ulong pregap; - if(track == null) - continue; + if(track == null) continue; // Hidden track if(track.Sequence == 0) @@ -1622,7 +1544,7 @@ public static class CompactDisc pregap = track.Pregap; } - if(!trackFlags.TryGetValue((byte)(track?.Sequence ?? 0), out trkFlags) && + if(!trackFlags.TryGetValue((byte)(track?.Sequence ?? 0), out byte trkFlags) && track?.Type != TrackType.Audio) flags = (byte)CdFlags.DataTrack; else @@ -1635,7 +1557,10 @@ public static class CompactDisc else index = 0; - updateProgress?.Invoke($"Generating subchannel for sector {sector}...", sector, (long)blocks); + updateProgress?.Invoke(string.Format(Localization.Core.Generating_subchannel_for_sector_0, sector), + sector, + (long)blocks); + dumpLog?.WriteLine($"Generating subchannel for sector {sector}."); byte[] sub = Subchannel.Generate(sector, track?.Sequence ?? 0, (int)pregap, (int)trackStart, flags, index); diff --git a/Aaru.Core/Media/Detection/MMC.cs b/Aaru.Core/Media/Detection/MMC.cs index 0d91b2896..3649356d2 100644 --- a/Aaru.Core/Media/Detection/MMC.cs +++ b/Aaru.Core/Media/Detection/MMC.cs @@ -27,13 +27,11 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable JoinDeclarationAndInitializer -namespace Aaru.Core.Media.Detection; - using System; using System.Collections.Generic; using System.IO; @@ -50,6 +48,9 @@ using Aaru.Decoders.Sega; using Aaru.Devices; using Aaru.Helpers; using DMI = Aaru.Decoders.Xbox.DMI; +using Sector = Aaru.Decoders.CD.Sector; + +namespace Aaru.Core.Media.Detection; /// Detects media type for MMC class devices public static class MMC @@ -62,63 +63,38 @@ public static class MMC /// SHA256 of PlayStation 2 boot sectors, seen in Japanese discs const string PS2_JAPANESE_HASH = "b82bffb809070d61fe050b7e1545df53d8f3cc648257cdff7502bc0ba6b38870"; + const string MODULE_NAME = "Media detection"; static readonly byte[] _ps3Id = - { + [ 0x50, 0x6C, 0x61, 0x79, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x33, 0x00, 0x00, 0x00, 0x00 - }; + ]; static readonly byte[] _ps4Id = - { + [ 0x50, 0x6C, 0x61, 0x79, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x34, 0x00, 0x00, 0x00, 0x00 - }; + ]; static readonly byte[] _ps5Id = - { + [ 0x50, 0x6C, 0x61, 0x79, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x35, 0x00, 0x00, 0x00, 0x00 - }; + ]; - static readonly byte[] _operaId = - { - 0x01, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x01 - }; + static readonly byte[] _operaId = [0x01, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x01]; // Only present on bootable CDs, but those make more than 99% of all available - static readonly byte[] _fmTownsBootId = - { - 0x49, 0x50, 0x4C, 0x34, 0xEB, 0x55, 0x06 - }; + static readonly byte[] _fmTownsBootId = [0x49, 0x50, 0x4C, 0x34, 0xEB, 0x55, 0x06]; /// Present on first two seconds of second track, says "COPYRIGHT BANDAI" - static readonly byte[] _playdiaCopyright = - { - 0x43, 0x4F, 0x50, 0x59, 0x52, 0x49, 0x47, 0x48, 0x54, 0x20, 0x42, 0x41, 0x4E, 0x44, 0x41, 0x49 - }; - - static readonly byte[] _pcEngineSignature = - { - 0x50, 0x43, 0x20, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x20, 0x43, 0x44, 0x2D, 0x52, 0x4F, 0x4D, 0x20, 0x53, - 0x59, 0x53, 0x54, 0x45, 0x4D - }; - - static readonly byte[] _pcFxSignature = - { - 0x50, 0x43, 0x2D, 0x46, 0x58, 0x3A, 0x48, 0x75, 0x5F, 0x43, 0x44, 0x2D, 0x52, 0x4F, 0x4D - }; - + static readonly byte[] _playdiaCopyright = "COPYRIGHT BANDAI"u8.ToArray(); + static readonly byte[] _pcEngineSignature = "PC Engine CD-ROM SYSTEM"u8.ToArray(); + static readonly byte[] _pcFxSignature = "PC-FX:Hu_CD-ROM"u8.ToArray(); static readonly byte[] _atariSignature = - { - 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, - 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, - 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, - 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x49, 0x52, 0x54, 0x41, 0x52, 0x41, 0x20, 0x49, 0x50, 0x41, - 0x52, 0x50, 0x56, 0x4F, 0x44, 0x45, 0x44, 0x20, 0x54, 0x41, 0x20, 0x41, 0x45, 0x48, 0x44, 0x41, 0x52, 0x45, - 0x41, 0x20, 0x52, 0x54 - }; + "TAIRTAIRTAIRTAIRTAIRTAIRTAIRTAIRTAIRTAIRTAIRTAIRTAIRTAIRTAIRTAIRTARA IPARPVODED TA AEHDAREA RT"u8.ToArray(); /// This is some kind of header. Every 10 bytes there's an audio byte. static readonly byte[] _videoNowColorFrameMarker = - { + [ 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, @@ -142,17 +118,13 @@ public static class MMC 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 - }; + ]; static bool IsData(byte[] sector) { - if(sector?.Length != 2352) - return false; + if(sector?.Length != 2352) return false; - byte[] syncMark = - { - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 - }; + byte[] syncMark = [0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00]; var testMark = new byte[12]; Array.Copy(sector, 0, testMark, 0, 12); @@ -164,13 +136,9 @@ public static class MMC { offset = 0; - if(sector?.Length != 2352) - return false; + if(sector?.Length != 2352) return false; - byte[] syncMark = - { - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 - }; + byte[] syncMark = [0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00]; var testMark = new byte[12]; @@ -223,19 +191,13 @@ public static class MMC /// true if it corresponds to a CD-i, falseotherwise. static bool IsCdi(byte[] sector0, byte[] sector16) { - if(sector16?.Length != 2352) - return false; + if(sector16?.Length != 2352) return false; - byte[] cdiMark = - { - 0x01, 0x43, 0x44, 0x2D - }; + byte[] cdiMark = [0x01, 0x43, 0x44, 0x2D]; bool isData = IsData(sector0); - if(!isData || - sector0[0xF] != 2 && sector0[0xF] != 1) - return false; + if(!isData || sector0[0xF] != 2 && sector0[0xF] != 1) return false; var testMark = new byte[4]; Array.Copy(sector16, 24, testMark, 0, 4); @@ -245,9 +207,7 @@ public static class MMC static bool IsVideoNowColor(byte[] videoFrame) { - if(videoFrame is null || - videoFrame.Length < _videoNowColorFrameMarker.Length) - return false; + if(videoFrame is null || videoFrame.Length < _videoNowColorFrameMarker.Length) return false; var buffer = new byte[_videoNowColorFrameMarker.Length]; @@ -255,11 +215,9 @@ public static class MMC { Array.Copy(videoFrame, framePosition, buffer, 0, buffer.Length); - for(var ab = 9; ab < buffer.Length; ab += 10) - buffer[ab] = 0; + for(var ab = 9; ab < buffer.Length; ab += 10) buffer[ab] = 0; - if(!_videoNowColorFrameMarker.SequenceEqual(buffer)) - continue; + if(!_videoNowColorFrameMarker.SequenceEqual(buffer)) continue; return true; } @@ -275,11 +233,9 @@ public static class MMC { Array.Copy(data, framePosition, buffer, 0, buffer.Length); - for(var ab = 9; ab < buffer.Length; ab += 10) - buffer[ab] = 0; + for(var ab = 9; ab < buffer.Length; ab += 10) buffer[ab] = 0; - if(!_videoNowColorFrameMarker.SequenceEqual(buffer)) - continue; + if(!_videoNowColorFrameMarker.SequenceEqual(buffer)) continue; return 18032 - framePosition; } @@ -288,12 +244,11 @@ public static class MMC } internal static void DetectDiscType(ref MediaType mediaType, int sessions, FullTOC.CDFullTOC? decodedToc, - Device dev, out bool hiddenTrack, out bool hiddenData, - int firstTrackLastSession, ulong blocks) + Device dev, out bool hiddenTrack, out bool hiddenData, + int firstTrackLastSession, ulong blocks) { uint startOfFirstDataTrack = uint.MaxValue; DI.DiscInformation? blurayDi = null; - byte[] cmdBuf; bool sense; byte secondSessionFirstTrack = 0; byte[] sector0; @@ -309,138 +264,55 @@ public static class MMC hiddenTrack = false; hiddenData = false; - sense = dev.GetConfiguration(out cmdBuf, out _, 0, MmcGetConfigurationRt.Current, dev.Timeout, out _); + sense = dev.GetConfiguration(out byte[] cmdBuf, out _, 0, MmcGetConfigurationRt.Current, dev.Timeout, out _); if(!sense) { Features.SeparatedFeatures ftr = Features.Separate(cmdBuf); - AaruConsole.DebugWriteLine("Media-Info command", "GET CONFIGURATION current profile is {0:X4}h", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.GET_CONFIGURATION_current_profile_is_0, ftr.CurrentProfile); - switch(ftr.CurrentProfile) - { - case 0x0001: - mediaType = MediaType.GENERIC_HDD; - - break; - case 0x0005: - mediaType = MediaType.CDMO; - - break; - case 0x0008: - mediaType = MediaType.CD; - - break; - case 0x0009: - mediaType = MediaType.CDR; - - break; - case 0x000A: - mediaType = MediaType.CDRW; - - break; - case 0x0010: - mediaType = MediaType.DVDROM; - - break; - case 0x0011: - mediaType = MediaType.DVDR; - - break; - case 0x0012: - mediaType = MediaType.DVDRAM; - - break; - case 0x0013: - case 0x0014: - mediaType = MediaType.DVDRW; - - break; - case 0x0015: - case 0x0016: - mediaType = MediaType.DVDRDL; - - break; - case 0x0017: - mediaType = MediaType.DVDRWDL; - - break; - case 0x0018: - mediaType = MediaType.DVDDownload; - - break; - case 0x001A: - mediaType = MediaType.DVDPRW; - - break; - case 0x001B: - mediaType = MediaType.DVDPR; - - break; - case 0x0020: - mediaType = MediaType.DDCD; - - break; - case 0x0021: - mediaType = MediaType.DDCDR; - - break; - case 0x0022: - mediaType = MediaType.DDCDRW; - - break; - case 0x002A: - mediaType = MediaType.DVDPRWDL; - - break; - case 0x002B: - mediaType = MediaType.DVDPRDL; - - break; - case 0x0040: - mediaType = MediaType.BDROM; - - break; - case 0x0041: - case 0x0042: - mediaType = MediaType.BDR; - - break; - case 0x0043: - mediaType = MediaType.BDRE; - - break; - case 0x0050: - mediaType = MediaType.HDDVDROM; - - break; - case 0x0051: - mediaType = MediaType.HDDVDR; - - break; - case 0x0052: - mediaType = MediaType.HDDVDRAM; - - break; - case 0x0053: - mediaType = MediaType.HDDVDRW; - - break; - case 0x0058: - mediaType = MediaType.HDDVDRDL; - - break; - case 0x005A: - mediaType = MediaType.HDDVDRWDL; - - break; - } + mediaType = ftr.CurrentProfile switch + { + 0x0001 => MediaType.GENERIC_HDD, + 0x0005 => MediaType.CDMO, + 0x0008 => MediaType.CD, + 0x0009 => MediaType.CDR, + 0x000A => MediaType.CDRW, + 0x0010 => MediaType.DVDROM, + 0x0011 => MediaType.DVDR, + 0x0012 => MediaType.DVDRAM, + 0x0013 or 0x0014 => MediaType.DVDRW, + 0x0015 or 0x0016 => MediaType.DVDRDL, + 0x0017 => MediaType.DVDRWDL, + 0x0018 => MediaType.DVDDownload, + 0x001A => MediaType.DVDPRW, + 0x001B => MediaType.DVDPR, + 0x0020 => MediaType.DDCD, + 0x0021 => MediaType.DDCDR, + 0x0022 => MediaType.DDCDRW, + 0x002A => MediaType.DVDPRWDL, + 0x002B => MediaType.DVDPRDL, + 0x0040 => MediaType.BDROM, + 0x0041 or 0x0042 => MediaType.BDR, + 0x0043 => MediaType.BDRE, + 0x0050 => MediaType.HDDVDROM, + 0x0051 => MediaType.HDDVDR, + 0x0052 => MediaType.HDDVDRAM, + 0x0053 => MediaType.HDDVDRW, + 0x0058 => MediaType.HDDVDRDL, + 0x005A => MediaType.HDDVDRWDL, + _ => mediaType + }; } if(decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == 2) == true) - secondSessionFirstTrack = decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == 2). - Min(t => t.POINT); + { + secondSessionFirstTrack = + decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == 2).Min(t => t.POINT); + } if(mediaType is MediaType.CD or MediaType.CDROMXA or MediaType.CDI) { @@ -467,25 +339,28 @@ public static class MMC if(decodedToc.HasValue) { FullTOC.TrackDataDescriptor a0Track = - decodedToc.Value.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA0 && t.ADR == 1); + decodedToc.Value.TrackDescriptors.FirstOrDefault(t => t is { POINT: 0xA0, ADR: 1 }); if(a0Track.POINT == 0xA0) + { switch(a0Track.PSEC) { case 0x10: - AaruConsole.DebugWriteLine("Media detection", "TOC says disc type is CD-i."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.TOC_says_disc_type_is_CD_i); mediaType = MediaType.CDI; break; case 0x20: - AaruConsole.DebugWriteLine("Media detection", "TOC says disc type is CD-ROM XA."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.TOC_says_disc_type_is_CD_ROM_XA); + mediaType = MediaType.CDROMXA; break; } + } foreach(FullTOC.TrackDataDescriptor track in - decodedToc.Value.TrackDescriptors.Where(t => t.POINT > 0 && t.POINT <= 0x99)) + decodedToc.Value.TrackDescriptors.Where(t => t.POINT is > 0 and <= 0x99)) { if(track.TNO == 1 && ((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack || @@ -495,11 +370,13 @@ public static class MMC if((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack || (TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental) { - var startAddress = (uint)(track.PHOUR * 3600 * 75 + track.PMIN * 60 * 75 + track.PSEC * 75 + - track.PFRAME - 150); + var startAddress = (uint)(track.PHOUR * 3600 * 75 + + track.PMIN * 60 * 75 + + track.PSEC * 75 + + track.PFRAME - + 150); - if(startAddress < startOfFirstDataTrack) - startOfFirstDataTrack = startAddress; + if(startAddress < startOfFirstDataTrack) startOfFirstDataTrack = startAddress; hasDataTrack = true; allFirstSessionTracksAreAudio &= track.POINT >= firstTrackLastSession; @@ -513,65 +390,73 @@ public static class MMC if(mediaType != MediaType.CDI) { - if(hasDataTrack && - hasAudioTrack && - allFirstSessionTracksAreAudio && - sessions == 2) + switch(hasDataTrack) { - AaruConsole.DebugWriteLine("Media detection", - "Disc has audio and data tracks, two sessions, and all data tracks are in second session, setting as CD+."); + case true when hasAudioTrack && allFirstSessionTracksAreAudio && sessions == 2: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core + .Disc_has_audio_and_data_two_sessions_all_data_second_CD_Plus); - mediaType = MediaType.CDPLUS; + mediaType = MediaType.CDPLUS; + + break; + case false when hasAudioTrack && sessions == 1: + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Disc_has_only_audio_in_a_session_CD_Digital_Audio); + + mediaType = MediaType.CDDA; + + break; } - if(!hasDataTrack && - hasAudioTrack && - sessions == 1) + if(hasDataTrack && !hasAudioTrack && sessions == 1) { - AaruConsole.DebugWriteLine("Media detection", - "Disc has only audio tracks in a single session, setting as CD Digital Audio."); - - mediaType = MediaType.CDDA; - } - - if(hasDataTrack && - !hasAudioTrack && - sessions == 1) - { - AaruConsole.DebugWriteLine("Media detection", - "Disc has only data tracks in a single session, setting as CD-ROM."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Disc_has_only_data_in_a_session_CD_ROM); mediaType = MediaType.CDROM; } - if(hasVideoTrack && - !hasDataTrack && - sessions == 1) + if(hasVideoTrack && !hasDataTrack && sessions == 1) { - AaruConsole.DebugWriteLine("Media detection", - "Disc has video tracks in a single session, setting as CD Video."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Disc_has_video_tracks_CD_Video); mediaType = MediaType.CDV; } } if(mediaType is MediaType.CD or MediaType.CDROM && hasDataTrack) - foreach(uint startAddress in decodedToc.Value.TrackDescriptors. - Where(t => t.POINT > 0 && t.POINT <= 0x99 && + { + foreach(uint startAddress in decodedToc.Value.TrackDescriptors + .Where(t => t.POINT is > 0 and <= 0x99 && ((TocControl)(t.CONTROL & 0x0D) == TocControl.DataTrack || (TocControl)(t.CONTROL & 0x0D) == - TocControl.DataTrackIncremental)). - Select(track => (uint)(track.PHOUR * 3600 * 75 + - track.PMIN * 60 * 75 + track.PSEC * 75 + - track.PFRAME - 150) + 16)) + TocControl.DataTrackIncremental)) + .Select(track => (uint)(track.PHOUR * 3600 * 75 + + track.PMIN * 60 * 75 + + track.PSEC * 75 + + track.PFRAME - + 150) + + 16)) { - sense = dev.ReadCd(out cmdBuf, out _, startAddress, 2352, 1, MmcSectorTypes.AllTypes, false, false, - true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + startAddress, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(sense || dev.Error) - continue; + if(sense || dev.Error) continue; if(cmdBuf[0] != 0x00 || cmdBuf[1] != 0xFF || @@ -588,13 +473,13 @@ public static class MMC cmdBuf[15] != 0x02) continue; - AaruConsole.DebugWriteLine("Media detection", - "Disc has a mode 2 data track, setting as CD-ROM XA."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Disc_has_a_mode_two_data_track_CD_ROM_XA); mediaType = MediaType.CDROMXA; break; } + } } if(secondSessionFirstTrack != 0 && @@ -606,42 +491,89 @@ public static class MMC var firstSectorSecondSessionFirstTrack = (uint)(secondSessionFirstTrackTrack.PHOUR * 3600 * 75 + secondSessionFirstTrackTrack.PMIN * 60 * 75 + secondSessionFirstTrackTrack.PSEC * 75 + - secondSessionFirstTrackTrack.PFRAME - 150); + secondSessionFirstTrackTrack.PFRAME - + 150); - sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack, 2352, 1, MmcSectorTypes.AllTypes, - false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + firstSectorSecondSessionFirstTrack, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) firstTrackSecondSession = cmdBuf; else { - sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack, 2352, 1, MmcSectorTypes.Cdda, - false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + firstSectorSecondSessionFirstTrack, + 2352, + 1, + MmcSectorTypes.Cdda, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) - firstTrackSecondSession = cmdBuf; + if(!sense && !dev.Error) firstTrackSecondSession = cmdBuf; } - sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack - 1, 2352, 3, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + firstSectorSecondSessionFirstTrack - 1, + 2352, + 3, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) firstTrackSecondSessionAudio = cmdBuf; else { - sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack - 1, 2352, 3, - MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + firstSectorSecondSessionFirstTrack - 1, + 2352, + 3, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) - firstTrackSecondSessionAudio = cmdBuf; + if(!sense && !dev.Error) firstTrackSecondSessionAudio = cmdBuf; } } @@ -649,15 +581,41 @@ public static class MMC for(var i = 0; i < 9; i++) { - sense = dev.ReadCd(out cmdBuf, out _, (uint)i, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + (uint)i, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); if(sense || dev.Error) { - sense = dev.ReadCd(out cmdBuf, out _, (uint)i, 2352, 1, MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + (uint)i, + 2352, + 1, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); if(sense || !dev.Error) { @@ -676,18 +634,33 @@ public static class MMC if(firstTrack?.POINT is >= 1 and < 0xA0) { - var firstTrackSector = (uint)(firstTrack.Value.PHOUR * 3600 * 75 + firstTrack.Value.PMIN * 60 * 75 + - firstTrack.Value.PSEC * 75 + firstTrack.Value.PFRAME - 150); + var firstTrackSector = (uint)(firstTrack.Value.PHOUR * 3600 * 75 + + firstTrack.Value.PMIN * 60 * 75 + + firstTrack.Value.PSEC * 75 + + firstTrack.Value.PFRAME - + 150); // Check for hidden data before start of track 1 if(firstTrackSector > 0) { - sense = dev.ReadCd(out sector0, out _, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out sector0, + out _, + 0, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!dev.Error && - !sense) + if(!dev.Error && !sense) { hiddenTrack = true; @@ -695,17 +668,29 @@ public static class MMC if(hiddenData) { - sense = dev.ReadCd(out byte[] sector16, out _, 16, 2352, 1, MmcSectorTypes.AllTypes, false, - false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out byte[] sector16, + out _, + 16, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - IsCdi(sector0, sector16)) + if(!sense && IsCdi(sector0, sector16)) { mediaType = MediaType.CDIREADY; - AaruConsole.DebugWriteLine("Media detection", - "Disc has a hidden CD-i track in track 1's pregap, setting as CD-i Ready."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Disc_has_hidden_CD_i_pregap_CD_i_Ready); return; } @@ -718,11 +703,9 @@ public static class MMC { int sectorsForOffset = combinedOffset / 2352; - if(sectorsForOffset < 0) - sectorsForOffset *= -1; + if(sectorsForOffset < 0) sectorsForOffset *= -1; - if(combinedOffset % 2352 != 0) - sectorsForOffset++; + if(combinedOffset % 2352 != 0) sectorsForOffset++; var lba0 = 0; var lba16 = 16; @@ -733,25 +716,64 @@ public static class MMC lba16 -= sectorsForOffset; } - sense = dev.ReadCd(out sector0, out _, (uint)lba0, 2352, (uint)sectorsForOffset + 1, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, - true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out sector0, + out _, + (uint)lba0, + 2352, + (uint)sectorsForOffset + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); // Drive does not support reading negative sectors? if(sense && lba0 < 0) { - dev.ReadCd(out sector0, out _, 0, 2352, 2, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, dev.Timeout, out _); + dev.ReadCd(out sector0, + out _, + 0, + 2352, + 2, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); sector0 = DescrambleAndFixOffset(sector0, combinedOffset, sectorsForOffset); } else sector0 = DescrambleAndFixOffset(sector0, combinedOffset, sectorsForOffset); - dev.ReadCd(out byte[] sector16, out _, (uint)lba16, 2352, (uint)sectorsForOffset + 1, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + dev.ReadCd(out byte[] sector16, + out _, + (uint)lba16, + 2352, + (uint)sectorsForOffset + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); sector16 = DescrambleAndFixOffset(sector16, combinedOffset, sectorsForOffset); @@ -759,8 +781,8 @@ public static class MMC { mediaType = MediaType.CDIREADY; - AaruConsole.DebugWriteLine("Media detection", - "Disc has a hidden CD-i track in track 1's pregap, setting as CD-i Ready."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Disc_has_hidden_CD_i_pregap_CD_i_Ready); return; } @@ -780,44 +802,92 @@ public static class MMC case MediaType.CDROM: case MediaType.CDROMXA: { - sense = dev.ReadCd(out cmdBuf, out _, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 0, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { sector0 = new byte[2048]; Array.Copy(cmdBuf, 16, sector0, 0, 2048); - sense = dev.ReadCd(out cmdBuf, out _, 1, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 1, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { sector1 = new byte[2048]; Array.Copy(cmdBuf, 16, sector1, 0, 2048); } - sense = dev.ReadCd(out cmdBuf, out _, 4200, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 4200, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { playdia1 = new byte[2048]; Array.Copy(cmdBuf, 24, playdia1, 0, 2048); } - sense = dev.ReadCd(out cmdBuf, out _, 4201, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 4201, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { playdia2 = new byte[2048]; Array.Copy(cmdBuf, 24, playdia2, 0, 2048); @@ -825,23 +895,47 @@ public static class MMC if(startOfFirstDataTrack != uint.MaxValue) { - sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack, 2352, 1, MmcSectorTypes.AllTypes, - false, false, true, MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + startOfFirstDataTrack, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { firstDataSectorNotZero = new byte[2048]; Array.Copy(cmdBuf, 16, firstDataSectorNotZero, 0, 2048); } - sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack + 1, 2352, 1, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, - true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + startOfFirstDataTrack + 1, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { secondDataSectorNotZero = new byte[2048]; Array.Copy(cmdBuf, 16, secondDataSectorNotZero, 0, 2048); @@ -852,59 +946,118 @@ public static class MMC for(uint p = 0; p < 12; p++) { - sense = dev.ReadCd(out cmdBuf, out _, p, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + p, + 2352, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(sense || dev.Error) - break; + if(sense || dev.Error) break; ps2Ms.Write(cmdBuf, cmdBuf[0x0F] == 0x02 ? 24 : 16, 2048); } - if(ps2Ms.Length == 0x6000) - ps2BootSectors = ps2Ms.ToArray(); + if(ps2Ms.Length == 0x6000) ps2BootSectors = ps2Ms.ToArray(); } else { - sense = dev.ReadCd(out cmdBuf, out _, 0, 2324, 1, MmcSectorTypes.Mode2, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 0, + 2324, + 1, + MmcSectorTypes.Mode2, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { sector0 = new byte[2048]; Array.Copy(cmdBuf, 0, sector0, 0, 2048); - sense = dev.ReadCd(out cmdBuf, out _, 1, 2324, 1, MmcSectorTypes.Mode2, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 1, + 2324, + 1, + MmcSectorTypes.Mode2, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { sector1 = new byte[2048]; Array.Copy(cmdBuf, 1, sector0, 0, 2048); } - sense = dev.ReadCd(out cmdBuf, out _, 4200, 2324, 1, MmcSectorTypes.Mode2, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 4200, + 2324, + 1, + MmcSectorTypes.Mode2, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { playdia1 = new byte[2048]; Array.Copy(cmdBuf, 0, playdia1, 0, 2048); } - sense = dev.ReadCd(out cmdBuf, out _, 4201, 2324, 1, MmcSectorTypes.Mode2, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 4201, + 2324, + 1, + MmcSectorTypes.Mode2, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { playdia2 = new byte[2048]; Array.Copy(cmdBuf, 0, playdia2, 0, 2048); @@ -912,23 +1065,47 @@ public static class MMC if(startOfFirstDataTrack != uint.MaxValue) { - sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack, 2324, 1, MmcSectorTypes.Mode2, - false, false, false, MmcHeaderCodes.None, true, false, - MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + startOfFirstDataTrack, + 2324, + 1, + MmcSectorTypes.Mode2, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { firstDataSectorNotZero = new byte[2048]; Array.Copy(cmdBuf, 0, firstDataSectorNotZero, 0, 2048); } - sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack + 1, 2324, 1, - MmcSectorTypes.Mode2, false, false, false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + startOfFirstDataTrack + 1, + 2324, + 1, + MmcSectorTypes.Mode2, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { secondDataSectorNotZero = new byte[2048]; Array.Copy(cmdBuf, 0, secondDataSectorNotZero, 0, 2048); @@ -939,63 +1116,130 @@ public static class MMC for(uint p = 0; p < 12; p++) { - sense = dev.ReadCd(out cmdBuf, out _, p, 2324, 1, MmcSectorTypes.Mode2, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + p, + 2324, + 1, + MmcSectorTypes.Mode2, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(sense || dev.Error) - break; + if(sense || dev.Error) break; ps2Ms.Write(cmdBuf, 0, 2048); } - if(ps2Ms.Length == 0x6000) - ps2BootSectors = ps2Ms.ToArray(); + if(ps2Ms.Length == 0x6000) ps2BootSectors = ps2Ms.ToArray(); } else { - sense = dev.ReadCd(out cmdBuf, out _, 0, 2048, 1, MmcSectorTypes.Mode1, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 0, + 2048, + 1, + MmcSectorTypes.Mode1, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { sector0 = cmdBuf; - sense = dev.ReadCd(out cmdBuf, out _, 0, 2048, 1, MmcSectorTypes.Mode1, false, false, false, - MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 0, + 2048, + 1, + MmcSectorTypes.Mode1, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) - sector1 = cmdBuf; + if(!sense && !dev.Error) sector1 = cmdBuf; - sense = dev.ReadCd(out cmdBuf, out _, 0, 2048, 12, MmcSectorTypes.Mode1, false, false, - false, MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 0, + 2048, + 12, + MmcSectorTypes.Mode1, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) - ps2BootSectors = cmdBuf; + if(!sense && !dev.Error) ps2BootSectors = cmdBuf; if(startOfFirstDataTrack != uint.MaxValue) { - sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack, 2048, 1, - MmcSectorTypes.Mode1, false, false, false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + startOfFirstDataTrack, + 2048, + 1, + MmcSectorTypes.Mode1, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) - firstDataSectorNotZero = cmdBuf; + if(!sense && !dev.Error) firstDataSectorNotZero = cmdBuf; - sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack + 1, 2048, 1, - MmcSectorTypes.Mode1, false, false, false, MmcHeaderCodes.None, true, - false, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + startOfFirstDataTrack + 1, + 2048, + 1, + MmcSectorTypes.Mode1, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) - secondDataSectorNotZero = cmdBuf; + if(!sense && !dev.Error) secondDataSectorNotZero = cmdBuf; } } else @@ -1007,7 +1251,8 @@ public static class MMC } // TODO: Check for CD-i Ready - case MediaType.CDI: break; + case MediaType.CDI: + break; case MediaType.DVDROM: case MediaType.HDDVDROM: case MediaType.BDROM: @@ -1015,106 +1260,179 @@ public static class MMC case MediaType.Unknown: if(mediaType is MediaType.BDROM or MediaType.UHDBD) { - sense = dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.DiscInformation, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.DiscInformation, + 0, + dev.Timeout, + out _); - if(!sense) - blurayDi = DI.Decode(cmdBuf); + if(!sense) blurayDi = DI.Decode(cmdBuf); } sense = dev.Read16(out cmdBuf, out _, 0, false, false, false, 0, 2048, 0, 1, false, dev.Timeout, out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { sector0 = cmdBuf; - sense = dev.Read16(out cmdBuf, out _, 0, false, false, false, 1, 2048, 0, 1, false, dev.Timeout, + sense = dev.Read16(out cmdBuf, + out _, + 0, + false, + false, + false, + 1, + 2048, + 0, + 1, + false, + dev.Timeout, out _); - if(!sense && - !dev.Error) - sector1 = cmdBuf; + if(!sense && !dev.Error) sector1 = cmdBuf; - sense = dev.Read16(out cmdBuf, out _, 0, false, false, false, 0, 2048, 0, 12, false, dev.Timeout, + sense = dev.Read16(out cmdBuf, + out _, + 0, + false, + false, + false, + 0, + 2048, + 0, + 12, + false, + dev.Timeout, out _); - if(!sense && - !dev.Error && - cmdBuf.Length == 0x6000) - ps2BootSectors = cmdBuf; + if(!sense && !dev.Error && cmdBuf.Length == 0x6000) ps2BootSectors = cmdBuf; } else { - sense = dev.Read12(out cmdBuf, out _, 0, false, false, false, false, 0, 2048, 0, 1, false, - dev.Timeout, out _); + sense = dev.Read12(out cmdBuf, + out _, + 0, + false, + false, + false, + false, + 0, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { sector0 = cmdBuf; - sense = dev.Read12(out cmdBuf, out _, 0, false, false, false, false, 1, 2048, 0, 1, false, - dev.Timeout, out _); + sense = dev.Read12(out cmdBuf, + out _, + 0, + false, + false, + false, + false, + 1, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(!sense && - !dev.Error) - sector1 = cmdBuf; + if(!sense && !dev.Error) sector1 = cmdBuf; - sense = dev.Read12(out cmdBuf, out _, 0, false, false, false, false, 0, 2048, 0, 12, false, - dev.Timeout, out _); + sense = dev.Read12(out cmdBuf, + out _, + 0, + false, + false, + false, + false, + 0, + 2048, + 0, + 12, + false, + dev.Timeout, + out _); - if(!sense && - !dev.Error && - cmdBuf.Length == 0x6000) - ps2BootSectors = cmdBuf; + if(!sense && !dev.Error && cmdBuf.Length == 0x6000) ps2BootSectors = cmdBuf; } else { - sense = dev.Read10(out cmdBuf, out _, 0, false, false, false, false, 0, 2048, 0, 1, dev.Timeout, + sense = dev.Read10(out cmdBuf, + out _, + 0, + false, + false, + false, + false, + 0, + 2048, + 0, + 1, + dev.Timeout, out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { sector0 = cmdBuf; - sense = dev.Read10(out cmdBuf, out _, 0, false, false, false, false, 1, 2048, 0, 1, - dev.Timeout, out _); + sense = dev.Read10(out cmdBuf, + out _, + 0, + false, + false, + false, + false, + 1, + 2048, + 0, + 1, + dev.Timeout, + out _); - if(!sense && - !dev.Error) - sector1 = cmdBuf; + if(!sense && !dev.Error) sector1 = cmdBuf; - sense = dev.Read10(out cmdBuf, out _, 0, false, false, false, false, 0, 2048, 0, 12, - dev.Timeout, out _); + sense = dev.Read10(out cmdBuf, + out _, + 0, + false, + false, + false, + false, + 0, + 2048, + 0, + 12, + dev.Timeout, + out _); - if(!sense && - !dev.Error && - cmdBuf.Length == 0x6000) - ps2BootSectors = cmdBuf; + if(!sense && !dev.Error && cmdBuf.Length == 0x6000) ps2BootSectors = cmdBuf; } else { sense = dev.Read6(out cmdBuf, out _, 0, 2048, 1, dev.Timeout, out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { sector0 = cmdBuf; sense = dev.Read6(out cmdBuf, out _, 1, 2048, 1, dev.Timeout, out _); - if(!sense && - !dev.Error) - sector1 = cmdBuf; + if(!sense && !dev.Error) sector1 = cmdBuf; sense = dev.Read6(out cmdBuf, out _, 0, 2048, 12, dev.Timeout, out _); - if(!sense && - !dev.Error && - cmdBuf.Length == 0x6000) - ps2BootSectors = cmdBuf; + if(!sense && !dev.Error && cmdBuf.Length == 0x6000) ps2BootSectors = cmdBuf; } } } @@ -1122,80 +1440,63 @@ public static class MMC if(mediaType == MediaType.DVDROM) { - sense = dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + dev.Timeout, + out _); if(!sense) { PFI.PhysicalFormatInformation? pfi = PFI.Decode(cmdBuf, mediaType); if(pfi != null) - switch(pfi.Value.DiskCategory) - { - case DiskCategory.DVDPR: - mediaType = MediaType.DVDPR; - - break; - case DiskCategory.DVDPRDL: - mediaType = MediaType.DVDPRDL; - - break; - case DiskCategory.DVDPRW: - mediaType = MediaType.DVDPRW; - - break; - case DiskCategory.DVDPRWDL: - mediaType = MediaType.DVDPRWDL; - - break; - case DiskCategory.DVDR: - mediaType = pfi.Value.PartVersion >= 6 ? MediaType.DVDRDL : MediaType.DVDR; - - break; - case DiskCategory.DVDRAM: - mediaType = MediaType.DVDRAM; - - break; - case DiskCategory.DVDRW: - mediaType = pfi.Value.PartVersion >= 15 ? MediaType.DVDRWDL : MediaType.DVDRW; - - break; - case DiskCategory.HDDVDR: - mediaType = MediaType.HDDVDR; - - break; - case DiskCategory.HDDVDRAM: - mediaType = MediaType.HDDVDRAM; - - break; - case DiskCategory.HDDVDROM: - mediaType = MediaType.HDDVDROM; - - break; - case DiskCategory.HDDVDRW: - mediaType = MediaType.HDDVDRW; - - break; - case DiskCategory.Nintendo: - mediaType = pfi.Value.DiscSize == DVDSize.Eighty ? MediaType.GOD : MediaType.WOD; - - break; - case DiskCategory.UMD: - mediaType = MediaType.UMD; - - break; - } + { + mediaType = pfi.Value.DiskCategory switch + { + DiskCategory.DVDPR => MediaType.DVDPR, + DiskCategory.DVDPRDL => MediaType.DVDPRDL, + DiskCategory.DVDPRW => MediaType.DVDPRW, + DiskCategory.DVDPRWDL => MediaType.DVDPRWDL, + DiskCategory.DVDR => pfi.Value.PartVersion >= 6 + ? MediaType.DVDRDL + : MediaType.DVDR, + DiskCategory.DVDRAM => MediaType.DVDRAM, + DiskCategory.DVDRW => pfi.Value.PartVersion >= 15 + ? MediaType.DVDRWDL + : MediaType.DVDRW, + DiskCategory.HDDVDR => MediaType.HDDVDR, + DiskCategory.HDDVDRAM => MediaType.HDDVDRAM, + DiskCategory.HDDVDROM => MediaType.HDDVDROM, + DiskCategory.HDDVDRW => MediaType.HDDVDRW, + DiskCategory.Nintendo => pfi.Value.DiscSize == DVDSize.Eighty + ? MediaType.GOD + : MediaType.WOD, + DiskCategory.UMD => MediaType.UMD, + _ => mediaType + }; + } } - sense = dev.ReadDiscStructure(out cmdBuf, out _, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DiscManufacturingInformation, 0, dev.Timeout, + sense = dev.ReadDiscStructure(out cmdBuf, + out _, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DiscManufacturingInformation, + 0, + dev.Timeout, out _); if(!sense) { if(DMI.IsXbox(cmdBuf)) { - AaruConsole.DebugWriteLine("Media detection", + AaruConsole.DebugWriteLine(MODULE_NAME, "Found Xbox DMI, setting disc type to Xbox Game Disc (XGD)."); mediaType = MediaType.XGD; @@ -1208,7 +1509,7 @@ public static class MMC // All XGD3 all have the same number of blocks if(blocks is 25063 or 4229664 or 4246304) // Wxripper unlock { - AaruConsole.DebugWriteLine("Media detection", + AaruConsole.DebugWriteLine(MODULE_NAME, "Found Xbox 360 DMI with {0} blocks, setting disc type to Xbox 360 Game Disc 3 (XGD3)."); mediaType = MediaType.XGD3; @@ -1216,7 +1517,7 @@ public static class MMC return; } - AaruConsole.DebugWriteLine("Media detection", + AaruConsole.DebugWriteLine(MODULE_NAME, "Found Xbox 360 DMI with {0} blocks, setting disc type to Xbox 360 Game Disc 2 (XGD2)."); mediaType = MediaType.XGD2; @@ -1231,8 +1532,20 @@ public static class MMC // Recordables will be checked for PhotoCD only case MediaType.CDR: // Check if ISO9660 - sense = dev.Read12(out byte[] isoSector, out _, 0, false, false, false, false, 16, 2048, 0, 1, false, - dev.Timeout, out _); + sense = dev.Read12(out byte[] isoSector, + out _, + 0, + false, + false, + false, + false, + 16, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); // Sector 16 reads, and contains "CD001" magic? if(sense || @@ -1248,12 +1561,23 @@ public static class MMC while(isoSectorPosition < 32) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, isoSectorPosition, 2048, 0, - 1, false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + isoSectorPosition, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); // If sector cannot be read, break here - if(sense) - break; + if(sense) break; // If sector does not contain "CD001" magic, break if(isoSector[1] != 0x43 || @@ -1264,9 +1588,7 @@ public static class MMC break; // If it is PVD or end of descriptor chain, break - if(isoSector[0] == 1 || - isoSector[0] == 255) - break; + if(isoSector[0] == 1 || isoSector[0] == 255) break; isoSectorPosition++; } @@ -1283,9 +1605,7 @@ public static class MMC var rootStart = BitConverter.ToUInt32(isoSector, 158); var rootLength = BitConverter.ToUInt32(isoSector, 166); - if(rootStart == 0 || - rootLength == 0) - return; + if(rootStart == 0 || rootLength == 0) return; rootLength /= 2048; @@ -1295,11 +1615,22 @@ public static class MMC for(uint i = 0; i < rootLength; i++) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, rootStart + i, 2048, 0, - 1, false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + rootStart + i, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(sense) - break; + if(sense) break; rootMs.Write(isoSector, 0, 2048); } @@ -1311,8 +1642,7 @@ public static class MMC return; } - if(isoSector.Length < 2048) - return; + if(isoSector.Length < 2048) return; var rootPos = 0; uint pcdStart = 0; @@ -1327,11 +1657,9 @@ public static class MMC Array.Copy(isoSector, rootPos + 33, tmpName, 0, nameLen); string name = StringHandlers.CToString(tmpName).ToUpperInvariant(); - if(name.EndsWith(";1", StringComparison.InvariantCulture)) - name = name.Substring(0, name.Length - 2); + if(name.EndsWith(";1", StringComparison.InvariantCulture)) name = name[..^2]; - if(name == "PHOTO_CD" && - (isoSector[rootPos + 25] & 0x02) == 0x02) + if(name == "PHOTO_CD" && (isoSector[rootPos + 25] & 0x02) == 0x02) { pcdStart = BitConverter.ToUInt32(isoSector, rootPos + 2); pcdLength = BitConverter.ToUInt32(isoSector, rootPos + 10) / 2048; @@ -1348,11 +1676,22 @@ public static class MMC for(uint i = 0; i < pcdLength; i++) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, pcdStart + i, 2048, - 0, 1, false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + pcdStart + i, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(sense) - break; + if(sense) break; pcdMs.Write(isoSector, 0, 2048); } @@ -1364,8 +1703,7 @@ public static class MMC return; } - if(isoSector.Length < 2048) - return; + if(isoSector.Length < 2048) return; for(var pi = 0; pi < pcdLength; pi++) { @@ -1381,8 +1719,7 @@ public static class MMC Array.Copy(isoSector, pcdPos + 33, tmpName, 0, nameLen); string name = StringHandlers.CToString(tmpName).ToUpperInvariant(); - if(name.EndsWith(";1", StringComparison.InvariantCulture)) - name = name.Substring(0, name.Length - 2); + if(name.EndsWith(";1", StringComparison.InvariantCulture)) name = name[..^2]; if(name == "INFO.PCD") { @@ -1396,11 +1733,22 @@ public static class MMC if(infoPos > 0) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, infoPos, 2048, 0, 1, - false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + infoPos, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(sense) - break; + if(sense) break; var systemId = new byte[8]; Array.Copy(isoSector, 0, systemId, 0, 8); @@ -1412,8 +1760,8 @@ public static class MMC case "PHOTO_CD": mediaType = MediaType.PCD; - AaruConsole.DebugWriteLine("Media detection", - "Found Photo CD description file, setting disc type to Photo CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Photo_CD_description_file); return; } @@ -1446,11 +1794,11 @@ public static class MMC case MediaType.BDR: case MediaType.BDRE: case MediaType.BDRXL: - case MediaType.BDREXL: return; + case MediaType.BDREXL: + return; } - if(sector0 == null) - return; + if(sector0 == null) return; switch(mediaType) { @@ -1465,8 +1813,7 @@ public static class MMC { mediaType = MediaType.MEGACD; - AaruConsole.DebugWriteLine("Media detection", - "Found Mega/Sega CD IP.BIN, setting disc type to Mega CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_Mega_Sega_CD_IP_BIN); return; } @@ -1475,8 +1822,7 @@ public static class MMC { mediaType = MediaType.SATURNCD; - AaruConsole.DebugWriteLine("Media detection", - "Found Sega Saturn IP.BIN, setting disc type to Saturn CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_Sega_Saturn_IP_BIN); return; } @@ -1486,8 +1832,7 @@ public static class MMC { mediaType = MediaType.GDROM; - AaruConsole.DebugWriteLine("Media detection", - "Found Sega Dreamcast IP.BIN, setting disc type to GD-ROM."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_Sega_Dreamcast_IP_BIN); return; } @@ -1497,20 +1842,20 @@ public static class MMC // The decryption key is applied as XOR. As first byte is originally always NULL, it gives us the key :) byte decryptByte = ps2BootSectors[0]; - for(var i = 0; i < 0x6000; i++) - ps2BootSectors[i] ^= decryptByte; + for(var i = 0; i < 0x6000; i++) ps2BootSectors[i] ^= decryptByte; string ps2BootSectorsHash = Sha256Context.Data(ps2BootSectors, out _); - AaruConsole.DebugWriteLine("Media-info Command", "PlayStation 2 boot sectors SHA256: {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.PlayStation_2_boot_sectors_SHA256_0, ps2BootSectorsHash); if(ps2BootSectorsHash is PS2_PAL_HASH or PS2_NTSC_HASH or PS2_JAPANESE_HASH) { mediaType = MediaType.PS2CD; - AaruConsole.DebugWriteLine("Media detection", - "Found Sony PlayStation 2 boot sectors, setting disc type to PS2 CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Sony_PlayStation_2_boot_sectors); goto hasPs2CdBoot; } @@ -1525,8 +1870,7 @@ public static class MMC { mediaType = MediaType.ThreeDO; - AaruConsole.DebugWriteLine("Media detection", - "Found Opera filesystem, setting disc type to 3DO."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_Opera_filesystem); return; } @@ -1535,29 +1879,25 @@ public static class MMC { mediaType = MediaType.FMTOWNS; - AaruConsole.DebugWriteLine("Media detection", - "Found FM-Towns boot, setting disc type to FM-Towns."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_FM_Towns_boot); return; } } - if(playdia1 != null && - playdia2 != null) + if(playdia1 != null && playdia2 != null) { var pd1 = new byte[_playdiaCopyright.Length]; var pd2 = new byte[_playdiaCopyright.Length]; Array.Copy(playdia1, 38, pd1, 0, pd1.Length); - Array.Copy(playdia2, 0, pd2, 0, pd1.Length); + Array.Copy(playdia2, 0, pd2, 0, pd1.Length); - if(_playdiaCopyright.SequenceEqual(pd1) && - _playdiaCopyright.SequenceEqual(pd2)) + if(_playdiaCopyright.SequenceEqual(pd1) && _playdiaCopyright.SequenceEqual(pd2)) { mediaType = MediaType.Playdia; - AaruConsole.DebugWriteLine("Media detection", - "Found Playdia copyright, setting disc type to Playdia."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_Playdia_copyright); return; } @@ -1572,8 +1912,7 @@ public static class MMC { mediaType = MediaType.SuperCDROM2; - AaruConsole.DebugWriteLine("Media detection", - "Found PC-Engine CD signature, setting disc type to Super CD-ROM²."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_PC_Engine_CD_signature); return; } @@ -1588,8 +1927,7 @@ public static class MMC { mediaType = MediaType.PCFX; - AaruConsole.DebugWriteLine("Media detection", - "Found PC-FX copyright, setting disc type to PC-FX."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_PC_FX_copyright); return; } @@ -1603,13 +1941,11 @@ public static class MMC { Array.Copy(firstTrackSecondSessionAudio, i, jaguar, 0, jaguar.Length); - if(!_atariSignature.SequenceEqual(jaguar)) - continue; + if(!_atariSignature.SequenceEqual(jaguar)) continue; mediaType = MediaType.JaguarCD; - AaruConsole.DebugWriteLine("Media detection", - "Found Atari signature, setting disc type to Jaguar CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_Atari_signature); break; } @@ -1624,8 +1960,8 @@ public static class MMC { mediaType = MediaType.MilCD; - AaruConsole.DebugWriteLine("Media detection", - "Found Sega Dreamcast IP.BIN on second session, setting disc type to MilCD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Sega_Dreamcast_IP_BIN_on_second_session); return; } @@ -1637,8 +1973,7 @@ public static class MMC { mediaType = MediaType.VideoNowColor; - AaruConsole.DebugWriteLine("Media detection", - "Found VideoNow! Color frame, setting disc type to VideoNow Color."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_VideoNow_Color_frame); return; } @@ -1646,9 +1981,22 @@ public static class MMC // Check CD+G, CD+EG and CD+MIDI if(mediaType == MediaType.CDDA) { - sense = dev.ReadCd(out byte[] subBuf, out _, 150, 96, 8, MmcSectorTypes.Cdda, false, false, false, - MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Raw, - dev.Timeout, out _); + sense = dev.ReadCd(out byte[] subBuf, + out _, + 150, + 96, + 8, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + false, + false, + MmcErrorField.None, + MmcSubchannel.Raw, + dev.Timeout, + out _); if(!sense) { @@ -1662,22 +2010,19 @@ public static class MMC Array.Copy(subBuf, i * 96, tmpSub, 0, 96); DetectRwPackets(tmpSub, out bool cdgPacket, out bool cdegPacket, out bool cdmidiPacket); - if(cdgPacket) - cdg = true; + if(cdgPacket) cdg = true; - if(cdegPacket) - cdeg = true; + if(cdegPacket) cdeg = true; - if(cdmidiPacket) - cdmidi = true; + if(cdmidiPacket) cdmidi = true; } if(cdeg) { mediaType = MediaType.CDEG; - AaruConsole.DebugWriteLine("Media detection", - "Found enhanced graphics RW packet, setting disc type to CD+EG."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_enhanced_graphics_RW_packet); return; } @@ -1686,8 +2031,7 @@ public static class MMC { mediaType = MediaType.CDG; - AaruConsole.DebugWriteLine("Media detection", - "Found graphics RW packet, setting disc type to CD+G."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_graphics_RW_packet); return; } @@ -1696,8 +2040,7 @@ public static class MMC { mediaType = MediaType.CDMIDI; - AaruConsole.DebugWriteLine("Media detection", - "Found MIDI RW packet, setting disc type to CD+MIDI."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_MIDI_RW_packet); return; } @@ -1708,8 +2051,20 @@ public static class MMC hasPs2CdBoot: // Check if ISO9660 - sense = dev.Read12(out byte[] isoSector, out _, 0, false, false, false, false, 16, 2048, 0, 1, false, - dev.Timeout, out _); + sense = dev.Read12(out byte[] isoSector, + out _, + 0, + false, + false, + false, + false, + 16, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); // Sector 16 reads, and contains "CD001" magic? if(sense || @@ -1725,12 +2080,23 @@ public static class MMC while(isoSectorPosition < 32) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, isoSectorPosition, 2048, 0, - 1, false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + isoSectorPosition, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); // If sector cannot be read, break here - if(sense) - break; + if(sense) break; // If sector does not contain "CD001" magic, break if(isoSector[1] != 0x43 || @@ -1741,9 +2107,7 @@ public static class MMC break; // If it is PVD or end of descriptor chain, break - if(isoSector[0] == 1 || - isoSector[0] == 255) - break; + if(isoSector[0] == 1 || isoSector[0] == 255) break; isoSectorPosition++; } @@ -1760,9 +2124,7 @@ public static class MMC var rootStart = BitConverter.ToUInt32(isoSector, 158); var rootLength = BitConverter.ToUInt32(isoSector, 166); - if(rootStart == 0 || - rootLength == 0) - return; + if(rootStart == 0 || rootLength == 0) return; rootLength /= 2048; @@ -1772,11 +2134,22 @@ public static class MMC for(uint i = 0; i < rootLength; i++) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, rootStart + i, 2048, 0, - 1, false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + rootStart + i, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(sense) - break; + if(sense) break; rootMs.Write(isoSector, 0, 2048); } @@ -1788,18 +2161,17 @@ public static class MMC return; } - if(isoSector.Length < 2048) - return; + if(isoSector.Length < 2048) return; - var rootEntries = new List(); - uint ngcdIplStart = 0; - uint ngcdIplLength = 0; - uint vcdStart = 0; - uint vcdLength = 0; - uint pcdStart = 0; - uint pcdLength = 0; - uint ps1Start = 0; - uint ps1Length = 0; + List rootEntries = []; + uint ngcdIplStart = 0; + uint ngcdIplLength = 0; + uint vcdStart = 0; + uint vcdLength = 0; + uint pcdStart = 0; + uint pcdLength = 0; + uint ps1Start = 0; + uint ps1Length = 0; for(var ri = 0; ri < rootLength; ri++) { @@ -1814,8 +2186,7 @@ public static class MMC Array.Copy(isoSector, rootPos + 33, tmpName, 0, nameLen); string name = StringHandlers.CToString(tmpName).ToUpperInvariant(); - if(name.EndsWith(";1", StringComparison.InvariantCulture)) - name = name.Substring(0, name.Length - 2); + if(name.EndsWith(";1", StringComparison.InvariantCulture)) name = name[..^2]; rootEntries.Add(name); @@ -1850,15 +2221,13 @@ public static class MMC } } - if(rootEntries.Count == 0) - return; + if(rootEntries.Count == 0) return; if(rootEntries.Contains("CD32.TM")) { mediaType = MediaType.CD32; - AaruConsole.DebugWriteLine("Media detection", - "Found CD32.TM file in root, setting disc type to Amiga CD32."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_CD32_TM_file_in_root); return; } @@ -1867,8 +2236,7 @@ public static class MMC { mediaType = MediaType.CDTV; - AaruConsole.DebugWriteLine("Media detection", - "Found CDTV.TM file in root, setting disc type to Commodore CDTV."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_CDTV_TM_file_in_root); return; } @@ -1878,8 +2246,7 @@ public static class MMC { uint ngcdSectors = ngcdIplLength / 2048; - if(ngcdIplLength % 2048 > 0) - ngcdSectors++; + if(ngcdIplLength % 2048 > 0) ngcdSectors++; string iplTxt; @@ -1890,11 +2257,22 @@ public static class MMC for(uint i = 0; i < ngcdSectors; i++) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, ngcdIplStart + i, - 2048, 0, 1, false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + ngcdIplStart + i, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(sense) - break; + if(sense) break; ngcdMs.Write(isoSector, 0, 2048); } @@ -1920,11 +2298,9 @@ public static class MMC string line = sr.ReadLine(); // End of file - if(line is null || - line.Length == 0) + if(line is null || line.Length == 0) { - if(lineNumber == 0) - correctNeoGeoCd = false; + if(lineNumber == 0) correctNeoGeoCd = false; break; } @@ -1933,14 +2309,12 @@ public static class MMC string[] split = line.Split(','); // Empty line - if(split.Length == 0) - continue; + if(split.Length == 0) continue; // More than 3 entries if(split.Length != 3) { - if(line[0] < 0x20) - break; + if(line[0] < 0x20) break; correctNeoGeoCd = false; @@ -1975,8 +2349,7 @@ public static class MMC } // Second part must be a single digit - if(split[1].Length != 1 || - !byte.TryParse(split[1], out _)) + if(split[1].Length != 1 || !byte.TryParse(split[1], out _)) { correctNeoGeoCd = false; @@ -2009,8 +2382,8 @@ public static class MMC { mediaType = MediaType.NeoGeoCD; - AaruConsole.DebugWriteLine("Media detection", - "Found correct IPL.TXT file in root, setting disc type to Neo Geo CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_correct_IPL_TXT_file_in_root); return; } @@ -2025,11 +2398,22 @@ public static class MMC for(uint i = 0; i < vcdLength; i++) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, vcdStart + i, 2048, - 0, 1, false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + vcdStart + i, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(sense) - break; + if(sense) break; vcdMs.Write(isoSector, 0, 2048); } @@ -2041,8 +2425,7 @@ public static class MMC return; } - if(isoSector.Length < 2048) - return; + if(isoSector.Length < 2048) return; uint infoPos = 0; @@ -2059,8 +2442,7 @@ public static class MMC Array.Copy(isoSector, vcdPos + 33, tmpName, 0, nameLen); string name = StringHandlers.CToString(tmpName).ToUpperInvariant(); - if(name.EndsWith(";1", StringComparison.InvariantCulture)) - name = name.Substring(0, name.Length - 2); + if(name.EndsWith(";1", StringComparison.InvariantCulture)) name = name[..^2]; if(name is "INFO.VCD" or "INFO.SVD") { @@ -2075,11 +2457,22 @@ public static class MMC if(infoPos > 0) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, infoPos, 2048, 0, 1, - false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + infoPos, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(sense) - break; + if(sense) break; var systemId = new byte[8]; Array.Copy(isoSector, 0, systemId, 0, 8); @@ -2091,22 +2484,22 @@ public static class MMC case "VIDEO_CD": mediaType = MediaType.VCD; - AaruConsole.DebugWriteLine("Media detection", - "Found Video CD description file, setting disc type to Video CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Video_CD_description_file); return; case "SUPERVCD": mediaType = MediaType.SVCD; - AaruConsole.DebugWriteLine("Media detection", - "Found Super Video CD description file, setting disc type to Super Video CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Super_Video_CD_description_file); break; case "HQ-VCD": mediaType = MediaType.CVD; - AaruConsole.DebugWriteLine("Media detection", - "Found China Video Disc description file, setting disc type to China Video Disc."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_China_Video_Disc_description_file); break; } @@ -2121,11 +2514,22 @@ public static class MMC for(uint i = 0; i < pcdLength; i++) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, pcdStart + i, 2048, - 0, 1, false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + pcdStart + i, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(sense) - break; + if(sense) break; pcdMs.Write(isoSector, 0, 2048); } @@ -2137,8 +2541,7 @@ public static class MMC return; } - if(isoSector.Length < 2048) - return; + if(isoSector.Length < 2048) return; uint infoPos = 0; @@ -2155,8 +2558,7 @@ public static class MMC Array.Copy(isoSector, pcdPos + 33, tmpName, 0, nameLen); string name = StringHandlers.CToString(tmpName).ToUpperInvariant(); - if(name.EndsWith(";1", StringComparison.InvariantCulture)) - name = name.Substring(0, name.Length - 2); + if(name.EndsWith(";1", StringComparison.InvariantCulture)) name = name[..^2]; if(name == "INFO.PCD") { @@ -2171,11 +2573,22 @@ public static class MMC if(infoPos > 0) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, infoPos, 2048, 0, 1, - false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + infoPos, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(sense) - break; + if(sense) break; var systemId = new byte[8]; Array.Copy(isoSector, 0, systemId, 0, 8); @@ -2187,8 +2600,8 @@ public static class MMC case "PHOTO_CD": mediaType = MediaType.PCD; - AaruConsole.DebugWriteLine("Media detection", - "Found Photo CD description file, setting disc type to Photo CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Photo_CD_description_file); return; } @@ -2200,8 +2613,7 @@ public static class MMC { uint ps1Sectors = ps1Length / 2048; - if(ps1Length % 2048 > 0) - ps1Sectors++; + if(ps1Length % 2048 > 0) ps1Sectors++; string ps1Txt; @@ -2212,11 +2624,22 @@ public static class MMC for(uint i = 0; i < ps1Sectors; i++) { - sense = dev.Read12(out isoSector, out _, 0, false, false, false, false, ps1Start + i, 2048, - 0, 1, false, dev.Timeout, out _); + sense = dev.Read12(out isoSector, + out _, + 0, + false, + false, + false, + false, + ps1Start + i, + 2048, + 0, + 1, + false, + dev.Timeout, + out _); - if(sense) - break; + if(sense) break; ps1Ms.Write(isoSector, 0, 2048); } @@ -2242,55 +2665,48 @@ public static class MMC string line = sr.ReadLine(); // End of file - if(line is null || - line.Length == 0) - break; + if(line is null || line.Length == 0) break; line = line.Replace(" ", ""); if(line.StartsWith("BOOT=cdrom:", StringComparison.InvariantCultureIgnoreCase)) { - ps1BootFile = line.Substring(11); + ps1BootFile = line[11..]; - if(ps1BootFile.StartsWith('\\')) - ps1BootFile = ps1BootFile.Substring(1); + if(ps1BootFile.StartsWith('\\')) ps1BootFile = ps1BootFile[1..]; if(ps1BootFile.EndsWith(";1", StringComparison.InvariantCultureIgnoreCase)) - ps1BootFile = ps1BootFile.Substring(0, ps1BootFile.Length - 2); + ps1BootFile = ps1BootFile[..^2]; break; } - if(line.StartsWith("BOOT2=cdrom0:", StringComparison.InvariantCultureIgnoreCase)) - { - ps2BootFile = line.Substring(13); + if(!line.StartsWith("BOOT2=cdrom0:", StringComparison.InvariantCultureIgnoreCase)) continue; - if(ps2BootFile.StartsWith('\\')) - ps2BootFile = ps2BootFile.Substring(1); + ps2BootFile = line[13..]; - if(ps2BootFile.EndsWith(";1", StringComparison.InvariantCultureIgnoreCase)) - ps2BootFile = ps2BootFile.Substring(0, ps2BootFile.Length - 2); + if(ps2BootFile.StartsWith('\\')) ps2BootFile = ps2BootFile[1..]; - break; - } + if(ps2BootFile.EndsWith(";1", StringComparison.InvariantCultureIgnoreCase)) + ps2BootFile = ps2BootFile[..^2]; + + break; } - if(ps1BootFile != null && - rootEntries.Contains(ps1BootFile.ToUpperInvariant())) + if(ps1BootFile != null && rootEntries.Contains(ps1BootFile.ToUpperInvariant())) { mediaType = MediaType.PS1CD; - AaruConsole.DebugWriteLine("Media detection", - "Found correct SYSTEM.CNF file in root pointing to existing file in root, setting disc type to PlayStation CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_correct_SYSTEM_CNF_file_in_root_PS1); } - if(ps2BootFile != null && - rootEntries.Contains(ps2BootFile.ToUpperInvariant())) + if(ps2BootFile != null && rootEntries.Contains(ps2BootFile.ToUpperInvariant())) { mediaType = MediaType.PS2CD; - AaruConsole.DebugWriteLine("Media detection", - "Found correct SYSTEM.CNF file in root pointing to existing file in root, setting disc type to PlayStation 2 CD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_correct_SYSTEM_CNF_file_in_root_PS2); } } } @@ -2299,7 +2715,8 @@ public static class MMC } // TODO: Check for CD-i Ready - case MediaType.CDI: break; + case MediaType.CDI: + break; case MediaType.DVDROM: case MediaType.HDDVDROM: case MediaType.BDROM: @@ -2311,18 +2728,18 @@ public static class MMC // The decryption key is applied as XOR. As first byte is originally always NULL, it gives us the key :) byte decryptByte = ps2BootSectors[0]; - for(var i = 0; i < 0x6000; i++) - ps2BootSectors[i] ^= decryptByte; + for(var i = 0; i < 0x6000; i++) ps2BootSectors[i] ^= decryptByte; string ps2BootSectorsHash = Sha256Context.Data(ps2BootSectors, out _); - AaruConsole.DebugWriteLine("Media-info Command", "PlayStation 2 boot sectors SHA256: {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.PlayStation_2_boot_sectors_SHA256_0, ps2BootSectorsHash); if(ps2BootSectorsHash is PS2_PAL_HASH or PS2_NTSC_HASH or PS2_JAPANESE_HASH) { - AaruConsole.DebugWriteLine("Media detection", - "Found Sony PlayStation 2 boot sectors, setting disc type to PS2 DVD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Sony_PlayStation_2_boot_sectors_DVD); mediaType = MediaType.PS2DVD; } @@ -2334,48 +2751,47 @@ public static class MMC Array.Copy(sector1, 0, tmp, 0, tmp.Length); if(tmp.SequenceEqual(_ps3Id)) + { switch(mediaType) { case MediaType.BDROM: - AaruConsole.DebugWriteLine("Media detection", - "Found Sony PlayStation 3 boot sectors, setting disc type to PS3 Blu-ray."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Sony_PlayStation_3_boot_sectors); mediaType = MediaType.PS3BD; break; case MediaType.DVDROM: - AaruConsole.DebugWriteLine("Media detection", - "Found Sony PlayStation 3 boot sectors, setting disc type to PS3 DVD."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Sony_PlayStation_3_boot_sectors_DVD); mediaType = MediaType.PS3DVD; break; } + } tmp = new byte[_ps4Id.Length]; Array.Copy(sector1, 512, tmp, 0, tmp.Length); - if(tmp.SequenceEqual(_ps4Id) && - mediaType == MediaType.BDROM) + if(tmp.SequenceEqual(_ps4Id) && mediaType == MediaType.BDROM) { mediaType = MediaType.PS4BD; - AaruConsole.DebugWriteLine("Media detection", - "Found Sony PlayStation 4 boot sectors, setting disc type to PS4 Blu-ray."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Sony_PlayStation_4_boot_sectors); } } - if(blurayDi != null && - blurayDi?.Units?.Length > 0 && - blurayDi?.Units[0].DiscTypeIdentifier != null) + if(blurayDi is { Units.Length: > 0 } && blurayDi?.Units[0].DiscTypeIdentifier != null) { string blurayType = StringHandlers.CToString(blurayDi?.Units[0].DiscTypeIdentifier); switch(blurayType) { case "XG4": - AaruConsole.DebugWriteLine("Media detection", - "Blu-ray type set to \"XG4\", setting disc type to Xbox One Disc (XGD4)."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Blu_ray_type_XG4_setting_disc_type_XGD4); mediaType = MediaType.XGD4; @@ -2392,15 +2808,15 @@ public static class MMC { mediaType = MediaType.PS5BD; - AaruConsole.DebugWriteLine("Media detection", - "Found Sony PlayStation 5 boot sectors, setting disc type to PS5 Ultra HD Blu-ray."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_Sony_PlayStation_5_boot_sectors); break; } } - AaruConsole.DebugWriteLine("Media detection", - "Blu-ray type set to \"BDU\", setting disc type to Ultra HD Blu-ray."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Blu_ray_type_BDU_setting_disc_type_UHD); mediaType = MediaType.UHDBD; @@ -2425,17 +2841,13 @@ public static class MMC var i = 0; - for(var j = 0; j < 24; j++) - cdSubRwPack1[j] = (byte)(subchannel[i++] & 0x3F); + for(var j = 0; j < 24; j++) cdSubRwPack1[j] = (byte)(subchannel[i++] & 0x3F); - for(var j = 0; j < 24; j++) - cdSubRwPack2[j] = (byte)(subchannel[i++] & 0x3F); + for(var j = 0; j < 24; j++) cdSubRwPack2[j] = (byte)(subchannel[i++] & 0x3F); - for(var j = 0; j < 24; j++) - cdSubRwPack3[j] = (byte)(subchannel[i++] & 0x3F); + for(var j = 0; j < 24; j++) cdSubRwPack3[j] = (byte)(subchannel[i++] & 0x3F); - for(var j = 0; j < 24; j++) - cdSubRwPack4[j] = (byte)(subchannel[i++] & 0x3F); + for(var j = 0; j < 24; j++) cdSubRwPack4[j] = (byte)(subchannel[i++] & 0x3F); switch(cdSubRwPack1[0]) { diff --git a/Aaru.Core/Media/Info/CompactDisc.cs b/Aaru.Core/Media/Info/CompactDisc.cs index ff8064619..f1c495020 100644 --- a/Aaru.Core/Media/Info/CompactDisc.cs +++ b/Aaru.Core/Media/Info/CompactDisc.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core.Media.Info; - using System; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -45,6 +43,8 @@ using Aaru.Decoders.CD; using Aaru.Devices; using Device = Aaru.Database.Models.Device; +namespace Aaru.Core.Media.Info; + /// Core operations for retrieving information about CD based media public static class CompactDisc { @@ -62,9 +62,9 @@ public static class CompactDisc /// Set to true if drive supports PLEXTOR READ CD-DA vendor command /// true if offset could be found, false otherwise [SuppressMessage("ReSharper", "TooWideLocalVariableScope")] - public static void GetOffset(CdOffset cdOffset, Device dbDev, bool debug, Aaru.Devices.Device dev, + public static void GetOffset(CdOffset cdOffset, Device dbDev, bool debug, Aaru.Devices.Device dev, MediaType dskType, DumpLog dumpLog, Track[] tracks, UpdateStatusHandler updateStatus, - out int? driveOffset, out int? combinedOffset, out bool supportsPlextorReadCdDa) + out int? driveOffset, out int? combinedOffset, out bool supportsPlextorReadCdDa) { byte[] cmdBuf; bool sense; @@ -92,10 +92,7 @@ public static class CompactDisc if(dataTrack != null) { // Build sync - sectorSync = new byte[] - { - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 - }; + sectorSync = [0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00]; tmpBuf = new byte[sectorSync.Length]; @@ -105,13 +102,18 @@ public static class CompactDisc // Plextor READ CDDA if(dbDev?.ATAPI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true || dbDev?.SCSI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true || - dev.Manufacturer.ToLowerInvariant() == "plextor") + dev.Manufacturer.Equals("plextor", StringComparison.InvariantCultureIgnoreCase)) { - sense = dev.PlextorReadCdDa(out cmdBuf, out _, wantedLba, sectorSize, 3, PlextorSubchannel.None, - dev.Timeout, out _); + sense = dev.PlextorReadCdDa(out cmdBuf, + out _, + wantedLba, + sectorSize, + 3, + PlextorSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { supportsPlextorReadCdDa = true; @@ -119,8 +121,7 @@ public static class CompactDisc { Array.Copy(cmdBuf, i, tmpBuf, 0, sectorSync.Length); - if(!tmpBuf.SequenceEqual(sectorSync)) - continue; + if(!tmpBuf.SequenceEqual(sectorSync)) continue; // De-scramble M and S minute = cmdBuf[i + 12] ^ 0x01; @@ -147,40 +148,76 @@ public static class CompactDisc } if(!offsetFound && - (debug || dbDev?.ATAPI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true || + (debug || + dbDev?.ATAPI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true || dbDev?.SCSI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true || dbDev?.SCSI?.MultiMediaDevice?.TestedMedia?.Any(d => d.CanReadCdScrambled == true) == true || - dev.Manufacturer.ToLowerInvariant() == "hl-dt-st")) + dev.Manufacturer.Equals("hl-dt-st", StringComparison.InvariantCultureIgnoreCase))) { - sense = dev.ReadCd(out cmdBuf, out _, wantedLba, sectorSize, 3, MmcSectorTypes.Cdda, false, - false, false, MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + wantedLba, + sectorSize, + 3, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(!sense && - !dev.Error) + if(!sense && !dev.Error) { // Clear cache for(var i = 0; i < 63; i++) { - sense = dev.ReadCd(out _, out _, (uint)(wantedLba + 3 + 16 * i), sectorSize, 16, - MmcSectorTypes.AllTypes, false, false, false, MmcHeaderCodes.None, - true, false, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, + sense = dev.ReadCd(out _, + out _, + (uint)(wantedLba + 3 + 16 * i), + sectorSize, + 16, + MmcSectorTypes.AllTypes, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, out _); - if(sense || dev.Error) - break; + if(sense || dev.Error) break; } - dev.ReadCd(out cmdBuf, out _, wantedLba, sectorSize, 3, MmcSectorTypes.Cdda, false, false, - false, MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + dev.ReadCd(out cmdBuf, + out _, + wantedLba, + sectorSize, + 3, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); for(var i = 0; i < cmdBuf.Length - sectorSync.Length; i++) { Array.Copy(cmdBuf, i, tmpBuf, 0, sectorSync.Length); - if(!tmpBuf.SequenceEqual(sectorSync)) - continue; + if(!tmpBuf.SequenceEqual(sectorSync)) continue; // De-scramble M and S minute = cmdBuf[i + 12] ^ 0x01; @@ -208,16 +245,13 @@ public static class CompactDisc } } - if(offsetFound) - return; + if(offsetFound) return; // Try to get another the offset some other way, we need an audio track just after a data track, same session for(var i = 1; i < tracks.Length; i++) { - if(tracks[i - 1].Type == TrackType.Audio || - tracks[i].Type != TrackType.Audio) - continue; + if(tracks[i - 1].Type == TrackType.Audio || tracks[i].Type != TrackType.Audio) continue; dataTrack = tracks[i - 1]; audioTrack = tracks[i]; @@ -225,17 +259,27 @@ public static class CompactDisc break; } - if(dataTrack is null || - audioTrack is null) - return; + if(dataTrack is null || audioTrack is null) return; // Found them - sense = dev.ReadCd(out cmdBuf, out _, (uint)audioTrack.StartSector, sectorSize, 3, MmcSectorTypes.Cdda, - false, false, false, MmcHeaderCodes.None, true, false, MmcErrorField.None, - MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + (uint)audioTrack.StartSector, + sectorSize, + 3, + MmcSectorTypes.Cdda, + false, + false, + false, + MmcHeaderCodes.None, + true, + false, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(sense || dev.Error) - return; + if(sense || dev.Error) return; dataTrack.EndSector += 150; @@ -247,20 +291,20 @@ public static class CompactDisc dataTrack.EndSector -= 150; // Convert to BCD - minute = ((minute / 10) << 4) + minute % 10; - second = ((second / 10) << 4) + second % 10; - frame = ((frame / 10) << 4) + frame % 10; + minute = (minute / 10 << 4) + minute % 10; + second = (second / 10 << 4) + second % 10; + frame = (frame / 10 << 4) + frame % 10; // Scramble M and S minute ^= 0x01; second ^= 0x80; // Build sync - sectorSync = new byte[] - { + sectorSync = + [ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, (byte)minute, (byte)second, (byte)frame - }; + ]; tmpBuf = new byte[sectorSync.Length]; @@ -268,8 +312,7 @@ public static class CompactDisc { Array.Copy(cmdBuf, i, tmpBuf, 0, sectorSync.Length); - if(!tmpBuf.SequenceEqual(sectorSync)) - continue; + if(!tmpBuf.SequenceEqual(sectorSync)) continue; combinedOffset = i + 2352; offsetFound = true; @@ -277,29 +320,38 @@ public static class CompactDisc break; } - if(offsetFound || audioTrack.Pregap <= 0) - return; + if(offsetFound || audioTrack.Pregap <= 0) return; - sense = dev.ReadCd(out byte[] dataBuf, out _, (uint)dataTrack.EndSector, sectorSize, 1, - MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, - MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); + sense = dev.ReadCd(out byte[] dataBuf, + out _, + (uint)dataTrack.EndSector, + sectorSize, + 1, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); - if(sense || dev.Error) - return; + if(sense || dev.Error) return; - for(var i = 0; i < dataBuf.Length; i++) - dataBuf[i] ^= Sector.ScrambleTable[i]; + for(var i = 0; i < dataBuf.Length; i++) dataBuf[i] ^= Sector.ScrambleTable[i]; for(var i = 0; i < 2352; i++) { var dataSide = new byte[2352 - i]; var audioSide = new byte[2352 - i]; - Array.Copy(dataBuf, i, dataSide, 0, dataSide.Length); - Array.Copy(cmdBuf, 0, audioSide, 0, audioSide.Length); + Array.Copy(dataBuf, i, dataSide, 0, dataSide.Length); + Array.Copy(cmdBuf, 0, audioSide, 0, audioSide.Length); - if(!dataSide.SequenceEqual(audioSide)) - continue; + if(!dataSide.SequenceEqual(audioSide)) continue; combinedOffset = audioSide.Length; @@ -310,29 +362,57 @@ public static class CompactDisc { var videoNowColorFrame = new byte[9 * sectorSize]; - sense = dev.ReadCd(out cmdBuf, out _, 0, sectorSize, 9, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, - dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, + out _, + 0, + sectorSize, + 9, + MmcSectorTypes.AllTypes, + false, + false, + true, + MmcHeaderCodes.AllHeaders, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, + out _); if(sense || dev.Error) { - sense = dev.ReadCd(out cmdBuf, out _, 0, sectorSize, 9, MmcSectorTypes.Cdda, false, false, true, - MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, + sense = dev.ReadCd(out cmdBuf, + out _, + 0, + sectorSize, + 9, + MmcSectorTypes.Cdda, + false, + false, + true, + MmcHeaderCodes.None, + true, + true, + MmcErrorField.None, + MmcSubchannel.None, + dev.Timeout, out _); - if(sense || dev.Error) - videoNowColorFrame = null; + if(sense || dev.Error) videoNowColorFrame = null; } if(videoNowColorFrame is null) { - dumpLog?.WriteLine("Could not find VideoNow Color frame offset, dump may not be correct."); + dumpLog?.WriteLine(Localization.Core.Could_not_find_VideoNow_Color_frame_offset); updateStatus?.Invoke("Could not find VideoNow Color frame offset, dump may not be correct."); } else { combinedOffset = MMC.GetVideoNowColorOffset(videoNowColorFrame); - dumpLog?.WriteLine($"VideoNow Color frame is offset {combinedOffset} bytes."); + + dumpLog?.WriteLine(string.Format(Localization.Core.VideoNow_Color_frame_is_offset_0_bytes, + combinedOffset)); + updateStatus?.Invoke($"VideoNow Color frame is offset {combinedOffset} bytes."); } } diff --git a/Aaru.Core/Media/Info/ScsiInfo.cs b/Aaru.Core/Media/Info/ScsiInfo.cs index 68996f869..8723dde45 100644 --- a/Aaru.Core/Media/Info/ScsiInfo.cs +++ b/Aaru.Core/Media/Info/ScsiInfo.cs @@ -27,13 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -using DVDDecryption = Aaru.Decryption.DVD.Dump; - -namespace Aaru.Core.Media.Info; - using System; using System.Collections.Generic; using System.Linq; @@ -52,18 +48,21 @@ using Aaru.Decoders.Xbox; using Aaru.Devices; using DeviceInfo = Aaru.Core.Devices.Info.DeviceInfo; using DMI = Aaru.Decoders.Xbox.DMI; +using DVDDecryption = Aaru.Decryption.DVD.Dump; using Inquiry = Aaru.CommonTypes.Structs.Devices.SCSI.Inquiry; +namespace Aaru.Core.Media.Info; + /// Retrieves information from a SCSI device public sealed class ScsiInfo { + const string MODULE_NAME = "Media information"; + /// Initializes this class with the specific device, and fills in the information /// Device public ScsiInfo(Device dev) { - if(dev.Type != DeviceType.SCSI && - dev.Type != DeviceType.ATAPI) - return; + if(dev.Type != DeviceType.SCSI && dev.Type != DeviceType.ATAPI) return; MediaType = MediaType.Unknown; MediaInserted = false; @@ -91,68 +90,70 @@ public sealed class ScsiInfo { resets++; - if(resets < 5) - goto deviceGotReset; + if(resets < 5) goto deviceGotReset; } - if(decSense?.ASC == 0x3A) + switch(decSense?.ASC) { - var leftRetries = 5; - - while(leftRetries > 0) + case 0x3A: { - //AaruConsole.WriteLine("\rWaiting for drive to become ready"); - Thread.Sleep(2000); - sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _); + var leftRetries = 5; - if(!sense) - break; + while(leftRetries > 0) + { + //AaruConsole.WriteLine("\rWaiting for drive to become ready"); + Thread.Sleep(2000); + sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _); - leftRetries--; + if(!sense) break; + + leftRetries--; + } + + if(sense) + { + AaruConsole.ErrorWriteLine(Localization.Core.Please_insert_media_in_drive); + + return; + } + + break; } - - if(sense) + case 0x04 when decSense?.ASCQ == 0x01: { - AaruConsole.ErrorWriteLine("Please insert media in drive"); + var leftRetries = 10; - return; + while(leftRetries > 0) + { + //AaruConsole.WriteLine("\rWaiting for drive to become ready"); + Thread.Sleep(2000); + sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _); + + if(!sense) break; + + leftRetries--; + } + + if(sense) + { + AaruConsole.ErrorWriteLine(Localization.Core.Error_testing_unit_was_ready_0, + Sense.PrettifySense(senseBuf)); + + return; + } + + break; } - } - else if(decSense?.ASC == 0x04 && - decSense?.ASCQ == 0x01) - { - var leftRetries = 10; - - while(leftRetries > 0) - { - //AaruConsole.WriteLine("\rWaiting for drive to become ready"); - Thread.Sleep(2000); - sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _); - - if(!sense) - break; - - leftRetries--; - } - - if(sense) - { - AaruConsole.ErrorWriteLine("Error testing unit was ready:\n{0}", + default: + AaruConsole.ErrorWriteLine(Localization.Core.Error_testing_unit_was_ready_0, Sense.PrettifySense(senseBuf)); return; - } - } - else - { - AaruConsole.ErrorWriteLine("Error testing unit was ready:\n{0}", Sense.PrettifySense(senseBuf)); - - return; } } else { - AaruConsole.ErrorWriteLine("Unknown testing unit was ready."); + AaruConsole.ErrorWriteLine(Localization.Core.Unknown_sense_testing_unit_was_ready); return; } @@ -173,7 +174,7 @@ public sealed class ScsiInfo if(DeviceInfo.ScsiMode?.Header.BlockDescriptors?.Length > 0) scsiDensityCode = (byte)DeviceInfo.ScsiMode.Value.Header.BlockDescriptors[0].Density; - if(DeviceInfo.ScsiMode.Value.Pages != null) + if(DeviceInfo.ScsiMode?.Pages != null) containsFloppyPage = DeviceInfo.ScsiMode.Value.Pages.Any(p => p.Page == 0x05); } @@ -201,19 +202,18 @@ public sealed class ScsiInfo sense = dev.ReadCapacity16(out cmdBuf, out senseBuf, dev.Timeout, out _); - if(!sense) - ReadCapacity16 = cmdBuf; + if(!sense) ReadCapacity16 = cmdBuf; - if(ReadCapacity == null || - Blocks is 0xFFFFFFFF or 0) + if(ReadCapacity == null || Blocks is 0xFFFFFFFF or 0) { - if(ReadCapacity16 == null && - Blocks == 0) + if(ReadCapacity16 == null && Blocks == 0) + { if(dev.ScsiType != PeripheralDeviceTypes.MultiMediaDevice) { - AaruConsole.ErrorWriteLine("Unable to get media capacity"); + AaruConsole.ErrorWriteLine(Localization.Core.Unable_to_get_media_capacity); AaruConsole.ErrorWriteLine("{0}", Sense.PrettifySense(senseBuf)); } + } if(ReadCapacity16 != null) { @@ -226,9 +226,7 @@ public sealed class ScsiInfo } } - if(Blocks != 0 && - BlockSize != 0) - Blocks++; + if(Blocks != 0 && BlockSize != 0) Blocks++; break; case PeripheralDeviceTypes.SequentialAccess: @@ -240,8 +238,7 @@ public sealed class ScsiInfo { sense = dev.ReportDensitySupport(out medBuf, out senseBuf, true, dev.Timeout, out _); - if(!sense && - !seqBuf.SequenceEqual(medBuf)) + if(!sense && !seqBuf.SequenceEqual(medBuf)) { DensitySupport = seqBuf; DensitySupportHeader = Decoders.SCSI.SSC.DensitySupport.DecodeDensity(seqBuf); @@ -254,8 +251,7 @@ public sealed class ScsiInfo { sense = dev.ReportDensitySupport(out medBuf, out senseBuf, true, true, dev.Timeout, out _); - if(!sense && - !seqBuf.SequenceEqual(medBuf)) + if(!sense && !seqBuf.SequenceEqual(medBuf)) { MediaTypeSupport = medBuf; MediaTypeSupportHeader = Decoders.SCSI.SSC.DensitySupport.DecodeMediumType(seqBuf); @@ -269,7 +265,7 @@ public sealed class ScsiInfo AaruConsole.ErrorWriteLine("SCSI READ ATTRIBUTE:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else { - DataFile.WriteTo("Media-Info command", outputPrefix, "_scsi_readattribute.bin", "SCSI READ ATTRIBUTE", seqBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_scsi_readattribute.bin", "SCSI READ ATTRIBUTE", seqBuf); } */ break; @@ -291,197 +287,111 @@ public sealed class ScsiInfo if(dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice) { - sense = dev.GetConfiguration(out cmdBuf, out senseBuf, 0, MmcGetConfigurationRt.Current, dev.Timeout, + sense = dev.GetConfiguration(out cmdBuf, + out senseBuf, + 0, + MmcGetConfigurationRt.Current, + dev.Timeout, out _); if(sense) { - AaruConsole.DebugWriteLine("Media-Info command", "READ GET CONFIGURATION:\n{0}", - Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ GET CONFIGURATION:\n{0}", Sense.PrettifySense(senseBuf)); - if(dev.IsUsb && - scsiMediumType is 0x40 or 0x41 or 0x42) - MediaType = MediaType.FlashDrive; + if(dev.IsUsb && scsiMediumType is 0x40 or 0x41 or 0x42) MediaType = MediaType.FlashDrive; } else { MmcConfiguration = cmdBuf; Features.SeparatedFeatures ftr = Features.Separate(cmdBuf); - AaruConsole.DebugWriteLine("Media-Info command", "GET CONFIGURATION current profile is {0:X4}h", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.GET_CONFIGURATION_current_profile_is_0, ftr.CurrentProfile); - switch(ftr.CurrentProfile) - { - case 0x0001: - MediaType = MediaType.GENERIC_HDD; - - break; - case 0x0002: - switch(scsiMediumType) - { - case 0x01: - MediaType = MediaType.PD650; - - break; - case 0x41: - switch(Blocks) - { - case 58620544: - MediaType = MediaType.REV120; - - break; - case 17090880: - MediaType = MediaType.REV35; - - break; - case 34185728: - MediaType = MediaType.REV70; - - break; - } - - break; - default: - MediaType = MediaType.Unknown; - - break; - } - - break; - case 0x0005: - MediaType = MediaType.CDMO; - - break; - case 0x0008: - MediaType = MediaType.CD; - - break; - case 0x0009: - MediaType = MediaType.CDR; - - break; - case 0x000A: - MediaType = MediaType.CDRW; - - break; - case 0x0010: - MediaType = MediaType.DVDROM; - - break; - case 0x0011: - MediaType = MediaType.DVDR; - - break; - case 0x0012: - MediaType = MediaType.DVDRAM; - - break; - case 0x0013: - case 0x0014: - MediaType = MediaType.DVDRW; - - break; - case 0x0015: - case 0x0016: - MediaType = MediaType.DVDRDL; - - break; - case 0x0017: - MediaType = MediaType.DVDRWDL; - - break; - case 0x0018: - MediaType = MediaType.DVDDownload; - - break; - case 0x001A: - MediaType = MediaType.DVDPRW; - - break; - case 0x001B: - MediaType = MediaType.DVDPR; - - break; - case 0x0020: - MediaType = MediaType.DDCD; - - break; - case 0x0021: - MediaType = MediaType.DDCDR; - - break; - case 0x0022: - MediaType = MediaType.DDCDRW; - - break; - case 0x002A: - MediaType = MediaType.DVDPRWDL; - - break; - case 0x002B: - MediaType = MediaType.DVDPRDL; - - break; - case 0x0040: - MediaType = MediaType.BDROM; - - break; - case 0x0041: - case 0x0042: - MediaType = MediaType.BDR; - - break; - case 0x0043: - MediaType = MediaType.BDRE; - - break; - case 0x0050: - MediaType = MediaType.HDDVDROM; - - break; - case 0x0051: - MediaType = MediaType.HDDVDR; - - break; - case 0x0052: - MediaType = MediaType.HDDVDRAM; - - break; - case 0x0053: - MediaType = MediaType.HDDVDRW; - - break; - case 0x0058: - MediaType = MediaType.HDDVDRDL; - - break; - case 0x005A: - MediaType = MediaType.HDDVDRWDL; - - break; - } + MediaType = ftr.CurrentProfile switch + { + 0x0001 => MediaType.GENERIC_HDD, + 0x0002 => scsiMediumType switch + { + 0x01 => MediaType.PD650, + 0x41 => Blocks switch + { + 58620544 => MediaType.REV120, + 17090880 => MediaType.REV35, + 34185728 => MediaType.REV70, + _ => MediaType + }, + _ => MediaType.Unknown + }, + 0x0005 => MediaType.CDMO, + 0x0008 => MediaType.CD, + 0x0009 => MediaType.CDR, + 0x000A => MediaType.CDRW, + 0x0010 => MediaType.DVDROM, + 0x0011 => MediaType.DVDR, + 0x0012 => MediaType.DVDRAM, + 0x0013 or 0x0014 => MediaType.DVDRW, + 0x0015 or 0x0016 => MediaType.DVDRDL, + 0x0017 => MediaType.DVDRWDL, + 0x0018 => MediaType.DVDDownload, + 0x001A => MediaType.DVDPRW, + 0x001B => MediaType.DVDPR, + 0x0020 => MediaType.DDCD, + 0x0021 => MediaType.DDCDR, + 0x0022 => MediaType.DDCDRW, + 0x002A => MediaType.DVDPRWDL, + 0x002B => MediaType.DVDPRDL, + 0x0040 => MediaType.BDROM, + 0x0041 or 0x0042 => MediaType.BDR, + 0x0043 => MediaType.BDRE, + 0x0050 => MediaType.HDDVDROM, + 0x0051 => MediaType.HDDVDR, + 0x0052 => MediaType.HDDVDRAM, + 0x0053 => MediaType.HDDVDRW, + 0x0058 => MediaType.HDDVDRDL, + 0x005A => MediaType.HDDVDRWDL, + _ => MediaType + }; } - if(MediaType == MediaType.PD650 && - Blocks == 1281856) - MediaType = MediaType.PD650_WORM; + if(MediaType == MediaType.PD650 && Blocks == 1281856) MediaType = MediaType.PD650_WORM; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.RecognizedFormatLayers, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.RecognizedFormatLayers, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Recognized Format Layers\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Recognized_Format_Layers_0, Sense.PrettifySense(senseBuf)); + } else RecognizedFormatLayers = cmdBuf; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.WriteProtectionStatus, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.WriteProtectionStatus, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Write Protection Status\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Write_Protection_Status_0, Sense.PrettifySense(senseBuf)); + } else WriteProtectionStatus = cmdBuf; @@ -489,101 +399,99 @@ public sealed class ScsiInfo /* sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.CapabilityList, 0, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Capability List\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: Capability List\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else - DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_capabilitylist.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_readdiscstructure_capabilitylist.bin", "SCSI READ DISC STRUCTURE", cmdBuf); */ - #region All DVD and HD DVD types - if(MediaType is MediaType.DVDDownload or MediaType.DVDPR or MediaType.DVDPRDL or MediaType.DVDPRW - or MediaType.DVDPRWDL or MediaType.DVDR or MediaType.DVDRAM or MediaType.DVDRDL - or MediaType.DVDROM or MediaType.DVDRW or MediaType.DVDRWDL or MediaType.HDDVDR - or MediaType.HDDVDRAM or MediaType.HDDVDRDL or MediaType.HDDVDROM or MediaType.HDDVDRW +#region All DVD and HD DVD types + + if(MediaType is MediaType.DVDDownload + or MediaType.DVDPR + or MediaType.DVDPRDL + or MediaType.DVDPRW + or MediaType.DVDPRWDL + or MediaType.DVDR + or MediaType.DVDRAM + or MediaType.DVDRDL + or MediaType.DVDROM + or MediaType.DVDRW + or MediaType.DVDRWDL + or MediaType.HDDVDR + or MediaType.HDDVDRAM + or MediaType.HDDVDRDL + or MediaType.HDDVDROM + or MediaType.HDDVDRW or MediaType.HDDVDRWDL) { - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: PFI\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_PFI_0, Sense.PrettifySense(senseBuf)); + } else { DvdPfi = cmdBuf; DecodedPfi = PFI.Decode(cmdBuf, MediaType); if(DecodedPfi.HasValue) + { if(MediaType == MediaType.DVDROM) - switch(DecodedPfi.Value.DiskCategory) - { - case DiskCategory.DVDPR: - MediaType = MediaType.DVDPR; - - break; - case DiskCategory.DVDPRDL: - MediaType = MediaType.DVDPRDL; - - break; - case DiskCategory.DVDPRW: - MediaType = MediaType.DVDPRW; - - break; - case DiskCategory.DVDPRWDL: - MediaType = MediaType.DVDPRWDL; - - break; - case DiskCategory.DVDR: - MediaType = DecodedPfi.Value.PartVersion >= 6 ? MediaType.DVDRDL : MediaType.DVDR; - - break; - case DiskCategory.DVDRAM: - MediaType = MediaType.DVDRAM; - - break; - default: - MediaType = MediaType.DVDROM; - - break; - case DiskCategory.DVDRW: - MediaType = DecodedPfi.Value.PartVersion >= 15 ? MediaType.DVDRWDL - : MediaType.DVDRW; - - break; - case DiskCategory.HDDVDR: - MediaType = MediaType.HDDVDR; - - break; - case DiskCategory.HDDVDRAM: - MediaType = MediaType.HDDVDRAM; - - break; - case DiskCategory.HDDVDROM: - MediaType = MediaType.HDDVDROM; - - break; - case DiskCategory.HDDVDRW: - MediaType = MediaType.HDDVDRW; - - break; - case DiskCategory.Nintendo: - MediaType = DecodedPfi.Value.DiscSize == DVDSize.Eighty ? MediaType.GOD - : MediaType.WOD; - - break; - case DiskCategory.UMD: - MediaType = MediaType.UMD; - - break; - } + { + MediaType = DecodedPfi.Value.DiskCategory switch + { + DiskCategory.DVDPR => MediaType.DVDPR, + DiskCategory.DVDPRDL => MediaType.DVDPRDL, + DiskCategory.DVDPRW => MediaType.DVDPRW, + DiskCategory.DVDPRWDL => MediaType.DVDPRWDL, + DiskCategory.DVDR => DecodedPfi.Value.PartVersion >= 6 + ? MediaType.DVDRDL + : MediaType.DVDR, + DiskCategory.DVDRAM => MediaType.DVDRAM, + DiskCategory.DVDRW => DecodedPfi.Value.PartVersion >= 15 + ? MediaType.DVDRWDL + : MediaType.DVDRW, + DiskCategory.HDDVDR => MediaType.HDDVDR, + DiskCategory.HDDVDRAM => MediaType.HDDVDRAM, + DiskCategory.HDDVDROM => MediaType.HDDVDROM, + DiskCategory.HDDVDRW => MediaType.HDDVDRW, + DiskCategory.Nintendo => DecodedPfi.Value.DiscSize == DVDSize.Eighty + ? MediaType.GOD + : MediaType.WOD, + DiskCategory.UMD => MediaType.UMD, + _ => MediaType.DVDROM + }; + } + } } - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DiscManufacturingInformation, 0, dev.Timeout, + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DiscManufacturingInformation, + 0, + dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: DMI\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_DMI_0, Sense.PrettifySense(senseBuf)); + } else { DvdDmi = cmdBuf; @@ -600,98 +508,175 @@ public sealed class ScsiInfo } } } - #endregion All DVD and HD DVD types - #region DVD-ROM +#endregion All DVD and HD DVD types + +#region DVD-ROM + if(MediaType is MediaType.DVDDownload or MediaType.DVDROM) { - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.CopyrightInformation, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.CopyrightInformation, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: CMI\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_CMI_0, Sense.PrettifySense(senseBuf)); + } else DvdCmi = cmdBuf; } - #endregion DVD-ROM + +#endregion DVD-ROM switch(MediaType) { - #region DVD-ROM and HD DVD-ROM +#region DVD-ROM and HD DVD-ROM + case MediaType.DVDDownload: case MediaType.DVDROM: case MediaType.HDDVDROM: - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.BurstCuttingArea, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.BurstCuttingArea, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: BCA\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_BCA_0, Sense.PrettifySense(senseBuf)); + } else DvdBca = cmdBuf; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdAacs, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdAacs, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: DVD AACS\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_DVD_AACS_0, Sense.PrettifySense(senseBuf)); + } else DvdAacs = cmdBuf; break; - #endregion DVD-ROM and HD DVD-ROM - #region DVD-RAM and HD DVD-RAM +#endregion DVD-ROM and HD DVD-ROM + +#region DVD-RAM and HD DVD-RAM + case MediaType.DVDRAM: case MediaType.HDDVDRAM: - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdramDds, 0, dev.Timeout, out _); - - if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: DDS\n{0}", - Sense.PrettifySense(senseBuf)); - else - DvdRamDds = cmdBuf; - - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdramMediumStatus, 0, dev.Timeout, out _); - - if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Medium Status\n{0}", - Sense.PrettifySense(senseBuf)); - else - DvdRamCartridgeStatus = cmdBuf; - - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdramSpareAreaInformation, 0, dev.Timeout, + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdramDds, + 0, + dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: SAI\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_DDS_0, Sense.PrettifySense(senseBuf)); + } + else + DvdRamDds = cmdBuf; + + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdramMediumStatus, + 0, + dev.Timeout, + out _); + + if(sense) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Medium_Status_0, + Sense.PrettifySense(senseBuf)); + } + else + DvdRamCartridgeStatus = cmdBuf; + + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdramSpareAreaInformation, + 0, + dev.Timeout, + out _); + + if(sense) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_SAI_0, + Sense.PrettifySense(senseBuf)); + } else DvdRamSpareArea = cmdBuf; break; - #endregion DVD-RAM and HD DVD-RAM - #region DVD-R and HD DVD-R +#endregion DVD-RAM and HD DVD-RAM + +#region DVD-R and HD DVD-R + case MediaType.DVDR: case MediaType.HDDVDR: - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.LastBorderOutRmd, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.LastBorderOutRmd, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", - "READ DISC STRUCTURE: Last-Out Border RMD\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Last_Out_Border_RMD_0, Sense.PrettifySense(senseBuf)); + } else LastBorderOutRmd = cmdBuf; break; - #endregion DVD-R and HD DVD-R + +#endregion DVD-R and HD DVD-R } var dvdDecrypt = new DVDDecryption(dev); @@ -699,85 +684,117 @@ public sealed class ScsiInfo if(!sense) { - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DiscKey, dvdDecrypt.Agid, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DiscKey, + dvdDecrypt.Agid, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Disc Key\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Disc_Key_0, Sense.PrettifySense(senseBuf)); + } else DvdDiscKey = cmdBuf; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.SectorCopyrightInformation, dvdDecrypt.Agid, - dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.SectorCopyrightInformation, + dvdDecrypt.Agid, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Sector CMI\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Sector_CMI_0, Sense.PrettifySense(senseBuf)); + } else DvdSectorCmi = cmdBuf; } - #region Require drive authentication, won't work +#region Require drive authentication, won't work + /* sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.MediaIdentifier, 0, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Media ID\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: Media ID\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else - DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_mediaid.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_readdiscstructure_dvd_mediaid.bin", "SCSI READ DISC STRUCTURE", cmdBuf); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.MediaKeyBlock, 0, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: MKB\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: MKB\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else - DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_mkb.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_readdiscstructure_dvd_mkb.bin", "SCSI READ DISC STRUCTURE", cmdBuf); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.AACSVolId, 0, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: AACS Volume ID\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: AACS Volume ID\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else - DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_aacsvolid.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_readdiscstructure_aacsvolid.bin", "SCSI READ DISC STRUCTURE", cmdBuf); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.AACSMediaSerial, 0, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: AACS Media Serial Number\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: AACS Media Serial Number\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else - DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_aacssn.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_readdiscstructure_aacssn.bin", "SCSI READ DISC STRUCTURE", cmdBuf); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.AACSMediaId, 0, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: AACS Media ID\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: AACS Media ID\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else - DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_aacsmediaid.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_readdiscstructure_aacsmediaid.bin", "SCSI READ DISC STRUCTURE", cmdBuf); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.AACSMKB, 0, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: AACS MKB\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: AACS MKB\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else - DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_aacsmkb.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_readdiscstructure_aacsmkb.bin", "SCSI READ DISC STRUCTURE", cmdBuf); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.AACSLBAExtents, 0, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: AACS LBA Extents\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: AACS LBA Extents\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else - DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_aacslbaextents.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_readdiscstructure_aacslbaextents.bin", "SCSI READ DISC STRUCTURE", cmdBuf); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.AACSMKBCPRM, 0, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: AACS CPRM MKB\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: AACS CPRM MKB\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else - DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_aacscprmmkb.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_readdiscstructure_aacscprmmkb.bin", "SCSI READ DISC STRUCTURE", cmdBuf); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.AACSDataKeys, 0, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: AACS Data Keys\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: AACS Data Keys\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else - DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_aacsdatakeys.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DataFile.WriteTo(MODULE_NAME, outputPrefix, "_readdiscstructure_aacsdatakeys.bin", "SCSI READ DISC STRUCTURE", cmdBuf); */ - #endregion Require drive authentication, won't work - #region DVD-R and DVD-RW +#endregion Require drive authentication, won't work + +#region DVD-R and DVD-RW + if(MediaType is MediaType.DVDR or MediaType.DVDRW or MediaType.DVDRDL or MediaType.DVDRWDL) { - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PreRecordedInfo, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PreRecordedInfo, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Pre-Recorded Info\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Pre_Recorded_Info_0, Sense.PrettifySense(senseBuf)); + } else { DvdPreRecordedInfo = cmdBuf; @@ -785,32 +802,53 @@ public sealed class ScsiInfo DecodedDvdPrePitInformation = PRI.Decode(cmdBuf); } } - #endregion DVD-R and DVD-RW + +#endregion DVD-R and DVD-RW switch(MediaType) { - #region DVD-R, DVD-RW and HD DVD-R +#region DVD-R, DVD-RW and HD DVD-R + case MediaType.DVDR: case MediaType.DVDRW: case MediaType.DVDRDL: case MediaType.DVDRWDL: case MediaType.HDDVDR: - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdrMediaIdentifier, 0, dev.Timeout, out _); - - if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: DVD-R Media ID\n{0}", - Sense.PrettifySense(senseBuf)); - else - DvdrMediaIdentifier = cmdBuf; - - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdrPhysicalInformation, 0, dev.Timeout, + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdrMediaIdentifier, + 0, + dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: DVD-R PFI\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_DVD_R_Media_ID_0, Sense.PrettifySense(senseBuf)); + } + else + DvdrMediaIdentifier = cmdBuf; + + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdrPhysicalInformation, + 0, + dev.Timeout, + out _); + + if(sense) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_DVD_R_PFI_0, + Sense.PrettifySense(senseBuf)); + } else { DvdrPhysicalInformation = cmdBuf; @@ -819,242 +857,445 @@ public sealed class ScsiInfo } break; - #endregion DVD-R, DVD-RW and HD DVD-R - #region All DVD+ +#endregion DVD-R, DVD-RW and HD DVD-R + +#region All DVD+ + case MediaType.DVDPR: case MediaType.DVDPRDL: case MediaType.DVDPRW: case MediaType.DVDPRWDL: - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.Adip, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.Adip, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: ADIP\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_ADIP_0, Sense.PrettifySense(senseBuf)); + } else DvdPlusAdip = cmdBuf; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.Dcb, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.Dcb, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: DCB\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_DCB_0, Sense.PrettifySense(senseBuf)); + } else DvdPlusDcb = cmdBuf; break; - #endregion All DVD+ - #region HD DVD-ROM +#endregion All DVD+ + +#region HD DVD-ROM + case MediaType.HDDVDROM: - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.HddvdCopyrightInformation, 0, dev.Timeout, + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.HddvdCopyrightInformation, + 0, + dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: HD DVD CMI\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_HD_DVD_CMI_0, Sense.PrettifySense(senseBuf)); + } else HddvdCopyrightInformation = cmdBuf; break; - #endregion HD DVD-ROM + +#endregion HD DVD-ROM } - #region HD DVD-R - if(MediaType == MediaType.HDDVDR) - { - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.HddvdrMediumStatus, 0, dev.Timeout, out _); - - if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: HD DVD-R Medium Status\n{0}", - Sense.PrettifySense(senseBuf)); - else - HddvdrMediumStatus = cmdBuf; - - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.HddvdrLastRmd, 0, dev.Timeout, out _); - - if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Last RMD\n{0}", - Sense.PrettifySense(senseBuf)); - else - HddvdrLastRmd = cmdBuf; - } - #endregion HD DVD-R - - #region DVD-R DL, DVD-RW DL, DVD+R DL, DVD+RW DL - if(MediaType is MediaType.DVDPRDL or MediaType.DVDRDL or MediaType.DVDRWDL or MediaType.DVDPRWDL) - { - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DvdrLayerCapacity, 0, dev.Timeout, out _); - - if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Layer Capacity\n{0}", - Sense.PrettifySense(senseBuf)); - else - DvdrLayerCapacity = cmdBuf; - } - #endregion DVD-R DL, DVD-RW DL, DVD+R DL, DVD+RW DL - switch(MediaType) { - #region DVD-R DL - case MediaType.DVDRDL: - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.MiddleZoneStart, 0, dev.Timeout, out _); +#region HD DVD-R - if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Middle Zone Start\n{0}", - Sense.PrettifySense(senseBuf)); - else - DvdrDlMiddleZoneStart = cmdBuf; - - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.JumpIntervalSize, 0, dev.Timeout, out _); - - if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Jump Interval Size\n{0}", - Sense.PrettifySense(senseBuf)); - else - DvdrDlJumpIntervalSize = cmdBuf; - - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.ManualLayerJumpStartLba, 0, dev.Timeout, + case MediaType.HDDVDR: + { + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.HddvdrMediumStatus, + 0, + dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", - "READ DISC STRUCTURE: Manual Layer Jump Start LBA\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_HD_DVD_R_Medium_Status, Sense.PrettifySense(senseBuf)); + } + else + HddvdrMediumStatus = cmdBuf; + + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.HddvdrLastRmd, + 0, + dev.Timeout, + out _); + + if(sense) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Last_RMD_0, + Sense.PrettifySense(senseBuf)); + } + else + HddvdrLastRmd = cmdBuf; + + break; + } + +#endregion HD DVD-R + +#region DVD-R DL, DVD-RW DL, DVD+R DL, DVD+RW DL + + case MediaType.DVDPRDL or MediaType.DVDRDL or MediaType.DVDRWDL or MediaType.DVDPRWDL: + { + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DvdrLayerCapacity, + 0, + dev.Timeout, + out _); + + if(sense) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Layer_Capacity_0, + Sense.PrettifySense(senseBuf)); + } + else + DvdrLayerCapacity = cmdBuf; + + break; + } + +#endregion DVD-R DL, DVD-RW DL, DVD+R DL, DVD+RW DL + } + + switch(MediaType) + { +#region DVD-R DL + + case MediaType.DVDRDL: + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.MiddleZoneStart, + 0, + dev.Timeout, + out _); + + if(sense) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Middle_Zone_Start_0, + Sense.PrettifySense(senseBuf)); + } + else + DvdrDlMiddleZoneStart = cmdBuf; + + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.JumpIntervalSize, + 0, + dev.Timeout, + out _); + + if(sense) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Jump_Interval_Size_0, + Sense.PrettifySense(senseBuf)); + } + else + DvdrDlJumpIntervalSize = cmdBuf; + + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.ManualLayerJumpStartLba, + 0, + dev.Timeout, + out _); + + if(sense) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Manual_Layer_Jump_Start_LBA_0, + Sense.PrettifySense(senseBuf)); + } else DvdrDlManualLayerJumpStartLba = cmdBuf; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.RemapAnchorPoint, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.RemapAnchorPoint, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Remap Anchor Point\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Remap_Anchor_Point_0, Sense.PrettifySense(senseBuf)); + } else DvdrDlRemapAnchorPoint = cmdBuf; break; - #endregion DVD-R DL - #region All Blu-ray +#endregion DVD-R DL + +#region All Blu-ray + case MediaType.BDR: case MediaType.BDRE: case MediaType.BDROM: case MediaType.UHDBD: case MediaType.BDRXL: case MediaType.BDREXL: - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.DiscInformation, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.DiscInformation, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: DI\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_DI_0, Sense.PrettifySense(senseBuf)); + } else BlurayDiscInformation = cmdBuf; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.Pac, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.Pac, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: PAC\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_PAC_0, Sense.PrettifySense(senseBuf)); + } else BlurayPac = cmdBuf; break; - #endregion All Blu-ray + +#endregion All Blu-ray } switch(MediaType) { - #region BD-ROM only +#region BD-ROM only + case MediaType.BDROM: case MediaType.UHDBD: - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.BdBurstCuttingArea, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.BdBurstCuttingArea, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: BCA\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_BCA_0, Sense.PrettifySense(senseBuf)); + } else BlurayBurstCuttingArea = cmdBuf; break; - #endregion BD-ROM only - #region Writable Blu-ray only +#endregion BD-ROM only + +#region Writable Blu-ray only + case MediaType.BDR: case MediaType.BDRE: case MediaType.BDRXL: case MediaType.BDREXL: - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.BdDds, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.BdDds, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: DDS\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_DDS_0, Sense.PrettifySense(senseBuf)); + } else BlurayDds = cmdBuf; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.CartridgeStatus, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.CartridgeStatus, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Cartridge Status\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Cartridge_Status_0, Sense.PrettifySense(senseBuf)); + } else BlurayCartridgeStatus = cmdBuf; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.BdSpareAreaInformation, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.BdSpareAreaInformation, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", + { + AaruConsole.DebugWriteLine(MODULE_NAME, "READ DISC STRUCTURE: Spare Area Information\n{0}", Sense.PrettifySense(senseBuf)); + } else BluraySpareAreaInformation = cmdBuf; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, - MmcDiscStructureFormat.RawDfl, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Bd, + 0, + 0, + MmcDiscStructureFormat.RawDfl, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: Raw DFL\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_Raw_DFL_0, Sense.PrettifySense(senseBuf)); + } else BlurayRawDfl = cmdBuf; - sense = dev.ReadDiscInformation(out cmdBuf, out senseBuf, - MmcDiscInformationDataTypes.TrackResources, dev.Timeout, out _); + sense = dev.ReadDiscInformation(out cmdBuf, + out senseBuf, + MmcDiscInformationDataTypes.TrackResources, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC INFORMATION 001b\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_001b_0, Sense.PrettifySense(senseBuf)); + } else BlurayTrackResources = cmdBuf; - sense = dev.ReadDiscInformation(out cmdBuf, out senseBuf, MmcDiscInformationDataTypes.PowResources, - dev.Timeout, out _); + sense = dev.ReadDiscInformation(out cmdBuf, + out senseBuf, + MmcDiscInformationDataTypes.PowResources, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC INFORMATION 010b\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_010b_0, Sense.PrettifySense(senseBuf)); + } else BlurayPowResources = cmdBuf; break; - #endregion Writable Blu-ray only - #region CDs +#endregion Writable Blu-ray only + +#region CDs + case MediaType.CD: case MediaType.CDR: case MediaType.CDROM: @@ -1065,24 +1306,29 @@ public sealed class ScsiInfo bool tocSense = dev.ReadTocPmaAtip(out cmdBuf, out senseBuf, false, 0, 0, dev.Timeout, out _); if(tocSense) - AaruConsole.DebugWriteLine("Media-Info command", "READ TOC/PMA/ATIP: TOC\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_TOC_PMA_ATIP_TOC_0, Sense.PrettifySense(senseBuf)); + } else { Toc = cmdBuf; DecodedToc = TOC.Decode(cmdBuf); // As we have a TOC we know it is a CD - if(MediaType == MediaType.Unknown) - MediaType = MediaType.CD; + if(MediaType == MediaType.Unknown) MediaType = MediaType.CD; } // ATIP exists on blank CDs sense = dev.ReadAtip(out cmdBuf, out senseBuf, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ TOC/PMA/ATIP: ATIP\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_TOC_PMA_ATIP_ATIP_0, Sense.PrettifySense(senseBuf)); + } else { Atip = cmdBuf; @@ -1102,8 +1348,11 @@ public sealed class ScsiInfo sense = dev.ReadSessionInfo(out cmdBuf, out senseBuf, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ TOC/PMA/ATIP: Session info\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_TOC_PMA_ATIP_Session_Info_0, Sense.PrettifySense(senseBuf)); + } else if(cmdBuf.Length > 4) { Session = cmdBuf; @@ -1119,8 +1368,11 @@ public sealed class ScsiInfo sense = dev.ReadRawToc(out cmdBuf, out senseBuf, 1, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ TOC/PMA/ATIP: Raw TOC\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_TOC_PMA_ATIP_Raw_TOC_0, Sense.PrettifySense(senseBuf)); + } else if(cmdBuf.Length > 4) { RawToc = cmdBuf; @@ -1131,16 +1383,21 @@ public sealed class ScsiInfo sense = dev.ReadPma(out cmdBuf, out senseBuf, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ TOC/PMA/ATIP: PMA\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_TOC_PMA_ATIP_PMA_0, Sense.PrettifySense(senseBuf)); - else if(cmdBuf.Length > 4) - Pma = cmdBuf; + } + else if(cmdBuf.Length > 4) Pma = cmdBuf; sense = dev.ReadCdText(out cmdBuf, out senseBuf, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ TOC/PMA/ATIP: CD-TEXT\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_TOC_PMA_ATIP_CD_TEXT_0, Sense.PrettifySense(senseBuf)); + } else if(cmdBuf.Length > 4) { CdTextLeadIn = cmdBuf; @@ -1149,10 +1406,7 @@ public sealed class ScsiInfo sense = dev.ReadMcn(out string mcn, out _, out _, dev.Timeout, out _); - if(!sense && - mcn != null && - mcn != "0000000000000") - Mcn = mcn; + if(!sense && mcn != null && mcn != "0000000000000") Mcn = mcn; Isrcs = new Dictionary(); @@ -1160,30 +1414,37 @@ public sealed class ScsiInfo { sense = dev.ReadIsrc(i, out string isrc, out _, out _, dev.Timeout, out _); - if(!sense && - isrc != null && - isrc != "000000000000") - Isrcs.Add(i, isrc); + if(!sense && isrc != null && isrc != "000000000000") Isrcs.Add(i, isrc); } - if(Isrcs.Count == 0) - Isrcs = null; + if(Isrcs.Count == 0) Isrcs = null; } break; - #endregion CDs + +#endregion CDs } - #region Nintendo - if(MediaType == MediaType.Unknown && - Blocks > 0) +#region Nintendo + + if(MediaType == MediaType.Unknown && Blocks > 0) { - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, dev.Timeout, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: PFI\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_PFI_0, Sense.PrettifySense(senseBuf)); + } else { DvdPfi = cmdBuf; @@ -1193,49 +1454,58 @@ public sealed class ScsiInfo { AaruConsole.WriteLine("PFI:\n{0}", PFI.Prettify(cmdBuf, MediaType)); - if(nintendoPfi.Value.DiskCategory == DiskCategory.Nintendo && - nintendoPfi.Value.PartVersion == 15) - switch(nintendoPfi.Value.DiscSize) - { - case DVDSize.Eighty: - MediaType = MediaType.GOD; - - break; - case DVDSize.OneTwenty: - MediaType = MediaType.WOD; - - break; - } + if(nintendoPfi is { DiskCategory: DiskCategory.Nintendo, PartVersion: 15 }) + { + MediaType = nintendoPfi.Value.DiscSize switch + { + DVDSize.Eighty => MediaType.GOD, + DVDSize.OneTwenty => MediaType.WOD, + _ => MediaType + }; + } } } - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.DiscManufacturingInformation, 0, dev.Timeout, + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.DiscManufacturingInformation, + 0, + dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC STRUCTURE: DMI\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_STRUCTURE_DMI_0, Sense.PrettifySense(senseBuf)); + } else DvdDmi = cmdBuf; } - #endregion Nintendo + +#endregion Nintendo } sense = dev.ReadMediaSerialNumber(out cmdBuf, out senseBuf, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ MEDIA SERIAL NUMBER\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_MEDIA_SERIAL_NUMBER_0, Sense.PrettifySense(senseBuf)); + } else { - if(cmdBuf.Length >= 4) - MediaSerialNumber = cmdBuf; + if(cmdBuf.Length >= 4) MediaSerialNumber = cmdBuf; } switch(MediaType) { - #region Xbox +#region Xbox + case MediaType.XGD: case MediaType.XGD2: case MediaType.XGD3: @@ -1251,20 +1521,24 @@ public sealed class ScsiInfo sense = dev.KreonExtractSs(out cmdBuf, out senseBuf, dev.Timeout, out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "KREON EXTRACT SS:\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.KREON_EXTRACT_SS_0, Sense.PrettifySense(senseBuf)); + } else XboxSecuritySector = cmdBuf; DecodedXboxSecuritySector = SS.Decode(cmdBuf); // Get video partition size - AaruConsole.DebugWriteLine("Dump-media command", "Getting video partition size"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Getting_video_partition_size); + sense = dev.KreonLock(out senseBuf, dev.Timeout, out _); if(sense) { - AaruConsole.ErrorWriteLine("Cannot lock drive, not continuing."); + AaruConsole.ErrorWriteLine(Localization.Core.Cannot_lock_drive_not_continuing); break; } @@ -1273,7 +1547,7 @@ public sealed class ScsiInfo if(sense) { - AaruConsole.ErrorWriteLine("Cannot get disc capacity."); + AaruConsole.ErrorWriteLine(Localization.Core.Cannot_get_disc_capacity); break; } @@ -1281,31 +1555,40 @@ public sealed class ScsiInfo ulong totalSize = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]) & 0xFFFFFFFF; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + 0, + out _); if(sense) { - AaruConsole.ErrorWriteLine("Cannot get PFI."); + AaruConsole.ErrorWriteLine(Localization.Core.Cannot_get_PFI); break; } - AaruConsole.DebugWriteLine("Dump-media command", "Video partition total size: {0} sectors", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Video_partition_total_size_0_sectors, totalSize); ulong l0Video = PFI.Decode(cmdBuf, MediaType).Value.Layer0EndPSN - - PFI.Decode(cmdBuf, MediaType).Value.DataAreaStartPSN + 1; + PFI.Decode(cmdBuf, MediaType).Value.DataAreaStartPSN + + 1; ulong l1Video = totalSize - l0Video + 1; // Get game partition size - AaruConsole.DebugWriteLine("Dump-media command", "Getting game partition size"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Getting_game_partition_size); sense = dev.KreonUnlockXtreme(out senseBuf, dev.Timeout, out _); if(sense) { - AaruConsole.ErrorWriteLine("Cannot unlock drive, not continuing."); + AaruConsole.ErrorWriteLine(Localization.Core.Cannot_unlock_drive_not_continuing); break; } @@ -1314,25 +1597,27 @@ public sealed class ScsiInfo if(sense) { - AaruConsole.ErrorWriteLine("Cannot get disc capacity."); + AaruConsole.ErrorWriteLine(Localization.Core.Cannot_get_disc_capacity); return; } ulong gameSize = ((ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]) & - 0xFFFFFFFF) + 1; + 0xFFFFFFFF) + + 1; - AaruConsole.DebugWriteLine("Dump-media command", "Game partition total size: {0} sectors", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Game_partition_total_size_0_sectors, gameSize); // Get middle zone size - AaruConsole.DebugWriteLine("Dump-media command", "Getting middle zone size"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Getting_middle_zone_size); sense = dev.KreonUnlockWxripper(out senseBuf, dev.Timeout, out _); if(sense) { - AaruConsole.ErrorWriteLine("Cannot unlock drive, not continuing."); + AaruConsole.ErrorWriteLine(Localization.Core.Cannot_unlock_drive_not_continuing); break; } @@ -1341,7 +1626,7 @@ public sealed class ScsiInfo if(sense) { - AaruConsole.ErrorWriteLine("Cannot get disc capacity."); + AaruConsole.ErrorWriteLine(Localization.Core.Cannot_get_disc_capacity); break; } @@ -1349,21 +1634,33 @@ public sealed class ScsiInfo totalSize = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]) & 0xFFFFFFFF; - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); + sense = dev.ReadDiscStructure(out cmdBuf, + out senseBuf, + MmcDiscStructureMediaType.Dvd, + 0, + 0, + MmcDiscStructureFormat.PhysicalInformation, + 0, + 0, + out _); if(sense) { - AaruConsole.ErrorWriteLine("Cannot get PFI."); + AaruConsole.ErrorWriteLine(Localization.Core.Cannot_get_PFI); break; } - AaruConsole.DebugWriteLine("Dump-media command", "Unlocked total size: {0} sectors", totalSize); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Unlocked_total_size_0_sectors, + totalSize); - ulong middleZone = - totalSize - (PFI.Decode(cmdBuf, MediaType).Value.Layer0EndPSN - - PFI.Decode(cmdBuf, MediaType).Value.DataAreaStartPSN + 1) - gameSize + 1; + ulong middleZone = totalSize - + (PFI.Decode(cmdBuf, MediaType).Value.Layer0EndPSN - + PFI.Decode(cmdBuf, MediaType).Value.DataAreaStartPSN + + 1) - + gameSize + + 1; totalSize = l0Video + l1Video + middleZone * 2 + gameSize; ulong layerBreak = l0Video + middleZone + gameSize / 2; @@ -1381,53 +1678,60 @@ public sealed class ScsiInfo } break; - #endregion Xbox + +#endregion Xbox case MediaType.Unknown: - MediaType = MediaTypeFromDevice.GetFromScsi((byte)dev.ScsiType, dev.Manufacturer, dev.Model, - scsiMediumType, scsiDensityCode, Blocks, BlockSize, - dev.IsUsb, true); + MediaType = MediaTypeFromDevice.GetFromScsi((byte)dev.ScsiType, + dev.Manufacturer, + dev.Model, + scsiMediumType, + scsiDensityCode, + Blocks, + BlockSize, + dev.IsUsb, + true); break; } - if(MediaType == MediaType.Unknown && - dev.IsUsb && - containsFloppyPage) - MediaType = MediaType.FlashDrive; + if(MediaType == MediaType.Unknown && dev.IsUsb && containsFloppyPage) MediaType = MediaType.FlashDrive; - if(MediaType == MediaType.Unknown && - !dev.IsRemovable) - MediaType = MediaType.GENERIC_HDD; + if(MediaType == MediaType.Unknown && !dev.IsRemovable) MediaType = MediaType.GENERIC_HDD; if(DeviceInfo.ScsiType != PeripheralDeviceTypes.MultiMediaDevice || dev.IsUsb && scsiMediumType is 0x40 or 0x41 or 0x42) return; - sense = dev.ReadDiscInformation(out cmdBuf, out senseBuf, MmcDiscInformationDataTypes.DiscInformation, - dev.Timeout, out _); + sense = dev.ReadDiscInformation(out cmdBuf, + out senseBuf, + MmcDiscInformationDataTypes.DiscInformation, + dev.Timeout, + out _); if(sense) - AaruConsole.DebugWriteLine("Media-Info command", "READ DISC INFORMATION 000b\n{0}", + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.READ_DISC_INFORMATION_000b_0, Sense.PrettifySense(senseBuf)); + } else { DiscInformation = cmdBuf; DecodedDiscInformation = Decoders.SCSI.MMC.DiscInformation.Decode000b(cmdBuf); if(DecodedDiscInformation.HasValue) + { if(MediaType == MediaType.CD) - switch(DecodedDiscInformation.Value.DiscType) - { - case 0x10: - MediaType = MediaType.CDI; - - break; - case 0x20: - MediaType = MediaType.CDROMXA; - - break; - } + { + MediaType = DecodedDiscInformation.Value.DiscType switch + { + 0x10 => MediaType.CDI, + 0x20 => MediaType.CDROMXA, + _ => MediaType + }; + } + } } MediaType tmpType = MediaType; @@ -1438,140 +1742,208 @@ public sealed class ScsiInfo /// Decoded DVD Pre-Recorded Information public PRI.PreRecordedInformation? DecodedDvdPrePitInformation { get; } + /// Decoded recordable DVD Physical Format Information public PFI.PhysicalFormatInformation? DecodedDvdrPfi { get; } + /// Raw media serial number public byte[] MediaSerialNumber { get; } + /// Raw Xbox security sectors public byte[] XboxSecuritySector { get; } + /// Decoded Xbox security sectors public SS.SecuritySector? DecodedXboxSecuritySector { get; } + /// Information about an XGD, XGD2 or XGD3 media public XgdInfo XgdInfo { get; } + /// MMC drive raw GET CONFIGURATION public byte[] MmcConfiguration { get; } + /// Raw recognized format layers public byte[] RecognizedFormatLayers { get; } + /// Raw write protection status public byte[] WriteProtectionStatus { get; } + /// Raw DVD Physical Format Information public byte[] DvdPfi { get; } + /// Decoded DVD Physical Format Information public PFI.PhysicalFormatInformation? DecodedPfi { get; } + /// Raw DVD Disc Manufacturing Information public byte[] DvdDmi { get; } + /// Raw DVD Copyright Management Information public byte[] DvdCmi { get; } + /// Raw DVD Burst Cutting Area public byte[] DvdBca { get; } + /// Raw DVD AACS information public byte[] DvdAacs { get; } + /// Raw DVD-RAM Disc Definition Structure public byte[] DvdRamDds { get; } + /// Raw DVD-RAM Cartridge Status public byte[] DvdRamCartridgeStatus { get; } + /// Raw DVD-RAM Spare Area Information public byte[] DvdRamSpareArea { get; } + /// Raw DVD-R(W) Last Border-Out RMD public byte[] LastBorderOutRmd { get; } + /// Raw DVD-R(W) Pre-Recorded Information public byte[] DvdPreRecordedInfo { get; } + /// Raw DVD-R Media ID public byte[] DvdrMediaIdentifier { get; } + /// Raw recordable DVD Physical Format Information public byte[] DvdrPhysicalInformation { get; } + /// Raw DVD+R(W) ADIP public byte[] DvdPlusAdip { get; } + /// Raw DVD+R(W) Disc Control Blocks public byte[] DvdPlusDcb { get; } + /// Raw HD DVD Copyright Management Information public byte[] HddvdCopyrightInformation { get; } + /// Raw HD DVD-R Medium Status public byte[] HddvdrMediumStatus { get; } + /// Raw HD DVD-R(W) Last Border-Out RMD public byte[] HddvdrLastRmd { get; } + /// Raw DVD-R(W) Layer Capacity public byte[] DvdrLayerCapacity { get; } + /// Raw DVD-R DL Middle Zone start public byte[] DvdrDlMiddleZoneStart { get; } + /// Raw DVD-R DL Jump Interval size public byte[] DvdrDlJumpIntervalSize { get; } + /// Raw DVD-R DL Manual Layer Jump Start LBA public byte[] DvdrDlManualLayerJumpStartLba { get; } + /// Raw DVD-R DL Remap Anchor Point public byte[] DvdrDlRemapAnchorPoint { get; } + /// Raw Blu-ray Disc Information public byte[] BlurayDiscInformation { get; } + /// Raw Blu-ray PAC public byte[] BlurayPac { get; } + /// Raw Blu-ray Burst Cutting Area public byte[] BlurayBurstCuttingArea { get; } + /// Raw Blu-ray Disc Definition Structure public byte[] BlurayDds { get; } + /// Raw Blu-ray Cartridge Status public byte[] BlurayCartridgeStatus { get; } + /// Raw Blu-ray Spare Area Information public byte[] BluraySpareAreaInformation { get; } + /// Raw Blu-ray DFL public byte[] BlurayRawDfl { get; } + /// Raw Blu-ray Pseudo OverWrite Resources public byte[] BlurayPowResources { get; } + /// Raw READ TOC response public byte[] Toc { get; } + /// Raw READ ATIP response public byte[] Atip { get; } + /// Raw READ DISC INFORMATION response public byte[] DiscInformation { get; } + /// Raw READ SESSION response public byte[] Session { get; } + /// Raw READ FULL TOC response public byte[] RawToc { get; } + /// Raw READ PMA response public byte[] Pma { get; } + /// Raw Lead-In's CD-TEXT response public byte[] CdTextLeadIn { get; } + /// Decoded READ TOC response public TOC.CDTOC? DecodedToc { get; } + /// Decoded READ ATIP response public ATIP.CDATIP DecodedAtip { get; } + /// Decoded READ SESSION response public Session.CDSessionInfo? DecodedSession { get; } + /// Decoded READ FULL TOC response public FullTOC.CDFullTOC? FullToc { get; } + /// Decoded Lead-In CD-TEXT response public CDTextOnLeadIn.CDText? DecodedCdTextLeadIn { get; } + /// Raw Blu-ray track resources public byte[] BlurayTrackResources { get; } + /// Decoded Blu-ray Disc Information public DiscInformation.StandardDiscInformation? DecodedDiscInformation { get; } + /// Decoded Media Catalogue Number public string Mcn { get; } + /// List of decoded track ISRCs public Dictionary Isrcs { get; } + /// Set if media is inserted in drive public bool MediaInserted { get; } + /// Detected media type public MediaType MediaType { get; } + /// Device information public DeviceInfo DeviceInfo { get; } + /// Raw READ CAPACITY(10) response public byte[] ReadCapacity { get; } + /// Number of blocks in media public ulong Blocks { get; } + /// Logical block size public uint BlockSize { get; } + /// Raw READ CAPACITY(16) response public byte[] ReadCapacity16 { get; } + /// Raw SSC Density support public byte[] DensitySupport { get; } + /// Decoded SSC Density support public DensitySupport.DensitySupportHeader? DensitySupportHeader { get; } + /// Raw SSC media support public byte[] MediaTypeSupport { get; } + /// Decoded SSC media support public DensitySupport.MediaTypeSupportHeader? MediaTypeSupportHeader { get; } + /// Raw data from DVD sector Copyright Management Information public byte[] DvdSectorCmi { get; } + /// Raw DVD Disc Key public byte[] DvdDiscKey { get; } } \ No newline at end of file diff --git a/Aaru.Core/Media/Info/XgdInfo.cs b/Aaru.Core/Media/Info/XgdInfo.cs index 097b5e1fb..7cd397572 100644 --- a/Aaru.Core/Media/Info/XgdInfo.cs +++ b/Aaru.Core/Media/Info/XgdInfo.cs @@ -27,7 +27,7 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Core.Media.Info; diff --git a/Aaru.Core/Options.cs b/Aaru.Core/Options.cs index 424773bee..105c7c575 100644 --- a/Aaru.Core/Options.cs +++ b/Aaru.Core/Options.cs @@ -27,15 +27,15 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System.Collections.Generic; using System.Globalization; using System.Text; +namespace Aaru.Core; + /// Option parsing public static class Options { @@ -44,16 +44,15 @@ public static class Options /// Options name-value dictionary public static Dictionary Parse(string options) { - var parsed = new Dictionary(); - var escaped = false; - var quoted = false; - var inValue = false; - string name = null; - string value; - var sb = new StringBuilder(); + Dictionary parsed = new(); + var escaped = false; + var quoted = false; + var inValue = false; + string name = null; + string value; + var sb = new StringBuilder(); - if(options == null) - return parsed; + if(options == null) return parsed; for(var index = 0; index < options.Length; index++) { @@ -88,18 +87,16 @@ public static class Options sb = new StringBuilder(); inValue = false; - if(string.IsNullOrEmpty(name) || - string.IsNullOrEmpty(value)) - continue; + if(string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value)) continue; - if(parsed.ContainsKey(name)) - parsed.Remove(name); + if(parsed.ContainsKey(name)) parsed.Remove(name); parsed.Add(name, value); break; default: if(escaped) + { switch(c) { case 'a': @@ -177,6 +174,7 @@ public static class Options break; } + } else sb.Append(c); @@ -184,17 +182,13 @@ public static class Options } } - if(!inValue) - return parsed; + if(!inValue) return parsed; value = sb.ToString(); - if(string.IsNullOrEmpty(name) || - string.IsNullOrEmpty(value)) - return parsed; + if(string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value)) return parsed; - if(parsed.ContainsKey(name)) - parsed.Remove(name); + if(parsed.ContainsKey(name)) parsed.Remove(name); parsed.Add(name, value); diff --git a/Aaru.Core/Partitions.cs b/Aaru.Core/Partitions.cs index ead7a32b0..38bf62896 100644 --- a/Aaru.Core/Partitions.cs +++ b/Aaru.Core/Partitions.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System.Collections.Generic; using System.Linq; using Aaru.CommonTypes; @@ -39,63 +37,84 @@ using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; +namespace Aaru.Core; + /// Implements methods for handling partitions public static class Partitions { + const string MODULE_NAME = "Partitions"; + /// Gets a list of all partitions present in the specified image /// Image /// List of found partitions public static List GetAll(IMediaImage image) { - PluginBase plugins = GetPluginBase.Instance; - var foundPartitions = new List(); - var childPartitions = new List(); - var checkedLocations = new List(); + PluginRegister plugins = PluginRegister.Singleton; + List foundPartitions = []; + List childPartitions = []; + List checkedLocations = []; var tapeImage = image as ITapeImage; var partitionableImage = image as IPartitionableMediaImage; // Create partitions from image files if(tapeImage?.Files != null) + { foreach(TapeFile tapeFile in tapeImage.Files) { - foreach(IPartition partitionPlugin in plugins.PartPluginsList.Values) - if(partitionPlugin.GetInformation(image, out List partitions, tapeFile.FirstBlock)) - { - foundPartitions.AddRange(partitions); + foreach(IPartition plugin in plugins.Partitions.Values) + { + if(plugin is null) continue; - AaruConsole.DebugWriteLine("Partitions", "Found {0} @ {1}", partitionPlugin.Name, - tapeFile.FirstBlock); - } + if(!plugin.GetInformation(image, out List partitions, tapeFile.FirstBlock)) continue; + + foundPartitions.AddRange(partitions); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_0_at_1, + plugin.Name, + tapeFile.FirstBlock); + } checkedLocations.Add(tapeFile.FirstBlock); } + } // Getting all partitions from device (e.g. tracks) if(partitionableImage?.Partitions != null) + { foreach(Partition imagePartition in partitionableImage.Partitions) { - foreach(IPartition partitionPlugin in plugins.PartPluginsList.Values) - if(partitionPlugin.GetInformation(image, out List partitions, imagePartition.Start)) - { - foundPartitions.AddRange(partitions); + foreach(IPartition plugin in plugins.Partitions.Values) + { + if(plugin is null) continue; - AaruConsole.DebugWriteLine("Partitions", "Found {0} @ {1}", partitionPlugin.Name, - imagePartition.Start); - } + if(!plugin.GetInformation(image, out List partitions, imagePartition.Start)) continue; + + foundPartitions.AddRange(partitions); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_0_at_1, + plugin.Name, + imagePartition.Start); + } checkedLocations.Add(imagePartition.Start); } + } // Getting all partitions at start of device if(!checkedLocations.Contains(0)) { - foreach(IPartition partitionPlugin in plugins.PartPluginsList.Values) - if(partitionPlugin.GetInformation(image, out List partitions, 0)) - { - foundPartitions.AddRange(partitions); - AaruConsole.DebugWriteLine("Partitions", "Found {0} @ 0", partitionPlugin.Name); - } + foreach(IPartition plugin in plugins.Partitions.Values) + { + if(plugin is null) continue; + + if(!plugin.GetInformation(image, out List partitions, 0)) continue; + + foundPartitions.AddRange(partitions); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Found_0_at_zero, plugin.Name); + } checkedLocations.Add(0); } @@ -110,17 +129,22 @@ public static class Partitions continue; } - var children = new List(); + List children = []; - foreach(IPartition partitionPlugin in plugins.PartPluginsList.Values) + foreach(IPartition plugin in plugins.Partitions.Values) { - AaruConsole.DebugWriteLine("Partitions", "Trying {0} @ {1}", partitionPlugin.Name, + if(plugin is null) continue; + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Trying_0_at_1, + plugin.Name, foundPartitions[0].Start); - if(!partitionPlugin.GetInformation(image, out List partitions, foundPartitions[0].Start)) - continue; + if(!plugin.GetInformation(image, out List partitions, foundPartitions[0].Start)) continue; - AaruConsole.DebugWriteLine("Partitions", "Found {0} @ {1}", partitionPlugin.Name, + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Core.Found_0_at_1, + plugin.Name, foundPartitions[0].Start); children.AddRange(partitions); @@ -128,17 +152,19 @@ public static class Partitions checkedLocations.Add(foundPartitions[0].Start); - AaruConsole.DebugWriteLine("Partitions", "Got {0} children", children.Count); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Got_0_children, children.Count); if(children.Count > 0) { foundPartitions.RemoveAt(0); foreach(Partition child in children) + { if(checkedLocations.Contains(child.Start)) childPartitions.Add(child); else foundPartitions.Add(child); + } } else { @@ -146,40 +172,45 @@ public static class Partitions foundPartitions.RemoveAt(0); } - AaruConsole.DebugWriteLine("Partitions", "Got {0} parents", foundPartitions.Count); - AaruConsole.DebugWriteLine("Partitions", "Got {0} partitions", childPartitions.Count); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Got_0_parents, foundPartitions.Count); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Got_0_partitions, childPartitions.Count); } // Be sure that device partitions are not excluded if not mapped by any scheme... - if(!(tapeImage is null)) + if(tapeImage is not null) { var startLocations = childPartitions.Select(detectedPartition => detectedPartition.Start).ToList(); if(tapeImage.Files != null) - childPartitions.AddRange(tapeImage.Files.Where(f => !startLocations.Contains(f.FirstBlock)). - Select(tapeFile => new Partition + { + childPartitions.AddRange(tapeImage.Files.Where(f => !startLocations.Contains(f.FirstBlock)) + .Select(tapeFile => new Partition { Start = tapeFile.FirstBlock, Length = tapeFile.LastBlock - tapeFile.FirstBlock + 1, Sequence = tapeFile.File })); + } } - if(!(partitionableImage is null)) + if(partitionableImage is not null) { var startLocations = childPartitions.Select(detectedPartition => detectedPartition.Start).ToList(); if(partitionableImage.Partitions != null) + { childPartitions.AddRange(partitionableImage.Partitions.Where(imagePartition => - !startLocations. - Contains(imagePartition.Start))); + !startLocations.Contains(imagePartition + .Start))); + } } - Partition[] childArray = childPartitions.OrderBy(part => part.Start).ThenBy(part => part.Length). - ThenBy(part => part.Scheme).ToArray(); + Partition[] childArray = childPartitions.OrderBy(part => part.Start) + .ThenBy(part => part.Length) + .ThenBy(part => part.Scheme) + .ToArray(); - for(long i = 0; i < childArray.LongLength; i++) - childArray[i].Sequence = (ulong)i; + for(long i = 0; i < childArray.LongLength; i++) childArray[i].Sequence = (ulong)i; return childArray.ToList(); } @@ -188,16 +219,12 @@ public static class Partitions /// List of partitions public static void AddSchemesToStats(List partitions) { - if(partitions == null || - partitions.Count == 0) - return; + if(partitions == null || partitions.Count == 0) return; - var schemes = new List(); + List schemes = []; - foreach(Partition part in partitions.Where(part => !schemes.Contains(part.Scheme))) - schemes.Add(part.Scheme); + foreach(Partition part in partitions.Where(part => !schemes.Contains(part.Scheme))) schemes.Add(part.Scheme); - foreach(string scheme in schemes) - Statistics.AddPartition(scheme); + foreach(string scheme in schemes) Statistics.AddPartition(scheme); } } \ No newline at end of file diff --git a/Aaru.Core/GetPluginBase.cs b/Aaru.Core/PluginBase.cs similarity index 56% rename from Aaru.Core/GetPluginBase.cs rename to Aaru.Core/PluginBase.cs index 1027e0f10..5f81409d8 100644 --- a/Aaru.Core/GetPluginBase.cs +++ b/Aaru.Core/PluginBase.cs @@ -2,14 +2,14 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : ImageFormat.cs +// Filename : PluginBase.cs // Author(s) : Natalia Portillo // // Component : Core algorithms. // // --[ Description ] ---------------------------------------------------------- // -// Gets a new instance of all known plugins. +// Gets lists of all known plugins. // // --[ License ] -------------------------------------------------------------- // @@ -27,40 +27,31 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Aaru.Checksums; using Aaru.CommonTypes; using Aaru.CommonTypes.Interfaces; +namespace Aaru.Core; + /// Plugin base operations -public static class GetPluginBase +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static class PluginBase { - /// Gets an instance with all the known plugins - public static PluginBase Instance + public static void Init() { - get + PluginRegister.Singleton.InitPlugins(new List { - var instance = new PluginBase(); - - IPluginRegister checksumRegister = new Register(); - IPluginRegister imagesRegister = new DiscImages.Register(); - IPluginRegister filesystemsRegister = new Aaru.Filesystems.Register(); - IPluginRegister filtersRegister = new Filters.Register(); - IPluginRegister partitionsRegister = new Aaru.Partitions.Register(); - IPluginRegister archiveRegister = new Archives.Register(); - - instance.AddPlugins(checksumRegister); - instance.AddPlugins(imagesRegister); - instance.AddPlugins(filesystemsRegister); - instance.AddPlugins(filtersRegister); - instance.AddPlugins(partitionsRegister); - instance.AddPlugins(archiveRegister); - - return instance; - } + new Register(), + new Filters.Register(), + new Images.Register(), + new Aaru.Filesystems.Register(), + new Aaru.Partitions.Register(), + new Archives.Register() + }); } } \ No newline at end of file diff --git a/Aaru.Core/PrintScsiModePages.cs b/Aaru.Core/PrintScsiModePages.cs index 77178a666..a92c90565 100644 --- a/Aaru.Core/PrintScsiModePages.cs +++ b/Aaru.Core/PrintScsiModePages.cs @@ -27,16 +27,16 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Console; using Aaru.Decoders.SCSI; using Aaru.Helpers; +namespace Aaru.Core; + /// Prints all SCSI MODE pages public static class PrintScsiModePages { @@ -48,26 +48,28 @@ public static class PrintScsiModePages { AaruConsole.WriteLine(Modes.PrettifyModeHeader(decMode.Header, devType)); - if(decMode.Pages == null) - return; + if(decMode.Pages == null) return; foreach(Modes.ModePage page in decMode.Pages) //AaruConsole.WriteLine("Page {0:X2}h subpage {1:X2}h is {2} bytes long", page.Page, page.Subpage, page.PageResponse.Length); + { switch(page.Page) { case 0x00: { - if(devType == PeripheralDeviceTypes.MultiMediaDevice && - page.Subpage == 0) + if(devType == PeripheralDeviceTypes.MultiMediaDevice && page.Subpage == 0) AaruConsole.WriteLine(Modes.PrettifyModePage_00_SFF(page.PageResponse)); else { if(page.Subpage != 0) - AaruConsole.WriteLine("Found unknown vendor mode page {0:X2}h subpage {1:X2}h", page.Page, + { + AaruConsole.WriteLine(Localization.Core.Found_unknown_vendor_mode_page_0_subpage_1, + page.Page, page.Subpage); + } else - AaruConsole.WriteLine("Found unknown vendor mode page {0:X2}h", page.Page); + AaruConsole.WriteLine(Localization.Core.Found_unknown_vendor_mode_page_0, page.Page); } break; @@ -75,9 +77,11 @@ public static class PrintScsiModePages case 0x01: { if(page.Subpage == 0) + { AaruConsole.WriteLine(devType == PeripheralDeviceTypes.MultiMediaDevice ? Modes.PrettifyModePage_01_MMC(page.PageResponse) : Modes.PrettifyModePage_01(page.PageResponse)); + } else goto default; @@ -131,9 +135,11 @@ public static class PrintScsiModePages case 0x07: { if(page.Subpage == 0) + { AaruConsole.WriteLine(devType == PeripheralDeviceTypes.MultiMediaDevice ? Modes.PrettifyModePage_07_MMC(page.PageResponse) : Modes.PrettifyModePage_07(page.PageResponse)); + } else goto default; @@ -198,9 +204,11 @@ public static class PrintScsiModePages case 0x10: { if(page.Subpage == 0) + { AaruConsole.WriteLine(devType == PeripheralDeviceTypes.SequentialAccess ? Modes.PrettifyModePage_10_SSC(page.PageResponse) : Modes.PrettifyModePage_10(page.PageResponse)); + } else goto default; @@ -249,9 +257,11 @@ public static class PrintScsiModePages case 0x1C: { if(page.Subpage == 0) + { AaruConsole.WriteLine(devType == PeripheralDeviceTypes.MultiMediaDevice ? Modes.PrettifyModePage_1C_SFF(page.PageResponse) : Modes.PrettifyModePage_1C(page.PageResponse)); + } else if(page.Subpage == 1) AaruConsole.WriteLine(Modes.PrettifyModePage_1C_S01(page.PageResponse)); else @@ -316,7 +326,7 @@ public static class PrintScsiModePages case 0x30: { if(Modes.IsAppleModePage_30(page.PageResponse)) - AaruConsole.WriteLine("Drive identifies as Apple OEM drive"); + AaruConsole.WriteLine(Localization.Core.Drive_identifies_as_Apple_OEM_drive); else goto default; @@ -365,13 +375,17 @@ public static class PrintScsiModePages default: { if(page.Subpage != 0) - AaruConsole.WriteLine("Found unknown mode page {0:X2}h subpage {1:X2}h", page.Page, + { + AaruConsole.WriteLine(Localization.Core.Found_unknown_mode_page_0_subpage_1, + page.Page, page.Subpage); + } else - AaruConsole.WriteLine("Found unknown mode page {0:X2}h", page.Page); + AaruConsole.WriteLine(Localization.Core.Found_unknown_mode_page_0, page.Page); break; } } + } } } \ No newline at end of file diff --git a/Aaru.Core/Remote.cs b/Aaru.Core/Remote.cs index 1ee9984a1..b6121f7ad 100644 --- a/Aaru.Core/Remote.cs +++ b/Aaru.Core/Remote.cs @@ -27,11 +27,9 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; using System.Collections.Generic; using System.Diagnostics; @@ -40,101 +38,100 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Text; -using System.Threading; +using System.Text.Json; +using System.Threading.Tasks; using Aaru.CommonTypes.Metadata; using Aaru.Console; using Aaru.Database; using Aaru.Database.Models; using Aaru.Dto; -using Aaru.Settings; -using global::Spectre.Console; using Microsoft.EntityFrameworkCore; -using Newtonsoft.Json; +using Spectre.Console; using CdOffset = Aaru.Database.Models.CdOffset; using Version = Aaru.CommonTypes.Metadata.Version; +namespace Aaru.Core; + /// Handles connections to Aaru.Server public static class Remote { /// Submits a device report /// Device report - public static void SubmitReport(DeviceReportV2 report) + public static Task SubmitReportAsync(DeviceReport report) { - var submitThread = new Thread(() => - { - Spectre.ProgressSingleSpinner(ctx => - { - ctx.AddTask("Uploading device report").IsIndeterminate(); + return AnsiConsole.Status() + .StartAsync(Localization.Core.Uploading_device_report, + async _ => + { + try + { + string json = + JsonSerializer.Serialize(report, + typeof(DeviceReport), + DeviceReportContext.Default); - try - { - string json = JsonConvert.SerializeObject(report, Formatting.Indented, new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore - }); + var httpClient = new HttpClient(); - var httpClient = new HttpClient(); + httpClient.DefaultRequestHeaders.Add("User-Agent", + $"Aaru {typeof(Version).Assembly.GetName().Version}"); - httpClient.DefaultRequestHeaders.Add("User-Agent", - $"Aaru {typeof(Version).Assembly.GetName().Version}"); + httpClient.BaseAddress = new Uri("https://www.aaru.app"); - httpClient.BaseAddress = new Uri("https://www.aaru.app"); + HttpResponseMessage response = + await httpClient.PostAsync("/api/uploadreportv2", + new StringContent(json, + Encoding.UTF8, + "application/json")); - HttpResponseMessage response = httpClient. - PostAsync("/api/uploadreportv2", - new StringContent(json, Encoding.UTF8, - "application/json")).GetAwaiter(). - GetResult(); + if(!response.IsSuccessStatusCode) return; - if(!response.IsSuccessStatusCode) - return; + Stream data = await response.Content.ReadAsStreamAsync(); + var reader = new StreamReader(data); - Stream data = response.Content.ReadAsStream(); - var reader = new StreamReader(data); + await reader.ReadToEndAsync(); + data.Close(); + } + catch(WebException) + { + // Can't connect to the server, do nothing + } - reader.ReadToEnd(); - data.Close(); - } - catch(WebException) - { - // Can't connect to the server, do nothing - } - - // ReSharper disable once RedundantCatchClause - catch - { - #if DEBUG - if(Debugger.IsAttached) - throw; - #endif - } - }); - }); - - submitThread.Start(); + // ReSharper disable once RedundantCatchClause + catch + { +#if DEBUG + if(Debugger.IsAttached) throw; +#endif + } + }); } /// Updates the main database /// If true creates the database from scratch, otherwise updates an existing database - public static void UpdateMainDatabase(bool create) + public static async Task UpdateMainDatabaseAsync(bool create) { - var mctx = AaruContext.Create(Settings.MainDbPath); + var mctx = AaruContext.Create(Settings.Settings.MainDbPath); if(create) { - mctx.Database.EnsureCreated(); + await mctx.Database.EnsureCreatedAsync(); - mctx.Database. - ExecuteSqlRaw("CREATE TABLE IF NOT EXISTS \"__EFMigrationsHistory\" (\"MigrationId\" TEXT PRIMARY KEY, \"ProductVersion\" TEXT)"); + await mctx.Database + .ExecuteSqlRawAsync("CREATE TABLE IF NOT EXISTS \"__EFMigrationsHistory\" (\"MigrationId\" TEXT PRIMARY KEY, \"ProductVersion\" TEXT)"); - foreach(string migration in mctx.Database.GetPendingMigrations()) - mctx.Database. - ExecuteSqlRaw($"INSERT INTO \"__EFMigrationsHistory\" (MigrationId, ProductVersion) VALUES ('{migration}', '0.0.0')"); + foreach(string migration in await mctx.Database.GetPendingMigrationsAsync()) + { + await mctx.Database +#pragma warning disable EF1002 + .ExecuteSqlRawAsync($"INSERT INTO \"__EFMigrationsHistory\" (MigrationId, ProductVersion) VALUES ('{ + migration}', '0.0.0')"); +#pragma warning restore EF1002 + } } else - mctx.Database.Migrate(); + await mctx.Database.MigrateAsync(); - mctx.SaveChanges(); + await mctx.SaveChangesAsync(); try { @@ -143,19 +140,16 @@ public static class Remote if(!create) { - List latestAll = new(); + List latestAll = []; - if(mctx.UsbVendors.Any()) - latestAll.Add(mctx.UsbVendors.Max(v => v.ModifiedWhen)); + if(await mctx.UsbVendors.AnyAsync()) latestAll.Add(await mctx.UsbVendors.MaxAsync(v => v.ModifiedWhen)); - if(mctx.UsbProducts.Any()) - latestAll.Add(mctx.UsbProducts.Max(p => p.ModifiedWhen)); + if(await mctx.UsbProducts.AnyAsync()) + latestAll.Add(await mctx.UsbProducts.MaxAsync(p => p.ModifiedWhen)); - if(mctx.CdOffsets.Any()) - latestAll.Add(mctx.CdOffsets.Max(o => o.ModifiedWhen)); + if(await mctx.CdOffsets.AnyAsync()) latestAll.Add(await mctx.CdOffsets.MaxAsync(o => o.ModifiedWhen)); - if(mctx.Devices.Any()) - latestAll.Add(mctx.Devices.Max(d => d.LastSynchronized)); + if(await mctx.Devices.AnyAsync()) latestAll.Add(await mctx.Devices.MaxAsync(d => d.LastSynchronized)); if(latestAll.Any()) { @@ -167,144 +161,170 @@ public static class Remote if(lastUpdate == 0) { create = true; - AaruConsole.WriteLine("Creating main database"); + AaruConsole.WriteLine(Localization.Core.Creating_main_database); } else { - AaruConsole.WriteLine("Updating main database"); - AaruConsole.WriteLine("Last update: {0}", latest); + AaruConsole.WriteLine(Localization.Core.Updating_main_database); + AaruConsole.WriteLine(Localization.Core.Last_update_0, latest); } DateTime updateStart = DateTime.UtcNow; var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("User-Agent", $"Aaru {typeof(Version).Assembly.GetName().Version}"); - httpClient.BaseAddress = new Uri("https://www.aaru.app"); + httpClient.BaseAddress = new Uri("http://localhost:5279"); - HttpResponseMessage response = - httpClient.GetAsync($"/api/update?timestamp={lastUpdate}").GetAwaiter().GetResult(); + HttpResponseMessage response = await httpClient.GetAsync($"/api/update?timestamp={lastUpdate}"); if(!response.IsSuccessStatusCode) { - AaruConsole.ErrorWriteLine("Error {0} when trying to get updated entities.", response.StatusCode); + AaruConsole.ErrorWriteLine(Localization.Core.Error_0_when_trying_to_get_updated_entities, + response.StatusCode); return; } - Stream data = response.Content.ReadAsStream(); + Stream data = await response.Content.ReadAsStreamAsync(); var reader = new StreamReader(data); - SyncDto sync = JsonConvert.DeserializeObject(reader.ReadToEnd()) ?? new SyncDto(); + SyncDto sync = JsonSerializer.Deserialize(await reader.ReadToEndAsync()) ?? new SyncDto(); if(create) { - AnsiConsole.Progress().AutoClear(true).HideCompleted(true). - Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). - Start(ctx => - { - ProgressTask task = ctx.AddTask("Adding USB vendors"); - task.MaxValue = sync.UsbVendors.Count; + await AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .Start(ctx => + { + ProgressTask task = ctx.AddTask(Localization.Core.Adding_USB_vendors); + task.MaxValue = sync.UsbVendors.Count; - foreach(UsbVendorDto vendor in sync.UsbVendors) - { - task.Increment(1); - mctx.UsbVendors.Add(new UsbVendor(vendor.VendorId, vendor.Vendor)); - } - }); + foreach(UsbVendorDto vendor in sync.UsbVendors) + { + task.Increment(1); + mctx.UsbVendors.Add(new UsbVendor(vendor.VendorId, vendor.Vendor)); + } - AaruConsole.WriteLine("Added {0} usb vendors", sync.UsbVendors.Count); + return Task.CompletedTask; + }); - AnsiConsole.Progress().AutoClear(true).HideCompleted(true). - Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). - Start(ctx => - { - ProgressTask task = ctx.AddTask("Adding USB products"); - task.MaxValue = sync.UsbProducts.Count; + AaruConsole.WriteLine(Localization.Core.Added_0_usb_vendors, sync.UsbVendors.Count); - foreach(UsbProductDto product in sync.UsbProducts) - { - task.Increment(1); + await AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .Start(ctx => + { + ProgressTask task = ctx.AddTask(Localization.Core.Adding_USB_products); + task.MaxValue = sync.UsbProducts.Count; - mctx.UsbProducts.Add(new UsbProduct(product.VendorId, product.ProductId, - product.Product)); - } - }); + foreach(UsbProductDto product in sync.UsbProducts) + { + task.Increment(1); - AaruConsole.WriteLine("Added {0} usb products", sync.UsbProducts.Count); + mctx.UsbProducts.Add(new UsbProduct(product.VendorId, + product.ProductId, + product.Product)); + } - AnsiConsole.Progress().AutoClear(true).HideCompleted(true). - Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). - Start(ctx => - { - ProgressTask task = ctx.AddTask("Adding CompactDisc read offsets"); - task.MaxValue = sync.Offsets.Count; + return Task.CompletedTask; + }); - foreach(CdOffsetDto offset in sync.Offsets) - { - task.Increment(1); + AaruConsole.WriteLine(Localization.Core.Added_0_usb_products, sync.UsbProducts.Count); - mctx.CdOffsets.Add(new CdOffset(offset) - { - Id = offset.Id - }); - } - }); + await AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .Start(ctx => + { + ProgressTask task = + ctx.AddTask(Localization.Core.Adding_CompactDisc_read_offsets); - AaruConsole.WriteLine("Added {0} CompactDisc read offsets", sync.Offsets.Count); + task.MaxValue = sync.Offsets.Count; - AnsiConsole.Progress().AutoClear(true).HideCompleted(true). - Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). - Start(ctx => - { - ProgressTask task = ctx.AddTask("Adding known devices"); - task.MaxValue = sync.Devices.Count; + foreach(CdOffsetDto offset in sync.Offsets) + { + task.Increment(1); - foreach(DeviceDto device in sync.Devices) + mctx.CdOffsets.Add(new CdOffset(offset) + { + Id = offset.Id + }); + } - { - task.Increment(1); + return Task.CompletedTask; + }); - mctx.Devices.Add(new Device(device) - { - Id = device.Id - }); - } - }); + AaruConsole.WriteLine(Localization.Core.Added_0_CompactDisc_read_offsets, sync.Offsets.Count); - AaruConsole.WriteLine("Added {0} known devices", sync.Devices.Count); + await AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .Start(ctx => + { + ProgressTask task = ctx.AddTask(Localization.Core.Adding_known_devices); + task.MaxValue = sync.Devices.Count; - AnsiConsole.Progress().AutoClear(true).HideCompleted(true). - Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). - Start(ctx => - { - ProgressTask task = ctx.AddTask("Adding known iNES/NES 2.0 headers"); - task.MaxValue = sync.NesHeaders?.Count ?? 0; + foreach(DeviceDto device in sync.Devices) - foreach(NesHeaderDto header in sync.NesHeaders ?? new List()) - { - task.Increment(1); + { + task.Increment(1); - mctx.NesHeaders.Add(new NesHeaderInfo - { - Id = header.Id, - AddedWhen = DateTime.UtcNow, - BatteryPresent = header.BatteryPresent, - ConsoleType = header.ConsoleType, - DefaultExpansionDevice = header.DefaultExpansionDevice, - ExtendedConsoleType = header.ExtendedConsoleType, - FourScreenMode = header.FourScreenMode, - Mapper = header.Mapper, - ModifiedWhen = DateTime.UtcNow, - NametableMirroring = header.NametableMirroring, - Sha256 = header.Sha256, - Submapper = header.Submapper, - TimingMode = header.TimingMode, - VsHardwareType = header.VsHardwareType, - VsPpuType = header.VsPpuType - }); - } - }); + mctx.Devices.Add(new Device(device) + { + Id = device.Id + }); + } - AaruConsole.WriteLine("Added {0} known iNES/NES 2.0 headers", sync.NesHeaders?.Count ?? 0); + return Task.CompletedTask; + }); + + AaruConsole.WriteLine(Localization.Core.Added_0_known_devices, sync.Devices.Count); + + await AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .Start(ctx => + { + ProgressTask task = + ctx.AddTask(Localization.Core.Adding_known_iNES_NES_2_0_headers); + + task.MaxValue = sync.NesHeaders?.Count ?? 0; + + foreach(NesHeaderDto header in sync.NesHeaders ?? []) + { + task.Increment(1); + + mctx.NesHeaders.Add(new NesHeaderInfo + { + Id = header.Id, + AddedWhen = DateTime.UtcNow, + BatteryPresent = header.BatteryPresent, + ConsoleType = header.ConsoleType, + DefaultExpansionDevice = header.DefaultExpansionDevice, + ExtendedConsoleType = header.ExtendedConsoleType, + FourScreenMode = header.FourScreenMode, + Mapper = header.Mapper, + ModifiedWhen = DateTime.UtcNow, + NametableMirroring = header.NametableMirroring, + Sha256 = header.Sha256, + Submapper = header.Submapper, + TimingMode = header.TimingMode, + VsHardwareType = header.VsHardwareType, + VsPpuType = header.VsPpuType + }); + } + + return Task.CompletedTask; + }); + + AaruConsole.WriteLine(Localization.Core.Added_0_known_iNES_NES_2_0_headers, + sync.NesHeaders?.Count ?? 0); } else { @@ -319,233 +339,259 @@ public static class Remote long modifiedDevices = 0; long modifiedNesHeaders = 0; - AnsiConsole.Progress().AutoClear(true).HideCompleted(true). - Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). - Start(ctx => - { - ProgressTask task = ctx.AddTask("Updating USB vendors"); - task.MaxValue = sync.UsbVendors.Count; + await AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .StartAsync(async ctx => + { + ProgressTask task = ctx.AddTask(Localization.Core.Updating_USB_vendors); + task.MaxValue = sync.UsbVendors.Count; - foreach(UsbVendorDto vendor in sync.UsbVendors) - { - task.Increment(1); + foreach(UsbVendorDto vendor in sync.UsbVendors) + { + task.Increment(1); - UsbVendor existing = mctx.UsbVendors.FirstOrDefault(v => v.Id == vendor.VendorId); + UsbVendor existing = + await mctx.UsbVendors.FirstOrDefaultAsync(v => v.Id == vendor.VendorId); - if(existing != null) - { - modifiedVendors++; - existing.Vendor = vendor.Vendor; - existing.ModifiedWhen = updateStart; - mctx.UsbVendors.Update(existing); - } - else - { - addedVendors++; - mctx.UsbVendors.Add(new UsbVendor(vendor.VendorId, vendor.Vendor)); - } - } - }); + if(existing != null) + { + modifiedVendors++; + existing.Vendor = vendor.Vendor; + existing.ModifiedWhen = updateStart; + mctx.UsbVendors.Update(existing); + } + else + { + addedVendors++; + mctx.UsbVendors.Add(new UsbVendor(vendor.VendorId, vendor.Vendor)); + } + } + }); - AaruConsole.WriteLine("Added {0} USB vendors", addedVendors); - AaruConsole.WriteLine("Modified {0} USB vendors", modifiedVendors); + AaruConsole.WriteLine(Localization.Core.Added_0_usb_vendors, addedVendors); + AaruConsole.WriteLine(Localization.Core.Modified_0_USB_vendors, modifiedVendors); - AnsiConsole.Progress().AutoClear(true).HideCompleted(true). - Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). - Start(ctx => - { - ProgressTask task = ctx.AddTask("Updating USB products"); - task.MaxValue = sync.UsbVendors.Count; + await AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .StartAsync(async ctx => + { + ProgressTask task = ctx.AddTask(Localization.Core.Updating_USB_products); + task.MaxValue = sync.UsbVendors.Count; - foreach(UsbProductDto product in sync.UsbProducts) - { - task.Increment(1); + foreach(UsbProductDto product in sync.UsbProducts) + { + task.Increment(1); - UsbProduct existing = - mctx.UsbProducts.FirstOrDefault(p => p.VendorId == product.VendorId && - p.ProductId == product.ProductId); + UsbProduct existing = + await mctx.UsbProducts.FirstOrDefaultAsync(p => + p.VendorId == product.VendorId && + p.ProductId == product.ProductId); - if(existing != null) - { - modifiedProducts++; - existing.Product = product.Product; - existing.ModifiedWhen = updateStart; - mctx.UsbProducts.Update(existing); - } - else - { - addedProducts++; + if(existing != null) + { + modifiedProducts++; + existing.Product = product.Product; + existing.ModifiedWhen = updateStart; + mctx.UsbProducts.Update(existing); + } + else + { + addedProducts++; - mctx.UsbProducts.Add(new UsbProduct(product.VendorId, product.ProductId, - product.Product)); - } - } - }); + mctx.UsbProducts.Add(new UsbProduct(product.VendorId, + product.ProductId, + product.Product)); + } + } + }); - AaruConsole.WriteLine("Added {0} USB products", addedProducts); - AaruConsole.WriteLine("Modified {0} USB products", modifiedProducts); + AaruConsole.WriteLine(Localization.Core.Added_0_usb_products, addedProducts); + AaruConsole.WriteLine(Localization.Core.Modified_0_USB_products, modifiedProducts); - AnsiConsole.Progress().AutoClear(true).HideCompleted(true). - Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). - Start(ctx => - { - ProgressTask task = ctx.AddTask("Updating CompactDisc read offsets"); - task.MaxValue = sync.Offsets.Count; + await AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .StartAsync(async ctx => + { + ProgressTask task = + ctx.AddTask(Localization.Core.Updating_CompactDisc_read_offsets); - foreach(CdOffsetDto offset in sync.Offsets) - { - CdOffset existing = mctx.CdOffsets.FirstOrDefault(o => o.Id == offset.Id); - task.Increment(1); + task.MaxValue = sync.Offsets.Count; - if(existing != null) - { - modifiedOffsets++; - existing.Agreement = offset.Agreement; - existing.Manufacturer = offset.Manufacturer; - existing.Model = offset.Model; - existing.Submissions = offset.Submissions; - existing.Offset = offset.Offset; - existing.ModifiedWhen = updateStart; - mctx.CdOffsets.Update(existing); - } - else - { - addedOffsets++; + foreach(CdOffsetDto offset in sync.Offsets) + { + CdOffset existing = + await mctx.CdOffsets.FirstOrDefaultAsync(o => o.Id == offset.Id); - mctx.CdOffsets.Add(new CdOffset(offset) - { - Id = offset.Id - }); - } - } - }); + task.Increment(1); - AaruConsole.WriteLine("Added {0} CompactDisc read offsets", addedOffsets); - AaruConsole.WriteLine("Modified {0} CompactDisc read offsets", modifiedOffsets); + if(existing != null) + { + modifiedOffsets++; + existing.Agreement = offset.Agreement; + existing.Manufacturer = offset.Manufacturer; + existing.Model = offset.Model; + existing.Submissions = offset.Submissions; + existing.Offset = offset.Offset; + existing.ModifiedWhen = updateStart; + mctx.CdOffsets.Update(existing); + } + else + { + addedOffsets++; - AnsiConsole.Progress().AutoClear(true).HideCompleted(true). - Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). - Start(ctx => - { - ProgressTask task = ctx.AddTask("Updating known devices"); - task.MaxValue = sync.Offsets.Count; + mctx.CdOffsets.Add(new CdOffset(offset) + { + Id = offset.Id + }); + } + } + }); - foreach(DeviceDto device in sync.Devices) - { - task.Increment(1); - Device existing = mctx.Devices.FirstOrDefault(d => d.Id == device.Id); + AaruConsole.WriteLine(Localization.Core.Added_0_CompactDisc_read_offsets, addedOffsets); + AaruConsole.WriteLine(Localization.Core.Modified_0_CompactDisc_read_offsets, modifiedOffsets); - if(existing != null) - { - modifiedDevices++; + await AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .StartAsync(async ctx => + { + ProgressTask task = ctx.AddTask(Localization.Core.Updating_known_devices); + task.MaxValue = sync.Offsets.Count; - mctx.Remove(existing); + foreach(DeviceDto device in sync.Devices) + { + task.Increment(1); - existing = new Device(device) - { - Id = device.Id, - OptimalMultipleSectorsRead = device.OptimalMultipleSectorsRead, - CanReadGdRomUsingSwapDisc = device.CanReadGdRomUsingSwapDisc - }; + Device existing = + await mctx.Devices.FirstOrDefaultAsync(d => d.Id == device.Id); - mctx.Devices.Add(existing); - } - else - { - addedDevices++; + if(existing != null) + { + modifiedDevices++; - mctx.Devices.Add(new Device(device) - { - Id = device.Id, - OptimalMultipleSectorsRead = device.OptimalMultipleSectorsRead, - CanReadGdRomUsingSwapDisc = device.CanReadGdRomUsingSwapDisc - }); - } - } - }); + mctx.Remove(existing); - AaruConsole.WriteLine("Added {0} known devices", addedDevices); - AaruConsole.WriteLine("Modified {0} known devices", modifiedDevices); + existing = new Device(device) + { + Id = device.Id, + OptimalMultipleSectorsRead = device.OptimalMultipleSectorsRead, + CanReadGdRomUsingSwapDisc = device.CanReadGdRomUsingSwapDisc + }; - AnsiConsole.Progress().AutoClear(true).HideCompleted(true). - Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). - Start(ctx => - { - ProgressTask task = ctx.AddTask("Updating known iNES/NES 2.0 headers"); - task.MaxValue = sync.Offsets.Count; + mctx.Devices.Add(existing); + } + else + { + addedDevices++; - foreach(NesHeaderDto header in sync.NesHeaders) - { - task.Increment(1); - NesHeaderInfo existing = mctx.NesHeaders.FirstOrDefault(d => d.Id == header.Id); + mctx.Devices.Add(new Device(device) + { + Id = device.Id, + OptimalMultipleSectorsRead = device.OptimalMultipleSectorsRead, + CanReadGdRomUsingSwapDisc = device.CanReadGdRomUsingSwapDisc + }); + } + } + }); - if(existing != null) - { - modifiedNesHeaders++; - DateTime addedDate = existing.AddedWhen; + AaruConsole.WriteLine(Localization.Core.Added_0_known_devices, addedDevices); + AaruConsole.WriteLine(Localization.Core.Modified_0_known_devices, modifiedDevices); - mctx.Remove(existing); + await AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .StartAsync(async ctx => + { + ProgressTask task = + ctx.AddTask(Localization.Core.Updating_known_iNES_NES_2_0_headers); - existing = new NesHeaderInfo - { - Id = header.Id, - AddedWhen = addedDate, - BatteryPresent = header.BatteryPresent, - ConsoleType = header.ConsoleType, - DefaultExpansionDevice = header.DefaultExpansionDevice, - ExtendedConsoleType = header.ExtendedConsoleType, - FourScreenMode = header.FourScreenMode, - Mapper = header.Mapper, - ModifiedWhen = DateTime.UtcNow, - NametableMirroring = header.NametableMirroring, - Sha256 = header.Sha256, - Submapper = header.Submapper, - TimingMode = header.TimingMode, - VsHardwareType = header.VsHardwareType, - VsPpuType = header.VsPpuType - }; + task.MaxValue = sync.Offsets.Count; - mctx.NesHeaders.Add(existing); - } - else - { - addedNesHeaders++; + sync.NesHeaders ??= []; - mctx.NesHeaders.Add(new NesHeaderInfo - { - Id = header.Id, - AddedWhen = DateTime.UtcNow, - BatteryPresent = header.BatteryPresent, - ConsoleType = header.ConsoleType, - DefaultExpansionDevice = header.DefaultExpansionDevice, - ExtendedConsoleType = header.ExtendedConsoleType, - FourScreenMode = header.FourScreenMode, - Mapper = header.Mapper, - ModifiedWhen = DateTime.UtcNow, - NametableMirroring = header.NametableMirroring, - Sha256 = header.Sha256, - Submapper = header.Submapper, - TimingMode = header.TimingMode, - VsHardwareType = header.VsHardwareType, - VsPpuType = header.VsPpuType - }); - } - } - }); + foreach(NesHeaderDto header in sync.NesHeaders) + { + task.Increment(1); - AaruConsole.WriteLine("Added {0} known iNES/NES 2.0 headers", addedNesHeaders); - AaruConsole.WriteLine("Modified {0} known iNES/NES 2.0 headers", modifiedNesHeaders); + NesHeaderInfo existing = + await mctx.NesHeaders.FirstOrDefaultAsync(d => d.Id == header.Id); + + if(existing != null) + { + modifiedNesHeaders++; + DateTime addedDate = existing.AddedWhen; + + mctx.Remove(existing); + + existing = new NesHeaderInfo + { + Id = header.Id, + AddedWhen = addedDate, + BatteryPresent = header.BatteryPresent, + ConsoleType = header.ConsoleType, + DefaultExpansionDevice = header.DefaultExpansionDevice, + ExtendedConsoleType = header.ExtendedConsoleType, + FourScreenMode = header.FourScreenMode, + Mapper = header.Mapper, + ModifiedWhen = DateTime.UtcNow, + NametableMirroring = header.NametableMirroring, + Sha256 = header.Sha256, + Submapper = header.Submapper, + TimingMode = header.TimingMode, + VsHardwareType = header.VsHardwareType, + VsPpuType = header.VsPpuType + }; + + mctx.NesHeaders.Add(existing); + } + else + { + addedNesHeaders++; + + mctx.NesHeaders.Add(new NesHeaderInfo + { + Id = header.Id, + AddedWhen = DateTime.UtcNow, + BatteryPresent = header.BatteryPresent, + ConsoleType = header.ConsoleType, + DefaultExpansionDevice = header.DefaultExpansionDevice, + ExtendedConsoleType = header.ExtendedConsoleType, + FourScreenMode = header.FourScreenMode, + Mapper = header.Mapper, + ModifiedWhen = DateTime.UtcNow, + NametableMirroring = header.NametableMirroring, + Sha256 = header.Sha256, + Submapper = header.Submapper, + TimingMode = header.TimingMode, + VsHardwareType = header.VsHardwareType, + VsPpuType = header.VsPpuType + }); + } + } + }); + + AaruConsole.WriteLine(Localization.Core.Added_0_known_iNES_NES_2_0_headers, addedNesHeaders); + AaruConsole.WriteLine(Localization.Core.Modified_0_known_iNES_NES_2_0_headers, modifiedNesHeaders); } } catch(Exception ex) { - AaruConsole.ErrorWriteLine("Exception {0} when updating database.", ex); + AaruConsole.ErrorWriteLine(Localization.Core.Exception_0_when_updating_database, ex); + AaruConsole.WriteException(ex); } finally { Spectre.ProgressSingleSpinner(ctx => { - ctx.AddTask("Saving changes...").IsIndeterminate(); + ctx.AddTask(Localization.Core.Saving_changes).IsIndeterminate(); mctx.SaveChanges(); }); } diff --git a/Aaru.Core/Sidecar/AudioMedia.cs b/Aaru.Core/Sidecar/AudioMedia.cs index 5f9902e83..7667efd9e 100644 --- a/Aaru.Core/Sidecar/AudioMedia.cs +++ b/Aaru.Core/Sidecar/AudioMedia.cs @@ -27,18 +27,20 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; using System.Collections.Generic; using System.IO; using System.Text; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Interfaces; -using Schemas; + +// ReSharper disable UnusedParameter.Local + +namespace Aaru.Core; public sealed partial class Sidecar { @@ -52,39 +54,38 @@ public sealed partial class Sidecar /// List of image checksums /// Metadata sidecar /// Encoding to be used for filesystem plugins - static void AudioMedia(IBaseImage image, Guid filterId, string imagePath, FileInfo fi, PluginBase plugins, - List imgChecksums, ref CICMMetadataType sidecar, Encoding encoding) + static void AudioMedia(IBaseImage image, Guid filterId, string imagePath, FileInfo fi, PluginRegister plugins, + List imgChecksums, ref Metadata sidecar, + Encoding encoding) { - sidecar.AudioMedia = new[] - { - new AudioMediaType + sidecar.AudioMedias = + [ + new AudioMedia { - Checksums = imgChecksums.ToArray(), - Image = new ImageType + Checksums = imgChecksums, + Image = new Image { - format = image.Format, - offset = 0, - offsetSpecified = true, - Value = Path.GetFileName(imagePath) + Format = image.Format, + Offset = 0, + Value = Path.GetFileName(imagePath) }, Size = (ulong)fi.Length, - Sequence = new SequenceType + Sequence = new Sequence { - MediaTitle = image.Info.MediaTitle + Title = image.Info.MediaTitle } } - }; + ]; - if(image.Info.MediaSequence != 0 && - image.Info.LastMediaSequence != 0) + if(image.Info.MediaSequence != 0 && image.Info.LastMediaSequence != 0) { - sidecar.AudioMedia[0].Sequence.MediaSequence = (uint)image.Info.MediaSequence; - sidecar.AudioMedia[0].Sequence.TotalMedia = (uint)image.Info.LastMediaSequence; + sidecar.AudioMedias[0].Sequence.MediaSequence = (uint)image.Info.MediaSequence; + sidecar.AudioMedias[0].Sequence.TotalMedia = (uint)image.Info.LastMediaSequence; } else { - sidecar.AudioMedia[0].Sequence.MediaSequence = 1; - sidecar.AudioMedia[0].Sequence.TotalMedia = 1; + sidecar.AudioMedias[0].Sequence.MediaSequence = 1; + sidecar.AudioMedias[0].Sequence.TotalMedia = 1; } } } \ No newline at end of file diff --git a/Aaru.Core/Sidecar/BlockMedia.cs b/Aaru.Core/Sidecar/BlockMedia.cs index c3f322014..76a88b6ec 100644 --- a/Aaru.Core/Sidecar/BlockMedia.cs +++ b/Aaru.Core/Sidecar/BlockMedia.cs @@ -27,30 +27,32 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Metadata; -using Aaru.CommonTypes.Structs; using Aaru.CommonTypes.Structs.Devices.ATA; using Aaru.Console; using Aaru.Decoders.PCMCIA; -using Aaru.DiscImages; using Aaru.Filters; -using Schemas; +using Aaru.Helpers; +using Aaru.Images; +using Directory = System.IO.Directory; +using File = System.IO.File; using MediaType = Aaru.CommonTypes.Metadata.MediaType; +using Partition = Aaru.CommonTypes.Partition; using Tuple = Aaru.Decoders.PCMCIA.Tuple; +namespace Aaru.Core; + public sealed partial class Sidecar { /// Creates a metadata sidecar for a block media (e.g. floppy, hard disk, flash card, usb stick) @@ -62,66 +64,61 @@ public sealed partial class Sidecar /// List of image checksums /// Metadata sidecar /// Encoding to be used for filesystem plugins - void BlockMedia(IMediaImage image, Guid filterId, string imagePath, FileInfo fi, PluginBase plugins, - List imgChecksums, ref CICMMetadataType sidecar, Encoding encoding) + void BlockMedia(IMediaImage image, Guid filterId, string imagePath, FileInfo fi, PluginRegister plugins, + List imgChecksums, ref Metadata sidecar, Encoding encoding) { - if(_aborted) - return; + if(_aborted) return; - sidecar.BlockMedia = new[] - { - new BlockMediaType + sidecar.BlockMedias = + [ + new BlockMedia { - Checksums = imgChecksums.ToArray(), - Image = new ImageType + Checksums = imgChecksums, + Image = new Image { - format = image.Format, - offset = 0, - offsetSpecified = true, - Value = Path.GetFileName(imagePath) + Format = image.Format, + Offset = 0, + Value = Path.GetFileName(imagePath) }, Size = (ulong)fi.Length, - Sequence = new SequenceType + Sequence = new Sequence { - MediaTitle = image.Info.MediaTitle + Title = image.Info.MediaTitle } } - }; + ]; - if(image.Info.MediaSequence != 0 && - image.Info.LastMediaSequence != 0) + if(image.Info.MediaSequence != 0 && image.Info.LastMediaSequence != 0) { - sidecar.BlockMedia[0].Sequence.MediaSequence = (uint)image.Info.MediaSequence; - sidecar.BlockMedia[0].Sequence.TotalMedia = (uint)image.Info.LastMediaSequence; + sidecar.BlockMedias[0].Sequence.MediaSequence = (uint)image.Info.MediaSequence; + sidecar.BlockMedias[0].Sequence.TotalMedia = (uint)image.Info.LastMediaSequence; } else { - sidecar.BlockMedia[0].Sequence.MediaSequence = 1; - sidecar.BlockMedia[0].Sequence.TotalMedia = 1; + sidecar.BlockMedias[0].Sequence.MediaSequence = 1; + sidecar.BlockMedias[0].Sequence.TotalMedia = 1; } - UpdateStatus("Hashing media tags..."); + UpdateStatus(Localization.Core.Hashing_media_tags); ErrorNumber errno; byte[] buffer; foreach(MediaTagType tagType in image.Info.ReadableMediaTags) { - if(_aborted) - return; + if(_aborted) return; switch(tagType) { case MediaTagType.ATAPI_IDENTIFY: errno = image.ReadMediaTag(MediaTagType.ATAPI_IDENTIFY, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].ATA = new ATAType + sidecar.BlockMedias[0].ATA = new ATA { - Identify = new DumpType + Identify = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length } }; @@ -130,14 +127,13 @@ public sealed partial class Sidecar case MediaTagType.ATA_IDENTIFY: errno = image.ReadMediaTag(MediaTagType.ATA_IDENTIFY, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].ATA = new ATAType + sidecar.BlockMedias[0].ATA = new ATA { - Identify = new DumpType + Identify = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length } }; @@ -146,14 +142,13 @@ public sealed partial class Sidecar case MediaTagType.PCMCIA_CIS: errno = image.ReadMediaTag(MediaTagType.PCMCIA_CIS, out byte[] cis); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].PCMCIA = new PCMCIAType + sidecar.BlockMedias[0].Pcmcia = new Pcmcia { - CIS = new DumpType + Cis = new Dump { - Checksums = Checksum.GetChecksums(cis).ToArray(), + Checksums = Checksum.GetChecksums(cis), Size = (ulong)cis.Length } }; @@ -161,7 +156,9 @@ public sealed partial class Sidecar Tuple[] tuples = CIS.GetTuples(cis); if(tuples != null) + { foreach(Tuple tuple in tuples) + { switch(tuple.Code) { case TupleCodes.CISTPL_MANFID: @@ -170,11 +167,9 @@ public sealed partial class Sidecar if(manfid != null) { - sidecar.BlockMedia[0].PCMCIA.ManufacturerCode = manfid.ManufacturerID; + sidecar.BlockMedias[0].Pcmcia.ManufacturerCode = manfid.ManufacturerID; - sidecar.BlockMedia[0].PCMCIA.CardCode = manfid.CardID; - sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true; - sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true; + sidecar.BlockMedias[0].Pcmcia.CardCode = manfid.CardID; } break; @@ -183,30 +178,34 @@ public sealed partial class Sidecar if(vers != null) { - sidecar.BlockMedia[0].PCMCIA.Manufacturer = vers.Manufacturer; - sidecar.BlockMedia[0].PCMCIA.ProductName = vers.Product; + sidecar.BlockMedias[0].Pcmcia.Manufacturer = vers.Manufacturer; + sidecar.BlockMedias[0].Pcmcia.ProductName = vers.Product; - sidecar.BlockMedia[0].PCMCIA.Compliance = + sidecar.BlockMedias[0].Pcmcia.Compliance = $"{vers.MajorVersion}.{vers.MinorVersion}"; - sidecar.BlockMedia[0].PCMCIA.AdditionalInformation = vers.AdditionalInformation; + sidecar.BlockMedias[0].Pcmcia.AdditionalInformation = + [ + ..vers.AdditionalInformation + ]; } break; } + } + } break; case MediaTagType.SCSI_INQUIRY: errno = image.ReadMediaTag(MediaTagType.SCSI_INQUIRY, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].SCSI = new SCSIType + sidecar.BlockMedias[0].SCSI = new SCSI { - Inquiry = new DumpType + Inquiry = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length } }; @@ -215,14 +214,13 @@ public sealed partial class Sidecar case MediaTagType.SD_CID: errno = image.ReadMediaTag(MediaTagType.SD_CID, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].SecureDigital ??= new SecureDigitalType(); + sidecar.BlockMedias[0].SecureDigital ??= new SecureDigital(); - sidecar.BlockMedia[0].SecureDigital.CID = new DumpType + sidecar.BlockMedias[0].SecureDigital.CID = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -230,14 +228,13 @@ public sealed partial class Sidecar case MediaTagType.SD_CSD: errno = image.ReadMediaTag(MediaTagType.SD_CSD, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].SecureDigital ??= new SecureDigitalType(); + sidecar.BlockMedias[0].SecureDigital ??= new SecureDigital(); - sidecar.BlockMedia[0].SecureDigital.CSD = new DumpType + sidecar.BlockMedias[0].SecureDigital.CSD = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -245,14 +242,13 @@ public sealed partial class Sidecar case MediaTagType.SD_SCR: errno = image.ReadMediaTag(MediaTagType.SD_SCR, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].SecureDigital ??= new SecureDigitalType(); + sidecar.BlockMedias[0].SecureDigital ??= new SecureDigital(); - sidecar.BlockMedia[0].SecureDigital.SCR = new DumpType + sidecar.BlockMedias[0].SecureDigital.SCR = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -260,14 +256,13 @@ public sealed partial class Sidecar case MediaTagType.SD_OCR: errno = image.ReadMediaTag(MediaTagType.SD_OCR, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].SecureDigital ??= new SecureDigitalType(); + sidecar.BlockMedias[0].SecureDigital ??= new SecureDigital(); - sidecar.BlockMedia[0].SecureDigital.OCR = new DumpType + sidecar.BlockMedias[0].SecureDigital.OCR = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -275,14 +270,13 @@ public sealed partial class Sidecar case MediaTagType.MMC_CID: errno = image.ReadMediaTag(MediaTagType.MMC_CID, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].MultiMediaCard ??= new MultiMediaCardType(); + sidecar.BlockMedias[0].MultiMediaCard ??= new MultiMediaCard(); - sidecar.BlockMedia[0].MultiMediaCard.CID = new DumpType + sidecar.BlockMedias[0].MultiMediaCard.CID = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -290,14 +284,13 @@ public sealed partial class Sidecar case MediaTagType.MMC_CSD: errno = image.ReadMediaTag(MediaTagType.MMC_CSD, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].MultiMediaCard ??= new MultiMediaCardType(); + sidecar.BlockMedias[0].MultiMediaCard ??= new MultiMediaCard(); - sidecar.BlockMedia[0].MultiMediaCard.CSD = new DumpType + sidecar.BlockMedias[0].MultiMediaCard.CSD = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -305,14 +298,13 @@ public sealed partial class Sidecar case MediaTagType.MMC_OCR: errno = image.ReadMediaTag(MediaTagType.MMC_OCR, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].MultiMediaCard ??= new MultiMediaCardType(); + sidecar.BlockMedias[0].MultiMediaCard ??= new MultiMediaCard(); - sidecar.BlockMedia[0].MultiMediaCard.OCR = new DumpType + sidecar.BlockMedias[0].MultiMediaCard.OCR = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -320,14 +312,13 @@ public sealed partial class Sidecar case MediaTagType.MMC_ExtendedCSD: errno = image.ReadMediaTag(MediaTagType.MMC_ExtendedCSD, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].MultiMediaCard ??= new MultiMediaCardType(); + sidecar.BlockMedias[0].MultiMediaCard ??= new MultiMediaCard(); - sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD = new DumpType + sidecar.BlockMedias[0].MultiMediaCard.ExtendedCSD = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -335,14 +326,13 @@ public sealed partial class Sidecar case MediaTagType.USB_Descriptors: errno = image.ReadMediaTag(MediaTagType.USB_Descriptors, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].USB ??= new USBType(); + sidecar.BlockMedias[0].Usb ??= new Usb(); - sidecar.BlockMedia[0].USB.Descriptors = new DumpType + sidecar.BlockMedias[0].Usb.Descriptors = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -350,14 +340,13 @@ public sealed partial class Sidecar case MediaTagType.SCSI_MODESENSE_6: errno = image.ReadMediaTag(MediaTagType.SCSI_MODESENSE_6, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].SCSI ??= new SCSIType(); + sidecar.BlockMedias[0].SCSI ??= new SCSI(); - sidecar.BlockMedia[0].SCSI.ModeSense = new DumpType + sidecar.BlockMedias[0].SCSI.ModeSense = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -365,14 +354,13 @@ public sealed partial class Sidecar case MediaTagType.SCSI_MODESENSE_10: errno = image.ReadMediaTag(MediaTagType.SCSI_MODESENSE_10, out buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; - sidecar.BlockMedia[0].SCSI ??= new SCSIType(); + sidecar.BlockMedias[0].SCSI ??= new SCSI(); - sidecar.BlockMedia[0].SCSI.ModeSense10 = new DumpType + sidecar.BlockMedias[0].SCSI.ModeSense10 = new Dump { - Checksums = Checksum.GetChecksums(buffer).ToArray(), + Checksums = Checksum.GetChecksums(buffer), Size = (ulong)buffer.Length }; @@ -383,19 +371,19 @@ public sealed partial class Sidecar // If there is only one track, and it's the same as the image file (e.g. ".iso" files), don't re-checksum. if(image.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000") && filterId == new Guid("12345678-AAAA-BBBB-CCCC-123456789000")) - sidecar.BlockMedia[0].ContentChecksums = sidecar.BlockMedia[0].Checksums; + sidecar.BlockMedias[0].ContentChecksums = sidecar.BlockMedias[0].Checksums; else { - UpdateStatus("Hashing sectors..."); + UpdateStatus(Localization.Core.Hashing_sectors); var contentChkWorker = new Checksum(); // For fast debugging, skip checksum //goto skipImageChecksum; - uint sectorsToRead = 64; - ulong sectors = image.Info.Sectors; - ulong doneSectors = 0; + const uint sectorsToRead = 64; + ulong sectors = image.Info.Sectors; + ulong doneSectors = 0; InitProgress2(); @@ -416,13 +404,13 @@ public sealed partial class Sidecar if(errno != ErrorNumber.NoError) { - UpdateStatus($"Error {errno} reading sector {doneSectors}"); + UpdateStatus(string.Format(Localization.Core.Error_0_reading_sector_1, errno, doneSectors)); EndProgress2(); return; } - UpdateProgress2("Hashing sector {0} of {1}", (long)doneSectors, (long)sectors); + UpdateProgress2(Localization.Core.Hashing_sector_0_of_1, (long)doneSectors, (long)sectors); doneSectors += sectorsToRead; } else @@ -431,13 +419,13 @@ public sealed partial class Sidecar if(errno != ErrorNumber.NoError) { - UpdateStatus($"Error {errno} reading sector {doneSectors}"); + UpdateStatus(string.Format(Localization.Core.Error_0_reading_sector_1, errno, doneSectors)); EndProgress2(); return; } - UpdateProgress2("Hashing sector {0} of {1}", (long)doneSectors, (long)sectors); + UpdateProgress2(Localization.Core.Hashing_sector_0_of_1, (long)doneSectors, (long)sectors); doneSectors += sectors - doneSectors; } @@ -447,57 +435,54 @@ public sealed partial class Sidecar // For fast debugging, skip checksum //skipImageChecksum: - List cntChecksums = contentChkWorker.End(); - - sidecar.BlockMedia[0].ContentChecksums = cntChecksums.ToArray(); + sidecar.BlockMedias[0].ContentChecksums = contentChkWorker.End(); EndProgress2(); } (string type, string subType) diskType = MediaType.MediaTypeToString(image.Info.MediaType); - sidecar.BlockMedia[0].DiskType = diskType.type; - sidecar.BlockMedia[0].DiskSubType = diskType.subType; + sidecar.BlockMedias[0].MediaType = diskType.type; + sidecar.BlockMedias[0].MediaSubType = diskType.subType; Statistics.AddMedia(image.Info.MediaType, false); - sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(image.Info.MediaType); + sidecar.BlockMedias[0].Dimensions = Dimensions.FromMediaType(image.Info.MediaType); - sidecar.BlockMedia[0].LogicalBlocks = image.Info.Sectors; - sidecar.BlockMedia[0].LogicalBlockSize = image.Info.SectorSize; + sidecar.BlockMedias[0].LogicalBlocks = image.Info.Sectors; + sidecar.BlockMedias[0].LogicalBlockSize = image.Info.SectorSize; // TODO: Detect it - sidecar.BlockMedia[0].PhysicalBlockSize = image.Info.SectorSize; + sidecar.BlockMedias[0].PhysicalBlockSize = image.Info.SectorSize; if(image is ITapeImage { IsTape: true } tapeImage) { - List tapePartitions = new(); + List tapePartitions = []; - foreach(TapePartition tapePartition in tapeImage.TapePartitions) + foreach(CommonTypes.Structs.TapePartition tapePartition in tapeImage.TapePartitions) { - var thisPartition = new TapePartitionType + var thisPartition = new TapePartition { - Image = sidecar.BlockMedia[0].Image, + Image = sidecar.BlockMedias[0].Image, Sequence = tapePartition.Number, StartBlock = tapePartition.FirstBlock, EndBlock = tapePartition.LastBlock }; if(tapeImage.TapePartitions.Count == 1) - thisPartition.Checksums = sidecar.BlockMedia[0].ContentChecksums; + thisPartition.Checksums = sidecar.BlockMedias[0].ContentChecksums; else { - UpdateStatus($"Hashing partition {tapePartition.Number}..."); + UpdateStatus(string.Format(Localization.Core.Hashing_partition_0, tapePartition.Number)); - if(_aborted) - return; + if(_aborted) return; var tapePartitionChk = new Checksum(); // For fast debugging, skip checksum //goto skipImageChecksum; - uint sectorsToRead = 64; - ulong sectors = tapePartition.LastBlock - tapePartition.FirstBlock + 1; - ulong doneSectors = 0; + const uint sectorsToRead = 64; + ulong sectors = tapePartition.LastBlock - tapePartition.FirstBlock + 1; + ulong doneSectors = 0; InitProgress2(); @@ -514,38 +499,42 @@ public sealed partial class Sidecar if(sectors - doneSectors >= sectorsToRead) { - errno = image.ReadSectors(tapePartition.FirstBlock + doneSectors, sectorsToRead, + errno = image.ReadSectors(tapePartition.FirstBlock + doneSectors, + sectorsToRead, out sector); if(errno != ErrorNumber.NoError) { - AaruConsole. - ErrorWriteLine($"Error {errno} reading sector {tapePartition.FirstBlock + doneSectors}"); + AaruConsole.ErrorWriteLine(string.Format(Localization.Core.Error_0_reading_sector_1, + errno, + tapePartition.FirstBlock + doneSectors)); EndProgress2(); return; } - UpdateProgress2("Hashing blocks {0} of {1}", (long)doneSectors, (long)sectors); + UpdateProgress2(Localization.Core.Hashing_blocks_0_of_1, (long)doneSectors, (long)sectors); doneSectors += sectorsToRead; } else { errno = image.ReadSectors(tapePartition.FirstBlock + doneSectors, - (uint)(sectors - doneSectors), out sector); + (uint)(sectors - doneSectors), + out sector); if(errno != ErrorNumber.NoError) { - AaruConsole. - ErrorWriteLine($"Error {errno} reading sector {tapePartition.FirstBlock + doneSectors}"); + AaruConsole.ErrorWriteLine(string.Format(Localization.Core.Error_0_reading_sector_1, + errno, + tapePartition.FirstBlock + doneSectors)); EndProgress2(); return; } - UpdateProgress2("Hashing blocks {0} of {1}", (long)doneSectors, (long)sectors); + UpdateProgress2(Localization.Core.Hashing_blocks_0_of_1, (long)doneSectors, (long)sectors); doneSectors += sectors - doneSectors; } @@ -557,23 +546,22 @@ public sealed partial class Sidecar // For fast debugging, skip checksum //skipImageChecksum: - List partitionChecksums = tapePartitionChk.End(); - - thisPartition.Checksums = partitionChecksums.ToArray(); + thisPartition.Checksums = tapePartitionChk.End(); EndProgress2(); } - List filesInPartition = new(); + List filesInPartition = []; - foreach(TapeFile tapeFile in tapeImage.Files.Where(f => f.Partition == tapePartition.Number)) + foreach(CommonTypes.Structs.TapeFile tapeFile in + tapeImage.Files.Where(f => f.Partition == tapePartition.Number)) { - var thisFile = new TapeFileType + var thisFile = new TapeFile { Sequence = tapeFile.File, StartBlock = tapeFile.FirstBlock, EndBlock = tapeFile.LastBlock, - Image = sidecar.BlockMedia[0].Image, + Image = sidecar.BlockMedias[0].Image, Size = 0, BlockSize = 0 }; @@ -585,19 +573,18 @@ public sealed partial class Sidecar } else { - UpdateStatus($"Hashing file {tapeFile.File}..."); + UpdateStatus(string.Format(Localization.Core.Hashing_file_0, tapeFile.File)); - if(_aborted) - return; + if(_aborted) return; var tapeFileChk = new Checksum(); // For fast debugging, skip checksum //goto skipImageChecksum; - uint sectorsToRead = 64; - ulong sectors = tapeFile.LastBlock - tapeFile.FirstBlock + 1; - ulong doneSectors = 0; + const uint sectorsToRead = 64; + ulong sectors = tapeFile.LastBlock - tapeFile.FirstBlock + 1; + ulong doneSectors = 0; InitProgress2(); @@ -618,33 +605,42 @@ public sealed partial class Sidecar if(errno != ErrorNumber.NoError) { - AaruConsole. - ErrorWriteLine($"Error {errno} reading sector {tapeFile.FirstBlock + doneSectors}"); + AaruConsole.ErrorWriteLine(string.Format(Localization.Core.Error_0_reading_sector_1, + errno, + tapeFile.FirstBlock + doneSectors)); EndProgress2(); return; } - UpdateProgress2("Hashing blocks {0} of {1}", (long)doneSectors, (long)sectors); + UpdateProgress2(Localization.Core.Hashing_blocks_0_of_1, + (long)doneSectors, + (long)sectors); + doneSectors += sectorsToRead; } else { errno = image.ReadSectors(tapeFile.FirstBlock + doneSectors, - (uint)(sectors - doneSectors), out sector); + (uint)(sectors - doneSectors), + out sector); if(errno != ErrorNumber.NoError) { - AaruConsole. - ErrorWriteLine($"Error {errno} reading sector {tapeFile.FirstBlock + doneSectors}"); + AaruConsole.ErrorWriteLine(string.Format(Localization.Core.Error_0_reading_sector_1, + errno, + tapeFile.FirstBlock + doneSectors)); EndProgress2(); return; } - UpdateProgress2("Hashing blocks {0} of {1}", (long)doneSectors, (long)sectors); + UpdateProgress2(Localization.Core.Hashing_blocks_0_of_1, + (long)doneSectors, + (long)sectors); + doneSectors += sectors - doneSectors; } @@ -659,9 +655,7 @@ public sealed partial class Sidecar // For fast debugging, skip checksum //skipImageChecksum: - List fileChecksums = tapeFileChk.End(); - - thisFile.Checksums = fileChecksums.ToArray(); + thisFile.Checksums = tapeFileChk.End(); EndProgress2(); } @@ -669,85 +663,88 @@ public sealed partial class Sidecar filesInPartition.Add(thisFile); } - thisPartition.File = filesInPartition.ToArray(); + thisPartition.Files = filesInPartition; tapePartitions.Add(thisPartition); } - sidecar.BlockMedia[0].TapeInformation = tapePartitions.ToArray(); + sidecar.BlockMedias[0].TapeInformation = tapePartitions; } - UpdateStatus("Checking filesystems..."); + UpdateStatus(Localization.Core.Checking_filesystems); - if(_aborted) - return; + if(_aborted) return; List partitions = Partitions.GetAll(image); Partitions.AddSchemesToStats(partitions); - sidecar.BlockMedia[0].FileSystemInformation = new PartitionType[1]; + sidecar.BlockMedias[0].FileSystemInformation = []; if(partitions.Count > 0) { - sidecar.BlockMedia[0].FileSystemInformation = new PartitionType[partitions.Count]; - - for(var i = 0; i < partitions.Count; i++) + foreach(Partition partition in partitions) { - if(_aborted) - return; + if(_aborted) return; - sidecar.BlockMedia[0].FileSystemInformation[i] = new PartitionType + var fsInfo = new CommonTypes.AaruMetadata.Partition { - Description = partitions[i].Description, - EndSector = partitions[i].End, - Name = partitions[i].Name, - Sequence = (uint)partitions[i].Sequence, - StartSector = partitions[i].Start, - Type = partitions[i].Type + Description = partition.Description, + EndSector = partition.End, + Name = partition.Name, + Sequence = (uint)partition.Sequence, + StartSector = partition.Start, + Type = partition.Type }; - List lstFs = new(); + List lstFs = []; - foreach(IFilesystem plugin in plugins.PluginsList.Values) + foreach(IFilesystem fs in plugins.Filesystems.Values) + { try { - if(_aborted) - return; + if(_aborted) return; - if(!plugin.Identify(image, partitions[i])) - continue; + if(fs is null) continue; - if(plugin is IReadOnlyFilesystem fsPlugin && - fsPlugin.Mount(image, partitions[i], encoding, null, null) == ErrorNumber.NoError) + if(!fs.Identify(image, partition)) continue; + + if(fs is IReadOnlyFilesystem rofs && + rofs.Mount(image, partition, encoding, null, null) == ErrorNumber.NoError) { - UpdateStatus($"Mounting {fsPlugin.XmlFsType.Type}"); + UpdateStatus(string.Format(Localization.Core.Mounting_0, rofs.Metadata.Type)); - fsPlugin.XmlFsType.Contents = Files(fsPlugin); + rofs.Metadata.Contents = Files(rofs); - fsPlugin.Unmount(); + lstFs.Add(rofs.Metadata); + Statistics.AddFilesystem(rofs.Metadata.Type); + + rofs.Unmount(); } else - plugin.GetInformation(image, partitions[i], out _, encoding); + { + fs.GetInformation(image, partition, encoding, out _, out FileSystem fsMetadata); - lstFs.Add(plugin.XmlFsType); - Statistics.AddFilesystem(plugin.XmlFsType.Type); + lstFs.Add(fsMetadata); + Statistics.AddFilesystem(fsMetadata.Type); + } } - #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch - #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body { - //AaruConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name); + //AaruConsole.DebugWriteLine(MODULE_NAME, "Plugin {0} crashed", _plugin.Name); } + } - if(lstFs.Count > 0) - sidecar.BlockMedia[0].FileSystemInformation[i].FileSystems = lstFs.ToArray(); + if(lstFs.Count > 0) fsInfo.FileSystems = lstFs; + + sidecar.BlockMedias[0].FileSystemInformation.Add(fsInfo); } } else { - if(_aborted) - return; + if(_aborted) return; - sidecar.BlockMedia[0].FileSystemInformation[0] = new PartitionType + var fsInfo = new CommonTypes.AaruMetadata.Partition { StartSector = 0, EndSector = image.Info.Sectors - 1 @@ -755,60 +752,63 @@ public sealed partial class Sidecar var wholePart = new Partition { - Name = "Whole device", + Name = Localization.Core.Whole_device, Length = image.Info.Sectors, Size = image.Info.Sectors * image.Info.SectorSize }; - List lstFs = new(); + List lstFs = []; - foreach(IFilesystem plugin in plugins.PluginsList.Values) + foreach(IFilesystem fs in plugins.Filesystems.Values) + { try { - if(_aborted) - return; + if(_aborted) return; - if(!plugin.Identify(image, wholePart)) - continue; + if(fs is null) continue; - if(plugin is IReadOnlyFilesystem fsPlugin && - fsPlugin.Mount(image, wholePart, encoding, null, null) == ErrorNumber.NoError) + if(!fs.Identify(image, wholePart)) continue; + + if(fs is IReadOnlyFilesystem rofs && + rofs.Mount(image, wholePart, encoding, null, null) == ErrorNumber.NoError) { - UpdateStatus($"Mounting {fsPlugin.XmlFsType.Type}"); + UpdateStatus(string.Format(Localization.Core.Mounting_0, rofs.Metadata.Type)); - fsPlugin.XmlFsType.Contents = Files(fsPlugin); + rofs.Metadata.Contents = Files(rofs); - fsPlugin.Unmount(); + lstFs.Add(rofs.Metadata); + Statistics.AddFilesystem(rofs.Metadata.Type); + + rofs.Unmount(); } else - plugin.GetInformation(image, wholePart, out _, encoding); + { + fs.GetInformation(image, wholePart, encoding, out _, out FileSystem fsMetadata); - lstFs.Add(plugin.XmlFsType); - Statistics.AddFilesystem(plugin.XmlFsType.Type); + lstFs.Add(fsMetadata); + Statistics.AddFilesystem(fsMetadata.Type); + } } - #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch - #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body { - //AaruConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name); + //AaruConsole.DebugWriteLine(MODULE_NAME, "Plugin {0} crashed", _plugin.Name); } + } - if(lstFs.Count > 0) - sidecar.BlockMedia[0].FileSystemInformation[0].FileSystems = lstFs.ToArray(); + if(lstFs.Count > 0) fsInfo.FileSystems = lstFs; + + sidecar.BlockMedias[0].FileSystemInformation.Add(fsInfo); } - UpdateStatus("Saving metadata..."); + UpdateStatus(Localization.Core.Saving_metadata); - if(image.Info.Cylinders > 0 && - image.Info.Heads > 0 && - image.Info.SectorsPerTrack > 0) + if(image.Info.Cylinders > 0 && image.Info is { Heads: > 0, SectorsPerTrack: > 0 }) { - sidecar.BlockMedia[0].CylindersSpecified = true; - sidecar.BlockMedia[0].HeadsSpecified = true; - sidecar.BlockMedia[0].SectorsPerTrackSpecified = true; - sidecar.BlockMedia[0].Cylinders = image.Info.Cylinders; - sidecar.BlockMedia[0].Heads = (ushort)image.Info.Heads; - sidecar.BlockMedia[0].SectorsPerTrack = image.Info.SectorsPerTrack; + sidecar.BlockMedias[0].Cylinders = image.Info.Cylinders; + sidecar.BlockMedias[0].Heads = (ushort)image.Info.Heads; + sidecar.BlockMedias[0].SectorsPerTrack = image.Info.SectorsPerTrack; } if(image.Info.ReadableMediaTags.Contains(MediaTagType.ATA_IDENTIFY)) @@ -816,36 +816,26 @@ public sealed partial class Sidecar Identify.IdentifyDevice? ataId = null; errno = image.ReadMediaTag(MediaTagType.ATA_IDENTIFY, out buffer); - if(errno == ErrorNumber.NoError) - ataId = Identify.Decode(buffer); + if(errno == ErrorNumber.NoError) ataId = Identify.Decode(buffer); - if(ataId.HasValue) - if(ataId.Value.CurrentCylinders > 0 && - ataId.Value.CurrentHeads > 0 && - ataId.Value.CurrentSectorsPerTrack > 0) - { - sidecar.BlockMedia[0].CylindersSpecified = true; - sidecar.BlockMedia[0].HeadsSpecified = true; - sidecar.BlockMedia[0].SectorsPerTrackSpecified = true; - sidecar.BlockMedia[0].Cylinders = ataId.Value.CurrentCylinders; - sidecar.BlockMedia[0].Heads = ataId.Value.CurrentHeads; - sidecar.BlockMedia[0].SectorsPerTrack = ataId.Value.CurrentSectorsPerTrack; - } - else if(ataId.Value.Cylinders > 0 && - ataId.Value.Heads > 0 && - ataId.Value.SectorsPerTrack > 0) - { - sidecar.BlockMedia[0].CylindersSpecified = true; - sidecar.BlockMedia[0].HeadsSpecified = true; - sidecar.BlockMedia[0].SectorsPerTrackSpecified = true; - sidecar.BlockMedia[0].Cylinders = ataId.Value.Cylinders; - sidecar.BlockMedia[0].Heads = ataId.Value.Heads; - sidecar.BlockMedia[0].SectorsPerTrack = ataId.Value.SectorsPerTrack; - } + switch(ataId) + { + case { CurrentCylinders: > 0, CurrentHeads: > 0, CurrentSectorsPerTrack: > 0 }: + sidecar.BlockMedias[0].Cylinders = ataId.Value.CurrentCylinders; + sidecar.BlockMedias[0].Heads = ataId.Value.CurrentHeads; + sidecar.BlockMedias[0].SectorsPerTrack = ataId.Value.CurrentSectorsPerTrack; + + break; + case { Cylinders: > 0, Heads: > 0, SectorsPerTrack: > 0 }: + sidecar.BlockMedias[0].Cylinders = ataId.Value.Cylinders; + sidecar.BlockMedias[0].Heads = ataId.Value.Heads; + sidecar.BlockMedias[0].SectorsPerTrack = ataId.Value.SectorsPerTrack; + + break; + } } - if(image.DumpHardware != null) - sidecar.BlockMedia[0].DumpHardwareArray = image.DumpHardware.ToArray(); + sidecar.BlockMedias[0].DumpHardware = image.DumpHardware; // TODO: This is more of a hack, redo it planned for >4.0 string trkFormat = null; @@ -951,7 +941,8 @@ public sealed partial class Sidecar break; case CommonTypes.MediaType.SHARP_525_9: - case CommonTypes.MediaType.SHARP_35_9: break; + case CommonTypes.MediaType.SHARP_35_9: + break; case CommonTypes.MediaType.ECMA_99_15: case CommonTypes.MediaType.ECMA_99_26: case CommonTypes.MediaType.ECMA_99_8: @@ -976,22 +967,21 @@ public sealed partial class Sidecar break; } - #region SuperCardPro +#region SuperCardPro + string scpFilePath = Path.Combine(Path.GetDirectoryName(imagePath), Path.GetFileNameWithoutExtension(imagePath) + ".scp"); - if(_aborted) - return; + if(_aborted) return; if(File.Exists(scpFilePath)) { - UpdateStatus("Hashing SuperCardPro image..."); + UpdateStatus(Localization.Core.Hashing_SuperCardPro_image); var scpImage = new SuperCardPro(); var scpFilter = new ZZZNoFilter(); scpFilter.Open(scpFilePath); - if(image.Info.Heads <= 2 && - scpImage.Identify(scpFilter)) + if(image.Info.Heads <= 2 && scpImage.Identify(scpFilter)) { try { @@ -1001,26 +991,26 @@ public sealed partial class Sidecar if(image.Info.Heads == 2 && scpImage.Header.heads == 0 || image.Info.Heads == 1 && scpImage.Header.heads is 1 or 2) + { if(scpImage.Header.end + 1 >= image.Info.Cylinders) { - List scpBlockTrackTypes = new(); - ulong currentSector = 0; - Stream scpStream = scpFilter.GetDataForkStream(); + List scpBlockTrackTypes = []; + ulong currentSector = 0; + Stream scpStream = scpFilter.GetDataForkStream(); for(byte t = scpImage.Header.start; t <= scpImage.Header.end; t++) { - if(_aborted) - return; + if(_aborted) return; - var scpBlockTrackType = new BlockTrackType + var scpBlockTrackType = new BlockTrack { Cylinder = t / image.Info.Heads, Head = (ushort)(t % image.Info.Heads), - Image = new ImageType + Image = new Image { - format = scpImage.Format, + Format = scpImage.Format, Value = Path.GetFileName(scpFilePath), - offset = scpImage.Header.offsets[t] + Offset = scpImage.Header.offsets[t] } }; @@ -1037,42 +1027,52 @@ public sealed partial class Sidecar if(scpImage.ScpTracks.TryGetValue(t, out SuperCardPro.TrackHeader scpTrack)) { var trackContents = - new byte[scpTrack.Entries.Last().dataOffset + scpTrack.Entries.Last().trackLength - - scpImage.Header.offsets[t] + 1]; + new byte[scpTrack.Entries.Last().dataOffset + + scpTrack.Entries.Last().trackLength - + scpImage.Header.offsets[t] + + 1]; scpStream.Position = scpImage.Header.offsets[t]; - scpStream.Read(trackContents, 0, trackContents.Length); + scpStream.EnsureRead(trackContents, 0, trackContents.Length); scpBlockTrackType.Size = (ulong)trackContents.Length; - scpBlockTrackType.Checksums = Checksum.GetChecksums(trackContents).ToArray(); + scpBlockTrackType.Checksums = Checksum.GetChecksums(trackContents); } scpBlockTrackTypes.Add(scpBlockTrackType); } - sidecar.BlockMedia[0].Track = scpBlockTrackTypes.OrderBy(t => t.Cylinder). - ThenBy(t => t.Head).ToArray(); + sidecar.BlockMedias[0].Track = + scpBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToList(); } else - AaruConsole. - ErrorWriteLine("SuperCardPro image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...", - scpImage.Header.end + 1, image.Info.Cylinders); + { + AaruConsole.ErrorWriteLine(Localization.Core + .SCP_image_do_not_same_number_tracks_0_disk_image_1_ignoring, + scpImage.Header.end + 1, + image.Info.Cylinders); + } + } else - AaruConsole. - ErrorWriteLine("SuperCardPro image do not contain same number of heads ({0}) than disk image ({1}), ignoring...", - 2, image.Info.Heads); + { + AaruConsole.ErrorWriteLine(Localization.Core + .SCP_image_do_not_same_number_heads_0_disk_image_1_ignoring, + 2, + image.Info.Heads); + } } } - #endregion - #region KryoFlux +#endregion + +#region KryoFlux + string kfFile = null; string basename = Path.Combine(Path.GetDirectoryName(imagePath), Path.GetFileNameWithoutExtension(imagePath)); var kfDir = false; - if(_aborted) - return; + if(_aborted) return; if(Directory.Exists(basename)) { @@ -1085,20 +1085,18 @@ public sealed partial class Sidecar } } else if(File.Exists(basename + "00.0.raw")) - kfFile = basename + "00.0.raw"; - else if(File.Exists(basename + "00.1.raw")) - kfFile = basename + "00.1.raw"; + kfFile = basename + "00.0.raw"; + else if(File.Exists(basename + "00.1.raw")) kfFile = basename + "00.1.raw"; if(kfFile != null) { - UpdateStatus("Hashing KryoFlux images..."); + UpdateStatus(Localization.Core.Hashing_KryoFlux_images); var kfImage = new KryoFlux(); var kfFilter = new ZZZNoFilter(); kfFilter.Open(kfFile); - if(image.Info.Heads <= 2 && - kfImage.Identify(kfFilter)) + if(image.Info.Heads <= 2 && kfImage.Identify(kfFilter)) { try { @@ -1107,29 +1105,30 @@ public sealed partial class Sidecar catch(NotImplementedException) {} if(kfImage.Info.Heads == image.Info.Heads) + { if(kfImage.Info.Cylinders >= image.Info.Cylinders) { - List kfBlockTrackTypes = new(); + List kfBlockTrackTypes = []; ulong currentSector = 0; foreach(KeyValuePair kvp in kfImage.tracks) { - if(_aborted) - return; + if(_aborted) return; - var kfBlockTrackType = new BlockTrackType + var kfBlockTrackType = new BlockTrack { Cylinder = kvp.Key / image.Info.Heads, Head = (ushort)(kvp.Key % image.Info.Heads), - Image = new ImageType + Image = new Image { - format = kfImage.Format, + Format = kfImage.Format, Value = kfDir - ? Path. - Combine(Path.GetFileName(Path.GetDirectoryName(kvp.Value.BasePath)), - kvp.Value.Filename) : kvp.Value.Filename, - offset = 0 + ? Path.Combine(Path.GetFileName(Path.GetDirectoryName(kvp.Value + .BasePath)), + kvp.Value.Filename) + : kvp.Value.Filename, + Offset = 0 } }; @@ -1146,44 +1145,50 @@ public sealed partial class Sidecar Stream kfStream = kvp.Value.GetDataForkStream(); var trackContents = new byte[kfStream.Length]; kfStream.Position = 0; - kfStream.Read(trackContents, 0, trackContents.Length); + kfStream.EnsureRead(trackContents, 0, trackContents.Length); kfBlockTrackType.Size = (ulong)trackContents.Length; - kfBlockTrackType.Checksums = Checksum.GetChecksums(trackContents).ToArray(); + kfBlockTrackType.Checksums = Checksum.GetChecksums(trackContents); kfBlockTrackTypes.Add(kfBlockTrackType); } - sidecar.BlockMedia[0].Track = kfBlockTrackTypes.OrderBy(t => t.Cylinder). - ThenBy(t => t.Head).ToArray(); + sidecar.BlockMedias[0].Track = + kfBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToList(); } else - AaruConsole. - ErrorWriteLine("KryoFlux image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...", - kfImage.Info.Cylinders, image.Info.Cylinders); + { + AaruConsole.ErrorWriteLine(Localization.Core + .KryoFlux_image_do_not_same_number_tracks_0_disk_image_1_ignoring, + kfImage.Info.Cylinders, + image.Info.Cylinders); + } + } else - AaruConsole. - ErrorWriteLine("KryoFluximage do not contain same number of heads ({0}) than disk image ({1}), ignoring...", - kfImage.Info.Heads, image.Info.Heads); + { + AaruConsole.ErrorWriteLine(Localization.Core + .KryoFlux_image_do_not_same_number_heads_0_disk_image_1_ignoring, + kfImage.Info.Heads, + image.Info.Heads); + } } } - #endregion - #region DiscFerret +#endregion + +#region DiscFerret + string dfiFilePath = Path.Combine(Path.GetDirectoryName(imagePath), Path.GetFileNameWithoutExtension(imagePath) + ".dfi"); - if(_aborted) - return; + if(_aborted) return; - if(!File.Exists(dfiFilePath)) - return; + if(!File.Exists(dfiFilePath)) return; var dfiImage = new DiscFerret(); var dfiFilter = new ZZZNoFilter(); dfiFilter.Open(dfiFilePath); - if(!dfiImage.Identify(dfiFilter)) - return; + if(!dfiImage.Identify(dfiFilter)) return; try { @@ -1191,27 +1196,27 @@ public sealed partial class Sidecar } catch(NotImplementedException) {} - UpdateStatus("Hashing DiscFerret image..."); + UpdateStatus(Localization.Core.Hashing_DiscFerret_image); if(image.Info.Heads == dfiImage.Info.Heads) + { if(dfiImage.Info.Cylinders >= image.Info.Cylinders) { - List dfiBlockTrackTypes = new(); - ulong currentSector = 0; - Stream dfiStream = dfiFilter.GetDataForkStream(); + List dfiBlockTrackTypes = []; + ulong currentSector = 0; + Stream dfiStream = dfiFilter.GetDataForkStream(); foreach(int t in dfiImage.TrackOffsets.Keys) { - if(_aborted) - return; + if(_aborted) return; - var dfiBlockTrackType = new BlockTrackType + var dfiBlockTrackType = new BlockTrack { Cylinder = (uint)(t / image.Info.Heads), Head = (ushort)(t % image.Info.Heads), - Image = new ImageType + Image = new Image { - format = dfiImage.Format, + Format = dfiImage.Format, Value = Path.GetFileName(dfiFilePath) } }; @@ -1229,28 +1234,36 @@ public sealed partial class Sidecar if(dfiImage.TrackOffsets.TryGetValue(t, out long offset) && dfiImage.TrackLengths.TryGetValue(t, out long length)) { - dfiBlockTrackType.Image.offset = (ulong)offset; + dfiBlockTrackType.Image.Offset = (ulong)offset; var trackContents = new byte[length]; dfiStream.Position = offset; - dfiStream.Read(trackContents, 0, trackContents.Length); + dfiStream.EnsureRead(trackContents, 0, trackContents.Length); dfiBlockTrackType.Size = (ulong)trackContents.Length; - dfiBlockTrackType.Checksums = Checksum.GetChecksums(trackContents).ToArray(); + dfiBlockTrackType.Checksums = Checksum.GetChecksums(trackContents); } dfiBlockTrackTypes.Add(dfiBlockTrackType); } - sidecar.BlockMedia[0].Track = dfiBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToArray(); + sidecar.BlockMedias[0].Track = dfiBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToList(); } else - AaruConsole. - ErrorWriteLine("DiscFerret image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...", - dfiImage.Info.Cylinders, image.Info.Cylinders); + { + AaruConsole.ErrorWriteLine(Localization.Core + .DiscFerret_image_do_not_same_number_tracks_0_disk_image_1_ignoring, + dfiImage.Info.Cylinders, + image.Info.Cylinders); + } + } else - AaruConsole. - ErrorWriteLine("DiscFerret image do not contain same number of heads ({0}) than disk image ({1}), ignoring...", - dfiImage.Info.Heads, image.Info.Heads); - #endregion + { + AaruConsole.ErrorWriteLine(Localization.Core + .DiscFerret_image_do_not_same_number_heads_0_disk_image_1_ignoring, + dfiImage.Info.Heads, + image.Info.Heads); + } + +#endregion // TODO: Implement support for getting CHS from SCSI mode pages } diff --git a/Aaru.Core/Sidecar/BlockTape.cs b/Aaru.Core/Sidecar/BlockTape.cs index 6f32860a7..4a403ecb0 100644 --- a/Aaru.Core/Sidecar/BlockTape.cs +++ b/Aaru.Core/Sidecar/BlockTape.cs @@ -27,14 +27,15 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System.Collections.Generic; using System.IO; -using Schemas; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.Helpers; + +namespace Aaru.Core; /// Sidecar operations public sealed partial class Sidecar @@ -43,68 +44,64 @@ public sealed partial class Sidecar /// List of files /// Dump path /// Expected block size in bytes - public CICMMetadataType BlockTape(string folderName, List files, uint blockSize) + public Metadata BlockTape(string folderName, List files, uint blockSize) { - _sidecar = new CICMMetadataType + _sidecar = new Metadata { - BlockMedia = new[] - { - new BlockMediaType + BlockMedias = + [ + new BlockMedia { - Image = new ImageType + Image = new Image { - format = "Directory", - offsetSpecified = false, - Value = folderName + Format = "Directory", + Value = folderName }, - Sequence = new SequenceType + Sequence = new Sequence { - MediaTitle = folderName, + Title = folderName, MediaSequence = 1, TotalMedia = 1 }, PhysicalBlockSize = blockSize, LogicalBlockSize = blockSize, - TapeInformation = new[] - { - new TapePartitionType + TapeInformation = + [ + new TapePartition { - Image = new ImageType + Image = new Image { - format = "Directory", - offsetSpecified = false, - Value = folderName + Format = "Directory", + Value = folderName } } - } + ] } - } + ] }; - if(_aborted) - return _sidecar; + if(_aborted) return _sidecar; - ulong currentBlock = 0; - ulong totalSize = 0; - var tapeWorker = new Checksum(); - var tapeFiles = new List(); + ulong currentBlock = 0; + ulong totalSize = 0; + var tapeWorker = new Checksum(); + List tapeFiles = []; - UpdateStatus("Hashing files..."); + UpdateStatus(Localization.Core.Hashing_files); for(var i = 0; i < files.Count; i++) { - if(_aborted) - return _sidecar; + if(_aborted) return _sidecar; _fs = new FileStream(files[i], FileMode.Open, FileAccess.Read); var fileWorker = new Checksum(); - var tapeFile = new TapeFileType + var tapeFile = new TapeFile { - Image = new ImageType + Image = new Image { - format = "Raw disk image (sector by sector copy)", - offset = 0, + Format = "Raw disk image (sector by sector copy)", + Offset = 0, Value = Path.GetFileName(files[i]) }, Size = (ulong)_fs.Length, @@ -133,20 +130,22 @@ public sealed partial class Sidecar if(sectors - doneSectors >= sectorsToRead) { sector = new byte[sectorsToRead * blockSize]; - _fs.Read(sector, 0, sector.Length); + _fs.EnsureRead(sector, 0, sector.Length); UpdateProgress2($"Hashing block {doneSectors} of {sectors} on file {i + 1} of {files.Count}", - (long)doneSectors, (long)sectors); + (long)doneSectors, + (long)sectors); doneSectors += sectorsToRead; } else { sector = new byte[(uint)(sectors - doneSectors) * blockSize]; - _fs.Read(sector, 0, sector.Length); + _fs.EnsureRead(sector, 0, sector.Length); UpdateProgress2($"Hashing block {doneSectors} of {sectors} on file {i + 1} of {files.Count}", - (long)doneSectors, (long)sectors); + (long)doneSectors, + (long)sectors); doneSectors += sectors - doneSectors; } @@ -158,63 +157,92 @@ public sealed partial class Sidecar tapeFile.EndBlock = tapeFile.StartBlock + sectors - 1; currentBlock += sectors; totalSize += (ulong)_fs.Length; - tapeFile.Checksums = fileWorker.End().ToArray(); + tapeFile.Checksums = fileWorker.End(); tapeFiles.Add(tapeFile); EndProgress2(); } UpdateStatus("Setting metadata..."); - _sidecar.BlockMedia[0].Checksums = tapeWorker.End().ToArray(); - _sidecar.BlockMedia[0].ContentChecksums = _sidecar.BlockMedia[0].Checksums; - _sidecar.BlockMedia[0].Size = totalSize; - _sidecar.BlockMedia[0].LogicalBlocks = currentBlock; - _sidecar.BlockMedia[0].TapeInformation[0].EndBlock = currentBlock - 1; - _sidecar.BlockMedia[0].TapeInformation[0].Size = totalSize; - _sidecar.BlockMedia[0].TapeInformation[0].Checksums = _sidecar.BlockMedia[0].Checksums; - _sidecar.BlockMedia[0].TapeInformation[0].File = tapeFiles.ToArray(); + _sidecar.BlockMedias[0].Checksums = tapeWorker.End(); + _sidecar.BlockMedias[0].ContentChecksums = _sidecar.BlockMedias[0].Checksums; + _sidecar.BlockMedias[0].Size = totalSize; + _sidecar.BlockMedias[0].LogicalBlocks = currentBlock; + _sidecar.BlockMedias[0].TapeInformation[0].EndBlock = currentBlock - 1; + _sidecar.BlockMedias[0].TapeInformation[0].Size = totalSize; + _sidecar.BlockMedias[0].TapeInformation[0].Checksums = _sidecar.BlockMedias[0].Checksums; + _sidecar.BlockMedias[0].TapeInformation[0].Files = tapeFiles; // This is purely for convenience, as typically these kind of data represents QIC tapes if(blockSize == 512) { - _sidecar.BlockMedia[0].DiskType = "Quarter-inch cartridge"; + _sidecar.BlockMedias[0].MediaType = "Quarter-inch cartridge"; - if(totalSize <= 20 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-11"; - else if(totalSize <= 40 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-40"; - else if(totalSize <= 60 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-24"; - else if(totalSize <= 80 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-80"; - else if(totalSize <= 120 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-120"; - else if(totalSize <= 150 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-150"; - else if(totalSize <= 320 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-320"; - else if(totalSize <= 340 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-3010"; - else if(totalSize <= 525 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-525"; - else if(totalSize <= 670 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-3020"; - else if(totalSize <= 1200 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-3080"; - else if(totalSize <= 1350 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-1350"; - else if(totalSize <= (long)4000 * 1048576) - _sidecar.BlockMedia[0].DiskSubType = "QIC-3095"; - else + switch(totalSize) { - _sidecar.BlockMedia[0].DiskType = "Unknown tape"; - _sidecar.BlockMedia[0].DiskSubType = "Unknown tape"; + case <= 20 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-11"; + + break; + case <= 40 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-40"; + + break; + case <= 60 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-24"; + + break; + case <= 80 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-80"; + + break; + case <= 120 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-120"; + + break; + case <= 150 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-150"; + + break; + case <= 320 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-320"; + + break; + case <= 340 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-3010"; + + break; + case <= 525 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-525"; + + break; + case <= 670 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-3020"; + + break; + case <= 1200 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-3080"; + + break; + case <= 1350 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-1350"; + + break; + case <= (long)4000 * 1048576: + _sidecar.BlockMedias[0].MediaSubType = "QIC-3095"; + + break; + default: + _sidecar.BlockMedias[0].MediaType = "Unknown tape"; + _sidecar.BlockMedias[0].MediaSubType = "Unknown tape"; + + break; } } else { - _sidecar.BlockMedia[0].DiskType = "Unknown tape"; - _sidecar.BlockMedia[0].DiskSubType = "Unknown tape"; + _sidecar.BlockMedias[0].MediaType = "Unknown tape"; + _sidecar.BlockMedias[0].MediaSubType = "Unknown tape"; } return _sidecar; diff --git a/Aaru.Core/Sidecar/Events.cs b/Aaru.Core/Sidecar/Events.cs index 4b46ecc88..8e9d4bc0d 100644 --- a/Aaru.Core/Sidecar/Events.cs +++ b/Aaru.Core/Sidecar/Events.cs @@ -27,27 +27,33 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using Aaru.CommonTypes; +namespace Aaru.Core; + public sealed partial class Sidecar { /// Initializes a progress indicator (e.g. makes a progress bar visible) public event InitProgressHandler InitProgressEvent; + /// Updates a progress indicator with text public event UpdateProgressHandler UpdateProgressEvent; + /// Uninitializes a progress indicator (e.g. adds a newline to the console) public event EndProgressHandler EndProgressEvent; + /// Initializes a secondary progress indicator (e.g. makes a progress bar visible) public event InitProgressHandler2 InitProgressEvent2; + /// Event raised to update the values of a determinate progress bar public event UpdateProgressHandler2 UpdateProgressEvent2; + /// Event raised when the progress bar is not longer needed public event EndProgressHandler2 EndProgressEvent2; + /// Updates a status indicator public event UpdateStatusHandler UpdateStatusEvent; diff --git a/Aaru.Core/Sidecar/Files.cs b/Aaru.Core/Sidecar/Files.cs index 68ab3fdb2..f3c5f3b6c 100644 --- a/Aaru.Core/Sidecar/Files.cs +++ b/Aaru.Core/Sidecar/Files.cs @@ -28,41 +28,39 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - -using System; using System.Collections.Generic; using System.Linq; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; -using Schemas; + +namespace Aaru.Core; public sealed partial class Sidecar { - FilesystemContentsType Files(IReadOnlyFilesystem filesystem) + FilesystemContents Files(IReadOnlyFilesystem filesystem) { - var contents = new FilesystemContentsType(); + var contents = new FilesystemContents(); - ErrorNumber ret = filesystem.ReadDir("/", out List dirents); + ErrorNumber ret = filesystem.OpenDir("/", out IDirNode node); - if(ret != ErrorNumber.NoError) - return null; + if(ret != ErrorNumber.NoError) return null; - List directories = new(); - List files = new(); + List directories = []; + List files = []; - foreach(string dirent in dirents) + while(filesystem.ReadDir(node, out string dirent) == ErrorNumber.NoError && dirent is not null) { ret = filesystem.Stat(dirent, out FileEntryInfo stat); if(ret != ErrorNumber.NoError) { - AaruConsole.DebugWriteLine("Create-Sidecar command", "Cannot stat {0}", dirent); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Cannot_stat_0, dirent); continue; } @@ -77,95 +75,48 @@ public sealed partial class Sidecar files.Add(SidecarFile(filesystem, "", dirent, stat)); } - if(files.Count > 0) - contents.File = files.OrderBy(f => f.name).ToArray(); + filesystem.CloseDir(node); - if(directories.Count > 0) - contents.Directory = directories.OrderBy(d => d.name).ToArray(); + if(files.Count > 0) contents.Files = files.OrderBy(f => f.Name).ToList(); + + if(directories.Count > 0) contents.Directories = directories.OrderBy(d => d.Name).ToList(); return contents; } - DirectoryType SidecarDirectory(IReadOnlyFilesystem filesystem, string path, string filename, FileEntryInfo stat) + Directory SidecarDirectory(IReadOnlyFilesystem filesystem, string path, string filename, FileEntryInfo stat) { - var directory = new DirectoryType(); - - if(stat.AccessTimeUtc.HasValue) + var directory = new Directory { - directory.accessTime = stat.AccessTimeUtc.Value; - directory.accessTimeSpecified = true; - } + AccessTime = stat.AccessTimeUtc, + Attributes = (ulong)stat.Attributes, + BackupTime = stat.BackupTimeUtc, + CreationTime = stat.CreationTimeUtc, + DeviceNumber = stat.DeviceNo, + Inode = stat.Inode, + LastWriteTime = stat.LastWriteTimeUtc, + Links = stat.Links, + Name = filename, + PosixGroupId = stat.GID, + PosixMode = stat.Mode, + PosixUserId = stat.UID, + StatusChangeTime = stat.StatusChangeTimeUtc + }; - directory.attributes = (ulong)stat.Attributes; + ErrorNumber ret = filesystem.OpenDir(path + "/" + filename, out IDirNode node); - if(stat.BackupTimeUtc.HasValue) - { - directory.backupTime = stat.BackupTimeUtc.Value; - directory.backupTimeSpecified = true; - } + if(ret != ErrorNumber.NoError) return null; - if(stat.CreationTimeUtc.HasValue) - { - directory.creationTime = stat.CreationTimeUtc.Value; - directory.creationTimeSpecified = true; - } + List directories = []; + List files = []; - if(stat.DeviceNo.HasValue) - { - directory.deviceNumber = stat.DeviceNo.Value; - directory.deviceNumberSpecified = true; - } - - directory.inode = stat.Inode; - - if(stat.LastWriteTimeUtc.HasValue) - { - directory.lastWriteTime = stat.LastWriteTimeUtc.Value; - directory.lastWriteTimeSpecified = true; - } - - directory.links = stat.Links; - directory.name = filename; - - if(stat.GID.HasValue) - { - directory.posixGroupId = stat.GID.Value; - directory.posixGroupIdSpecified = true; - } - - if(stat.Mode.HasValue) - { - directory.posixMode = stat.Mode.Value; - directory.posixModeSpecified = true; - } - - if(stat.UID.HasValue) - { - directory.posixUserId = stat.UID.Value; - directory.posixUserIdSpecified = true; - } - - if(stat.StatusChangeTimeUtc.HasValue) - { - directory.statusChangeTime = stat.StatusChangeTimeUtc.Value; - directory.statusChangeTimeSpecified = true; - } - - ErrorNumber ret = filesystem.ReadDir(path + "/" + filename, out List dirents); - - if(ret != ErrorNumber.NoError) - return null; - - List directories = new(); - List files = new(); - - foreach(string dirent in dirents) + while(filesystem.ReadDir(node, out string dirent) == ErrorNumber.NoError && dirent is not null) { ret = filesystem.Stat(path + "/" + filename + "/" + dirent, out FileEntryInfo entryStat); if(ret != ErrorNumber.NoError) { - AaruConsole.DebugWriteLine("Create-Sidecar command", "Cannot stat {0}", dirent); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Cannot_stat_0, dirent); continue; } @@ -180,146 +131,103 @@ public sealed partial class Sidecar files.Add(SidecarFile(filesystem, path + "/" + filename, dirent, entryStat)); } - if(files.Count > 0) - directory.File = files.OrderBy(f => f.name).ToArray(); + if(files.Count > 0) directory.Files = files.OrderBy(f => f.Name).ToList(); - if(directories.Count > 0) - directory.Directory = directories.OrderBy(d => d.name).ToArray(); + if(directories.Count > 0) directory.Directories = directories.OrderBy(d => d.Name).ToList(); return directory; } - ContentsFileType SidecarFile(IReadOnlyFilesystem filesystem, string path, string filename, FileEntryInfo stat) + ContentsFile SidecarFile(IReadOnlyFilesystem filesystem, string path, string filename, FileEntryInfo stat) { - var file = new ContentsFileType(); var fileChkWorker = new Checksum(); - if(stat.AccessTimeUtc.HasValue) + var file = new ContentsFile { - file.accessTime = stat.AccessTimeUtc.Value; - file.accessTimeSpecified = true; - } + AccessTime = stat.AccessTimeUtc, + Attributes = (ulong)stat.Attributes, + BackupTime = stat.BackupTimeUtc, + CreationTime = stat.CreationTimeUtc, + DeviceNumber = stat.DeviceNo, + Inode = stat.Inode, + LastWriteTime = stat.LastWriteTimeUtc, + Length = (ulong)stat.Length, + Links = stat.Links, + Name = filename, + PosixGroupId = stat.GID, + PosixMode = stat.Mode, + PosixUserId = stat.UID, + StatusChangeTime = stat.StatusChangeTimeUtc + }; - file.attributes = (ulong)stat.Attributes; - - if(stat.BackupTimeUtc.HasValue) - { - file.backupTime = stat.BackupTimeUtc.Value; - file.backupTimeSpecified = true; - } - - if(stat.CreationTimeUtc.HasValue) - { - file.creationTime = stat.CreationTimeUtc.Value; - file.creationTimeSpecified = true; - } - - if(stat.DeviceNo.HasValue) - { - file.deviceNumber = stat.DeviceNo.Value; - file.deviceNumberSpecified = true; - } - - file.inode = stat.Inode; - - if(stat.LastWriteTimeUtc.HasValue) - { - file.lastWriteTime = stat.LastWriteTimeUtc.Value; - file.lastWriteTimeSpecified = true; - } - - file.length = (ulong)stat.Length; - file.links = stat.Links; - file.name = filename; - - if(stat.GID.HasValue) - { - file.posixGroupId = stat.GID.Value; - file.posixGroupIdSpecified = true; - } - - if(stat.Mode.HasValue) - { - file.posixMode = stat.Mode.Value; - file.posixModeSpecified = true; - } - - if(stat.UID.HasValue) - { - file.posixUserId = stat.UID.Value; - file.posixUserIdSpecified = true; - } - - if(stat.StatusChangeTimeUtc.HasValue) - { - file.statusChangeTime = stat.StatusChangeTimeUtc.Value; - file.statusChangeTimeSpecified = true; - } - - byte[] data = Array.Empty(); + byte[] data = null; if(stat.Length > 0) { long position = 0; - UpdateStatus($"Hashing file {path}/{filename}..."); + UpdateStatus(string.Format(Localization.Core.Hashing_file_0_1, path, filename)); InitProgress2(); - while(position < stat.Length - 1048576) + ErrorNumber error = filesystem.OpenFile(path + "/" + filename, out IFileNode fileNode); + + if(error == ErrorNumber.NoError) { - if(_aborted) - return file; - data = new byte[1048576]; - filesystem.Read(path + "/" + filename, position, 1048576, ref data); - UpdateProgress2("Hashing file byte {0} of {1}", position, stat.Length); + while(position < stat.Length - 1048576) + { + if(_aborted) return file; + + // TODO: Better error handling + filesystem.ReadFile(fileNode, 1048576, data, out _); + + UpdateProgress2(Localization.Core.Hashing_file_byte_0_of_1, position, stat.Length); + + fileChkWorker.Update(data); + + position += 1048576; + } + + data = new byte[stat.Length - position]; + filesystem.ReadFile(fileNode, data.Length, data, out _); + + UpdateProgress2(Localization.Core.Hashing_file_byte_0_of_1, position, stat.Length); fileChkWorker.Update(data); - - position += 1048576; + filesystem.CloseFile(fileNode); } - data = new byte[stat.Length - position]; - filesystem.Read(path + "/" + filename, position, stat.Length - position, ref data); - - UpdateProgress2("Hashing file byte {0} of {1}", position, stat.Length); - - fileChkWorker.Update(data); - EndProgress2(); - file.Checksums = fileChkWorker.End().ToArray(); + file.Checksums = fileChkWorker.End(); } else file.Checksums = _emptyChecksums; ErrorNumber ret = filesystem.ListXAttr(path + "/" + filename, out List xattrs); - if(ret != ErrorNumber.NoError) - return file; + if(ret != ErrorNumber.NoError) return file; - List xattrTypes = new(); + List xattrTypes = []; foreach(string xattr in xattrs) { ret = filesystem.GetXattr(path + "/" + filename, xattr, ref data); - if(ret != ErrorNumber.NoError) - continue; + if(ret != ErrorNumber.NoError) continue; var xattrChkWorker = new Checksum(); xattrChkWorker.Update(data); - xattrTypes.Add(new ExtendedAttributeType + xattrTypes.Add(new ExtendedAttribute { - Checksums = xattrChkWorker.End().ToArray(), - length = (ulong)data.Length, - name = xattr + Checksums = xattrChkWorker.End(), + Length = (ulong)data.Length, + Name = xattr }); } - if(xattrTypes.Count > 0) - file.ExtendedAttributes = xattrTypes.OrderBy(x => x.name).ToArray(); + if(xattrTypes.Count > 0) file.ExtendedAttributes = xattrTypes.OrderBy(x => x.Name).ToList(); return file; } diff --git a/Aaru.Core/Sidecar/Helpers.cs b/Aaru.Core/Sidecar/Helpers.cs index a2e97f410..7af330b47 100644 --- a/Aaru.Core/Sidecar/Helpers.cs +++ b/Aaru.Core/Sidecar/Helpers.cs @@ -27,7 +27,7 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Core; diff --git a/Aaru.Core/Sidecar/LinearMedia.cs b/Aaru.Core/Sidecar/LinearMedia.cs index e23bff4a0..aa7e45870 100644 --- a/Aaru.Core/Sidecar/LinearMedia.cs +++ b/Aaru.Core/Sidecar/LinearMedia.cs @@ -27,18 +27,20 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; using System.Collections.Generic; using System.IO; using System.Text; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Interfaces; -using Schemas; + +// ReSharper disable UnusedParameter.Local + +namespace Aaru.Core; public sealed partial class Sidecar { @@ -52,21 +54,20 @@ public sealed partial class Sidecar /// List of image checksums /// Metadata sidecar /// Encoding to be used for filesystem plugins - static void LinearMedia(IByteAddressableImage image, Guid filterId, string imagePath, FileInfo fi, - PluginBase plugins, List imgChecksums, ref CICMMetadataType sidecar, - Encoding encoding) => sidecar.LinearMedia = new[] - { - new LinearMediaType - { - Checksums = imgChecksums.ToArray(), - Image = new ImageType - { - format = image.Format, - offset = 0, - offsetSpecified = true, - Value = Path.GetFileName(imagePath) - }, - Size = image.Info.Sectors - } - }; + static void LinearMedia(IByteAddressableImage image, Guid filterId, string imagePath, FileInfo fi, + PluginRegister plugins, List imgChecksums, + ref Metadata sidecar, Encoding encoding) => sidecar.LinearMedias = + [ + new LinearMedia + { + Checksums = imgChecksums, + Image = new Image + { + Format = image.Format, + Offset = 0, + Value = Path.GetFileName(imagePath) + }, + Size = image.Info.Sectors + } + ]; } \ No newline at end of file diff --git a/Aaru.Core/Sidecar/OpticalDisc.cs b/Aaru.Core/Sidecar/OpticalDisc.cs index 4a9914515..241a714cd 100644 --- a/Aaru.Core/Sidecar/OpticalDisc.cs +++ b/Aaru.Core/Sidecar/OpticalDisc.cs @@ -27,29 +27,28 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Metadata; -using Aaru.CommonTypes.Structs; -using Aaru.Core.Devices.Dumping; using Aaru.Decoders.CD; using Aaru.Decoders.DVD; -using Schemas; using DMI = Aaru.Decoders.Xbox.DMI; -using MediaType = Aaru.CommonTypes.MediaType; +using Dump = Aaru.Core.Devices.Dumping.Dump; +using Partition = Aaru.CommonTypes.Partition; using Session = Aaru.CommonTypes.Structs.Session; -using TrackType = Schemas.TrackType; +using Track = Aaru.CommonTypes.Structs.Track; +using TrackType = Aaru.CommonTypes.Enums.TrackType; + +namespace Aaru.Core; public sealed partial class Sidecar { @@ -62,58 +61,53 @@ public sealed partial class Sidecar /// List of image checksums /// Metadata sidecar /// Encoding to be used for filesystem plugins - void OpticalDisc(IOpticalMediaImage image, Guid filterId, string imagePath, FileInfo fi, PluginBase plugins, - List imgChecksums, ref CICMMetadataType sidecar, Encoding encoding) + void OpticalDisc(IOpticalMediaImage image, Guid filterId, string imagePath, FileInfo fi, PluginRegister plugins, + List imgChecksums, ref Metadata sidecar, Encoding encoding) { - if(_aborted) - return; + if(_aborted) return; - sidecar.OpticalDisc = new[] - { - new OpticalDiscType + sidecar.OpticalDiscs = + [ + new OpticalDisc { - Checksums = imgChecksums.ToArray(), - Image = new ImageType + Checksums = imgChecksums, + Image = new Image { - format = image.Format, - offset = 0, - offsetSpecified = true, - Value = Path.GetFileName(imagePath) + Format = image.Format, + Offset = 0, + Value = Path.GetFileName(imagePath) }, Size = (ulong)fi.Length, - Sequence = new SequenceType + Sequence = new Sequence { - MediaTitle = image.Info.MediaTitle + Title = image.Info.MediaTitle } } - }; + ]; - if(image.Info.MediaSequence != 0 && - image.Info.LastMediaSequence != 0) + if(image.Info.MediaSequence != 0 && image.Info.LastMediaSequence != 0) { - sidecar.OpticalDisc[0].Sequence.MediaSequence = (uint)image.Info.MediaSequence; - sidecar.OpticalDisc[0].Sequence.TotalMedia = (uint)image.Info.LastMediaSequence; + sidecar.OpticalDiscs[0].Sequence.MediaSequence = (uint)image.Info.MediaSequence; + sidecar.OpticalDiscs[0].Sequence.TotalMedia = (uint)image.Info.LastMediaSequence; } else { - sidecar.OpticalDisc[0].Sequence.MediaSequence = 1; - sidecar.OpticalDisc[0].Sequence.TotalMedia = 1; + sidecar.OpticalDiscs[0].Sequence.MediaSequence = 1; + sidecar.OpticalDiscs[0].Sequence.TotalMedia = 1; } MediaType dskType = image.Info.MediaType; ErrorNumber errno; - UpdateStatus("Hashing media tags..."); + UpdateStatus(Localization.Core.Hashing_media_tags); foreach(MediaTagType tagType in image.Info.ReadableMediaTags) { - if(_aborted) - return; + if(_aborted) return; errno = image.ReadMediaTag(tagType, out byte[] tag); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; Dump.AddMediaTagToSidecar(imagePath, tagType, tag, ref sidecar); @@ -123,10 +117,12 @@ public sealed partial class Sidecar ATIP.CDATIP atip = ATIP.Decode(tag); if(atip != null) + { if(atip.DDCD) dskType = atip.DiscType ? MediaType.DDCDRW : MediaType.DDCDR; else dskType = atip.DiscType ? MediaType.CDRW : MediaType.CDR; + } break; case MediaTagType.DVD_DMI: @@ -134,7 +130,7 @@ public sealed partial class Sidecar { dskType = MediaType.XGD; - sidecar.OpticalDisc[0].Dimensions = new DimensionsType + sidecar.OpticalDiscs[0].Dimensions = new Dimensions { Diameter = 120, Thickness = 1.2 @@ -144,7 +140,7 @@ public sealed partial class Sidecar { dskType = MediaType.XGD2; - sidecar.OpticalDisc[0].Dimensions = new DimensionsType + sidecar.OpticalDiscs[0].Dimensions = new Dimensions { Diameter = 120, Thickness = 1.2 @@ -156,6 +152,7 @@ public sealed partial class Sidecar PFI.PhysicalFormatInformation? pfi = PFI.Decode(tag, dskType); if(pfi.HasValue) + { if(dskType != MediaType.XGD && dskType != MediaType.XGD2 && dskType != MediaType.XGD3 && @@ -163,105 +160,58 @@ public sealed partial class Sidecar dskType != MediaType.PS3DVD && dskType != MediaType.Nuon) { - switch(pfi.Value.DiskCategory) - { - case DiskCategory.DVDPR: - dskType = MediaType.DVDPR; + dskType = pfi.Value.DiskCategory switch + { + DiskCategory.DVDPR => MediaType.DVDPR, + DiskCategory.DVDPRDL => MediaType.DVDPRDL, + DiskCategory.DVDPRW => MediaType.DVDPRW, + DiskCategory.DVDPRWDL => MediaType.DVDPRWDL, + DiskCategory.DVDR => MediaType.DVDR, + DiskCategory.DVDRAM => MediaType.DVDRAM, + DiskCategory.DVDROM => MediaType.DVDROM, + DiskCategory.DVDRW => MediaType.DVDRW, + DiskCategory.HDDVDR => MediaType.HDDVDR, + DiskCategory.HDDVDRAM => MediaType.HDDVDRAM, + DiskCategory.HDDVDROM => MediaType.HDDVDROM, + DiskCategory.HDDVDRW => MediaType.HDDVDRW, + DiskCategory.Nintendo => MediaType.GOD, + DiskCategory.UMD => MediaType.UMD, + _ => dskType + }; - break; - case DiskCategory.DVDPRDL: - dskType = MediaType.DVDPRDL; + if(dskType == MediaType.DVDR && pfi.Value.PartVersion >= 6) dskType = MediaType.DVDRDL; - break; - case DiskCategory.DVDPRW: - dskType = MediaType.DVDPRW; + if(dskType == MediaType.DVDRW && pfi.Value.PartVersion >= 15) dskType = MediaType.DVDRWDL; - break; - case DiskCategory.DVDPRWDL: - dskType = MediaType.DVDPRWDL; - - break; - case DiskCategory.DVDR: - dskType = MediaType.DVDR; - - break; - case DiskCategory.DVDRAM: - dskType = MediaType.DVDRAM; - - break; - case DiskCategory.DVDROM: - dskType = MediaType.DVDROM; - - break; - case DiskCategory.DVDRW: - dskType = MediaType.DVDRW; - - break; - case DiskCategory.HDDVDR: - dskType = MediaType.HDDVDR; - - break; - case DiskCategory.HDDVDRAM: - dskType = MediaType.HDDVDRAM; - - break; - case DiskCategory.HDDVDROM: - dskType = MediaType.HDDVDROM; - - break; - case DiskCategory.HDDVDRW: - dskType = MediaType.HDDVDRW; - - break; - case DiskCategory.Nintendo: - dskType = MediaType.GOD; - - break; - case DiskCategory.UMD: - dskType = MediaType.UMD; - - break; - } - - if(dskType == MediaType.DVDR && - pfi.Value.PartVersion >= 6) - dskType = MediaType.DVDRDL; - - if(dskType == MediaType.DVDRW && - pfi.Value.PartVersion >= 15) - dskType = MediaType.DVDRWDL; - - if(dskType == MediaType.GOD && - pfi.Value.DiscSize == DVDSize.OneTwenty) + if(dskType == MediaType.GOD && pfi.Value.DiscSize == DVDSize.OneTwenty) dskType = MediaType.WOD; - sidecar.OpticalDisc[0].Dimensions = new DimensionsType(); + sidecar.OpticalDiscs[0].Dimensions = new Dimensions(); if(dskType == MediaType.UMD) { - sidecar.OpticalDisc[0].Dimensions.Height = 64; - sidecar.OpticalDisc[0].Dimensions.HeightSpecified = true; - sidecar.OpticalDisc[0].Dimensions.Width = 63; - sidecar.OpticalDisc[0].Dimensions.WidthSpecified = true; - sidecar.OpticalDisc[0].Dimensions.Thickness = 4; + sidecar.OpticalDiscs[0].Dimensions.Height = 64; + sidecar.OpticalDiscs[0].Dimensions.Width = 63; + sidecar.OpticalDiscs[0].Dimensions.Thickness = 4; } else + { switch(pfi.Value.DiscSize) { case DVDSize.Eighty: - sidecar.OpticalDisc[0].Dimensions.Diameter = 80; - sidecar.OpticalDisc[0].Dimensions.DiameterSpecified = true; - sidecar.OpticalDisc[0].Dimensions.Thickness = 1.2; + sidecar.OpticalDiscs[0].Dimensions.Diameter = 80; + sidecar.OpticalDiscs[0].Dimensions.Thickness = 1.2; break; case DVDSize.OneTwenty: - sidecar.OpticalDisc[0].Dimensions.Diameter = 120; - sidecar.OpticalDisc[0].Dimensions.DiameterSpecified = true; - sidecar.OpticalDisc[0].Dimensions.Thickness = 1.2; + sidecar.OpticalDiscs[0].Dimensions.Diameter = 120; + sidecar.OpticalDiscs[0].Dimensions.Thickness = 1.2; break; } + } } + } break; } @@ -270,37 +220,35 @@ public sealed partial class Sidecar try { List sessions = image.Sessions; - sidecar.OpticalDisc[0].Sessions = (uint)(sessions?.Count ?? 1); + sidecar.OpticalDiscs[0].Sessions = (uint)(sessions?.Count ?? 1); } catch { - sidecar.OpticalDisc[0].Sessions = 1; + sidecar.OpticalDiscs[0].Sessions = 1; } - List tracks = image.Tracks; - List trksLst = null; + List tracks = image.Tracks; + List trksLst = null; if(tracks != null) { - sidecar.OpticalDisc[0].Tracks = new uint[1]; - sidecar.OpticalDisc[0].Tracks[0] = (uint)tracks.Count; - trksLst = new List(); + sidecar.OpticalDiscs[0].Tracks = new uint[1]; + sidecar.OpticalDiscs[0].Tracks[0] = (uint)tracks.Count; + trksLst = []; } - if(sidecar.OpticalDisc[0].Dimensions == null && - image.Info.MediaType != MediaType.Unknown) - sidecar.OpticalDisc[0].Dimensions = Dimensions.DimensionsFromMediaType(image.Info.MediaType); + if(sidecar.OpticalDiscs[0].Dimensions == null && image.Info.MediaType != MediaType.Unknown) + sidecar.OpticalDiscs[0].Dimensions = Dimensions.FromMediaType(image.Info.MediaType); - if(_aborted) - return; + if(_aborted) return; InitProgress(); - UpdateStatus("Checking filesystems"); + UpdateStatus(Localization.Core.Checking_filesystems); List partitions = Partitions.GetAll(image); Partitions.AddSchemesToStats(partitions); - UpdateStatus("Hashing tracks..."); + UpdateStatus(Localization.Core.Hashing_tracks); foreach(Track trk in tracks) { @@ -311,107 +259,67 @@ public sealed partial class Sidecar return; } - var xmlTrk = new TrackType(); + var xmlTrk = new CommonTypes.AaruMetadata.Track(); - switch(trk.Type) + xmlTrk.Type = trk.Type switch + { + TrackType.Audio => CommonTypes.AaruMetadata.TrackType.Audio, + TrackType.CdMode2Form2 => CommonTypes.AaruMetadata.TrackType.Mode2Form2, + TrackType.CdMode2Formless => CommonTypes.AaruMetadata.TrackType.Mode2, + TrackType.CdMode2Form1 => CommonTypes.AaruMetadata.TrackType.Mode2Form1, + TrackType.CdMode1 => CommonTypes.AaruMetadata.TrackType.Mode1, + TrackType.Data => sidecar.OpticalDiscs[0].DiscType switch + { + "BD" => CommonTypes.AaruMetadata.TrackType.Bluray, + "DDCD" => CommonTypes.AaruMetadata.TrackType.Ddcd, + "DVD" => CommonTypes.AaruMetadata.TrackType.Dvd, + "HD DVD" => CommonTypes.AaruMetadata.TrackType.HdDvd, + _ => CommonTypes.AaruMetadata.TrackType.Mode1 + }, + _ => xmlTrk.Type + }; + + xmlTrk.Sequence = new TrackSequence { - case CommonTypes.Enums.TrackType.Audio: - xmlTrk.TrackType1 = TrackTypeTrackType.audio; - - break; - case CommonTypes.Enums.TrackType.CdMode2Form2: - xmlTrk.TrackType1 = TrackTypeTrackType.m2f2; - - break; - case CommonTypes.Enums.TrackType.CdMode2Formless: - xmlTrk.TrackType1 = TrackTypeTrackType.mode2; - - break; - case CommonTypes.Enums.TrackType.CdMode2Form1: - xmlTrk.TrackType1 = TrackTypeTrackType.m2f1; - - break; - case CommonTypes.Enums.TrackType.CdMode1: - xmlTrk.TrackType1 = TrackTypeTrackType.mode1; - - break; - case CommonTypes.Enums.TrackType.Data: - switch(sidecar.OpticalDisc[0].DiscType) - { - case "BD": - xmlTrk.TrackType1 = TrackTypeTrackType.bluray; - - break; - case "DDCD": - xmlTrk.TrackType1 = TrackTypeTrackType.ddcd; - - break; - case "DVD": - xmlTrk.TrackType1 = TrackTypeTrackType.dvd; - - break; - case "HD DVD": - xmlTrk.TrackType1 = TrackTypeTrackType.hddvd; - - break; - default: - xmlTrk.TrackType1 = TrackTypeTrackType.mode1; - - break; - } - - break; - } - - xmlTrk.Sequence = new TrackSequenceType - { - Session = trk.Session, - TrackNumber = trk.Sequence + Session = trk.Session, + Number = trk.Sequence }; xmlTrk.StartSector = trk.StartSector; xmlTrk.EndSector = trk.EndSector; - int idx0; + if(trk.Indexes?.TryGetValue(0, out int idx0) == true && idx0 >= 0) xmlTrk.StartSector = (ulong)idx0; - if(trk.Indexes?.TryGetValue(0, out idx0) == true && - idx0 >= 0) - xmlTrk.StartSector = (ulong)idx0; - - switch(sidecar.OpticalDisc[0].DiscType) + switch(sidecar.OpticalDiscs[0].DiscType) { case "CD": case "GD": - xmlTrk.StartMSF = LbaToMsf((long)xmlTrk.StartSector); - xmlTrk.EndMSF = LbaToMsf((long)xmlTrk.EndSector); + xmlTrk.StartMsf = LbaToMsf((long)xmlTrk.StartSector); + xmlTrk.EndMsf = LbaToMsf((long)xmlTrk.EndSector); break; case "DDCD": - xmlTrk.StartMSF = DdcdLbaToMsf((long)xmlTrk.StartSector); - xmlTrk.EndMSF = DdcdLbaToMsf((long)xmlTrk.EndSector); + xmlTrk.StartMsf = DdcdLbaToMsf((long)xmlTrk.StartSector); + xmlTrk.EndMsf = DdcdLbaToMsf((long)xmlTrk.EndSector); break; } - xmlTrk.Image = new ImageType + xmlTrk.Image = new Image { Value = Path.GetFileName(trk.File), - format = trk.FileType + Format = trk.FileType }; - if(trk.FileOffset > 0) - { - xmlTrk.Image.offset = trk.FileOffset; - xmlTrk.Image.offsetSpecified = true; - } + if(trk.FileOffset > 0) xmlTrk.Image.Offset = trk.FileOffset; xmlTrk.Size = (xmlTrk.EndSector - xmlTrk.StartSector + 1) * (ulong)trk.RawBytesPerSector; xmlTrk.BytesPerSector = (uint)trk.BytesPerSector; - uint sectorsToRead = 512; - ulong sectors = xmlTrk.EndSector - xmlTrk.StartSector + 1; - ulong doneSectors = 0; + const uint sectorsToRead = 512; + ulong sectors = xmlTrk.EndSector - xmlTrk.StartSector + 1; + ulong doneSectors = 0; // If there is only one track, and it's the same as the image file (e.g. ".iso" files), don't re-checksum. if(image.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000") && @@ -421,10 +329,10 @@ public sealed partial class Sidecar // ...or AppleDouble filterId == new Guid("1b2165ee-c9df-4b21-bbbb-9e5892b2df4d"))) - xmlTrk.Checksums = sidecar.OpticalDisc[0].Checksums; + xmlTrk.Checksums = sidecar.OpticalDiscs[0].Checksums; else { - UpdateProgress("Track {0} of {1}", trk.Sequence, tracks.Count); + UpdateProgress(Localization.Core.Track_0_of_1, trk.Sequence, tracks.Count); // For fast debugging, skip checksum //goto skipChecksum; @@ -447,15 +355,15 @@ public sealed partial class Sidecar if(sectors - doneSectors >= sectorsToRead) { - errno = image.ReadSectorsLong(doneSectors, sectorsToRead, xmlTrk.Sequence.TrackNumber, - out sector); + errno = image.ReadSectorsLong(doneSectors, sectorsToRead, xmlTrk.Sequence.Number, out sector); - UpdateProgress2("Hashing sector {0} of {1}", (long)doneSectors, + UpdateProgress2(Localization.Core.Hashing_sector_0_of_1, + (long)doneSectors, (long)(trk.EndSector - trk.StartSector + 1)); if(errno != ErrorNumber.NoError) { - UpdateStatus($"Error {errno} reading sector {doneSectors}"); + UpdateStatus(string.Format(Localization.Core.Error_0_reading_sector_1, errno, doneSectors)); EndProgress2(); return; @@ -465,15 +373,18 @@ public sealed partial class Sidecar } else { - errno = image.ReadSectorsLong(doneSectors, (uint)(sectors - doneSectors), - xmlTrk.Sequence.TrackNumber, out sector); + errno = image.ReadSectorsLong(doneSectors, + (uint)(sectors - doneSectors), + xmlTrk.Sequence.Number, + out sector); - UpdateProgress2("Hashing sector {0} of {1}", (long)doneSectors, + UpdateProgress2(Localization.Core.Hashing_sector_0_of_1, + (long)doneSectors, (long)(trk.EndSector - trk.StartSector + 1)); if(errno != ErrorNumber.NoError) { - UpdateStatus($"Error {errno} reading sector {doneSectors}"); + UpdateStatus(string.Format(Localization.Core.Error_0_reading_sector_1, errno, doneSectors)); EndProgress2(); return; @@ -485,18 +396,16 @@ public sealed partial class Sidecar trkChkWorker.Update(sector); } - List trkChecksums = trkChkWorker.End(); - - xmlTrk.Checksums = trkChecksums.ToArray(); + xmlTrk.Checksums = trkChkWorker.End(); EndProgress2(); } if(trk.SubchannelType != TrackSubchannelType.None) { - xmlTrk.SubChannel = new SubChannelType + xmlTrk.SubChannel = new SubChannel { - Image = new ImageType + Image = new Image { Value = trk.SubchannelFile }, @@ -505,30 +414,18 @@ public sealed partial class Sidecar Size = (xmlTrk.EndSector - xmlTrk.StartSector + 1) * 96 }; - switch(trk.SubchannelType) - { - case TrackSubchannelType.Packed: - case TrackSubchannelType.PackedInterleaved: - xmlTrk.SubChannel.Image.format = "rw"; + xmlTrk.SubChannel.Image.Format = trk.SubchannelType switch + { + TrackSubchannelType.Packed + or TrackSubchannelType.PackedInterleaved => "rw", + TrackSubchannelType.Raw + or TrackSubchannelType.RawInterleaved => "rw_raw", + TrackSubchannelType.Q16 + or TrackSubchannelType.Q16Interleaved => "q16", + _ => xmlTrk.SubChannel.Image.Format + }; - break; - case TrackSubchannelType.Raw: - case TrackSubchannelType.RawInterleaved: - xmlTrk.SubChannel.Image.format = "rw_raw"; - - break; - case TrackSubchannelType.Q16: - case TrackSubchannelType.Q16Interleaved: - xmlTrk.SubChannel.Image.format = "q16"; - - break; - } - - if(trk.FileOffset > 0) - { - xmlTrk.SubChannel.Image.offset = trk.SubchannelOffset; - xmlTrk.SubChannel.Image.offsetSpecified = true; - } + if(trk.FileOffset > 0) xmlTrk.SubChannel.Image.Offset = trk.SubchannelOffset; var subChkWorker = new Checksum(); @@ -551,15 +448,19 @@ public sealed partial class Sidecar if(sectors - doneSectors >= sectorsToRead) { - errno = image.ReadSectorsTag(doneSectors, sectorsToRead, xmlTrk.Sequence.TrackNumber, - SectorTagType.CdSectorSubchannel, out sector); + errno = image.ReadSectorsTag(doneSectors, + sectorsToRead, + xmlTrk.Sequence.Number, + SectorTagType.CdSectorSubchannel, + out sector); - UpdateProgress2("Hashing subchannel sector {0} of {1}", (long)doneSectors, + UpdateProgress2(Localization.Core.Hashing_subchannel_sector_0_of_1, + (long)doneSectors, (long)(trk.EndSector - trk.StartSector + 1)); if(errno != ErrorNumber.NoError) { - UpdateStatus($"Error {errno} reading sector {doneSectors}"); + UpdateStatus(string.Format(Localization.Core.Error_0_reading_sector_1, errno, doneSectors)); EndProgress2(); return; @@ -569,16 +470,19 @@ public sealed partial class Sidecar } else { - errno = image.ReadSectorsTag(doneSectors, (uint)(sectors - doneSectors), - xmlTrk.Sequence.TrackNumber, SectorTagType.CdSectorSubchannel, + errno = image.ReadSectorsTag(doneSectors, + (uint)(sectors - doneSectors), + xmlTrk.Sequence.Number, + SectorTagType.CdSectorSubchannel, out sector); - UpdateProgress2("Hashing subchannel sector {0} of {1}", (long)doneSectors, + UpdateProgress2(Localization.Core.Hashing_subchannel_sector_0_of_1, + (long)doneSectors, (long)(trk.EndSector - trk.StartSector + 1)); if(errno != ErrorNumber.NoError) { - UpdateStatus($"Error {errno} reading sector {doneSectors}"); + UpdateStatus(string.Format(Localization.Core.Error_0_reading_sector_1, errno, doneSectors)); EndProgress2(); return; @@ -590,9 +494,7 @@ public sealed partial class Sidecar subChkWorker.Update(sector); } - List subChecksums = subChkWorker.End(); - - xmlTrk.SubChannel.Checksums = subChecksums.ToArray(); + xmlTrk.SubChannel.Checksums = subChkWorker.End(); EndProgress2(); } @@ -602,27 +504,26 @@ public sealed partial class Sidecar var trkPartitions = partitions.Where(p => p.Start >= trk.StartSector && p.End <= trk.EndSector).ToList(); - xmlTrk.FileSystemInformation = new PartitionType[1]; + xmlTrk.FileSystemInformation = []; if(trkPartitions.Count > 0) { - xmlTrk.FileSystemInformation = new PartitionType[trkPartitions.Count]; - - for(var i = 0; i < trkPartitions.Count; i++) + foreach(Partition partition in trkPartitions) { - xmlTrk.FileSystemInformation[i] = new PartitionType + var metadataPartition = new CommonTypes.AaruMetadata.Partition { - Description = trkPartitions[i].Description, - EndSector = trkPartitions[i].End, - Name = trkPartitions[i].Name, - Sequence = (uint)trkPartitions[i].Sequence, - StartSector = trkPartitions[i].Start, - Type = trkPartitions[i].Type + Description = partition.Description, + EndSector = partition.End, + Name = partition.Name, + Sequence = (uint)partition.Sequence, + StartSector = partition.Start, + Type = partition.Type }; - List lstFs = new(); + List lstFs = []; - foreach(IFilesystem plugin in plugins.PluginsList.Values) + foreach(IFilesystem fs in plugins.Filesystems.Values) + { try { if(_aborted) @@ -632,64 +533,57 @@ public sealed partial class Sidecar return; } - if(!plugin.Identify(image, trkPartitions[i])) - continue; + if(fs is null) continue; - plugin.GetInformation(image, trkPartitions[i], out _, encoding); - lstFs.Add(plugin.XmlFsType); - Statistics.AddFilesystem(plugin.XmlFsType.Type); + if(!fs.Identify(image, partition)) continue; - switch(plugin.XmlFsType.Type) - { - case "Opera": - dskType = MediaType.ThreeDO; + fs.GetInformation(image, partition, encoding, out _, out FileSystem fsMetadata); + lstFs.Add(fsMetadata); + Statistics.AddFilesystem(fsMetadata.Type); - break; - case "PC Engine filesystem": - dskType = MediaType.SuperCDROM2; - - break; - case "Nintendo Wii filesystem": - dskType = MediaType.WOD; - - break; - case "Nintendo Gamecube filesystem": - dskType = MediaType.GOD; - - break; - } + dskType = fsMetadata.Type switch + { + "Opera" => MediaType.ThreeDO, + "PC Engine filesystem" => MediaType.SuperCDROM2, + "Nintendo Wii filesystem" => MediaType.WOD, + "Nintendo Gamecube filesystem" => MediaType.GOD, + _ => dskType + }; } - #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch - #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body { - //AaruConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name); + //AaruConsole.DebugWriteLine(MODULE_NAME, "Plugin {0} crashed", _plugin.Name); } + } - if(lstFs.Count > 0) - xmlTrk.FileSystemInformation[i].FileSystems = lstFs.ToArray(); + if(lstFs.Count > 0) metadataPartition.FileSystems = lstFs; + + xmlTrk.FileSystemInformation.Add(metadataPartition); } } else { - xmlTrk.FileSystemInformation[0] = new PartitionType + var metadataPartition = new CommonTypes.AaruMetadata.Partition { EndSector = xmlTrk.EndSector, StartSector = xmlTrk.StartSector }; - List lstFs = new(); + List lstFs = []; var xmlPart = new Partition { Start = xmlTrk.StartSector, Length = xmlTrk.EndSector - xmlTrk.StartSector + 1, - Type = xmlTrk.TrackType1.ToString(), + Type = xmlTrk.Type.ToString(), Size = xmlTrk.Size, - Sequence = xmlTrk.Sequence.TrackNumber + Sequence = xmlTrk.Sequence.Number }; - foreach(IFilesystem plugin in plugins.PluginsList.Values) + foreach(IFilesystem fs in plugins.Filesystems.Values) + { try { if(_aborted) @@ -699,48 +593,39 @@ public sealed partial class Sidecar return; } - if(!plugin.Identify(image, xmlPart)) - continue; + if(fs is null) continue; - plugin.GetInformation(image, xmlPart, out _, encoding); - lstFs.Add(plugin.XmlFsType); - Statistics.AddFilesystem(plugin.XmlFsType.Type); + if(!fs.Identify(image, xmlPart)) continue; - switch(plugin.XmlFsType.Type) - { - case "Opera": - dskType = MediaType.ThreeDO; + fs.GetInformation(image, xmlPart, encoding, out _, out FileSystem fsMetadata); + lstFs.Add(fsMetadata); + Statistics.AddFilesystem(fsMetadata.Type); - break; - case "PC Engine filesystem": - dskType = MediaType.SuperCDROM2; - - break; - case "Nintendo Wii filesystem": - dskType = MediaType.WOD; - - break; - case "Nintendo Gamecube filesystem": - dskType = MediaType.GOD; - - break; - } + dskType = fsMetadata.Type switch + { + "Opera" => MediaType.ThreeDO, + "PC Engine filesystem" => MediaType.SuperCDROM2, + "Nintendo Wii filesystem" => MediaType.WOD, + "Nintendo Gamecube filesystem" => MediaType.GOD, + _ => dskType + }; } - #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch - #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body +#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body { - //AaruConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name); + //AaruConsole.DebugWriteLine(MODULE_NAME, "Plugin {0} crashed", _plugin.Name); } + } - if(lstFs.Count > 0) - xmlTrk.FileSystemInformation[0].FileSystems = lstFs.ToArray(); + if(lstFs.Count > 0) metadataPartition.FileSystems = lstFs; + + xmlTrk.FileSystemInformation.Add(metadataPartition); } errno = image.ReadSectorTag(trk.Sequence, SectorTagType.CdTrackIsrc, out byte[] isrcData); - if(errno == ErrorNumber.NoError) - xmlTrk.ISRC = Encoding.UTF8.GetString(isrcData); + if(errno == ErrorNumber.NoError) xmlTrk.ISRC = Encoding.UTF8.GetString(isrcData); errno = image.ReadSectorTag(trk.Sequence, SectorTagType.CdTrackFlags, out byte[] flagsData); @@ -748,7 +633,7 @@ public sealed partial class Sidecar { var trackFlags = (CdFlags)flagsData[0]; - xmlTrk.Flags = new TrackFlagsType + xmlTrk.Flags = new TrackFlags { PreEmphasis = trackFlags.HasFlag(CdFlags.PreEmphasis), CopyPermitted = trackFlags.HasFlag(CdFlags.CopyPermitted), @@ -758,63 +643,69 @@ public sealed partial class Sidecar } if(trk.Indexes?.Count > 0) - xmlTrk.Indexes = trk.Indexes?.OrderBy(i => i.Key).Select(i => new TrackIndexType - { - index = i.Key, - Value = i.Value - }).ToArray(); + { + xmlTrk.Indexes = trk.Indexes?.OrderBy(i => i.Key) + .Select(i => new TrackIndex + { + Index = i.Key, + Value = i.Value + }) + .ToList(); + } trksLst.Add(xmlTrk); } EndProgress(); - if(trksLst != null) - sidecar.OpticalDisc[0].Track = trksLst.ToArray(); + if(trksLst != null) sidecar.OpticalDiscs[0].Track = trksLst; // All XGD3 all have the same number of blocks - if(dskType == MediaType.XGD2 && - sidecar.OpticalDisc[0].Track.Length == 1) + if(dskType == MediaType.XGD2 && sidecar.OpticalDiscs[0].Track.Count == 1) { - ulong blocks = sidecar.OpticalDisc[0].Track[0].EndSector - sidecar.OpticalDisc[0].Track[0].StartSector + 1; + ulong blocks = sidecar.OpticalDiscs[0].Track[0].EndSector - + sidecar.OpticalDiscs[0].Track[0].StartSector + + 1; if(blocks is 25063 or 4229664 or 4246304) // Wxripper unlock dskType = MediaType.XGD3; } (string type, string subType) discType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType); - sidecar.OpticalDisc[0].DiscType = discType.type; - sidecar.OpticalDisc[0].DiscSubType = discType.subType; + sidecar.OpticalDiscs[0].DiscType = discType.type; + sidecar.OpticalDiscs[0].DiscSubType = discType.subType; Statistics.AddMedia(dskType, false); if(image.DumpHardware != null) - sidecar.OpticalDisc[0].DumpHardwareArray = image.DumpHardware.ToArray(); + sidecar.OpticalDiscs[0].DumpHardware = image.DumpHardware; else if(!string.IsNullOrEmpty(image.Info.DriveManufacturer) || !string.IsNullOrEmpty(image.Info.DriveModel) || !string.IsNullOrEmpty(image.Info.DriveFirmwareRevision) || !string.IsNullOrEmpty(image.Info.DriveSerialNumber)) - sidecar.OpticalDisc[0].DumpHardwareArray = new[] - { - new DumpHardwareType + { + sidecar.OpticalDiscs[0].DumpHardware = + [ + new DumpHardware { - Extents = new[] - { - new ExtentType + Extents = + [ + new Extent { Start = 0, End = image.Info.Sectors } - }, + ], Manufacturer = image.Info.DriveManufacturer, Model = image.Info.DriveModel, Firmware = image.Info.DriveFirmwareRevision, Serial = image.Info.DriveSerialNumber, - Software = new SoftwareType + Software = new Software { Name = image.Info.Application, Version = image.Info.ApplicationVersion } } - }; + ]; + } } } \ No newline at end of file diff --git a/Aaru.Core/Sidecar/Sidecar.cs b/Aaru.Core/Sidecar/Sidecar.cs index 75f2fecca..59795082e 100644 --- a/Aaru.Core/Sidecar/Sidecar.cs +++ b/Aaru.Core/Sidecar/Sidecar.cs @@ -27,45 +27,47 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; using System.Collections.Generic; using System.IO; using System.Text; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Console; -using Schemas; +using Aaru.Helpers; + +namespace Aaru.Core; public sealed partial class Sidecar { - readonly ChecksumType[] _emptyChecksums; - readonly Encoding _encoding; - readonly FileInfo _fi; - readonly Guid _filterId; - readonly IBaseImage _image; - readonly string _imagePath; - readonly Checksum _imgChkWorker; - readonly PluginBase _plugins; - bool _aborted; - FileStream _fs; - CICMMetadataType _sidecar; + const string MODULE_NAME = "Sidecar creation"; + readonly List _emptyChecksums; + readonly Encoding _encoding; + readonly FileInfo _fi; + readonly Guid _filterId; + readonly IBaseImage _image; + readonly string _imagePath; + readonly Checksum _imgChkWorker; + readonly PluginRegister _plugins; + bool _aborted; + FileStream _fs; + Metadata _sidecar; /// Initializes a new instance of this class public Sidecar() { - _plugins = GetPluginBase.Instance; + _plugins = PluginRegister.Singleton; _imgChkWorker = new Checksum(); _aborted = false; var emptyChkWorker = new Checksum(); - emptyChkWorker.Update(Array.Empty()); - _emptyChecksums = emptyChkWorker.End().ToArray(); + emptyChkWorker.Update([]); + _emptyChecksums = emptyChkWorker.End(); } /// Image @@ -78,8 +80,8 @@ public sealed partial class Sidecar _imagePath = imagePath; _filterId = filterId; _encoding = encoding; - _sidecar = image.CicmMetadata ?? new CICMMetadataType(); - _plugins = GetPluginBase.Instance; + _sidecar = image.AaruMetadata ?? new Metadata(); + _plugins = PluginRegister.Singleton; _fi = new FileInfo(imagePath); _fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read); _imgChkWorker = new Checksum(); @@ -88,25 +90,24 @@ public sealed partial class Sidecar /// Implements creating a metadata sidecar /// The metadata sidecar - public CICMMetadataType Create() + public Metadata Create() { // For fast debugging, skip checksum //goto skipImageChecksum; byte[] data; long position = 0; - UpdateStatus("Hashing image file..."); + UpdateStatus(Localization.Core.Hashing_image_file); InitProgress(); while(position < _fi.Length - 1048576) { - if(_aborted) - return _sidecar; + if(_aborted) return _sidecar; data = new byte[1048576]; - _fs.Read(data, 0, 1048576); + _fs.EnsureRead(data, 0, 1048576); - UpdateProgress("Hashing image file byte {0} of {1}", position, _fi.Length); + UpdateProgress(Localization.Core.Hashing_image_file_byte_0_of_1, position, _fi.Length); _imgChkWorker.Update(data); @@ -114,9 +115,9 @@ public sealed partial class Sidecar } data = new byte[_fi.Length - position]; - _fs.Read(data, 0, (int)(_fi.Length - position)); + _fs.EnsureRead(data, 0, (int)(_fi.Length - position)); - UpdateProgress("Hashing image file byte {0} of {1}", position, _fi.Length); + UpdateProgress(Localization.Core.Hashing_image_file_byte_0_of_1, position, _fi.Length); _imgChkWorker.Update(data); @@ -126,57 +127,67 @@ public sealed partial class Sidecar EndProgress(); _fs.Close(); - List imgChecksums = _imgChkWorker.End(); + List imgChecksums = _imgChkWorker.End(); - _sidecar.OpticalDisc = null; - _sidecar.BlockMedia = null; - _sidecar.AudioMedia = null; - _sidecar.LinearMedia = null; + if(_aborted) return _sidecar; - if(_aborted) - return _sidecar; - - switch(_image.Info.XmlMediaType) + switch(_image.Info.MetadataMediaType) { - case XmlMediaType.OpticalDisc: + case MetadataMediaType.OpticalDisc: if(_image is IOpticalMediaImage opticalImage) - OpticalDisc(opticalImage, _filterId, _imagePath, _fi, _plugins, imgChecksums, ref _sidecar, + { + OpticalDisc(opticalImage, + _filterId, + _imagePath, + _fi, + _plugins, + imgChecksums, + ref _sidecar, _encoding); + } else { - AaruConsole. - ErrorWriteLine("The specified image says it contains an optical media but at the same time says it does not support them."); + AaruConsole.ErrorWriteLine(Localization.Core + .The_specified_image_says_it_contains_an_optical_media_but_at_the_same_time_says_it_does_not_support_them); - AaruConsole.ErrorWriteLine("Please open an issue at Github."); + AaruConsole.ErrorWriteLine(Localization.Core.Please_open_an_issue_at_Github); } break; - case XmlMediaType.BlockMedia: + case MetadataMediaType.BlockMedia: if(_image is IMediaImage blockImage) BlockMedia(blockImage, _filterId, _imagePath, _fi, _plugins, imgChecksums, ref _sidecar, _encoding); else { - AaruConsole. - ErrorWriteLine("The specified image says it contains a block addressable media but at the same time says it does not support them."); + AaruConsole.ErrorWriteLine(Localization.Core + .The_specified_image_says_it_contains_a_block_addressable_media_but_at_the_same_time_says_it_does_not_support_them); - AaruConsole.ErrorWriteLine("Please open an issue at Github."); + AaruConsole.ErrorWriteLine(Localization.Core.Please_open_an_issue_at_Github); } break; - case XmlMediaType.LinearMedia: + case MetadataMediaType.LinearMedia: if(_image is IByteAddressableImage byteAddressableImage) - LinearMedia(byteAddressableImage, _filterId, _imagePath, _fi, _plugins, imgChecksums, ref _sidecar, + { + LinearMedia(byteAddressableImage, + _filterId, + _imagePath, + _fi, + _plugins, + imgChecksums, + ref _sidecar, _encoding); + } else { - AaruConsole. - ErrorWriteLine("The specified image says it contains a byte addressable media but at the same time says it does not support them."); + AaruConsole.ErrorWriteLine(Localization.Core + .The_specified_image_says_it_contains_a_byte_addressable_media_but_at_the_same_time_says_it_does_not_support_them); - AaruConsole.ErrorWriteLine("Please open an issue at Github."); + AaruConsole.ErrorWriteLine(Localization.Core.Please_open_an_issue_at_Github); } break; - case XmlMediaType.AudioMedia: + case MetadataMediaType.AudioMedia: AudioMedia(_image, _filterId, _imagePath, _fi, _plugins, imgChecksums, ref _sidecar, _encoding); break; @@ -188,7 +199,7 @@ public sealed partial class Sidecar /// Aborts sidecar running operation public void Abort() { - UpdateStatus("Aborting..."); + UpdateStatus(Localization.Core.Aborting); _aborted = true; } } \ No newline at end of file diff --git a/Aaru.Core/Spectre.cs b/Aaru.Core/Spectre.cs index 49a11eca7..8f85a174d 100644 --- a/Aaru.Core/Spectre.cs +++ b/Aaru.Core/Spectre.cs @@ -1,17 +1,16 @@ +using System; +using Spectre.Console; + namespace Aaru.Core; -using System; -using global::Spectre.Console; - -/// -/// Implement core operations using the Spectre console -/// +/// Implement core operations using the Spectre console public static class Spectre { - /// - /// Initializes a progress bar with a single spinner - /// + /// Initializes a progress bar with a single spinner /// Action to execute in the progress bar - public static void ProgressSingleSpinner(Action action) => AnsiConsole.Progress().AutoClear(true). - HideCompleted(true).Columns(new TaskDescriptionColumn(), new SpinnerColumn()).Start(action); + public static void ProgressSingleSpinner(Action action) => AnsiConsole.Progress() + .AutoClear(true) + .HideCompleted(true) + .Columns(new TaskDescriptionColumn(), new SpinnerColumn()) + .Start(action); } \ No newline at end of file diff --git a/Aaru.Core/Statistics.cs b/Aaru.Core/Statistics.cs index fb9a1317a..2042502dd 100644 --- a/Aaru.Core/Statistics.cs +++ b/Aaru.Core/Statistics.cs @@ -27,37 +27,36 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Core; - using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Text; -using System.Threading; -using System.Xml.Serialization; +using System.Text.Json; +using System.Threading.Tasks; using Aaru.CommonTypes.Interop; using Aaru.CommonTypes.Metadata; using Aaru.Console; using Aaru.Database; using Aaru.Database.Models; -using Aaru.Settings; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; -using Newtonsoft.Json; using Device = Aaru.Devices.Device; using MediaType = Aaru.CommonTypes.MediaType; using OperatingSystem = Aaru.Database.Models.OperatingSystem; using Version = Aaru.Database.Models.Version; +namespace Aaru.Core; + /// Handles anonymous usage statistics public static class Statistics { + const string MODULE_NAME = "Stats"; /// Statistics file semaphore static bool _submitStatsLock; @@ -66,467 +65,9 @@ public static class Statistics { try { - using var ctx = AaruContext.Create(Settings.LocalDbPath); + using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); - if(File.Exists(Path.Combine(Settings.StatsPath, "Statistics.xml"))) - try - { - var allStats = new Stats(); - var xs = new XmlSerializer(allStats.GetType()); - - var sr = new StreamReader(Path.Combine(Settings.StatsPath, "Statistics.xml")); - - allStats = (Stats)xs.Deserialize(sr); - sr.Close(); - - if(allStats != null) - { - if(allStats.Commands?.Analyze > 0) - { - Command command = ctx.Commands.FirstOrDefault(c => c.Name == "fs-info" && c.Synchronized) ?? - new Command - { - Name = "fs-info", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.Analyze; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.Checksum > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "checksum" && c.Synchronized) ?? new Command - { - Name = "checksum", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.Checksum; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.Compare > 0) - { - Command command = ctx.Commands.FirstOrDefault(c => c.Name == "compare" && c.Synchronized) ?? - new Command - { - Name = "compare", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.Compare; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.ConvertImage > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "convert-image" && c.Synchronized) ?? - new Command - { - Name = "convert-image", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.ConvertImage; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.CreateSidecar > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "create-sidecar" && c.Synchronized) ?? - new Command - { - Name = "create-sidecar", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.CreateSidecar; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.Decode > 0) - { - Command command = ctx.Commands.FirstOrDefault(c => c.Name == "decode" && c.Synchronized) ?? - new Command - { - Name = "decode", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.Decode; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.DeviceInfo > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "device-info" && c.Synchronized) ?? - new Command - { - Name = "device-info", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.DeviceInfo; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.DeviceReport > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "device-report" && c.Synchronized) ?? - new Command - { - Name = "device-report", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.DeviceReport; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.DumpMedia > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "dump-media" && c.Synchronized) ?? - new Command - { - Name = "dump-media", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.DumpMedia; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.Entropy > 0) - { - Command command = ctx.Commands.FirstOrDefault(c => c.Name == "entropy" && c.Synchronized) ?? - new Command - { - Name = "entropy", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.Entropy; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.ExtractFiles > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "extract-files" && c.Synchronized) ?? - new Command - { - Name = "extract-files", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.ExtractFiles; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.Formats > 0) - { - Command command = ctx.Commands.FirstOrDefault(c => c.Name == "formats" && c.Synchronized) ?? - new Command - { - Name = "formats", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.Formats; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.ImageInfo > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "image-info" && c.Synchronized) ?? - new Command - { - Name = "image-info", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.ImageInfo; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.ListDevices > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "list-devices" && c.Synchronized) ?? - new Command - { - Name = "list-devices", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.ListDevices; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.ListEncodings > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "list-encodings" && c.Synchronized) ?? - new Command - { - Name = "list-encodings", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.ListEncodings; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.Ls > 0) - { - Command command = ctx.Commands.FirstOrDefault(c => c.Name == "ls" && c.Synchronized) ?? - new Command - { - Name = "ls", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.Ls; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.MediaInfo > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "media-info" && c.Synchronized) ?? - new Command - { - Name = "media-info", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.MediaInfo; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.MediaScan > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "media-scan" && c.Synchronized) ?? - new Command - { - Name = "media-scan", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.MediaScan; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.PrintHex > 0) - { - Command command = - ctx.Commands.FirstOrDefault(c => c.Name == "printhex" && c.Synchronized) ?? new Command - { - Name = "printhex", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.PrintHex; - ctx.Commands.Update(command); - } - - if(allStats.Commands?.Verify > 0) - { - Command command = ctx.Commands.FirstOrDefault(c => c.Name == "verify" && c.Synchronized) ?? - new Command - { - Name = "verify", - Synchronized = true - }; - - command.Count += (ulong)allStats.Commands.Verify; - ctx.Commands.Update(command); - } - - if(allStats.OperatingSystems != null) - foreach(OsStats operatingSystem in allStats.OperatingSystems) - { - if(string.IsNullOrWhiteSpace(operatingSystem.name) || - string.IsNullOrWhiteSpace(operatingSystem.version)) - continue; - - OperatingSystem existing = - ctx.OperatingSystems.FirstOrDefault(c => c.Name == operatingSystem.name && - c.Version == operatingSystem.version && - c.Synchronized) ?? new OperatingSystem - { - Name = operatingSystem.name, - Version = operatingSystem.version, - Synchronized = true - }; - - existing.Count += (ulong)operatingSystem.Value; - ctx.OperatingSystems.Update(existing); - } - - if(allStats.Versions != null) - foreach(NameValueStats nvs in allStats.Versions) - { - if(string.IsNullOrWhiteSpace(nvs.name)) - continue; - - Version existing = - ctx.Versions.FirstOrDefault(c => c.Name == nvs.name && c.Synchronized) ?? - new Version - { - Name = nvs.name, - Synchronized = true - }; - - existing.Count += (ulong)nvs.Value; - ctx.Versions.Update(existing); - } - - if(allStats.Filesystems != null) - foreach(NameValueStats nvs in allStats.Filesystems) - { - if(string.IsNullOrWhiteSpace(nvs.name)) - continue; - - Filesystem existing = - ctx.Filesystems.FirstOrDefault(c => c.Name == nvs.name && c.Synchronized) ?? - new Filesystem - { - Name = nvs.name, - Synchronized = true - }; - - existing.Count += (ulong)nvs.Value; - ctx.Filesystems.Update(existing); - } - - if(allStats.Partitions != null) - foreach(NameValueStats nvs in allStats.Partitions) - { - if(string.IsNullOrWhiteSpace(nvs.name)) - continue; - - Partition existing = - ctx.Partitions.FirstOrDefault(c => c.Name == nvs.name && c.Synchronized) ?? - new Partition - { - Name = nvs.name, - Synchronized = true - }; - - existing.Count += (ulong)nvs.Value; - ctx.Partitions.Update(existing); - } - - if(allStats.Filesystems != null) - foreach(NameValueStats nvs in allStats.Filesystems) - { - if(string.IsNullOrWhiteSpace(nvs.name)) - continue; - - Filesystem existing = - ctx.Filesystems.FirstOrDefault(c => c.Name == nvs.name && c.Synchronized) ?? - new Filesystem - { - Name = nvs.name, - Synchronized = true - }; - - existing.Count += (ulong)nvs.Value; - ctx.Filesystems.Update(existing); - } - - if(allStats.MediaImages != null) - foreach(NameValueStats nvs in allStats.MediaImages) - { - if(string.IsNullOrWhiteSpace(nvs.name)) - continue; - - MediaFormat existing = - ctx.MediaFormats.FirstOrDefault(c => c.Name == nvs.name && c.Synchronized) ?? - new MediaFormat - { - Name = nvs.name, - Synchronized = true - }; - - existing.Count += (ulong)nvs.Value; - ctx.MediaFormats.Update(existing); - } - - if(allStats.Filters != null) - foreach(NameValueStats nvs in allStats.Filters) - { - if(string.IsNullOrWhiteSpace(nvs.name)) - continue; - - Filter existing = - ctx.Filters.FirstOrDefault(c => c.Name == nvs.name && c.Synchronized) ?? new Filter - { - Name = nvs.name, - Synchronized = true - }; - - existing.Count += (ulong)nvs.Value; - ctx.Filters.Update(existing); - } - - if(allStats.Devices != null) - foreach(DeviceStats device in allStats.Devices) - { - if(ctx.SeenDevices.Any(d => d.Manufacturer == device.Manufacturer && - d.Model == device.Model && d.Revision == device.Revision && - d.Bus == device.Bus)) - continue; - - ctx.SeenDevices.Add(new DeviceStat - { - Bus = device.Bus, - Manufacturer = device.Manufacturer, - Model = device.Model, - Revision = device.Revision, - Synchronized = true - }); - } - - if(allStats.Medias != null) - foreach(MediaStats media in allStats.Medias) - { - if(string.IsNullOrWhiteSpace(media.type)) - continue; - - Database.Models.Media existing = - ctx.Medias.FirstOrDefault(c => c.Type == media.type && c.Real == media.real && - c.Synchronized) ?? new Database.Models.Media - { - Type = media.type, - Real = media.real, - Synchronized = true - }; - - existing.Count += (ulong)media.Value; - ctx.Medias.Update(existing); - } - - ctx.SaveChanges(); - File.Delete(Path.Combine(Settings.StatsPath, "Statistics.xml")); - } } - catch - { - // Do not care about it - } - - if(Settings.Current.Stats == null) - return; + if(Settings.Settings.Current.Stats == null) return; ctx.OperatingSystems.Add(new OperatingSystem { @@ -547,660 +88,335 @@ public static class Statistics } catch(SqliteException ex) { - AaruConsole.DebugWriteLine("Stats", "Exception while trying to save statistics:"); - AaruConsole.DebugWriteLine("Stats", "{0}", ex); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Exception_while_trying_to_save_statistics); + AaruConsole.WriteException(ex); } } /// Saves statistics to disk - public static void SaveStats() + public static async Task SaveStatsAsync() { try { - using var ctx = AaruContext.Create(Settings.LocalDbPath); + await using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); - ctx.SaveChanges(); + await ctx.SaveChangesAsync(); } catch(SqliteException ex) { - AaruConsole.DebugWriteLine("Stats", "Exception while trying to save statistics:"); - AaruConsole.DebugWriteLine("Stats", "{0}", ex); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Exception_while_trying_to_save_statistics); + AaruConsole.WriteException(ex); } - if(Settings.Current.Stats is { ShareStats: true }) - SubmitStats(); + if(Settings.Settings.Current.Stats is { ShareStats: true }) await SubmitStatsAsync(); } /// Submits statistics to Aaru.Server - static void SubmitStats() + static async Task SubmitStatsAsync() { - var submitThread = new Thread(() => + await using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); + + try { - using var ctx = AaruContext.Create(Settings.LocalDbPath); + if(_submitStatsLock) return; - try + _submitStatsLock = true; + var dto = new StatsDto(); + + AddStats(ctx.Commands, out List nameValueStats); + + if(nameValueStats?.Count > 0) dto.Commands = nameValueStats; + + AddStats(ctx.Filesystems, out nameValueStats); + + if(nameValueStats?.Count > 0) dto.Filesystems = nameValueStats; + + AddStats(ctx.Filters, out nameValueStats); + + if(nameValueStats?.Count > 0) dto.Filters = nameValueStats; + + AddStats(ctx.MediaFormats, out nameValueStats); + + if(nameValueStats?.Count > 0) dto.MediaFormats = nameValueStats; + + AddStats(ctx.Partitions, out nameValueStats); + + if(nameValueStats?.Count > 0) dto.Partitions = nameValueStats; + + AddStats(ctx.Versions, out nameValueStats); + + if(nameValueStats?.Count > 0) dto.Versions = nameValueStats; + dto.Versions = []; + + if(ctx.Medias.Any(c => !c.Synchronized)) { - if(_submitStatsLock) - return; + dto.Medias = []; - _submitStatsLock = true; - - if(ctx.Commands.Any(c => !c.Synchronized) || - ctx.Filesystems.Any(c => !c.Synchronized) || - ctx.Filters.Any(c => !c.Synchronized) || - ctx.MediaFormats.Any(c => !c.Synchronized) || - ctx.Partitions.Any(c => !c.Synchronized) || - ctx.Medias.Any(c => !c.Synchronized) || - ctx.SeenDevices.Any(c => !c.Synchronized) || - ctx.OperatingSystems.Any(c => !c.Synchronized) || - ctx.Versions.Any(c => !c.Synchronized) || - ctx.RemoteApplications.Any(c => !c.Synchronized) || - ctx.RemoteArchitectures.Any(c => !c.Synchronized) || - ctx.RemoteOperatingSystems.Any(c => !c.Synchronized)) + foreach(string media in ctx.Medias.Where(c => !c.Synchronized).Select(c => c.Type).Distinct()) { - var dto = new StatsDto(); - - if(ctx.Commands.Any(c => !c.Synchronized)) + if(ctx.Medias.Any(c => !c.Synchronized && c.Type == media && c.Real)) { - dto.Commands = new List(); - - foreach(string nvs in ctx.Commands.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) - dto.Commands.Add(new NameValueStats - { - name = nvs, - Value = ctx.Commands.LongCount(c => !c.Synchronized && c.Name == nvs) - }); - } - - if(ctx.Filesystems.Any(c => !c.Synchronized)) - { - dto.Filesystems = new List(); - - foreach(string nvs in ctx.Filesystems.Where(c => !c.Synchronized).Select(c => c.Name). - Distinct()) - dto.Filesystems.Add(new NameValueStats - { - name = nvs, - Value = ctx.Filesystems.LongCount(c => !c.Synchronized && c.Name == nvs) - }); - } - - if(ctx.Filters.Any(c => !c.Synchronized)) - { - dto.Filters = new List(); - - foreach(string nvs in ctx.Filters.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) - dto.Filters.Add(new NameValueStats - { - name = nvs, - Value = ctx.Filters.LongCount(c => !c.Synchronized && c.Name == nvs) - }); - } - - if(ctx.MediaFormats.Any(c => !c.Synchronized)) - { - dto.MediaFormats = new List(); - - foreach(string nvs in ctx.MediaFormats.Where(c => !c.Synchronized).Select(c => c.Name). - Distinct()) - dto.MediaFormats.Add(new NameValueStats - { - name = nvs, - Value = ctx.MediaFormats.LongCount(c => !c.Synchronized && c.Name == nvs) - }); - } - - if(ctx.Partitions.Any(c => !c.Synchronized)) - { - dto.Partitions = new List(); - - foreach(string nvs in ctx.Partitions.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) - dto.Partitions.Add(new NameValueStats - { - name = nvs, - Value = ctx.Partitions.LongCount(c => !c.Synchronized && c.Name == nvs) - }); - } - - if(ctx.Versions.Any(c => !c.Synchronized)) - { - dto.Versions = new List(); - - foreach(string nvs in ctx.Versions.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) - dto.Versions.Add(new NameValueStats - { - name = nvs, - Value = ctx.Versions.LongCount(c => !c.Synchronized && c.Name == nvs) - }); - } - - if(ctx.Medias.Any(c => !c.Synchronized)) - { - dto.Medias = new List(); - - foreach(string media in ctx.Medias.Where(c => !c.Synchronized).Select(c => c.Type).Distinct()) + dto.Medias.Add(new MediaStats { - if(ctx.Medias.Any(c => !c.Synchronized && c.Type == media && c.Real)) - dto.Medias.Add(new MediaStats - { - real = true, - type = media, - Value = ctx.Medias.LongCount(c => !c.Synchronized && c.Type == media && c.Real) - }); - - if(ctx.Medias.Any(c => !c.Synchronized && c.Type == media && !c.Real)) - dto.Medias.Add(new MediaStats - { - real = false, - type = media, - Value = ctx.Medias.LongCount(c => !c.Synchronized && c.Type == media && !c.Real) - }); - } + real = true, + MediaType = media, + Value = ctx.Medias.LongCount(c => !c.Synchronized && c.Type == media && c.Real) + }); } - if(ctx.SeenDevices.Any(c => !c.Synchronized)) + if(ctx.Medias.Any(c => !c.Synchronized && c.Type == media && !c.Real)) { - dto.Devices = new List(); - - foreach(DeviceStat device in ctx.SeenDevices.Where(c => !c.Synchronized)) - dto.Devices.Add(new DeviceStats - { - Bus = device.Bus, - Manufacturer = device.Manufacturer, - ManufacturerSpecified = !(device.Manufacturer is null), - Model = device.Model, - Revision = device.Revision - }); - } - - if(ctx.OperatingSystems.Any(c => !c.Synchronized)) - { - dto.OperatingSystems = new List(); - - foreach(string osName in ctx.OperatingSystems.Where(c => !c.Synchronized).Select(c => c.Name). - Distinct()) + dto.Medias.Add(new MediaStats { - foreach(string osVersion in ctx.OperatingSystems. - Where(c => !c.Synchronized && c.Name == osName). - Select(c => c.Version).Distinct()) - dto.OperatingSystems.Add(new OsStats - { - name = osName, - version = osVersion, - Value = ctx.OperatingSystems.LongCount(c => !c.Synchronized && c.Name == osName && - c.Version == osVersion) - }); - } + real = false, + MediaType = media, + Value = ctx.Medias.LongCount(c => !c.Synchronized && c.Type == media && !c.Real) + }); } + } + } - if(ctx.RemoteApplications.Any(c => !c.Synchronized)) + if(ctx.SeenDevices.Any(c => !c.Synchronized)) + { + dto.Devices = []; + + foreach(DeviceStat device in ctx.SeenDevices.Where(c => !c.Synchronized)) + { + dto.Devices.Add(new DeviceStats { - dto.RemoteApplications = new List(); - - foreach(string remoteAppName in ctx.RemoteApplications.Where(c => !c.Synchronized). - Select(c => c.Name).Distinct()) - { - foreach(string remoteAppVersion in ctx.RemoteApplications. - Where(c => !c.Synchronized && - c.Name == remoteAppName). - Select(c => c.Version).Distinct()) - dto.RemoteApplications.Add(new OsStats - { - name = remoteAppName, - version = remoteAppVersion, - Value = ctx.RemoteApplications.LongCount(c => !c.Synchronized && - c.Name == remoteAppName && - c.Version == remoteAppVersion) - }); - } - } - - if(ctx.RemoteArchitectures.Any(c => !c.Synchronized)) - { - dto.RemoteArchitectures = new List(); - - foreach(string nvs in ctx.RemoteArchitectures.Where(c => !c.Synchronized).Select(c => c.Name). - Distinct()) - dto.RemoteArchitectures.Add(new NameValueStats - { - name = nvs, - Value = ctx.RemoteArchitectures.LongCount(c => !c.Synchronized && c.Name == nvs) - }); - } - - if(ctx.RemoteOperatingSystems.Any(c => !c.Synchronized)) - { - dto.RemoteOperatingSystems = new List(); - - foreach(string remoteOsName in ctx.RemoteOperatingSystems.Where(c => !c.Synchronized). - Select(c => c.Name).Distinct()) - { - foreach(string remoteOsVersion in ctx.RemoteOperatingSystems. - Where(c => !c.Synchronized && c.Name == remoteOsName). - Select(c => c.Version).Distinct()) - dto.RemoteOperatingSystems.Add(new OsStats - { - name = remoteOsName, - version = remoteOsVersion, - Value = ctx.RemoteOperatingSystems.LongCount(c => !c.Synchronized && - c.Name == remoteOsName && c.Version == remoteOsVersion) - }); - } - } - - #if DEBUG - Console.WriteLine("Uploading statistics"); - #else - Aaru.Console.AaruConsole.DebugWriteLine("Submit stats", "Uploading statistics"); - #endif - - string json = JsonConvert.SerializeObject(dto, Formatting.Indented, new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore + Bus = device.Bus, + Manufacturer = device.Manufacturer, + ManufacturerSpecified = device.Manufacturer is not null, + Model = device.Model, + Revision = device.Revision }); + } + } - byte[] jsonBytes = Encoding.UTF8.GetBytes(json); - var request = WebRequest.Create("https://www.aaru.app/api/uploadstatsv2"); + AddOperatingSystem(ctx.OperatingSystems, out List osStats); + if(nameValueStats?.Count > 0) dto.OperatingSystems = osStats; + dto.OperatingSystems = []; - ((HttpWebRequest)request).UserAgent = $"Aaru {typeof(Version).Assembly.GetName().Version}"; + AddOperatingSystem(ctx.RemoteApplications, out osStats); + if(nameValueStats?.Count > 0) dto.RemoteApplications = osStats; + dto.RemoteApplications = []; - request.Method = "POST"; - request.ContentLength = jsonBytes.Length; - request.ContentType = "application/json"; - Stream reqStream = request.GetRequestStream(); - reqStream.Write(jsonBytes, 0, jsonBytes.Length); + AddStats(ctx.RemoteArchitectures, out nameValueStats); - //jsonStream.CopyTo(reqStream); - reqStream.Close(); - WebResponse response = request.GetResponse(); + if(nameValueStats?.Count > 0) dto.RemoteArchitectures = nameValueStats; + dto.RemoteArchitectures = []; - if(((HttpWebResponse)response).StatusCode != HttpStatusCode.OK) - return; + AddOperatingSystem(ctx.RemoteOperatingSystems, out osStats); + if(nameValueStats?.Count > 0) dto.RemoteOperatingSystems = osStats; + dto.RemoteOperatingSystems = []; - Stream data = response.GetResponseStream(); - var reader = new StreamReader(data ?? throw new InvalidOperationException()); +#if DEBUG + System.Console.WriteLine(Localization.Core.Uploading_statistics); +#else + Aaru.Console.AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Uploading_statistics); +#endif + using StringContent jsonContent = + new(JsonSerializer.Serialize(dto, typeof(StatsDto), StatsDtoContext.Default), + Encoding.UTF8, + "application/json"); - string result = reader.ReadToEnd(); - data.Close(); - response.Close(); + var client = new HttpClient(); + client.BaseAddress = new Uri("https://www.aaru.app"); + client.DefaultRequestHeaders.Add("User-Agent", $"Aaru {typeof(Version).Assembly.GetName().Version}"); - if(result != "ok") - return; + using HttpResponseMessage response = await client.PostAsync("/api/uploadstatsv2", jsonContent); - if(ctx.Commands.Any(c => !c.Synchronized)) - foreach(string nvs in ctx.Commands.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) - { - Command existing = ctx.Commands.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ?? - new Command - { - Name = nvs, - Synchronized = true - }; + if(response.StatusCode != HttpStatusCode.OK) return; - existing.Count += (ulong)ctx.Commands.LongCount(c => !c.Synchronized && c.Name == nvs); - ctx.Commands.Update(existing); - ctx.Commands.RemoveRange(ctx.Commands.Where(c => !c.Synchronized && c.Name == nvs)); - } + string result = await response.Content.ReadAsStringAsync(); - if(ctx.Filesystems.Any(c => !c.Synchronized)) - foreach(string nvs in ctx.Filesystems.Where(c => !c.Synchronized).Select(c => c.Name). - Distinct()) - { - Filesystem existing = - ctx.Filesystems.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ?? new Filesystem - { - Name = nvs, - Synchronized = true - }; + if(result != "ok") return; - existing.Count += (ulong)ctx.Filesystems.LongCount(c => !c.Synchronized && c.Name == nvs); + await UpdateStatsAsync(ctx.Commands); + await UpdateStatsAsync(ctx.Filesystems); + await UpdateStatsAsync(ctx.Filters); + await UpdateStatsAsync(ctx.MediaFormats); + await UpdateStatsAsync(ctx.Partitions); + await UpdateStatsAsync(ctx.Versions); - ctx.Filesystems.Update(existing); - - ctx.Filesystems.RemoveRange(ctx.Filesystems.Where(c => !c.Synchronized && c.Name == nvs)); - } - - if(ctx.Filters.Any(c => !c.Synchronized)) - foreach(string nvs in ctx.Filters.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) - { - Filter existing = ctx.Filters.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ?? - new Filter - { - Name = nvs, - Synchronized = true - }; - - existing.Count += (ulong)ctx.Filters.LongCount(c => !c.Synchronized && c.Name == nvs); - ctx.Filters.Update(existing); - ctx.Filters.RemoveRange(ctx.Filters.Where(c => !c.Synchronized && c.Name == nvs)); - } - - if(ctx.MediaFormats.Any(c => !c.Synchronized)) - foreach(string nvs in ctx.MediaFormats.Where(c => !c.Synchronized).Select(c => c.Name). - Distinct()) - { - MediaFormat existing = - ctx.MediaFormats.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ?? new MediaFormat - { - Name = nvs, - Synchronized = true - }; - - existing.Count += (ulong)ctx.MediaFormats.LongCount(c => !c.Synchronized && c.Name == nvs); - - ctx.MediaFormats.Update(existing); - - ctx.MediaFormats.RemoveRange(ctx.MediaFormats.Where(c => !c.Synchronized && c.Name == nvs)); - } - - if(ctx.Partitions.Any(c => !c.Synchronized)) - foreach(string nvs in ctx.Partitions.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) - { - Partition existing = - ctx.Partitions.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ?? new Partition - { - Name = nvs, - Synchronized = true - }; - - existing.Count += (ulong)ctx.Partitions.LongCount(c => !c.Synchronized && c.Name == nvs); - - ctx.Partitions.Update(existing); - ctx.Partitions.RemoveRange(ctx.Partitions.Where(c => !c.Synchronized && c.Name == nvs)); - } - - if(ctx.Versions.Any(c => !c.Synchronized)) - foreach(string nvs in ctx.Versions.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) - { - Version existing = ctx.Versions.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ?? - new Version - { - Name = nvs, - Synchronized = true - }; - - existing.Count += (ulong)ctx.Versions.LongCount(c => !c.Synchronized && c.Name == nvs); - ctx.Versions.Update(existing); - ctx.Versions.RemoveRange(ctx.Versions.Where(c => !c.Synchronized && c.Name == nvs)); - } - - if(ctx.Medias.Any(c => !c.Synchronized)) - foreach(string media in ctx.Medias.Where(c => !c.Synchronized).Select(c => c.Type).Distinct()) - { - if(ctx.Medias.Any(c => !c.Synchronized && c.Type == media && c.Real)) - { - Database.Models.Media existing = - ctx.Medias.FirstOrDefault(c => c.Synchronized && c.Type == media && c.Real) ?? - new Database.Models.Media - { - Synchronized = true, - Type = media, - Real = true - }; - - existing.Count += - (ulong)ctx.Medias.LongCount(c => !c.Synchronized && c.Type == media && c.Real); - - ctx.Medias.Update(existing); - - ctx.Medias.RemoveRange(ctx.Medias.Where(c => !c.Synchronized && c.Type == media && - c.Real)); - } - - if(!ctx.Medias.Any(c => !c.Synchronized && c.Type == media && !c.Real)) - continue; - - { - Database.Models.Media existing = - ctx.Medias.FirstOrDefault(c => c.Synchronized && c.Type == media && !c.Real) ?? - new Database.Models.Media - { - Synchronized = true, - Type = media, - Real = false - }; - - existing.Count += - (ulong)ctx.Medias.LongCount(c => !c.Synchronized && c.Type == media && !c.Real); - - ctx.Medias.Update(existing); - - ctx.Medias.RemoveRange(ctx.Medias.Where(c => !c.Synchronized && c.Type == media && - !c.Real)); - } - } - - if(ctx.SeenDevices.Any(c => !c.Synchronized)) - foreach(DeviceStat device in ctx.SeenDevices.Where(c => !c.Synchronized)) - { - device.Synchronized = true; - ctx.Update(device); - } - - if(ctx.OperatingSystems.Any(c => !c.Synchronized)) - foreach(string osName in ctx.OperatingSystems.Where(c => !c.Synchronized).Select(c => c.Name). - Distinct()) - { - foreach(string osVersion in ctx.OperatingSystems. - Where(c => !c.Synchronized && c.Name == osName). - Select(c => c.Version).Distinct()) - { - OperatingSystem existing = - ctx.OperatingSystems.FirstOrDefault(c => c.Synchronized && c.Name == osName && - c.Version == osVersion) ?? - new OperatingSystem - { - Synchronized = true, - Version = osVersion, - Name = osName - }; - - existing.Count += - (ulong)ctx.OperatingSystems.LongCount(c => !c.Synchronized && c.Name == osName && - c.Version == osVersion); - - ctx.OperatingSystems.Update(existing); - - ctx.OperatingSystems.RemoveRange(ctx.OperatingSystems.Where(c => !c.Synchronized && - c.Name == osName && - c.Version == osVersion)); - } - } - - if(ctx.RemoteApplications.Any(c => !c.Synchronized)) - foreach(string remoteAppName in ctx.RemoteApplications.Where(c => !c.Synchronized). - Select(c => c.Name).Distinct()) - { - foreach(string remoteAppVersion in ctx.RemoteApplications. - Where(c => !c.Synchronized && - c.Name == remoteAppName). - Select(c => c.Version).Distinct()) - { - RemoteApplication existing = - ctx.RemoteApplications.FirstOrDefault(c => c.Synchronized && - c.Name == remoteAppName && - c.Version == remoteAppVersion) ?? - new RemoteApplication - { - Synchronized = true, - Version = remoteAppVersion, - Name = remoteAppName - }; - - existing.Count += - (ulong)ctx.RemoteApplications.LongCount(c => !c.Synchronized && - c.Name == remoteAppName && - c.Version == remoteAppVersion); - - ctx.RemoteApplications.Update(existing); - - ctx.RemoteApplications.RemoveRange(ctx.RemoteApplications.Where(c => !c.Synchronized && - c.Name == remoteAppName && - c.Version == remoteAppVersion)); - } - } - - if(ctx.RemoteArchitectures.Any(c => !c.Synchronized)) - foreach(string nvs in ctx.RemoteArchitectures.Where(c => !c.Synchronized).Select(c => c.Name). - Distinct()) - { - RemoteArchitecture existing = - ctx.RemoteArchitectures.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ?? - new RemoteArchitecture - { - Name = nvs, - Synchronized = true - }; - - existing.Count += - (ulong)ctx.RemoteArchitectures.LongCount(c => !c.Synchronized && c.Name == nvs); - - ctx.RemoteArchitectures.Update(existing); - - ctx.RemoteArchitectures.RemoveRange(ctx.RemoteArchitectures.Where(c => !c.Synchronized && - c.Name == nvs)); - } - - foreach(string remoteOsName in ctx.RemoteOperatingSystems.Where(c => !c.Synchronized). - Select(c => c.Name).Distinct()) + if(ctx.Medias.Any(c => !c.Synchronized)) + { + foreach(string media in ctx.Medias.Where(c => !c.Synchronized).Select(c => c.Type).Distinct()) + { + if(ctx.Medias.Any(c => !c.Synchronized && c.Type == media && c.Real)) { - foreach(string remoteOsVersion in ctx.RemoteOperatingSystems. - Where(c => !c.Synchronized && c.Name == remoteOsName). - Select(c => c.Version).Distinct()) - { - RemoteOperatingSystem existing = - ctx.RemoteOperatingSystems.FirstOrDefault(c => c.Synchronized && - c.Name == remoteOsName && - c.Version == remoteOsVersion) ?? - new RemoteOperatingSystem - { - Synchronized = true, - Version = remoteOsVersion, - Name = remoteOsName - }; + Database.Models.Media existing = + await ctx.Medias.FirstOrDefaultAsync(c => c.Synchronized && c.Type == media && c.Real) ?? + new Database.Models.Media + { + Synchronized = true, + Type = media, + Real = true + }; - existing.Count += - (ulong)ctx.RemoteOperatingSystems.LongCount(c => !c.Synchronized && - c.Name == remoteOsName && - c.Version == remoteOsVersion); + existing.Count += + (ulong)ctx.Medias.LongCount(c => !c.Synchronized && c.Type == media && c.Real); - ctx.RemoteOperatingSystems.Update(existing); + ctx.Medias.Update(existing); - ctx.RemoteOperatingSystems.RemoveRange(ctx.RemoteOperatingSystems.Where(c => - !c.Synchronized && - c.Name == remoteOsName && - c.Version == remoteOsVersion)); - } + ctx.Medias.RemoveRange(ctx.Medias.Where(c => !c.Synchronized && c.Type == media && c.Real)); } - ctx.SaveChanges(); + if(!ctx.Medias.Any(c => !c.Synchronized && c.Type == media && !c.Real)) continue; + + { + Database.Models.Media existing = + await ctx.Medias.FirstOrDefaultAsync(c => c.Synchronized && c.Type == media && !c.Real) ?? + new Database.Models.Media + { + Synchronized = true, + Type = media, + Real = false + }; + + existing.Count += + (ulong)ctx.Medias.LongCount(c => !c.Synchronized && c.Type == media && !c.Real); + + ctx.Medias.Update(existing); + + ctx.Medias.RemoveRange(ctx.Medias.Where(c => !c.Synchronized && c.Type == media && !c.Real)); + } } } - catch(WebException) + + if(ctx.SeenDevices.Any(c => !c.Synchronized)) { - // Can't connect to the server, do nothing - } - catch(DbUpdateConcurrencyException) - { - // Ignore db concurrency errors + foreach(DeviceStat device in ctx.SeenDevices.Where(c => !c.Synchronized)) + { + device.Synchronized = true; + ctx.Update(device); + } } - // ReSharper disable once RedundantCatchClause - catch - { - #if DEBUG - _submitStatsLock = false; + await UpdateOperatingSystemAsync(ctx.OperatingSystems); + await UpdateOperatingSystemAsync(ctx.RemoteApplications); + await UpdateStatsAsync(ctx.RemoteArchitectures); + await UpdateOperatingSystemAsync(ctx.RemoteOperatingSystems); - if(Debugger.IsAttached) - throw; - #endif - } - - IEnumerable statsFiles = - Directory.EnumerateFiles(Settings.StatsPath, "PartialStats_*.xml", SearchOption.TopDirectoryOnly); - - foreach(string statsFile in statsFiles) - try - { - if(!File.Exists(statsFile)) - continue; - - var stats = new Stats(); - - // This can execute before debug console has been inited - #if DEBUG - Console.WriteLine("Uploading partial statistics file {0}", statsFile); - #else - Aaru.Console.AaruConsole.DebugWriteLine("Submit stats", "Uploading partial statistics file {0}", statsFile); - #endif - - var fs = new FileStream(statsFile, FileMode.Open, FileAccess.Read); - var xs = new XmlSerializer(stats.GetType()); - xs.Deserialize(fs); // Just to test validity of stats file - fs.Seek(0, SeekOrigin.Begin); - - var request = WebRequest.Create("https://www.aaru.app/api/uploadstats"); - - ((HttpWebRequest)request).UserAgent = - $"Aaru {typeof(CommonTypes.Interop.Version).Assembly.GetName().Version}"; - - request.Method = "POST"; - request.ContentLength = fs.Length; - request.ContentType = "application/xml"; - Stream reqStream = request.GetRequestStream(); - fs.CopyTo(reqStream); - reqStream.Close(); - WebResponse response = request.GetResponse(); - - if(((HttpWebResponse)response).StatusCode != HttpStatusCode.OK) - return; - - Stream data = response.GetResponseStream(); - var reader = new StreamReader(data ?? throw new InvalidOperationException()); - - string responseFromServer = reader.ReadToEnd(); - data.Close(); - response.Close(); - fs.Close(); - - if(responseFromServer == "ok") - File.Delete(statsFile); - } - catch(WebException) - { - // Can't connect to the server, postpone til next try - break; - } - catch - { - #if DEBUG - if(!Debugger.IsAttached) - continue; - - _submitStatsLock = false; - - throw; - #endif - } + await ctx.SaveChangesAsync(); + } + catch(WebException) + { + // Can't connect to the server, do nothing + } + catch(DbUpdateConcurrencyException) + { + // Ignore db concurrency errors + } + // ReSharper disable once RedundantCatchClause + catch + { +#if DEBUG _submitStatsLock = false; - }); - submitThread.Start(); + if(Debugger.IsAttached) throw; +#endif + } + + _submitStatsLock = false; + } + + static async Task UpdateOperatingSystemAsync(DbSet source) where T : BaseOperatingSystem, new() + { + if(!source.Any(c => !c.Synchronized)) return; + + foreach(string name in source.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) + { + foreach(string version in source.Where(c => !c.Synchronized && c.Name == name) + .Select(c => c.Version) + .Distinct()) + { + T existing = + await source.FirstOrDefaultAsync(c => c.Synchronized && c.Name == name && c.Version == version) ?? + new T + { + Synchronized = true, + Version = version, + Name = name + }; + + existing.Count += + (ulong)source.LongCount(c => !c.Synchronized && c.Name == name && c.Version == version); + + source.Update(existing); + + source.RemoveRange(source.Where(c => !c.Synchronized && c.Name == name && c.Version == version)); + } + } + } + + static async Task UpdateStatsAsync(DbSet source) where T : NameCountModel, new() + { + if(!source.Any(c => !c.Synchronized)) return; + + foreach(string nvs in source.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) + { + T existing = await source.FirstOrDefaultAsync(c => c.Synchronized && c.Name == nvs) ?? + new T + { + Name = nvs, + Synchronized = true + }; + + existing.Count += (ulong)source.LongCount(c => !c.Synchronized && c.Name == nvs); + source.Update(existing); + source.RemoveRange(source.Where(c => !c.Synchronized && c.Name == nvs)); + } + } + + static void AddOperatingSystem(IQueryable source, out List destination) + { + destination = []; + + foreach(string remoteOsName in source.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) + { + foreach(string remoteOsVersion in source.Where(c => !c.Synchronized && c.Name == remoteOsName) + .Select(c => c.Version) + .Distinct()) + { + destination.Add(new OsStats + { + name = remoteOsName, + version = remoteOsVersion, + Value = source.LongCount(c => !c.Synchronized && + c.Name == remoteOsName && + c.Version == remoteOsVersion) + }); + } + } + } + + static void AddStats(IQueryable source, out List destination) + { + destination = []; + + if(!source.Any(c => !c.Synchronized)) return; + + foreach(string nvs in source.Where(c => !c.Synchronized).Select(c => c.Name).Distinct()) + { + destination.Add(new NameValueStats + { + name = nvs, + Value = source.LongCount(c => !c.Synchronized && c.Name == nvs) + }); + } } /// Adds the execution of a command to statistics /// Command public static void AddCommand(string command) { - if(string.IsNullOrWhiteSpace(command)) - return; + if(string.IsNullOrWhiteSpace(command)) return; - if(Settings.Current.Stats == null || - !Settings.Current.Stats.DeviceStats) - return; + if(Settings.Settings.Current.Stats is not { DeviceStats: true }) return; - using var ctx = AaruContext.Create(Settings.LocalDbPath); + using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); ctx.Commands.Add(new Command { @@ -1215,8 +431,8 @@ public static class Statistics } catch(SqliteException ex) { - AaruConsole.DebugWriteLine("Stats", "Exception while trying to save statistics:"); - AaruConsole.DebugWriteLine("Stats", "{0}", ex); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Exception_while_trying_to_save_statistics); + AaruConsole.WriteException(ex); } } @@ -1224,14 +440,11 @@ public static class Statistics /// Filesystem name public static void AddFilesystem(string filesystem) { - if(string.IsNullOrWhiteSpace(filesystem)) - return; + if(string.IsNullOrWhiteSpace(filesystem)) return; - if(Settings.Current.Stats == null || - !Settings.Current.Stats.FilesystemStats) - return; + if(Settings.Settings.Current.Stats is not { FilesystemStats: true }) return; - using var ctx = AaruContext.Create(Settings.LocalDbPath); + using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); ctx.Filesystems.Add(new Filesystem { @@ -1246,8 +459,8 @@ public static class Statistics } catch(SqliteException ex) { - AaruConsole.DebugWriteLine("Stats", "Exception while trying to save statistics:"); - AaruConsole.DebugWriteLine("Stats", "{0}", ex); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Exception_while_trying_to_save_statistics); + AaruConsole.WriteException(ex); } } @@ -1255,14 +468,11 @@ public static class Statistics /// Partition scheme name internal static void AddPartition(string partition) { - if(string.IsNullOrWhiteSpace(partition)) - return; + if(string.IsNullOrWhiteSpace(partition)) return; - if(Settings.Current.Stats == null || - !Settings.Current.Stats.PartitionStats) - return; + if(Settings.Settings.Current.Stats is not { PartitionStats: true }) return; - using var ctx = AaruContext.Create(Settings.LocalDbPath); + using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); ctx.Partitions.Add(new Partition { @@ -1277,8 +487,8 @@ public static class Statistics } catch(SqliteException ex) { - AaruConsole.DebugWriteLine("Stats", "Exception while trying to save statistics:"); - AaruConsole.DebugWriteLine("Stats", "{0}", ex); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Exception_while_trying_to_save_statistics); + AaruConsole.WriteException(ex); } } @@ -1286,14 +496,11 @@ public static class Statistics /// Filter name public static void AddFilter(string filter) { - if(string.IsNullOrWhiteSpace(filter)) - return; + if(string.IsNullOrWhiteSpace(filter)) return; - if(Settings.Current.Stats == null || - !Settings.Current.Stats.FilterStats) - return; + if(Settings.Settings.Current.Stats is not { FilterStats: true }) return; - using var ctx = AaruContext.Create(Settings.LocalDbPath); + using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); ctx.Filters.Add(new Filter { @@ -1308,8 +515,8 @@ public static class Statistics } catch(SqliteException ex) { - AaruConsole.DebugWriteLine("Stats", "Exception while trying to save statistics:"); - AaruConsole.DebugWriteLine("Stats", "{0}", ex); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Exception_while_trying_to_save_statistics); + AaruConsole.WriteException(ex); } } @@ -1317,14 +524,11 @@ public static class Statistics /// Media image name public static void AddMediaFormat(string format) { - if(string.IsNullOrWhiteSpace(format)) - return; + if(string.IsNullOrWhiteSpace(format)) return; - if(Settings.Current.Stats == null || - !Settings.Current.Stats.MediaImageStats) - return; + if(Settings.Settings.Current.Stats is not { MediaImageStats: true }) return; - using var ctx = AaruContext.Create(Settings.LocalDbPath); + using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); ctx.MediaFormats.Add(new MediaFormat { @@ -1339,8 +543,8 @@ public static class Statistics } catch(SqliteException ex) { - AaruConsole.DebugWriteLine("Stats", "Exception while trying to save statistics:"); - AaruConsole.DebugWriteLine("Stats", "{0}", ex); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Exception_while_trying_to_save_statistics); + AaruConsole.WriteException(ex); } } @@ -1348,9 +552,7 @@ public static class Statistics /// Device public static void AddDevice(Device dev) { - if(Settings.Current.Stats == null || - !Settings.Current.Stats.DeviceStats) - return; + if(Settings.Settings.Current.Stats is not { DeviceStats: true }) return; string deviceBus; @@ -1361,10 +563,12 @@ public static class Statistics else deviceBus = dev.Type.ToString(); - using var ctx = AaruContext.Create(Settings.LocalDbPath); + using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); - if(ctx.SeenDevices.Any(d => d.Manufacturer == dev.Manufacturer && d.Model == dev.Model && - d.Revision == dev.FirmwareRevision && d.Bus == deviceBus)) + if(ctx.SeenDevices.Any(d => d.Manufacturer == dev.Manufacturer && + d.Model == dev.Model && + d.Revision == dev.FirmwareRevision && + d.Bus == deviceBus)) return; ctx.SeenDevices.Add(new DeviceStat @@ -1382,8 +586,8 @@ public static class Statistics } catch(SqliteException ex) { - AaruConsole.DebugWriteLine("Stats", "Exception while trying to save statistics:"); - AaruConsole.DebugWriteLine("Stats", "{0}", ex); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Exception_while_trying_to_save_statistics); + AaruConsole.WriteException(ex); } } @@ -1392,11 +596,9 @@ public static class Statistics /// Set if media was found on a real device, otherwise found on a media image public static void AddMedia(MediaType type, bool real) { - if(Settings.Current.Stats == null || - !Settings.Current.Stats.MediaStats) - return; + if(Settings.Settings.Current.Stats is not { MediaStats: true }) return; - using var ctx = AaruContext.Create(Settings.LocalDbPath); + using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); ctx.Medias.Add(new Database.Models.Media { @@ -1412,8 +614,8 @@ public static class Statistics } catch(SqliteException ex) { - AaruConsole.DebugWriteLine("Stats", "Exception while trying to save statistics:"); - AaruConsole.DebugWriteLine("Stats", "{0}", ex); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Exception_while_trying_to_save_statistics); + AaruConsole.WriteException(ex); } } @@ -1421,11 +623,9 @@ public static class Statistics public static void AddRemote(string serverApplication, string serverVersion, string serverOperatingSystem, string serverOperatingSystemVersion, string serverArchitecture) { - if(Settings.Current.Stats == null || - !Settings.Current.Stats.MediaStats) - return; + if(Settings.Settings.Current.Stats is not { MediaStats: true }) return; - using var ctx = AaruContext.Create(Settings.LocalDbPath); + using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); ctx.RemoteApplications.Add(new RemoteApplication { @@ -1456,8 +656,8 @@ public static class Statistics } catch(SqliteException ex) { - AaruConsole.DebugWriteLine("Stats", "Exception while trying to save statistics:"); - AaruConsole.DebugWriteLine("Stats", "{0}", ex); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Core.Exception_while_trying_to_save_statistics); + AaruConsole.WriteException(ex); } } } \ No newline at end of file diff --git a/Aaru.Database/Aaru.Database.csproj b/Aaru.Database/Aaru.Database.csproj index 5c67df999..b24e8927c 100644 --- a/Aaru.Database/Aaru.Database.csproj +++ b/Aaru.Database/Aaru.Database.csproj @@ -1,198 +1,101 @@  - - Debug - AnyCPU - 2.0 - Library - Aaru.Database - Aaru.Database - $(Version) - false - true - 6.0.0-alpha8 - Claunia.com - Copyright © 2011-2022 Natalia Portillo - Aaru Data Preservation Suite - Aaru.Database - $(Version) - net6.0 - 10 - Database models used by the Aaru Data Preservation Suite. - https://github.com/aaru-dps/ - LGPL-2.1-only - https://github.com/aaru-dps/Aaru - true - en-US - true - true - snupkg - Natalia Portillo <claunia@claunia.com> - true - - - $(Version)+{chash:8} - true - true - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - full - true - bin\Release - prompt - 4 - false - - - - LICENSE.LGPL - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /Library/Frameworks/Mono.framework/Versions/Current/lib/mono - /usr/lib/mono - /usr/local/lib/mono - - $(BaseFrameworkPathOverrideForMono)/4.0-api - $(BaseFrameworkPathOverrideForMono)/4.5-api - $(BaseFrameworkPathOverrideForMono)/4.5.1-api - $(BaseFrameworkPathOverrideForMono)/4.5.2-api - $(BaseFrameworkPathOverrideForMono)/4.6-api - $(BaseFrameworkPathOverrideForMono)/4.6.1-api - $(BaseFrameworkPathOverrideForMono)/4.6.2-api - $(BaseFrameworkPathOverrideForMono)/4.7-api - $(BaseFrameworkPathOverrideForMono)/4.7.1-api - true - - $(FrameworkPathOverride)/Facades;$(AssemblySearchPaths) - + + 2.0 + Library + Aaru.Database + Aaru.Database + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Database + $(Version) + net8.0 + 12 + Database models used by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + LGPL-2.1-only + https://github.com/aaru-dps/Aaru + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + LICENSE.LGPL + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + \ No newline at end of file diff --git a/Aaru.Database/Context.cs b/Aaru.Database/Context.cs index 22549abb4..1862fccd7 100644 --- a/Aaru.Database/Context.cs +++ b/Aaru.Database/Context.cs @@ -27,14 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Database; - using Aaru.Database.Models; using Microsoft.EntityFrameworkCore; +namespace Aaru.Database; + /// /// Database context public sealed class AaruContext : DbContext @@ -46,38 +46,55 @@ public sealed class AaruContext : DbContext /// List of known devices public DbSet Devices { get; set; } + /// List of local device reports public DbSet Reports { get; set; } + /// Command usage statistics public DbSet Commands { get; set; } + /// Statistics for found filesystems public DbSet Filesystems { get; set; } + /// Statistics for used filters public DbSet Filters { get; set; } + /// Statistics for media image formats public DbSet MediaFormats { get; set; } + /// Statistics for partitioning schemes public DbSet Partitions { get; set; } + /// Statistics for media types public DbSet Medias { get; set; } + /// Statistics for devices seen using commands public DbSet SeenDevices { get; set; } + /// Statistics for operating systems public DbSet OperatingSystems { get; set; } + /// Statistics for used Aaru versions public DbSet Versions { get; set; } + /// List of known USB vendors public DbSet UsbVendors { get; set; } + /// List of known USB products public DbSet UsbProducts { get; set; } + /// List of CD reading offsets public DbSet CdOffsets { get; set; } + /// Statistics of remote applications public DbSet RemoteApplications { get; set; } + /// Statistics of remote architectures public DbSet RemoteArchitectures { get; set; } + /// Statistics of remote operating systems public DbSet RemoteOperatingSystems { get; set; } + /// Known iNES/NES 2.0 headers public DbSet NesHeaders { get; set; } @@ -91,8 +108,8 @@ public sealed class AaruContext : DbContext { var optionsBuilder = new DbContextOptionsBuilder(); - optionsBuilder.UseLazyLoadingProxies(). - UseSqlite(!pooling ? $"Data Source={dbPath};Pooling=False" : $"Data Source={dbPath}"); + optionsBuilder.UseLazyLoadingProxies() + .UseSqlite(!pooling ? $"Data Source={dbPath};Pooling=False" : $"Data Source={dbPath}"); return new AaruContext(optionsBuilder.Options); } @@ -103,138 +120,217 @@ public sealed class AaruContext : DbContext base.OnModelCreating(modelBuilder); modelBuilder.Entity("Aaru.CommonTypes.Metadata.Ata", - b => b.HasOne("Aaru.CommonTypes.Metadata.TestedMedia", "ReadCapabilities").WithMany(). - HasForeignKey("ReadCapabilitiesId").OnDelete(DeleteBehavior.SetNull)); + b => b.HasOne("Aaru.CommonTypes.Metadata.TestedMedia", "ReadCapabilities") + .WithMany() + .HasForeignKey("ReadCapabilitiesId") + .OnDelete(DeleteBehavior.SetNull)); modelBuilder.Entity("Aaru.CommonTypes.Metadata.BlockDescriptor", - b => b.HasOne("Aaru.CommonTypes.Metadata.ScsiMode", null).WithMany("BlockDescriptors"). - HasForeignKey("ScsiModeId").OnDelete(DeleteBehavior.Cascade)); + b => b.HasOne("Aaru.CommonTypes.Metadata.ScsiMode", null) + .WithMany("BlockDescriptors") + .HasForeignKey("ScsiModeId") + .OnDelete(DeleteBehavior.Cascade)); modelBuilder.Entity("Aaru.CommonTypes.Metadata.DensityCode", - b => b.HasOne("Aaru.CommonTypes.Metadata.SscSupportedMedia", null).WithMany("DensityCodes"). - HasForeignKey("SscSupportedMediaId").OnDelete(DeleteBehavior.Cascade)); + b => b.HasOne("Aaru.CommonTypes.Metadata.SscSupportedMedia", null) + .WithMany("DensityCodes") + .HasForeignKey("SscSupportedMediaId") + .OnDelete(DeleteBehavior.Cascade)); modelBuilder.Entity("Aaru.CommonTypes.Metadata.Mmc", - b => b.HasOne("Aaru.CommonTypes.Metadata.MmcFeatures", "Features").WithMany(). - HasForeignKey("FeaturesId").OnDelete(DeleteBehavior.SetNull)); + b => b.HasOne("Aaru.CommonTypes.Metadata.MmcFeatures", "Features") + .WithMany() + .HasForeignKey("FeaturesId") + .OnDelete(DeleteBehavior.SetNull)); - modelBuilder.Entity("Aaru.CommonTypes.Metadata.Scsi", b => - { - b.HasOne("Aaru.CommonTypes.Metadata.ScsiMode", "ModeSense").WithMany().HasForeignKey("ModeSenseId"). - OnDelete(DeleteBehavior.SetNull); + modelBuilder.Entity("Aaru.CommonTypes.Metadata.Scsi", + b => + { + b.HasOne("Aaru.CommonTypes.Metadata.ScsiMode", "ModeSense") + .WithMany() + .HasForeignKey("ModeSenseId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Mmc", "MultiMediaDevice").WithMany(). - HasForeignKey("MultiMediaDeviceId").OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.Mmc", "MultiMediaDevice") + .WithMany() + .HasForeignKey("MultiMediaDeviceId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.TestedMedia", "ReadCapabilities").WithMany(). - HasForeignKey("ReadCapabilitiesId").OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.TestedMedia", "ReadCapabilities") + .WithMany() + .HasForeignKey("ReadCapabilitiesId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Ssc", "SequentialDevice").WithMany(). - HasForeignKey("SequentialDeviceId").OnDelete(DeleteBehavior.SetNull); - }); + b.HasOne("Aaru.CommonTypes.Metadata.Ssc", "SequentialDevice") + .WithMany() + .HasForeignKey("SequentialDeviceId") + .OnDelete(DeleteBehavior.SetNull); + }); - modelBuilder.Entity("Aaru.CommonTypes.Metadata.ScsiPage", b => - { - b.HasOne("Aaru.CommonTypes.Metadata.Scsi", null).WithMany("EVPDPages").HasForeignKey("ScsiId"). - OnDelete(DeleteBehavior.SetNull); + modelBuilder.Entity("Aaru.CommonTypes.Metadata.ScsiPage", + b => + { + b.HasOne("Aaru.CommonTypes.Metadata.Scsi", null) + .WithMany("EVPDPages") + .HasForeignKey("ScsiId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.ScsiMode", null).WithMany("ModePages").HasForeignKey("ScsiModeId"). - OnDelete(DeleteBehavior.SetNull); - }); + b.HasOne("Aaru.CommonTypes.Metadata.ScsiMode", null) + .WithMany("ModePages") + .HasForeignKey("ScsiModeId") + .OnDelete(DeleteBehavior.SetNull); + }); - modelBuilder.Entity("Aaru.CommonTypes.Metadata.SscSupportedMedia", b => - { - b.HasOne("Aaru.CommonTypes.Metadata.Ssc", null).WithMany("SupportedMediaTypes").HasForeignKey("SscId"). - OnDelete(DeleteBehavior.SetNull); + modelBuilder.Entity("Aaru.CommonTypes.Metadata.SscSupportedMedia", + b => + { + b.HasOne("Aaru.CommonTypes.Metadata.Ssc", null) + .WithMany("SupportedMediaTypes") + .HasForeignKey("SscId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.TestedSequentialMedia", null).WithMany("SupportedMediaTypes"). - HasForeignKey("TestedSequentialMediaId").OnDelete(DeleteBehavior.SetNull); - }); + b.HasOne("Aaru.CommonTypes.Metadata.TestedSequentialMedia", null) + .WithMany("SupportedMediaTypes") + .HasForeignKey("TestedSequentialMediaId") + .OnDelete(DeleteBehavior.SetNull); + }); - modelBuilder.Entity("Aaru.CommonTypes.Metadata.SupportedDensity", b => - { - b.HasOne("Aaru.CommonTypes.Metadata.Ssc", null).WithMany("SupportedDensities").HasForeignKey("SscId"). - OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity("Aaru.CommonTypes.Metadata.SupportedDensity", + b => + { + b.HasOne("Aaru.CommonTypes.Metadata.Ssc", null) + .WithMany("SupportedDensities") + .HasForeignKey("SscId") + .OnDelete(DeleteBehavior.Cascade); - b.HasOne("Aaru.CommonTypes.Metadata.TestedSequentialMedia", null).WithMany("SupportedDensities"). - HasForeignKey("TestedSequentialMediaId").OnDelete(DeleteBehavior.Cascade); - }); + b.HasOne("Aaru.CommonTypes.Metadata.TestedSequentialMedia", null) + .WithMany("SupportedDensities") + .HasForeignKey("TestedSequentialMediaId") + .OnDelete(DeleteBehavior.Cascade); + }); - modelBuilder.Entity("Aaru.CommonTypes.Metadata.TestedMedia", b => - { - b.HasOne("Aaru.CommonTypes.Metadata.Ata", null).WithMany("RemovableMedias").HasForeignKey("AtaId"). - OnDelete(DeleteBehavior.SetNull); + modelBuilder.Entity("Aaru.CommonTypes.Metadata.TestedMedia", + b => + { + b.HasOne("Aaru.CommonTypes.Metadata.Ata", null) + .WithMany("RemovableMedias") + .HasForeignKey("AtaId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Chs", "CHS").WithMany().HasForeignKey("CHSId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.Chs", "CHS") + .WithMany() + .HasForeignKey("CHSId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Chs", "CurrentCHS").WithMany().HasForeignKey("CurrentCHSId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.Chs", "CurrentCHS") + .WithMany() + .HasForeignKey("CurrentCHSId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Mmc", null).WithMany("TestedMedia").HasForeignKey("MmcId"). - OnDelete(DeleteBehavior.Cascade); + b.HasOne("Aaru.CommonTypes.Metadata.Mmc", null) + .WithMany("TestedMedia") + .HasForeignKey("MmcId") + .OnDelete(DeleteBehavior.Cascade); - b.HasOne("Aaru.CommonTypes.Metadata.Scsi", null).WithMany("RemovableMedias").HasForeignKey("ScsiId"). - OnDelete(DeleteBehavior.SetNull); - }); + b.HasOne("Aaru.CommonTypes.Metadata.Scsi", null) + .WithMany("RemovableMedias") + .HasForeignKey("ScsiId") + .OnDelete(DeleteBehavior.SetNull); + }); modelBuilder.Entity("Aaru.CommonTypes.Metadata.TestedSequentialMedia", - b => b.HasOne("Aaru.CommonTypes.Metadata.Ssc", null).WithMany("TestedMedia"). - HasForeignKey("SscId").OnDelete(DeleteBehavior.SetNull)); + b => b.HasOne("Aaru.CommonTypes.Metadata.Ssc", null) + .WithMany("TestedMedia") + .HasForeignKey("SscId") + .OnDelete(DeleteBehavior.SetNull)); - modelBuilder.Entity("Aaru.Database.Models.Device", b => - { - b.HasOne("Aaru.CommonTypes.Metadata.Ata", "ATA").WithMany().HasForeignKey("ATAId"). - OnDelete(DeleteBehavior.SetNull); + modelBuilder.Entity("Aaru.Database.Models.Device", + b => + { + b.HasOne("Aaru.CommonTypes.Metadata.Ata", "ATA") + .WithMany() + .HasForeignKey("ATAId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Ata", "ATAPI").WithMany().HasForeignKey("ATAPIId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.Ata", "ATAPI") + .WithMany() + .HasForeignKey("ATAPIId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.FireWire", "FireWire").WithMany().HasForeignKey("FireWireId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.FireWire", "FireWire") + .WithMany() + .HasForeignKey("FireWireId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.MmcSd", "MultiMediaCard").WithMany().HasForeignKey("MultiMediaCardId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.MmcSd", "MultiMediaCard") + .WithMany() + .HasForeignKey("MultiMediaCardId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Pcmcia", "PCMCIA").WithMany().HasForeignKey("PCMCIAId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.Pcmcia", "PCMCIA") + .WithMany() + .HasForeignKey("PCMCIAId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Scsi", "SCSI").WithMany().HasForeignKey("SCSIId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.Scsi", "SCSI") + .WithMany() + .HasForeignKey("SCSIId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.MmcSd", "SecureDigital").WithMany().HasForeignKey("SecureDigitalId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.MmcSd", "SecureDigital") + .WithMany() + .HasForeignKey("SecureDigitalId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Usb", "USB").WithMany().HasForeignKey("USBId"). - OnDelete(DeleteBehavior.SetNull); - }); + b.HasOne("Aaru.CommonTypes.Metadata.Usb", "USB") + .WithMany() + .HasForeignKey("USBId") + .OnDelete(DeleteBehavior.SetNull); + }); - modelBuilder.Entity("Aaru.Database.Models.Report", b => - { - b.HasOne("Aaru.CommonTypes.Metadata.Ata", "ATA").WithMany().HasForeignKey("ATAId"). - OnDelete(DeleteBehavior.SetNull); + modelBuilder.Entity("Aaru.Database.Models.Report", + b => + { + b.HasOne("Aaru.CommonTypes.Metadata.Ata", "ATA") + .WithMany() + .HasForeignKey("ATAId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Ata", "ATAPI").WithMany().HasForeignKey("ATAPIId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.Ata", "ATAPI") + .WithMany() + .HasForeignKey("ATAPIId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.FireWire", "FireWire").WithMany().HasForeignKey("FireWireId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.FireWire", "FireWire") + .WithMany() + .HasForeignKey("FireWireId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.MmcSd", "MultiMediaCard").WithMany().HasForeignKey("MultiMediaCardId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.MmcSd", "MultiMediaCard") + .WithMany() + .HasForeignKey("MultiMediaCardId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Pcmcia", "PCMCIA").WithMany().HasForeignKey("PCMCIAId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.Pcmcia", "PCMCIA") + .WithMany() + .HasForeignKey("PCMCIAId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Scsi", "SCSI").WithMany().HasForeignKey("SCSIId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.Scsi", "SCSI") + .WithMany() + .HasForeignKey("SCSIId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.MmcSd", "SecureDigital").WithMany().HasForeignKey("SecureDigitalId"). - OnDelete(DeleteBehavior.SetNull); + b.HasOne("Aaru.CommonTypes.Metadata.MmcSd", "SecureDigital") + .WithMany() + .HasForeignKey("SecureDigitalId") + .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Aaru.CommonTypes.Metadata.Usb", "USB").WithMany().HasForeignKey("USBId"). - OnDelete(DeleteBehavior.SetNull); - }); + b.HasOne("Aaru.CommonTypes.Metadata.Usb", "USB") + .WithMany() + .HasForeignKey("USBId") + .OnDelete(DeleteBehavior.SetNull); + }); modelBuilder.Entity().HasIndex(b => b.ModifiedWhen); diff --git a/Aaru.Database/ContextFactory.cs b/Aaru.Database/ContextFactory.cs index 67e3049cc..8c26a14f2 100644 --- a/Aaru.Database/ContextFactory.cs +++ b/Aaru.Database/ContextFactory.cs @@ -27,20 +27,26 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System.Diagnostics.CodeAnalysis; +using Microsoft.EntityFrameworkCore.Design; + namespace Aaru.Database; -using Microsoft.EntityFrameworkCore.Design; - /// /// Database context factory, for design time +[SuppressMessage("ReSharper", "UnusedType.Global")] public class AaruContextFactory : IDesignTimeDbContextFactory { +#region IDesignTimeDbContextFactory Members + /// /// Creates a database context /// Ignored parameters /// A database context public AaruContext CreateDbContext(string[] args) => AaruContext.Create("aaru.db"); + +#endregion } \ No newline at end of file diff --git a/Aaru.Database/Models/BaseModel.cs b/Aaru.Database/Models/BaseModel.cs index 423b93fff..05c58b067 100644 --- a/Aaru.Database/Models/BaseModel.cs +++ b/Aaru.Database/Models/BaseModel.cs @@ -27,13 +27,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Database.Models; - using System.ComponentModel.DataAnnotations; +namespace Aaru.Database.Models; + /// Base database model public abstract class BaseModel { diff --git a/Aaru.Database/Models/BaseOperatingSystem.cs b/Aaru.Database/Models/BaseOperatingSystem.cs index 307403f74..6a9d896ff 100644 --- a/Aaru.Database/Models/BaseOperatingSystem.cs +++ b/Aaru.Database/Models/BaseOperatingSystem.cs @@ -27,7 +27,7 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; @@ -38,10 +38,13 @@ public abstract class BaseOperatingSystem : BaseModel { /// Operating system name public string Name { get; set; } + /// Operating system version public string Version { get; set; } + /// Has already been synchronized with Aaru's server public bool Synchronized { get; set; } + /// Statistical count public ulong Count { get; set; } } \ No newline at end of file diff --git a/Aaru.Database/Models/CdOffset.cs b/Aaru.Database/Models/CdOffset.cs index cc131a18f..9cb4e51e3 100644 --- a/Aaru.Database/Models/CdOffset.cs +++ b/Aaru.Database/Models/CdOffset.cs @@ -27,13 +27,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Database.Models; - using System; +namespace Aaru.Database.Models; + /// /// CD read offset public class CdOffset : CommonTypes.Metadata.CdOffset @@ -71,8 +71,10 @@ public class CdOffset : CommonTypes.Metadata.CdOffset /// Database ID public int Id { get; set; } + /// Date when model has been added to the database public DateTime AddedWhen { get; set; } + /// Date when model was last modified public DateTime ModifiedWhen { get; set; } } \ No newline at end of file diff --git a/Aaru.Database/Models/Command.cs b/Aaru.Database/Models/Command.cs index d280bfc12..4321e97c4 100644 --- a/Aaru.Database/Models/Command.cs +++ b/Aaru.Database/Models/Command.cs @@ -27,11 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; /// /// Command statistics. -public class Command : NameCountModel {} \ No newline at end of file +public class Command : NameCountModel; \ No newline at end of file diff --git a/Aaru.Database/Models/Device.cs b/Aaru.Database/Models/Device.cs index 8f07e0004..edff200a4 100644 --- a/Aaru.Database/Models/Device.cs +++ b/Aaru.Database/Models/Device.cs @@ -27,18 +27,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Database.Models; - using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using Aaru.CommonTypes.Metadata; +namespace Aaru.Database.Models; + /// Known device -public class Device : DeviceReportV2 +public class Device : DeviceReport { /// Builds an empty device public Device() => LastSynchronized = DateTime.UtcNow; @@ -46,7 +46,7 @@ public class Device : DeviceReportV2 /// Builds a device from a device report /// Device report [SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")] - public Device(DeviceReportV2 report) + public Device(DeviceReport report) { ATA = report.ATA; ATAPI = report.ATAPI; diff --git a/Aaru.Database/Models/DeviceStat.cs b/Aaru.Database/Models/DeviceStat.cs index 3ec61b6cb..890d70637 100644 --- a/Aaru.Database/Models/DeviceStat.cs +++ b/Aaru.Database/Models/DeviceStat.cs @@ -27,7 +27,7 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; @@ -38,12 +38,16 @@ public class DeviceStat : BaseModel { /// Manufacturer public string Manufacturer { get; set; } + /// Model public string Model { get; set; } + /// Revision or firmware version public string Revision { get; set; } + /// Bus public string Bus { get; set; } + /// Has already been synchronized with Aaru's server public bool Synchronized { get; set; } } \ No newline at end of file diff --git a/Aaru.Database/Models/Filesystem.cs b/Aaru.Database/Models/Filesystem.cs index 516c52330..1bf953434 100644 --- a/Aaru.Database/Models/Filesystem.cs +++ b/Aaru.Database/Models/Filesystem.cs @@ -27,11 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; /// /// Filesystem found -public class Filesystem : NameCountModel {} \ No newline at end of file +public class Filesystem : NameCountModel; \ No newline at end of file diff --git a/Aaru.Database/Models/Filter.cs b/Aaru.Database/Models/Filter.cs index 082f44285..fffa14a16 100644 --- a/Aaru.Database/Models/Filter.cs +++ b/Aaru.Database/Models/Filter.cs @@ -27,11 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; /// /// Filter used -public class Filter : NameCountModel {} \ No newline at end of file +public class Filter : NameCountModel; \ No newline at end of file diff --git a/Aaru.Database/Models/Media.cs b/Aaru.Database/Models/Media.cs index 9bf096d47..42126c56a 100644 --- a/Aaru.Database/Models/Media.cs +++ b/Aaru.Database/Models/Media.cs @@ -27,7 +27,7 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; @@ -38,10 +38,13 @@ public class Media : BaseModel { /// Media type name public string Type { get; set; } + /// Found physically, or in image public bool Real { get; set; } + /// Has already been synchronized with Aaru's server public bool Synchronized { get; set; } + /// Count of times found public ulong Count { get; set; } } \ No newline at end of file diff --git a/Aaru.Database/Models/MediaFormat.cs b/Aaru.Database/Models/MediaFormat.cs index 804344375..1c258c5b1 100644 --- a/Aaru.Database/Models/MediaFormat.cs +++ b/Aaru.Database/Models/MediaFormat.cs @@ -27,11 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; /// /// Media image format -public class MediaFormat : NameCountModel {} \ No newline at end of file +public class MediaFormat : NameCountModel; \ No newline at end of file diff --git a/Aaru.Database/Models/NameCountModel.cs b/Aaru.Database/Models/NameCountModel.cs index 6d0d0c90b..fc62d4569 100644 --- a/Aaru.Database/Models/NameCountModel.cs +++ b/Aaru.Database/Models/NameCountModel.cs @@ -27,7 +27,7 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; @@ -38,8 +38,10 @@ public abstract class NameCountModel : BaseModel { /// Value name public string Name { get; set; } + /// Has already been synchronized with Aaru's server public bool Synchronized { get; set; } + /// Value count public ulong Count { get; set; } } \ No newline at end of file diff --git a/Aaru.Database/Models/NesHeaderInfo.cs b/Aaru.Database/Models/NesHeaderInfo.cs index 1da53ef97..8821ab12d 100644 --- a/Aaru.Database/Models/NesHeaderInfo.cs +++ b/Aaru.Database/Models/NesHeaderInfo.cs @@ -1,40 +1,54 @@ -namespace Aaru.Database.Models; - using System; using System.ComponentModel.DataAnnotations; using Aaru.CommonTypes.Enums; +namespace Aaru.Database.Models; + /// /// Information needed to rebuild an iNES/NES 2.0 header from a ROM hash public class NesHeaderInfo : BaseModel { /// ROM hash - [StringLength(64), Required] + [StringLength(64)] + [Required] public string Sha256 { get; set; } + /// If true vertical mirroring is hard-wired, horizontal or mapper defined otherwise public bool NametableMirroring { get; set; } + /// If true a battery is present public bool BatteryPresent { get; set; } + /// If true the four player screen mode is hardwired public bool FourScreenMode { get; set; } + /// Mapper number (NES 2.0 when in conflict) public ushort Mapper { get; set; } + /// Console type public NesConsoleType ConsoleType { get; set; } + /// Submapper number public byte Submapper { get; set; } + /// Timing mode public NesTimingMode TimingMode { get; set; } + /// Vs. PPU type public NesVsPpuType VsPpuType { get; set; } + /// Vs. hardware type public NesVsHardwareType VsHardwareType { get; set; } + /// Extended console type public NesExtendedConsoleType ExtendedConsoleType { get; set; } + /// Default expansion device public NesDefaultExpansionDevice DefaultExpansionDevice { get; set; } + /// Date when model has been added to the database public DateTime AddedWhen { get; set; } + /// Date when model was last modified public DateTime ModifiedWhen { get; set; } } \ No newline at end of file diff --git a/Aaru.Database/Models/OperatingSystem.cs b/Aaru.Database/Models/OperatingSystem.cs index a15980f4e..b85eab135 100644 --- a/Aaru.Database/Models/OperatingSystem.cs +++ b/Aaru.Database/Models/OperatingSystem.cs @@ -27,11 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; /// /// Operating system -public class OperatingSystem : BaseOperatingSystem {} \ No newline at end of file +public class OperatingSystem : BaseOperatingSystem; \ No newline at end of file diff --git a/Aaru.Database/Models/Partition.cs b/Aaru.Database/Models/Partition.cs index 15919a6ef..90a4e7840 100644 --- a/Aaru.Database/Models/Partition.cs +++ b/Aaru.Database/Models/Partition.cs @@ -27,11 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; /// /// Partitioning scheme -public class Partition : NameCountModel {} \ No newline at end of file +public class Partition : NameCountModel; \ No newline at end of file diff --git a/Aaru.Database/Models/RemoteApplication.cs b/Aaru.Database/Models/RemoteApplication.cs index a42bc609b..0e788acba 100644 --- a/Aaru.Database/Models/RemoteApplication.cs +++ b/Aaru.Database/Models/RemoteApplication.cs @@ -27,11 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; /// /// Remote application -public class RemoteApplication : BaseOperatingSystem {} \ No newline at end of file +public class RemoteApplication : BaseOperatingSystem; \ No newline at end of file diff --git a/Aaru.Database/Models/RemoteArchitecture.cs b/Aaru.Database/Models/RemoteArchitecture.cs index 6aa2556a5..e3e592386 100644 --- a/Aaru.Database/Models/RemoteArchitecture.cs +++ b/Aaru.Database/Models/RemoteArchitecture.cs @@ -27,11 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; /// /// Remote architecture -public class RemoteArchitecture : NameCountModel {} \ No newline at end of file +public class RemoteArchitecture : NameCountModel; \ No newline at end of file diff --git a/Aaru.Database/Models/RemoteOperatingSystem.cs b/Aaru.Database/Models/RemoteOperatingSystem.cs index 56a8be39b..a57a2029a 100644 --- a/Aaru.Database/Models/RemoteOperatingSystem.cs +++ b/Aaru.Database/Models/RemoteOperatingSystem.cs @@ -27,11 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; /// /// Remote operating system -public class RemoteOperatingSystem : BaseOperatingSystem {} \ No newline at end of file +public class RemoteOperatingSystem : BaseOperatingSystem; \ No newline at end of file diff --git a/Aaru.Database/Models/Report.cs b/Aaru.Database/Models/Report.cs index 9335facaa..fa6b5f387 100644 --- a/Aaru.Database/Models/Report.cs +++ b/Aaru.Database/Models/Report.cs @@ -27,17 +27,17 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Database.Models; - using System; using System.Diagnostics.CodeAnalysis; using Aaru.CommonTypes.Metadata; +namespace Aaru.Database.Models; + /// Device report -public class Report : DeviceReportV2 +public class Report : DeviceReport { /// Builds an empty device report public Report() @@ -49,7 +49,7 @@ public class Report : DeviceReportV2 /// Builds a device report model from a device report /// Device report [SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")] - public Report(DeviceReportV2 report) + public Report(DeviceReport report) { ATA = report.ATA; ATAPI = report.ATAPI; @@ -70,6 +70,7 @@ public class Report : DeviceReportV2 /// Date when the device report was created public DateTime Created { get; set; } + /// If this model has already been upload public bool Uploaded { get; set; } } \ No newline at end of file diff --git a/Aaru.Database/Models/UsbProduct.cs b/Aaru.Database/Models/UsbProduct.cs index c13fb745a..5a6901f16 100644 --- a/Aaru.Database/Models/UsbProduct.cs +++ b/Aaru.Database/Models/UsbProduct.cs @@ -27,14 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Database.Models; - using System; using System.ComponentModel.DataAnnotations; +namespace Aaru.Database.Models; + /// USB product public class UsbProduct { @@ -56,16 +56,22 @@ public class UsbProduct /// Database ID [Key] public int Id { get; set; } + /// Product ID public ushort ProductId { get; set; } + /// Product name public string Product { get; set; } + /// Date when model has been added to the database public DateTime AddedWhen { get; set; } + /// Date when model was last modified public DateTime ModifiedWhen { get; set; } + /// USB vendor ID public ushort VendorId { get; set; } + /// Database link to USB vendor public virtual UsbVendor Vendor { get; set; } } \ No newline at end of file diff --git a/Aaru.Database/Models/UsbVendor.cs b/Aaru.Database/Models/UsbVendor.cs index 00f27f043..20eaab47a 100644 --- a/Aaru.Database/Models/UsbVendor.cs +++ b/Aaru.Database/Models/UsbVendor.cs @@ -27,15 +27,15 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Database.Models; - using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +namespace Aaru.Database.Models; + /// USB vendor public class UsbVendor { @@ -55,10 +55,13 @@ public class UsbVendor /// Database ID [Key] public ushort Id { get; set; } + /// Vendor name public string Vendor { get; set; } + /// Date when model has been added to the database public DateTime AddedWhen { get; set; } + /// Date when model was last modified public DateTime ModifiedWhen { get; set; } diff --git a/Aaru.Database/Models/Version.cs b/Aaru.Database/Models/Version.cs index 09f070fca..b858f63f9 100644 --- a/Aaru.Database/Models/Version.cs +++ b/Aaru.Database/Models/Version.cs @@ -27,11 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Database.Models; /// /// Aaru version -public class Version : NameCountModel {} \ No newline at end of file +public class Version : NameCountModel; \ No newline at end of file diff --git a/Aaru.Decoders b/Aaru.Decoders deleted file mode 160000 index 1230d6f25..000000000 --- a/Aaru.Decoders +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1230d6f255633970b4220d3dd000ce5a90e46d50 diff --git a/Aaru.Decoders/.gitignore b/Aaru.Decoders/.gitignore new file mode 100644 index 000000000..05c540d38 --- /dev/null +++ b/Aaru.Decoders/.gitignore @@ -0,0 +1,595 @@ +### VisualStudio template +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ +### Linux template + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +### C++ template +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o + +# Precompiled Headers +*.gch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### MonoDevelop template +#User Specific +*.usertasks + +#Mono Project Files +*.resources +test-results/ +### GPG template +secring.* + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests +### CMake template +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +### C template +# Object files +*.ko +*.elf + +# Linker output +*.map +*.exp + +*.so.* + +# Executables +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# NuGet Packages Directory +packages/ +## TODO: If the tool you use requires repositories.config uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +# This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) +!packages/build/ + + +# Others +sql/ +*.Cache + +# Visual Studio 2017 +.vs + +workspace.xml +cmake-build-debug +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +pkg/**/pkg +pkg/**/src +pkg/**/*.asc +pkg/**/*.sig +pkg/**/*.tar.xz +pkg/**/*.zip +pkg/**/aaru + +.sonarqube \ No newline at end of file diff --git a/Aaru.Decoders/ATA/Identify.cs b/Aaru.Decoders/ATA/Identify.cs new file mode 100644 index 000000000..23cd6fb77 --- /dev/null +++ b/Aaru.Decoders/ATA/Identify.cs @@ -0,0 +1,2341 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Identify.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes ATA IDENTIFY DEVICE response. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.Structs.Devices.SCSI; +using Aaru.Localization; + +namespace Aaru.Decoders.ATA; + +// Information from following standards: +// T10-791D rev. 4c (ATA) +// T10-948D rev. 4c (ATA-2) +// T13-1153D rev. 18 (ATA/ATAPI-4) +// T13-1321D rev. 3 (ATA/ATAPI-5) +// T13-1410D rev. 3b (ATA/ATAPI-6) +// T13-1532D rev. 4b (ATA/ATAPI-7) +// T13-1699D rev. 3f (ATA8-ACS) +// T13-1699D rev. 4a (ATA8-ACS) +// T13-2015D rev. 2 (ACS-2) +// T13-2161D rev. 5 (ACS-3) +// CF+ & CF Specification rev. 1.4 (CFA) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Identify +{ + public static string Prettify(byte[] IdentifyDeviceResponse) + { + if(IdentifyDeviceResponse.Length != 512) return null; + + CommonTypes.Structs.Devices.ATA.Identify.IdentifyDevice? decoded = + CommonTypes.Structs.Devices.ATA.Identify.Decode(IdentifyDeviceResponse); + + return Prettify(decoded); + } + + public static string Prettify(CommonTypes.Structs.Devices.ATA.Identify.IdentifyDevice? IdentifyDeviceResponse) + { + if(IdentifyDeviceResponse == null) return null; + + var sb = new StringBuilder(); + + var atapi = false; + var cfa = false; + + CommonTypes.Structs.Devices.ATA.Identify.IdentifyDevice ATAID = IdentifyDeviceResponse.Value; + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .NonMagnetic)) + { + if((ushort)ATAID.GeneralConfiguration != 0x848A) + atapi = true; + else + cfa = true; + } + + if(atapi) + sb.AppendLine(Localization.ATAPI_device); + else if(cfa) + sb.AppendLine(Localization.CompactFlash_device); + else + sb.AppendLine(Localization.ATA_device); + + if(ATAID.Model != "") sb.AppendFormat(Core.Model_0, ATAID.Model).AppendLine(); + + if(ATAID.FirmwareRevision != "") sb.AppendFormat(Core.Firmware_revision_0, ATAID.FirmwareRevision).AppendLine(); + + if(ATAID.SerialNumber != "") sb.AppendFormat(Core.Serial_number_0, ATAID.SerialNumber).AppendLine(); + + if(ATAID.AdditionalPID != "") + sb.AppendFormat(Localization.Additional_product_ID_0, ATAID.AdditionalPID).AppendLine(); + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeSet) && + !ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeClear)) + { + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MediaSerial)) + { + if(ATAID.MediaManufacturer != "") + sb.AppendFormat(Core.Media_manufacturer_0, ATAID.MediaManufacturer).AppendLine(); + + if(ATAID.MediaSerial != "") sb.AppendFormat(Core.Media_serial_number_0, ATAID.MediaSerial).AppendLine(); + } + + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.WWN)) + sb.AppendFormat(Localization.World_Wide_Name_0, ATAID.WWN).AppendLine(); + } + + bool ata1 = false, + ata2 = false, + ata3 = false, + ata4 = false, + ata5 = false, + ata6 = false, + ata7 = false, + acs = false, + acs2 = false, + acs3 = false, + acs4 = false; + + if((ushort)ATAID.MajorVersion == 0x0000 || (ushort)ATAID.MajorVersion == 0xFFFF) + { + // Obsolete in ATA-2, if present, device supports ATA-1 + ata1 |= + ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .FastIDE) || + ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .SlowIDE) || + ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .UltraFastIDE); + + ata2 |= ATAID.ExtendedIdentify.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.ExtendedIdentifyBit + .Words64to70Valid); + + if(!ata1 && !ata2 && !atapi && !cfa) ata2 = true; + + ata4 |= atapi; + ata3 |= cfa; + + if(cfa && ata1) ata1 = false; + + if(cfa && ata2) ata2 = false; + + ata5 |= ATAID.Signature == 0xA5; + } + else + { + ata1 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata1); + ata2 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata2); + ata3 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata3); + ata4 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi4); + ata5 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi5); + ata6 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi6); + ata7 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi7); + acs |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata8ACS); + acs2 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.ACS2); + acs3 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.ACS3); + acs4 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.ACS4); + } + + var maxatalevel = 0; + var minatalevel = 255; + sb.Append(Localization.Supported_ATA_versions); + + if(ata1) + { + sb.Append("ATA-1 "); + maxatalevel = 1; + minatalevel = 1; + } + + if(ata2) + { + sb.Append("ATA-2 "); + maxatalevel = 2; + + if(minatalevel > 2) minatalevel = 2; + } + + if(ata3) + { + sb.Append("ATA-3 "); + maxatalevel = 3; + + if(minatalevel > 3) minatalevel = 3; + } + + if(ata4) + { + sb.Append("ATA/ATAPI-4 "); + maxatalevel = 4; + + if(minatalevel > 4) minatalevel = 4; + } + + if(ata5) + { + sb.Append("ATA/ATAPI-5 "); + maxatalevel = 5; + + if(minatalevel > 5) minatalevel = 5; + } + + if(ata6) + { + sb.Append("ATA/ATAPI-6 "); + maxatalevel = 6; + + if(minatalevel > 6) minatalevel = 6; + } + + if(ata7) + { + sb.Append("ATA/ATAPI-7 "); + maxatalevel = 7; + + if(minatalevel > 7) minatalevel = 7; + } + + if(acs) + { + sb.Append("ATA8-ACS "); + maxatalevel = 8; + + if(minatalevel > 8) minatalevel = 8; + } + + if(acs2) + { + sb.Append("ATA8-ACS2 "); + maxatalevel = 9; + + if(minatalevel > 9) minatalevel = 9; + } + + if(acs3) + { + sb.Append("ATA8-ACS3 "); + maxatalevel = 10; + + if(minatalevel > 10) minatalevel = 10; + } + + if(acs4) + { + sb.Append("ATA8-ACS4 "); + maxatalevel = 11; + + if(minatalevel > 11) minatalevel = 11; + } + + sb.AppendLine(); + + sb.Append(Localization.Maximum_ATA_revision_supported); + + if(maxatalevel >= 3) + { + switch(ATAID.MinorVersion) + { + case 0x0000: + case 0xFFFF: + sb.AppendLine(Localization.Minor_ATA_version_not_specified); + + break; + case 0x0001: + sb.AppendLine(Localization.ATA_ATA_1_X3T9_2_781D_prior_to_revision_4); + + break; + case 0x0002: + sb.AppendLine(Localization.ATA_1_published_ANSI_X3_221_1994); + + break; + case 0x0003: + sb.AppendLine(Localization.ATA_ATA_1_X3T9_2_781D_revision_4); + + break; + case 0x0004: + sb.AppendLine(Localization.ATA_2_published_ANSI_X3_279_1996); + + break; + case 0x0005: + sb.AppendLine(Localization.ATA_2_X3T10_948D_prior_to_revision_2k); + + break; + case 0x0006: + sb.AppendLine(Localization.ATA_3_X3T10_2008D_revision_1); + + break; + case 0x0007: + sb.AppendLine(Localization.ATA_2_X3T10_948D_revision_2k); + + break; + case 0x0008: + sb.AppendLine(Localization.ATA_3_X3T10_2008D_revision_0); + + break; + case 0x0009: + sb.AppendLine(Localization.ATA_2_X3T10_948D_revision_3); + + break; + case 0x000A: + sb.AppendLine(Localization.ATA_3_published_ANSI_X3_298_1997); + + break; + case 0x000B: + sb.AppendLine(Localization.ATA_3_X3T10_2008D_revision_6); + + break; + case 0x000C: + sb.AppendLine(Localization.ATA_3_X3T13_2008D_revision_7); + + break; + case 0x000D: + sb.AppendLine(Localization.ATA_ATAPI_4_X3T13_1153D_revision_6); + + break; + case 0x000E: + sb.AppendLine(Localization.ATA_ATAPI_4_T13_1153D_revision_13); + + break; + case 0x000F: + sb.AppendLine(Localization.ATA_ATAPI_4_X3T13_1153D_revision_7); + + break; + case 0x0010: + sb.AppendLine(Localization.ATA_ATAPI_4_T13_1153D_revision_18); + + break; + case 0x0011: + sb.AppendLine(Localization.ATA_ATAPI_4_T13_1153D_revision_15); + + break; + case 0x0012: + sb.AppendLine(Localization.ATA_ATAPI_4_published_ANSI_INCITS_317_1998); + + break; + case 0x0013: + sb.AppendLine(Localization.ATA_ATAPI_5_T13_1321D_revision_3); + + break; + case 0x0014: + sb.AppendLine(Localization.ATA_ATAPI_4_T13_1153D_revision_14); + + break; + case 0x0015: + sb.AppendLine(Localization.ATA_ATAPI_5_T13_1321D_revision_1); + + break; + case 0x0016: + sb.AppendLine(Localization.ATA_ATAPI_5_published_ANSI_INCITS_340_2000); + + break; + case 0x0017: + sb.AppendLine(Localization.ATA_ATAPI_4_T13_1153D_revision_17); + + break; + case 0x0018: + sb.AppendLine(Localization.ATA_ATAPI_6_T13_1410D_revision_0); + + break; + case 0x0019: + sb.AppendLine(Localization.ATA_ATAPI_6_T13_1410D_revision_3a); + + break; + case 0x001A: + sb.AppendLine(Localization.ATA_ATAPI_7_T13_1532D_revision_1); + + break; + case 0x001B: + sb.AppendLine(Localization.ATA_ATAPI_6_T13_1410D_revision_2); + + break; + case 0x001C: + sb.AppendLine(Localization.ATA_ATAPI_6_T13_1410D_revision_1); + + break; + case 0x001D: + sb.AppendLine(Localization.ATA_ATAPI_7_published_ANSI_INCITS_397_2005); + + break; + case 0x001E: + sb.AppendLine(Localization.ATA_ATAPI_7_T13_1532D_revision_0); + + break; + case 0x001F: + sb.AppendLine(Localization.ACS_3_Revision_3b); + + break; + case 0x0021: + sb.AppendLine(Localization.ATA_ATAPI_7_T13_1532D_revision_4a); + + break; + case 0x0022: + sb.AppendLine(Localization.ATA_ATAPI_6_published_ANSI_INCITS_361_2002); + + break; + case 0x0027: + sb.AppendLine(Localization.ATA8_ACS_revision_3c); + + break; + case 0x0028: + sb.AppendLine(Localization.ATA8_ACS_revision_6); + + break; + case 0x0029: + sb.AppendLine(Localization.ATA8_ACS_revision_4); + + break; + case 0x0031: + sb.AppendLine(Localization.ACS_2_Revision_2); + + break; + case 0x0033: + sb.AppendLine(Localization.ATA8_ACS_Revision_3e); + + break; + case 0x0039: + sb.AppendLine(Localization.ATA8_ACS_Revision_4c); + + break; + case 0x0042: + sb.AppendLine(Localization.ATA8_ACS_Revision_3f); + + break; + case 0x0052: + sb.AppendLine(Localization.ATA8_ACS_revision_3b); + + break; + case 0x006D: + sb.AppendLine(Localization.ACS_3_Revision_5); + + break; + case 0x0082: + sb.AppendLine(Localization.ACS_2_published_ANSI_INCITS_482_2012); + + break; + case 0x0107: + sb.AppendLine(Localization.ATA8_ACS_revision_2d); + + break; + case 0x0110: + sb.AppendLine(Localization.ACS_2_Revision_3); + + break; + case 0x011B: + sb.AppendLine(Localization.ACS_3_Revision_4); + + break; + default: + sb.AppendFormat(Localization.Unknown_ATA_revision_0, ATAID.MinorVersion).AppendLine(); + + break; + } + } + + switch((ATAID.TransportMajorVersion & 0xF000) >> 12) + { + case 0x0: + sb.Append(Localization.Parallel_ATA_device); + + if((ATAID.TransportMajorVersion & 0x0002) == 0x0002) sb.Append("ATA/ATAPI-7 "); + + if((ATAID.TransportMajorVersion & 0x0001) == 0x0001) sb.Append("ATA8-APT "); + + sb.AppendLine(); + + break; + case 0x1: + sb.Append(Localization.Serial_ATA_device); + + if((ATAID.TransportMajorVersion & 0x0001) == 0x0001) sb.Append("ATA8-AST "); + + if((ATAID.TransportMajorVersion & 0x0002) == 0x0002) sb.Append("SATA 1.0a "); + + if((ATAID.TransportMajorVersion & 0x0004) == 0x0004) sb.Append("SATA II Extensions "); + + if((ATAID.TransportMajorVersion & 0x0008) == 0x0008) sb.Append("SATA 2.5 "); + + if((ATAID.TransportMajorVersion & 0x0010) == 0x0010) sb.Append("SATA 2.6 "); + + if((ATAID.TransportMajorVersion & 0x0020) == 0x0020) sb.Append("SATA 3.0 "); + + if((ATAID.TransportMajorVersion & 0x0040) == 0x0040) sb.Append("SATA 3.1 "); + + sb.AppendLine(); + + break; + case 0xE: + sb.AppendLine(Localization.SATA_Express_device); + + break; + default: + sb.AppendFormat(Localization.Unknown_transport_type_0, (ATAID.TransportMajorVersion & 0xF000) >> 12) + .AppendLine(); + + break; + } + + if(atapi) + { + // Bits 12 to 8, SCSI Peripheral Device Type + switch((PeripheralDeviceTypes)(((ushort)ATAID.GeneralConfiguration & 0x1F00) >> 8)) + { + case PeripheralDeviceTypes.DirectAccess: //0x00, + sb.AppendLine(Localization.ATAPI_Direct_access_device); + + break; + case PeripheralDeviceTypes.SequentialAccess: //0x01, + sb.AppendLine(Localization.ATAPI_Sequential_access_device); + + break; + case PeripheralDeviceTypes.PrinterDevice: //0x02, + sb.AppendLine(Localization.ATAPI_Printer_device); + + break; + case PeripheralDeviceTypes.ProcessorDevice: //0x03, + sb.AppendLine(Localization.ATAPI_Processor_device); + + break; + case PeripheralDeviceTypes.WriteOnceDevice: //0x04, + sb.AppendLine(Localization.ATAPI_Write_once_device); + + break; + case PeripheralDeviceTypes.MultiMediaDevice: //0x05, + sb.AppendLine(Localization.ATAPI_CD_ROM_DVD_etc_device); + + break; + case PeripheralDeviceTypes.ScannerDevice: //0x06, + sb.AppendLine(Localization.ATAPI_Scanner_device); + + break; + case PeripheralDeviceTypes.OpticalDevice: //0x07, + sb.AppendLine(Localization.ATAPI_Optical_memory_device); + + break; + case PeripheralDeviceTypes.MediumChangerDevice: //0x08, + sb.AppendLine(Localization.ATAPI_Medium_change_device); + + break; + case PeripheralDeviceTypes.CommsDevice: //0x09, + sb.AppendLine(Localization.ATAPI_Communications_device); + + break; + case PeripheralDeviceTypes.PrePressDevice1: //0x0A, + sb.AppendLine(Localization.ATAPI_Graphics_arts_pre_press_device_defined_in_ASC_IT8); + + break; + case PeripheralDeviceTypes.PrePressDevice2: //0x0B, + sb.AppendLine(Localization.ATAPI_Graphics_arts_pre_press_device_defined_in_ASC_IT8); + + break; + case PeripheralDeviceTypes.ArrayControllerDevice: //0x0C, + sb.AppendLine(Localization.ATAPI_Array_controller_device); + + break; + case PeripheralDeviceTypes.EnclosureServiceDevice: //0x0D, + sb.AppendLine(Localization.ATAPI_Enclosure_services_device); + + break; + case PeripheralDeviceTypes.SimplifiedDevice: //0x0E, + sb.AppendLine(Localization.ATAPI_Simplified_direct_access_device); + + break; + case PeripheralDeviceTypes.OCRWDevice: //0x0F, + sb.AppendLine(Localization.ATAPI_Optical_card_reader_writer_device); + + break; + case PeripheralDeviceTypes.BridgingExpander: //0x10, + sb.AppendLine(Localization.ATAPI_Bridging_Expanders); + + break; + case PeripheralDeviceTypes.ObjectDevice: //0x11, + sb.AppendLine(Localization.ATAPI_Object_based_Storage_Device); + + break; + case PeripheralDeviceTypes.ADCDevice: //0x12, + sb.AppendLine(Localization.ATAPI_Automation_Drive_Interface); + + break; + case PeripheralDeviceTypes.WellKnownDevice: //0x1E, + sb.AppendLine(Localization.ATAPI_Well_known_logical_unit); + + break; + case PeripheralDeviceTypes.UnknownDevice: //0x1F + sb.AppendLine(Localization.ATAPI_Unknown_or_no_device_type); + + break; + default: + sb.AppendFormat(Localization.ATAPI_Unknown_device_type_field_value_0, + ((ushort)ATAID.GeneralConfiguration & 0x1F00) >> 8) + .AppendLine(); + + break; + } + + // ATAPI DRQ behaviour + switch(((ushort)ATAID.GeneralConfiguration & 0x60) >> 5) + { + case 0: + sb.AppendLine(Localization.Device_shall_set_DRQ_within_3_ms_of_receiving_PACKET); + + break; + case 1: + sb.AppendLine(Localization.Device_shall_assert_INTRQ_when_DRQ_is_set_to_one); + + break; + case 2: + sb.AppendLine(Localization.Device_shall_set_DRQ_within_50_µs_of_receiving_PACKET); + + break; + default: + sb.AppendFormat(Localization.Unknown_ATAPI_DRQ_behaviour_code_0, + ((ushort)ATAID.GeneralConfiguration & 0x60) >> 5) + .AppendLine(); + + break; + } + + // ATAPI PACKET size + switch((ushort)ATAID.GeneralConfiguration & 0x03) + { + case 0: + sb.AppendLine(Localization.ATAPI_device_uses_12_byte_command_packet); + + break; + case 1: + sb.AppendLine(Localization.ATAPI_device_uses_16_byte_command_packet); + + break; + default: + sb.AppendFormat(Localization.Unknown_ATAPI_packet_size_code_0, + (ushort)ATAID.GeneralConfiguration & 0x03) + .AppendLine(); + + break; + } + } + else if(!cfa) + { + if(minatalevel >= 5) + { + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .IncompleteResponse)) + sb.AppendLine(Localization.Incomplete_identify_response); + } + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .NonMagnetic)) + sb.AppendLine(Localization.Device_uses_non_magnetic_media); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .Removable)) + sb.AppendLine(Localization.Device_is_removable); + + if(minatalevel <= 5) + { + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .Fixed)) + sb.AppendLine(Localization.Device_is_fixed); + } + + if(ata1) + { + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .SlowIDE)) + sb.AppendLine(Localization.Device_transfer_rate_less_than_5_Mbs); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .FastIDE)) + sb.AppendLine(Localization.Device_transfer_rate_is_more_5_Mbs_less_10_Mbs); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .UltraFastIDE)) + sb.AppendLine(Localization.Device_transfer_rate_more_than_10_Mbs); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .SoftSector)) + sb.AppendLine(Localization.Device_is_soft_sectored); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .HardSector)) + sb.AppendLine(Localization.Device_is_hard_sectored); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .NotMFM)) + sb.AppendLine(Localization.Device_is_not_MFM_encoded); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .FormatGapReq)) + sb.AppendLine(Localization.Format_speed_tolerance_gap_is_required); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .TrackOffset)) + sb.AppendLine(Localization.Track_offset_option_is_available); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .DataStrobeOffset)) + sb.AppendLine(Localization.Data_strobe_offset_option_is_available); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .RotationalSpeedTolerance)) + sb.AppendLine(Localization.Rotational_speed_tolerance_is_higher_than_0_5_percent); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .SpindleControl)) + sb.AppendLine(Localization.Spindle_motor_control_is_implemented); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit + .HighHeadSwitch)) + sb.AppendLine(Localization.Head_switch_time_is_bigger_than_15_µs); + } + } + + if(ATAID.NominalRotationRate != 0x0000 && ATAID.NominalRotationRate != 0xFFFF) + { + if(ATAID.NominalRotationRate == 0x0001) + sb.AppendLine(Localization.Device_does_not_rotate); + else + sb.AppendFormat(Localization.Device_rotates_at_0_rpm, ATAID.NominalRotationRate).AppendLine(); + } + + uint logicalSectorSize = 0; + + if(!atapi) + { + uint physicalSectorSize; + + if((ATAID.PhysLogSectorSize & 0x8000) == 0x0000 && (ATAID.PhysLogSectorSize & 0x4000) == 0x4000) + { + if((ATAID.PhysLogSectorSize & 0x1000) == 0x1000) + { + if(ATAID.LogicalSectorWords <= 255 || ATAID.LogicalAlignment == 0xFFFF) + logicalSectorSize = 512; + else + logicalSectorSize = ATAID.LogicalSectorWords * 2; + } + else + logicalSectorSize = 512; + + if((ATAID.PhysLogSectorSize & 0x2000) == 0x2000) + physicalSectorSize = logicalSectorSize * (uint)Math.Pow(2, ATAID.PhysLogSectorSize & 0xF); + else + physicalSectorSize = logicalSectorSize; + } + else + { + logicalSectorSize = 512; + physicalSectorSize = 512; + } + + sb.AppendFormat(Localization.Physical_sector_size_0_bytes, physicalSectorSize).AppendLine(); + sb.AppendFormat(Localization.Logical_sector_size_0_bytes, logicalSectorSize).AppendLine(); + + if(logicalSectorSize != physicalSectorSize && + (ATAID.LogicalAlignment & 0x8000) == 0x0000 && + (ATAID.LogicalAlignment & 0x4000) == 0x4000) + { + sb.AppendFormat(Localization.Logical_sector_starts_at_offset_0_from_physical_sector, + ATAID.LogicalAlignment & 0x3FFF) + .AppendLine(); + } + + if(minatalevel <= 5) + { + if(ATAID.CurrentCylinders > 0 && ATAID is { CurrentHeads: > 0, CurrentSectorsPerTrack: > 0 }) + { + sb.AppendFormat(Localization.Cylinders_0_max_1_current, ATAID.Cylinders, ATAID.CurrentCylinders) + .AppendLine(); + + sb.AppendFormat(Localization.Heads_0_max_1_current, ATAID.Heads, ATAID.CurrentHeads).AppendLine(); + + sb.AppendFormat(Localization.Sectors_per_track_0_max_1_current, + ATAID.SectorsPerTrack, + ATAID.CurrentSectorsPerTrack) + .AppendLine(); + + sb.AppendFormat(Localization.Sectors_addressable_in_CHS_mode_0_max_1_current, + ATAID.Cylinders * ATAID.Heads * ATAID.SectorsPerTrack, + ATAID.CurrentSectors) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Cylinders_0, ATAID.Cylinders).AppendLine(); + sb.AppendFormat(Localization.Heads_0, ATAID.Heads).AppendLine(); + sb.AppendFormat(Localization.Sectors_per_track_0, ATAID.SectorsPerTrack).AppendLine(); + + sb.AppendFormat(Localization.Sectors_addressable_in_CHS_mode_0, + ATAID.Cylinders * ATAID.Heads * ATAID.SectorsPerTrack) + .AppendLine(); + } + } + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.LBASupport)) + sb.AppendFormat(Localization._0_sectors_in_28_bit_LBA_mode, ATAID.LBASectors).AppendLine(); + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) + sb.AppendFormat(Localization._0_sectors_in_48_bit_LBA_mode, ATAID.LBA48Sectors).AppendLine(); + + if(minatalevel <= 5) + { + if(ATAID.CurrentSectors > 0) + { + sb.AppendFormat(Localization.Device_size_in_CHS_mode_0_bytes_1_Mb_2_MiB, + (ulong)ATAID.CurrentSectors * logicalSectorSize, + (ulong)ATAID.CurrentSectors * logicalSectorSize / 1000 / 1000, + (ulong)ATAID.CurrentSectors * 512 / 1024 / 1024) + .AppendLine(); + } + else + { + var currentSectors = (ulong)(ATAID.Cylinders * ATAID.Heads * ATAID.SectorsPerTrack); + + sb.AppendFormat(Localization.Device_size_in_CHS_mode_0_bytes_1_Mb_2_MiB, + currentSectors * logicalSectorSize, + currentSectors * logicalSectorSize / 1000 / 1000, + currentSectors * 512 / 1024 / 1024) + .AppendLine(); + } + } + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.LBASupport)) + { + switch((ulong)ATAID.LBASectors * logicalSectorSize / 1024 / 1024) + { + case > 1000000: + sb.AppendFormat(Localization.Device_size_in_28_bit_LBA_mode_0_bytes_1_Tb_2_TiB, + (ulong)ATAID.LBASectors * logicalSectorSize, + (ulong)ATAID.LBASectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000, + (ulong)ATAID.LBASectors * 512 / 1024 / 1024 / 1024 / 1024) + .AppendLine(); + + break; + case > 1000: + sb.AppendFormat(Localization.Device_size_in_28_bit_LBA_mode_0_bytes_1_Gb_2_GiB, + (ulong)ATAID.LBASectors * logicalSectorSize, + (ulong)ATAID.LBASectors * logicalSectorSize / 1000 / 1000 / 1000, + (ulong)ATAID.LBASectors * 512 / 1024 / 1024 / 1024) + .AppendLine(); + + break; + default: + sb.AppendFormat(Localization.Device_size_in_28_bit_LBA_mode_0_bytes_1_Mb_2_MiB, + (ulong)ATAID.LBASectors * logicalSectorSize, + (ulong)ATAID.LBASectors * logicalSectorSize / 1000 / 1000, + (ulong)ATAID.LBASectors * 512 / 1024 / 1024) + .AppendLine(); + + break; + } + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) + { + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ExtSectors)) + { + switch(ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024) + { + case > 1000000: + sb.AppendFormat(Localization.Device_size_in_48_bit_LBA_mode_0_bytes_1_Tb_2_TiB, + ATAID.ExtendedUserSectors * logicalSectorSize, + ATAID.ExtendedUserSectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000, + ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024 / 1024 / 1024) + .AppendLine(); + + break; + case > 1000: + sb.AppendFormat(Localization.Device_size_in_48_bit_LBA_mode_0_bytes_1_Gb_2_GiB, + ATAID.ExtendedUserSectors * logicalSectorSize, + ATAID.ExtendedUserSectors * logicalSectorSize / 1000 / 1000 / 1000, + ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024 / 1024) + .AppendLine(); + + break; + default: + sb.AppendFormat(Localization.Device_size_in_48_bit_LBA_mode_0_bytes_1_Mb_2_MiB, + ATAID.ExtendedUserSectors * logicalSectorSize, + ATAID.ExtendedUserSectors * logicalSectorSize / 1000 / 1000, + ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024) + .AppendLine(); + + break; + } + } + else + { + switch(ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024) + { + case > 1000000: + sb.AppendFormat(Localization.Device_size_in_48_bit_LBA_mode_0_bytes_1_Tb_2_TiB, + ATAID.LBA48Sectors * logicalSectorSize, + ATAID.LBA48Sectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000, + ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024 / 1024 / 1024) + .AppendLine(); + + break; + case > 1000: + sb.AppendFormat(Localization.Device_size_in_48_bit_LBA_mode_0_bytes_1_Gb_2_GiB, + ATAID.LBA48Sectors * logicalSectorSize, + ATAID.LBA48Sectors * logicalSectorSize / 1000 / 1000 / 1000, + ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024 / 1024) + .AppendLine(); + + break; + default: + sb.AppendFormat(Localization.Device_size_in_48_bit_LBA_mode_0_bytes_1_Mb_2_MiB, + ATAID.LBA48Sectors * logicalSectorSize, + ATAID.LBA48Sectors * logicalSectorSize / 1000 / 1000, + ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024) + .AppendLine(); + + break; + } + } + } + + if(ata1 || cfa) + { + if(cfa) sb.AppendFormat(Localization._0_sectors_in_card, ATAID.SectorsPerCard).AppendLine(); + + if(ATAID.UnformattedBPT > 0) + sb.AppendFormat(Localization._0_bytes_per_unformatted_track, ATAID.UnformattedBPT).AppendLine(); + + if(ATAID.UnformattedBPS > 0) + sb.AppendFormat(Localization._0_bytes_per_unformatted_sector, ATAID.UnformattedBPS).AppendLine(); + } + } + + if((ushort)ATAID.SpecificConfiguration != 0x0000 && (ushort)ATAID.SpecificConfiguration != 0xFFFF) + { + switch(ATAID.SpecificConfiguration) + { + case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum.RequiresSetIncompleteResponse: + sb.AppendLine(Localization + .Device_requires_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_incomplete); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum.RequiresSetCompleteResponse: + sb.AppendLine(Localization + .Device_requires_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_complete); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum + .NotRequiresSetIncompleteResponse: + sb.AppendLine(Localization + .Device_does_not_require_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_incomplete); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum.NotRequiresSetCompleteResponse: + sb.AppendLine(Localization + .Device_does_not_require_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_complete); + + break; + default: + sb.AppendFormat(Localization.Unknown_device_specific_configuration_0, + (ushort)ATAID.SpecificConfiguration) + .AppendLine(); + + break; + } + } + + // Obsolete since ATA-2, however, it is yet used in ATA-8 devices + if(ATAID.BufferSize != 0x0000 && + ATAID.BufferSize != 0xFFFF && + ATAID.BufferType != 0x0000 && + ATAID.BufferType != 0xFFFF) + { + switch(ATAID.BufferType) + { + case 1: + sb.AppendFormat(Localization._0_KiB_of_single_ported_single_sector_buffer, + ATAID.BufferSize * 512 / 1024) + .AppendLine(); + + break; + case 2: + sb.AppendFormat(Localization._0_KiB_of_dual_ported_multi_sector_buffer, + ATAID.BufferSize * 512 / 1024) + .AppendLine(); + + break; + case 3: + sb.AppendFormat(Localization._0_KiB_of_dual_ported_multi_sector_buffer_with_read_caching, + ATAID.BufferSize * 512 / 1024) + .AppendLine(); + + break; + default: + sb.AppendFormat(Localization._0_KiB_of_unknown_type_1_buffer, + ATAID.BufferSize * 512 / 1024, + ATAID.BufferType) + .AppendLine(); + + break; + } + } + + if(ATAID.EccBytes != 0x0000 && ATAID.EccBytes != 0xFFFF) + sb.AppendFormat(Localization.READ_WRITE_LONG_has_0_extra_bytes, ATAID.EccBytes).AppendLine(); + + sb.AppendLine(); + + sb.Append(Localization.Device_capabilities); + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.StandardStandbyTimer)) + sb.AppendLine().Append(Localization.Standby_time_values_are_standard); + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.IORDY)) + { + sb.AppendLine() + .Append(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit + .CanDisableIORDY) + ? Localization.IORDY_is_supported_and_can_be_disabled + : Localization.IORDY_is_supported); + } + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.DMASupport)) + sb.AppendLine().Append(Localization.DMA_is_supported); + + if(ATAID.Capabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit2.MustBeSet) && + !ATAID.Capabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit2.MustBeClear)) + { + if(ATAID.Capabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit2 + .SpecificStandbyTimer)) + sb.AppendLine().Append(Localization.Device_indicates_a_specific_minimum_standby_timer_value); + } + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.MultipleValid)) + { + sb.AppendLine() + .AppendFormat(Localization.A_maximum_of_0_sectors_can_be_transferred_per_interrupt_on_READ_WRITE_MULTIPLE, + ATAID.MultipleSectorNumber); + + sb.AppendLine() + .AppendFormat(Localization.Device_supports_setting_a_maximum_of_0_sectors, ATAID.MultipleMaxSectors); + } + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.PhysicalAlignment1) || + ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.PhysicalAlignment0)) + { + sb.AppendLine() + .AppendFormat(Localization.Long_Physical_Alignment_setting_is_0, (ushort)ATAID.Capabilities & 0x03); + } + + if(ata1) + { + if(ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit + .TrustedComputing)) + sb.AppendLine().Append(Localization.Device_supports_doubleword_IO); + } + + if(atapi) + { + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.InterleavedDMA)) + sb.AppendLine().Append(Localization.ATAPI_device_supports_interleaved_DMA); + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.CommandQueue)) + sb.AppendLine().Append(Localization.ATAPI_device_supports_command_queueing); + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.OverlapOperation)) + sb.AppendLine().Append(Localization.ATAPI_device_supports_overlapped_operations); + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit + .RequiresATASoftReset)) + sb.AppendLine().Append(Localization.ATAPI_device_requires_ATA_software_reset); + } + + if(minatalevel <= 3) + { + sb.AppendLine().AppendFormat(Localization.PIO_timing_mode_0, ATAID.PIOTransferTimingMode); + sb.AppendLine().AppendFormat(Localization.DMA_timing_mode_0, ATAID.DMATransferTimingMode); + } + + sb.AppendLine().Append(Localization.Advanced_PIO); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) sb.Append("PIO0 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) sb.Append("PIO1 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) sb.Append("PIO2 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) sb.Append("PIO3 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) sb.Append("PIO4 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) sb.Append("PIO5 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) sb.Append("PIO6 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) sb.Append("PIO7 "); + + if(minatalevel <= 3 && !atapi) + { + sb.AppendLine().Append(Localization.Single_word_DMA); + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + { + sb.Append("DMA0 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + sb.Append(Localization._active_); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + { + sb.Append("DMA1 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + sb.Append(Localization._active_); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + { + sb.Append("DMA2 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + sb.Append(Localization._active_); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + { + sb.Append("DMA3 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + sb.Append(Localization._active_); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + { + sb.Append("DMA4 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + sb.Append(Localization._active_); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + { + sb.Append("DMA5 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + sb.Append(Localization._active_); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + { + sb.Append("DMA6 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + sb.Append(Localization._active_); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + { + sb.Append("DMA7 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + sb.Append(Localization._active_); + } + } + + sb.AppendLine().Append(Localization.Multi_word_DMA); + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + { + sb.Append("MDMA0 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + sb.Append(Localization._active_); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + { + sb.Append("MDMA1 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + sb.Append(Localization._active_); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + { + sb.Append("MDMA2 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + sb.Append(Localization._active_); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + { + sb.Append("MDMA3 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + sb.Append(Localization._active_); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + { + sb.Append("MDMA4 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + sb.Append(Localization._active_); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + { + sb.Append("MDMA5 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + sb.Append(Localization._active_); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + { + sb.Append("MDMA6 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + sb.Append(Localization._active_); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + { + sb.Append("MDMA7 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + sb.Append(Localization._active_); + } + + sb.AppendLine().Append(Localization.Ultra_DMA); + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + { + sb.Append("UDMA0 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + sb.Append(Localization._active_); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + { + sb.Append("UDMA1 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + sb.Append(Localization._active_); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + { + sb.Append("UDMA2 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + sb.Append(Localization._active_); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + { + sb.Append("UDMA3 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + sb.Append(Localization._active_); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + { + sb.Append("UDMA4 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + sb.Append(Localization._active_); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + { + sb.Append("UDMA5 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + sb.Append(Localization._active_); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + { + sb.Append("UDMA6 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + sb.Append(Localization._active_); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + { + sb.Append("UDMA7 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + sb.Append(Localization._active_); + } + + if(ATAID.MinMDMACycleTime != 0 && ATAID.RecMDMACycleTime != 0) + { + sb.AppendLine() + .AppendFormat(Localization.At_minimum_0_ns_transfer_cycle_time_per_word_in_MDMA_1_ns_recommended, + ATAID.MinMDMACycleTime, + ATAID.RecMDMACycleTime); + } + + if(ATAID.MinPIOCycleTimeNoFlow != 0) + { + sb.AppendLine() + .AppendFormat(Localization.At_minimum_0_ns_transfer_cycle_time_per_word_in_PIO_without_flow_control, + ATAID.MinPIOCycleTimeNoFlow); + } + + if(ATAID.MinPIOCycleTimeFlow != 0) + { + sb.AppendLine() + .AppendFormat(Localization.At_minimum_0_ns_transfer_cycle_time_per_word_in_PIO_with_IORDY_flow_control, + ATAID.MinPIOCycleTimeFlow); + } + + if(ATAID.MaxQueueDepth != 0) + sb.AppendLine().AppendFormat(Localization._0_depth_of_queue_maximum, ATAID.MaxQueueDepth + 1); + + if(atapi) + { + if(ATAID.PacketBusRelease != 0) + { + sb.AppendLine() + .AppendFormat(Localization._0_ns_typical_to_release_bus_from_receipt_of_PACKET, + ATAID.PacketBusRelease); + } + + if(ATAID.ServiceBusyClear != 0) + { + sb.AppendLine() + .AppendFormat(Localization._0_ns_typical_to_clear_BSY_bit_from_receipt_of_SERVICE, + ATAID.ServiceBusyClear); + } + } + + if((ATAID.TransportMajorVersion & 0xF000) >> 12 == 0x1 || (ATAID.TransportMajorVersion & 0xF000) >> 12 == 0xE) + { + if(!ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.Clear)) + { + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .Gen1Speed)) + sb.AppendLine().Append(Localization.SATA_1_5Gbs_is_supported); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .Gen2Speed)) + sb.AppendLine().Append(Localization.SATA_3_0Gbs_is_supported); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .Gen3Speed)) + sb.AppendLine().Append(Localization.SATA_6_0Gbs_is_supported); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .PowerReceipt)) + { + sb.AppendLine() + .Append(Localization.Receipt_of_host_initiated_power_management_requests_is_supported); + } + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .PHYEventCounter)) + sb.AppendLine().Append(Localization.PHY_Event_counters_are_supported); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .HostSlumbTrans)) + { + sb.AppendLine() + .Append(Localization.Supports_host_automatic_partial_to_slumber_transitions_is_supported); + } + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .DevSlumbTrans)) + { + sb.AppendLine() + .Append(Localization.Supports_device_automatic_partial_to_slumber_transitions_is_supported); + } + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.NCQ)) + { + sb.AppendLine().Append(Localization.NCQ_is_supported); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .NCQPriority)) + sb.AppendLine().Append(Localization.NCQ_priority_is_supported); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .UnloadNCQ)) + sb.AppendLine().Append(Localization.Unload_is_supported_with_outstanding_NCQ_commands); + } + } + + if(!ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2.Clear)) + { + if(!ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .Clear) && + ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.NCQ)) + { + if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2 + .NCQMgmt)) + sb.AppendLine().Append(Localization.NCQ_queue_management_is_supported); + + if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2 + .NCQStream)) + sb.AppendLine().Append(Localization.NCQ_streaming_is_supported); + } + + if(atapi) + { + if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2 + .HostEnvDetect)) + sb.AppendLine().Append(Localization.ATAPI_device_supports_host_environment_detection); + + if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2 + .DevAttSlimline)) + { + sb.AppendLine() + .Append(Localization.ATAPI_device_supports_attention_on_slimline_connected_devices); + } + } + + //sb.AppendFormat("Negotiated speed = {0}", ((ushort)ATAID.SATACapabilities2 & 0x000E) >> 1); + } + } + + if(ATAID.InterseekDelay != 0x0000 && ATAID.InterseekDelay != 0xFFFF) + { + sb.AppendLine() + .AppendFormat(Localization._0_microseconds_of_interseek_delay_for_ISO_7779_acoustic_testing, + ATAID.InterseekDelay); + } + + if((ushort)ATAID.DeviceFormFactor != 0x0000 && (ushort)ATAID.DeviceFormFactor != 0xFFFF) + { + switch(ATAID.DeviceFormFactor) + { + case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.FiveAndQuarter: + sb.AppendLine().Append(Localization.Device_nominal_size_is_5_25); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.ThreeAndHalf: + sb.AppendLine().Append(Localization.Device_nominal_size_is_3_5); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.TwoAndHalf: + sb.AppendLine().Append(Localization.Device_nominal_size_is_2_5); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.OnePointEight: + sb.AppendLine().Append(Localization.Device_nominal_size_is_1_8); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.LessThanOnePointEight: + sb.AppendLine().Append(Localization.Device_nominal_size_is_smaller_than_1_8); + + break; + default: + sb.AppendLine() + .AppendFormat(Localization.Device_nominal_size_field_value_0_is_unknown, ATAID.DeviceFormFactor); + + break; + } + } + + if(atapi) + { + if(ATAID.ATAPIByteCount > 0) + sb.AppendLine().AppendFormat(Localization._0_bytes_count_limit_for_ATAPI, ATAID.ATAPIByteCount); + } + + if(cfa) + { + if((ATAID.CFAPowerMode & 0x8000) == 0x8000) + { + sb.AppendLine().Append(Localization.CompactFlash_device_supports_power_mode_1); + + if((ATAID.CFAPowerMode & 0x2000) == 0x2000) + sb.AppendLine().Append(Localization.CompactFlash_power_mode_1_required_for_one_or_more_commands); + + if((ATAID.CFAPowerMode & 0x1000) == 0x1000) + sb.AppendLine().Append(Localization.CompactFlash_power_mode_1_is_disabled); + + sb.AppendLine() + .AppendFormat(Localization.CompactFlash_device_uses_a_maximum_of_0_mA, ATAID.CFAPowerMode & 0x0FFF); + } + } + + sb.AppendLine(); + + sb.AppendLine().Append(Localization.Command_set_and_features); + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Nop)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Nop) + ? Localization.NOP_is_supported_and_enabled + : Localization.NOP_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.ReadBuffer)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.ReadBuffer) + ? Localization.READ_BUFFER_is_supported_and_enabled + : Localization.READ_BUFFER_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteBuffer)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit + .WriteBuffer) + ? Localization.WRITE_BUFFER_is_supported_and_enabled + : Localization.WRITE_BUFFER_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.HPA)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.HPA) + ? Localization.Host_Protected_Area_is_supported_and_enabled + : Localization.Host_Protected_Area_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.DeviceReset)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit + .DeviceReset) + ? Localization.DEVICE_RESET_is_supported_and_enabled + : Localization._); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Service)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Service) + ? Localization.SERVICE_interrupt_is_supported_and_enabled + : Localization.SERVICE_interrupt_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Release)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Release) + ? Localization.Release_is_supported_and_enabled + : Localization.Release_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.LookAhead)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.LookAhead) + ? Localization.Look_ahead_read_is_supported_and_enabled + : Localization.Look_ahead_read_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteCache)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteCache) + ? Localization.Write_cache_is_supported_and_enabled + : Localization.Write_cache_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Packet)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Packet) + ? Localization.PACKET_is_supported_and_enabled + : Localization.PACKET_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.PowerManagement)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit + .PowerManagement) + ? Localization.Power_management_is_supported_and_enabled + : Localization.Power_management_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.RemovableMedia)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit + .RemovableMedia) + ? Localization.Removable_media_feature_set_is_supported_and_enabled + : Localization.Removable_media_feature_set_is_supported); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SecurityMode)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit + .SecurityMode) + ? Localization.Security_mode_is_supported_and_enabled + : Localization.Security_mode_is_supported); + } + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.LBASupport)) + sb.AppendLine().Append(Localization._28_bit_LBA_is_supported); + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.MustBeSet) && + !ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.MustBeClear)) + { + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .LBA48) + ? Localization._48_bit_LBA_is_supported_and_enabled + : Localization._48_bit_LBA_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.FlushCache)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .FlushCache) + ? Localization.FLUSH_CACHE_is_supported_and_enabled + : Localization.FLUSH_CACHE_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.FlushCacheExt)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .FlushCacheExt) + ? Localization.FLUSH_CACHE_EXT_is_supported_and_enabled + : Localization.FLUSH_CACHE_EXT_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.DCO)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.DCO) + ? Localization.Device_Configuration_Overlay_feature_set_is_supported_and_enabled + : Localization.Device_Configuration_Overlay_feature_set_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.AAM)) + { + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.AAM)) + { + sb.AppendLine() + .AppendFormat(Localization + .Automatic_Acoustic_Management_is_supported_and_enabled_with_value_0_vendor_recommends_1, + ATAID.CurrentAAM, + ATAID.RecommendedAAM); + } + else + sb.AppendLine().Append(Localization.Automatic_Acoustic_Management_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.SetMax)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .SetMax) + ? Localization.SET_MAX_security_extension_is_supported_and_enabled + : Localization.SET_MAX_security_extension_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .AddressOffsetReservedAreaBoot)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .AddressOffsetReservedAreaBoot) + ? Localization.Address_Offset_Reserved_Area_Boot_is_supported_and_enabled + : Localization.Address_Offset_Reserved_Area_Boot_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.SetFeaturesRequired)) + sb.AppendLine().Append(Localization.SET_FEATURES_is_required_before_spin_up); + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.PowerUpInStandby)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .PowerUpInStandby) + ? Localization.Power_up_in_standby_is_supported_and_enabled + : Localization.Power_up_in_standby_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.RemovableNotification)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .RemovableNotification) + ? Localization.Removable_Media_Status_Notification_is_supported_and_enabled + : Localization.Removable_Media_Status_Notification_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.APM)) + { + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.APM)) + { + sb.AppendLine() + .AppendFormat(Localization.Advanced_Power_Management_is_supported_and_enabled_with_value_0, + ATAID.CurrentAPM); + } + else + sb.AppendLine().Append(Localization.Advanced_Power_Management_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.CompactFlash)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .CompactFlash) + ? Localization.CompactFlash_feature_set_is_supported_and_enabled + : Localization.CompactFlash_feature_set_is_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.RWQueuedDMA)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .RWQueuedDMA) + ? Localization.READ_DMA_QUEUED_and_WRITE_DMA_QUEUED_are_supported_and_enabled + : Localization.READ_DMA_QUEUED_and_WRITE_DMA_QUEUED_are_supported); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.DownloadMicrocode)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2 + .DownloadMicrocode) + ? Localization.DOWNLOAD_MICROCODE_is_supported_and_enabled + : Localization.DOWNLOAD_MICROCODE_is_supported); + } + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SMART)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SMART) + ? Localization.SMART_is_supported_and_enabled + : Localization.SMART_is_supported); + } + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit.Supported)) + sb.AppendLine().Append(Localization.SMART_Command_Transport_is_supported); + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeSet) && + !ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeClear)) + { + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.SMARTSelfTest)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3 + .SMARTSelfTest) + ? Localization.SMART_self_testing_is_supported_and_enabled + : Localization.SMART_self_testing_is_supported); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.SMARTLog)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3 + .SMARTLog) + ? Localization.SMART_error_logging_is_supported_and_enabled + : Localization.SMART_error_logging_is_supported); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.IdleImmediate)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3 + .IdleImmediate) + ? Localization.IDLE_IMMEDIATE_with_UNLOAD_FEATURE_is_supported_and_enabled + : Localization.IDLE_IMMEDIATE_with_UNLOAD_FEATURE_is_supported); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.WriteURG)) + sb.AppendLine().Append(Localization.URG_bit_is_supported_in_WRITE_STREAM_DMA_EXT_and_WRITE_STREAM_EXT); + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.ReadURG)) + sb.AppendLine().Append(Localization.URG_bit_is_supported_in_READ_STREAM_DMA_EXT_and_READ_STREAM_EXT); + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.WWN)) + sb.AppendLine().Append(Localization.Device_has_a_World_Wide_Name); + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.FUAWriteQ)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3 + .FUAWriteQ) + ? Localization.WRITE_DMA_QUEUED_FUA_EXT_is_supported_and_enabled + : Localization.WRITE_DMA_QUEUED_FUA_EXT_is_supported); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.FUAWrite)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3 + .FUAWrite) + ? Localization.WRITE_DMA_FUA_EXT_and_WRITE_MULTIPLE_FUA_EXT_are_supported_and_enabled + : Localization.WRITE_DMA_FUA_EXT_and_WRITE_MULTIPLE_FUA_EXT_are_supported); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.GPL)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.GPL) + ? Localization.General_Purpose_Logging_is_supported_and_enabled + : Localization.General_Purpose_Logging_is_supported); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.Streaming)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3 + .Streaming) + ? Localization.Streaming_feature_set_is_supported_and_enabled + : Localization.Streaming_feature_set_is_supported); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MCPT)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MCPT) + ? Localization.Media_Card_Pass_Through_command_set_is_supported_and_enabled + : Localization.Media_Card_Pass_Through_command_set_is_supported); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MediaSerial)) + { + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3 + .MediaSerial)) + sb.AppendLine().Append(Localization.Media_Serial_is_supported_and_valid); + + sb.AppendLine().Append(Localization.Media_Serial_is_supported); + } + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.MustBeSet) && + !ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.MustBeClear)) + { + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DSN)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DSN) + ? Localization.DSN_feature_set_is_supported_and_enabled + : Localization.DSN_feature_set_is_supported); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.AMAC)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.AMAC) + ? Localization.Accessible_Max_Address_Configuration_is_supported_and_enabled + : Localization.Accessible_Max_Address_Configuration_is_supported); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.ExtPowerCond)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4 + .ExtPowerCond) + ? Localization.Extended_Power_Conditions_are_supported_and_enabled + : Localization.Extended_Power_Conditions_are_supported); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.ExtStatusReport)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4 + .ExtStatusReport) + ? Localization.Extended_Status_Reporting_is_supported_and_enabled + : Localization.Extended_Status_Reporting_is_supported); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.FreeFallControl)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4 + .FreeFallControl) + ? Localization.Free_fall_control_feature_set_is_supported_and_enabled + : Localization.Free_fall_control_feature_set_is_supported); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4 + .SegmentedDownloadMicrocode)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4 + .SegmentedDownloadMicrocode) + ? Localization.Segmented_feature_in_DOWNLOAD_MICROCODE_is_supported_and_enabled + : Localization.Segmented_feature_in_DOWNLOAD_MICROCODE_is_supported); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.RWDMAExtGpl)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4 + .RWDMAExtGpl) + ? Localization.READ_WRITE_DMA_EXT_GPL_are_supported_and_enabled + : Localization.READ_WRITE_DMA_EXT_GPL_are_supported); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WriteUnc)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4 + .WriteUnc) + ? Localization.WRITE_UNCORRECTABLE_is_supported_and_enabled + : Localization.WRITE_UNCORRECTABLE_is_supported); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WRV)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WRV) + ? Localization.Write_Read_Verify_is_supported_and_enabled + : Localization.Write_Read_Verify_is_supported); + + sb.AppendLine() + .AppendFormat(Localization._0_sectors_for_Write_Read_Verify_mode_two, ATAID.WRVSectorCountMode2); + + sb.AppendLine() + .AppendFormat(Localization._0_sectors_for_Write_Read_Verify_mode_three, ATAID.WRVSectorCountMode3); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WRV)) + sb.AppendLine().AppendFormat(Localization.Current_Write_Read_Verify_mode_0, ATAID.WRVMode); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DT1825)) + { + sb.AppendLine() + .Append(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4 + .DT1825) + ? Localization.DT1825_is_supported_and_enabled + : Localization.DT1825_is_supported); + } + } + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.BlockErase)) + sb.AppendLine().Append(Localization.BLOCK_ERASE_EXT_is_supported); + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.Overwrite)) + sb.AppendLine().Append(Localization.OVERWRITE_EXT_is_supported); + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.CryptoScramble)) + sb.AppendLine().Append(Localization.CRYPTO_SCRAMBLE_EXT_is_supported); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.DeviceConfDMA)) + { + sb.AppendLine() + .Append(Localization.DEVICE_CONFIGURATION_IDENTIFY_DMA_and_DEVICE_CONFIGURATION_SET_DMA_are_supported); + } + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ReadBufferDMA)) + sb.AppendLine().Append(Localization.READ_BUFFER_DMA_is_supported); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.WriteBufferDMA)) + sb.AppendLine().Append(Localization.WRITE_BUFFER_DMA_is_supported); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.DownloadMicroCodeDMA)) + sb.AppendLine().Append(Localization.DOWNLOAD_MICROCODE_DMA_is_supported); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.SetMaxDMA)) + sb.AppendLine().Append(Localization.SET_PASSWORD_DMA_and_SET_UNLOCK_DMA_are_supported); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.Ata28)) + sb.AppendLine().Append(Localization.Not_all_28_bit_commands_are_supported); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.CFast)) + sb.AppendLine().Append(Localization.Device_follows_CFast_specification); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.IEEE1667)) + sb.AppendLine().Append(Localization.Device_follows_IEEE_1667); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.DeterministicTrim)) + { + sb.AppendLine().Append(Localization.Read_after_TRIM_is_deterministic); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ReadZeroTrim)) + sb.AppendLine().Append(Localization.Read_after_TRIM_returns_empty_data); + } + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.LongPhysSectorAligError)) + sb.AppendLine().Append(Localization.Device_supports_Long_Physical_Sector_Alignment_Error_Reporting_Control); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.Encrypted)) + sb.AppendLine().Append(Localization.Device_encrypts_all_user_data); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.AllCacheNV)) + sb.AppendLine().Append(Localization.Device_s_write_cache_is_non_volatile); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ZonedBit0) || + ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ZonedBit1)) + sb.AppendLine().Append(Localization.Device_is_zoned); + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.Sanitize)) + { + sb.AppendLine().Append(Localization.Sanitize_feature_set_is_supported); + + sb.AppendLine() + .Append(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3 + .SanitizeCommands) + ? Localization.Sanitize_commands_are_specified_by_ACS_3_or_higher + : Localization.Sanitize_commands_are_specified_by_ACS_2); + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3 + .SanitizeAntifreeze)) + sb.AppendLine().Append(Localization.SANITIZE_ANTIFREEZE_LOCK_EXT_is_supported); + } + + if(!ata1 && maxatalevel >= 8) + { + if(ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit.Set) && + !ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit.Clear) && + ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit + .TrustedComputing)) + sb.AppendLine().Append(Localization.Trusted_Computing_feature_set_is_supported); + } + + if((ATAID.TransportMajorVersion & 0xF000) >> 12 == 0x1 || (ATAID.TransportMajorVersion & 0xF000) >> 12 == 0xE) + { + if(!ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.Clear)) + { + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit + .ReadLogDMAExt)) + sb.AppendLine().Append(Localization.READ_LOG_DMA_EXT_is_supported); + } + + if(!ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2.Clear)) + { + if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2 + .FPDMAQ)) + sb.AppendLine().Append(Localization.RECEIVE_FPDMA_QUEUED_and_SEND_FPDMA_QUEUED_are_supported); + } + + if(!ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.Clear)) + { + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit + .NonZeroBufferOffset)) + { + sb.AppendLine() + .Append(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit + .NonZeroBufferOffset) + ? Localization.Non_zero_buffer_offsets_are_supported_and_enabled + : Localization.Non_zero_buffer_offsets_are_supported); + } + + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.DMASetup)) + { + sb.AppendLine() + .Append(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit + .DMASetup) + ? Localization.DMA_Setup_auto_activation_is_supported_and_enabled + : Localization.DMA_Setup_auto_activation_is_supported); + } + + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.InitPowerMgmt)) + { + sb.AppendLine() + .Append(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit + .InitPowerMgmt) + ? Localization.Device_initiated_power_management_is_supported_and_enabled + : Localization.Device_initiated_power_management_is_supported); + } + + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.InOrderData)) + { + sb.AppendLine() + .Append(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit + .InOrderData) + ? Localization.In_order_data_delivery_is_supported_and_enabled + : Localization.In_order_data_delivery_is_supported); + } + + switch(atapi) + { + case false: + { + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit + .HardwareFeatureControl)) + { + sb.AppendLine() + .Append(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify + .SATAFeaturesBit.HardwareFeatureControl) + ? Localization.Hardware_Feature_Control_is_supported_and_enabled + : Localization.Hardware_Feature_Control_is_supported); + } + + break; + } + case true: + { + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit + .AsyncNotification)) + { + sb.AppendLine() + .Append(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify + .SATAFeaturesBit.AsyncNotification) + ? Localization.Asynchronous_notification_is_supported_and_enabled + : Localization.Asynchronous_notification_is_supported); + } + + break; + } + } + + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit + .SettingsPreserve)) + { + sb.AppendLine() + .Append(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit + .SettingsPreserve) + ? Localization.Software_Settings_Preservation_is_supported_and_enabled + : Localization.Software_Settings_Preservation_is_supported); + } + + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.NCQAutoSense)) + sb.AppendLine().Append(Localization.NCQ_Autosense_is_supported); + + if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit + .EnabledSlumber)) + sb.AppendLine().Append(Localization.Automatic_Partial_to_Slumber_transitions_are_enabled); + } + } + + if((ATAID.RemovableStatusSet & 0x03) > 0) + sb.AppendLine().Append(Localization.Removable_Media_Status_Notification_feature_set_is_supported); + + if(ATAID.FreeFallSensitivity != 0x00 && ATAID.FreeFallSensitivity != 0xFF) + sb.AppendLine().AppendFormat(Localization.Free_fall_sensitivity_set_to_0, ATAID.FreeFallSensitivity); + + if(ATAID.DataSetMgmt.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.DataSetMgmtBit.Trim)) + sb.AppendLine().Append("TRIM is supported"); + + if(ATAID.DataSetMgmtSize > 0) + { + sb.AppendLine() + .AppendFormat(Localization.DATA_SET_MANAGEMENT_can_receive_a_maximum_of_0_blocks_of_512_bytes, + ATAID.DataSetMgmtSize); + } + + sb.AppendLine().AppendLine(); + + if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Supported)) + { + sb.AppendLine(Localization.Security); + + if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Enabled)) + { + sb.AppendLine(Localization.Security_is_enabled); + + sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit + .Locked) + ? Localization.Security_is_locked + : Localization.Security_is_not_locked); + + sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit + .Frozen) + ? Localization.Security_is_frozen + : Localization.Security_is_not_frozen); + + sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit + .Expired) + ? Localization.Security_count_has_expired + : Localization.Security_count_has_not_expired); + + sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit + .Maximum) + ? Localization.Security_level_is_maximum + : Localization.Security_level_is_high); + } + else + sb.AppendLine(Localization.Security_is_not_enabled); + + if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Enhanced)) + sb.AppendLine(Localization.Supports_enhanced_security_erase); + + sb.AppendFormat(Localization._0_minutes_to_complete_secure_erase, ATAID.SecurityEraseTime * 2).AppendLine(); + + if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Enhanced)) + { + sb.AppendFormat(Localization._0_minutes_to_complete_enhanced_secure_erase, + ATAID.EnhancedSecurityEraseTime * 2) + .AppendLine(); + } + + sb.AppendFormat(Localization.Master_password_revision_code_0, ATAID.MasterPasswordRevisionCode) + .AppendLine(); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeSet) && + !ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeClear) && + ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.Streaming)) + { + sb.AppendLine().AppendLine(Localization.Streaming); + sb.AppendFormat(Localization.Minimum_request_size_is_0, ATAID.StreamMinReqSize); + sb.AppendFormat(Localization.Streaming_transfer_time_in_PIO_is_0, ATAID.StreamTransferTimePIO); + sb.AppendFormat(Localization.Streaming_transfer_time_in_DMA_is_0, ATAID.StreamTransferTimeDMA); + sb.AppendFormat(Localization.Streaming_access_latency_is_0, ATAID.StreamAccessLatency); + sb.AppendFormat(Localization.Streaming_performance_granularity_is_0, ATAID.StreamPerformanceGranularity); + } + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit.Supported)) + { + sb.AppendLine().AppendLine(Localization.SMART_Command_Transport_SCT); + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit + .LongSectorAccess)) + sb.AppendLine(Localization.SCT_Long_Sector_Address_is_supported); + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit + .WriteSame)) + sb.AppendLine(Localization.SCT_Write_Same_is_supported); + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit + .ErrorRecoveryControl)) + sb.AppendLine(Localization.SCT_Error_Recovery_Control_is_supported); + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit + .FeaturesControl)) + sb.AppendLine(Localization.SCT_Features_Control_is_supported); + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit + .DataTables)) + sb.AppendLine(Localization.SCT_Data_Tables_are_supported); + } + + if((ATAID.NVCacheCaps & 0x0010) == 0x0010) + { + sb.AppendLine().AppendLine(Localization.Non_Volatile_Cache); + sb.AppendLine().AppendFormat(Localization.Version_0, (ATAID.NVCacheCaps & 0xF000) >> 12).AppendLine(); + + if((ATAID.NVCacheCaps & 0x0001) == 0x0001) + { + sb.Append((ATAID.NVCacheCaps & 0x0002) == 0x0002 + ? Localization.Power_mode_feature_set_is_supported_and_enabled + : Localization.Power_mode_feature_set_is_supported); + + sb.AppendLine(); + + sb.AppendLine().AppendFormat(Localization.Version_0, (ATAID.NVCacheCaps & 0x0F00) >> 8).AppendLine(); + } + + sb.AppendLine() + .AppendFormat(Localization.Non_Volatile_Cache_is_0_bytes, ATAID.NVCacheSize * logicalSectorSize) + .AppendLine(); + } + +#if DEBUG + sb.AppendLine(); + + if(ATAID.VendorWord9 != 0x0000 && ATAID.VendorWord9 != 0xFFFF) + sb.AppendFormat(Localization.Word_nine_0, ATAID.VendorWord9).AppendLine(); + + if((ATAID.VendorWord47 & 0x7F) != 0x7F && (ATAID.VendorWord47 & 0x7F) != 0x00) + sb.AppendFormat(Localization.Word_47_bits_15_to_8_0, ATAID.VendorWord47).AppendLine(); + + if(ATAID.VendorWord51 != 0x00 && ATAID.VendorWord51 != 0xFF) + sb.AppendFormat(Localization.Word_51_bits_7_to_0_0, ATAID.VendorWord51).AppendLine(); + + if(ATAID.VendorWord52 != 0x00 && ATAID.VendorWord52 != 0xFF) + sb.AppendFormat(Localization.Word_52_bits_7_to_0_0, ATAID.VendorWord52).AppendLine(); + + if(ATAID.ReservedWord64 != 0x00 && ATAID.ReservedWord64 != 0xFF) + sb.AppendFormat(Localization.Word_64_bits_15_to_8_0, ATAID.ReservedWord64).AppendLine(); + + if(ATAID.ReservedWord70 != 0x0000 && ATAID.ReservedWord70 != 0xFFFF) + sb.AppendFormat(Localization.Word_70_0, ATAID.ReservedWord70).AppendLine(); + + if(ATAID.ReservedWord73 != 0x0000 && ATAID.ReservedWord73 != 0xFFFF) + sb.AppendFormat(Localization.Word_73_0, ATAID.ReservedWord73).AppendLine(); + + if(ATAID.ReservedWord74 != 0x0000 && ATAID.ReservedWord74 != 0xFFFF) + sb.AppendFormat(Localization.Word_74_0, ATAID.ReservedWord74).AppendLine(); + + if(ATAID.ReservedWord116 != 0x0000 && ATAID.ReservedWord116 != 0xFFFF) + sb.AppendFormat(Localization.Word_116_0, ATAID.ReservedWord116).AppendLine(); + + for(var i = 0; i < ATAID.ReservedWords121.Length; i++) + { + if(ATAID.ReservedWords121[i] != 0x0000 && ATAID.ReservedWords121[i] != 0xFFFF) + sb.AppendFormat(Localization.Word_1_0, ATAID.ReservedWords121[i], 121 + i).AppendLine(); + } + + for(var i = 0; i < ATAID.ReservedWords129.Length; i++) + { + if(ATAID.ReservedWords129[i] != 0x0000 && ATAID.ReservedWords129[i] != 0xFFFF) + sb.AppendFormat(Localization.Word_1_0, ATAID.ReservedWords129[i], 129 + i).AppendLine(); + } + + for(var i = 0; i < ATAID.ReservedCFA.Length; i++) + { + if(ATAID.ReservedCFA[i] != 0x0000 && ATAID.ReservedCFA[i] != 0xFFFF) + sb.AppendFormat(Localization.Word_1_CFA_0, ATAID.ReservedCFA[i], 161 + i).AppendLine(); + } + + if(ATAID.ReservedWord174 != 0x0000 && ATAID.ReservedWord174 != 0xFFFF) + sb.AppendFormat(Localization.Word_174_0, ATAID.ReservedWord174).AppendLine(); + + if(ATAID.ReservedWord175 != 0x0000 && ATAID.ReservedWord175 != 0xFFFF) + sb.AppendFormat(Localization.Word_175_0, ATAID.ReservedWord175).AppendLine(); + + if(ATAID.ReservedCEATAWord207 != 0x0000 && ATAID.ReservedCEATAWord207 != 0xFFFF) + sb.AppendFormat(Localization.Word_207_CE_ATA_0, ATAID.ReservedCEATAWord207).AppendLine(); + + if(ATAID.ReservedCEATAWord208 != 0x0000 && ATAID.ReservedCEATAWord208 != 0xFFFF) + sb.AppendFormat(Localization.Word_208_CE_ATA_0, ATAID.ReservedCEATAWord208).AppendLine(); + + if(ATAID.NVReserved != 0x00 && ATAID.NVReserved != 0xFF) + sb.AppendFormat(Localization.Word_219_bits_15_to_8_0, ATAID.NVReserved).AppendLine(); + + if(ATAID.WRVReserved != 0x00 && ATAID.WRVReserved != 0xFF) + sb.AppendFormat(Localization.Word_220_bits_15_to_8_0, ATAID.WRVReserved).AppendLine(); + + if(ATAID.ReservedWord221 != 0x0000 && ATAID.ReservedWord221 != 0xFFFF) + sb.AppendFormat(Localization.Word_221_0, ATAID.ReservedWord221).AppendLine(); + + for(var i = 0; i < ATAID.ReservedCEATA224.Length; i++) + { + if(ATAID.ReservedCEATA224[i] != 0x0000 && ATAID.ReservedCEATA224[i] != 0xFFFF) + sb.AppendFormat(Localization.Word_1_CE_ATA_0, ATAID.ReservedCEATA224[i], 224 + i).AppendLine(); + } + + for(var i = 0; i < ATAID.ReservedWords.Length; i++) + { + if(ATAID.ReservedWords[i] != 0x0000 && ATAID.ReservedWords[i] != 0xFFFF) + sb.AppendFormat(Localization.Word_1_0, ATAID.ReservedWords[i], 236 + i).AppendLine(); + } +#endif + return sb.ToString(); + } +} \ No newline at end of file diff --git a/Aaru.Decoders/ATA/Registers.cs b/Aaru.Decoders/ATA/Registers.cs new file mode 100644 index 000000000..691b46ada --- /dev/null +++ b/Aaru.Decoders/ATA/Registers.cs @@ -0,0 +1,113 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Errors.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes ATA error registers. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Decoders.ATA; + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaRegistersChs +{ + public byte Feature; + public byte SectorCount; + public byte Sector; + public byte CylinderLow; + public byte CylinderHigh; + public byte DeviceHead; + public byte Command; +} + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaRegistersLba28 +{ + public byte Feature; + public byte SectorCount; + public byte LbaLow; + public byte LbaMid; + public byte LbaHigh; + public byte DeviceHead; + public byte Command; +} + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaRegistersLba48 +{ + public ushort Feature; + public ushort SectorCount; + public byte LbaLowPrevious; + public byte LbaLowCurrent; + public byte LbaMidPrevious; + public byte LbaMidCurrent; + public byte LbaHighPrevious; + public byte LbaHighCurrent; + public byte DeviceHead; + public byte Command; +} + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaErrorRegistersChs +{ + public byte Status; + public byte Error; + public byte SectorCount; + public byte Sector; + public byte CylinderLow; + public byte CylinderHigh; + public byte DeviceHead; +} + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaErrorRegistersLba28 +{ + public byte Status; + public byte Error; + public byte SectorCount; + public byte LbaLow; + public byte LbaMid; + public byte LbaHigh; + public byte DeviceHead; +} + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaErrorRegistersLba48 +{ + public byte Status; + public byte Error; + public ushort SectorCount; + public byte LbaLowPrevious; + public byte LbaLowCurrent; + public byte LbaMidPrevious; + public byte LbaMidCurrent; + public byte LbaHighPrevious; + public byte LbaHighCurrent; + public byte DeviceHead; +} \ No newline at end of file diff --git a/Aaru.Decoders/Aaru.Decoders.csproj b/Aaru.Decoders/Aaru.Decoders.csproj new file mode 100644 index 000000000..852e02dbc --- /dev/null +++ b/Aaru.Decoders/Aaru.Decoders.csproj @@ -0,0 +1,114 @@ + + + + 2.0 + {0BEB3088-B634-4289-AE17-CDF2D25D00D5} + Library + Aaru.Decoders + Aaru.Decoders + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Decoders + $(Version) + net8.0 + 12 + Binary structure decoders used by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + LGPL-2.1-only + https://github.com/aaru-dps/Aaru + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + + + + + + + + + + + + + + + + + + + + + LICENSE.LGPL + + + ResXFileCodeGenerator + Localization.Designer.cs + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + \ No newline at end of file diff --git a/Aaru.Decoders/Aaru.Decoders.csproj.DotSettings b/Aaru.Decoders/Aaru.Decoders.csproj.DotSettings new file mode 100644 index 000000000..79d039579 --- /dev/null +++ b/Aaru.Decoders/Aaru.Decoders.csproj.DotSettings @@ -0,0 +1,6 @@ + + True + True \ No newline at end of file diff --git a/Aaru.Decoders/Bluray/BCA.cs b/Aaru.Decoders/Bluray/BCA.cs new file mode 100644 index 000000000..bf436a583 --- /dev/null +++ b/Aaru.Decoders/Bluray/BCA.cs @@ -0,0 +1,135 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : BCA.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Blu-ray Burst Cutting Area. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.Bluray; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class BCA +{ + const string MODULE_NAME = "BD BCA decoder"; + +#region Nested type: BurstCuttingArea + +#region Public structures + + public struct BurstCuttingArea + { + /// Bytes 0 to 1 Always 66 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 to 67 BCA data + public byte[] BCA; + } + +#endregion Public structures + +#endregion + +#region Public methods + + public static BurstCuttingArea? Decode(byte[] BCAResponse) + { + if(BCAResponse == null) return null; + + if(BCAResponse.Length != 68) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Found_incorrect_Blu_ray_BCA_size_0_bytes, + BCAResponse.Length); + + return null; + } + + var decoded = new BurstCuttingArea + { + DataLength = BigEndianBitConverter.ToUInt16(BCAResponse, 0), + Reserved1 = BCAResponse[2], + Reserved2 = BCAResponse[3], + BCA = new byte[64] + }; + + Array.Copy(BCAResponse, 4, decoded.BCA, 0, 64); + + return decoded; + } + + public static string Prettify(BurstCuttingArea? BCAResponse) + { + if(BCAResponse == null) return null; + + BurstCuttingArea response = BCAResponse.Value; + + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); +#endif + + sb.AppendFormat(Localization.Blu_ray_Burst_Cutting_Area_in_hex_follows); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.BCA, 80)); + + return sb.ToString(); + } + + public static string Prettify(byte[] BCAResponse) => Prettify(Decode(BCAResponse)); + +#endregion Public methods +} \ No newline at end of file diff --git a/Aaru.Decoders/Bluray/Cartridge.cs b/Aaru.Decoders/Bluray/Cartridge.cs new file mode 100644 index 000000000..2e852f44a --- /dev/null +++ b/Aaru.Decoders/Bluray/Cartridge.cs @@ -0,0 +1,186 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Cartridge.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Blu-ray cartridge structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.Bluray; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnassignedField.Global")] +public static class Cartridge +{ + const string MODULE_NAME = "BD Cartridge Status decoder"; + +#region Nested type: CartridgeStatus + +#region Public structures + + public struct CartridgeStatus + { + /// Bytes 0 to 1 Always 6 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bit 7 Medium is inserted in a cartridge + public bool Cartridge; + /// Byte 4, bit 6 Medium taken out / put in a cartridge + public bool OUT; + /// Byte 4, bits 5 to 3 Reserved + public byte Reserved3; + /// Byte 4, bit 2 Cartridge sets write protection + public bool CWP; + /// Byte 4, bits 1 to 0 Reserved + public byte Reserved4; + /// Byte 5 Reserved + public byte Reserved5; + /// Byte 6 Reserved + public byte Reserved6; + /// Byte 7 Reserved + public byte Reserved7; + } + +#endregion Public structures + +#endregion + +#region Public methods + + public static CartridgeStatus? Decode(byte[] CSResponse) + { + if(CSResponse == null) return null; + + if(CSResponse.Length != 8) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Found_incorrect_Blu_ray_Cartridge_Status_size_0_bytes, + CSResponse.Length); + + return null; + } + + var decoded = new CartridgeStatus + { + DataLength = BigEndianBitConverter.ToUInt16(CSResponse, 0), + Reserved1 = CSResponse[2], + Reserved2 = CSResponse[3], + Cartridge = Convert.ToBoolean(CSResponse[4] & 0x80), + OUT = Convert.ToBoolean(CSResponse[4] & 0x40), + Reserved3 = (byte)((CSResponse[4] & 0x38) >> 3), + CWP = Convert.ToBoolean(CSResponse[4] & 0x04), + Reserved4 = (byte)(CSResponse[4] & 0x03), + Reserved5 = CSResponse[5], + Reserved6 = CSResponse[6], + Reserved7 = CSResponse[7] + }; + + return decoded; + } + + public static string Prettify(CartridgeStatus? CSResponse) + { + if(CSResponse == null) return null; + + CartridgeStatus response = CSResponse.Value; + + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); + + if(response.Reserved3 != 0) + sb.AppendFormat(Localization.Reserved3_equals_0_X8, response.Reserved3).AppendLine(); + + if(response.Reserved4 != 0) + sb.AppendFormat(Localization.Reserved4_equals_0_X8, response.Reserved4).AppendLine(); + + if(response.Reserved5 != 0) + sb.AppendFormat(Localization.Reserved5_equals_0_X8, response.Reserved5).AppendLine(); + + if(response.Reserved6 != 0) + sb.AppendFormat(Localization.Reserved6_equals_0_X8, response.Reserved6).AppendLine(); + + if(response.Reserved7 != 0) + sb.AppendFormat(Localization.Reserved7_equals_0_X8, response.Reserved7).AppendLine(); +#endif + + if(response.Cartridge) + { + sb.AppendLine(Localization.Media_is_inserted_in_a_cartridge); + + if(response.OUT) sb.AppendLine(Localization.Media_has_been_taken_out_or_inserted_in_the_cartridge); + + if(response.CWP) sb.AppendLine(Localization.Media_is_write_protected); + } + else + { + sb.AppendLine(Localization.Media_is_not_in_a_cartridge); + +#if DEBUG + if(response.OUT) sb.AppendLine(Localization.Media_has_out_bit_marked_shouldnt); + + if(response.CWP) sb.AppendLine(Localization.Media_has_write_protection_bit_marked_shouldnt); +#endif + } + + return sb.ToString(); + } + + public static string Prettify(byte[] CSResponse) => Prettify(Decode(CSResponse)); + +#endregion Public methods +} \ No newline at end of file diff --git a/Aaru.Decoders/Bluray/DDS.cs b/Aaru.Decoders/Bluray/DDS.cs new file mode 100644 index 000000000..c553254f3 --- /dev/null +++ b/Aaru.Decoders/Bluray/DDS.cs @@ -0,0 +1,238 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DDS.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Blu-ray Disc Definition Structure. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.Bluray; + +/// Information from the following standards: +/// ANSI X3.304-1997 +/// T10/1048-D revision 9.0 +/// T10/1048-D revision 10a +/// T10/1228-D revision 7.0c +/// T10/1228-D revision 11a +/// T10/1363-D revision 10g +/// T10/1545-D revision 1d +/// T10/1545-D revision 5 +/// T10/1545-D revision 5a +/// T10/1675-D revision 2c +/// T10/1675-D revision 4 +/// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DDS +{ +#region Nested type: DiscDefinitionStructure + +#region Public structures + + public struct DiscDefinitionStructure + { + /// Bytes 0 to 1 Data Length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 5 "DS" + public ushort Signature; + /// Byte 6 DDS format + public byte Format; + /// Byte 7 Reserved + public byte Reserved3; + /// Bytes 8 to 11 DDS update count + public uint UpdateCount; + /// Bytes 12 to 19 Reserved + public ulong Reserved4; + /// Bytes 20 to 23 First PSN of Drive Area + public uint DriveAreaPSN; + /// Bytes 24 to 27 Reserved + public uint Reserved5; + /// Bytes 28 to 31 First PSN of Defect List + public uint DefectListPSN; + /// Bytes 32 to 35 Reserved + public uint Reserved6; + /// Bytes 36 to 39 PSN of LSN 0 of user data area + public uint PSNofLSNZero; + /// Bytes 40 to 43 Last LSN of user data area + public uint LastUserAreaLSN; + /// Bytes 44 to 47 ISA0 size + public uint ISA0; + /// Bytes 48 to 51 OSA size + public uint OSA; + /// Bytes 52 to 55 ISA1 size + public uint ISA1; + /// Byte 56 Spare Area full flags + public byte SpareAreaFullFlags; + /// Byte 57 Reserved + public byte Reserved7; + /// Byte 58 Disc type specific field + public byte DiscTypeSpecificField1; + /// Byte 59 Reserved + public byte Reserved8; + /// Byte 60 to 63 Disc type specific field + public uint DiscTypeSpecificField2; + /// Byte 64 to 67 Reserved + public uint Reserved9; + /// Bytes 68 to 99 Status bits of INFO1/2 and PAC1/2 on L0 and L1 + public byte[] StatusBits; + /// Bytes 100 to end Disc type specific data + public byte[] DiscTypeSpecificData; + } + +#endregion Public structures + +#endregion + +#region Private constants + + /// Disc Definition Structure Identifier "DS" + const ushort DDSIdentifier = 0x4453; + const string MODULE_NAME = "BD DDS decoder"; + +#endregion Private constants + +#region Public methods + + public static DiscDefinitionStructure? Decode(byte[] DDSResponse) + { + if(DDSResponse == null) return null; + + var decoded = new DiscDefinitionStructure + { + DataLength = BigEndianBitConverter.ToUInt16(DDSResponse, 0), + Reserved1 = DDSResponse[2], + Reserved2 = DDSResponse[3], + Signature = BigEndianBitConverter.ToUInt16(DDSResponse, 4) + }; + + if(decoded.Signature != DDSIdentifier) + { + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Found_incorrect_DDS_signature_0, decoded.Signature); + + return null; + } + + decoded.Format = DDSResponse[6]; + decoded.Reserved3 = DDSResponse[7]; + decoded.UpdateCount = BigEndianBitConverter.ToUInt32(DDSResponse, 8); + decoded.Reserved4 = BigEndianBitConverter.ToUInt64(DDSResponse, 12); + decoded.DriveAreaPSN = BigEndianBitConverter.ToUInt32(DDSResponse, 20); + decoded.Reserved5 = BigEndianBitConverter.ToUInt32(DDSResponse, 24); + decoded.DefectListPSN = BigEndianBitConverter.ToUInt32(DDSResponse, 28); + decoded.Reserved6 = BigEndianBitConverter.ToUInt32(DDSResponse, 32); + decoded.PSNofLSNZero = BigEndianBitConverter.ToUInt32(DDSResponse, 36); + decoded.LastUserAreaLSN = BigEndianBitConverter.ToUInt32(DDSResponse, 40); + decoded.ISA0 = BigEndianBitConverter.ToUInt32(DDSResponse, 44); + decoded.OSA = BigEndianBitConverter.ToUInt32(DDSResponse, 48); + decoded.ISA1 = BigEndianBitConverter.ToUInt32(DDSResponse, 52); + decoded.SpareAreaFullFlags = DDSResponse[56]; + decoded.Reserved7 = DDSResponse[57]; + decoded.DiscTypeSpecificField1 = DDSResponse[58]; + decoded.Reserved8 = DDSResponse[59]; + decoded.DiscTypeSpecificField2 = BigEndianBitConverter.ToUInt32(DDSResponse, 60); + decoded.Reserved9 = BigEndianBitConverter.ToUInt32(DDSResponse, 64); + decoded.StatusBits = new byte[32]; + Array.Copy(DDSResponse, 68, decoded.StatusBits, 0, 32); + decoded.DiscTypeSpecificData = new byte[DDSResponse.Length - 100]; + Array.Copy(DDSResponse, 100, decoded.DiscTypeSpecificData, 0, DDSResponse.Length - 100); + + return decoded; + } + + public static string Prettify(DiscDefinitionStructure? DDSResponse) + { + if(DDSResponse == null) return null; + + DiscDefinitionStructure response = DDSResponse.Value; + + var sb = new StringBuilder(); + + sb.AppendFormat(Localization.DDS_Format_0, response.Format).AppendLine(); + sb.AppendFormat(Localization.DDS_has_been_updated_0_times, response.UpdateCount).AppendLine(); + sb.AppendFormat(Localization.First_PSN_of_Drive_Area_0, response.DriveAreaPSN).AppendLine(); + sb.AppendFormat(Localization.First_PSN_of_Defect_List_0, response.DefectListPSN).AppendLine(); + sb.AppendFormat(Localization.PSN_of_User_Data_Areas_LSN_0_0, response.PSNofLSNZero).AppendLine(); + sb.AppendFormat(Localization.Last_User_Data_Areas_LSN_0_0, response.LastUserAreaLSN).AppendLine(); + sb.AppendFormat(Localization.ISA0_size_0, response.ISA0).AppendLine(); + sb.AppendFormat(Localization.OSA_size_0, response.OSA).AppendLine(); + sb.AppendFormat(Localization.ISA1_size_0, response.ISA1).AppendLine(); + sb.AppendFormat(Localization.Spare_Area_Full_Flags_0, response.SpareAreaFullFlags).AppendLine(); + sb.AppendFormat(Localization.Disc_Type_Specific_Field_1_0, response.DiscTypeSpecificField1).AppendLine(); + sb.AppendFormat(Localization.Disc_Type_Specific_Field_2_0, response.DiscTypeSpecificField2).AppendLine(); + sb.AppendFormat(Localization.Blu_ray_DDS_Status_Bits_in_hex_follows); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.StatusBits, 80)); + sb.AppendFormat(Localization.Blu_ray_DDS_Disc_Type_Specific_Data_in_hex_follows); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.DiscTypeSpecificData, 80)); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); + + if(response.Reserved3 != 0) + sb.AppendFormat(Localization.Reserved_3_equals_0_X2, response.Reserved3).AppendLine(); + + if(response.Reserved4 != 0) + sb.AppendFormat(Localization.Reserved4_equals_0_X16, response.Reserved4).AppendLine(); + + if(response.Reserved5 != 0) + sb.AppendFormat(Localization.Reserved5_equals_0_X8, response.Reserved5).AppendLine(); + + if(response.Reserved6 != 0) + sb.AppendFormat(Localization.Reserved6_equals_0_X8, response.Reserved6).AppendLine(); + + if(response.Reserved7 != 0) + sb.AppendFormat(Localization.Reserved7_equals_0_X2, response.Reserved7).AppendLine(); + + if(response.Reserved8 != 0) + sb.AppendFormat(Localization.Reserved8_equals_0_X2, response.Reserved8).AppendLine(); + + if(response.Reserved9 != 0) + sb.AppendFormat(Localization.Reserved9_equals_0_X8, response.Reserved9).AppendLine(); +#endif + + return sb.ToString(); + } + + public static string Prettify(byte[] DDSResponse) => Prettify(Decode(DDSResponse)); + +#endregion Public methods +} \ No newline at end of file diff --git a/Aaru.Decoders/Bluray/DI.cs b/Aaru.Decoders/Bluray/DI.cs new file mode 100644 index 000000000..8102b6020 --- /dev/null +++ b/Aaru.Decoders/Bluray/DI.cs @@ -0,0 +1,555 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DI.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Blu-ray Disc Information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.Bluray; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static class DI +{ +#region BluSize enum + + public enum BluSize : byte + { + /// 120mm + OneTwenty = 0, + /// 80mm + Eighty = 1 + } + +#endregion + +#region ChannelLength enum + + public enum ChannelLength : byte + { + /// 74.5nm channel or 25Gb/layer + Seventy = 1, + /// 69.0nm channel or 27Gb/layer + Sixty = 2 + } + +#endregion + +#region HybridLayer enum + + public enum HybridLayer : byte + { + /// No hybrid layer + None = 0, + /// -ROM layer + ReadOnly = 1, + /// -R layer + Recordable = 2, + /// -RW layer + Rewritable = 3 + } + +#endregion + +#region Private constants + + const string DiscTypeBDROM = "BDO"; + const string DiscTypeBDRE = "BDW"; + const string DiscTypeBDR = "BDR"; + + /// Disc Information Unit Identifier "DI" + const ushort DIUIdentifier = 0x4449; + const string MODULE_NAME = "BD Disc Information decoder"; + +#endregion Private constants + +#region Public methods + + public static DiscInformation? Decode(byte[] DIResponse) + { + if(DIResponse == null) return null; + + if(DIResponse.Length != 4100) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Found_incorrect_Blu_ray_Disc_Information_size_0_bytes, + DIResponse.Length); + + return null; + } + + var decoded = new DiscInformation + { + DataLength = BigEndianBitConverter.ToUInt16(DIResponse, 0), + Reserved1 = DIResponse[2], + Reserved2 = DIResponse[3] + }; + + var offset = 4; + List units = []; + + while(true) + { + if(offset >= 4100) break; + + var unit = new DiscInformationUnits + { + Signature = BigEndianBitConverter.ToUInt16(DIResponse, 0 + offset) + }; + + if(unit.Signature != DIUIdentifier) break; + + unit.Format = DIResponse[2 + offset]; + unit.UnitsPerBlock = (byte)((DIResponse[3 + offset] & 0xF8) >> 3); + unit.Layer = (byte)(DIResponse[3 + offset] & 0x07); + unit.Legacy = DIResponse[4 + offset]; + unit.Sequence = DIResponse[5 + offset]; + unit.Continuation = (DIResponse[6 + offset] & 0x80) == 0x80; + unit.Length = (byte)(DIResponse[6 + offset] & 0x7F); + unit.Reserved = DIResponse[7 + offset]; + unit.DiscTypeIdentifier = new byte[3]; + Array.Copy(DIResponse, 8 + offset, unit.DiscTypeIdentifier, 0, 3); + unit.DiscSize = (BluSize)((DIResponse[11 + offset] & 0xC0) >> 6); + unit.DiscClass = (byte)((DIResponse[11 + offset] & 0x30) >> 4); + unit.DiscVersion = (byte)(DIResponse[11 + offset] & 0x0F); + unit.Layers = (byte)((DIResponse[12 + offset] & 0xF0) >> 4); + unit.DvdLayer = (HybridLayer)((DIResponse[13 + offset] & 0xC0) >> 6); + unit.CdLayer = (HybridLayer)((DIResponse[13 + offset] & 0x30) >> 4); + unit.ChannelLength = (ChannelLength)(DIResponse[13 + offset] & 0x0F); + unit.Polarity = DIResponse[14 + offset]; + unit.RecordedPolarity = DIResponse[14 + offset]; + unit.Bca = (byte)(DIResponse[16 + offset] & 0x0F); + unit.MaxTransfer = DIResponse[17 + offset]; + + unit.LastPsn = (uint)((DIResponse[20 + offset] << 24) + + (DIResponse[21 + offset] << 16) + + (DIResponse[22 + offset] << 8) + + DIResponse[23 + offset]); + + // TODO: In -R/-RE how does this relate to layer size??? + unit.FirstAun = (uint)((DIResponse[24 + offset] << 24) + + (DIResponse[25 + offset] << 16) + + (DIResponse[26 + offset] << 8) + + DIResponse[27 + offset]); + + unit.LastAun = (uint)((DIResponse[28 + offset] << 24) + + (DIResponse[29 + offset] << 16) + + (DIResponse[30 + offset] << 8) + + DIResponse[31 + offset]); + + switch(Encoding.ASCII.GetString(unit.DiscTypeIdentifier)) + { + case DiscTypeBDROM: + { + unit.FormatDependentContents = new byte[32]; + Array.Copy(DIResponse, 32 + offset, unit.FormatDependentContents, 0, 32); + + break; + } + + case DiscTypeBDRE: + case DiscTypeBDR: + { + unit.FormatDependentContents = new byte[66]; + Array.Copy(DIResponse, 32 + offset, unit.FormatDependentContents, 0, 66); + unit.ManufacturerID = new byte[6]; + Array.Copy(DIResponse, 100 + offset, unit.ManufacturerID, 0, 6); + unit.MediaTypeID = new byte[3]; + Array.Copy(DIResponse, 106 + offset, unit.MediaTypeID, 0, 3); + unit.TimeStamp = BigEndianBitConverter.ToUInt16(DIResponse, 109 + offset); + unit.ProductRevisionNumber = DIResponse[111 + offset]; + + offset += 14; + + break; + } + + default: + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Found_unknown_disc_type_identifier_0, + Encoding.ASCII.GetString(unit.DiscTypeIdentifier)); + + break; + } + } + + units.Add(unit); + + offset += unit.Length; + } + + if(units.Count <= 0) return decoded; + + decoded.Units = new DiscInformationUnits[units.Count]; + + for(var i = 0; i < units.Count; i++) decoded.Units[i] = units[i]; + + return decoded; + } + + public static string Prettify(DiscInformation? DIResponse) + { + if(DIResponse == null) return null; + + DiscInformation response = DIResponse.Value; + + var sb = new StringBuilder(); + + foreach(DiscInformationUnits unit in response.Units) + { + sb.AppendFormat(Localization.DI_Unit_Sequence_0, unit.Sequence).AppendLine(); + sb.AppendFormat(Localization.DI_Unit_Format_0, unit.Format).AppendLine(); + sb.AppendFormat(Localization.There_are_0_per_block, unit.UnitsPerBlock).AppendLine(); + sb.AppendFormat(Localization.This_DI_refers_to_layer_0, unit.Layer).AppendLine(); + + if(Encoding.ASCII.GetString(unit.DiscTypeIdentifier) == DiscTypeBDRE) + sb.AppendFormat(Localization.Legacy_value_0, unit.Legacy).AppendLine(); + + sb.AppendLine(unit.Continuation + ? Localization.This_DI_continues_previous_unit + : Localization.This_DI_starts_a_new_unit); + + sb.AppendFormat(Localization.DI_Unit_is_0_bytes, unit.Length).AppendLine(); + + sb.AppendFormat(Localization.Disc_type_identifier_0, Encoding.ASCII.GetString(unit.DiscTypeIdentifier)) + .AppendLine(); + + switch(unit.DiscSize) + { + case BluSize.OneTwenty: + sb.AppendLine(Localization.Disc_size_120mm); + + break; + case BluSize.Eighty: + sb.AppendLine(Localization.Disc_size_80mm); + + break; + default: + sb.AppendFormat(Localization.Disc_size_Unknown_code_0, (byte)unit.DiscSize).AppendLine(); + + break; + } + + sb.AppendFormat(Localization.Disc_class_0, unit.DiscClass).AppendLine(); + sb.AppendFormat(Localization.Disc_version_0, unit.DiscVersion).AppendLine(); + sb.AppendFormat(Localization.This_disc_has_0_layers, unit.Layers).AppendLine(); + + switch(unit.DvdLayer) + { + case HybridLayer.None: + sb.AppendLine(Localization.This_disc_does_not_contain_a_DVD_layer); + + break; + case HybridLayer.ReadOnly: + sb.AppendLine(Localization.This_disc_contains_a_DVD_ROM_layer); + + break; + case HybridLayer.Recordable: + sb.AppendLine(Localization.This_disc_contains_a_DVD_R_layer); + + break; + case HybridLayer.Rewritable: + sb.AppendLine(Localization.This_disc_contains_a_DVD_RW_layer); + + break; + } + + switch(unit.CdLayer) + { + case HybridLayer.None: + sb.AppendLine(Localization.This_disc_does_not_contain_a_CD_layer); + + break; + case HybridLayer.ReadOnly: + sb.AppendLine(Localization.This_disc_contains_a_CD_ROM_layer); + + break; + case HybridLayer.Recordable: + sb.AppendLine(Localization.This_disc_contains_a_CD_R_layer); + + break; + case HybridLayer.Rewritable: + sb.AppendLine(Localization.This_disc_contains_a_CD_RW_layer); + + break; + } + + switch(unit.ChannelLength) + { + case ChannelLength.Seventy: + sb.AppendLine(Localization.Disc_uses_a_74_5nm_channel_giving_25_Gb_per_layer); + + break; + case ChannelLength.Sixty: + sb.AppendLine(Localization.Disc_uses_a_69_0nm_channel_giving_27_Gb_per_layer); + + break; + default: + sb.AppendFormat(Localization.Disc_uses_unknown_channel_length_with_code_0, (byte)unit.ChannelLength) + .AppendLine(); + + break; + } + + switch(unit.Polarity) + { + case 0: + sb.AppendLine(Localization.Disc_uses_positive_polarity); + + break; + case 1: + sb.AppendLine(Localization.Disc_uses_negative_polarity); + + break; + default: + sb.AppendFormat(Localization.Disc_uses_unknown_polarity_with_code_0, unit.Polarity).AppendLine(); + + break; + } + + if(Encoding.ASCII.GetString(unit.DiscTypeIdentifier) == DiscTypeBDR) + { + switch(unit.RecordedPolarity) + { + case 0: + sb.AppendLine(Localization + .Recorded_marks_have_a_lower_reflectivity_than_unrecorded_ones_HTL_disc); + + break; + case 1: + sb.AppendLine(Localization + .Recorded_marks_have_a_higher_reflectivity_than_unrecorded_ones_LTH_disc); + + break; + default: + sb.AppendFormat(Localization.Disc_uses_unknown_recorded_reflectivity_polarity_with_code_0, + unit.RecordedPolarity) + .AppendLine(); + + break; + } + } + + switch(unit.Bca) + { + case 0: + sb.AppendLine(Localization.Disc_doesn_t_have_a_BCA); + + break; + case 1: + sb.AppendLine(Localization.Disc_has_a_BCA); + + break; + default: + sb.AppendFormat(Localization.Disc_uses_unknown_BCA_code_0, unit.Bca).AppendLine(); + + break; + } + + if(unit.MaxTransfer > 0) + { + sb.AppendFormat(Localization.Disc_has_a_maximum_transfer_rate_of_0_Mbit_sec, unit.MaxTransfer) + .AppendLine(); + } + else + sb.AppendLine(Localization.Disc_does_not_specify_a_maximum_transfer_rate); + + sb.AppendFormat(Localization.Last_user_data_PSN_for_disc_0, unit.LastPsn).AppendLine(); + + sb.AppendFormat(Localization.First_address_unit_number_of_data_zone_in_this_layer_0, unit.FirstAun) + .AppendLine(); + + sb.AppendFormat(Localization.Last_address_unit_number_of_data_zone_in_this_layer_0, unit.LastAun) + .AppendLine(); + + if(Encoding.ASCII.GetString(unit.DiscTypeIdentifier) == DiscTypeBDR || + Encoding.ASCII.GetString(unit.DiscTypeIdentifier) == DiscTypeBDRE) + { + sb.AppendFormat(Localization.Disc_manufacturer_ID_0, Encoding.ASCII.GetString(unit.ManufacturerID)) + .AppendLine(); + + sb.AppendFormat(Localization.Disc_media_type_ID_0, Encoding.ASCII.GetString(unit.MediaTypeID)) + .AppendLine(); + + sb.AppendFormat(Localization.Disc_timestamp_0, unit.TimeStamp).AppendLine(); + sb.AppendFormat(Localization.Disc_product_revision_number_0, unit.ProductRevisionNumber).AppendLine(); + } + + sb.AppendFormat(Localization.Blu_ray_DI_Unit_format_dependent_contents_as_hex_follows); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(unit.FormatDependentContents, 80)); + } + + return sb.ToString(); + } + + public static string Prettify(byte[] DIResponse) => Prettify(Decode(DIResponse)); + + public static string ManufacturerFromDI(string manufacturerId) + { + // ReSharper disable StringLiteralTypo + string manufacturer = manufacturerId switch + { + "AMESOB" or "OTCBDR" => "Amethystum Storage Technology Co., Ltd.", + "UMEBDR" or "ANWELL" => "Avic Umedisc HK Ltd.", + "MAXELL" => "Hitachi Maxell, Ltd.", + "CMCMAG" => "CMC Magnetics Corporation", + "ISMMBD" => "Info Source Digital Media (Zhong Shan) Co., Ltd.", + "LGEBRA" => "LG Electronics Inc.", + "MILLEN" => "Millenniata, Inc.", + "VERBAT" or "VAMKM" => "Mitsubishi Chemical Media Co., Ltd.", + "PHILIP" or "MBI" => "Moser Baer India Ltd.", + "MEI" or "PAN" => "Matsushita Electric Industrial Co., Ltd.", + "PRODIS" => "Prodisc Technology Inc.", + "RITEK" => "Ritek Co.", + "SONY" => "Sony Corporation", + "TYG-BD" => "Taiyo Yuden Company Ltd.", + "TDKBLD" => "TDK Corporation", + "JVC-AM" or "JVCVAM" => "Victor Advanced media Co., Ltd.", + "JVCRE1" => "JVC KENWOOD Corporation", + "INFOME" => "InfoMedia Inc.", + _ => "" + }; + + // ReSharper restore StringLiteralTypo + + return manufacturer != "" ? $"{manufacturer} (\"{manufacturerId}\")" : $"\"{manufacturerId}\""; + } + +#endregion Public methods + +#region Public structures + + public struct DiscInformation + { + /// Bytes 0 to 1 Always 4098 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 to 4099 Disc information units + public DiscInformationUnits[] Units; + } + + public struct DiscInformationUnits + { + /// Byte 0 "DI" + public ushort Signature; + /// Byte 2 Disc information format + public byte Format; + /// Byte 3, bits 7 to 3 Number of DI units per block + public byte UnitsPerBlock; + /// Byte 3, bits 2 to 0 Layer this DI refers to + public byte Layer; + /// Byte 4 Reserved for BD-ROM, legacy information for BD-R/-RE + public byte Legacy; + /// Byte 5 Sequence number for this DI unit + public byte Sequence; + /// Byte 6, bit 7 If set this DI is a continuation of the previous one + public bool Continuation; + /// Byte 6, bits 6 to 0 Number of bytes used by this DI unit, should be 64 for BD-ROM and 112 for BD-R/-RE + public byte Length; + /// Byte 7 Reserved + public byte Reserved; + /// Bytes 8 to 10 Disc type identifier + public byte[] DiscTypeIdentifier; + /// Byte 11, bits 7 to 6 Disc size + public BluSize DiscSize; + /// Byte 11, bits 5 to 4 Disc class + public byte DiscClass; + /// Byte 11, bits 3 to 0 Disc version + public byte DiscVersion; + /// Byte 12, bits 7 to 4 Layers in this disc + public byte Layers; + /// Byte 12, bits 3 to 0 Reserved + public byte Reserved2; + /// Byte 13, bits 7 to 6 DVD layer + public HybridLayer DvdLayer; + /// Byte 13, bits 5 to 4 CD layer + public HybridLayer CdLayer; + /// Byte 13, bits 3 to 0 Channel length + public ChannelLength ChannelLength; + /// Byte 14 Polarity + public byte Polarity; + /// Byte 15 Recorded polarity + public byte RecordedPolarity; + /// Byte 16, bits 7 to 4 Reserved + public byte Reserved3; + /// Byte 16, bits 3 to 0 If 0 no BCA, if 1 BCA, rest not defined + public byte Bca; + /// Byte 17 Maximum transfer speed in megabits/second, 0 if no maximum + public byte MaxTransfer; + /// Bytes 18 to 19 Reserved + public ushort Reserved4; + /// Bytes 20 to 23 Last user data PSN for disc + public uint LastPsn; + /// Bytes 24 to 27 First address unit number of data zone in this layer + public uint FirstAun; + /// Bytes 28 to 31 Last address unit number of data zone in this layer + public uint LastAun; + /// + /// Bytes 32 to 63 for BD-ROM, bytes 32 to 99 for BD-R/-RE Format dependent contents, disclosed in private blu-ray + /// specifications + /// + public byte[] FormatDependentContents; + /// Bytes 100 to 105, BD-R/-RE only Manufacturer ID + public byte[] ManufacturerID; + /// Bytes 106 to 108, BD-R/-RE only Media type ID + public byte[] MediaTypeID; + /// Bytes 109 to 110, BD-R/-RE only Timestamp + public ushort TimeStamp; + /// Byte 111 Product revision number + public byte ProductRevisionNumber; + } + +#endregion Public structures +} \ No newline at end of file diff --git a/Aaru.Decoders/Bluray/Spare.cs b/Aaru.Decoders/Bluray/Spare.cs new file mode 100644 index 000000000..f0237c603 --- /dev/null +++ b/Aaru.Decoders/Bluray/Spare.cs @@ -0,0 +1,141 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Spare.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Blu-ray Spare Area Information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.Bluray; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class Spare +{ + const string MODULE_NAME = "BD Spare Area Information decoder"; + +#region Nested type: SpareAreaInformation + +#region Public structures + + public struct SpareAreaInformation + { + /// Bytes 0 to 1 Always 14 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 7 Reserved + public uint Reserved3; + /// Bytes 8 to 11 Free spare blocks + public uint FreeSpareBlocks; + /// Bytes 12 to 15 Allocated spare blocks + public uint AllocatedSpareBlocks; + } + +#endregion Public structures + +#endregion + +#region Public methods + + public static SpareAreaInformation? Decode(byte[] SAIResponse) + { + if(SAIResponse == null) return null; + + if(SAIResponse.Length != 16) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Spare_Decode_Found_incorrect_Blu_ray_Spare_Area_Information_size_0_bytes, + SAIResponse.Length); + + return null; + } + + var decoded = new SpareAreaInformation + { + DataLength = BigEndianBitConverter.ToUInt16(SAIResponse, 0), + Reserved1 = SAIResponse[2], + Reserved2 = SAIResponse[3], + Reserved3 = BigEndianBitConverter.ToUInt32(SAIResponse, 4), + FreeSpareBlocks = BigEndianBitConverter.ToUInt32(SAIResponse, 8), + AllocatedSpareBlocks = BigEndianBitConverter.ToUInt32(SAIResponse, 12) + }; + + return decoded; + } + + public static string Prettify(SpareAreaInformation? SAIResponse) + { + if(SAIResponse == null) return null; + + SpareAreaInformation response = SAIResponse.Value; + + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); + + if(response.Reserved3 != 0) + sb.AppendFormat(Localization.Reserved3_equals_0_X8, response.Reserved3).AppendLine(); +#endif + sb.AppendFormat(Localization._0_free_spare_blocks, response.FreeSpareBlocks).AppendLine(); + sb.AppendFormat(Localization._0_allocated_spare_blocks, response.AllocatedSpareBlocks).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify(byte[] SAIResponse) => Prettify(Decode(SAIResponse)); + +#endregion Public methods +} \ No newline at end of file diff --git a/Aaru.Decoders/CD/ATIP.cs b/Aaru.Decoders/CD/ATIP.cs new file mode 100644 index 000000000..5080e32ae --- /dev/null +++ b/Aaru.Decoders/CD/ATIP.cs @@ -0,0 +1,809 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ATIP.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes CD Absolute-Time-In-Pregroove +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.CD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class ATIP +{ + const string MODULE_NAME = "CD ATIP decoder"; + + public static CDATIP Decode(byte[] CDATIPResponse) + { + if(CDATIPResponse is not { Length: > 4 }) return null; + + var decoded = new CDATIP(); + + if(CDATIPResponse.Length != 32 && CDATIPResponse.Length != 28) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Expected_CD_ATIP_size_32_bytes_is_not_received_size_0_bytes_not_decoding, + CDATIPResponse.Length); + + return null; + } + + decoded.DataLength = BigEndianBitConverter.ToUInt16(CDATIPResponse, 0); + decoded.Reserved1 = CDATIPResponse[2]; + decoded.Reserved2 = CDATIPResponse[3]; + decoded.ITWP = (byte)((CDATIPResponse[4] & 0xF0) >> 4); + decoded.DDCD = Convert.ToBoolean(CDATIPResponse[4] & 0x08); + decoded.ReferenceSpeed = (byte)(CDATIPResponse[4] & 0x07); + decoded.AlwaysZero = Convert.ToBoolean(CDATIPResponse[5] & 0x80); + decoded.URU = Convert.ToBoolean(CDATIPResponse[5] & 0x40); + decoded.Reserved3 = (byte)(CDATIPResponse[5] & 0x3F); + + decoded.AlwaysOne = Convert.ToBoolean(CDATIPResponse[6] & 0x80); + decoded.DiscType = Convert.ToBoolean(CDATIPResponse[6] & 0x40); + decoded.DiscSubType = (byte)((CDATIPResponse[6] & 0x38) >> 3); + decoded.A1Valid = Convert.ToBoolean(CDATIPResponse[6] & 0x04); + decoded.A2Valid = Convert.ToBoolean(CDATIPResponse[6] & 0x02); + decoded.A3Valid = Convert.ToBoolean(CDATIPResponse[6] & 0x01); + + decoded.Reserved4 = CDATIPResponse[7]; + decoded.LeadInStartMin = CDATIPResponse[8]; + decoded.LeadInStartSec = CDATIPResponse[9]; + decoded.LeadInStartFrame = CDATIPResponse[10]; + decoded.Reserved5 = CDATIPResponse[11]; + decoded.LeadOutStartMin = CDATIPResponse[12]; + decoded.LeadOutStartSec = CDATIPResponse[13]; + decoded.LeadOutStartFrame = CDATIPResponse[14]; + decoded.Reserved6 = CDATIPResponse[15]; + + decoded.A1Values = new byte[3]; + decoded.A2Values = new byte[3]; + decoded.A3Values = new byte[3]; + + Array.Copy(CDATIPResponse, 16, decoded.A1Values, 0, 3); + Array.Copy(CDATIPResponse, 20, decoded.A2Values, 0, 3); + Array.Copy(CDATIPResponse, 24, decoded.A3Values, 0, 3); + + decoded.Reserved7 = CDATIPResponse[19]; + decoded.Reserved8 = CDATIPResponse[23]; + decoded.Reserved9 = CDATIPResponse[27]; + + if(CDATIPResponse.Length < 32) return decoded.AlwaysOne ? decoded : null; + + decoded.S4Values = new byte[3]; + Array.Copy(CDATIPResponse, 28, decoded.S4Values, 0, 3); + decoded.Reserved10 = CDATIPResponse[31]; + + return decoded.AlwaysOne ? decoded : null; + } + + public static string Prettify(CDATIP response) + { + if(response == null) return null; + + var sb = new StringBuilder(); + + if(response.DDCD) + { + sb.AppendFormat(Localization.Indicative_Target_Writing_Power_0, response.ITWP).AppendLine(); + sb.AppendLine(response.DiscType ? Localization.Disc_is_DDCD_RW : Localization.Disc_is_DDCD_R); + + switch(response.ReferenceSpeed) + { + case 2: + sb.AppendLine(Localization.Reference_speed_is_4x); + + break; + case 3: + sb.AppendLine(Localization.Reference_speed_is_8x); + + break; + default: + sb.AppendFormat(Localization.Reference_speed_set_is_unknown_0, response.ReferenceSpeed) + .AppendLine(); + + break; + } + + sb.AppendFormat(Localization.ATIP_Start_time_of_Lead_in_0, + (response.LeadInStartMin << 16) + + (response.LeadInStartSec << 8) + + response.LeadInStartFrame) + .AppendLine(); + + sb.AppendFormat(Localization.ATIP_Last_possible_start_time_of_Lead_out_0, + (response.LeadOutStartMin << 16) + + (response.LeadOutStartSec << 8) + + response.LeadOutStartFrame) + .AppendLine(); + + sb.AppendFormat(Localization.S4_value_0, + (response.S4Values[0] << 16) + (response.S4Values[1] << 8) + response.S4Values[2]) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Indicative_Target_Writing_Power_0, response.ITWP & 0x07).AppendLine(); + + if(response.DiscType) + { + switch(response.DiscSubType) + { + case 0: + sb.AppendLine(Localization.Disc_is_CD_RW); + + break; + case 1: + sb.AppendLine(Localization.Disc_is_High_Speed_CD_RW); + + break; + case 2: + sb.AppendLine(Localization.Disc_is_Ultra_Speed_CD_RW); + + break; + case 3: + sb.AppendLine(Localization.Disc_is_Ultra_Speed_Plus_CD_RW); + + break; + case 4: + sb.AppendLine(Localization.Disc_is_medium_type_B_low_beta_category_CD_RW); + + break; + case 5: + sb.AppendLine(Localization.Disc_is_medium_type_B_high_beta_category_CD_RW); + + break; + case 6: + sb.AppendLine(Localization.Disc_is_medium_type_C_low_beta_category_CD_RW); + + break; + case 7: + sb.AppendLine(Localization.Disc_is_medium_type_C_high_beta_category_CD_RW); + + break; + default: + sb.AppendFormat(Localization.Unknown_CD_RW_disc_subtype_0, response.DiscSubType).AppendLine(); + + break; + } + + switch(response.ReferenceSpeed) + { + case 1: + sb.AppendLine(Localization.Reference_speed_is_2x); + + break; + default: + sb.AppendFormat(Localization.Reference_speed_set_is_unknown_0, response.ReferenceSpeed) + .AppendLine(); + + break; + } + } + else + { + sb.AppendLine(Localization.Disc_is_CD_R); + + switch(response.DiscSubType) + { + case 0: + sb.AppendLine(Localization.Disc_is_normal_speed_CLV_CD_R); + + break; + case 1: + sb.AppendLine(Localization.Disc_is_high_speed_CAV_CD_R); + + break; + case 2: + sb.AppendLine(Localization.Disc_is_medium_type_A_low_beta_category_CD_R); + + break; + case 3: + sb.AppendLine(Localization.Disc_is_medium_type_A_high_beta_category_CD_R); + + break; + case 4: + sb.AppendLine(Localization.Disc_is_medium_type_B_low_beta_category_CD_R); + + break; + case 5: + sb.AppendLine(Localization.Disc_is_medium_type_B_high_beta_category__CD_R); + + break; + case 6: + sb.AppendLine(Localization.Disc_is_medium_type_C_low_beta_category__CD_R); + + break; + case 7: + sb.AppendLine(Localization.Disc_is_medium_type_C_high_beta_category__CD_R); + + break; + default: + sb.AppendFormat(Localization.Unknown_CD_R_disc_subtype_0, response.DiscSubType).AppendLine(); + + break; + } + } + + sb.AppendLine(response.URU ? Localization.Disc_use_is_unrestricted : Localization.Disc_use_is_restricted); + + sb.AppendFormat(Localization.ATIP_Start_time_of_Lead_in_0_1_2, + response.LeadInStartMin, + response.LeadInStartSec, + response.LeadInStartFrame) + .AppendLine(); + + sb.AppendFormat(Localization.ATIP_Last_possible_start_time_of_Lead_out_0_1_2, + response.LeadOutStartMin, + response.LeadOutStartSec, + response.LeadOutStartFrame) + .AppendLine(); + + if(response.A1Valid) + { + sb.AppendFormat(Localization.A1_value_0, + (response.A1Values[0] << 16) + (response.A1Values[1] << 8) + response.A1Values[2]) + .AppendLine(); + } + + if(response.A2Valid) + { + sb.AppendFormat(Localization.A2_value_0, + (response.A2Values[0] << 16) + (response.A2Values[1] << 8) + response.A2Values[2]) + .AppendLine(); + } + + if(response.A3Valid) + { + sb.AppendFormat(Localization.A3_value_0, + (response.A3Values[0] << 16) + (response.A3Values[1] << 8) + response.A3Values[2]) + .AppendLine(); + } + + if(response.S4Values != null) + { + sb.AppendFormat(Localization.S4_value_0, + (response.S4Values[0] << 16) + (response.S4Values[1] << 8) + response.S4Values[2]) + .AppendLine(); + } + } + + if(response.LeadInStartMin != 97) return sb.ToString(); + + int type = response.LeadInStartFrame % 10; + int frm = response.LeadInStartFrame - type; + + if(response.DiscType) + sb.AppendLine(Localization.Disc_uses_phase_change); + else + { + sb.AppendLine(type < 5 + ? Localization.Disc_uses_long_strategy_type_dye_Cyanine_AZO_etc + : Localization.Disc_uses_short_strategy_type_dye_Phthalocyanine_etc); + } + + string manufacturer = ManufacturerFromATIP(response.LeadInStartSec, frm); + + if(manufacturer != "") sb.AppendFormat(Localization.Disc_manufactured_by_0, manufacturer).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify(byte[] CDATIPResponse) + { + CDATIP decoded = Decode(CDATIPResponse); + + return Prettify(decoded); + } + + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public static string ManufacturerFromATIP(byte sec, int frm) + { + switch(sec) + { + case 10: + switch(frm) + { + case 00: + return "Ritek Co."; + } + + break; + case 15: + switch(frm) + { + case 00: + return "TDK Corporation"; + case 10: + return "Ritek Co."; + case 20: + return "Mitsubishi Chemical Corporation"; + case 30: + return "NAN-YA Plastics Corporation"; + } + + break; + case 16: + switch(frm) + { + case 20: + return "Shenzen SG&Gast Digital Optical Discs"; + case 30: + return "Grand Advance Technology Ltd."; + } + + break; + case 17: + if(frm == 00) return "Moser Baer India Ltd."; + + break; + case 18: + switch(frm) + { + case 10: + return "Wealth Fair Investment Ltd."; + case 60: + return "Taroko International Co. Ltd."; + } + + break; + case 20: + if(frm == 10) return "CDA Datenträger Albrechts GmbH"; + + break; + case 21: + switch(frm) + { + case 10: + return "Grupo Condor S.L."; + case 20: + return "E-TOP Mediatek Inc."; + case 30: + return "Bestdisc Technology Corporation"; + case 40: + return "Optical Disc Manufacturing Equipment"; + case 50: + return "Sound Sound Multi-Media Development Ltd."; + } + + break; + case 22: + switch(frm) + { + case 00: + return "Woongjin Media Corp."; + case 10: + return "Seantram Technology Inc."; + case 20: + return "Advanced Digital Media"; + case 30: + return "EXIMPO"; + case 40: + return "CIS Technology Inc."; + case 50: + return "Hong Kong Digital Technology Co., Ltd."; + case 60: + return "Acer Media Technology, Inc."; + } + + break; + case 23: + switch(frm) + { + case 00: + return "Matsushita Electric Industrial Co., Ltd."; + case 10: + return "Doremi Media Co., Ltd."; + case 20: + return "Nacar Media s.r.l."; + case 30: + return "Audio Distributors Co., Ltd."; + case 40: + return "Victor Company of Japan, Ltd."; + case 50: + return "Optrom Inc."; + case 60: + return "Customer Pressing Oosterhout"; + } + + break; + case 24: + switch(frm) + { + case 00: + return "Taiyo Yuden Company Ltd."; + case 10: + return "SONY Corporation"; + case 20: + return "Computer Support Italy s.r.l."; + case 30: + return "Unitech Japan Inc."; + case 40: + return "kdg mediatech AG"; + case 50: + return "Guann Yinn Co., Ltd."; + case 60: + return "Harmonic Hall Optical Disc Ltd."; + } + + break; + case 25: + switch(frm) + { + case 00: + return "MPO"; + case 20: + return "Hitachi Maxell, Ltd."; + case 30: + return "Infodisc Technology Co. Ltd."; + case 40: + return "Vivastar AG"; + case 50: + return "AMS Technology Inc."; + case 60: + return "Xcitec Inc."; + } + + break; + case 26: + switch(frm) + { + case 00: + return "Fornet International Pte Ltd."; + case 10: + return "POSTECH Corporation"; + case 20: + return "SKC Co., Ltd."; + case 30: + return "Optical Disc Corporation"; + case 40: + return "FUJI Photo Film Co., Ltd."; + case 50: + return "Lead Data Inc."; + case 60: + return "CMC Magnetics Corporation"; + } + + break; + case 27: + switch(frm) + { + case 00: + return "Digital Storage Technology Co., Ltd."; + case 10: + return "Plasmon Data systems Ltd."; + case 20: + return "Princo Corporation"; + case 30: + return "Pioneer Video Corporation"; + case 40: + return "Kodak Japan Ltd."; + case 50: + return "Mitsui Chemicals, Inc."; + case 60: + return "Ricoh Company Ltd."; + } + + break; + case 28: + switch(frm) + { + case 00: + return "Opti.Me.S. S.p.A."; + case 10: + return "Gigastore Corporation"; + case 20: + return "Multi Media Masters & Machinary SA"; + case 30: + return "Auvistar Industry Co., Ltd."; + case 40: + return "King Pro Mediatek Inc."; + case 50: + return "Delphi Technology Inc."; + case 60: + return "Friendly CD-Tek Co."; + } + + break; + case 29: + switch(frm) + { + case 00: + return "Taeil Media Co., Ltd."; + case 10: + return "Vanguard Disc Inc."; + case 20: + return "Unidisc Technology Co., Ltd."; + case 30: + return "Hile Optical Disc Technology Corp."; + case 40: + return "Viva Magnetics Ltd."; + case 50: + return "General Magnetics Ltd."; + } + + break; + case 30: + if(frm == 10) return "CDA Datenträger Albrechts GmbH"; + + break; + case 31: + switch(frm) + { + case 00: + return "Ritek Co."; + case 30: + return "Grand Advance Technology Ltd."; + } + + break; + case 32: + switch(frm) + { + case 00: + return "TDK Corporation"; + case 10: + return "Prodisc Technology Inc."; + } + + break; + case 34: + switch(frm) + { + case 20: + case 22: + return "Mitsubishi Chemical Corporation"; + } + + break; + case 36: + switch(frm) + { + case 00: + return "Gish International Co., Ltd."; + } + + break; + case 42: + if(frm == 20) return "Advanced Digital Media"; + + break; + case 45: + switch(frm) + { + case 00: + return "Fornet International Pte Ltd."; + case 10: + return "Unitech Japan Inc."; + case 20: + return "Acer Media Technology, Inc."; + case 40: + return "CIS Technology Inc."; + case 50: + return "Guann Yinn Co., Ltd."; + case 60: + return "Xcitec Inc."; + } + + break; + case 46: + switch(frm) + { + case 00: + return "Taiyo Yuden Company Ltd."; + case 10: + return "Hong Kong Digital Technology Co., Ltd."; + case 20: + return "Multi Media Masters & Machinary SA"; + case 30: + return "Computer Support Italy s.r.l."; + case 40: + return "FUJI Photo Film Co., Ltd."; + case 50: + return "Auvistar Industry Co., Ltd."; + case 60: + return "CMC Magnetics Corporation"; + } + + break; + case 47: + switch(frm) + { + case 10: + return "Hitachi Maxell, Ltd."; + case 20: + return "Princo Corporation"; + case 40: + return "POSTECH Corporation"; + case 50: + return "Ritek Co."; + case 60: + return "Prodisc Technology Inc."; + } + + break; + case 48: + switch(frm) + { + case 00: + return "Ricoh Company Ltd."; + case 10: + return "Kodak Japan Ltd."; + case 20: + return "Plasmon Data systems Ltd."; + case 30: + return "Pioneer Video Corporation"; + case 40: + return "Digital Storage Technology Co., Ltd."; + case 50: + return "Mitsui Chemicals, Inc."; + case 60: + return "Lead Data Inc."; + } + + break; + case 49: + switch(frm) + { + case 00: + return "TDK Corporation"; + case 10: + return "Gigastore Corporation"; + case 20: + return "King Pro Mediatek Inc."; + case 30: + return "Opti.Me.S. S.p.A."; + case 40: + return "Victor Company of Japan, Ltd."; + case 60: + return "Matsushita Electric Industrial Co., Ltd."; + } + + break; + case 50: + switch(frm) + { + case 10: + return "Vanguard Disc Inc."; + case 20: + return "Mitsubishi Chemical Corporation"; + case 30: + return "CDA Datenträger Albrechts GmbH"; + } + + break; + case 51: + switch(frm) + { + case 10: + return "Grand Advance Technology Ltd."; + case 20: + return "Infodisc Technology Co. Ltd."; + case 50: + return "Hile Optical Disc Technology Corp."; + } + + break; + } + + return ""; + } + +#region Nested type: CDATIP + + public class CDATIP + { + /// Byte 6, bit 2 A1 values are valid + public bool A1Valid; + /// Bytes 16 to 18 A1 values + public byte[] A1Values; + /// Byte 6, bit 1 A2 values are valid + public bool A2Valid; + /// Bytes 20 to 22 A2 values + public byte[] A2Values; + /// Byte 6, bit 0 A3 values are valid + public bool A3Valid; + /// Bytes 24 to 26 A3 values + public byte[] A3Values; + /// Byte 6, bit 7 Always set + public bool AlwaysOne; + /// Byte 5, bit 7 Always unset + public bool AlwaysZero; + /// Bytes 1 to 0 Total size of returned session information minus this field + public ushort DataLength; + /// Byte 4, bit 3 Set if DDCD + public bool DDCD; + /// Byte 6, bits 5 to 3 Disc subtype + public byte DiscSubType; + /// Byte 6, bit 6 Set if rewritable (CD-RW or DDCD-RW) + public bool DiscType; + /// Byte 4, bits 7 to 4 Indicative target writing power + public byte ITWP; + /// Byte 10 ATIP Start time of Lead-In (Frame) + public byte LeadInStartFrame; + /// Byte 8 ATIP Start time of Lead-In (Minute) + public byte LeadInStartMin; + /// Byte 9 ATIP Start time of Lead-In (Second) + public byte LeadInStartSec; + /// Byte 14 ATIP Last possible start time of Lead-Out (Frame) + public byte LeadOutStartFrame; + /// Byte 12 ATIP Last possible start time of Lead-Out (Minute) + public byte LeadOutStartMin; + /// Byte 13 ATIP Last possible start time of Lead-Out (Second) + public byte LeadOutStartSec; + /// Byte 4, bits 2 to 0 Reference speed + public byte ReferenceSpeed; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 31 Reserved + public byte Reserved10; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 5, bits 5 to 0 Reserved + public byte Reserved3; + /// Byte 7 Reserved + public byte Reserved4; + /// Byte 11 Reserved + public byte Reserved5; + /// Byte 15 Reserved + public byte Reserved6; + /// Byte 19 Reserved + public byte Reserved7; + /// Byte 23 Reserved + public byte Reserved8; + /// Byte 27 Reserved + public byte Reserved9; + /// Bytes 28 to 30 S4 values + public byte[] S4Values; + /// Byte 5, bit 6 Unrestricted media + public bool URU; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/CD/CDTextOnLeadIn.cs b/Aaru.Decoders/CD/CDTextOnLeadIn.cs new file mode 100644 index 000000000..a56c1b5ad --- /dev/null +++ b/Aaru.Decoders/CD/CDTextOnLeadIn.cs @@ -0,0 +1,405 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CDTextOnLeadIn.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes CD-TEXT on Lead-In. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.CD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class CDTextOnLeadIn +{ +#region PackTypeIndicator enum + + public enum PackTypeIndicator : byte + { + /// Title of the track (or album if track == 0) + Title = 0x80, + /// Performer + Performer = 0x81, + /// Songwriter + Songwriter = 0x82, + /// Composer + Composer = 0x83, + /// Arranger + Arranger = 0x84, + /// Message from the content provider or artist + Message = 0x85, + /// Disc identification information + DiscIdentification = 0x86, + /// Genre identification + GenreIdentification = 0x87, + /// Table of content information + TOCInformation = 0x88, + /// Second table of content information + SecondTOCInformation = 0x89, + /// Reserved + Reserved1 = 0x8A, + /// Reserved + Reserved2 = 0x8B, + /// Reserved + Reserved3 = 0x8C, + /// Reserved for content provider only + ReservedForContentProvider = 0x8D, + /// UPC of album or ISRC of track + UPCorISRC = 0x8E, + /// Size information of the block + BlockSizeInformation = 0x8F + } + +#endregion + + const string MODULE_NAME = "CD-TEXT decoder"; + + public static CDText? Decode(byte[] CDTextResponse) + { + if(CDTextResponse is not { Length: > 4 }) return null; + + var decoded = new CDText + { + DataLength = BigEndianBitConverter.ToUInt16(CDTextResponse, 0), + Reserved1 = CDTextResponse[2], + Reserved2 = CDTextResponse[3] + }; + + decoded.DataPacks = new CDTextPack[(decoded.DataLength - 2) / 18]; + + if(decoded.DataLength == 2) return null; + + if(decoded.DataLength + 2 != CDTextResponse.Length) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Expected_CD_TEXT_size_0_bytes_is_not_received_size_1_bytes_not_decoding, + decoded.DataLength + 2, + CDTextResponse.Length); + + return null; + } + + for(var i = 0; i < (decoded.DataLength - 2) / 18; i++) + { + decoded.DataPacks[i].HeaderID1 = CDTextResponse[0 + i * 18 + 4]; + decoded.DataPacks[i].HeaderID2 = CDTextResponse[1 + i * 18 + 4]; + decoded.DataPacks[i].HeaderID3 = CDTextResponse[2 + i * 18 + 4]; + decoded.DataPacks[i].DBCC = Convert.ToBoolean(CDTextResponse[3 + i * 18 + 4] & 0x80); + decoded.DataPacks[i].BlockNumber = (byte)((CDTextResponse[3 + i * 18 + 4] & 0x70) >> 4); + decoded.DataPacks[i].CharacterPosition = (byte)(CDTextResponse[3 + i * 18 + 4] & 0x0F); + decoded.DataPacks[i].TextDataField = new byte[12]; + Array.Copy(CDTextResponse, 4 + i * 18 + 4, decoded.DataPacks[i].TextDataField, 0, 12); + decoded.DataPacks[i].CRC = BigEndianBitConverter.ToUInt16(CDTextResponse, 16 + i * 18 + 4); + } + + return decoded; + } + + public static string Prettify(CDText? CDTextResponse) + { + if(CDTextResponse == null) return null; + + CDText response = CDTextResponse.Value; + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); +#endif + + foreach(CDTextPack descriptor in response.DataPacks) + { + if((descriptor.HeaderID1 & 0x80) != 0x80) + { + // Ignore NOPs + if((descriptor.HeaderID1 & 0x80) != 0) + { + sb.AppendFormat(Localization.Incorrect_CD_Text_pack_type_0_not_decoding, descriptor.HeaderID1) + .AppendLine(); + } + } + else + { + switch(descriptor.HeaderID1) + { + case 0x80: + { + if(descriptor.HeaderID2 == 0x00) + sb.AppendLine(Localization.CD_Text_pack_contains_title_for_album); + else + { + sb.AppendFormat(Localization.CD_Text_pack_contains_title_for_track_0, descriptor.HeaderID2) + .AppendLine(); + } + + break; + } + + case 0x81: + { + if(descriptor.HeaderID2 == 0x00) + sb.AppendLine(Localization.CD_Text_pack_contains_performer_for_album); + else + { + sb.AppendFormat(Localization.CD_Text_pack_contains_performer_for_track_0, + descriptor.HeaderID2) + .AppendLine(); + } + + break; + } + + case 0x82: + { + if(descriptor.HeaderID2 == 0x00) + sb.AppendLine(Localization.CD_Text_pack_contains_songwriter_for_album); + else + { + sb.AppendFormat(Localization.CD_Text_pack_contains_songwriter_for_track_0, + descriptor.HeaderID2) + .AppendLine(); + } + + break; + } + + case 0x83: + { + if(descriptor.HeaderID2 == 0x00) + sb.AppendLine(Localization.album); + else + sb.AppendFormat(Localization.track_0, descriptor.HeaderID2).AppendLine(); + + break; + } + + case 0x84: + { + if(descriptor.HeaderID2 == 0x00) + sb.AppendLine(Localization.CD_Text_pack_contains_arranger_for_album); + else + { + sb.AppendFormat(Localization.CD_Text_pack_contains_arranger_for_track_0, + descriptor.HeaderID2) + .AppendLine(); + } + + break; + } + + case 0x85: + { + if(descriptor.HeaderID2 == 0x00) + sb.AppendLine(Localization.CD_Text_pack_contains_content_provider_message_for_album); + else + { + sb.AppendFormat(Localization.CD_Text_pack_contains_content_provider_message_for_track_0, + descriptor.HeaderID2) + .AppendLine(); + } + + break; + } + + case 0x86: + { + sb.AppendLine(Localization.CD_Text_pack_contains_disc_identification_information); + + break; + } + + case 0x87: + { + sb.AppendLine(Localization.CD_Text_pack_contains_genre_identification_information); + + break; + } + + case 0x88: + { + sb.AppendLine(Localization.CD_Text_pack_contains_table_of_contents_information); + + break; + } + + case 0x89: + { + sb.AppendLine(Localization.CD_Text_pack_contains_second_table_of_contents_information); + + break; + } + + case 0x8A: + case 0x8B: + case 0x8C: + { + sb.AppendLine(Localization.CD_Text_pack_contains_reserved_data); + + break; + } + + case 0x8D: + { + sb.AppendLine(Localization.CD_Text_pack_contains_data_reserved_for_content_provider_only); + + break; + } + + case 0x8E: + { + if(descriptor.HeaderID2 == 0x00) + sb.AppendLine(Localization.CD_Text_pack_contains_UPC); + else + sb.AppendFormat(Localization.track_0, descriptor.HeaderID2).AppendLine(); + + break; + } + + case 0x8F: + { + sb.AppendLine(Localization.CD_Text_pack_contains_size_block_information); + + break; + } + } + + switch(descriptor.HeaderID1) + { + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x8E: + { + if(descriptor.DBCC) sb.AppendLine(Localization.Double_Byte_Character_Code_is_used); + + sb.AppendFormat(Localization.Block_number_0, descriptor.BlockNumber).AppendLine(); + sb.AppendFormat(Localization.Character_position_0, descriptor.CharacterPosition).AppendLine(); + + sb.AppendFormat(Localization.Text_field_0, + StringHandlers.CToString(descriptor.TextDataField, + Encoding.GetEncoding("iso-8859-1"))) + .AppendLine(); + + break; + } + + default: + { + sb.AppendFormat(Localization.Binary_contents_0, + PrintHex.ByteArrayToHexArrayString(descriptor.TextDataField, 28)) + .AppendLine(); + + break; + } + } + + sb.AppendFormat(Localization.CRC_0_X4, descriptor.CRC).AppendLine(); + } + } + + return sb.ToString(); + } + + public static string Prettify(byte[] CDTextResponse) + { + CDText? decoded = Decode(CDTextResponse); + + return Prettify(decoded); + } + +#region Nested type: CDText + + public struct CDText + { + /// Total size of returned CD-Text information minus this field + public ushort DataLength; + /// Reserved + public byte Reserved1; + /// Reserved + public byte Reserved2; + /// CD-Text data packs + public CDTextPack[] DataPacks; + } + +#endregion + +#region Nested type: CDTextPack + + public struct CDTextPack + { + /// Byte 0 Pack ID1 (Pack Type) + public byte HeaderID1; + /// Byte 1 Pack ID2 (Track number) + public byte HeaderID2; + /// Byte 2 Pack ID3 + public byte HeaderID3; + /// Byte 3, bit 7 Double Byte Character Code + public bool DBCC; + /// Byte 3, bits 6 to 4 Block number + public byte BlockNumber; + /// Byte 3, bits 3 to 0 Character position + public byte CharacterPosition; + /// Bytes 4 to 15 Text data + public byte[] TextDataField; + /// Bytes 16 to 17 CRC16 + public ushort CRC; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/CD/Enums.cs b/Aaru.Decoders/CD/Enums.cs new file mode 100644 index 000000000..d9eb3ee95 --- /dev/null +++ b/Aaru.Decoders/CD/Enums.cs @@ -0,0 +1,72 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains various CD enumerations. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.CD; + +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +public enum TocAdr : byte +{ + /// Q Sub-channel mode information not supplied + NoInformation = 0x00, + /// Q Sub-channel encodes current position data + CurrentPosition = 0x01, + /// Q Sub-channel encodes the media catalog number + MediaCatalogNumber = 0x02, + /// Q Sub-channel encodes the ISRC + ISRC = 0x03, + /// Q Sub-channel encodes the start of an audio/data track (if found in TOC) + TrackPointer = 0x01, + /// Q Sub-channel encodes the start of a video track (if found in TOC) for CD-V + VideoTrackPointer = 0x04 +} + +public enum TocControl : byte +{ + /// Stereo audio, no pre-emphasis + TwoChanNoPreEmph = 0x00, + /// Stereo audio with pre-emphasis + TwoChanPreEmph = 0x01, + /// If mask applied, track can be copied + CopyPermissionMask = 0x02, + /// Data track, recorded uninterrumpted + DataTrack = 0x04, + /// Data track, recorded incrementally + DataTrackIncremental = 0x05, + /// Quadraphonic audio, no pre-emphasis + FourChanNoPreEmph = 0x08, + /// Quadraphonic audio with pre-emphasis + FourChanPreEmph = 0x09, + /// Reserved mask + ReservedMask = 0x0C +} \ No newline at end of file diff --git a/Aaru.Decoders/CD/FullTOC.cs b/Aaru.Decoders/CD/FullTOC.cs new file mode 100644 index 000000000..375861a97 --- /dev/null +++ b/Aaru.Decoders/CD/FullTOC.cs @@ -0,0 +1,860 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : FullTOC.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes CD full Table of Contents. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Structs; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.CD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ISO/IEC 61104: Compact disc video system - 12 cm CD-V +// ISO/IEC 60908: Audio recording - Compact disc digital audio system +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class FullTOC +{ + const string MODULE_NAME = "CD full TOC decoder"; + + public static CDFullTOC? Decode(byte[] CDFullTOCResponse) + { + if(CDFullTOCResponse is not { Length: > 4 }) return null; + + var decoded = new CDFullTOC + { + DataLength = BigEndianBitConverter.ToUInt16(CDFullTOCResponse, 0), + FirstCompleteSession = CDFullTOCResponse[2], + LastCompleteSession = CDFullTOCResponse[3] + }; + + decoded.TrackDescriptors = new TrackDataDescriptor[(decoded.DataLength - 2) / 11]; + + if(decoded.DataLength + 2 != CDFullTOCResponse.Length) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Expected_CDFullTOC_size_0_bytes_is_not_received_size_1_bytes_not_decoding, + decoded.DataLength + 2, + CDFullTOCResponse.Length); + + return null; + } + + for(var i = 0; i < (decoded.DataLength - 2) / 11; i++) + { + decoded.TrackDescriptors[i].SessionNumber = CDFullTOCResponse[0 + i * 11 + 4]; + decoded.TrackDescriptors[i].ADR = (byte)((CDFullTOCResponse[1 + i * 11 + 4] & 0xF0) >> 4); + decoded.TrackDescriptors[i].CONTROL = (byte)(CDFullTOCResponse[1 + i * 11 + 4] & 0x0F); + decoded.TrackDescriptors[i].TNO = CDFullTOCResponse[2 + i * 11 + 4]; + decoded.TrackDescriptors[i].POINT = CDFullTOCResponse[3 + i * 11 + 4]; + decoded.TrackDescriptors[i].Min = CDFullTOCResponse[4 + i * 11 + 4]; + decoded.TrackDescriptors[i].Sec = CDFullTOCResponse[5 + i * 11 + 4]; + decoded.TrackDescriptors[i].Frame = CDFullTOCResponse[6 + i * 11 + 4]; + decoded.TrackDescriptors[i].Zero = CDFullTOCResponse[7 + i * 11 + 4]; + decoded.TrackDescriptors[i].HOUR = (byte)((CDFullTOCResponse[7 + i * 11 + 4] & 0xF0) >> 4); + decoded.TrackDescriptors[i].PHOUR = (byte)(CDFullTOCResponse[7 + i * 11 + 4] & 0x0F); + decoded.TrackDescriptors[i].PMIN = CDFullTOCResponse[8 + i * 11 + 4]; + decoded.TrackDescriptors[i].PSEC = CDFullTOCResponse[9 + i * 11 + 4]; + decoded.TrackDescriptors[i].PFRAME = CDFullTOCResponse[10 + i * 11 + 4]; + } + + return decoded; + } + + public static string Prettify(CDFullTOC? CDFullTOCResponse) + { + if(CDFullTOCResponse == null) return null; + + CDFullTOC response = CDFullTOCResponse.Value; + + var sb = new StringBuilder(); + + var lastSession = 0; + + sb.AppendFormat(Localization.First_complete_session_number_0, response.FirstCompleteSession).AppendLine(); + sb.AppendFormat(Localization.Last_complete_session_number_0, response.LastCompleteSession).AppendLine(); + + foreach(TrackDataDescriptor descriptor in response.TrackDescriptors) + { + if((descriptor.CONTROL & 0x08) == 0x08 || + descriptor.ADR != 1 && descriptor.ADR != 5 && descriptor.ADR != 4 && descriptor.ADR != 6 || + descriptor.TNO != 0) + { + sb.AppendLine(Localization.Unknown_TOC_entry_format_printing_values_as_is); + sb.AppendLine($"SessionNumber = {descriptor.SessionNumber}"); + sb.AppendLine($"ADR = {descriptor.ADR}"); + sb.AppendLine($"CONTROL = {descriptor.CONTROL}"); + sb.AppendLine($"TNO = {descriptor.TNO}"); + sb.AppendLine($"POINT = {descriptor.POINT}"); + sb.AppendLine($"Min = {descriptor.Min}"); + sb.AppendLine($"Sec = {descriptor.Sec}"); + sb.AppendLine($"Frame = {descriptor.Frame}"); + sb.AppendLine($"HOUR = {descriptor.HOUR}"); + sb.AppendLine($"PHOUR = {descriptor.PHOUR}"); + sb.AppendLine($"PMIN = {descriptor.PMIN}"); + sb.AppendLine($"PSEC = {descriptor.PSEC}"); + sb.AppendLine($"PFRAME = {descriptor.PFRAME}"); + } + else + { + if(descriptor.SessionNumber > lastSession) + { + sb.AppendFormat(Localization.Session_0, descriptor.SessionNumber).AppendLine(); + lastSession = descriptor.SessionNumber; + } + + switch(descriptor.ADR) + { + case 1: + case 4: + { + switch(descriptor.POINT) + { + case 0xA0 when descriptor.ADR == 4: + { + sb.AppendFormat(Localization.First_video_track_number_0, descriptor.PMIN).AppendLine(); + + switch(descriptor.PSEC) + { + case 0x10: + sb.AppendLine(Localization + .CD_V_single_in_NTSC_format_with_digital_stereo_sound); + + break; + case 0x11: + sb.AppendLine(Localization + .CD_V_single_in_NTSC_format_with_digital_bilingual_sound); + + break; + case 0x12: + sb.AppendLine(Localization.CD_V_disc_in_NTSC_format_with_digital_stereo_sound); + + break; + case 0x13: + sb.AppendLine(Localization + .CD_V_disc_in_NTSC_format_with_digital_bilingual_sound); + + break; + case 0x20: + sb.AppendLine(Localization.CD_V_single_in_PAL_format_with_digital_stereo_sound); + + break; + case 0x21: + sb.AppendLine(Localization + .CD_V_single_in_PAL_format_with_digital_bilingual_sound); + + break; + case 0x22: + sb.AppendLine(Localization.CD_V_disc_in_PAL_format_with_digital_stereo_sound); + + break; + case 0x23: + sb.AppendLine(Localization + .CD_V_disc_in_PAL_format_with_digital_bilingual_sound); + + break; + } + + break; + } + + case 0xA0 when descriptor.ADR == 1: + { + sb.AppendFormat(Localization.First_track_number_0_open_parenthesis, descriptor.PMIN); + + switch((TocControl)(descriptor.CONTROL & 0x0D)) + { + case TocControl.TwoChanNoPreEmph: + sb.Append(Localization.Stereo_audio_track_with_no_pre_emphasis); + + break; + case TocControl.TwoChanPreEmph: + sb.Append(Localization.Stereo_audio_track_with_50_15_us_pre_emphasis); + + break; + case TocControl.FourChanNoPreEmph: + sb.Append(Localization.Quadraphonic_audio_track_with_no_pre_emphasis); + + break; + case TocControl.FourChanPreEmph: + sb.Append(Localization.Quadraphonic_audio_track_with_50_15_us_pre_emphasis); + + break; + case TocControl.DataTrack: + sb.Append(Localization.Data_track_recorded_uninterrupted); + + break; + case TocControl.DataTrackIncremental: + sb.Append(Localization.Data_track_recorded_incrementally); + + break; + } + + sb.AppendLine(Localization.close_parenthesis); + sb.AppendFormat(Localization.Disc_type_0, descriptor.PSEC).AppendLine(); + + //sb.AppendFormat("Absolute time: {3:D2}:{0:D2}:{1:D2}:{2:D2}", descriptor.Min, descriptor.Sec, descriptor.Frame, descriptor.HOUR).AppendLine(); + break; + } + + case 0xA1 when descriptor.ADR == 4: + sb.AppendFormat(Localization.Last_video_track_number_0, descriptor.PMIN).AppendLine(); + + break; + case 0xA1 when descriptor.ADR == 1: + { + sb.AppendFormat(Localization.Last_track_number_0_open_parenthesis, descriptor.PMIN); + + switch((TocControl)(descriptor.CONTROL & 0x0D)) + { + case TocControl.TwoChanNoPreEmph: + sb.Append(Localization.Stereo_audio_track_with_no_pre_emphasis); + + break; + case TocControl.TwoChanPreEmph: + sb.Append(Localization.Stereo_audio_track_with_50_15_us_pre_emphasis); + + break; + case TocControl.FourChanNoPreEmph: + sb.Append(Localization.Quadraphonic_audio_track_with_no_pre_emphasis); + + break; + case TocControl.FourChanPreEmph: + sb.Append(Localization.Quadraphonic_audio_track_with_50_15_us_pre_emphasis); + + break; + case TocControl.DataTrack: + sb.Append(Localization.Data_track_recorded_uninterrupted); + + break; + case TocControl.DataTrackIncremental: + sb.Append(Localization.Data_track_recorded_incrementally); + + break; + } + + sb.AppendLine(Localization.close_parenthesis); + + //sb.AppendFormat("Absolute time: {3:D2}:{0:D2}:{1:D2}:{2:D2}", descriptor.Min, descriptor.Sec, descriptor.Frame, descriptor.HOUR).AppendLine(); + break; + } + + case 0xA2: + { + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization.Lead_out_start_position_3_0_1_2, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Lead_out_start_position_0_1_2, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME) + .AppendLine(); + } + + //sb.AppendFormat("Absolute time: {3:D2}:{0:D2}:{1:D2}:{2:D2}", descriptor.Min, descriptor.Sec, descriptor.Frame, descriptor.HOUR).AppendLine(); + + switch((TocControl)(descriptor.CONTROL & 0x0D)) + { + case TocControl.TwoChanNoPreEmph: + case TocControl.TwoChanPreEmph: + case TocControl.FourChanNoPreEmph: + case TocControl.FourChanPreEmph: + sb.AppendLine(Localization.Lead_out_is_audio_type); + + break; + case TocControl.DataTrack: + case TocControl.DataTrackIncremental: + sb.AppendLine(Localization.Lead_out_is_data_type); + + break; + } + + break; + } + + case 0xF0: + { + sb.AppendFormat(Localization.Book_type_0, descriptor.PMIN); + sb.AppendFormat(Localization.Material_type_0, descriptor.PSEC); + sb.AppendFormat(Localization.Moment_of_inertia_0, descriptor.PFRAME); + + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization.Absolute_time_3_0_1_2, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Absolute_time_0_1_2, + descriptor.Min, + descriptor.Sec, + descriptor.Frame) + .AppendLine(); + } + + break; + } + + default: + { + if(descriptor.POINT is >= 0x01 and <= 0x63) + { + if(descriptor.ADR == 4) + { + sb.AppendFormat(Localization.Video_track_3_starts_at_0_1_2, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.POINT) + .AppendLine(); + } + else + { + bool data = (TocControl)(descriptor.CONTROL & 0x0D) == TocControl.DataTrack || + (TocControl)(descriptor.CONTROL & 0x0D) == + TocControl.DataTrackIncremental; + + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(data + ? Localization + .Data_track_3_starts_at_4_0_1_2_open_parenthesis + : Localization + .Audio_track_3_starts_at_4_0_1_2_open_parenthesis, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.POINT, + descriptor.PHOUR); + } + + else + { + sb.AppendFormat(data + ? Localization + .Data_track_3_starts_at_0_1_2_open_parenthesis + : Localization + .Audio_track_3_starts_at_0_1_2_open_parenthesis, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.POINT); + } + + switch((TocControl)(descriptor.CONTROL & 0x0D)) + { + case TocControl.TwoChanNoPreEmph: + sb.Append(Localization.Stereo_audio_track_with_no_pre_emphasis); + + break; + case TocControl.TwoChanPreEmph: + sb.Append(Localization.Stereo_audio_track_with_50_15_us_pre_emphasis); + + break; + case TocControl.FourChanNoPreEmph: + sb.Append(Localization.Quadraphonic_audio_track_with_no_pre_emphasis); + + break; + case TocControl.FourChanPreEmph: + sb.Append(Localization + .Quadraphonic_audio_track_with_50_15_us_pre_emphasis); + + break; + case TocControl.DataTrack: + sb.Append(Localization.Data_track_recorded_uninterrupted); + + break; + case TocControl.DataTrackIncremental: + sb.Append(Localization.Data_track_recorded_incrementally); + + break; + } + + sb.AppendLine(Localization.close_parenthesis); + } + } + else + { + sb.Append($"ADR = {descriptor.ADR}").AppendLine(); + sb.Append($"CONTROL = {descriptor.CONTROL}").AppendLine(); + sb.Append($"TNO = {descriptor.TNO}").AppendLine(); + sb.Append($"POINT = {descriptor.POINT}").AppendLine(); + sb.Append($"Min = {descriptor.Min}").AppendLine(); + sb.Append($"Sec = {descriptor.Sec}").AppendLine(); + sb.Append($"Frame = {descriptor.Frame}").AppendLine(); + sb.Append($"HOUR = {descriptor.HOUR}").AppendLine(); + sb.Append($"PHOUR = {descriptor.PHOUR}").AppendLine(); + sb.Append($"PMIN = {descriptor.PMIN}").AppendLine(); + sb.Append($"PSEC = {descriptor.PSEC}").AppendLine(); + sb.Append($"PFRAME = {descriptor.PFRAME}").AppendLine(); + } + + break; + } + } + + break; + } + + case 5: + { + switch(descriptor.POINT) + { + case 0xB0: + { + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization + .Start_of_next_possible_program_in_the_recordable_area_of_the_disc_3_0_1_2, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR) + .AppendLine(); + + sb.AppendFormat(Localization + .Maximum_start_of_outermost_Lead_out_in_the_recordable_area_of_the_disc_3_0_1_2, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization + .Start_of_next_possible_program_in_the_recordable_area_of_the_disc_0_1_2, + descriptor.Min, + descriptor.Sec, + descriptor.Frame) + .AppendLine(); + + sb.AppendFormat(Localization + .Maximum_start_of_outermost_Lead_out_in_the_recordable_area_of_the_disc_0_1_2, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME) + .AppendLine(); + } + + break; + } + + case 0xB1: + { + sb.AppendFormat(Localization.Number_of_skip_interval_pointers_0, descriptor.PMIN) + .AppendLine(); + + sb.AppendFormat(Localization.Number_of_skip_track_pointers_0, descriptor.PSEC) + .AppendLine(); + + break; + } + + case 0xB2: + case 0xB3: + case 0xB4: + { + sb.AppendFormat(Localization.Skip_track_0, descriptor.Min).AppendLine(); + sb.AppendFormat(Localization.Skip_track_0, descriptor.Sec).AppendLine(); + sb.AppendFormat(Localization.Skip_track_0, descriptor.Frame).AppendLine(); + sb.AppendFormat(Localization.Skip_track_0, descriptor.Zero).AppendLine(); + sb.AppendFormat(Localization.Skip_track_0, descriptor.PMIN).AppendLine(); + sb.AppendFormat(Localization.Skip_track_0, descriptor.PSEC).AppendLine(); + sb.AppendFormat(Localization.Skip_track_0, descriptor.PFRAME).AppendLine(); + + break; + } + + case 0xC0: + { + sb.AppendFormat(Localization.Optimum_recording_power_0, descriptor.Min).AppendLine(); + + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization + .Start_time_of_the_first_Lead_in_area_in_the_disc_3_0_1_2, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Start_time_of_the_first_Lead_in_area_in_the_disc_0_1_2, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME) + .AppendLine(); + } + + break; + } + + case 0xC1: + { + sb.AppendFormat(Localization.Copy_of_information_of_A1_from_ATIP_found); + sb.Append($"Min = {descriptor.Min}").AppendLine(); + sb.Append($"Sec = {descriptor.Sec}").AppendLine(); + sb.Append($"Frame = {descriptor.Frame}").AppendLine(); + sb.Append($"Zero = {descriptor.Zero}").AppendLine(); + sb.Append($"PMIN = {descriptor.PMIN}").AppendLine(); + sb.Append($"PSEC = {descriptor.PSEC}").AppendLine(); + sb.Append($"PFRAME = {descriptor.PFRAME}").AppendLine(); + + break; + } + + case 0xCF: + { + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization.Start_position_of_outer_part_lead_in_area_3_0_1_2, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR) + .AppendLine(); + + sb.AppendFormat(Localization.Stop_position_of_inner_part_lead_out_area_3_0_1_2, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Start_position_of_outer_part_lead_in_area_0_1_2, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME) + .AppendLine(); + + sb.AppendFormat(Localization.Stop_position_of_inner_part_lead_out_area_0_1_2, + descriptor.Min, + descriptor.Sec, + descriptor.Frame) + .AppendLine(); + } + + break; + } + + default: + { + if(descriptor.POINT is >= 0x01 and <= 0x40) + { + sb.AppendFormat(Localization.Start_time_for_interval_that_should_be_skipped_0_1_2, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME) + .AppendLine(); + + sb.AppendFormat(Localization.Ending_time_for_interval_that_should_be_skipped_0_1_2, + descriptor.Min, + descriptor.Sec, + descriptor.Frame) + .AppendLine(); + } + else + { + sb.Append($"ADR = {descriptor.ADR}").AppendLine(); + sb.Append($"CONTROL = {descriptor.CONTROL}").AppendLine(); + sb.Append($"TNO = {descriptor.TNO}").AppendLine(); + sb.Append($"POINT = {descriptor.POINT}").AppendLine(); + sb.Append($"Min = {descriptor.Min}").AppendLine(); + sb.Append($"Sec = {descriptor.Sec}").AppendLine(); + sb.Append($"Frame = {descriptor.Frame}").AppendLine(); + sb.Append($"HOUR = {descriptor.HOUR}").AppendLine(); + sb.Append($"PHOUR = {descriptor.PHOUR}").AppendLine(); + sb.Append($"PMIN = {descriptor.PMIN}").AppendLine(); + sb.Append($"PSEC = {descriptor.PSEC}").AppendLine(); + sb.Append($"PFRAME = {descriptor.PFRAME}").AppendLine(); + } + + break; + } + } + + break; + } + + case 6: + { + var id = (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame); + sb.AppendFormat(Localization.Disc_ID_0_X6, id & 0x00FFFFFF).AppendLine(); + + break; + } + } + } + } + + return sb.ToString(); + } + + public static string Prettify(byte[] CDFullTOCResponse) + { + CDFullTOC? decoded = Decode(CDFullTOCResponse); + + return Prettify(decoded); + } + + public static CDFullTOC Create(List tracks, Dictionary trackFlags, bool createC0Entry = false) + { + var toc = new CDFullTOC(); + Dictionary sessionEndingTrack = new(); + toc.FirstCompleteSession = byte.MaxValue; + toc.LastCompleteSession = byte.MinValue; + List trackDescriptors = []; + byte currentTrack = 0; + + foreach(Track track in tracks.OrderBy(t => t.Session).ThenBy(t => t.Sequence)) + { + if(track.Session < toc.FirstCompleteSession) toc.FirstCompleteSession = (byte)track.Session; + + if(track.Session <= toc.LastCompleteSession) + { + currentTrack = (byte)track.Sequence; + + continue; + } + + if(toc.LastCompleteSession > 0) sessionEndingTrack.Add(toc.LastCompleteSession, currentTrack); + + toc.LastCompleteSession = (byte)track.Session; + } + + sessionEndingTrack.TryAdd(toc.LastCompleteSession, + (byte)tracks.Where(t => t.Session == toc.LastCompleteSession).Max(t => t.Sequence)); + + byte currentSession = 0; + + foreach(Track track in tracks.OrderBy(t => t.Session).ThenBy(t => t.Sequence)) + { + trackFlags.TryGetValue((byte)track.Sequence, out byte trackControl); + + if(trackControl == 0 && track.Type != TrackType.Audio) trackControl = (byte)CdFlags.DataTrack; + + // Lead-Out + if(track.Session > currentSession && currentSession != 0) + { + (byte minute, byte second, byte frame) leadoutAmsf = LbaToMsf(track.StartSector - 150); + + (byte minute, byte second, byte frame) leadoutPmsf = + LbaToMsf(tracks.OrderBy(t => t.Session).ThenBy(t => t.Sequence).Last().StartSector); + + // Lead-out + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = currentSession, + POINT = 0xB0, + ADR = 5, + CONTROL = 0, + HOUR = 0, + Min = leadoutAmsf.minute, + Sec = leadoutAmsf.second, + Frame = leadoutAmsf.frame, + PHOUR = 2, + PMIN = leadoutPmsf.minute, + PSEC = leadoutPmsf.second, + PFRAME = leadoutPmsf.frame + }); + + // This seems to be constant? It should not exist on CD-ROM but CloneCD creates them anyway + // Format seems like ATIP, but ATIP should not be as 0xC0 in TOC... + if(createC0Entry) + { + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = currentSession, + POINT = 0xC0, + ADR = 5, + CONTROL = 0, + Min = 128, + PMIN = 97, + PSEC = 25 + }); + } + } + + // Lead-in + if(track.Session > currentSession) + { + currentSession = (byte)track.Session; + sessionEndingTrack.TryGetValue(currentSession, out byte endingTrackNumber); + + (byte minute, byte second, byte frame) leadinPmsf = + LbaToMsf((tracks.FirstOrDefault(t => t.Sequence == endingTrackNumber)?.EndSector ?? 0) + 1); + + // Starting track + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = currentSession, + POINT = 0xA0, + ADR = 1, + CONTROL = trackControl, + PMIN = (byte)track.Sequence + }); + + // Ending track + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = currentSession, + POINT = 0xA1, + ADR = 1, + CONTROL = trackControl, + PMIN = endingTrackNumber + }); + + // Lead-out start + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = currentSession, + POINT = 0xA2, + ADR = 1, + CONTROL = trackControl, + PHOUR = 0, + PMIN = leadinPmsf.minute, + PSEC = leadinPmsf.second, + PFRAME = leadinPmsf.frame + }); + } + + (byte minute, byte second, byte frame) pmsf = LbaToMsf((ulong)track.Indexes[1]); + + // Track + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = (byte)track.Session, + POINT = (byte)track.Sequence, + ADR = 1, + CONTROL = trackControl, + PHOUR = 0, + PMIN = pmsf.minute, + PSEC = pmsf.second, + PFRAME = pmsf.frame + }); + } + + toc.TrackDescriptors = trackDescriptors.ToArray(); + + return toc; + } + + static (byte minute, byte second, byte frame) LbaToMsf(ulong sector) => + ((byte)((sector + 150) / 75 / 60), (byte)((sector + 150) / 75 % 60), (byte)((sector + 150) % 75)); + +#region Nested type: CDFullTOC + + public struct CDFullTOC + { + /// Total size of returned session information minus this field + public ushort DataLength; + /// First complete session number in hex + public byte FirstCompleteSession; + /// Last complete session number in hex + public byte LastCompleteSession; + /// Track descriptors + public TrackDataDescriptor[] TrackDescriptors; + } + +#endregion + +#region Nested type: TrackDataDescriptor + + public struct TrackDataDescriptor + { + /// Byte 0 Session number in hex + public byte SessionNumber; + /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found + public byte ADR; + /// Byte 1, bits 3 to 0 Track attributes + public byte CONTROL; + /// Byte 2 + public byte TNO; + /// Byte 3 + public byte POINT; + /// Byte 4 + public byte Min; + /// Byte 5 + public byte Sec; + /// Byte 6 + public byte Frame; + /// Byte 7, CD only + public byte Zero; + /// Byte 7, bits 7 to 4, DDCD only + public byte HOUR; + /// Byte 7, bits 3 to 0, DDCD only + public byte PHOUR; + /// Byte 8 + public byte PMIN; + /// Byte 9 + public byte PSEC; + /// Byte 10 + public byte PFRAME; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/CD/PMA.cs b/Aaru.Decoders/CD/PMA.cs new file mode 100644 index 000000000..c7774e4e3 --- /dev/null +++ b/Aaru.Decoders/CD/PMA.cs @@ -0,0 +1,502 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PMA.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes CD Power Management Area. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.CD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class PMA +{ + const string MODULE_NAME = "CD PMA decoder"; + + public static CDPMA? Decode(byte[] CDPMAResponse) + { + if(CDPMAResponse is not { Length: > 4 }) return null; + + var decoded = new CDPMA + { + DataLength = BigEndianBitConverter.ToUInt16(CDPMAResponse, 0), + Reserved1 = CDPMAResponse[2], + Reserved2 = CDPMAResponse[3] + }; + + decoded.PMADescriptors = new CDPMADescriptors[(decoded.DataLength - 2) / 11]; + + if(decoded.PMADescriptors.Length == 0) return null; + + if(decoded.DataLength + 2 != CDPMAResponse.Length) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Expected_CD_PMA_size_0_bytes_is_not_received_size_1_bytes_not_decoding, + decoded.DataLength + 2, + CDPMAResponse.Length); + + return null; + } + + for(var i = 0; i < (decoded.DataLength - 2) / 11; i++) + { + decoded.PMADescriptors[i].Reserved = CDPMAResponse[0 + i * 11 + 4]; + decoded.PMADescriptors[i].ADR = (byte)((CDPMAResponse[1 + i * 11 + 4] & 0xF0) >> 4); + decoded.PMADescriptors[i].CONTROL = (byte)(CDPMAResponse[1 + i * 11 + 4] & 0x0F); + decoded.PMADescriptors[i].TNO = CDPMAResponse[2 + i * 11 + 4]; + decoded.PMADescriptors[i].POINT = CDPMAResponse[3 + i * 11 + 4]; + decoded.PMADescriptors[i].Min = CDPMAResponse[4 + i * 11 + 4]; + decoded.PMADescriptors[i].Sec = CDPMAResponse[5 + i * 11 + 4]; + decoded.PMADescriptors[i].Frame = CDPMAResponse[6 + i * 11 + 4]; + decoded.PMADescriptors[i].HOUR = (byte)((CDPMAResponse[7 + i * 11 + 4] & 0xF0) >> 4); + decoded.PMADescriptors[i].PHOUR = (byte)(CDPMAResponse[7 + i * 11 + 4] & 0x0F); + decoded.PMADescriptors[i].PMIN = CDPMAResponse[8 + i * 11 + 4]; + decoded.PMADescriptors[i].PSEC = CDPMAResponse[9 + i * 11 + 4]; + decoded.PMADescriptors[i].PFRAME = CDPMAResponse[10 + i * 11 + 4]; + } + + return decoded; + } + + public static string Prettify(CDPMA? CDPMAResponse) + { + if(CDPMAResponse == null) return null; + + CDPMA response = CDPMAResponse.Value; + + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); +#endif + + foreach(CDPMADescriptors descriptor in response.PMADescriptors) + { +#if DEBUG + if(descriptor.Reserved != 0) + sb.AppendFormat(Localization.Reserved_equals_0_X2, descriptor.Reserved).AppendLine(); +#endif + + List tracks; + + switch(descriptor.ADR) + { + case 1: + if(descriptor.POINT > 0) + { + switch((TocControl)(descriptor.CONTROL & 0x0D)) + { + case TocControl.TwoChanNoPreEmph: + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization + .Track_0_Stereo_audio_track_with_no_pre_emphasis_starts_at_4_1_2_3_and_ends_at_8_5_6_7, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR); + } + else + { + sb.AppendFormat(Localization + .Track_0_Stereo_audio_track_with_no_pre_emphasis_starts_at_1_2_3_and_ends_at_4_5_6, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.Min, + descriptor.Sec, + descriptor.Frame); + } + + break; + case TocControl.TwoChanPreEmph: + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization + .Track_0_Stereo_audio_track_with_50_15_s_pre_emphasis_starts_at_4_1_2_3_and_ends_at_8_5_6_7, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR); + } + else + { + sb.AppendFormat(Localization + .Track_0_Stereo_audio_track_with_50_15_us_pre_emphasis_starts_at_1_2_3_and_ends_at_4_5_6, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.Min, + descriptor.Sec, + descriptor.Frame); + } + + break; + case TocControl.FourChanNoPreEmph: + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization + .Track_0_Quadraphonic_audio_track_with_no_pre_emphasis_starts_at_4_1_2_3_and_ends_at_8_5_6_7, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR); + } + else + { + sb.AppendFormat(Localization + .Track_0_Quadraphonic_audio_track_with_no_pre_emphasis_starts_at_1_2_3_and_ends_at_4_5_6, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.Min, + descriptor.Sec, + descriptor.Frame); + } + + break; + case TocControl.FourChanPreEmph: + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization + .Track_0_Quadraphonic_audio_track_with_50_15_us_pre_emphasis_starts_at_4_1_2_3_and_ends_at_8_5_6_7, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR); + } + else + { + sb.AppendFormat(Localization + .Track_0_Quadraphonic_audio_track_with_50_15_us_pre_emphasis_starts_at_1_2_3_and_ends_at_4_5_6, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.Min, + descriptor.Sec, + descriptor.Frame); + } + + break; + case TocControl.DataTrack: + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization + .Track_0_Data_track_recorded_uninterrupted_starts_at_4_1_2_3_and_ends_at_8_5_6_7, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR); + } + else + { + sb.AppendFormat(Localization + .Track_0_Data_track_recorded_uninterrupted_starts_at_1_2_3_and_ends_at_4_5_6, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.Min, + descriptor.Sec, + descriptor.Frame); + } + + break; + case TocControl.DataTrackIncremental: + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization + .Track_0_Data_track_recorded_incrementally_starts_at_4_1_2_3_and_ends_at_8_5_6_7, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR); + } + else + { + sb.AppendFormat(Localization + .Track_0_Data_track_recorded_incrementally_starts_at_1_2_3_and_ends_at_4_5_6, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.Min, + descriptor.Sec, + descriptor.Frame); + } + + break; + } + + sb.AppendLine(); + } + else + goto default; + + break; + case 2: + var id = (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame); + sb.AppendFormat(Localization.Disc_ID_0_X6, id & 0x00FFFFFF).AppendLine(); + + break; + case 3: + tracks = []; + + if(descriptor.Min > 0) tracks.Add($"{descriptor.Min}"); + + if(descriptor.Sec > 0) tracks.Add($"{descriptor.Sec}"); + + if(descriptor.Frame > 0) tracks.Add($"{descriptor.Frame}"); + + if(descriptor.PMIN > 0) tracks.Add($"{descriptor.PMIN}"); + + if(descriptor.PSEC > 0) tracks.Add($"{descriptor.PSEC}"); + + if(descriptor.PFRAME > 0) tracks.Add($"{descriptor.PFRAME}"); + + sb.AppendFormat(Localization.Skip_track_assignment_0_says_that_tracks_1_should_be_skipped, + descriptor.POINT, + string.Join(' ', tracks)); + + break; + case 4: + tracks = []; + + if(descriptor.Min > 0) tracks.Add($"{descriptor.Min}"); + + if(descriptor.Sec > 0) tracks.Add($"{descriptor.Sec}"); + + if(descriptor.Frame > 0) tracks.Add($"{descriptor.Frame}"); + + if(descriptor.PMIN > 0) tracks.Add($"{descriptor.PMIN}"); + + if(descriptor.PSEC > 0) tracks.Add($"{descriptor.PSEC}"); + + if(descriptor.PFRAME > 0) tracks.Add($"{descriptor.PFRAME}"); + + sb.AppendFormat(Localization.Unskip_track_assignment_0_says_that_tracks_1_should_not_be_skipped, + descriptor.POINT, + string.Join(' ', tracks)); + + break; + case 5: + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization + .Skip_time_interval_assignment_0_says_that_from_4_1_2_3_to_8_5_6_7_should_be_skipped, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR); + } + else + { + sb.AppendFormat(Localization + .Skip_time_interval_assignment_0_says_that_from_1_2_3_to_4_5_6_should_be_skipped, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.Min, + descriptor.Sec, + descriptor.Frame); + } + + break; + case 6: + if(descriptor.PHOUR > 0) + { + sb.AppendFormat(Localization + .Unskip_time_interval_assignment_0_says_that_from_4_1_2_3_to_8_5_6_7_should_not_be_skipped, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.PHOUR, + descriptor.Min, + descriptor.Sec, + descriptor.Frame, + descriptor.HOUR); + } + else + { + sb.AppendFormat(Localization + .Unskip_time_interval_assignment_0_says_that_from_1_2_3_to_4_5_6_should_not_be_skipped, + descriptor.POINT, + descriptor.PMIN, + descriptor.PSEC, + descriptor.PFRAME, + descriptor.Min, + descriptor.Sec, + descriptor.Frame); + } + + break; + default: + + sb.AppendLine($"ADR = {descriptor.ADR}"); + sb.AppendLine($"CONTROL = {descriptor.CONTROL}"); + sb.AppendLine($"TNO = {descriptor.TNO}"); + sb.AppendLine($"POINT = {descriptor.POINT}"); + sb.AppendLine($"Min = {descriptor.Min}"); + sb.AppendLine($"Sec = {descriptor.Sec}"); + sb.AppendLine($"Frame = {descriptor.Frame}"); + sb.AppendLine($"HOUR = {descriptor.HOUR}"); + sb.AppendLine($"PHOUR = {descriptor.PHOUR}"); + sb.AppendLine($"PMIN = {descriptor.PMIN}"); + sb.AppendLine($"PSEC = {descriptor.PSEC}"); + sb.AppendLine($"PFRAME = {descriptor.PFRAME}"); + + break; + } + } + + return sb.ToString(); + } + + public static string Prettify(byte[] CDPMAResponse) + { + CDPMA? decoded = Decode(CDPMAResponse); + + return Prettify(decoded); + } + +#region Nested type: CDPMA + + public struct CDPMA + { + /// Total size of returned session information minus this field + public ushort DataLength; + /// Reserved + public byte Reserved1; + /// Reserved + public byte Reserved2; + /// Track descriptors + public CDPMADescriptors[] PMADescriptors; + } + +#endregion + +#region Nested type: CDPMADescriptors + + public struct CDPMADescriptors + { + /// Byte 0 Reserved + public byte Reserved; + /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found + public byte ADR; + /// Byte 1, bits 3 to 0 Track attributes + public byte CONTROL; + /// Byte 2 + public byte TNO; + /// Byte 3 + public byte POINT; + /// Byte 4 + public byte Min; + /// Byte 5 + public byte Sec; + /// Byte 6 + public byte Frame; + /// Byte 7, bits 7 to 4 + public byte HOUR; + /// Byte 7, bits 3 to 0 + public byte PHOUR; + /// Byte 8 + public byte PMIN; + /// Byte 9 + public byte PSEC; + /// Byte 10 + public byte PFRAME; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/CD/Sector.cs b/Aaru.Decoders/CD/Sector.cs new file mode 100644 index 000000000..897d0599f --- /dev/null +++ b/Aaru.Decoders/CD/Sector.cs @@ -0,0 +1,468 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Sector.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes and descrambles CompactDisc sectors. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using Aaru.Checksums; + +namespace Aaru.Decoders.CD; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static class Sector +{ + public static readonly byte[] ScrambleTable = + [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x28, + 0x00, 0x1E, 0x80, 0x08, 0x60, 0x06, 0xA8, 0x02, 0xFE, 0x81, 0x80, 0x60, 0x60, 0x28, 0x28, 0x1E, 0x9E, 0x88, + 0x68, 0x66, 0xAE, 0xAA, 0xFC, 0x7F, 0x01, 0xE0, 0x00, 0x48, 0x00, 0x36, 0x80, 0x16, 0xE0, 0x0E, 0xC8, 0x04, + 0x56, 0x83, 0x7E, 0xE1, 0xE0, 0x48, 0x48, 0x36, 0xB6, 0x96, 0xF6, 0xEE, 0xC6, 0xCC, 0x52, 0xD5, 0xFD, 0x9F, + 0x01, 0xA8, 0x00, 0x7E, 0x80, 0x20, 0x60, 0x18, 0x28, 0x0A, 0x9E, 0x87, 0x28, 0x62, 0x9E, 0xA9, 0xA8, 0x7E, + 0xFE, 0xA0, 0x40, 0x78, 0x30, 0x22, 0x94, 0x19, 0xAF, 0x4A, 0xFC, 0x37, 0x01, 0xD6, 0x80, 0x5E, 0xE0, 0x38, + 0x48, 0x12, 0xB6, 0x8D, 0xB6, 0xE5, 0xB6, 0xCB, 0x36, 0xD7, 0x56, 0xDE, 0xBE, 0xD8, 0x70, 0x5A, 0xA4, 0x3B, + 0x3B, 0x53, 0x53, 0x7D, 0xFD, 0xE1, 0x81, 0x88, 0x60, 0x66, 0xA8, 0x2A, 0xFE, 0x9F, 0x00, 0x68, 0x00, 0x2E, + 0x80, 0x1C, 0x60, 0x09, 0xE8, 0x06, 0xCE, 0x82, 0xD4, 0x61, 0x9F, 0x68, 0x68, 0x2E, 0xAE, 0x9C, 0x7C, 0x69, + 0xE1, 0xEE, 0xC8, 0x4C, 0x56, 0xB5, 0xFE, 0xF7, 0x00, 0x46, 0x80, 0x32, 0xE0, 0x15, 0x88, 0x0F, 0x26, 0x84, + 0x1A, 0xE3, 0x4B, 0x09, 0xF7, 0x46, 0xC6, 0xB2, 0xD2, 0xF5, 0x9D, 0x87, 0x29, 0xA2, 0x9E, 0xF9, 0xA8, 0x42, + 0xFE, 0xB1, 0x80, 0x74, 0x60, 0x27, 0x68, 0x1A, 0xAE, 0x8B, 0x3C, 0x67, 0x51, 0xEA, 0xBC, 0x4F, 0x31, 0xF4, + 0x14, 0x47, 0x4F, 0x72, 0xB4, 0x25, 0xB7, 0x5B, 0x36, 0xBB, 0x56, 0xF3, 0x7E, 0xC5, 0xE0, 0x53, 0x08, 0x3D, + 0xC6, 0x91, 0x92, 0xEC, 0x6D, 0x8D, 0xED, 0xA5, 0x8D, 0xBB, 0x25, 0xB3, 0x5B, 0x35, 0xFB, 0x57, 0x03, 0x7E, + 0x81, 0xE0, 0x60, 0x48, 0x28, 0x36, 0x9E, 0x96, 0xE8, 0x6E, 0xCE, 0xAC, 0x54, 0x7D, 0xFF, 0x61, 0x80, 0x28, + 0x60, 0x1E, 0xA8, 0x08, 0x7E, 0x86, 0xA0, 0x62, 0xF8, 0x29, 0x82, 0x9E, 0xE1, 0xA8, 0x48, 0x7E, 0xB6, 0xA0, + 0x76, 0xF8, 0x26, 0xC2, 0x9A, 0xD1, 0xAB, 0x1C, 0x7F, 0x49, 0xE0, 0x36, 0xC8, 0x16, 0xD6, 0x8E, 0xDE, 0xE4, + 0x58, 0x4B, 0x7A, 0xB7, 0x63, 0x36, 0xA9, 0xD6, 0xFE, 0xDE, 0xC0, 0x58, 0x50, 0x3A, 0xBC, 0x13, 0x31, 0xCD, + 0xD4, 0x55, 0x9F, 0x7F, 0x28, 0x20, 0x1E, 0x98, 0x08, 0x6A, 0x86, 0xAF, 0x22, 0xFC, 0x19, 0x81, 0xCA, 0xE0, + 0x57, 0x08, 0x3E, 0x86, 0x90, 0x62, 0xEC, 0x29, 0x8D, 0xDE, 0xE5, 0x98, 0x4B, 0x2A, 0xB7, 0x5F, 0x36, 0xB8, + 0x16, 0xF2, 0x8E, 0xC5, 0xA4, 0x53, 0x3B, 0x7D, 0xD3, 0x61, 0x9D, 0xE8, 0x69, 0x8E, 0xAE, 0xE4, 0x7C, 0x4B, + 0x61, 0xF7, 0x68, 0x46, 0xAE, 0xB2, 0xFC, 0x75, 0x81, 0xE7, 0x20, 0x4A, 0x98, 0x37, 0x2A, 0x96, 0x9F, 0x2E, + 0xE8, 0x1C, 0x4E, 0x89, 0xF4, 0x66, 0xC7, 0x6A, 0xD2, 0xAF, 0x1D, 0xBC, 0x09, 0xB1, 0xC6, 0xF4, 0x52, 0xC7, + 0x7D, 0x92, 0xA1, 0xAD, 0xB8, 0x7D, 0xB2, 0xA1, 0xB5, 0xB8, 0x77, 0x32, 0xA6, 0x95, 0xBA, 0xEF, 0x33, 0x0C, + 0x15, 0xC5, 0xCF, 0x13, 0x14, 0x0D, 0xCF, 0x45, 0x94, 0x33, 0x2F, 0x55, 0xDC, 0x3F, 0x19, 0xD0, 0x0A, 0xDC, + 0x07, 0x19, 0xC2, 0x8A, 0xD1, 0xA7, 0x1C, 0x7A, 0x89, 0xE3, 0x26, 0xC9, 0xDA, 0xD6, 0xDB, 0x1E, 0xDB, 0x48, + 0x5B, 0x76, 0xBB, 0x66, 0xF3, 0x6A, 0xC5, 0xEF, 0x13, 0x0C, 0x0D, 0xC5, 0xC5, 0x93, 0x13, 0x2D, 0xCD, 0xDD, + 0x95, 0x99, 0xAF, 0x2A, 0xFC, 0x1F, 0x01, 0xC8, 0x00, 0x56, 0x80, 0x3E, 0xE0, 0x10, 0x48, 0x0C, 0x36, 0x85, + 0xD6, 0xE3, 0x1E, 0xC9, 0xC8, 0x56, 0xD6, 0xBE, 0xDE, 0xF0, 0x58, 0x44, 0x3A, 0xB3, 0x53, 0x35, 0xFD, 0xD7, + 0x01, 0x9E, 0x80, 0x68, 0x60, 0x2E, 0xA8, 0x1C, 0x7E, 0x89, 0xE0, 0x66, 0xC8, 0x2A, 0xD6, 0x9F, 0x1E, 0xE8, + 0x08, 0x4E, 0x86, 0xB4, 0x62, 0xF7, 0x69, 0x86, 0xAE, 0xE2, 0xFC, 0x49, 0x81, 0xF6, 0xE0, 0x46, 0xC8, 0x32, + 0xD6, 0x95, 0x9E, 0xEF, 0x28, 0x4C, 0x1E, 0xB5, 0xC8, 0x77, 0x16, 0xA6, 0x8E, 0xFA, 0xE4, 0x43, 0x0B, 0x71, + 0xC7, 0x64, 0x52, 0xAB, 0x7D, 0xBF, 0x61, 0xB0, 0x28, 0x74, 0x1E, 0xA7, 0x48, 0x7A, 0xB6, 0xA3, 0x36, 0xF9, + 0xD6, 0xC2, 0xDE, 0xD1, 0x98, 0x5C, 0x6A, 0xB9, 0xEF, 0x32, 0xCC, 0x15, 0x95, 0xCF, 0x2F, 0x14, 0x1C, 0x0F, + 0x49, 0xC4, 0x36, 0xD3, 0x56, 0xDD, 0xFE, 0xD9, 0x80, 0x5A, 0xE0, 0x3B, 0x08, 0x13, 0x46, 0x8D, 0xF2, 0xE5, + 0x85, 0x8B, 0x23, 0x27, 0x59, 0xDA, 0xBA, 0xDB, 0x33, 0x1B, 0x55, 0xCB, 0x7F, 0x17, 0x60, 0x0E, 0xA8, 0x04, + 0x7E, 0x83, 0x60, 0x61, 0xE8, 0x28, 0x4E, 0x9E, 0xB4, 0x68, 0x77, 0x6E, 0xA6, 0xAC, 0x7A, 0xFD, 0xE3, 0x01, + 0x89, 0xC0, 0x66, 0xD0, 0x2A, 0xDC, 0x1F, 0x19, 0xC8, 0x0A, 0xD6, 0x87, 0x1E, 0xE2, 0x88, 0x49, 0xA6, 0xB6, + 0xFA, 0xF6, 0xC3, 0x06, 0xD1, 0xC2, 0xDC, 0x51, 0x99, 0xFC, 0x6A, 0xC1, 0xEF, 0x10, 0x4C, 0x0C, 0x35, 0xC5, + 0xD7, 0x13, 0x1E, 0x8D, 0xC8, 0x65, 0x96, 0xAB, 0x2E, 0xFF, 0x5C, 0x40, 0x39, 0xF0, 0x12, 0xC4, 0x0D, 0x93, + 0x45, 0xAD, 0xF3, 0x3D, 0x85, 0xD1, 0xA3, 0x1C, 0x79, 0xC9, 0xE2, 0xD6, 0xC9, 0x9E, 0xD6, 0xE8, 0x5E, 0xCE, + 0xB8, 0x54, 0x72, 0xBF, 0x65, 0xB0, 0x2B, 0x34, 0x1F, 0x57, 0x48, 0x3E, 0xB6, 0x90, 0x76, 0xEC, 0x26, 0xCD, + 0xDA, 0xD5, 0x9B, 0x1F, 0x2B, 0x48, 0x1F, 0x76, 0x88, 0x26, 0xE6, 0x9A, 0xCA, 0xEB, 0x17, 0x0F, 0x4E, 0x84, + 0x34, 0x63, 0x57, 0x69, 0xFE, 0xAE, 0xC0, 0x7C, 0x50, 0x21, 0xFC, 0x18, 0x41, 0xCA, 0xB0, 0x57, 0x34, 0x3E, + 0x97, 0x50, 0x6E, 0xBC, 0x2C, 0x71, 0xDD, 0xE4, 0x59, 0x8B, 0x7A, 0xE7, 0x63, 0x0A, 0xA9, 0xC7, 0x3E, 0xD2, + 0x90, 0x5D, 0xAC, 0x39, 0xBD, 0xD2, 0xF1, 0x9D, 0x84, 0x69, 0xA3, 0x6E, 0xF9, 0xEC, 0x42, 0xCD, 0xF1, 0x95, + 0x84, 0x6F, 0x23, 0x6C, 0x19, 0xED, 0xCA, 0xCD, 0x97, 0x15, 0xAE, 0x8F, 0x3C, 0x64, 0x11, 0xEB, 0x4C, 0x4F, + 0x75, 0xF4, 0x27, 0x07, 0x5A, 0x82, 0xBB, 0x21, 0xB3, 0x58, 0x75, 0xFA, 0xA7, 0x03, 0x3A, 0x81, 0xD3, 0x20, + 0x5D, 0xD8, 0x39, 0x9A, 0x92, 0xEB, 0x2D, 0x8F, 0x5D, 0xA4, 0x39, 0xBB, 0x52, 0xF3, 0x7D, 0x85, 0xE1, 0xA3, + 0x08, 0x79, 0xC6, 0xA2, 0xD2, 0xF9, 0x9D, 0x82, 0xE9, 0xA1, 0x8E, 0xF8, 0x64, 0x42, 0xAB, 0x71, 0xBF, 0x64, + 0x70, 0x2B, 0x64, 0x1F, 0x6B, 0x48, 0x2F, 0x76, 0x9C, 0x26, 0xE9, 0xDA, 0xCE, 0xDB, 0x14, 0x5B, 0x4F, 0x7B, + 0x74, 0x23, 0x67, 0x59, 0xEA, 0xBA, 0xCF, 0x33, 0x14, 0x15, 0xCF, 0x4F, 0x14, 0x34, 0x0F, 0x57, 0x44, 0x3E, + 0xB3, 0x50, 0x75, 0xFC, 0x27, 0x01, 0xDA, 0x80, 0x5B, 0x20, 0x3B, 0x58, 0x13, 0x7A, 0x8D, 0xE3, 0x25, 0x89, + 0xDB, 0x26, 0xDB, 0x5A, 0xDB, 0x7B, 0x1B, 0x63, 0x4B, 0x69, 0xF7, 0x6E, 0xC6, 0xAC, 0x52, 0xFD, 0xFD, 0x81, + 0x81, 0xA0, 0x60, 0x78, 0x28, 0x22, 0x9E, 0x99, 0xA8, 0x6A, 0xFE, 0xAF, 0x00, 0x7C, 0x00, 0x21, 0xC0, 0x18, + 0x50, 0x0A, 0xBC, 0x07, 0x31, 0xC2, 0x94, 0x51, 0xAF, 0x7C, 0x7C, 0x21, 0xE1, 0xD8, 0x48, 0x5A, 0xB6, 0xBB, + 0x36, 0xF3, 0x56, 0xC5, 0xFE, 0xD3, 0x00, 0x5D, 0xC0, 0x39, 0x90, 0x12, 0xEC, 0x0D, 0x8D, 0xC5, 0xA5, 0x93, + 0x3B, 0x2D, 0xD3, 0x5D, 0x9D, 0xF9, 0xA9, 0x82, 0xFE, 0xE1, 0x80, 0x48, 0x60, 0x36, 0xA8, 0x16, 0xFE, 0x8E, + 0xC0, 0x64, 0x50, 0x2B, 0x7C, 0x1F, 0x61, 0xC8, 0x28, 0x56, 0x9E, 0xBE, 0xE8, 0x70, 0x4E, 0xA4, 0x34, 0x7B, + 0x57, 0x63, 0x7E, 0xA9, 0xE0, 0x7E, 0xC8, 0x20, 0x56, 0x98, 0x3E, 0xEA, 0x90, 0x4F, 0x2C, 0x34, 0x1D, 0xD7, + 0x49, 0x9E, 0xB6, 0xE8, 0x76, 0xCE, 0xA6, 0xD4, 0x7A, 0xDF, 0x63, 0x18, 0x29, 0xCA, 0x9E, 0xD7, 0x28, 0x5E, + 0x9E, 0xB8, 0x68, 0x72, 0xAE, 0xA5, 0xBC, 0x7B, 0x31, 0xE3, 0x54, 0x49, 0xFF, 0x76, 0xC0, 0x26, 0xD0, 0x1A, + 0xDC, 0x0B, 0x19, 0xC7, 0x4A, 0xD2, 0xB7, 0x1D, 0xB6, 0x89, 0xB6, 0xE6, 0xF6, 0xCA, 0xC6, 0xD7, 0x12, 0xDE, + 0x8D, 0x98, 0x65, 0xAA, 0xAB, 0x3F, 0x3F, 0x50, 0x10, 0x3C, 0x0C, 0x11, 0xC5, 0xCC, 0x53, 0x15, 0xFD, 0xCF, + 0x01, 0x94, 0x00, 0x6F, 0x40, 0x2C, 0x30, 0x1D, 0xD4, 0x09, 0x9F, 0x46, 0xE8, 0x32, 0xCE, 0x95, 0x94, 0x6F, + 0x2F, 0x6C, 0x1C, 0x2D, 0xC9, 0xDD, 0x96, 0xD9, 0xAE, 0xDA, 0xFC, 0x5B, 0x01, 0xFB, 0x40, 0x43, 0x70, 0x31, + 0xE4, 0x14, 0x4B, 0x4F, 0x77, 0x74, 0x26, 0xA7, 0x5A, 0xFA, 0xBB, 0x03, 0x33, 0x41, 0xD5, 0xF0, 0x5F, 0x04, + 0x38, 0x03, 0x52, 0x81, 0xFD, 0xA0, 0x41, 0xB8, 0x30, 0x72, 0x94, 0x25, 0xAF, 0x5B, 0x3C, 0x3B, 0x51, 0xD3, + 0x7C, 0x5D, 0xE1, 0xF9, 0x88, 0x42, 0xE6, 0xB1, 0x8A, 0xF4, 0x67, 0x07, 0x6A, 0x82, 0xAF, 0x21, 0xBC, 0x18, + 0x71, 0xCA, 0xA4, 0x57, 0x3B, 0x7E, 0x93, 0x60, 0x6D, 0xE8, 0x2D, 0x8E, 0x9D, 0xA4, 0x69, 0xBB, 0x6E, 0xF3, + 0x6C, 0x45, 0xED, 0xF3, 0x0D, 0x85, 0xC5, 0xA3, 0x13, 0x39, 0xCD, 0xD2, 0xD5, 0x9D, 0x9F, 0x29, 0xA8, 0x1E, + 0xFE, 0x88, 0x40, 0x66, 0xB0, 0x2A, 0xF4, 0x1F, 0x07, 0x48, 0x02, 0xB6, 0x81, 0xB6, 0xE0, 0x76, 0xC8, 0x26, + 0xD6, 0x9A, 0xDE, 0xEB, 0x18, 0x4F, 0x4A, 0xB4, 0x37, 0x37, 0x56, 0x96, 0xBE, 0xEE, 0xF0, 0x4C, 0x44, 0x35, + 0xF3, 0x57, 0x05, 0xFE, 0x83, 0x00, 0x61, 0xC0, 0x28, 0x50, 0x1E, 0xBC, 0x08, 0x71, 0xC6, 0xA4, 0x52, 0xFB, + 0x7D, 0x83, 0x61, 0xA1, 0xE8, 0x78, 0x4E, 0xA2, 0xB4, 0x79, 0xB7, 0x62, 0xF6, 0xA9, 0x86, 0xFE, 0xE2, 0xC0, + 0x49, 0x90, 0x36, 0xEC, 0x16, 0xCD, 0xCE, 0xD5, 0x94, 0x5F, 0x2F, 0x78, 0x1C, 0x22, 0x89, 0xD9, 0xA6, 0xDA, + 0xFA, 0xDB, 0x03, 0x1B, 0x41, 0xCB, 0x70, 0x57, 0x64, 0x3E, 0xAB, 0x50, 0x7F, 0x7C, 0x20, 0x21, 0xD8, 0x18, + 0x5A, 0x8A, 0xBB, 0x27, 0x33, 0x5A, 0x95, 0xFB, 0x2F, 0x03, 0x5C, 0x01, 0xF9, 0xC0, 0x42, 0xD0, 0x31, 0x9C, + 0x14, 0x69, 0xCF, 0x6E, 0xD4, 0x2C, 0x5F, 0x5D, 0xF8, 0x39, 0x82, 0x92, 0xE1, 0xAD, 0x88, 0x7D, 0xA6, 0xA1, + 0xBA, 0xF8, 0x73, 0x02, 0xA5, 0xC1, 0xBB, 0x10, 0x73, 0x4C, 0x25, 0xF5, 0xDB, 0x07, 0x1B, 0x42, 0x8B, 0x71, + 0xA7, 0x64, 0x7A, 0xAB, 0x63, 0x3F, 0x69, 0xD0, 0x2E, 0xDC, 0x1C, 0x59, 0xC9, 0xFA, 0xD6, 0xC3, 0x1E, 0xD1, + 0xC8, 0x5C, 0x56, 0xB9, 0xFE, 0xF2, 0xC0, 0x45, 0x90, 0x33, 0x2C, 0x15, 0xDD, 0xCF, 0x19, 0x94, 0x0A, 0xEF, + 0x47, 0x0C, 0x32, 0x85, 0xD5, 0xA3, 0x1F, 0x39, 0xC8, 0x12, 0xD6, 0x8D, 0x9E, 0xE5, 0xA8, 0x4B, 0x3E, 0xB7, + 0x50, 0x76, 0xBC, 0x26, 0xF1, 0xDA, 0xC4, 0x5B, 0x13, 0x7B, 0x4D, 0xE3, 0x75, 0x89, 0xE7, 0x26, 0xCA, 0x9A, + 0xD7, 0x2B, 0x1E, 0x9F, 0x48, 0x68, 0x36, 0xAE, 0x96, 0xFC, 0x6E, 0xC1, 0xEC, 0x50, 0x4D, 0xFC, 0x35, 0x81, + 0xD7, 0x20, 0x5E, 0x98, 0x38, 0x6A, 0x92, 0xAF, 0x2D, 0xBC, 0x1D, 0xB1, 0xC9, 0xB4, 0x56, 0xF7, 0x7E, 0xC6, + 0xA0, 0x52, 0xF8, 0x3D, 0x82, 0x91, 0xA1, 0xAC, 0x78, 0x7D, 0xE2, 0xA1, 0x89, 0xB8, 0x66, 0xF2, 0xAA, 0xC5, + 0xBF, 0x13, 0x30, 0x0D, 0xD4, 0x05, 0x9F, 0x43, 0x28, 0x31, 0xDE, 0x94, 0x58, 0x6F, 0x7A, 0xAC, 0x23, 0x3D, + 0xD9, 0xD1, 0x9A, 0xDC, 0x6B, 0x19, 0xEF, 0x4A, 0xCC, 0x37, 0x15, 0xD6, 0x8F, 0x1E, 0xE4, 0x08, 0x4B, 0x46, + 0xB7, 0x72, 0xF6, 0xA5, 0x86, 0xFB, 0x22, 0xC3, 0x59, 0x91, 0xFA, 0xEC, 0x43, 0x0D, 0xF1, 0xC5, 0x84, 0x53, + 0x23, 0x7D, 0xD9, 0xE1, 0x9A, 0xC8, 0x6B, 0x16, 0xAF, 0x4E, 0xFC, 0x34, 0x41, 0xD7, 0x70, 0x5E, 0xA4, 0x38, + 0x7B, 0x52, 0xA3, 0x7D, 0xB9, 0xE1, 0xB2, 0xC8, 0x75, 0x96, 0xA7, 0x2E, 0xFA, 0x9C, 0x43, 0x29, 0xF1, 0xDE, + 0xC4, 0x58, 0x53, 0x7A, 0xBD, 0xE3, 0x31, 0x89, 0xD4, 0x66, 0xDF, 0x6A, 0xD8, 0x2F, 0x1A, 0x9C, 0x0B, 0x29, + 0xC7, 0x5E, 0xD2, 0xB8, 0x5D, 0xB2, 0xB9, 0xB5, 0xB2, 0xF7, 0x35, 0x86, 0x97, 0x22, 0xEE, 0x99, 0x8C, 0x6A, + 0xE5, 0xEF, 0x0B, 0x0C, 0x07, 0x45, 0xC2, 0xB3, 0x11, 0xB5, 0xCC, 0x77, 0x15, 0xE6, 0x8F, 0x0A, 0xE4, 0x07, + 0x0B, 0x42, 0x87, 0x71, 0xA2, 0xA4, 0x79, 0xBB, 0x62, 0xF3, 0x69, 0x85, 0xEE, 0xE3, 0x0C, 0x49, 0xC5, 0xF6, + 0xD3, 0x06, 0xDD, 0xC2, 0xD9, 0x91, 0x9A, 0xEC, 0x6B, 0x0D, 0xEF, 0x45, 0x8C, 0x33, 0x25, 0xD5, 0xDB, 0x1F, + 0x1B, 0x48, 0x0B, 0x76, 0x87, 0x66, 0xE2, 0xAA, 0xC9, 0xBF, 0x16, 0xF0, 0x0E, 0xC4, 0x04, 0x53, 0x43, 0x7D, + 0xF1, 0xE1, 0x84, 0x48, 0x63, 0x76, 0xA9, 0xE6, 0xFE, 0xCA, 0xC0, 0x57, 0x10, 0x3E, 0x8C, 0x10, 0x65, 0xCC, + 0x2B, 0x15, 0xDF, 0x4F, 0x18, 0x34, 0x0A, 0x97, 0x47, 0x2E, 0xB2, 0x9C, 0x75, 0xA9, 0xE7, 0x3E, 0xCA, 0x90, + 0x57, 0x2C, 0x3E, 0x9D, 0xD0, 0x69, 0x9C, 0x2E, 0xE9, 0xDC, 0x4E, 0xD9, 0xF4, 0x5A, 0xC7, 0x7B, 0x12, 0xA3, + 0x4D, 0xB9, 0xF5, 0xB2, 0xC7, 0x35, 0x92, 0x97, 0x2D, 0xAE, 0x9D, 0xBC, 0x69, 0xB1, 0xEE, 0xF4, 0x4C, 0x47, + 0x75, 0xF2, 0xA7, 0x05, 0xBA, 0x83, 0x33, 0x21, 0xD5, 0xD8, 0x5F, 0x1A, 0xB8, 0x0B, 0x32, 0x87, 0x55, 0xA2, + 0xBF, 0x39, 0xB0, 0x12, 0xF4, 0x0D, 0x87, 0x45, 0xA2, 0xB3, 0x39, 0xB5, 0xD2, 0xF7, 0x1D, 0x86, 0x89, 0xA2, + 0xE6, 0xF9, 0x8A, 0xC2, 0xE7, 0x11, 0x8A, 0x8C, 0x67, 0x25, 0xEA, 0x9B, 0x0F, 0x2B, 0x44, 0x1F, 0x73, 0x48, + 0x25, 0xF6, 0x9B, 0x06, 0xEB, 0x42, 0xCF, 0x71, 0x94, 0x24, 0x6F, 0x5B, 0x6C, 0x3B, 0x6D, 0xD3, 0x6D, 0x9D, + 0xED, 0xA9, 0x8D, 0xBE, 0xE5, 0xB0, 0x4B, 0x34, 0x37, 0x57, 0x56, 0xBE, 0xBE, 0xF0, 0x70, 0x44, 0x24, 0x33, + 0x5B, 0x55, 0xFB, 0x7F, 0x03, 0x60, 0x01, 0xE8, 0x00, 0x4E, 0x80, 0x34, 0x60, 0x17, 0x68, 0x0E, 0xAE, 0x84, + 0x7C, 0x63, 0x61, 0xE9, 0xE8, 0x4E, 0xCE, 0xB4, 0x54, 0x77, 0x7F, 0x66, 0xA0, 0x2A, 0xF8, 0x1F, 0x02, 0x88, + 0x01, 0xA6, 0x80, 0x7A, 0xE0, 0x23, 0x08, 0x19, 0xC6, 0x8A, 0xD2, 0xE7, 0x1D, 0x8A, 0x89, 0xA7, 0x26, 0xFA, + 0x9A, 0xC3, 0x2B, 0x11, 0xDF, 0x4C, 0x58, 0x35, 0xFA, 0x97, 0x03, 0x2E, 0x81, 0xDC, 0x60, 0x59, 0xE8, 0x3A, + 0xCE, 0x93, 0x14, 0x6D, 0xCF, 0x6D, 0x94, 0x2D, 0xAF, 0x5D, 0xBC, 0x39, 0xB1, 0xD2, 0xF4, 0x5D, 0x87, 0x79, + 0xA2, 0xA2, 0xF9, 0xB9, 0x82, 0xF2, 0xE1, 0x85, 0x88, 0x63, 0x26, 0xA9, 0xDA, 0xFE, 0xDB, 0x00, 0x5B, 0x40, + 0x3B, 0x70, 0x13, 0x64, 0x0D, 0xEB, 0x45, 0x8F, 0x73, 0x24, 0x25, 0xDB, 0x5B, 0x1B, 0x7B, 0x4B, 0x63, 0x77, + 0x69, 0xE6, 0xAE, 0xCA, 0xFC, 0x57, 0x01, 0xFE, 0x80, 0x40, 0x60, 0x30, 0x28, 0x14, 0x1E, 0x8F, 0x48, 0x64, + 0x36, 0xAB, 0x56, 0xFF, 0x7E, 0xC0, 0x20, 0x50, 0x18, 0x3C, 0x0A, 0x91, 0xC7, 0x2C, 0x52, 0x9D, 0xFD, 0xA9, + 0x81, 0xBE, 0xE0, 0x70, 0x48, 0x24, 0x36, 0x9B, 0x56, 0xEB, 0x7E, 0xCF, 0x60, 0x54, 0x28, 0x3F, 0x5E, 0x90, + 0x38, 0x6C, 0x12, 0xAD, 0xCD, 0xBD, 0x95, 0xB1, 0xAF, 0x34, 0x7C, 0x17, 0x61, 0xCE, 0xA8, 0x54, 0x7E, 0xBF, + 0x60, 0x70, 0x28, 0x24, 0x1E, 0x9B, 0x48, 0x6B, 0x76, 0xAF, 0x66, 0xFC, 0x2A, 0xC1, 0xDF, 0x10, 0x58, 0x0C, + 0x3A, 0x85, 0xD3, 0x23, 0x1D, 0xD9, 0xC9, 0x9A, 0xD6, 0xEB, 0x1E, 0xCF, 0x48, 0x54, 0x36, 0xBF, 0x56, 0xF0, + 0x3E, 0xC4, 0x10, 0x53, 0x4C, 0x3D, 0xF5, 0xD1, 0x87, 0x1C, 0x62, 0x89, 0xE9, 0xA6, 0xCE, 0xFA, 0xD4, 0x43, + 0x1F, 0x71, 0xC8, 0x24, 0x56, 0x9B, 0x7E, 0xEB, 0x60, 0x4F, 0x68, 0x34, 0x2E, 0x97, 0x5C, 0x6E, 0xB9, 0xEC, + 0x72, 0xCD, 0xE5, 0x95, 0x8B, 0x2F, 0x27, 0x5C, 0x1A, 0xB9, 0xCB, 0x32, 0xD7, 0x55, 0x9E, 0xBF, 0x28, 0x70, + 0x1E, 0xA4, 0x08, 0x7B, 0x46, 0xA3, 0x72, 0xF9, 0xE5, 0x82, 0xCB, 0x21, 0x97, 0x58, 0x6E, 0xBA, 0xAC, 0x73, + 0x3D, 0xE5, 0xD1, 0x8B, 0x1C, 0x67, 0x49, 0xEA, 0xB6, 0xCF, 0x36, 0xD4, 0x16, 0xDF, 0x4E, 0xD8, 0x34, 0x5A, + 0x97, 0x7B, 0x2E, 0xA3, 0x5C, 0x79, 0xF9, 0xE2, 0xC2, 0xC9, 0x91, 0x96, 0xEC, 0x6E, 0xCD, 0xEC, 0x55, 0x8D, + 0xFF, 0x25, 0x80, 0x1B, 0x20, 0x0B, 0x58, 0x07, 0x7A, 0x82, 0xA3, 0x21, 0xB9, 0xD8, 0x72, 0xDA, 0xA5, 0x9B, + 0x3B, 0x2B, 0x53, 0x5F, 0x7D, 0xF8, 0x21, 0x82, 0x98, 0x61, 0xAA, 0xA8, 0x7F, 0x3E, 0xA0, 0x10, 0x78, 0x0C, + 0x22, 0x85, 0xD9, 0xA3, 0x1A, 0xF9, 0xCB, 0x02, 0xD7, 0x41, 0x9E, 0xB0, 0x68, 0x74, 0x2E, 0xA7, 0x5C, 0x7A, + 0xB9, 0xE3, 0x32, 0xC9, 0xD5, 0x96, 0xDF, 0x2E, 0xD8, 0x1C, 0x5A, 0x89, 0xFB, 0x26, 0xC3, 0x5A, 0xD1, 0xFB, + 0x1C, 0x43, 0x49, 0xF1, 0xF6, 0xC4, 0x46, 0xD3, 0x72, 0xDD, 0xE5, 0x99 + ]; + + public static readonly byte[] SyncMark = [0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00]; + + public static byte[] Scramble(byte[] sector) + { + if(sector == null || sector.Length < 2352) return sector; + + var sync = new byte[12]; + Array.Copy(sector, 0, sync, 0, 12); + + if(!SyncMark.SequenceEqual(sync)) return sector; + + var scrambled = new byte[sector.Length]; + + for(var i = 0; i < 2352; i++) scrambled[i] = (byte)(sector[i] ^ ScrambleTable[i]); + + if(sector.Length <= 2352) return scrambled; + + for(var i = 2352; i < sector.Length; i++) scrambled[i] = sector[i]; + + return scrambled; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetUserData(byte[] data, bool interleaved = false, byte fileNumber = 0) + { + switch(data.Length) + { + case 2352 when data[0] != 0x00 || + data[1] != 0xFF || + data[2] != 0xFF || + data[3] != 0xFF || + data[4] != 0xFF || + data[5] != 0xFF || + data[6] != 0xFF || + data[7] != 0xFF || + data[8] != 0xFF || + data[9] != 0xFF || + data[10] != 0xFF || + data[11] != 0x00: + return data; + case 2352: + switch(data[15]) + { + case 0: + return new byte[2048]; + case 1: + var sector = new byte[2048]; + Array.Copy(data, 16, sector, 0, 2048); + + return sector; + case 2: + return GetUserDataFromMode2(data, interleaved, fileNumber); + default: + return data; + } + case 2336: + return GetUserDataFromMode2(data, interleaved, fileNumber); + default: + return data; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetUserDataFromMode2(byte[] data, bool interleaved = false, byte fileNumber = 0) + { + if(data.Length != 2352 && data.Length != 2336) return data; + + var pos = 0; + + if(data.Length == 2352) + { + if(data[0] != 0x00 || + data[1] != 0xFF || + data[2] != 0xFF || + data[3] != 0xFF || + data[4] != 0xFF || + data[5] != 0xFF || + data[6] != 0xFF || + data[7] != 0xFF || + data[8] != 0xFF || + data[9] != 0xFF || + data[10] != 0xFF || + data[11] != 0x00 || + data[15] != 0x02) + return data; + + pos = 16; + } + + // This is not the sector you are looking for + if(interleaved && data[pos] != fileNumber) return null; + + int len = (data[pos + 2] & 0x20) == 0x20 ? 2324 : 2048; + pos += 8; + + var sector = new byte[len]; + Array.Copy(data, pos, sector, 0, len); + + return sector; + } + + public static string Prettify(byte[] buffer) + { + if(buffer is null || buffer.Length <= 0) return null; + + if(buffer[0] != 0x00 || + buffer[1] != 0xFF || + buffer[2] != 0xFF || + buffer[3] != 0xFF || + buffer[4] != 0xFF || + buffer[5] != 0xFF || + buffer[6] != 0xFF || + buffer[7] != 0xFF || + buffer[8] != 0xFF || + buffer[9] != 0xFF || + buffer[10] != 0xFF || + buffer[11] != 0x00) + return Localization.CD_sector; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.CD_ROM_sector); + + byte min = buffer[12]; + byte sec = buffer[13]; + byte frame = buffer[14]; + var lba = 0; + var moreThan90 = false; + + if(min > 0x90) + { + lba += 405000; + min -= 0x90; + moreThan90 = true; + } + + lba += ((min >> 4) * 10 + (min & 0x0F)) * 75 * 60; + lba += ((sec >> 4) * 10 + (sec & 0x0F)) * 75; + lba += (frame >> 4) * 10 + (frame & 0x0F); + lba -= 150; + + if(moreThan90) min += 0x90; + + sb.AppendFormat(Localization.Position_0_1_2_LBA_3, min, sec, frame, lba).AppendLine(); + + switch(buffer[15] & 0x03) + { + case 0: + sb.AppendLine(Localization.Mode_0); + + break; + case 1: + sb.AppendLine(Localization.Mode_1); + + break; + case 2: + sb.AppendLine(Localization.Mode_2); + + break; + case 3: + sb.AppendLine(Localization.Invalid_mode_3); + + break; + } + + switch((buffer[15] & 0xE0) >> 5) + { + case 0: + sb.AppendLine(Localization.User_data_block); + + break; + case 1: + sb.AppendLine(Localization.Fourth_run_in_block); + + break; + case 2: + sb.AppendLine(Localization.Third_run_in_block); + + break; + case 3: + sb.AppendLine(Localization.Second_run_in_block); + + break; + case 4: + sb.AppendLine(Localization.First_run_in_block); + + break; + case 5: + sb.AppendLine(Localization.Link_block); + + break; + case 6: + sb.AppendLine(Localization.Second_run_out_block); + + break; + case 7: + sb.AppendLine(Localization.First_run_out_block); + + break; + } + + CdChecksums.CheckCdSector(buffer, out bool? correctEccP, out bool? correctEccQ, out bool? correctEdc); + + var empty = true; + + switch(buffer[15] & 0x03) + { + case 0: + + for(var i = 16; i < 2352; i++) + { + if(buffer[i] == 0x00) continue; + + empty = false; + + break; + } + + sb.AppendLine(empty ? Localization.Correct_sector_contents : Localization.Incorrect_sector_contents); + + break; + case 1: + sb.AppendLine(correctEdc == true ? Localization.Correct_EDC : Localization.Incorrect_EDC); + sb.AppendLine(correctEccP == true ? Localization.Correct_ECC_P : Localization.Incorrect_ECC_P); + sb.AppendLine(correctEccQ == true ? Localization.Correct_ECC_Q : Localization.Incorrect_ECC_Q); + + for(var i = 2068; i < 2076; i++) + { + if(buffer[i] == 0x00) continue; + + empty = false; + + break; + } + + sb.AppendLine(empty ? Localization.Correct_zero_fill : Localization.Incorrect_zero_fill); + + break; + case 2: + if(buffer[16] != buffer[20] || + buffer[17] != buffer[21] || + buffer[18] != buffer[22] || + buffer[19] != buffer[23]) + { + sb.AppendLine(Localization.Subheader_copies_differ); + sb.AppendLine(correctEdc == true ? Localization.Correct_EDC : Localization.Incorrect_EDC); + sb.AppendLine(correctEccP == true ? Localization.Correct_ECC_P : Localization.Incorrect_ECC_P); + sb.AppendLine(correctEccQ == true ? Localization.Correct_ECC_Q : Localization.Incorrect_ECC_Q); + + break; + } + + sb.AppendFormat(Localization.File_number_0, buffer[16]).AppendLine(); + sb.AppendFormat(Localization.Channel_number_0, buffer[17]).AppendLine(); + sb.AppendFormat(Localization.Coding_information_number_0, buffer[19]).AppendLine(); + + if((buffer[18] & 0x80) == 0x80) sb.AppendLine(Localization.End_of_file); + + if((buffer[18] & 0x40) == 0x40) sb.AppendLine(Localization.Real_time_block); + + sb.AppendLine((buffer[18] & 0x20) == 0x20 ? Localization.Form_2 : Localization.Form_1); + + if((buffer[18] & 0x10) == 0x10) sb.AppendLine(Localization.Trigger_block); + + if((buffer[18] & 0x08) == 0x08) sb.AppendLine(Localization.Data_block); + + if((buffer[18] & 0x04) == 0x04) sb.AppendLine(Localization.Audio_block); + + if((buffer[18] & 0x02) == 0x02) sb.AppendLine(Localization.Video_block); + + if((buffer[18] & 0x01) == 0x01) sb.AppendLine(Localization.End_of_record); + + if((buffer[18] & 0x20) != 0x20) + { + sb.AppendLine(correctEccP == true ? Localization.Correct_ECC_P : Localization.Incorrect_ECC_P); + sb.AppendLine(correctEccQ == true ? Localization.Correct_ECC_Q : Localization.Incorrect_ECC_Q); + } + + sb.AppendLine(correctEdc == true ? Localization.Correct_EDC : Localization.Incorrect_EDC); + + break; + } + + return sb.ToString(); + } +} \ No newline at end of file diff --git a/Aaru.Decoders/CD/SectorBuilder.cs b/Aaru.Decoders/CD/SectorBuilder.cs new file mode 100644 index 000000000..1b861879d --- /dev/null +++ b/Aaru.Decoders/CD/SectorBuilder.cs @@ -0,0 +1,236 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SectorBuilder.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Enums; + +namespace Aaru.Decoders.CD; + +public class SectorBuilder +{ + readonly byte[] _eccBTable; + readonly byte[] _eccFTable; + readonly uint[] _edcTable; + + public SectorBuilder() + { + _eccFTable = new byte[256]; + _eccBTable = new byte[256]; + _edcTable = new uint[256]; + + for(uint i = 0; i < 256; i++) + { + uint edc = i; + var j = (uint)(i << 1 ^ ((i & 0x80) == 0x80 ? 0x11D : 0)); + _eccFTable[i] = (byte)j; + _eccBTable[i ^ j] = (byte)i; + + for(j = 0; j < 8; j++) edc = edc >> 1 ^ ((edc & 1) > 0 ? 0xD8018001 : 0); + + _edcTable[i] = edc; + } + } + + static (byte minute, byte second, byte frame) LbaToMsf(long pos) => + ((byte)((pos + 150) / 75 / 60), (byte)((pos + 150) / 75 % 60), (byte)((pos + 150) % 75)); + + public void ReconstructPrefix(ref byte[] sector, // must point to a full 2352-byte sector + TrackType type, long lba) + { + // + // Sync + // + sector[0x000] = 0x00; + sector[0x001] = 0xFF; + sector[0x002] = 0xFF; + sector[0x003] = 0xFF; + sector[0x004] = 0xFF; + sector[0x005] = 0xFF; + sector[0x006] = 0xFF; + sector[0x007] = 0xFF; + sector[0x008] = 0xFF; + sector[0x009] = 0xFF; + sector[0x00A] = 0xFF; + sector[0x00B] = 0x00; + + (byte minute, byte second, byte frame) msf = LbaToMsf(lba); + + sector[0x00C] = (byte)((msf.minute / 10 << 4) + msf.minute % 10); + sector[0x00D] = (byte)((msf.second / 10 << 4) + msf.second % 10); + sector[0x00E] = (byte)((msf.frame / 10 << 4) + msf.frame % 10); + + switch(type) + { + case TrackType.CdMode1: + // + // Mode + // + sector[0x00F] = 0x01; + + break; + case TrackType.CdMode2Form1: + case TrackType.CdMode2Form2: + case TrackType.CdMode2Formless: + // + // Mode + // + sector[0x00F] = 0x02; + + // + // Flags + // + sector[0x010] = sector[0x014]; + sector[0x011] = sector[0x015]; + sector[0x012] = sector[0x016]; + sector[0x013] = sector[0x017]; + + break; + default: + return; + } + } + + uint ComputeEdc(uint edc, byte[] src, int size, int srcOffset = 0) + { + int pos = srcOffset; + + for(; size > 0; size--) edc = edc >> 8 ^ _edcTable[(edc ^ src[pos++]) & 0xFF]; + + return edc; + } + + public void ReconstructEcc(ref byte[] sector, // must point to a full 2352-byte sector + TrackType type) + { + byte[] computedEdc; + + switch(type) + { + // + // Compute EDC + // + case TrackType.CdMode1: + computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x810)); + sector[0x810] = computedEdc[0]; + sector[0x811] = computedEdc[1]; + sector[0x812] = computedEdc[2]; + sector[0x813] = computedEdc[3]; + + break; + case TrackType.CdMode2Form1: + computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x808, 0x10)); + sector[0x818] = computedEdc[0]; + sector[0x819] = computedEdc[1]; + sector[0x81A] = computedEdc[2]; + sector[0x81B] = computedEdc[3]; + + break; + case TrackType.CdMode2Form2: + computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x91C, 0x10)); + sector[0x92C] = computedEdc[0]; + sector[0x92D] = computedEdc[1]; + sector[0x92E] = computedEdc[2]; + sector[0x92F] = computedEdc[3]; + + break; + default: + return; + } + + var zeroaddress = new byte[4]; + + switch(type) + { + // + // Compute ECC + // + case TrackType.CdMode1: + // + // Reserved + // + sector[0x814] = 0x00; + sector[0x815] = 0x00; + sector[0x816] = 0x00; + sector[0x817] = 0x00; + sector[0x818] = 0x00; + sector[0x819] = 0x00; + sector[0x81A] = 0x00; + sector[0x81B] = 0x00; + EccWriteSector(sector, sector, ref sector, 0xC, 0x10, 0x81C); + + break; + case TrackType.CdMode2Form1: + EccWriteSector(zeroaddress, sector, ref sector, 0, 0x10, 0x81C); + + break; + default: + return; + } + + // + // Done + // + } + + void EccWriteSector(byte[] address, byte[] data, ref byte[] ecc, int addressOffset, int dataOffset, int eccOffset) + { + WriteEcc(address, data, 86, 24, 2, 86, ref ecc, addressOffset, dataOffset, eccOffset); // P + WriteEcc(address, data, 52, 43, 86, 88, ref ecc, addressOffset, dataOffset, eccOffset + 0xAC); // Q + } + + void WriteEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult, uint minorInc, + ref byte[] ecc, int addressOffset, int dataOffset, int eccOffset) + { + uint size = majorCount * minorCount; + uint major; + + for(major = 0; major < majorCount; major++) + { + uint idx = (major >> 1) * majorMult + (major & 1); + byte eccA = 0; + byte eccB = 0; + uint minor; + + for(minor = 0; minor < minorCount; minor++) + { + byte temp = idx < 4 ? address[idx + addressOffset] : data[idx + dataOffset - 4]; + idx += minorInc; + + if(idx >= size) idx -= size; + + eccA ^= temp; + eccB ^= temp; + eccA = _eccFTable[eccA]; + } + + eccA = _eccBTable[_eccFTable[eccA] ^ eccB]; + ecc[major + eccOffset] = eccA; + ecc[major + majorCount + eccOffset] = (byte)(eccA ^ eccB); + } + } +} \ No newline at end of file diff --git a/Aaru.Decoders/CD/Session.cs b/Aaru.Decoders/CD/Session.cs new file mode 100644 index 000000000..33824b718 --- /dev/null +++ b/Aaru.Decoders/CD/Session.cs @@ -0,0 +1,235 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Session.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes CD session structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.CD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Session +{ + const string MODULE_NAME = "CD Session Info decoder"; + + public static CDSessionInfo? Decode(byte[] CDSessionInfoResponse) + { + if(CDSessionInfoResponse is not { Length: > 4 }) return null; + + var decoded = new CDSessionInfo + { + DataLength = BigEndianBitConverter.ToUInt16(CDSessionInfoResponse, 0), + FirstCompleteSession = CDSessionInfoResponse[2], + LastCompleteSession = CDSessionInfoResponse[3] + }; + + decoded.TrackDescriptors = new TrackDataDescriptor[(decoded.DataLength - 2) / 8]; + + if(decoded.DataLength + 2 != CDSessionInfoResponse.Length) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Expected_CDSessionInfo_size_0_bytes_is_not_received_size_1_bytes_not_decoding, + decoded.DataLength + 2, + CDSessionInfoResponse.Length); + + return null; + } + + for(var i = 0; i < (decoded.DataLength - 2) / 8; i++) + { + decoded.TrackDescriptors[i].Reserved1 = CDSessionInfoResponse[0 + i * 8 + 4]; + decoded.TrackDescriptors[i].ADR = (byte)((CDSessionInfoResponse[1 + i * 8 + 4] & 0xF0) >> 4); + decoded.TrackDescriptors[i].CONTROL = (byte)(CDSessionInfoResponse[1 + i * 8 + 4] & 0x0F); + decoded.TrackDescriptors[i].TrackNumber = CDSessionInfoResponse[2 + i * 8 + 4]; + decoded.TrackDescriptors[i].Reserved2 = CDSessionInfoResponse[3 + i * 8 + 4]; + + decoded.TrackDescriptors[i].TrackStartAddress = + BigEndianBitConverter.ToUInt32(CDSessionInfoResponse, 4 + i * 8 + 4); + } + + return decoded; + } + + public static string Prettify(CDSessionInfo? CDSessionInfoResponse) + { + if(CDSessionInfoResponse == null) return null; + + CDSessionInfo response = CDSessionInfoResponse.Value; + + var sb = new StringBuilder(); + + sb.AppendFormat(Localization.First_complete_session_number_0, response.FirstCompleteSession).AppendLine(); + sb.AppendFormat(Localization.Last_complete_session_number_0, response.LastCompleteSession).AppendLine(); + + foreach(TrackDataDescriptor descriptor in response.TrackDescriptors) + { + sb.AppendFormat(Localization.First_track_number_in_last_complete_session_0, descriptor.TrackNumber) + .AppendLine(); + + sb.AppendFormat(Localization.Track_starts_at_LBA_0_or_MSF_2_3, + descriptor.TrackStartAddress, + (descriptor.TrackStartAddress & 0x0000FF00) >> 8, + (descriptor.TrackStartAddress & 0x00FF0000) >> 16, + (descriptor.TrackStartAddress & 0xFF000000) >> 24) + .AppendLine(); + + switch((TocAdr)descriptor.ADR) + { + case TocAdr.NoInformation: + sb.AppendLine(Localization.Q_subchannel_mode_not_given); + + break; + case TocAdr.CurrentPosition: + sb.AppendLine(Localization.Q_subchannel_stores_current_position); + + break; + case TocAdr.ISRC: + sb.AppendLine(Localization.Q_subchannel_stores_ISRC); + + break; + case TocAdr.MediaCatalogNumber: + sb.AppendLine(Localization.Q_subchannel_stores_media_catalog_number); + + break; + } + + if((descriptor.CONTROL & (byte)TocControl.ReservedMask) == (byte)TocControl.ReservedMask) + sb.AppendFormat(Localization.Reserved_flags_0_set, descriptor.CONTROL).AppendLine(); + else + { + switch((TocControl)(descriptor.CONTROL & 0x0D)) + { + case TocControl.TwoChanNoPreEmph: + sb.AppendLine(Localization.Stereo_audio_track_with_no_pre_emphasis); + + break; + case TocControl.TwoChanPreEmph: + sb.AppendLine(Localization.Stereo_audio_track_with_50_15_us_pre_emphasis); + + break; + case TocControl.FourChanNoPreEmph: + sb.AppendLine(Localization.Quadraphonic_audio_track_with_no_pre_emphasis); + + break; + case TocControl.FourChanPreEmph: + sb.AppendLine(Localization.Stereo_audio_track_with_50_15_us_pre_emphasis); + + break; + case TocControl.DataTrack: + sb.AppendLine(Localization.Data_track_recorded_uninterrupted); + + break; + case TocControl.DataTrackIncremental: + sb.AppendLine(Localization.Data_track_recorded_incrementally); + + break; + } + + sb.AppendLine((descriptor.CONTROL & (byte)TocControl.CopyPermissionMask) == + (byte)TocControl.CopyPermissionMask + ? Localization.Digital_copy_of_track_is_permitted + : Localization.Digital_copy_of_track_is_prohibited); + +#if DEBUG + if(descriptor.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, descriptor.Reserved1).AppendLine(); + + if(descriptor.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, descriptor.Reserved2).AppendLine(); +#endif + + sb.AppendLine(); + } + } + + return sb.ToString(); + } + + public static string Prettify(byte[] CDSessionInfoResponse) + { + CDSessionInfo? decoded = Decode(CDSessionInfoResponse); + + return Prettify(decoded); + } + +#region Nested type: CDSessionInfo + + public struct CDSessionInfo + { + /// Total size of returned session information minus this field + public ushort DataLength; + /// First track number in hex + public byte FirstCompleteSession; + /// Last track number in hex + public byte LastCompleteSession; + /// Track descriptors + public TrackDataDescriptor[] TrackDescriptors; + } + +#endregion + +#region Nested type: TrackDataDescriptor + + public struct TrackDataDescriptor + { + /// Byte 0 Reserved + public byte Reserved1; + /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found + public byte ADR; + /// Byte 1, bits 3 to 0 Track attributes + public byte CONTROL; + /// Byte 2 First track number in last complete session + public byte TrackNumber; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 7 First track number in last complete session start address in LBA or in MSF + public uint TrackStartAddress; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/CD/Subchannel.cs b/Aaru.Decoders/CD/Subchannel.cs new file mode 100644 index 000000000..1db2f77a8 --- /dev/null +++ b/Aaru.Decoders/CD/Subchannel.cs @@ -0,0 +1,1078 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Subchannel.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.Checksums; + +namespace Aaru.Decoders.CD; + +public static class Subchannel +{ + static readonly string[] _isrcTable = + [ + // 0x00 + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "", "", "", "", "", "", + + // 0x10 + "", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", + + // 0x20 + "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "", "", "", "", "", + + // 0x30 + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" + ]; + + public static void BinaryToBcdQ(byte[] q) + { + if((q[0] & 0xF) == 1 || (q[0] & 0xF) == 5) + { + q[1] = (byte)((q[1] / 10 << 4) + q[1] % 10); + q[2] = (byte)((q[2] / 10 << 4) + q[2] % 10); + q[3] = (byte)((q[3] / 10 << 4) + q[3] % 10); + q[4] = (byte)((q[4] / 10 << 4) + q[4] % 10); + q[5] = (byte)((q[5] / 10 << 4) + q[5] % 10); + q[6] = (byte)((q[6] / 10 << 4) + q[6] % 10); + q[7] = (byte)((q[7] / 10 << 4) + q[7] % 10); + q[8] = (byte)((q[8] / 10 << 4) + q[8] % 10); + } + + q[9] = (byte)((q[9] / 10 << 4) + q[9] % 10); + } + + public static void BcdToBinaryQ(byte[] q) + { + if((q[0] & 0xF) == 1 || (q[0] & 0xF) == 5) + { + q[1] = (byte)(q[1] / 16 * 10 + (q[1] & 0x0F)); + q[2] = (byte)(q[2] / 16 * 10 + (q[2] & 0x0F)); + q[3] = (byte)(q[3] / 16 * 10 + (q[3] & 0x0F)); + q[4] = (byte)(q[4] / 16 * 10 + (q[4] & 0x0F)); + q[5] = (byte)(q[5] / 16 * 10 + (q[5] & 0x0F)); + q[6] = (byte)(q[6] / 16 * 10 + (q[6] & 0x0F)); + q[7] = (byte)(q[7] / 16 * 10 + (q[7] & 0x0F)); + q[8] = (byte)(q[8] / 16 * 10 + (q[8] & 0x0F)); + } + + q[9] = (byte)(q[9] / 16 * 10 + (q[9] & 0x0F)); + } + + public static byte[] ConvertQToRaw(byte[] subchannel) + { + var pos = 0; + var subBuf = new byte[subchannel.Length * 6]; + + for(var i = 0; i < subchannel.Length; i += 16) + { + // P + if((subchannel[i + 15] & 0x80) <= 0) + pos += 12; + else + { + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + } + + // Q + subBuf[pos++] = subchannel[i + 0]; + subBuf[pos++] = subchannel[i + 1]; + subBuf[pos++] = subchannel[i + 2]; + subBuf[pos++] = subchannel[i + 3]; + subBuf[pos++] = subchannel[i + 4]; + subBuf[pos++] = subchannel[i + 5]; + subBuf[pos++] = subchannel[i + 6]; + subBuf[pos++] = subchannel[i + 7]; + subBuf[pos++] = subchannel[i + 8]; + subBuf[pos++] = subchannel[i + 9]; + subBuf[pos++] = subchannel[i + 10]; + subBuf[pos++] = subchannel[i + 11]; + + // R to W + pos += 72; + } + + return Interleave(subBuf); + } + + public static byte[] Interleave(byte[] subchannel) + { + var subBuf = new byte[subchannel.Length]; + + var outPos = 0; + + for(var inPos = 0; inPos < subchannel.Length; inPos += 96) + { + for(var i = 0; i < 12; i++) + { + // P + subBuf[outPos + 0] += (byte)(subchannel[inPos + i + 0] & 0x80); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 0] & 0x40) << 1); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 0] & 0x20) << 2); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 0] & 0x10) << 3); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 0] & 0x08) << 4); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 0] & 0x04) << 5); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 0] & 0x02) << 6); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 0] & 0x01) << 7); + + // Q + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 12] & 0x80) >> 1); + subBuf[outPos + 1] += (byte)(subchannel[inPos + i + 12] & 0x40); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 12] & 0x20) << 1); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 12] & 0x10) << 2); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 12] & 0x08) << 3); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 12] & 0x04) << 4); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 12] & 0x02) << 5); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 12] & 0x01) << 6); + + // R + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 24] & 0x80) >> 2); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 24] & 0x40) >> 1); + subBuf[outPos + 2] += (byte)(subchannel[inPos + i + 24] & 0x20); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 24] & 0x10) << 1); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 24] & 0x08) << 2); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 24] & 0x04) << 3); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 24] & 0x02) << 4); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 24] & 0x01) << 5); + + // S + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 36] & 0x80) >> 3); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 36] & 0x40) >> 2); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 36] & 0x20) >> 1); + subBuf[outPos + 3] += (byte)(subchannel[inPos + i + 36] & 0x10); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 36] & 0x08) << 1); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 36] & 0x04) << 2); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 36] & 0x02) << 3); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 36] & 0x01) << 4); + + // T + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 48] & 0x80) >> 4); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 48] & 0x40) >> 3); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 48] & 0x20) >> 2); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 48] & 0x10) >> 1); + subBuf[outPos + 4] += (byte)(subchannel[inPos + i + 48] & 0x08); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 48] & 0x04) << 1); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 48] & 0x02) << 2); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 48] & 0x01) << 3); + + // U + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 60] & 0x80) >> 5); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 60] & 0x40) >> 4); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 60] & 0x20) >> 3); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 60] & 0x10) >> 2); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 60] & 0x08) >> 1); + subBuf[outPos + 5] += (byte)(subchannel[inPos + i + 60] & 0x04); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 60] & 0x02) << 1); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 60] & 0x01) << 2); + + // V + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 72] & 0x80) >> 6); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 72] & 0x40) >> 5); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 72] & 0x20) >> 4); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 72] & 0x10) >> 3); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 72] & 0x08) >> 2); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 72] & 0x04) >> 1); + subBuf[outPos + 6] += (byte)(subchannel[inPos + i + 72] & 0x02); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 72] & 0x01) << 1); + + // W + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 84] & 0x80) >> 7); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 84] & 0x40) >> 6); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 84] & 0x20) >> 5); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 84] & 0x10) >> 4); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 84] & 0x08) >> 3); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 84] & 0x04) >> 2); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 84] & 0x02) >> 1); + subBuf[outPos + 7] += (byte)(subchannel[inPos + i + 84] & 0x01); + outPos += 8; + } + } + + return subBuf; + } + + public static byte[] Deinterleave(byte[] subchannel) + { + var subBuf = new byte[subchannel.Length]; + var inPos = 0; + + for(var outPos = 0; outPos < subchannel.Length; outPos += 96) + { + for(var i = 0; i < 12; i++) + { + // P + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 0] & 0x80) >> 0); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 1] & 0x80) >> 1); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 2] & 0x80) >> 2); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 3] & 0x80) >> 3); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 4] & 0x80) >> 4); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 5] & 0x80) >> 5); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 6] & 0x80) >> 6); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 7] & 0x80) >> 7); + + // Q + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 0] & 0x40) << 1); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 1] & 0x40) >> 0); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 2] & 0x40) >> 1); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 3] & 0x40) >> 2); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 4] & 0x40) >> 3); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 5] & 0x40) >> 4); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 6] & 0x40) >> 5); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 7] & 0x40) >> 6); + + // R + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 0] & 0x20) << 2); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 1] & 0x20) << 1); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 2] & 0x20) >> 0); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 3] & 0x20) >> 1); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 4] & 0x20) >> 2); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 5] & 0x20) >> 3); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 6] & 0x20) >> 4); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 7] & 0x20) >> 5); + + // S + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 0] & 0x10) << 3); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 1] & 0x10) << 2); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 2] & 0x10) << 1); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 3] & 0x10) >> 0); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 4] & 0x10) >> 1); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 5] & 0x10) >> 2); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 6] & 0x10) >> 3); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 7] & 0x10) >> 4); + + // T + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 0] & 0x8) << 4); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 1] & 0x8) << 3); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 2] & 0x8) << 2); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 3] & 0x8) << 1); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 4] & 0x8) >> 0); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 5] & 0x8) >> 1); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 6] & 0x8) >> 2); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 7] & 0x8) >> 3); + + // U + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 0] & 0x4) << 5); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 1] & 0x4) << 4); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 2] & 0x4) << 3); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 3] & 0x4) << 2); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 4] & 0x4) << 1); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 5] & 0x4) >> 0); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 6] & 0x4) >> 1); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 7] & 0x4) >> 2); + + // V + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 0] & 0x2) << 6); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 1] & 0x2) << 5); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 2] & 0x2) << 4); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 3] & 0x2) << 3); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 4] & 0x2) << 2); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 5] & 0x2) << 1); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 6] & 0x2) >> 0); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 7] & 0x2) >> 1); + + // W + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 0] & 0x1) << 7); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 1] & 0x1) << 6); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 2] & 0x1) << 5); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 3] & 0x1) << 4); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 4] & 0x1) << 3); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 5] & 0x1) << 2); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 6] & 0x1) << 1); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 7] & 0x1) >> 0); + + inPos += 8; + } + } + + return subBuf; + } + + public static string PrettifyQ(byte[] subBuf, bool bcd, long lba, bool corruptedPause, bool pause, bool rwEmpty) + { + CRC16CcittContext.Data(subBuf, 10, out byte[] crc); + + bool crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11]; + long minute = (lba + 150) / 4500; + long second = (lba + 150) % 4500 / 75; + long frame = (lba + 150) % 4500 % 75; + string area; + int control = (subBuf[0] & 0xF0) / 16; + int adr = subBuf[0] & 0x0F; + + string controlInfo = ((control & 0xC) / 4) switch + { + 0 => (control & 0x01) == 1 + ? Localization.Subchannel_PrettifyQ_stereo_audio_with_pre_emphasis + : Localization.Subchannel_PrettifyQ_stereo_audio_without_pre_emphasis, + 1 => (control & 0x01) == 1 + ? Localization.Subchannel_PrettifyQ_incremental_data + : Localization.Subchannel_PrettifyQ_uninterrupted_data, + 2 => (control & 0x01) == 1 + ? Localization.Subchannel_PrettifyQ_quadraphonic_audio_with_pre_emphasis + : Localization.Subchannel_PrettifyQ_quadraphonic_audio_without_pre_emphasis, + _ => string.Format(Localization.Subchannel_PrettifyQ_reserved_control_value__0_, + control & 0x01) + }; + + string copy = (control & 0x02) > 0 + ? Localization.Subchannel_PrettifyQ_copy_permitted + : Localization.Subchannel_PrettifyQ_copy_prohibited; + + if(bcd) BcdToBinaryQ(subBuf); + + int qPos = subBuf[3] * 60 * 75 + subBuf[4] * 75 + subBuf[5] - 150; + byte pmin = subBuf[7]; + byte psec = subBuf[8]; + + int qStart = subBuf[7] * 60 * 75 + subBuf[8] * 75 + subBuf[9] - 150; + int nextPos = subBuf[3] * 60 * 75 + subBuf[4] * 75 + subBuf[5] - 150; + byte zero = subBuf[6]; + int maxOut = subBuf[7] * 60 * 75 + subBuf[8] * 75 + subBuf[9] - 150; + bool final = subBuf[3] == 0xFF && subBuf[4] == 0xFF && subBuf[5] == 0xFF; + + BinaryToBcdQ(subBuf); + + if(lba < 0) + { + area = Localization.Subchannel_PrettifyQ_Lead_In; + + switch(adr) + { + case 1 when subBuf[2] < 0xA0: + return string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_9_10_11_LBA_12_track_13_starts_at_14_15_16_LBA_17_Q_CRC_18_19_20_R_W_21, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + subBuf[3], + subBuf[4], + subBuf[5], + qPos, + subBuf[2], + subBuf[7], + subBuf[8], + subBuf[9], + qStart, + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + case 1 when subBuf[2] == 0xA0: + { + string format = subBuf[8] switch + { + 0x00 => Localization.Subchannel_PrettifyQ_CD_DA_CD_ROM, + 0x10 => Localization.Subchannel_PrettifyQ_CD_i, + 0x20 => Localization.Subchannel_PrettifyQ_CD_ROM_XA, + _ => string.Format(Localization.Subchannel_PrettifyQ_unknown_0, subBuf[0]) + }; + + return string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_9_10_11_LBA_12_track_13_is_first_program_area_track_in_14_format_Q_CRC_15_16_17_R_W_18, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + subBuf[3], + subBuf[4], + subBuf[5], + qPos, + subBuf[2], + format, + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + } + case 1 when subBuf[2] == 0xA1: + return string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_9_10_11_LBA_12_track_13_is_last_program_area_track_Q_CRC_14_15_16_R_W_17, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + subBuf[3], + subBuf[4], + subBuf[5], + qPos, + subBuf[2], + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + case 1: + return subBuf[2] == 0xA2 + ? string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_9_10_11_LBA_12_track_13_starts_at_14_15_16_LBA_17_Q_CRC_18_19_20_R_W_21, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + subBuf[3], + subBuf[4], + subBuf[5], + qPos, + subBuf[2], + subBuf[7], + subBuf[8], + subBuf[9], + qStart, + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty) + : string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_8_9_10_11_12_13_14_15_16_17_CRC_18_19_20_R_W_21, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + subBuf[0], + subBuf[1], + subBuf[2], + subBuf[3], + subBuf[4], + subBuf[5], + subBuf[6], + subBuf[7], + subBuf[8], + subBuf[9], + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + case 2: + return string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_MCN_9_frame_10_CRC_11_12_13_R_W_14, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + DecodeMcn(subBuf), + subBuf[9], + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + } + + if(adr != 5) + { + return string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_8_9_10_11_12_13_14_15_16_17_CRC_18_19_20_R_W_21, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + subBuf[0], + subBuf[1], + subBuf[2], + subBuf[3], + subBuf[4], + subBuf[5], + subBuf[6], + subBuf[7], + subBuf[8], + subBuf[9], + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + } + + switch(subBuf[2]) + { + case <= 0x40: + return string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_skip_interval_start_time_9_10_11_skip_interval_stop_time_12_13_14_CRC_15_16_17_R_W_18, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + subBuf[7], + subBuf[8], + subBuf[9], + subBuf[3], + subBuf[4], + subBuf[5], + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + case 0xB0: + return final + ? string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_next_program_area_can_start_at_9_10_11_LBA_12_last_session_13_mode_5_pointers_CRC_14_15_16_R_W_17, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + subBuf[3], + subBuf[4], + subBuf[5], + nextPos, + zero, + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty) + : string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_next_program_area_can_start_at_9_10_11_LBA_12_maximum_Lead_out_at_13_14_15_LBA_16_17_mode_5_pointers_CRC_18_19_20_R_W_21, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + subBuf[3], + subBuf[4], + subBuf[5], + nextPos, + subBuf[7], + subBuf[8], + subBuf[9], + maxOut, + zero, + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + case 0xB1: + return string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_9_skip_interval_pointers_10_skip_track_assignments_CRC_11_12_13_R_W_14, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + pmin, + psec, + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + } + + if(subBuf[2] != 0xB2 && subBuf[2] != 0xB3 && subBuf[2] != 0xB4) + { + return subBuf[2] == 0xC0 + ? string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_ATIP_values_9_10_11_first_disc_Lead_in_starts_at_12_13_14_LBA_15_CRC_16_17_18_R_W_19, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + subBuf[3], + subBuf[4], + subBuf[5], + subBuf[7], + subBuf[8], + subBuf[9], + qStart, + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty) + : string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_8_9_10_11_12_13_14_15_16_17_CRC_18_19_20_R_W_21, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + subBuf[0], + subBuf[1], + subBuf[2], + subBuf[3], + subBuf[4], + subBuf[5], + subBuf[6], + subBuf[7], + subBuf[8], + subBuf[9], + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + } + + var skipTracks = $"{subBuf[3]:X2}"; + + if(subBuf[4] > 0) skipTracks += $", {subBuf[4]:X2}"; + + if(subBuf[5] > 0) skipTracks += $", {subBuf[4]:X2}"; + + if(subBuf[7] > 0) skipTracks += $", {subBuf[4]:X2}"; + + if(subBuf[8] > 0) skipTracks += $", {subBuf[4]:X2}"; + + if(subBuf[9] > 0) skipTracks += $", {subBuf[4]:X2}"; + + return string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_tracks_9_to_be_skipped_CRC_10_11_12_R_W_13, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + skipTracks, + subBuf[10], + subBuf[11], + crcOk ? Localization.Subchannel_PrettifyQ_OK : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty); + } + + area = subBuf[1] == 0xAA + ? Localization.Subchannel_PrettifyQ_Lead_out + : Localization.Subchannel_PrettifyQ_Program; + + return adr switch + { + 1 => string.Format(Localization + .Subchannel_PrettifyQ_0_D2_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_track_9_index_10_relative_position_11_12_13_LBA_14_absolute_position_15_16_17_LBA_18_Q_CRC_19_20_21_R_W_22, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + subBuf[1], + subBuf[2], + subBuf[3], + subBuf[4], + subBuf[5], + qPos + 150, + subBuf[7], + subBuf[8], + subBuf[9], + qStart, + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty), + 2 => string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_MCN_9_frame_10_CRC_11_12_13_R_W_14, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + DecodeMcn(subBuf), + subBuf[9], + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty), + 3 => string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_ISRC_9_frame_10_CRC_11_12_13_R_W_14, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + adr, + DecodeIsrc(subBuf), + subBuf[9], + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty), + _ => string.Format(Localization + .Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_8_9_10_11_12_13_14_15_16_17_CRC_18_19_20_R_W_21, + minute, + second, + frame, + lba, + area, + corruptedPause + ? Localization.Subchannel_PrettifyQ_corrupted_pause + : pause + ? Localization.Subchannel_PrettifyQ_pause + : Localization.Subchannel_PrettifyQ_not_pause, + controlInfo, + copy, + subBuf[0], + subBuf[1], + subBuf[2], + subBuf[3], + subBuf[4], + subBuf[5], + subBuf[6], + subBuf[7], + subBuf[8], + subBuf[9], + subBuf[10], + subBuf[11], + crcOk + ? Localization.Subchannel_PrettifyQ_OK + : Localization.Subchannel_PrettifyQ_BAD, + rwEmpty + ? Localization.Subchannel_PrettifyQ_empty + : Localization.Subchannel_PrettifyQ_not_empty) + }; + } + + public static string DecodeIsrc(byte[] q) => + $"{_isrcTable[q[1] / 4]}{_isrcTable[(q[1] & 3) * 16 + q[2] / 16]}{_isrcTable[(q[2] & 0xF) * 4 + q[3] / 64]}{_isrcTable[q[3] & 0x3F]}{_isrcTable[q[4] / 4]}{q[5]:X2}{q[6]:X2}{q[7]:X2}{q[8] / 16:X1}"; + + public static string DecodeMcn(byte[] q) => $"{q[1]:X2}{q[2]:X2}{q[3]:X2}{q[4]:X2}{q[5]:X2}{q[6]:X2}{q[7] >> 4:X}"; + + public static byte GetIsrcCode(char c) => c switch + { + '0' => 0x00, + '1' => 0x01, + '2' => 0x02, + '3' => 0x03, + '4' => 0x04, + '5' => 0x05, + '6' => 0x06, + '7' => 0x07, + '8' => 0x08, + '9' => 0x09, + 'A' => 0x11, + 'B' => 0x12, + 'C' => 0x13, + 'D' => 0x14, + 'E' => 0x15, + 'F' => 0x16, + 'G' => 0x17, + 'H' => 0x18, + 'I' => 0x19, + 'J' => 0x1A, + 'K' => 0x1B, + 'L' => 0x1C, + 'M' => 0x1D, + 'N' => 0x1E, + 'O' => 0x1F, + 'P' => 0x20, + 'Q' => 0x21, + 'R' => 0x22, + 'S' => 0x23, + 'T' => 0x24, + 'U' => 0x25, + 'V' => 0x26, + 'W' => 0x27, + 'X' => 0x28, + 'Y' => 0x29, + 'Z' => 0x2A, + _ => 0x00 + }; + + public static byte[] Generate(int sector, uint trackSequence, int pregap, int trackStart, byte flags, byte index) + { + bool isPregap = sector < 0 || sector <= trackStart + pregap; + + if(index == 0) index = (byte)(isPregap ? 0 : 1); + + var sub = new byte[96]; + + // P + if(isPregap) + { + sub[0] = 0xFF; + sub[1] = 0xFF; + sub[2] = 0xFF; + sub[3] = 0xFF; + sub[4] = 0xFF; + sub[5] = 0xFF; + sub[6] = 0xFF; + sub[7] = 0xFF; + sub[8] = 0xFF; + sub[9] = 0xFF; + sub[10] = 0xFF; + sub[11] = 0xFF; + } + + // Q + var q = new byte[12]; + + q[0] = (byte)((flags << 4) + 1); + q[1] = (byte)trackSequence; + q[2] = index; + + int relative; + + if(isPregap) + relative = pregap + trackStart - sector; + else + relative = sector - trackStart; + + sector += 150; + + int min = relative / 60 / 75; + int sec = relative / 75 - min * 60; + int frame = relative - min * 60 * 75 - sec * 75; + + int amin = sector / 60 / 75; + int asec = sector / 75 - amin * 60; + int aframe = sector - amin * 60 * 75 - asec * 75; + + q[3] = (byte)min; + q[4] = (byte)sec; + q[5] = (byte)frame; + + q[7] = (byte)amin; + q[8] = (byte)asec; + q[9] = (byte)aframe; + + q[1] = (byte)((q[1] / 10 << 4) + q[1] % 10); + q[2] = (byte)((q[2] / 10 << 4) + q[2] % 10); + q[3] = (byte)((q[3] / 10 << 4) + q[3] % 10); + q[4] = (byte)((q[4] / 10 << 4) + q[4] % 10); + q[5] = (byte)((q[5] / 10 << 4) + q[5] % 10); + q[6] = (byte)((q[6] / 10 << 4) + q[6] % 10); + q[7] = (byte)((q[7] / 10 << 4) + q[7] % 10); + q[8] = (byte)((q[8] / 10 << 4) + q[8] % 10); + + q[9] = (byte)((q[9] / 10 << 4) + q[9] % 10); + + CRC16CcittContext.Data(q, 10, out byte[] qCrc); + q[10] = qCrc[0]; + q[11] = qCrc[1]; + + Array.Copy(q, 0, sub, 12, 12); + + return Interleave(sub); + } +} \ No newline at end of file diff --git a/Aaru.Decoders/CD/TOC.cs b/Aaru.Decoders/CD/TOC.cs new file mode 100644 index 000000000..f9c869bf0 --- /dev/null +++ b/Aaru.Decoders/CD/TOC.cs @@ -0,0 +1,248 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : TOC.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes CD Table of Contents. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Console; +using Aaru.Helpers; + +namespace Aaru.Decoders.CD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ISO/IEC 61104: Compact disc video system - 12 cm CD-V +// ISO/IEC 60908: Audio recording - Compact disc digital audio system +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class TOC +{ + const string MODULE_NAME = "CD TOC decoder"; + + public static CDTOC? Decode(byte[] CDTOCResponse) + { + if(CDTOCResponse is not { Length: > 4 }) return null; + + var decoded = new CDTOC + { + DataLength = BigEndianBitConverter.ToUInt16(CDTOCResponse, 0), + FirstTrack = CDTOCResponse[2], + LastTrack = CDTOCResponse[3] + }; + + decoded.TrackDescriptors = new CDTOCTrackDataDescriptor[(decoded.DataLength - 2) / 8]; + + if(decoded.DataLength + 2 != CDTOCResponse.Length) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Expected_CD_TOC_size_0_bytes_is_not_received_size_1_bytes_not_decoding, + decoded.DataLength + 2, + CDTOCResponse.Length); + + return null; + } + + for(var i = 0; i < (decoded.DataLength - 2) / 8; i++) + { + decoded.TrackDescriptors[i].Reserved1 = CDTOCResponse[0 + i * 8 + 4]; + decoded.TrackDescriptors[i].ADR = (byte)((CDTOCResponse[1 + i * 8 + 4] & 0xF0) >> 4); + decoded.TrackDescriptors[i].CONTROL = (byte)(CDTOCResponse[1 + i * 8 + 4] & 0x0F); + decoded.TrackDescriptors[i].TrackNumber = CDTOCResponse[2 + i * 8 + 4]; + decoded.TrackDescriptors[i].Reserved2 = CDTOCResponse[3 + i * 8 + 4]; + + decoded.TrackDescriptors[i].TrackStartAddress = + BigEndianBitConverter.ToUInt32(CDTOCResponse, 4 + i * 8 + 4); + } + + return decoded; + } + + public static string Prettify(CDTOC? CDTOCResponse) + { + if(CDTOCResponse == null) return null; + + CDTOC response = CDTOCResponse.Value; + + var sb = new StringBuilder(); + + sb.AppendFormat(Localization.First_track_number_in_first_complete_session_0, response.FirstTrack).AppendLine(); + sb.AppendFormat(Localization.Last_track_number_in_last_complete_session_0, response.LastTrack).AppendLine(); + + foreach(CDTOCTrackDataDescriptor descriptor in response.TrackDescriptors) + { + if(descriptor.TrackNumber == 0xAA) + sb.AppendLine(Localization.Track_number_Lead_Out); + else + sb.AppendFormat(Localization.Track_number_0, descriptor.TrackNumber).AppendLine(); + + sb.AppendFormat(Localization.Track_starts_at_LBA_0_or_MSF_2_3, + descriptor.TrackStartAddress, + (descriptor.TrackStartAddress & 0x0000FF00) >> 8, + (descriptor.TrackStartAddress & 0x00FF0000) >> 16, + (descriptor.TrackStartAddress & 0xFF000000) >> 24) + .AppendLine(); + + switch((TocAdr)descriptor.ADR) + { + case TocAdr.NoInformation: + sb.AppendLine(Localization.Q_subchannel_mode_not_given); + + break; + case TocAdr.TrackPointer: + sb.AppendLine(Localization.Q_subchannel_stores_track_pointer); + + break; + case TocAdr.VideoTrackPointer: + sb.AppendLine(Localization.Q_subchannel_stores_video_track_pointer); + + break; + case TocAdr.ISRC: + sb.AppendLine(Localization.Q_subchannel_stores_ISRC); + + break; + case TocAdr.MediaCatalogNumber: + sb.AppendLine(Localization.Q_subchannel_stores_media_catalog_number); + + break; + default: + sb.AppendFormat(Localization.Q_subchannel_mode_0, descriptor.ADR).AppendLine(); + + break; + } + + if((descriptor.CONTROL & (byte)TocControl.ReservedMask) == (byte)TocControl.ReservedMask) + sb.AppendFormat(Localization.Reserved_flags_0_set, descriptor.CONTROL).AppendLine(); + else + { + switch((TocControl)(descriptor.CONTROL & 0x0D)) + { + case TocControl.TwoChanNoPreEmph: + sb.AppendLine(Localization.Stereo_audio_track_with_no_pre_emphasis); + + break; + case TocControl.TwoChanPreEmph: + sb.AppendLine(Localization.Stereo_audio_track_with_50_15_us_pre_emphasis); + + break; + case TocControl.FourChanNoPreEmph: + sb.AppendLine(Localization.Quadraphonic_audio_track_with_no_pre_emphasis); + + break; + case TocControl.FourChanPreEmph: + sb.AppendLine(Localization.Quadraphonic_audio_track_with_50_15_us_pre_emphasis); + + break; + case TocControl.DataTrack: + sb.AppendLine(Localization.Data_track_recorded_uninterrupted); + + break; + case TocControl.DataTrackIncremental: + sb.AppendLine(Localization.Data_track_recorded_incrementally); + + break; + } + + sb.AppendLine((descriptor.CONTROL & (byte)TocControl.CopyPermissionMask) == + (byte)TocControl.CopyPermissionMask + ? Localization.Digital_copy_of_track_is_permitted + : Localization.Digital_copy_of_track_is_prohibited); + +#if DEBUG + if(descriptor.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, descriptor.Reserved1).AppendLine(); + + if(descriptor.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, descriptor.Reserved2).AppendLine(); +#endif + + sb.AppendLine(); + } + } + + return sb.ToString(); + } + + public static string Prettify(byte[] CDTOCResponse) + { + CDTOC? decoded = Decode(CDTOCResponse); + + return Prettify(decoded); + } + +#region Nested type: CDTOC + + public struct CDTOC + { + /// Total size of returned TOC minus this field + public ushort DataLength; + /// First track number in hex + public byte FirstTrack; + /// Last track number in hex + public byte LastTrack; + /// Track descriptors + public CDTOCTrackDataDescriptor[] TrackDescriptors; + } + +#endregion + +#region Nested type: CDTOCTrackDataDescriptor + + public struct CDTOCTrackDataDescriptor + { + /// Byte 0 Reserved + public byte Reserved1; + /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found + public byte ADR; + /// Byte 1, bits 3 to 0 Track attributes + public byte CONTROL; + /// Byte 2 Track number + public byte TrackNumber; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 7 The track start address in LBA or in MSF + public uint TrackStartAddress; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/AACS.cs b/Aaru.Decoders/DVD/AACS.cs new file mode 100644 index 000000000..8612fed0d --- /dev/null +++ b/Aaru.Decoders/DVD/AACS.cs @@ -0,0 +1,73 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : AACS.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD AACS structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class AACS +{ +#region Nested type: HDLeadInCopyright + + public struct HDLeadInCopyright + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 2052 HD DVD Lead-In Copyright Information + public byte[] CopyrightInformation; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/ADIP.cs b/Aaru.Decoders/DVD/ADIP.cs new file mode 100644 index 000000000..d2c2485dd --- /dev/null +++ b/Aaru.Decoders/DVD/ADIP.cs @@ -0,0 +1,73 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ADIP.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD ADress-In-Pregroove. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class ADIP +{ +#region Nested type: ADIPInformation + + public struct ADIPInformation + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 259 ADIP, defined in DVD standards + public byte[] ADIP; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/BCA.cs b/Aaru.Decoders/DVD/BCA.cs new file mode 100644 index 000000000..65b3bdc91 --- /dev/null +++ b/Aaru.Decoders/DVD/BCA.cs @@ -0,0 +1,73 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : BCA.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD Burst Cutting Area. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class BCA +{ +#region Nested type: BurstCuttingArea + + public struct BurstCuttingArea + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end Burst cutting area contents, 12 to 188 bytes + public byte[] BCA; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/CPRM.cs b/Aaru.Decoders/DVD/CPRM.cs new file mode 100644 index 000000000..0d7d139de --- /dev/null +++ b/Aaru.Decoders/DVD/CPRM.cs @@ -0,0 +1,89 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CPRM.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD CPRM structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class CPRM +{ +#region Nested type: DiscMediaIdentifier + + public struct DiscMediaIdentifier + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end Disc Media Identifier for CPRM + public byte[] MediaIdentifier; + } + +#endregion + +#region Nested type: DiscMediaKeyBlock + + public struct DiscMediaKeyBlock + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end Disc Media Key Block for CPRM + public byte[] MediaKeyBlock; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/CSS&CPRM.cs b/Aaru.Decoders/DVD/CSS&CPRM.cs new file mode 100644 index 000000000..4f3b68440 --- /dev/null +++ b/Aaru.Decoders/DVD/CSS&CPRM.cs @@ -0,0 +1,378 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CSS&CPRM.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD CSS & CPRM structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// Copyright © 2020-2024 Rebecca Wallander +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class CSS_CPRM +{ + public static LeadInCopyright? DecodeLeadInCopyright(byte[] response) + { + if(response?.Length != 8) return null; + + return new LeadInCopyright + { + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + CopyrightType = (CopyrightType)response[4], + RegionInformation = response[5], + Reserved3 = response[6], + Reserved4 = response[7] + }; + } + + public static RegionalPlaybackControlState? DecodeRegionalPlaybackControlState(byte[] response) + { + if(response?.Length != 8) return null; + + return new RegionalPlaybackControlState + { + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + TypeCode_VendorResetsAvailable_UserControlledChangesAvailable = response[4], + RegionMask = response[5], + RPCScheme = response[6], + Reserved3 = response[7] + }; + } + + public static string PrettifyRegionalPlaybackControlState(RegionalPlaybackControlState? rpc) + { + if(rpc == null) return null; + + RegionalPlaybackControlState decoded = rpc.Value; + var sb = new StringBuilder(); + + var typeCode = (TypeCode)((decoded.TypeCode_VendorResetsAvailable_UserControlledChangesAvailable & 0xc0) >> 6); + + int vendorResets = (decoded.TypeCode_VendorResetsAvailable_UserControlledChangesAvailable & 0x38) >> 3; + + int userControlledChanges = decoded.TypeCode_VendorResetsAvailable_UserControlledChangesAvailable & 0x7; + + switch(typeCode) + { + case TypeCode.None: + sb.AppendLine(Localization.No_drive_region_setting); + + break; + case TypeCode.Set: + sb.AppendLine(Localization.Drive_region_is_set); + + break; + case TypeCode.LastChance: + sb.AppendLine(Localization.Drive_region_is_set_with_additional_restrictions_required_to_make_a_change); + + break; + case TypeCode.Perm: + sb.AppendLine(Localization + .Drive_region_has_been_set_permanently_but_may_be_reset_by_the_vendor_if_necessary); + + break; + } + + sb.AppendLine(string.Format(Localization.Drive_has_0_vendor_resets_available, vendorResets)); + sb.AppendLine(string.Format(Localization.Drive_has_0_user_controlled_changes_available, userControlledChanges)); + + switch(decoded.RegionMask) + { + case 0xFF: + sb.AppendLine(Localization.Drive_has_no_region_set); + + break; + case 0x00: + sb.AppendLine(Localization.Drive_is_region_free); + + break; + default: + { + sb.Append(Localization.Drive_has_the_following_regions_set); + + if((decoded.RegionMask & 0x01) != 0x01) sb.Append(" 1"); + + if((decoded.RegionMask & 0x02) != 0x02) sb.Append(" 2"); + + if((decoded.RegionMask & 0x04) != 0x04) sb.Append(" 3"); + + if((decoded.RegionMask & 0x08) != 0x08) sb.Append(" 4"); + + if((decoded.RegionMask & 0x10) != 0x10) sb.Append(" 5"); + + if((decoded.RegionMask & 0x20) != 0x20) sb.Append(" 6"); + + if((decoded.RegionMask & 0x40) != 0x40) sb.Append(" 7"); + + if((decoded.RegionMask & 0x80) != 0x80) sb.Append(" 8"); + + break; + } + } + + sb.AppendLine(""); + + switch(decoded.RPCScheme) + { + case 0x00: + sb.AppendLine(Localization.The_Logical_Unit_does_not_enforce_Region_Playback_Controls_RPC); + + break; + case 0x01: + sb.AppendLine(Localization + .The_Logical_Unit_shall_adhere_to_the_specification_and_all_requirements_of_the_CSS_license_agreement_concerning_RPC); + + break; + default: + sb.AppendLine(Localization.The_Logical_Unit_uses_an_unknown_region_enforcement_scheme); + + break; + } + + return sb.ToString(); + } + + public static string PrettifyRegionalPlaybackControlState(byte[] response) => + PrettifyRegionalPlaybackControlState(DecodeRegionalPlaybackControlState(response)); + + public static string PrettifyLeadInCopyright(LeadInCopyright? cmi) + { + if(cmi == null) return null; + + LeadInCopyright decoded = cmi.Value; + var sb = new StringBuilder(); + + switch(decoded.CopyrightType) + { + case CopyrightType.NoProtection: + sb.AppendLine(Localization.Disc_has_no_encryption); + + break; + case CopyrightType.CSS: + sb.AppendLine(Localization.Disc_is_encrypted_using_CSS_or_CPPM); + + break; + case CopyrightType.CPRM: + sb.AppendLine(Localization.Disc_is_encrypted_using_CPRM); + + break; + case CopyrightType.AACS: + sb.AppendLine(Localization.Disc_is_encrypted_using_AACS); + + break; + default: + sb.AppendFormat(Localization.Disc_is_encrypted_using_unknown_algorithm_with_ID_0, + decoded.CopyrightType); + + break; + } + + if(decoded.CopyrightType == 0) return sb.ToString(); + + switch(decoded.RegionInformation) + { + case 0xFF: + sb.AppendLine(Localization.Disc_cannot_be_played_in_any_region_at_all); + + break; + case 0x00: + sb.AppendLine(Localization.Disc_can_be_played_in_any_region); + + break; + default: + { + sb.Append(Localization.Disc_can_be_played_in_the_following_regions); + + if((decoded.RegionInformation & 0x01) != 0x01) sb.Append(" 1"); + + if((decoded.RegionInformation & 0x02) != 0x02) sb.Append(" 2"); + + if((decoded.RegionInformation & 0x04) != 0x04) sb.Append(" 3"); + + if((decoded.RegionInformation & 0x08) != 0x08) sb.Append(" 4"); + + if((decoded.RegionInformation & 0x10) != 0x10) sb.Append(" 5"); + + if((decoded.RegionInformation & 0x20) != 0x20) sb.Append(" 6"); + + if((decoded.RegionInformation & 0x40) != 0x40) sb.Append(" 7"); + + if((decoded.RegionInformation & 0x80) != 0x80) sb.Append(" 8"); + + break; + } + } + + return sb.ToString(); + } + + public static string PrettifyLeadInCopyright(byte[] response) => + PrettifyLeadInCopyright(DecodeLeadInCopyright(response)); + +#region Nested type: AuthenticationSuccessFlag + + public struct AuthenticationSuccessFlag + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved and ASF + public byte ASF; + } + +#endregion + +#region Nested type: DiscKey + + public struct DiscKey + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 2052 Disc key for CSS, Album Identifier for CPPM + public byte[] Key; + } + +#endregion + +#region Nested type: LeadInCopyright + + public struct LeadInCopyright + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Copy protection system type + public CopyrightType CopyrightType; + /// Byte 5 Bitmask of regions where this disc is playable + public byte RegionInformation; + /// Byte 6 Reserved + public byte Reserved3; + /// Byte 7 Reserved + public byte Reserved4; + } + +#endregion + +#region Nested type: RegionalPlaybackControlState + + public struct RegionalPlaybackControlState + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Type Code and # of Vendor Resets Available and # of User Controlled Changes Available + public byte TypeCode_VendorResetsAvailable_UserControlledChangesAvailable; + /// Byte 5 Region Mask + public byte RegionMask; + /// Byte 6 RPC Scheme + public byte RPCScheme; + /// Byte 7 Reserved + public byte Reserved3; + } + +#endregion + +#region Nested type: TitleKey + + public struct TitleKey + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 CPM + public byte CMI; + /// Bytes 5 to 10 Title key for CSS + public byte[] Key; + /// Byte 11 Reserved + public byte Reserved3; + /// Byte 12 Reserved + public byte Reserved4; + } + +#endregion + +#region Nested type: TypeCode + + enum TypeCode + { + None = 0, + Set = 1, + LastChance = 2, + Perm = 3 + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/Cartridge.cs b/Aaru.Decoders/DVD/Cartridge.cs new file mode 100644 index 000000000..edb8d4ae7 --- /dev/null +++ b/Aaru.Decoders/DVD/Cartridge.cs @@ -0,0 +1,176 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Cartridge.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD cartridge structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class Cartridge +{ + public static MediumStatus? Decode(byte[] response) + { + if(response?.Length != 8) return null; + + return new MediumStatus + { + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + Cartridge = (response[4] & 0x80) == 0x80, + OUT = (response[4] & 0x40) == 0x40, + Reserved3 = (byte)((response[4] & 0x30) >> 4), + MSWI = (response[4] & 0x08) == 0x08, + CWP = (response[4] & 0x04) == 0x04, + PWP = (response[4] & 0x02) == 0x02, + Reserved4 = (response[4] & 0x01) == 0x01, + DiscType = response[5], + Reserved5 = response[6], + RAMSWI = response[7] + }; + } + + public static string Prettify(MediumStatus? status) + { + if(status == null) return null; + + MediumStatus decoded = status.Value; + var sb = new StringBuilder(); + + if(decoded.PWP) sb.AppendLine(Localization.Disc_surface_is_set_to_write_protected_status); + + if(decoded.Cartridge) + { + sb.AppendLine(Localization.Disc_comes_in_a_cartridge); + + if(decoded.OUT) sb.AppendLine(Localization.Disc_has_been_extracted_from_the_cartridge); + + if(decoded.CWP) sb.AppendLine(Localization.Cartridge_is_set_to_write_protected); + } + + switch(decoded.DiscType) + { + case 0: + sb.AppendLine(Localization.Disc_shall_not_be_written_without_a_cartridge); + + break; + case 0x10: + sb.AppendLine(Localization.Disc_may_be_written_without_a_cartridge); + + break; + default: + sb.AppendFormat(Localization.Unknown_disc_type_id_0, decoded.DiscType).AppendLine(); + + break; + } + + if(!decoded.MSWI) return sb.ToString(); + + switch(decoded.RAMSWI) + { + case 0: + break; + case 1: + sb.AppendLine(Localization.Disc_is_write_inhibited_because_it_has_been_extracted_from_the_cartridge); + + break; + case 0xFF: + sb.AppendLine(Localization.Disc_is_write_inhibited_for_an_unspecified_reason); + + break; + default: + sb.AppendFormat(Localization.Disc_has_unknown_reason_0_for_write_inhibition, decoded.RAMSWI) + .AppendLine(); + + break; + } + + return sb.ToString(); + } + + public static string Prettify(byte[] response) => Prettify(Decode(response)); + +#region Nested type: MediumStatus + + public struct MediumStatus + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bit 7 Medium is in a cartridge + public bool Cartridge; + /// Byte 4, bit 6 Medium has been taken out/inserted in a cartridge + public bool OUT; + /// Byte 4, bits 5 to 4 Reserved + public byte Reserved3; + /// Byte 4, bit 3 Media is write protected by reason stablished in RAMSWI + public bool MSWI; + /// Byte 4, bit 2 Media is write protected by cartridge + public bool CWP; + /// Byte 4, bit 1 Media is persistently write protected + public bool PWP; + /// Byte 4, bit 0 Reserved + public bool Reserved4; + /// Byte 5 Writable status depending on cartridge + public byte DiscType; + /// Byte 6 Reserved + public byte Reserved5; + /// + /// Byte 7 Reason of specific write protection, only defined 0x01 as "bare disc wp", and 0xFF as unspecified. Rest + /// reserved. + /// + public byte RAMSWI; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/DDS.cs b/Aaru.Decoders/DVD/DDS.cs new file mode 100644 index 000000000..3ec484377 --- /dev/null +++ b/Aaru.Decoders/DVD/DDS.cs @@ -0,0 +1,259 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DDS.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD Disc Definition Structure. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 272: 120 mm DVD Rewritable Disk (DVD-RAM) +// ECMA 330: 120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable Disk (DVD-RAM) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DDS +{ + public static DiscDefinitionStructure? Decode(byte[] response) + { + if(response?.Length != 2052) return null; + + var dds = new DiscDefinitionStructure + { + Identifier = (ushort)((response[4] << 8) + response[5]) + }; + + if(dds.Identifier != 0x0A0A) return null; + + // Common to both DVD-RAM versions + dds.DataLength = (ushort)((response[0] << 8) + response[1]); + dds.Reserved1 = response[2]; + dds.Reserved2 = response[3]; + dds.Reserved3 = response[6]; + dds.InProcess |= (response[7] & 0x80) == 0x80; + dds.UserCertification |= (response[7] & 0x02) == 0x02; + dds.ManufacturerCertification |= (response[7] & 0x01) == 0x01; + + dds.UpdateCount = (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]); + + dds.Groups = (ushort)((response[12] << 8) + response[13]); + + // ECMA-272 + if(dds.Groups == 24) + { + dds.PartialCertification |= (response[7] & 0x40) == 0x40; + dds.FormattingOnlyAGroup |= (response[7] & 0x20) == 0x20; + dds.Reserved4 = (byte)((response[7] & 0x1C) >> 2); + dds.Reserved = new byte[6]; + Array.Copy(response, 14, dds.Reserved, 0, 6); + dds.GroupCertificationFlags = new GroupCertificationFlag[24]; + + for(var i = 0; i < 24; i++) + { + dds.GroupCertificationFlags[i].InProcess |= (response[20 + i] & 0x80) == 0x80; + dds.GroupCertificationFlags[i].PartialCertification |= (response[20 + i] & 0x40) == 0x40; + dds.GroupCertificationFlags[i].Reserved1 = (byte)((response[20 + i] & 0x3C) >> 2); + dds.GroupCertificationFlags[i].UserCertification |= (response[20 + i] & 0x02) == 0x02; + dds.GroupCertificationFlags[i].Reserved2 |= (response[20 + i] & 0x01) == 0x01; + } + } + + // ECMA-330 + if(dds.Groups != 1) return dds; + + { + dds.Reserved4 = (byte)((response[7] & 0x7C) >> 2); + dds.Reserved = new byte[68]; + Array.Copy(response, 16, dds.Reserved, 0, 68); + dds.Zones = (ushort)((response[14] << 8) + response[15]); + dds.SpareAreaFirstPSN = (uint)((response[85] << 16) + (response[86] << 8) + response[87]); + dds.SpareAreaLastPSN = (uint)((response[89] << 16) + (response[90] << 8) + response[91]); + dds.LSN0Location = (uint)((response[93] << 16) + (response[94] << 8) + response[95]); + dds.StartLSNForZone = new uint[dds.Zones]; + + for(var i = 0; i < dds.Zones; i++) + { + dds.StartLSNForZone[i] = (uint)((response[260 + i * 4 + 1] << 16) + + (response[260 + i * 4 + 2] << 8) + + response[260 + i * 4 + 3]); + } + } + + return dds; + } + + public static string Prettify(DiscDefinitionStructure? dds) + { + if(dds == null) return null; + + DiscDefinitionStructure decoded = dds.Value; + var sb = new StringBuilder(); + + if(decoded.InProcess) + { + sb.AppendLine(Localization.Formatting_in_progress); + + if(decoded.Groups == 24) + { + if(decoded.PartialCertification) + sb.AppendLine(Localization.Formatting_is_only_using_partial_certification); + + if(decoded.FormattingOnlyAGroup) sb.AppendLine(Localization.Only_a_group_is_being_formatted); + } + } + + if(decoded.UserCertification) sb.AppendLine(Localization.Disc_has_been_certified_by_a_user); + + if(decoded.ManufacturerCertification) sb.AppendLine(Localization.Disc_has_been_certified_by_a_manufacturer); + + sb.AppendFormat(Localization.DDS_has_been_updated_0_times, decoded.UpdateCount).AppendLine(); + + if(decoded.Groups == 24) + { + for(var i = 0; i < decoded.GroupCertificationFlags.Length; i++) + { + if(decoded.GroupCertificationFlags[i].InProcess) + { + sb.AppendFormat(Localization.Group_0_is_being_formatted, i).AppendLine(); + + if(decoded.GroupCertificationFlags[i].PartialCertification) + sb.AppendFormat(Localization.Group_0_is_being_certified_partially, i).AppendLine(); + } + + if(decoded.GroupCertificationFlags[i].UserCertification) + sb.AppendFormat(Localization.Group_0_has_been_certified_by_an_user, i).AppendLine(); + } + } + + if(decoded.Groups != 1) return sb.ToString(); + + { + sb.AppendFormat(Localization.Disc_has_0_zones, decoded.Zones).AppendLine(); + + sb.AppendFormat(Localization.Primary_Spare_Area_stats_at_PSN_0_and_ends_at_PSN_1_inclusively, + decoded.SpareAreaFirstPSN, + decoded.SpareAreaLastPSN) + .AppendLine(); + + sb.AppendFormat(Localization.LSN_zero_is_at_PSN_0, decoded.LSN0Location).AppendLine(); + + for(var i = 0; i < decoded.StartLSNForZone.Length; i++) + sb.AppendFormat(Localization.Zone_0_starts_at_LSN_1, i, decoded.StartLSNForZone[i]).AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify(byte[] response) => Prettify(Decode(response)); + +#region Nested type: DiscDefinitionStructure + + public struct DiscDefinitionStructure + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + + /// Bytes 4 to 5 DDS Identifier = 0x0A0A + public ushort Identifier; + /// Byte 6 Reserved + public byte Reserved3; + /// Byte 7, bit 7 If set, formatting is in process + public bool InProcess; + /// Byte 7, bit 6 If set, formatting is using partial certification Only in ECMA-272 + public bool PartialCertification; + /// Byte 7, bit 5 If set, only a group is being formatted Only in ECMA-272 + public bool FormattingOnlyAGroup; + /// Byte 7, bits 4 to 2 Reserved + public byte Reserved4; + /// Byte 7, bit 1 If set, disk has been certified by a user + public bool UserCertification; + /// Byte 7, bit 0 If set, disk has been certified by a manufacturer + public bool ManufacturerCertification; + /// Bytes 8 to 11 How many times the DDS has been updated + public uint UpdateCount; + /// Bytes 12 to 13 How many groups the disk has 24 for ECMA-272 1 for ECMA-330 + public ushort Groups; + /// Bytes 14 to 15 How many zones the disk has Only in ECMA-330 + public ushort Zones; + /// Bytes 14 to 19 in ECMA-272 Bytes 16 to 83 in ECMA-330 Reserved + public byte[] Reserved; + /// Bytes 20 to 43 Group certification flags + public GroupCertificationFlag[] GroupCertificationFlags; + + /// Bytes 85 to 87 Location of first sector in the Primary Spare Area + public uint SpareAreaFirstPSN; + /// Bytes 89 to 91 Location of first sector in the Primary Spare Area + public uint SpareAreaLastPSN; + /// Bytes 93 to 95 PSN for LSN 0 + public uint LSN0Location; + /// The starting LSN of each zone + public uint[] StartLSNForZone; + } + +#endregion + +#region Nested type: GroupCertificationFlag + + public struct GroupCertificationFlag + { + /// Bit 7 If set, formatting of this group is in process + public bool InProcess; + /// Bit 6 If set, formatting is using partial certification + public bool PartialCertification; + /// Bits 5 to 2 Reserved + public byte Reserved1; + /// Bit 1 If set, this group has been certified by user + public bool UserCertification; + /// Bit 0 Reserved + public bool Reserved2; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/DMI.cs b/Aaru.Decoders/DVD/DMI.cs new file mode 100644 index 000000000..f8d98ad8a --- /dev/null +++ b/Aaru.Decoders/DVD/DMI.cs @@ -0,0 +1,73 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DMI.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD Disc Manufacturer Information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class DMI +{ +#region Nested type: DiscManufacturingInformation + + public struct DiscManufacturingInformation + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 2052 Disc Manufacturing Information + public byte[] DMI; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/Enums.cs b/Aaru.Decoders/DVD/Enums.cs new file mode 100644 index 000000000..4f4d2e1a2 --- /dev/null +++ b/Aaru.Decoders/DVD/Enums.cs @@ -0,0 +1,186 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains various DVD enumerations. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + + +// ReSharper disable UnusedMember.Global +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedType.Global + +namespace Aaru.Decoders.DVD; + +#region Public enumerations + +public enum DiskCategory : byte +{ + /// DVD-ROM. Version 1 is ECMA-267 and ECMA-268. + DVDROM = 0, + /// DVD-RAM. Version 1 is ECMA-272. Version 6 is ECMA-330. + DVDRAM = 1, + /// DVD-R. Version 1 is ECMA-279. Version 5 is ECMA-359. Version 6 is ECMA-382. + DVDR = 2, + /// DVD-RW. Version 2 is ECMA-338. Version 3 is ECMA-384. + DVDRW = 3, + /// HD DVD-ROM + HDDVDROM = 4, + /// HD DVD-RAM + HDDVDRAM = 5, + /// HD DVD-R + HDDVDR = 6, + /// HD DVD-RW + HDDVDRW = 7, + /// UMD. Version 0 is ECMA-365. + UMD = 8, + /// DVD+RW. Version 1 is ECMA-274. Version 2 is ECMA-337. Version 3 is ECMA-371. + DVDPRW = 9, + /// DVD+R. Version 1 is ECMA-349. + DVDPR = 10, + /// DVD+RW DL. Version 1 is ECMA-374. + DVDPRWDL = 13, + /// DVD+R DL. Version 1 is ECMA-364. + DVDPRDL = 14, + /// According to standards this value is reserved. It's used by Nintendo GODs and WODs. + Nintendo = 15 +} + +public enum MaximumRateField : byte +{ + /// 2.52 Mbps + TwoMbps = 0x00, + /// 5.04 Mbps + FiveMbps = 0x01, + /// 10.08 Mbps + TenMbps = 0x02, + /// 20.16 Mbps + TwentyMbps = 0x03, + /// 30.24 Mbps + ThirtyMbps = 0x04, + Unspecified = 0x0F +} + +public enum LayerTypeFieldMask : byte +{ + Embossed = 0x01, + Recordable = 0x02, + Rewritable = 0x04, + Reserved = 0x08 +} + +public enum LinearDensityField : byte +{ + /// 0.267 μm/bit + TwoSix = 0x00, + /// 0.293 μm/bit + TwoNine = 0x01, + /// 0.409 to 0.435 μm/bit + FourZero = 0x02, + /// 0.280 to 0.291 μm/bit + TwoEight = 0x04, + /// 0.153 μm/bit + OneFive = 0x05, + /// 0.130 to 0.140 μm/bit + OneThree = 0x06, + /// 0.353 μm/bit + ThreeFive = 0x08 +} + +public enum TrackDensityField : byte +{ + /// 0.74 μm/track + Seven = 0x00, + /// 0.80 μm/track + Eight = 0x01, + /// 0.615 μm/track + Six = 0x02, + /// 0.40 μm/track + Four = 0x03, + /// 0.34 μm/track + Three = 0x04 +} + +public enum CopyrightType : byte +{ + /// There is no copy protection + NoProtection = 0x00, + /// Copy protection is CSS/CPPM + CSS = 0x01, + /// Copy protection is CPRM + CPRM = 0x02, + /// Copy protection is AACS + AACS = 0x10 +} + +public enum WPDiscTypes : byte +{ + /// Should not write without a cartridge + DoNotWrite = 0x00, + /// Can write without a cartridge + CanWrite = 0x01, + Reserved1 = 0x02, + Reserved2 = 0x03 +} + +public enum DVDSize +{ + /// 120 mm + OneTwenty = 0, + /// 80 mm + Eighty = 1 +} + +public enum DVDRAMDiscType +{ + /// Shall not be recorded without a case + Cased = 0, + /// May be recorded without a case or within one + Uncased = 1 +} + +public enum DVDLayerStructure +{ + Unspecified = 0, + InvertedStack = 1, + TwoP = 2, + Reserved = 3 +} + +public enum DVDRecordingSpeed +{ + None = 0, + Two = 0, + Four = 0x10, + Six = 0x20, + Eight = 0x30, + Ten = 0x40, + Twelve = 0x50 +} + +#endregion \ No newline at end of file diff --git a/Aaru.Decoders/DVD/Layers.cs b/Aaru.Decoders/DVD/Layers.cs new file mode 100644 index 000000000..778972688 --- /dev/null +++ b/Aaru.Decoders/DVD/Layers.cs @@ -0,0 +1,157 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Layers.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Records DVD layers structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static class Layers +{ +#region Nested type: JumpIntervalSize + + public struct JumpIntervalSize + { + /// Bytes 0 to 1 Data length = 10 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved + public byte Reserved6; + /// Byte 8 to 11 Jump Interval size for the Regular Interval Layer Jump + public uint Size; + } + +#endregion + +#region Nested type: LayerCapacity + + public struct LayerCapacity + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bit 7 If set, L0 capacity is immutable + public bool InitStatus; + /// Byte 4, bits 6 to 0 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved + public byte Reserved6; + /// Byte 8 to 11 L0 Data Area Capacity + public uint Capacity; + } + +#endregion + +#region Nested type: ManualLayerJumpAddress + + public struct ManualLayerJumpAddress + { + /// Bytes 0 to 1 Data length = 10 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved + public byte Reserved6; + /// Byte 8 to 11 LBA for the manual layer jump + public uint LBA; + } + +#endregion + +#region Nested type: MiddleZoneStartAddress + + public struct MiddleZoneStartAddress + { + /// Bytes 0 to 1 Data length = 10 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bit 7 If set, L0 shifter middle area is immutable + public bool InitStatus; + /// Byte 4, bits 6 to 0 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved + public byte Reserved6; + /// Byte 8 to 11 Start LBA of Shifted Middle Area on L0 + public uint ShiftedMiddleAreaStartAddress; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/PFI.cs b/Aaru.Decoders/DVD/PFI.cs new file mode 100644 index 000000000..7a589a6d9 --- /dev/null +++ b/Aaru.Decoders/DVD/PFI.cs @@ -0,0 +1,1495 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PFI.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Records DVD Physical Format Information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes; +using Aaru.Helpers; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 267: 120 mm DVD - Read-Only Disk +// ECMA 268: 80 mm DVD - Read-Only Disk +// ECMA 272: 120 mm DVD Rewritable Disk (DVD-RAM) +// ECMA 274: Data Interchange on 120 mm Optical Disk using +RW Format - Capacity: 3,0 Gbytes and 6,0 Gbytes +// ECMA 279: 80 mm (1,23 Gbytes per side) and 120 mm (3,95 Gbytes per side) DVD-Recordable Disk (DVD-R) +// ECMA 330: 120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable Disk (DVD-RAM) +// ECMA 337: Data Interchange on 120 mm and 80 mm Optical Disk using +RW Format - Capacity: 4,7 and 1,46 Gbytes per Side +// ECMA 338: 80 mm (1,46 Gbytes per side) and 120 mm (4,70 Gbytes per side) DVD Re-recordable Disk (DVD-RW) +// ECMA 349: Data Interchange on 120 mm and 80 mm Optical Disk using +R Format - Capacity: 4,7 and 1,46 Gbytes per Side +// ECMA 359: 80 mm (1,46 Gbytes per side) and 120 mm (4,70 Gbytes per side) DVD Recordable Disk (DVD-R) +// ECMA 364: Data Interchange on 120 mm and 80 mm Optical Disk using +R DL Format - Capacity 8,55 and 2,66 Gbytes per Side +// ECMA 365: Data Interchange on 60 mm Read-Only ODC - Capacity: 1,8 Gbytes (UMD™) +// ECMA 371: Data Interchange on 120 mm and 80 mm Optical Disk using +RW HS Format - Capacity 4,7 and 1,46 Gbytes per side +// ECMA 374: Data Interchange on 120 mm and 80 mm Optical Disk using +RW DL Format - Capacity 8,55 and 2,66 Gbytes per side +// ECMA 382: 120 mm (8,54 Gbytes per side) and 80 mm (2,66 Gbytes per side) DVD Recordable Disk for Dual Layer (DVD-R for DL) +// ECMA 384: 120 mm (8,54 Gbytes per side) and 80 mm (2,66 Gbytes per side) DVD Re-recordable Disk for Dual Layer (DVD-RW for DL) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static class PFI +{ + public static PhysicalFormatInformation? Decode(byte[] response, MediaType mediaType) + { + if(response == null) return null; + + if(response.Length == 2048) + { + var tmp2 = new byte[2052]; + Array.Copy(response, 0, tmp2, 4, 2048); + response = tmp2; + } + + if(response.Length < 2052) return null; + + var pfi = new PhysicalFormatInformation(); + byte[] tmp; + + pfi.DataLength = (ushort)((response[0] << 8) + response[1]); + pfi.Reserved1 = response[2]; + pfi.Reserved2 = response[3]; + + // Common + pfi.DiskCategory = (DiskCategory)((response[4] & 0xF0) >> 4); + pfi.PartVersion = (byte)(response[4] & 0x0F); + pfi.DiscSize = (DVDSize)((response[5] & 0xF0) >> 4); + pfi.MaximumRate = (MaximumRateField)(response[5] & 0x0F); + pfi.Reserved3 |= (response[6] & 0x80) == 0x80; + pfi.Layers = (byte)((response[6] & 0x60) >> 5); + pfi.TrackPath |= (response[6] & 0x08) == 0x08; + pfi.LayerType = (LayerTypeFieldMask)(response[6] & 0x07); + pfi.LinearDensity = (LinearDensityField)((response[7] & 0xF0) >> 4); + pfi.TrackDensity = (TrackDensityField)(response[7] & 0x0F); + + pfi.DataAreaStartPSN = (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]); + + pfi.DataAreaEndPSN = (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]); + + pfi.Layer0EndPSN = (uint)((response[16] << 24) + (response[17] << 16) + (response[18] << 8) + response[19]); + + pfi.BCA |= (response[20] & 0x80) == 0x80; + + pfi.RecordedBookType = pfi.DiskCategory; + + if(mediaType != MediaType.DVDROM) + { + switch(mediaType) + { + case MediaType.DVDPR: + pfi.DiskCategory = DiskCategory.DVDPR; + + break; + case MediaType.DVDPRDL: + pfi.DiskCategory = DiskCategory.DVDPRDL; + + break; + case MediaType.DVDPRW: + pfi.DiskCategory = DiskCategory.DVDPRW; + + break; + case MediaType.DVDPRWDL: + pfi.DiskCategory = DiskCategory.DVDPRWDL; + + break; + case MediaType.DVDRDL: + pfi.DiskCategory = DiskCategory.DVDR; + + if(pfi.PartVersion < 6) pfi.PartVersion = 6; + + break; + case MediaType.DVDR: + pfi.DiskCategory = DiskCategory.DVDR; + + if(pfi.PartVersion > 5) pfi.PartVersion = 5; + + break; + case MediaType.DVDRAM: + pfi.DiskCategory = DiskCategory.DVDRAM; + + break; + case MediaType.DVDRWDL: + pfi.DiskCategory = DiskCategory.DVDRW; + + if(pfi.PartVersion < 15) pfi.PartVersion = 15; + + break; + case MediaType.DVDRW: + pfi.DiskCategory = DiskCategory.DVDRW; + + if(pfi.PartVersion > 14) pfi.PartVersion = 14; + + break; + + case MediaType.HDDVDR: + pfi.DiskCategory = DiskCategory.HDDVDR; + + break; + case MediaType.HDDVDRAM: + pfi.DiskCategory = DiskCategory.HDDVDRAM; + + break; + case MediaType.HDDVDROM: + pfi.DiskCategory = DiskCategory.HDDVDROM; + + break; + case MediaType.HDDVDRW: + pfi.DiskCategory = DiskCategory.HDDVDRW; + + break; + case MediaType.GOD: + pfi.DiscSize = DVDSize.Eighty; + pfi.DiskCategory = DiskCategory.Nintendo; + + break; + case MediaType.WOD: + pfi.DiscSize = DVDSize.OneTwenty; + pfi.DiskCategory = DiskCategory.Nintendo; + + break; + case MediaType.UMD: + pfi.DiskCategory = DiskCategory.UMD; + + break; + } + } + + switch(pfi.DiskCategory) + { + // UMD + case DiskCategory.UMD: + pfi.MediaAttribute = (ushort)((response[21] << 8) + response[22]); + + break; + + // DVD-RAM + case DiskCategory.DVDRAM: + pfi.DiscType = (DVDRAMDiscType)response[36]; + + switch(pfi.PartVersion) + { + case 1: + pfi.Velocity = response[52]; + pfi.ReadPower = response[53]; + pfi.PeakPower = response[54]; + pfi.BiasPower = response[55]; + pfi.FirstPulseStart = response[56]; + pfi.FirstPulseEnd = response[57]; + pfi.MultiPulseDuration = response[58]; + pfi.LastPulseStart = response[59]; + pfi.LastPulseEnd = response[60]; + pfi.BiasPowerDuration = response[61]; + pfi.PeakPowerGroove = response[62]; + pfi.BiasPowerGroove = response[63]; + pfi.FirstPulseStartGroove = response[64]; + pfi.FirstPulseEndGroove = response[65]; + pfi.MultiplePulseDurationGroove = response[66]; + pfi.LastPulseStartGroove = response[67]; + pfi.LastPulseEndGroove = response[68]; + pfi.BiasPowerDurationGroove = response[69]; + + break; + case >= 6: + pfi.Velocity = response[504]; + pfi.ReadPower = response[505]; + pfi.AdaptativeWritePulseControlFlag |= (response[506] & 0x80) == 0x80; + pfi.PeakPower = response[507]; + pfi.BiasPower1 = response[508]; + pfi.BiasPower2 = response[509]; + pfi.BiasPower3 = response[510]; + pfi.PeakPowerGroove = response[511]; + pfi.BiasPower1Groove = response[512]; + pfi.BiasPower2Groove = response[513]; + pfi.BiasPower3Groove = response[514]; + pfi.FirstPulseEnd = response[515]; + pfi.FirstPulseDuration = response[516]; + pfi.MultiPulseDuration = response[518]; + pfi.LastPulseStart = response[519]; + pfi.BiasPower2Duration = response[520]; + pfi.FirstPulseStart3TSpace3T = response[521]; + pfi.FirstPulseStart4TSpace3T = response[522]; + pfi.FirstPulseStart5TSpace3T = response[523]; + pfi.FirstPulseStartSpace3T = response[524]; + pfi.FirstPulseStart3TSpace4T = response[525]; + pfi.FirstPulseStart4TSpace4T = response[526]; + pfi.FirstPulseStart5TSpace4T = response[527]; + pfi.FirstPulseStartSpace4T = response[528]; + pfi.FirstPulseStart3TSpace5T = response[529]; + pfi.FirstPulseStart4TSpace5T = response[530]; + pfi.FirstPulseStart5TSpace5T = response[531]; + pfi.FirstPulseStartSpace5T = response[532]; + pfi.FirstPulseStart3TSpace = response[533]; + pfi.FirstPulseStart4TSpace = response[534]; + pfi.FirstPulseStart5TSpace = response[535]; + pfi.FirstPulseStartSpace = response[536]; + pfi.FirstPulse3TStartTSpace3T = response[537]; + pfi.FirstPulse4TStartTSpace3T = response[538]; + pfi.FirstPulse5TStartTSpace3T = response[539]; + pfi.FirstPulseStartTSpace3T = response[540]; + pfi.FirstPulse3TStartTSpace4T = response[541]; + pfi.FirstPulse4TStartTSpace4T = response[542]; + pfi.FirstPulse5TStartTSpace4T = response[543]; + pfi.FirstPulseStartTSpace4T = response[544]; + pfi.FirstPulse3TStartTSpace5T = response[545]; + pfi.FirstPulse4TStartTSpace5T = response[546]; + pfi.FirstPulse5TStartTSpace5T = response[547]; + pfi.FirstPulseStartTSpace5T = response[548]; + pfi.FirstPulse3TStartTSpace = response[549]; + pfi.FirstPulse4TStartTSpace = response[550]; + pfi.FirstPulse5TStartTSpace = response[551]; + pfi.FirstPulseStartTSpace = response[552]; + tmp = new byte[48]; + Array.Copy(response, 553, tmp, 0, 48); + pfi.DiskManufacturer = StringHandlers.SpacePaddedToString(tmp); + tmp = new byte[16]; + Array.Copy(response, 601, tmp, 0, 16); + pfi.DiskManufacturerSupplementary = StringHandlers.SpacePaddedToString(tmp); + pfi.WritePowerControlParams = new byte[2]; + pfi.WritePowerControlParams[0] = response[617]; + pfi.WritePowerControlParams[1] = response[618]; + pfi.PowerRatioLandThreshold = response[619]; + pfi.TargetAsymmetry = response[620]; + pfi.TemporaryPeakPower = response[621]; + pfi.TemporaryBiasPower1 = response[622]; + pfi.TemporaryBiasPower2 = response[623]; + pfi.TemporaryBiasPower3 = response[624]; + pfi.PowerRatioGrooveThreshold = response[625]; + pfi.PowerRatioLandThreshold6T = response[626]; + pfi.PowerRatioGrooveThreshold6T = response[627]; + + break; + } + + break; + + // DVD-R and DVD-RW + case DiskCategory.DVDR when pfi.PartVersion < 6: + case DiskCategory.DVDRW when pfi.PartVersion < 15: + pfi.CurrentBorderOutSector = + (uint)((response[36] << 24) + (response[37] << 16) + (response[38] << 8) + response[39]); + + pfi.NextBorderInSector = + (uint)((response[40] << 24) + (response[41] << 16) + (response[42] << 8) + response[43]); + + break; + + // DVD+RW + case DiskCategory.DVDPRW: + pfi.RecordingVelocity = response[36]; + pfi.ReadPowerMaxVelocity = response[37]; + pfi.PIndMaxVelocity = response[38]; + pfi.PMaxVelocity = response[39]; + pfi.E1MaxVelocity = response[40]; + pfi.E2MaxVelocity = response[41]; + pfi.YTargetMaxVelocity = response[42]; + pfi.ReadPowerRefVelocity = response[43]; + pfi.PIndRefVelocity = response[44]; + pfi.PRefVelocity = response[45]; + pfi.E1RefVelocity = response[46]; + pfi.E2RefVelocity = response[47]; + pfi.YTargetRefVelocity = response[48]; + pfi.ReadPowerMinVelocity = response[49]; + pfi.PIndMinVelocity = response[50]; + pfi.PMinVelocity = response[51]; + pfi.E1MinVelocity = response[52]; + pfi.E2MinVelocity = response[53]; + pfi.YTargetMinVelocity = response[54]; + + break; + } + + // DVD+R, DVD+RW, DVD+R DL and DVD+RW DL + if(pfi.DiskCategory is DiskCategory.DVDPR + or DiskCategory.DVDPRW + or DiskCategory.DVDPRDL + or DiskCategory.DVDPRWDL) + { + pfi.VCPS |= (response[20] & 0x40) == 0x40; + pfi.ApplicationCode = response[21]; + pfi.ExtendedInformation = response[22]; + tmp = new byte[8]; + Array.Copy(response, 23, tmp, 0, 8); + pfi.DiskManufacturerID = StringHandlers.CToString(tmp); + tmp = new byte[3]; + Array.Copy(response, 31, tmp, 0, 3); + pfi.MediaTypeID = StringHandlers.CToString(tmp); + + pfi.ProductRevision = pfi.DiskCategory == DiskCategory.DVDPRDL ? (byte)(response[34] & 0x3F) : response[34]; + + pfi.PFIUsedInADIP = response[35]; + } + + switch(pfi.DiskCategory) + { + // DVD+RW + case DiskCategory.DVDPRW when pfi.PartVersion == 2: + pfi.TopFirstPulseDuration = response[55]; + pfi.MultiPulseDuration = response[56]; + pfi.FirstPulseLeadTime = response[57]; + pfi.EraseLeadTimeRefVelocity = response[58]; + pfi.EraseLeadTimeUppVelocity = response[59]; + + break; + + // DVD+R and DVD+R DL + case DiskCategory.DVDPR: + case DiskCategory.DVDPRDL: + pfi.PrimaryVelocity = response[36]; + pfi.UpperVelocity = response[37]; + pfi.Wavelength = response[38]; + pfi.NormalizedPowerDependency = response[39]; + pfi.MaximumPowerAtPrimaryVelocity = response[40]; + pfi.PindAtPrimaryVelocity = response[41]; + pfi.BtargetAtPrimaryVelocity = response[42]; + pfi.MaximumPowerAtUpperVelocity = response[43]; + pfi.PindAtUpperVelocity = response[44]; + pfi.BtargetAtUpperVelocity = response[45]; + pfi.FirstPulseDuration4TPrimaryVelocity = response[46]; + pfi.FirstPulseDuration3TPrimaryVelocity = response[47]; + pfi.MultiPulseDurationPrimaryVelocity = response[48]; + pfi.LastPulseDurationPrimaryVelocity = response[49]; + pfi.FirstPulseLeadTime4TPrimaryVelocity = response[50]; + pfi.FirstPulseLeadTime3TPrimaryVelocity = response[51]; + pfi.FirstPulseLeadingEdgePrimaryVelocity = response[52]; + pfi.FirstPulseDuration4TUpperVelocity = response[53]; + pfi.FirstPulseDuration3TUpperVelocity = response[54]; + pfi.MultiPulseDurationUpperVelocity = response[55]; + pfi.LastPulseDurationUpperVelocity = response[56]; + pfi.FirstPulseLeadTime4TUpperVelocity = response[57]; + pfi.FirstPulseLeadTime3TUpperVelocity = response[58]; + pfi.FirstPulseLeadingEdgeUpperVelocity = response[59]; + + break; + } + + switch(pfi.DiskCategory) + { + // DVD+R DL + case DiskCategory.DVDPRDL: + pfi.LayerStructure = (DVDLayerStructure)((response[34] & 0xC0) >> 6); + + break; + + // DVD+RW DL + case DiskCategory.DVDPRWDL: + pfi.BasicPrimaryVelocity = response[36]; + pfi.MaxReadPowerPrimaryVelocity = response[37]; + pfi.PindPrimaryVelocity = response[38]; + pfi.PPrimaryVelocity = response[39]; + pfi.E1PrimaryVelocity = response[40]; + pfi.E2PrimaryVelocity = response[41]; + pfi.YtargetPrimaryVelocity = response[42]; + pfi.BOptimumPrimaryVelocity = response[43]; + pfi.TFirstPulseDuration = response[46]; + pfi.TMultiPulseDuration = response[47]; + pfi.FirstPulseLeadTimeAnyRun = response[48]; + pfi.FirstPulseLeadTimeRun3T = response[49]; + pfi.LastPulseLeadTimeAnyRun = response[50]; + pfi.LastPulseLeadTime3T = response[51]; + pfi.LastPulseLeadTime4T = response[52]; + pfi.ErasePulseLeadTimeAny = response[53]; + pfi.ErasePulseLeadTime3T = response[54]; + pfi.ErasePulseLeadTime4T = response[55]; + + break; + + // DVD-R DL and DVD-RW DL + case DiskCategory.DVDR when pfi.PartVersion >= 6: + case DiskCategory.DVDRW when pfi.PartVersion >= 15: + pfi.MaxRecordingSpeed = (DVDRecordingSpeed)response[21]; + pfi.MinRecordingSpeed = (DVDRecordingSpeed)response[22]; + pfi.RecordingSpeed1 = (DVDRecordingSpeed)response[23]; + pfi.RecordingSpeed2 = (DVDRecordingSpeed)response[24]; + pfi.RecordingSpeed3 = (DVDRecordingSpeed)response[25]; + pfi.RecordingSpeed4 = (DVDRecordingSpeed)response[26]; + pfi.RecordingSpeed5 = (DVDRecordingSpeed)response[27]; + pfi.RecordingSpeed6 = (DVDRecordingSpeed)response[28]; + pfi.RecordingSpeed7 = (DVDRecordingSpeed)response[29]; + pfi.Class = response[30]; + pfi.ExtendedVersion = response[31]; + + pfi.CurrentBorderOutSector = + (uint)((response[36] << 24) + (response[37] << 16) + (response[38] << 8) + response[39]); + + pfi.NextBorderInSector = + (uint)((response[40] << 24) + (response[41] << 16) + (response[42] << 8) + response[43]); + + pfi.PreRecordedControlDataInv |= (response[44] & 0x01) == 0x01; + pfi.PreRecordedLeadIn |= (response[44] & 0x02) == 0x02; + pfi.PreRecordedLeadOut |= (response[44] & 0x08) == 0x08; + pfi.ARCharLayer1 = (byte)(response[45] & 0x0F); + pfi.TrackPolarityLayer1 = (byte)((response[45] & 0xF0) >> 4); + + break; + } + + return pfi; + } + + public static string Prettify(PhysicalFormatInformation? pfi) + { + if(pfi == null) return null; + + PhysicalFormatInformation decoded = pfi.Value; + var sb = new StringBuilder(); + + string sizeString = decoded.DiscSize switch + { + DVDSize.Eighty => Localization._80mm, + DVDSize.OneTwenty => Localization._120mm, + _ => string.Format(Localization.unknown_size_identifier_0, decoded.DiscSize) + }; + + switch(decoded.DiskCategory) + { + case DiskCategory.DVDROM: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "DVD-ROM", decoded.PartVersion) + .AppendLine(); + + switch(decoded.DiscSize) + { + case DVDSize.OneTwenty when decoded.PartVersion == 1: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_267); + + break; + case DVDSize.Eighty when decoded.PartVersion == 1: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_268); + + break; + } + + break; + case DiskCategory.DVDRAM: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "DVD-RAM", decoded.PartVersion) + .AppendLine(); + + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_272); + + break; + case 6: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_330); + + break; + } + + break; + case DiskCategory.DVDR: + if(decoded.PartVersion >= 6) + { + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "DVD-R DL", decoded.PartVersion) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "DVD-R", decoded.PartVersion) + .AppendLine(); + } + + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_279); + + break; + case 5: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_359); + + break; + case 6: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_382); + + break; + } + + break; + case DiskCategory.DVDRW: + if(decoded.PartVersion >= 15) + { + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "DVD-RW DL", decoded.PartVersion) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "DVD-RW", decoded.PartVersion) + .AppendLine(); + } + + switch(decoded.PartVersion) + { + case 2: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_338); + + break; + case 3: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_384); + + break; + } + + break; + case DiskCategory.UMD: + if(decoded.DiscSize == DVDSize.OneTwenty) + { + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, + Localization._60mm, + "UMD", + decoded.PartVersion) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, + Localization.invalid_size, + "UMD", + decoded.PartVersion) + .AppendLine(); + } + + switch(decoded.PartVersion) + { + case 0: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_365); + + break; + } + + break; + case DiskCategory.DVDPRW: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "DVD+RW", decoded.PartVersion) + .AppendLine(); + + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_274); + + break; + case 2: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_337); + + break; + case 3: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_371); + + break; + } + + break; + case DiskCategory.DVDPR: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "DVD+R", decoded.PartVersion) + .AppendLine(); + + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_349); + + break; + } + + break; + case DiskCategory.DVDPRWDL: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "DVD+RW DL", decoded.PartVersion) + .AppendLine(); + + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_374); + + break; + } + + break; + case DiskCategory.DVDPRDL: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "DVD+R DL", decoded.PartVersion) + .AppendLine(); + + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine(Localization.Disc_claims_conformation_to_ECMA_364); + + break; + } + + break; + case DiskCategory.Nintendo: + if(decoded.PartVersion == 15) + { + if(decoded.DiscSize == DVDSize.Eighty) + sb.AppendLine(Localization.Disc_is_a_Nintendo_Gamecube_Optical_Disc_GOD); + else if(decoded.DiscSize == DVDSize.OneTwenty) + sb.AppendLine(Localization.Disc_is_a_Nintendo_Wii_Optical_Disc_WOD); + else + goto default; + } + else + goto default; + + break; + case DiskCategory.HDDVDROM: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "HD DVD-ROM", decoded.PartVersion) + .AppendLine(); + + break; + case DiskCategory.HDDVDRAM: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "HD DVD-RAM", decoded.PartVersion) + .AppendLine(); + + break; + case DiskCategory.HDDVDR: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "HD DVD-R", decoded.PartVersion) + .AppendLine(); + + break; + case DiskCategory.HDDVDRW: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, sizeString, "HD DVD-RW", decoded.PartVersion) + .AppendLine(); + + break; + default: + sb.AppendFormat(Localization.Disc_is_a_0_1_version_2, + sizeString, + Localization.unknown_disc_type, + decoded.PartVersion) + .AppendLine(); + + break; + } + + if(decoded.RecordedBookType != decoded.DiskCategory) + { + switch(decoded.RecordedBookType) + { + case DiskCategory.DVDROM: + sb.AppendFormat(Localization.Disc_book_type_is_0, "DVD-ROM").AppendLine(); + + break; + case DiskCategory.DVDRAM: + sb.AppendFormat(Localization.Disc_book_type_is_0, "DVD-RAM").AppendLine(); + + break; + case DiskCategory.DVDR: + if(decoded.PartVersion >= 6) + sb.AppendFormat(Localization.Disc_book_type_is_0, "DVD-R DL").AppendLine(); + else + sb.AppendFormat(Localization.Disc_book_type_is_0, "DVD-R").AppendLine(); + + break; + case DiskCategory.DVDRW: + if(decoded.PartVersion >= 15) + sb.AppendFormat(Localization.Disc_book_type_is_0, "DVD-RW DL").AppendLine(); + else + sb.AppendFormat(Localization.Disc_book_type_is_0, "DVD-RW").AppendLine(); + + break; + case DiskCategory.UMD: + sb.AppendFormat(Localization.Disc_book_type_is_0, "UMD").AppendLine(); + + break; + case DiskCategory.DVDPRW: + sb.AppendFormat(Localization.Disc_book_type_is_0, "DVD+RW").AppendLine(); + + break; + case DiskCategory.DVDPR: + sb.AppendFormat(Localization.Disc_book_type_is_0, "DVD+R").AppendLine(); + + break; + case DiskCategory.DVDPRWDL: + sb.AppendFormat(Localization.Disc_book_type_is_0, "DVD+RW DL").AppendLine(); + + break; + case DiskCategory.DVDPRDL: + sb.AppendFormat(Localization.Disc_book_type_is_0, "DVD+R DL").AppendLine(); + + break; + case DiskCategory.HDDVDROM: + sb.AppendFormat(Localization.Disc_book_type_is_0, "HD DVD-ROM").AppendLine(); + + break; + case DiskCategory.HDDVDRAM: + sb.AppendFormat(Localization.Disc_book_type_is_0, "HD DVD-RAM").AppendLine(); + + break; + case DiskCategory.HDDVDR: + sb.AppendFormat(Localization.Disc_book_type_is_0, "HD DVD-R").AppendLine(); + + break; + case DiskCategory.HDDVDRW: + sb.AppendFormat(Localization.Disc_book_type_is_0, "HD DVD-RW").AppendLine(); + + break; + default: + sb.AppendFormat(Localization.Disc_book_type_is_0, Localization.unit_unknown).AppendLine(); + + break; + } + } + + switch(decoded.MaximumRate) + { + case MaximumRateField.TwoMbps: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_2_52_Mbit_sec); + + break; + case MaximumRateField.FiveMbps: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_5_04_Mbit_sec); + + break; + case MaximumRateField.TenMbps: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_10_08_Mbit_sec); + + break; + case MaximumRateField.TwentyMbps: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_20_16_Mbit_sec); + + break; + case MaximumRateField.ThirtyMbps: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_30_24_Mbit_sec); + + break; + case MaximumRateField.Unspecified: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_unspecified); + + break; + default: + sb.AppendFormat(Localization.Disc_maximum_transfer_rate_is_specified_by_unknown_key_0, + decoded.MaximumRate) + .AppendLine(); + + break; + } + + sb.AppendFormat(Localization.Disc_has_0_layers, decoded.Layers + 1).AppendLine(); + + switch(decoded.TrackPath) + { + case true when decoded.Layers == 1: + sb.AppendLine(Localization.Layers_are_in_parallel_track_path); + + break; + case false when decoded.Layers == 1: + sb.AppendLine(Localization.Layers_are_in_opposite_track_path); + + break; + } + + switch(decoded.LinearDensity) + { + case LinearDensityField.TwoSix: + sb.AppendLine(Localization.Pitch_size_is_0_267_μm_bit); + + break; + case LinearDensityField.TwoNine: + sb.AppendLine(Localization.Pitch_size_is_0_147_μm_bit); + + break; + case LinearDensityField.FourZero: + sb.AppendLine(Localization.Pitch_size_is_between_0_409_μm_bit_and_0_435_μm_bit); + + break; + case LinearDensityField.TwoEight: + sb.AppendLine(Localization.Pitch_size_is_between_0_140_μm_bit_and_0_148_μm_bit); + + break; + case LinearDensityField.OneFive: + sb.AppendLine(Localization.Pitch_size_is_0_153_μm_bit); + + break; + case LinearDensityField.OneThree: + sb.AppendLine(Localization.Pitch_size_is_between_0_130_μm_bit_and_0_140_μm_bit); + + break; + case LinearDensityField.ThreeFive: + sb.AppendLine(Localization.Pitch_size_is_0_353_μm_bit); + + break; + default: + sb.AppendFormat(Localization.Unknown_pitch_size_key_0, decoded.LinearDensity).AppendLine(); + + break; + } + + switch(decoded.TrackDensity) + { + case TrackDensityField.Seven: + sb.AppendLine(Localization.Track_size_is_0_74_μm); + + break; + case TrackDensityField.Eight: + sb.AppendLine(Localization.Track_size_is_0_80_μm); + + break; + case TrackDensityField.Six: + sb.AppendLine(Localization.Track_size_is_0_615_μm); + + break; + case TrackDensityField.Four: + sb.AppendLine(Localization.Track_size_is_0_40_μm); + + break; + case TrackDensityField.Three: + sb.AppendLine(Localization.Track_size_is_0_34_μm); + + break; + default: + sb.AppendFormat(Localization.Unknown_track_size_key__0_, decoded.LinearDensity).AppendLine(); + + break; + } + + if(decoded.DataAreaStartPSN > 0) + { + if(decoded.DataAreaEndPSN > 0) + { + sb.AppendFormat(Localization.Data_area_starts_at_PSN_0, decoded.DataAreaStartPSN).AppendLine(); + sb.AppendFormat(Localization.Data_area_ends_at_PSN_0, decoded.DataAreaEndPSN).AppendLine(); + + if(decoded is { Layers: 1, TrackPath: false }) + sb.AppendFormat(Localization.Layer_zero_ends_at_PSN_0, decoded.Layer0EndPSN).AppendLine(); + } + else + sb.AppendLine(Localization.Disc_is_empty); + } + else + sb.AppendLine(Localization.Disc_is_empty); + + if(decoded.BCA) sb.AppendLine(Localization.Disc_has_a_BCA); + + switch(decoded.DiskCategory) + { + case DiskCategory.UMD: + sb.AppendFormat(Localization.Media_attribute_is_0, decoded.MediaAttribute).AppendLine(); + + break; + case DiskCategory.DVDRAM: + switch(decoded.DiscType) + { + case DVDRAMDiscType.Cased: + sb.AppendLine(Localization.Disc_shall_be_recorded_with_a_case); + + break; + case DVDRAMDiscType.Uncased: + sb.AppendLine(Localization.Disc_can_be_recorded_with_or_without_a_case); + + break; + default: + sb.AppendFormat(Localization.Unknown_DVD_RAM_case_type_key_0, decoded.DiscType).AppendLine(); + + break; + } + + if(decoded.PartVersion == 6) + { + sb.AppendFormat(Localization.Disc_manufacturer_is_0, + ManufacturerFromDVDRAM(decoded.DiskManufacturer)) + .AppendLine(); + + sb.AppendFormat(Localization.Disc_manufacturer_supplementary_information_is_0, + decoded.DiskManufacturerSupplementary) + .AppendLine(); + } + + break; + case DiskCategory.DVDR when decoded.PartVersion < 6: + case DiskCategory.DVDRW when decoded.PartVersion < 15: + sb.AppendFormat(Localization.Current_Border_Out_first_sector_is_PSN_0, decoded.CurrentBorderOutSector) + .AppendLine(); + + sb.AppendFormat(Localization.Next_Border_In_first_sector_is_PSN_0, decoded.NextBorderInSector) + .AppendLine(); + + break; + case DiskCategory.DVDPR: + case DiskCategory.DVDPRW: + case DiskCategory.DVDPRDL: + case DiskCategory.DVDPRWDL: + if(decoded.VCPS) sb.AppendLine(Localization.Disc_contains_extended_information_for_VCPS); + + sb.AppendFormat(Localization.Disc_application_code_0, decoded.ApplicationCode).AppendLine(); + + sb.AppendFormat(Localization.Disc_manufacturer_is_0, + ManufacturerFromDVDPlusID(decoded.DiskManufacturerID)) + .AppendLine(); + + sb.AppendFormat(Localization.Disc_media_type_is_0, decoded.MediaTypeID).AppendLine(); + sb.AppendFormat(Localization.Disc_product_revision_is_0, decoded.ProductRevision).AppendLine(); + + break; + } + + if((decoded.DiskCategory != DiskCategory.DVDR || decoded.PartVersion < 6) && + (decoded.DiskCategory != DiskCategory.DVDRW || decoded.PartVersion < 15)) + return sb.ToString(); + + sb.AppendFormat(Localization.Current_RMD_in_extra_Border_zone_starts_at_PSN_0, decoded.CurrentRMDExtraBorderPSN) + .AppendLine(); + + sb.AppendFormat(Localization.PFI_in_extra_Border_zone_starts_at_PSN_0, decoded.PFIExtraBorderPSN).AppendLine(); + + if(!decoded.PreRecordedControlDataInv) sb.AppendLine(Localization.Control_Data_Zone_is_pre_recorded); + + if(decoded.PreRecordedLeadIn) sb.AppendLine(Localization.Lead_In_is_pre_recorded); + + if(decoded.PreRecordedLeadOut) sb.AppendLine(Localization.Lead_Out_is_pre_recorded); + + return sb.ToString(); + } + + public static string Prettify(byte[] response, MediaType mediaType) => Prettify(Decode(response, mediaType)); + +#pragma warning disable PH2077 // Waiting to get more information on the actual values + public static string ManufacturerFromDVDRAM(string manufacturerId) => manufacturerId switch + { + _ => + ManufacturerFromDVDPlusID(manufacturerId) + }; +#pragma warning restore PH2077 + + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public static string ManufacturerFromDVDPlusID(string manufacturerId) + { + string manufacturer = manufacturerId switch + { + "CMC MAG" => "CMC Magnetics Corporation", + "INFOME" => "InfoMedia Inc.", + "RITEK" => "Ritek Co.", + "RICOHJPN" => "Ricoh Company, Ltd.", + "ISSM" => "Info Source Digital Media (Zhongshan) Co., Ltd.", + "LD" => "Lead Data Inc.", + "MAXELL" => "Hitachi Maxell, Ltd.", + "MCC" => "Mitsubishi Kagaku Media Co., LTD.", + "PRODISC" => "Prodisc Technology Inc.", + "Philips" or "PHILIPS" => "Philips Components", + "YUDEN000" => "Taiyo Yuden Company Ltd.", + "AML" => "Avic Umedisc HK Ltd.", + "DAXON" => "Daxon Technology Inc.", + "FTI" => "Falcon Technologies International L.L.C.", + "GSC503" => "Gigastore Corporation", + "MBIPG101" => "Moser Baer India Ltd.", + "OPTODISC" => "OptoDisc Ltd.", + "SONY" => "Sony Corporation", + "TDK" => "TDK Corporation", + "SENTINEL" => "Sentinel B.V.", + "BeAll000" => "BeALL Developers, Inc.", + "MPOMEDIA" => "MPO Disque Compact", + "IMC JPN" => "Intermedia Co., Ltd.", + "INFODISC" => "InfoDisc Technology Co., Ltd.", + "WFKA11" => "Wealth Fair Investment Inc.", + "MAM" => "Manufacturing Advanced Media Europe", + "VDSPMSAB" => "Interaxia Digital Storage Materials AG", + "KIC00000" => "Advanced Media Corporation", + "MJC" => "Megan Media Holdings Berhad", + "MUST" => "Must Technology Co., Ltd.", + "IS02" => "Infosmart Technology Ltd.", + "DDDessau" => "Digital Disc Dessau GmbH", + "SKYMEDIA" => "Sky Media Manufacturing S.A.", + "MICRON" => "Eastgate Technology Ltd.", + "VIVA" => "Viva Optical Disc Manufacturing Ltd.", + "EMDPZ3" => "E-TOP Mediatek Inc.", + "LGEP16" => "LG Electronics Inc.", + "POS" => "POSTECH Corporation", + "Dvsn+160" => "Digital Storage Technology Co., Ltd.", + "ODMS" => "VDL Optical Disc Manufacturing Systems", + _ => "" + }; + + return manufacturer != "" ? $"{manufacturer} (\"{manufacturerId}\")" : $"\"{manufacturerId}\""; + } + +#region Nested type: PhysicalFormatInformation + + public struct PhysicalFormatInformation + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + +#region PFI common to all + + /// Byte 4, bits 7 to 4 Disk category field + public DiskCategory DiskCategory; + /// Byte 4, bits 3 to 0 Media version + public byte PartVersion; + /// Byte 5, bits 7 to 4 120mm if 0, 80mm if 1. If UMD (60mm) 0 also. Reserved rest of values + public DVDSize DiscSize; + /// Byte 5, bits 3 to 0 Maximum data rate + public MaximumRateField MaximumRate; + /// Byte 6, bit 7 Reserved + public bool Reserved3; + /// Byte 6, bits 6 to 5 Number of layers + public byte Layers; + /// Byte 6, bit 4 Track path + public bool TrackPath; + /// Byte 6, bits 3 to 0 Layer type + public LayerTypeFieldMask LayerType; + /// Byte 7, bits 7 to 4 Linear density field + public LinearDensityField LinearDensity; + /// Byte 7, bits 3 to 0 Track density field + public TrackDensityField TrackDensity; + /// Bytes 8 to 11 PSN where Data Area starts + public uint DataAreaStartPSN; + /// Bytes 12 to 15 PSN where Data Area ends + public uint DataAreaEndPSN; + /// Bytes 16 to 19 PSN where Data Area ends in Layer 0 + public uint Layer0EndPSN; + /// + /// Byte 20, bit 7 True if BCA exists. GC/Wii discs do not have this bit set, but there is a BCA, making it + /// unreadable in normal DVD drives + /// + public bool BCA; + /// Byte 20, bits 6 to 0 Reserved + public byte Reserved4; + +#endregion PFI common to all + +#region UMD PFI + + /// Bytes 21 to 22 UMD only, media attribute, application-defined, part of media specific in rest of discs + public ushort MediaAttribute; + +#endregion UMD PFI + +#region DVD-RAM PFI + + /// Byte 36 Disc type, respecting case recordability + public DVDRAMDiscType DiscType; + +#endregion DVD-RAM PFI + +#region DVD-RAM PFI, Version 0001b + + /// Byte 52 Byte 504 in Version 0110b Linear velocity, in tenths of m/s + public byte Velocity; + /// Byte 53 Byte 505 in Version 0110b Read power on disk surface, tenths of mW + public byte ReadPower; + /// Byte 54 Byte 507 in Version 0110b Peak power on disk surface for recording land tracks + public byte PeakPower; + /// Byte 55 Bias power on disk surface for recording land tracks + public byte BiasPower; + /// Byte 56 First pulse starting time for recording on land tracks, ns + public byte FirstPulseStart; + /// Byte 57 Byte 515 in Version 0110b First pulse ending time for recording on land tracks + public byte FirstPulseEnd; + /// Byte 58 Byte 518 in Version 0110b Multiple-pulse duration time for recording on land tracks + public byte MultiplePulseDuration; + /// Byte 59 Byte 519 in Version 0110b Last pulse starting time for recording on land tracks + public byte LastPulseStart; + /// Byte 60 Las pulse ending time for recording on land tracks + public byte LastPulseEnd; + /// Byte 61 Bias power duration for recording on land tracks + public byte BiasPowerDuration; + /// Byte 62 Byte 511 on Version 0110b Peak power for recording on groove tracks + public byte PeakPowerGroove; + /// Byte 63 Bias power for recording on groove tracks + public byte BiasPowerGroove; + /// Byte 64 First pulse starting time on groove tracks + public byte FirstPulseStartGroove; + /// Byte 65 First pulse ending time on groove tracks + public byte FirstPulseEndGroove; + /// Byte 66 Multiple-pulse duration time on groove tracks + public byte MultiplePulseDurationGroove; + /// Byte 67 Last pulse starting time on groove tracks + public byte LastPulseStartGroove; + /// Byte 68 Last pulse ending time on groove tracks + public byte LastPulseEndGroove; + /// Byte 69 Bias power duration for recording on groove tracks + public byte BiasPowerDurationGroove; + +#endregion DVD-RAM PFI, Version 0001b + +#region DVD-R PFI, DVD-RW PFI + + /// Bytes 36 to 39 Sector number of the first sector of the current Border Out + public uint CurrentBorderOutSector; + /// Bytes 40 to 43 Sector number of the first sector of the next Border In + public uint NextBorderInSector; + +#endregion DVD-R PFI, DVD-RW PFI + +#region DVD+RW PFI + + /// Byte 36 Linear velocities 0 = CLV from 4,90 m/s to 6,25 m/s 1 = CAV from 3,02 m/s to 7,35 m/s + public byte RecordingVelocity; + /// Byte 37 Maximum read power in milliwatts at maximum velocity mW = 20 * (value - 1) + public byte ReadPowerMaxVelocity; + /// Byte 38 Indicative value of Ptarget in mW at maximum velocity + public byte PIndMaxVelocity; + /// Byte 39 Peak power multiplication factor at maximum velocity + public byte PMaxVelocity; + /// Byte 40 Bias1/write power ration at maximum velocity + public byte E1MaxVelocity; + /// Byte 41 Bias2/write power ration at maximum velocity + public byte E2MaxVelocity; + /// Byte 42 Target value for γ, γtarget at the maximum velocity + public byte YTargetMaxVelocity; + /// Byte 43 Maximum read power in milliwatts at reference velocity (4,90 m/s) mW = 20 * (value - 1) + public byte ReadPowerRefVelocity; + /// Byte 44 Indicative value of Ptarget in mW at reference velocity (4,90 m/s) + public byte PIndRefVelocity; + /// Byte 45 Peak power multiplication factor at reference velocity (4,90 m/s) + public byte PRefVelocity; + /// Byte 46 Bias1/write power ration at reference velocity (4,90 m/s) + public byte E1RefVelocity; + /// Byte 47 Bias2/write power ration at reference velocity (4,90 m/s) + public byte E2RefVelocity; + /// Byte 48 Target value for γ, γtarget at the reference velocity (4,90 m/s) + public byte YTargetRefVelocity; + /// Byte 49 Maximum read power in milliwatts at minimum velocity mW = 20 * (value - 1) + public byte ReadPowerMinVelocity; + /// Byte 50 Indicative value of Ptarget in mW at minimum velocity + public byte PIndMinVelocity; + /// Byte 51 Peak power multiplication factor at minimum velocity + public byte PMinVelocity; + /// Byte 52 Bias1/write power ration at minimum velocity + public byte E1MinVelocity; + /// Byte 53 Bias2/write power ration at minimum velocity + public byte E2MinVelocity; + /// Byte 54 Target value for γ, γtarget at the minimum velocity + public byte YTargetMinVelocity; + +#endregion DVD+RW PFI + +#region DVD-RAM PFI, version 0110b + + /// Byte 506, bit 7 Mode of adaptative write pulse control + public bool AdaptativeWritePulseControlFlag; + /// Byte 508 Bias power 1 on disk surface for recording land tracks + public byte BiasPower1; + /// Byte 509 Bias power 2 on disk surface for recording land tracks + public byte BiasPower2; + /// Byte 510 Bias power 3 on disk surface for recording land tracks + public byte BiasPower3; + /// Byte 512 Bias power 1 on disk surface for recording groove tracks + public byte BiasPower1Groove; + /// Byte 513 Bias power 2 on disk surface for recording groove tracks + public byte BiasPower2Groove; + /// Byte 514 Bias power 3 on disk surface for recording groove tracks + public byte BiasPower3Groove; + /// Byte 516 First pulse duration + public byte FirstPulseDuration; + /// Byte 520 Bias power 2 duration on land tracks at Velocity 1 + public byte BiasPower2Duration; + /// Byte 521 First pulse start time, at Mark 3T and Leading Space 3T + public byte FirstPulseStart3TSpace3T; + /// Byte 522 First pulse start time, at Mark 4T and Leading Space 3T + public byte FirstPulseStart4TSpace3T; + /// Byte 523 First pulse start time, at Mark 5T and Leading Space 3T + public byte FirstPulseStart5TSpace3T; + /// Byte 524 First pulse start time, at Mark >5T and Leading Space 3T + public byte FirstPulseStartSpace3T; + /// Byte 525 First pulse start time, at Mark 3T and Leading Space 4T + public byte FirstPulseStart3TSpace4T; + /// Byte 526 First pulse start time, at Mark 4T and Leading Space 4T + public byte FirstPulseStart4TSpace4T; + /// Byte 527 First pulse start time, at Mark 5T and Leading Space 4T + public byte FirstPulseStart5TSpace4T; + /// Byte 528 First pulse start time, at Mark >5T and Leading Space 4T + public byte FirstPulseStartSpace4T; + /// Byte 529 First pulse start time, at Mark 3T and Leading Space 5T + public byte FirstPulseStart3TSpace5T; + /// Byte 530 First pulse start time, at Mark 4T and Leading Space 5T + public byte FirstPulseStart4TSpace5T; + /// Byte 531 First pulse start time, at Mark 5T and Leading Space 5T + public byte FirstPulseStart5TSpace5T; + /// Byte 532 First pulse start time, at Mark >5T and Leading Space 5T + public byte FirstPulseStartSpace5T; + /// Byte 533 First pulse start time, at Mark 3T and Leading Space >5T + public byte FirstPulseStart3TSpace; + /// Byte 534 First pulse start time, at Mark 4T and Leading Space >5T + public byte FirstPulseStart4TSpace; + /// Byte 535 First pulse start time, at Mark 5T and Leading Space >5T + public byte FirstPulseStart5TSpace; + /// Byte 536 First pulse start time, at Mark >5T and Leading Space >5T + public byte FirstPulseStartSpace; + /// Byte 537 First pulse start time, at Mark 3T and Trailing Space 3T + public byte FirstPulse3TStartTSpace3T; + /// Byte 538 First pulse start time, at Mark 4T and Trailing Space 3T + public byte FirstPulse4TStartTSpace3T; + /// Byte 539 First pulse start time, at Mark 5T and Trailing Space 3T + public byte FirstPulse5TStartTSpace3T; + /// Byte 540 First pulse start time, at Mark >5T and Trailing Space 3T + public byte FirstPulseStartTSpace3T; + /// Byte 541 First pulse start time, at Mark 3T and Trailing Space 4T + public byte FirstPulse3TStartTSpace4T; + /// Byte 542 First pulse start time, at Mark 4T and Trailing Space 4T + public byte FirstPulse4TStartTSpace4T; + /// Byte 543 First pulse start time, at Mark 5T and Trailing Space 4T + public byte FirstPulse5TStartTSpace4T; + /// Byte 544 First pulse start time, at Mark >5T and Trailing Space 4T + public byte FirstPulseStartTSpace4T; + /// Byte 545 First pulse start time, at Mark 3T and Trailing Space 5T + public byte FirstPulse3TStartTSpace5T; + /// Byte 546 First pulse start time, at Mark 4T and Trailing Space 5T + public byte FirstPulse4TStartTSpace5T; + /// Byte 547 First pulse start time, at Mark 5T and Trailing Space 5T + public byte FirstPulse5TStartTSpace5T; + /// Byte 548 First pulse start time, at Mark >5T and Trailing Space 5T + public byte FirstPulseStartTSpace5T; + /// Byte 549 First pulse start time, at Mark 3T and Trailing Space >5T + public byte FirstPulse3TStartTSpace; + /// Byte 550 First pulse start time, at Mark 4T and Trailing Space >5T + public byte FirstPulse4TStartTSpace; + /// Byte 551 First pulse start time, at Mark 5T and Trailing Space >5T + public byte FirstPulse5TStartTSpace; + /// Byte 552 First pulse start time, at Mark >5T and Trailing Space >5T + public byte FirstPulseStartTSpace; + /// Bytes 553 to 600 Disk manufacturer's name, space-padded + public string DiskManufacturer; + /// Bytes 601 to 616 Disk manufacturer's supplementary information + public string DiskManufacturerSupplementary; + /// Bytes 617 to 627 Write power control parameters + public byte[] WritePowerControlParams; + /// Byte 619 Ratio of peak power for land tracks to threshold peak power for land tracks + public byte PowerRatioLandThreshold; + /// Byte 620 Target asymmetry + public byte TargetAsymmetry; + /// Byte 621 Temporary peak power + public byte TemporaryPeakPower; + /// Byte 622 Temporary bias power 1 + public byte TemporaryBiasPower1; + /// Byte 623 Temporary bias power 2 + public byte TemporaryBiasPower2; + /// Byte 624 Temporary bias power 3 + public byte TemporaryBiasPower3; + /// Byte 625 Ratio of peak power for groove tracks to threshold peak power for groove tracks + public byte PowerRatioGrooveThreshold; + /// Byte 626 Ratio of peak power for land tracks to threshold 6T peak power for land tracks + public byte PowerRatioLandThreshold6T; + /// Byte 627 Ratio of peak power for groove tracks to threshold 6T peak power for groove tracks + public byte PowerRatioGrooveThreshold6T; + +#endregion DVD-RAM PFI, version 0110b + +#region DVD+RW PFI, DVD+R PFI, DVD+R DL PFI and DVD+RW DL PFI + + /// Byte 20, bit 6 If set indicates data zone contains extended information for VCPS + public bool VCPS; + /// Byte 21 Indicates restricted usage disk + public byte ApplicationCode; + /// Byte 22 Bitmap of extended information block presence + public byte ExtendedInformation; + /// Bytes 23 to 30 Disk manufacturer ID, null-padded + public string DiskManufacturerID; + /// Bytes 31 to 33 Media type ID, null-padded + public string MediaTypeID; + /// Byte 34 Product revision number + public byte ProductRevision; + /// Byte 35 Indicates how many bytes, up to 63, are used in ADIP's PFI + public byte PFIUsedInADIP; + +#endregion DVD+RW PFI, DVD+R PFI, DVD+R DL PFI and DVD+RW DL PFI + +#region DVD+RW PFI, version 0010b + + /// Byte 55 Ttop first pulse duration + public byte TopFirstPulseDuration; + /// Byte 56 Tmp multi pulse duration + public byte MultiPulseDuration; + /// Byte 57 dTtop first pulse lead time + public byte FirstPulseLeadTime; + /// Byte 58 dTera erase lead time at reference velocity + public byte EraseLeadTimeRefVelocity; + /// Byte 59 dTera erase lead time at upper velocity + public byte EraseLeadTimeUppVelocity; + +#endregion DVD+RW PFI, version 0010b + +#region DVD+R PFI version 0001b and DVD+R DL PFI version 0001b + + /// Byte 36 Primary recording velocity for the basic write strategy + public byte PrimaryVelocity; + /// Byte 37 Upper recording velocity for the basic write strategy + public byte UpperVelocity; + /// Byte 38 Wavelength λIND + public byte Wavelength; + /// Byte 39 Normalized write power dependency on wavelength (dP/dλ)/(PIND/λIND) + public byte NormalizedPowerDependency; + /// Byte 40 Maximum read power at primary velocity + public byte MaximumPowerAtPrimaryVelocity; + /// Byte 41 Pind at primary velocity + public byte PindAtPrimaryVelocity; + /// Byte 42 βtarget at primary velocity + public byte BtargetAtPrimaryVelocity; + /// Byte 43 Maximum read power at upper velocity + public byte MaximumPowerAtUpperVelocity; + /// Byte 44 Pind at primary velocity + public byte PindAtUpperVelocity; + /// Byte 45 βtarget at upper velocity + public byte BtargetAtUpperVelocity; + /// Byte 46 Ttop (≥4T) first pulse duration for cm∗ ≥4T at Primary velocity + public byte FirstPulseDuration4TPrimaryVelocity; + /// Byte 47 Ttop (=3T) first pulse duration for cm∗ =3T at Primary velocity + public byte FirstPulseDuration3TPrimaryVelocity; + /// Byte 48 Tmp multi pulse duration at Primary velocity + public byte MultiPulseDurationPrimaryVelocity; + /// Byte 49 Tlp last pulse duration at Primary velocity + public byte LastPulseDurationPrimaryVelocity; + /// Byte 50 dTtop (≥4T) first pulse lead time for cm∗ ≥4T at Primary velocity + public byte FirstPulseLeadTime4TPrimaryVelocity; + /// Byte 51 dTtop (=3T) first pulse lead time for cm∗ =3T at Primary velocity + public byte FirstPulseLeadTime3TPrimaryVelocity; + /// Byte 52 dTle first pulse leading edge shift for ps∗ =3T at Primary velocity + public byte FirstPulseLeadingEdgePrimaryVelocity; + /// Byte 53 Ttop (≥4T) first pulse duration for cm∗ ≥4T at Upper velocity + public byte FirstPulseDuration4TUpperVelocity; + /// Byte 54 Ttop (=3T) first pulse duration for cm∗ =3T at Upper velocity + public byte FirstPulseDuration3TUpperVelocity; + /// Byte 55 Tmp multi pulse duration at Upper velocity + public byte MultiPulseDurationUpperVelocity; + /// Byte 56 Tlp last pulse duration at Upper velocity + public byte LastPulseDurationUpperVelocity; + /// Byte 57 dTtop (≥4T) first pulse lead time for cm∗ ≥4T at Upper velocity + public byte FirstPulseLeadTime4TUpperVelocity; + /// Byte 58 dTtop (=3T) first pulse lead time for cm∗ =3T at Upper velocity + public byte FirstPulseLeadTime3TUpperVelocity; + /// Byte 59 dTle first pulse leading edge shift for ps∗ =3T at Upper velocity + public byte FirstPulseLeadingEdgeUpperVelocity; + +#endregion DVD+R PFI version 0001b and DVD+R DL PFI version 0001b + +#region DVD+R DL PFI version 0001b + + /// Byte 34, bits 7 to 6 + public DVDLayerStructure LayerStructure; + +#endregion DVD+R DL PFI version 0001b + +#region DVD+RW DL PFI + + /// Byte 36 Primary recording velocity for the basic write strategy + public byte BasicPrimaryVelocity; + /// Byte 37 Maximum read power at Primary velocity + public byte MaxReadPowerPrimaryVelocity; + /// Byte 38 PIND at Primary velocity + public byte PindPrimaryVelocity; + /// Byte 39 ρ at Primary velocity + public byte PPrimaryVelocity; + /// Byte 40 ε1 at Primary velocity + public byte E1PrimaryVelocity; + /// Byte 41 ε2 at Primary velocity + public byte E2PrimaryVelocity; + /// Byte 42 γtarget at Primary velocity + public byte YtargetPrimaryVelocity; + /// Byte 43 β optimum at Primary velocity + public byte BOptimumPrimaryVelocity; + /// Byte 46 Ttop first pulse duration + public byte TFirstPulseDuration; + /// Byte 47 Tmp multi pulse duration + public byte TMultiPulseDuration; + /// Byte 48 dTtop first pulse lead/lag time for any runlength ≥ 4T + public byte FirstPulseLeadTimeAnyRun; + /// Byte 49 dTtop,3 first pulse lead/lag time for runlengths = 3T + public byte FirstPulseLeadTimeRun3T; + /// Byte 50 dTlp last pulse lead/lag time for any runlength ≥ 5T + public byte LastPulseLeadTimeAnyRun; + /// Byte 51 dTlp,3 last pulse lead/lag time for runlengths = 3T + public byte LastPulseLeadTime3T; + /// Byte 52 dTlp,4 last pulse lead/lag time for runlengths = 4T + public byte LastPulseLeadTime4T; + /// Byte 53 dTera erase lead/lag time when preceding mark length ≥ 5T + public byte ErasePulseLeadTimeAny; + /// Byte 54 dTera,3 erase lead/lag time when preceding mark length = 3T + public byte ErasePulseLeadTime3T; + /// Byte 55 dTera,4 erase lead/lag time when preceding mark length = 4T + public byte ErasePulseLeadTime4T; + +#endregion DVD+RW DL PFI + +#region DVD-R DL PFI and DVD-RW DL PFI + + /// Byte 21 Maximum recording speed + public DVDRecordingSpeed MaxRecordingSpeed; + /// Byte 22 Minimum recording speed + public DVDRecordingSpeed MinRecordingSpeed; + /// Byte 23 Another recording speed + public DVDRecordingSpeed RecordingSpeed1; + /// Byte 24 Another recording speed + public DVDRecordingSpeed RecordingSpeed2; + /// Byte 25 Another recording speed + public DVDRecordingSpeed RecordingSpeed3; + /// Byte 26 Another recording speed + public DVDRecordingSpeed RecordingSpeed4; + /// Byte 27 Another recording speed + public DVDRecordingSpeed RecordingSpeed5; + /// Byte 28 Another recording speed + public DVDRecordingSpeed RecordingSpeed6; + /// Byte 29 Another recording speed + public DVDRecordingSpeed RecordingSpeed7; + /// Byte 30 Class + public byte Class; + /// Byte 31 Extended version. 0x30 = ECMA-382, 0x20 = ECMA-384 + public byte ExtendedVersion; + /// Byte 36 Start sector number of current RMD in Extra Border Zone + public uint CurrentRMDExtraBorderPSN; + /// Byte 40 Start sector number of Physical Format Information blocks in Extra Border Zone + public uint PFIExtraBorderPSN; + /// Byte 44, bit 0 If NOT set, Control Data Zone is pre-recorded + public bool PreRecordedControlDataInv; + /// Byte 44 bit 1 Lead-in Zone is pre-recorded + public bool PreRecordedLeadIn; + /// Byte 44 bit 3 Lead-out Zone is pre-recorded + public bool PreRecordedLeadOut; + /// Byte 45 bits 0 to 3 AR characteristic of LPP on Layer 1 + public byte ARCharLayer1; + /// Byte 45 bits 4 to 7 Tracking polarity on Layer 1 + public byte TrackPolarityLayer1; + +#endregion DVD-R DL PFI and DVD-RW DL PFI + + public DiskCategory RecordedBookType; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/PRI.cs b/Aaru.Decoders/DVD/PRI.cs new file mode 100644 index 000000000..0d8ccf4ef --- /dev/null +++ b/Aaru.Decoders/DVD/PRI.cs @@ -0,0 +1,452 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PRI.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD pre-recorded information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class PRI +{ + public static PreRecordedInformation? Decode(byte[] response) + { + if(response == null) return null; + + if(response.Length < 67) return null; + + var pri = new PreRecordedInformation + { + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + FieldId1 = response[4], + FieldId2 = response[12], + FieldId3 = response[20], + FieldId4 = response[28], + FieldId5 = response[36] + }; + + if(pri.FieldId1 != 1 || pri.FieldId2 != 2 || pri.FieldId3 != 3 || pri.FieldId4 != 4 || pri.FieldId5 != 5) + return null; + + pri.DiscApplicationCode = response[5]; + pri.DiscPhysicalCode = response[6]; + pri.LastAddressOfDataRecordableArea = (uint)((response[7] << 16) + (response[8] << 8) + response[9]); + pri.PartVersion = (byte)(response[10] >> 4); + pri.ExtensionCode = (byte)(response[10] & 0xF); + pri.Reserved3 = response[11]; + pri.OPCSuggestedCode = response[13]; + pri.WaveLengthCode = response[14]; + + pri.WriteStrategyCode = + (uint)((response[15] << 24) + (response[16] << 16) + (response[17] << 8) + response[18]); + + pri.Reserved4 = response[19]; + pri.ManufacturerId1 = new byte[6]; + pri.Reserved5 = response[27]; + pri.ManufacturerId2 = new byte[6]; + pri.Reserved6 = response[35]; + pri.ManufacturerId3 = new byte[6]; + pri.Reserved7 = response[43]; + pri.Reserved8 = new byte[response.Length - 44]; + + Array.Copy(response, 21, pri.ManufacturerId1, 0, 6); + Array.Copy(response, 29, pri.ManufacturerId2, 0, 6); + Array.Copy(response, 37, pri.ManufacturerId3, 0, 6); + Array.Copy(response, 44, pri.Reserved8, 0, pri.Reserved8.Length); + + var tmp = new byte[18]; + + Array.Copy(response, 21, tmp, 0, 6); + Array.Copy(response, 29, tmp, 6, 6); + + // If RW or has part version or has extension code, 3rd manufacturer ID is a write strategy code + if((pri.DiscPhysicalCode & 0x2) > 0 || pri.PartVersion > 0 || pri.ExtensionCode > 0) + { + pri.WriteStrategyCode2 = + (uint)((response[37] << 24) + (response[38] << 16) + (response[39] << 8) + response[40]); + } + else + Array.Copy(response, 37, tmp, 12, 6); + + pri.ManufacturerId = StringHandlers.CToString(tmp, Encoding.ASCII).Trim(); + + return pri; + } + + public static string Prettify(PreRecordedInformation? pri) + { + if(pri == null) return null; + + PreRecordedInformation decoded = pri.Value; + var sb = new StringBuilder(); + + if((decoded.DiscApplicationCode & 0x40) > 0) + { + sb.AppendLine(Localization.Disc_for_unrestricted_use); + + if((decoded.DiscApplicationCode & 0x3F) > 0) + { + sb.AppendFormat(Localization.Invalid_purpose_field_with_value_0, decoded.DiscApplicationCode & 0x3F) + .AppendLine(); + } + else + sb.AppendLine(Localization.Consumer_purpose_disc_for_use_in_consumer_purpose_drives); + } + else + { + sb.AppendLine(Localization.Disc_for_restricted_use); + + if((decoded.DiscApplicationCode & 0x3F) > 0) + { + sb.AppendFormat(Localization.Disc_for_use_in_special_drives_according_with_purpose_value_0, + decoded.DiscApplicationCode & 0x3F) + .AppendLine(); + } + else + sb.AppendLine(Localization.General_purpose_disc_for_use_in_general_purpose_drives); + } + + sb.AppendLine((decoded.DiscPhysicalCode & 0x80) > 0 + ? Localization.Disc_track_pitch_is_0_74_μm + : Localization.Unknown_track_pitch); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x40) > 0 + ? Localization.Reference_velocity_is_3_49_m_s + : Localization.Unknown_reference_velocity); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x20) > 0 + ? Localization.Disc_has_80mm_diameter + : Localization.Disc_has_120mm_diameter); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x10) > 0 + ? Localization.Disc_reflectivity_is_between_18_and_30 + : Localization.Disc_reflectivity_is_between_45_and_85); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x04) > 0 + ? Localization.Dye_is_organic + : Localization.Dye_is_phase_change); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x02) > 0 + ? Localization.Disc_is_RW_rewritable + : Localization.Disc_is_R_recordable); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x01) > 0 + ? Localization.Wavelength_is_650nm + : Localization.Unknown_wavelength); + + sb.AppendFormat(Localization.Last_writable_ECC_block_address_0_X6_, decoded.LastAddressOfDataRecordableArea) + .AppendLine(); + + if(decoded.PartVersion > 0) sb.AppendFormat(Localization.Part_version_0, decoded.PartVersion).AppendLine(); + + bool rw = (decoded.DiscPhysicalCode & 0x02) > 0; + + if(rw) + { + if((decoded.OPCSuggestedCode & 0xF) > 0) + { + double recordingPower = (decoded.OPCSuggestedCode & 0xF) switch + { + 1 => 7.0, + 2 => 7.5, + 3 => 8.0, + 4 => 8.5, + 5 => 9.0, + 6 => 9.5, + 7 => 10.0, + 8 => 10.5, + 9 => 11.0, + 10 => 11.5, + 11 => 12.0, + 12 => 12.5, + 13 => 13.0, + 14 => 13.5, + 15 => 14.0, + _ => 0 + }; + + sb.AppendFormat(Localization.Recommended_recording_power_is_0_mW, recordingPower).AppendLine(); + } + else + sb.AppendLine(Localization.Recording_power_is_not_specified); + + if((decoded.WaveLengthCode & 0xF) > 0) + { + double erasingPower = (decoded.WaveLengthCode & 0xF) switch + { + 1 => 0.38, + 2 => 0.40, + 3 => 0.42, + 4 => 0.44, + 5 => 0.46, + 6 => 0.48, + 7 => 0.50, + 8 => 0.52, + 9 => 0.54, + 10 => 0.56, + 11 => 0.58, + 12 => 0.60, + 13 => 0.62, + 14 => 0.64, + 15 => 0.66, + _ => 0 + }; + + sb.AppendFormat(Localization.Recommended_erasing_power_ratio_is_0, erasingPower).AppendLine(); + } + else + sb.AppendLine(Localization.Erasing_power_ratio_is_not_specified); + } + else + { + if((decoded.OPCSuggestedCode & 0xF) > 0) + { + double recordingPower = (decoded.OPCSuggestedCode & 0xF) switch + { + 1 => 6.0, + 2 => 6.5, + 3 => 7.0, + 4 => 7.5, + 5 => 8.0, + 6 => 8.5, + 7 => 9.0, + 8 => 9.5, + 9 => 10.0, + 10 => 10.5, + 11 => 11.0, + 12 => 11.5, + 13 => 12.0, + _ => 0 + }; + + sb.AppendFormat(Localization.Recommended_recording_power_is_0_mW, recordingPower).AppendLine(); + } + + if(decoded.WaveLengthCode > 0) + { + int wavelength = decoded.WaveLengthCode switch + { + 1 => 645, + 2 => 646, + 3 => 647, + 4 => 648, + 5 => 649, + 6 => 650, + 7 => 651, + 8 => 652, + 9 => 653, + 10 => 654, + 11 => 655, + 12 => 656, + 13 => 657, + 14 => 658, + 15 => 659, + 16 => 660, + _ => 0 + }; + + sb.AppendFormat(Localization.Recommended_recording_power_is_0_mW, wavelength).AppendLine(); + } + } + + sb.AppendFormat(Localization.Disc_manufacturer_is_0, ManufacturerFromPrePit(decoded.ManufacturerId)) + .AppendLine(); + + return sb.ToString(); + } + + public static string Prettify(byte[] response) => Prettify(Decode(response)); + + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public static string ManufacturerFromPrePit(string manufacturerId) + { + var manufacturer = ""; + + // Bad thing is that it also includes a media code... + if(manufacturerId.StartsWith("RITEK", StringComparison.Ordinal)) + manufacturer = "Ritek Co."; + else if(manufacturerId.StartsWith("CMC", StringComparison.Ordinal)) + manufacturer = "CMC Magnetics Corporation"; + else if(manufacturerId.StartsWith("Dvsn-", StringComparison.Ordinal)) + manufacturer = "Digital Storage Technology Co., Ltd."; + else if(manufacturerId.StartsWith("GSC", StringComparison.Ordinal)) + manufacturer = "Gigastore Corporation"; + else if(manufacturerId.StartsWith("INFOMEDIA", StringComparison.Ordinal)) + manufacturer = "InfoMedia Inc."; + else if(manufacturerId.StartsWith("ISSM", StringComparison.Ordinal)) + manufacturer = "Info Source Digital Media (Zhongshan) Co., Ltd."; + else if(manufacturerId.StartsWith("LEADDATA", StringComparison.Ordinal)) + manufacturer = "Lead Data Inc."; + else if(manufacturerId.StartsWith("MCC", StringComparison.Ordinal) || + manufacturerId.StartsWith("MKM", StringComparison.Ordinal)) + manufacturer = "Mitsubishi Kagaku Media Co., LTD."; + else if(manufacturerId.StartsWith("MUST", StringComparison.Ordinal)) + manufacturer = "Must Technology Co., Ltd."; + else if(manufacturerId.StartsWith("MXL", StringComparison.Ordinal)) + manufacturer = "Hitachi Maxell, Ltd."; + else if(manufacturerId.StartsWith("PRINCO", StringComparison.Ordinal)) + manufacturer = "Princo Corporation"; + else if(manufacturerId.StartsWith("Prodisc", StringComparison.Ordinal)) + manufacturer = "Prodisc Technology Inc."; + else if(manufacturerId.StartsWith("SONY", StringComparison.Ordinal) || + manufacturerId.StartsWith("80SONY", StringComparison.Ordinal)) + manufacturer = "Sony Corporation"; + else if(manufacturerId.StartsWith("TCLDS", StringComparison.Ordinal)) + manufacturer = "TCL Technology"; + else if(manufacturerId.StartsWith("TMI", StringComparison.Ordinal)) + manufacturer = "ThaiMedia Co., Ltd. "; + else if(manufacturerId.StartsWith("TY", StringComparison.Ordinal)) + manufacturer = "Taiyo Yuden Company Ltd."; + else if(manufacturerId.StartsWith("UME", StringComparison.Ordinal)) + manufacturer = "Avic Umedisc HK Ltd."; + else if(manufacturerId.StartsWith("DAXON", StringComparison.Ordinal)) + manufacturer = "Daxon Technology Inc."; + else if(manufacturerId.StartsWith("FTI", StringComparison.Ordinal)) + manufacturer = "Falcon Technologies International L.L.C."; + else if(manufacturerId.StartsWith("FUJIFILM", StringComparison.Ordinal)) + manufacturer = "Fuji Photo Film, Co., Ltd."; + else if(manufacturerId.StartsWith("MBI", StringComparison.Ordinal)) + manufacturer = "Moser Baer India Ltd."; + else if(manufacturerId.StartsWith("TT", StringComparison.Ordinal) || + manufacturerId.StartsWith("TDK", StringComparison.Ordinal)) + manufacturer = "TDK Corporation"; + else if(manufacturerId.StartsWith("JVC", StringComparison.Ordinal)) + manufacturer = "Victor Advanced media Co., Ltd."; + else if(manufacturerId.StartsWith("MEI", StringComparison.Ordinal)) + manufacturer = "Matsushita Electric Industrial Co., Ltd."; + else if(manufacturerId.StartsWith("OPTODISC", StringComparison.Ordinal)) + manufacturer = "OptoDisc Ltd."; + else if(manufacturerId.StartsWith("KIC", StringComparison.Ordinal)) + manufacturer = "Advance Media Corporation"; + else if(manufacturerId.StartsWith("IMC", StringComparison.Ordinal)) + manufacturer = "Intermedia Co., Ltd."; + else if(manufacturerId.StartsWith("LGE", StringComparison.Ordinal)) + manufacturer = "LG Electronics Inc."; + else if(manufacturerId.StartsWith("KDT", StringComparison.Ordinal)) + manufacturer = "King Disc Technology Corporation"; + else if(manufacturerId.StartsWith("POS", StringComparison.Ordinal)) + manufacturer = "POSTECH Corporation"; + else if(manufacturerId.StartsWith("VDSPMSAB", StringComparison.Ordinal)) + manufacturer = "Interaxia Digital Storage Materials AG"; + else if(manufacturerId.StartsWith("VANGUARD", StringComparison.Ordinal)) + manufacturer = "Vanguard Disc Inc."; + else if(manufacturerId.StartsWith("MJC", StringComparison.Ordinal)) + manufacturer = "Megan Media Holdings Berhad"; + else if(manufacturerId.StartsWith("DKM", StringComparison.Ordinal) || + manufacturerId.StartsWith("EDMA", StringComparison.Ordinal)) + manufacturer = "E-TOP Mediatek Inc."; + else if(manufacturerId.StartsWith("BeAll", StringComparison.Ordinal)) manufacturer = "BeALL Developers, Inc."; + + return manufacturer != "" ? $"{manufacturer} (\"{manufacturerId}\")" : $"\"{manufacturerId}\""; + } + +#region Nested type: PreRecordedInformation + + public struct PreRecordedInformation + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 == 1 + public byte FieldId1; + /// Byte 5 disc application code + public byte DiscApplicationCode; + /// Byte 6 disc physical code + public byte DiscPhysicalCode; + /// Bytes 7 to 9 last address of data recordable area + public uint LastAddressOfDataRecordableArea; + /// Byte 10, bits 7 to 4 part version + public byte PartVersion; + /// Byte 10, bits 3 to 0 extension code + public byte ExtensionCode; + /// Byte 11 reserved + public byte Reserved3; + /// Byte 12 == 2 + public byte FieldId2; + /// Byte 13 OPC suggested code + public byte OPCSuggestedCode; + /// Byte 14 wavelength code or second part of OPC suggested code + public byte WaveLengthCode; + /// Bytes 15 to 18 write strategy code + public uint WriteStrategyCode; + /// Byte 19 reserved + public byte Reserved4; + /// Byte 20 == 3 + public byte FieldId3; + /// Bytes 21 to 26 first part of manufacturer ID + public byte[] ManufacturerId1; + /// Byte 27 + public byte Reserved5; + /// Byte 28 == 4 + public byte FieldId4; + /// Bytes 29 to 34 second part of manufacturer ID + public byte[] ManufacturerId2; + /// Byte 35 reserved + public byte Reserved6; + /// Byte 36 == 5 + public byte FieldId5; + /// Bytes 37 to 42, third part of manufacturer code or write strategy code for RW and R later versions + public byte[] ManufacturerId3; + /// Byte 43 reserved + public byte Reserved7; + /// Bytes 44 to 68 reserved + public byte[] Reserved8; + + public string ManufacturerId; + public uint WriteStrategyCode2; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/RMD.cs b/Aaru.Decoders/DVD/RMD.cs new file mode 100644 index 000000000..874fc53d7 --- /dev/null +++ b/Aaru.Decoders/DVD/RMD.cs @@ -0,0 +1,95 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : RMD.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD RMD. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class RMD +{ +#region Nested type: HDMediumStatus + + public struct HDMediumStatus + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bits 7 to 1 Reserved + public byte Reserved3; + /// Byte 4, bit 0 Test Zone has been extended + public bool ExtendedTestZone; + /// Byte 5 Number of remaining RMDs in RDZ + public byte RemainingRMDs; + /// Bytes 6 to 7 Number of remaining RMDs in current RMZ + public ushort CurrentRemainingRMDs; + } + +#endregion + +#region Nested type: LastBorderOutRMD + + public struct LastBorderOutRMD + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end RMD in last recorded Border-out + public byte[] RMD; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/Sector.cs b/Aaru.Decoders/DVD/Sector.cs new file mode 100644 index 000000000..6133158e8 --- /dev/null +++ b/Aaru.Decoders/DVD/Sector.cs @@ -0,0 +1,244 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Sector.cs +// Author(s) : Rebecca Wallander +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes and descrambles DVD sectors. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Rebecca Wallander +// ****************************************************************************/ + +#nullable enable +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Aaru.CommonTypes.Enums; +using Aaru.Helpers; + +namespace Aaru.Decoders.DVD; + +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public sealed class Sector +{ + static readonly ushort[] _ecma267InitialValues = + [ + 0x0001, 0x5500, 0x0002, 0x2A00, 0x0004, 0x5400, 0x0008, 0x2800, 0x0010, 0x5000, 0x0020, 0x2001, 0x0040, + 0x4002, 0x0080, 0x0005 + ]; + + static readonly uint[] _edcTable = + [ + 0x00000000, 0x80000011, 0x80000033, 0x00000022, 0x80000077, 0x00000066, 0x00000044, 0x80000055, 0x800000FF, + 0x000000EE, 0x000000CC, 0x800000DD, 0x00000088, 0x80000099, 0x800000BB, 0x000000AA, 0x800001EF, 0x000001FE, + 0x000001DC, 0x800001CD, 0x00000198, 0x80000189, 0x800001AB, 0x000001BA, 0x00000110, 0x80000101, 0x80000123, + 0x00000132, 0x80000167, 0x00000176, 0x00000154, 0x80000145, 0x800003CF, 0x000003DE, 0x000003FC, 0x800003ED, + 0x000003B8, 0x800003A9, 0x8000038B, 0x0000039A, 0x00000330, 0x80000321, 0x80000303, 0x00000312, 0x80000347, + 0x00000356, 0x00000374, 0x80000365, 0x00000220, 0x80000231, 0x80000213, 0x00000202, 0x80000257, 0x00000246, + 0x00000264, 0x80000275, 0x800002DF, 0x000002CE, 0x000002EC, 0x800002FD, 0x000002A8, 0x800002B9, 0x8000029B, + 0x0000028A, 0x8000078F, 0x0000079E, 0x000007BC, 0x800007AD, 0x000007F8, 0x800007E9, 0x800007CB, 0x000007DA, + 0x00000770, 0x80000761, 0x80000743, 0x00000752, 0x80000707, 0x00000716, 0x00000734, 0x80000725, 0x00000660, + 0x80000671, 0x80000653, 0x00000642, 0x80000617, 0x00000606, 0x00000624, 0x80000635, 0x8000069F, 0x0000068E, + 0x000006AC, 0x800006BD, 0x000006E8, 0x800006F9, 0x800006DB, 0x000006CA, 0x00000440, 0x80000451, 0x80000473, + 0x00000462, 0x80000437, 0x00000426, 0x00000404, 0x80000415, 0x800004BF, 0x000004AE, 0x0000048C, 0x8000049D, + 0x000004C8, 0x800004D9, 0x800004FB, 0x000004EA, 0x800005AF, 0x000005BE, 0x0000059C, 0x8000058D, 0x000005D8, + 0x800005C9, 0x800005EB, 0x000005FA, 0x00000550, 0x80000541, 0x80000563, 0x00000572, 0x80000527, 0x00000536, + 0x00000514, 0x80000505, 0x80000F0F, 0x00000F1E, 0x00000F3C, 0x80000F2D, 0x00000F78, 0x80000F69, 0x80000F4B, + 0x00000F5A, 0x00000FF0, 0x80000FE1, 0x80000FC3, 0x00000FD2, 0x80000F87, 0x00000F96, 0x00000FB4, 0x80000FA5, + 0x00000EE0, 0x80000EF1, 0x80000ED3, 0x00000EC2, 0x80000E97, 0x00000E86, 0x00000EA4, 0x80000EB5, 0x80000E1F, + 0x00000E0E, 0x00000E2C, 0x80000E3D, 0x00000E68, 0x80000E79, 0x80000E5B, 0x00000E4A, 0x00000CC0, 0x80000CD1, + 0x80000CF3, 0x00000CE2, 0x80000CB7, 0x00000CA6, 0x00000C84, 0x80000C95, 0x80000C3F, 0x00000C2E, 0x00000C0C, + 0x80000C1D, 0x00000C48, 0x80000C59, 0x80000C7B, 0x00000C6A, 0x80000D2F, 0x00000D3E, 0x00000D1C, 0x80000D0D, + 0x00000D58, 0x80000D49, 0x80000D6B, 0x00000D7A, 0x00000DD0, 0x80000DC1, 0x80000DE3, 0x00000DF2, 0x80000DA7, + 0x00000DB6, 0x00000D94, 0x80000D85, 0x00000880, 0x80000891, 0x800008B3, 0x000008A2, 0x800008F7, 0x000008E6, + 0x000008C4, 0x800008D5, 0x8000087F, 0x0000086E, 0x0000084C, 0x8000085D, 0x00000808, 0x80000819, 0x8000083B, + 0x0000082A, 0x8000096F, 0x0000097E, 0x0000095C, 0x8000094D, 0x00000918, 0x80000909, 0x8000092B, 0x0000093A, + 0x00000990, 0x80000981, 0x800009A3, 0x000009B2, 0x800009E7, 0x000009F6, 0x000009D4, 0x800009C5, 0x80000B4F, + 0x00000B5E, 0x00000B7C, 0x80000B6D, 0x00000B38, 0x80000B29, 0x80000B0B, 0x00000B1A, 0x00000BB0, 0x80000BA1, + 0x80000B83, 0x00000B92, 0x80000BC7, 0x00000BD6, 0x00000BF4, 0x80000BE5, 0x00000AA0, 0x80000AB1, 0x80000A93, + 0x00000A82, 0x80000AD7, 0x00000AC6, 0x00000AE4, 0x80000AF5, 0x80000A5F, 0x00000A4E, 0x00000A6C, 0x80000A7D, + 0x00000A28, 0x80000A39, 0x80000A1B, 0x00000A0A + ]; + + readonly Dictionary _seeds = new(); + + ushort _lastSeed; + + ushort _lfsr; + + void LfsrInit(ushort seed) => _lfsr = seed; + + int LfsrTick() + { + int ret = _lfsr >> 14; + + int n = ret ^ _lfsr >> 10 & 1; + _lfsr = (ushort)((_lfsr << 1 | n) & 0x7FFF); + + return ret; + } + + byte LfsrByte() + { + byte ret = 0; + + for(var i = 0; i < 8; i++) ret = (byte)(ret << 1 | LfsrTick()); + + return ret; + } + + /// + /// Store seed and its cipher in cache + /// + /// The seed to store + /// The cipher for the seed + byte[] AddSeed(ushort seed) + { + int i; + var cypher = new byte[2048]; + + LfsrInit(seed); + + for(i = 0; i < 2048; i++) cypher[i] = LfsrByte(); + + _seeds.Add(seed, cypher); + + return cypher; + } + + static uint ComputeEdc(uint edc, IReadOnlyList src, int size) + { + var pos = 0; + + for(; size > 0; size--) edc = _edcTable[(edc >> 24 ^ src[pos++]) & 0xFF] ^ edc << 8; + + return edc; + } + + /// + /// Tests if a seed unscrambles a sector correctly + /// + /// Buffer of the scrambled sector + /// Seed to test + /// True if seed is correct, False if not + bool TestSeed(in byte[] sector, ushort seed) + { + var tmp = new byte[sector.Length]; + Array.Copy(sector, 0, tmp, 0, sector.Length); + + LfsrInit(seed); + + for(var i = 12; i < 2060; i++) tmp[i] ^= LfsrByte(); + + return ComputeEdc(0, tmp, 2060) == BigEndianBitConverter.ToUInt32(sector, 2060); + } + + /// + /// Find the seed used for scrambling a sector + /// + /// Buffer of the scrambled sector. + /// The scramble cipher + byte[]? GetSeed(byte[] sector) + { + // Try the last used key + if(TestSeed(sector, _lastSeed)) return _seeds[_lastSeed]; + + // Try the cached keys + foreach(ushort seedsKey in _seeds.Keys.Where(seedsKey => TestSeed(sector, seedsKey))) + { + _lastSeed = seedsKey; + + return _seeds[seedsKey]; + } + + // Try the ECMA-267 keys since they are often used + foreach(ushort iv in _ecma267InitialValues.Where(iv => TestSeed(sector, iv))) + { + _lastSeed = iv; + + return AddSeed(iv); + } + + // Brute force all other keys + for(ushort i = 0; i < 0x7FFF; i++) + { + if(!TestSeed(sector, i)) continue; + + _lastSeed = i; + + return AddSeed(i); + } + + return null; + } + + /// + /// Unscramble a sector with a cipher + /// + /// Buffer of the scrambled sector + /// Buffer of the scrambling cipher + /// Buffer of unscrambled sector data + /// The Error. + static ErrorNumber UnscrambleSector(byte[] sector, IReadOnlyList cipher, out byte[] scrambled) + { + scrambled = new byte[sector.Length]; + Array.Copy(sector, 0, scrambled, 0, sector.Length); + + for(var i = 0; i < 2048; i++) scrambled[i + 12] = (byte)(sector[i + 12] ^ cipher[i]); + + return ComputeEdc(0, scrambled, 2060) != BigEndianBitConverter.ToUInt32(sector, 2060) + ? ErrorNumber.NotVerifiable + : ErrorNumber.NoError; + } + + public ErrorNumber Scramble(byte[] sector, out byte[] scrambled) + { + scrambled = new byte[sector.Length]; + + if(sector is not { Length: 2064 }) return ErrorNumber.NotSupported; + + byte[]? cipher = GetSeed(sector); + + return cipher == null ? ErrorNumber.UnrecognizedFormat : UnscrambleSector(sector, cipher, out scrambled); + } + + public ErrorNumber Scramble(byte[] sector, uint transferLength, out byte[] scrambled) + { + scrambled = new byte[sector.Length]; + + if(sector.Length % 2064 != 0 || sector.Length / 2064 != transferLength) return ErrorNumber.NotSupported; + + for(uint i = 0; i < transferLength; i++) + { + ErrorNumber error = Scramble(sector.Skip((int)(i * 2064)).Take(2064).ToArray(), out byte[]? currentSector); + + if(error != ErrorNumber.NoError) return error; + + Array.Copy(currentSector, 0, scrambled, i * 2064, 2064); + } + + return ErrorNumber.NoError; + } +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/Spare.cs b/Aaru.Decoders/DVD/Spare.cs new file mode 100644 index 000000000..76c493460 --- /dev/null +++ b/Aaru.Decoders/DVD/Spare.cs @@ -0,0 +1,113 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Spare.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD spare area information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class Spare +{ + public static SpareAreaInformation? Decode(byte[] response) + { + if(response?.Length != 16) return null; + + return new SpareAreaInformation + { + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + UnusedPrimaryBlocks = (uint)((response[4] << 24) + (response[5] << 16) + (response[6] << 8) + response[7]), + UnusedSupplementaryBlocks = + (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]), + AllocatedSupplementaryBlocks = + (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]) + }; + } + + public static string Prettify(SpareAreaInformation? sai) + { + if(sai == null) return null; + + SpareAreaInformation decoded = sai.Value; + var sb = new StringBuilder(); + + sb.AppendFormat(Localization._0_unused_primary_spare_blocks, decoded.UnusedPrimaryBlocks).AppendLine(); + + sb.AppendFormat(Localization._0_unused_supplementary_spare_blocks, decoded.UnusedSupplementaryBlocks) + .AppendLine(); + + sb.AppendFormat(Localization._0_allocated_supplementary_spare_blocks, decoded.AllocatedSupplementaryBlocks) + .AppendLine(); + + return sb.ToString(); + } + + public static string Prettify(byte[] response) => Prettify(Decode(response)); + +#region Nested type: SpareAreaInformation + + public struct SpareAreaInformation + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 7 Data length + public uint UnusedPrimaryBlocks; + /// Bytes 8 to 11 Data length + public uint UnusedSupplementaryBlocks; + /// Bytes 12 to 15 Data length + public uint AllocatedSupplementaryBlocks; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/DVD/UDI.cs b/Aaru.Decoders/DVD/UDI.cs new file mode 100644 index 000000000..48f792b38 --- /dev/null +++ b/Aaru.Decoders/DVD/UDI.cs @@ -0,0 +1,89 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : UDI.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes DVD unique disc identifier. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.DVD; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +// ECMA 365 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class UDI +{ +#region Nested type: UniqueDiscIdentifier + + public struct UniqueDiscIdentifier + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Bytes 6 to 7 Random number + public ushort RandomNumber; + /// Byte 8 to 11 Year + public uint Year; + /// Byte 12 to 13 Month + public ushort Month; + /// Byte 14 to 15 Day + public ushort Day; + /// Byte 16 to 17 Hour + public ushort Hour; + /// Byte 18 to 19 Minute + public ushort Minute; + /// Byte 20 to 21 Second + public ushort Second; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Floppy/Amiga.cs b/Aaru.Decoders/Floppy/Amiga.cs new file mode 100644 index 000000000..6309ab9fa --- /dev/null +++ b/Aaru.Decoders/Floppy/Amiga.cs @@ -0,0 +1,76 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Amiga.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Commodore Amiga floppy structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Decoders.Floppy; + +/// Methods and structures for Commodore Amiga decoding +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class Amiga +{ +#region Nested type: Sector + + public struct Sector + { + /// Set to 0x00 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] zero; + /// Set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] sync; + /// Set to 0xFF + public byte amiga; + /// Track number + public byte track; + /// Sector number + public byte sector; + /// Remaining sectors til end of writing + public byte remaining; + /// OS dependent tag + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] label; + /// Checksum from to + public uint headerChecksum; + /// Checksum from + public uint dataChecksum; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] + public byte[] data; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Floppy/Apple2.cs b/Aaru.Decoders/Floppy/Apple2.cs new file mode 100644 index 000000000..15286021e --- /dev/null +++ b/Aaru.Decoders/Floppy/Apple2.cs @@ -0,0 +1,655 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Apple2.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Apple ][ floppy structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using Aaru.Console; +using Aaru.Localization; + +namespace Aaru.Decoders.Floppy; + +/// Methods and structures for Apple ][ floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "ClassCanBeSealed.Global")] +public static class Apple2 +{ + const string MODULE_NAME = "Apple ][ GCR Decoder"; + static readonly byte[] ReadTable5and3 = + [ + // 00h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 10h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 20h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 30h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 40h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 50h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 60h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 70h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 80h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 90h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // A0h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x01, 0x02, 0x03, + + // B0h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x05, 0x06, 0xFF, 0xFF, 0x07, 0x08, 0xFF, 0x09, 0x0A, 0x0B, + + // C0h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // D0h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0C, 0x0D, 0xFF, 0xFF, 0x0E, 0x0F, 0xFF, 0x10, 0x11, 0x12, + + // E0h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x13, 0x14, 0xFF, 0x15, 0x16, 0x17, + + // F0h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x18, 0x19, 0x1A, 0xFF, 0xFF, 0x1B, 0x1C, 0xFF, 0x1D, 0x1E, 0x1F + ]; + + static readonly byte[] ReadTable6and2 = + [ + // 00h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 10h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 20h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 30h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 40h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 50h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 60h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 70h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 80h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + // 90h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x04, 0x05, 0x06, + + // A0h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x08, 0xFF, 0xFF, 0xFF, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + + // B0h + 0xFF, 0xFF, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xFF, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, + + // C0h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0xFF, 0x1C, 0x1D, 0x1E, + + // D0h + 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x20, 0x21, 0xFF, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + + // E0h + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x29, 0x2A, 0x2B, 0xFF, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, + + // F0h + 0xFF, 0xFF, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0xFF, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F + ]; + + /// Decodes the 5and3 encoded data + /// 5and3 encoded data. + public static byte[] Decode5and3(byte[] data) + { + if(data is not { Length: 410 }) return null; + + var buffer = new byte[data.Length]; + byte carry = 0; + + for(var i = 0; i < data.Length; i++) + { + carry ^= ReadTable5and3[data[i]]; + buffer[i] = carry; + } + + var output = new byte[256]; + + for(var i = 0; i < 51; i++) + { + byte b1 = buffer[51 * 3 - i]; + byte b2 = buffer[51 * 2 - i]; + byte b3 = buffer[51 - i]; + var b4 = (byte)(((b1 & 2) << 1 | b2 & 2 | (b3 & 2) >> 1) & 0xFF); + var b5 = (byte)(((b1 & 1) << 2 | (b2 & 1) << 1 | b3 & 1) & 0xFF); + output[250 - 5 * i] = (byte)((buffer[i + 51 * 3 + 1] << 3 | b1 >> 2 & 0x7) & 0xFF); + output[251 - 5 * i] = (byte)((buffer[i + 51 * 4 + 1] << 3 | b2 >> 2 & 0x7) & 0xFF); + output[252 - 5 * i] = (byte)((buffer[i + 51 * 5 + 1] << 3 | b3 >> 2 & 0x7) & 0xFF); + output[253 - 5 * i] = (byte)((buffer[i + 51 * 6 + 1] << 3 | b4) & 0xFF); + output[254 - 5 * i] = (byte)((buffer[i + 51 * 7 + 1] << 3 | b5) & 0xFF); + } + + output[255] = (byte)((buffer[409] << 3 | buffer[0] & 0x7) & 0xFF); + + return output; + } + + /// Decodes the 6and2 encoded data + /// 6and2 encoded data. + public static byte[] Decode6and2(byte[] data) + { + if(data is not { Length: 342 }) return null; + + var buffer = new byte[data.Length]; + byte carry = 0; + + for(var i = 0; i < data.Length; i++) + { + carry ^= ReadTable6and2[data[i]]; + buffer[i] = carry; + } + + var output = new byte[256]; + + for(uint i = 0; i < 256; i++) + { + output[i] = (byte)(buffer[86 + i] << 2 & 0xFF); + + switch(i) + { + case < 86: + output[i] |= (byte)((buffer[i] & 1) << 1 & 0xFF); + output[i] |= (byte)((buffer[i] & 2) >> 1 & 0xFF); + + break; + case < 86 * 2: + output[i] |= (byte)((buffer[i - 86] & 4) >> 1 & 0xFF); + output[i] |= (byte)((buffer[i - 86] & 8) >> 3 & 0xFF); + + break; + default: + output[i] |= (byte)((buffer[i - 86 * 2] & 0x10) >> 3 & 0xFF); + output[i] |= (byte)((buffer[i - 86 * 2] & 0x20) >> 5 & 0xFF); + + break; + } + } + + return output; + } + + public static byte[] DecodeSector(RawSector sector) + { + if(sector.addressField.prologue[0] != 0xD5 || sector.addressField.prologue[1] != 0xAA) return null; + + // Pre DOS 3.3 + if(sector.addressField.prologue[2] == 0xB5) return Decode5and3(sector.dataField.data); + + // DOS 3.3 + return sector.addressField.prologue[2] == 0x96 ? Decode6and2(sector.dataField.data) : null; + + // Unknown + + // Not Apple ][ GCR? + } + + public static RawSector MarshalSector(byte[] data, int offset = 0) => MarshalSector(data, out _, offset); + + public static RawSector MarshalSector(byte[] data, out int endOffset, int offset = 0) + { + endOffset = offset; + + // Not an Apple ][ GCR sector + if(data == null || data.Length < 363) return null; + + int position = offset; + + try + { + while(position < data.Length) + { + // Prologue found + if(data[position] == 0xD5 && data[position + 1] == 0xAA) + { + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Prologue_found_at_0, position); + + // Epilogue not in correct position + if(data[position + 11] != 0xDE || data[position + 12] != 0xAA) return null; + + var sector = new RawSector + { + addressField = new RawAddressField + { + prologue = [data[position], data[position + 1], data[position + 2]], + volume = [data[position + 3], data[position + 4]], + track = [data[position + 5], data[position + 6]], + sector = [data[position + 7], data[position + 8]], + checksum = [data[position + 9], data[position + 10]], + epilogue = [data[position + 11], data[position + 12], data[position + 13]] + } + }; + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Volume_0, + ((sector.addressField.volume[0] & 0x55) << 1 | + sector.addressField.volume[1] & 0x55) & + 0xFF); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Core.Track_0, + ((sector.addressField.track[0] & 0x55) << 1 | + sector.addressField.track[1] & 0x55) & + 0xFF); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Sector_0, + ((sector.addressField.sector[0] & 0x55) << 1 | + sector.addressField.sector[1] & 0x55) & + 0xFF); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Checksum_0, + ((sector.addressField.checksum[0] & 0x55) << 1 | + sector.addressField.checksum[1] & 0x55) & + 0xFF); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Epilogue_0_1_2, + sector.addressField.epilogue[0], + sector.addressField.epilogue[1], + sector.addressField.epilogue[2]); + + position += 14; + var syncCount = 0; + var onSync = false; + var gaps = new MemoryStream(); + + while(data[position] == 0xFF) + { + gaps.WriteByte(data[position]); + syncCount++; + onSync = syncCount >= 5; + position++; + } + + // Lost sync + if(!onSync) return null; + + // Prologue not found + if(data[position] != 0xD5 || data[position + 1] != 0xAA) return null; + + sector.innerGap = gaps.ToArray(); + sector.dataField = new RawDataField(); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Inner_gap_has_0_bytes, sector.innerGap.Length); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Prologue_found_at_0, position); + sector.dataField.prologue = new byte[3]; + sector.dataField.prologue[0] = data[position]; + sector.dataField.prologue[1] = data[position + 1]; + sector.dataField.prologue[2] = data[position + 2]; + position += 3; + + gaps = new MemoryStream(); + + // Read data until epilogue is found + while(data[position + 1] != 0xDE || data[position + 2] != 0xAA) + { + gaps.WriteByte(data[position]); + position++; + + // No space left for epilogue + if(position + 4 > data.Length) return null; + } + + sector.dataField.data = gaps.ToArray(); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Data_has_0_bytes, + sector.dataField.data.Length); + + sector.dataField.checksum = data[position]; + sector.dataField.epilogue = new byte[3]; + sector.dataField.epilogue[0] = data[position + 1]; + sector.dataField.epilogue[1] = data[position + 2]; + sector.dataField.epilogue[2] = data[position + 3]; + + position += 4; + gaps = new MemoryStream(); + + // Read gap, if any + while(position < data.Length && data[position] == 0xFF) + { + gaps.WriteByte(data[position]); + position++; + } + + // Reduces last sector gap so doesn't eat next tracks's gap + if(gaps.Length > 5) + { + gaps.SetLength(gaps.Length / 2); + position -= (int)gaps.Length; + } + + sector.gap = gaps.ToArray(); + + // Return current position to be able to read separate sectors + endOffset = position; + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Got_0_bytes_of_gap, sector.gap.Length); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Finished_sector_at_0, position); + + return sector; + } + + if(data[position] == 0xFF) + position++; + + // Found data that is not sync or a prologue + else + return null; + } + } + catch(IndexOutOfRangeException) + { + return null; + } + + return null; + } + + public static byte[] MarshalAddressField(RawAddressField addressField) + { + if(addressField == null) return null; + + var raw = new MemoryStream(); + raw.Write(addressField.prologue, 0, addressField.prologue.Length); + raw.Write(addressField.volume, 0, addressField.volume.Length); + raw.Write(addressField.track, 0, addressField.track.Length); + raw.Write(addressField.sector, 0, addressField.sector.Length); + raw.Write(addressField.checksum, 0, addressField.checksum.Length); + raw.Write(addressField.epilogue, 0, addressField.epilogue.Length); + + return raw.ToArray(); + } + + public static byte[] MarshalSector(RawSector sector) + { + if(sector == null) return null; + + var raw = new MemoryStream(); + raw.Write(sector.addressField.prologue, 0, sector.addressField.prologue.Length); + raw.Write(sector.addressField.volume, 0, sector.addressField.volume.Length); + raw.Write(sector.addressField.track, 0, sector.addressField.track.Length); + raw.Write(sector.addressField.sector, 0, sector.addressField.sector.Length); + raw.Write(sector.addressField.checksum, 0, sector.addressField.checksum.Length); + raw.Write(sector.addressField.epilogue, 0, sector.addressField.epilogue.Length); + raw.Write(sector.innerGap, 0, sector.innerGap.Length); + raw.Write(sector.dataField.prologue, 0, sector.dataField.prologue.Length); + raw.Write(sector.dataField.data, 0, sector.dataField.data.Length); + raw.WriteByte(sector.dataField.checksum); + raw.Write(sector.dataField.epilogue, 0, sector.dataField.epilogue.Length); + raw.Write(sector.gap, 0, sector.gap.Length); + + return raw.ToArray(); + } + + public static RawTrack MarshalTrack(byte[] data, int offset = 0) => MarshalTrack(data, out _, offset); + + public static RawTrack MarshalTrack(byte[] data, out int endOffset, int offset = 0) + { + int position = offset; + var firstSector = true; + var onSync = false; + var gaps = new MemoryStream(); + var count = 0; + List sectors = []; + var trackNumber = new byte[2]; + endOffset = offset; + + while(position < data.Length && data[position] == 0xFF) + { + gaps.WriteByte(data[position]); + count++; + position++; + onSync = count >= 5; + } + + if(position >= data.Length) return null; + + if(!onSync) return null; + + while(position < data.Length) + { + int oldPosition = position; + RawSector sector = MarshalSector(data, out position, position); + + if(sector == null) break; + + if(firstSector) + { + trackNumber[0] = sector.addressField.track[0]; + trackNumber[1] = sector.addressField.track[1]; + firstSector = false; + } + + if(sector.addressField.track[0] != trackNumber[0] || sector.addressField.track[1] != trackNumber[1]) + { + position = oldPosition; + + break; + } + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Adding_sector_0_of_track_1, + ((sector.addressField.sector[0] & 0x55) << 1 | + sector.addressField.sector[1] & 0x55) & + 0xFF, + ((sector.addressField.track[0] & 0x55) << 1 | + sector.addressField.track[1] & 0x55) & + 0xFF); + + sectors.Add(sector); + } + + if(sectors.Count == 0) return null; + + var track = new RawTrack + { + gap = gaps.ToArray(), + sectors = sectors.ToArray() + }; + + endOffset = position; + + return track; + } + + public static byte[] MarshalTrack(RawTrack track) + { + if(track == null) return null; + + var raw = new MemoryStream(); + raw.Write(track.gap, 0, track.gap.Length); + + foreach(byte[] rawSector in track.sectors.Select(MarshalSector)) raw.Write(rawSector, 0, rawSector.Length); + + return raw.ToArray(); + } + + public static List MarshalDisk(byte[] data, int offset = 0) => MarshalDisk(data, out _, offset); + + [SuppressMessage("ReSharper", "OutParameterValueIsAlwaysDiscarded.Global")] + public static List MarshalDisk(byte[] data, out int endOffset, int offset = 0) + { + endOffset = offset; + List tracks = []; + int position = offset; + + RawTrack track = MarshalTrack(data, out position, position); + + while(track != null) + { + tracks.Add(track); + track = MarshalTrack(data, out position, position); + } + + if(tracks.Count == 0) return null; + + endOffset = position; + + return tracks; + } + + public static byte[] MarshalDisk(List disk) => MarshalDisk(disk.ToArray()); + + public static byte[] MarshalDisk(RawTrack[] disk) + { + if(disk == null) return null; + + var raw = new MemoryStream(); + + foreach(byte[] rawTrack in disk.Select(MarshalTrack)) raw.Write(rawTrack, 0, rawTrack.Length); + + return raw.ToArray(); + } + + public static bool IsApple2GCR(byte[] data) + { + RawSector sector = MarshalSector(data, out int position); + + return sector != null && position != 0; + } + +#region Nested type: RawAddressField + + /// GCR-encoded Apple ][ GCR floppy sector address field + public class RawAddressField + { + /// + /// decodedChecksum = decodedVolume ^ decodedTrack ^ decodedSector checksum[0] = (decodedChecksum >> 1) | 0xAA + /// checksum[1] = decodedChecksum | 0xAA + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] checksum; + /// Always 0xDE, 0xAA, 0xEB + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] epilogue; + /// Always 0xD5, 0xAA, 0x96 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] prologue; + /// Sector number encoded as: sector[0] = (decodedSector >> 1) | 0xAA sector[1] = decodedSector | 0xAA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] sector; + /// Track number encoded as: track[0] = (decodedTrack >> 1) | 0xAA track[1] = decodedTrack | 0xAA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] track; + /// Volume number encoded as: volume[0] = (decodedVolume >> 1) | 0xAA volume[1] = decodedVolume | 0xAA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] volume; + } + +#endregion + +#region Nested type: RawDataField + + /// GCR-encoded Apple ][ GCR floppy sector data field + public class RawDataField + { + public byte checksum; + /// Encoded data bytes. 410 bytes for 5to3 (aka DOS 3.2) format 342 bytes for 6to2 (aka DOS 3.3) format + public byte[] data; + /// Always 0xDE, 0xAA, 0xEB + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] epilogue; + /// Always 0xD5, 0xAA, 0xAD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] prologue; + } + +#endregion + +#region Nested type: RawSector + + /// GCR-encoded Apple ][ GCR floppy sector + public class RawSector + { + /// Address field + public RawAddressField addressField; + /// Data field + public RawDataField dataField; + /// Track preamble, set to self-sync 0xFF, between 14 and 24 bytes + public byte[] gap; + /// Track preamble, set to self-sync 0xFF, between 5 and 10 bytes + public byte[] innerGap; + } + +#endregion + +#region Nested type: RawTrack + + /// GCR-encoded Apple ][ GCR floppy track + public class RawTrack + { + /// Track preamble, set to self-sync 0xFF, between 40 and 95 bytes + public byte[] gap; + public RawSector[] sectors; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Floppy/AppleSony.cs b/Aaru.Decoders/Floppy/AppleSony.cs new file mode 100644 index 000000000..10e9eea16 --- /dev/null +++ b/Aaru.Decoders/Floppy/AppleSony.cs @@ -0,0 +1,495 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : AppleSony.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Apple/Sony floppy structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; + +namespace Aaru.Decoders.Floppy; + +// Information from: +// Inside Macintosh, Volume II, ISBN 0-201-17732-3 + +/// Methods and structures for Apple Sony GCR floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +[SuppressMessage("ReSharper", "OutParameterValueIsAlwaysDiscarded.Global")] +public static class AppleSony +{ + public static byte[] DecodeSector(RawSector sector) + { + if(sector.addressField.prologue[0] != 0xD5 || + sector.addressField.prologue[1] != 0xAA || + sector.addressField.prologue[2] != 0x96) + return null; + + var bf1 = new byte[175]; + var bf2 = new byte[175]; + var bf3 = new byte[175]; + byte[] nib_data = sector.dataField.data; + var ms = new MemoryStream(); + + var j = 0; + byte w3 = 0; + + for(var i = 0; i <= 174; i++) + { + byte w4 = nib_data[j++]; + byte w1 = nib_data[j++]; + byte w2 = nib_data[j++]; + + if(i != 174) w3 = nib_data[j++]; + + bf1[i] = (byte)((w1 & 0x3F | w4 << 2 & 0xC0) & 0x0F); + bf2[i] = (byte)((w2 & 0x3F | w4 << 4 & 0xC0) & 0x0F); + bf3[i] = (byte)((w3 & 0x3F | w4 << 6 & 0xC0) & 0x0F); + } + + j = 0; + uint ck1 = 0; + uint ck2 = 0; + uint ck3 = 0; + + while(true) + { + ck1 = (ck1 & 0xFF) << 1; + + if((ck1 & 0x0100) > 0) ck1++; + + var carry = (byte)((bf1[j] ^ ck1) & 0xFF); + ck3 += carry; + + if((ck1 & 0x0100) > 0) + { + ck3++; + ck1 &= 0xFF; + } + + ms.WriteByte(carry); + + carry = (byte)((bf2[j] ^ ck3) & 0xFF); + ck2 += carry; + + if(ck3 > 0xFF) + { + ck2++; + ck3 &= 0xFF; + } + + ms.WriteByte(carry); + + if(ms.Length == 524) break; + + carry = (byte)((bf3[j] ^ ck2) & 0xFF); + ck1 += carry; + + if(ck2 > 0xFF) + { + ck1++; + ck2 &= 0xFF; + } + + ms.WriteByte(carry); + j++; + } + + return ms.ToArray(); + + // Not Apple Sony GCR? + } + + public static RawSector MarshalSector(byte[] data, int offset = 0) => MarshalSector(data, out _, offset); + + public static RawSector MarshalSector(byte[] data, out int endOffset, int offset = 0) + { + endOffset = offset; + + // Not an Apple ][ GCR sector + if(data == null || data.Length < 363) return null; + + int position = offset; + + try + { + while(position < data.Length) + { + // Prologue found + if(data[position] == 0xD5 && data[position + 1] == 0xAA && data[position + 2] == 0x96) + { + // Epilogue not in correct position + if(data[position + 8] != 0xDE || data[position + 9] != 0xAA) return null; + + var sector = new RawSector + { + addressField = new RawAddressField + { + prologue = [data[position], data[position + 1], data[position + 2]], + track = data[position + 3], + sector = data[position + 4], + side = data[position + 5], + format = (AppleEncodedFormat)data[position + 6], + checksum = data[position + 7], + epilogue = [data[position + 8], data[position + 9]] + } + }; + + position += 10; + var syncCount = 0; + var onSync = false; + var gaps = new MemoryStream(); + + while(data[position] == 0xFF) + { + gaps.WriteByte(data[position]); + syncCount++; + onSync = syncCount >= 5; + position++; + } + + // Lost sync + if(!onSync) return null; + + // Prologue not found + if(data[position] != 0xDE || data[position + 1] != 0xAA || data[position + 2] != 0xAD) return null; + + sector.innerGap = gaps.ToArray(); + + sector.dataField = new RawDataField + { + prologue = [data[position], data[position + 1], data[position + 2]], + spare = data[position + 3] + }; + + position += 4; + + gaps = new MemoryStream(); + + // Read data until epilogue is found + while(data[position + 4] != 0xD5 || data[position + 5] != 0xAA) + { + gaps.WriteByte(data[position]); + position++; + + // No space left for epilogue + if(position + 7 > data.Length) return null; + } + + sector.dataField.data = gaps.ToArray(); + sector.dataField.checksum = new byte[4]; + sector.dataField.checksum[0] = data[position]; + sector.dataField.checksum[1] = data[position + 2]; + sector.dataField.checksum[2] = data[position + 3]; + sector.dataField.checksum[3] = data[position + 4]; + sector.dataField.epilogue = new byte[2]; + sector.dataField.epilogue[0] = data[position + 5]; + sector.dataField.epilogue[1] = data[position + 6]; + + position += 7; + gaps = new MemoryStream(); + + // Read gap, if any + while(position < data.Length && data[position] == 0xFF) + { + gaps.WriteByte(data[position]); + position++; + } + + // Reduces last sector gap so doesn't eat next tracks's gap + if(gaps.Length > 5) + { + gaps.SetLength(gaps.Length / 2); + position -= (int)gaps.Length; + } + + sector.gap = gaps.ToArray(); + + // Return current position to be able to read separate sectors + endOffset = position; + + return sector; + } + + if(data[position] == 0xFF) + position++; + + // Found data that is not sync or a prologue + else + return null; + } + } + catch(IndexOutOfRangeException) + { + return null; + } + + return null; + } + + public static byte[] MarshalAddressField(RawAddressField addressField) + { + if(addressField == null) return null; + + var raw = new MemoryStream(); + raw.Write(addressField.prologue, 0, addressField.prologue.Length); + raw.WriteByte(addressField.track); + raw.WriteByte(addressField.sector); + raw.WriteByte(addressField.side); + raw.WriteByte((byte)addressField.format); + raw.WriteByte(addressField.checksum); + + return raw.ToArray(); + } + + public static byte[] MarshalSector(RawSector sector) + { + if(sector == null) return null; + + var raw = new MemoryStream(); + raw.Write(sector.addressField.prologue, 0, sector.addressField.prologue.Length); + raw.WriteByte(sector.addressField.track); + raw.WriteByte(sector.addressField.sector); + raw.WriteByte(sector.addressField.side); + raw.WriteByte((byte)sector.addressField.format); + raw.WriteByte(sector.addressField.checksum); + raw.Write(sector.innerGap, 0, sector.innerGap.Length); + raw.Write(sector.dataField.prologue, 0, sector.dataField.prologue.Length); + raw.WriteByte(sector.dataField.spare); + raw.Write(sector.dataField.data, 0, sector.dataField.data.Length); + raw.Write(sector.dataField.checksum, 0, sector.dataField.checksum.Length); + raw.Write(sector.dataField.epilogue, 0, sector.dataField.epilogue.Length); + raw.Write(sector.gap, 0, sector.gap.Length); + + return raw.ToArray(); + } + + public static RawTrack MarshalTrack(byte[] data, int offset = 0) => MarshalTrack(data, out _, offset); + + public static RawTrack MarshalTrack(byte[] data, out int endOffset, int offset = 0) + { + int position = offset; + var firstSector = true; + var onSync = false; + var gaps = new MemoryStream(); + var count = 0; + List sectors = []; + byte trackNumber = 0; + byte sideNumber = 0; + endOffset = offset; + + while(position < data.Length && data[position] == 0xFF) + { + gaps.WriteByte(data[position]); + count++; + position++; + onSync = count >= 5; + } + + if(position >= data.Length) return null; + + if(!onSync) return null; + + while(position < data.Length) + { + int oldPosition = position; + RawSector sector = MarshalSector(data, out position, position); + + if(sector == null) break; + + if(firstSector) + { + trackNumber = sector.addressField.track; + sideNumber = sector.addressField.side; + firstSector = false; + } + + if(sector.addressField.track != trackNumber || sector.addressField.side != sideNumber) + { + position = oldPosition; + + break; + } + + sectors.Add(sector); + } + + if(sectors.Count == 0) return null; + + var track = new RawTrack + { + gap = gaps.ToArray(), + sectors = sectors.ToArray() + }; + + endOffset = position; + + return track; + } + + public static byte[] MarshalTrack(RawTrack track) + { + if(track == null) return null; + + var raw = new MemoryStream(); + raw.Write(track.gap, 0, track.gap.Length); + + foreach(byte[] rawSector in track.sectors.Select(MarshalSector)) raw.Write(rawSector, 0, rawSector.Length); + + return raw.ToArray(); + } + + public static List MarshalDisk(byte[] data, int offset = 0) => MarshalDisk(data, out _, offset); + + public static List MarshalDisk(byte[] data, out int endOffset, int offset = 0) + { + endOffset = offset; + List tracks = []; + int position = offset; + + RawTrack track = MarshalTrack(data, out position, position); + + while(track != null) + { + tracks.Add(track); + track = MarshalTrack(data, out position, position); + } + + if(tracks.Count == 0) return null; + + endOffset = position; + + return tracks; + } + + public static byte[] MarshalDisk(List disk) => MarshalDisk(disk.ToArray()); + + public static byte[] MarshalDisk(RawTrack[] disk) + { + if(disk == null) return null; + + var raw = new MemoryStream(); + + foreach(byte[] rawTrack in disk.Select(MarshalTrack)) raw.Write(rawTrack, 0, rawTrack.Length); + + return raw.ToArray(); + } + + public static bool IsAppleSonyGCR(byte[] data) + { + RawSector sector = MarshalSector(data, out int position); + + return sector != null && position != 0; + } + +#region Nested type: RawAddressField + + /// GCR-encoded Apple Sony GCR floppy sector address field + public sealed class RawAddressField + { + /// Checksum + public byte checksum; + /// Always 0xDE, 0xAA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] epilogue; + /// Disk format + public AppleEncodedFormat format; + /// Always 0xD5, 0xAA, 0x96 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] prologue; + /// Encoded sector number + public byte sector; + /// Encoded side number + public byte side; + /// Encoded (decodedTrack & 0x3F) + public byte track; + } + +#endregion + +#region Nested type: RawDataField + + /// GCR-encoded Apple ][ GCR floppy sector data field + public sealed class RawDataField + { + /// Checksum + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] checksum; + /// Encoded data bytes. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 698)] + public byte[] data; + /// Always 0xDE, 0xAA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] epilogue; + /// Always 0xD5, 0xAA, 0xAD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] prologue; + /// Spare, usually + public byte spare; + } + +#endregion + +#region Nested type: RawSector + + /// GCR-encoded Apple Sony GCR floppy sector + public sealed class RawSector + { + /// Address field + public RawAddressField addressField; + /// Data field + public RawDataField dataField; + /// Track preamble, set to self-sync 0xFF, unknown size + public byte[] gap; + /// Track preamble, set to self-sync 0xFF, 6 bytes + public byte[] innerGap; + } + +#endregion + +#region Nested type: RawTrack + + /// GCR-encoded Apple Sony GCR floppy track + public sealed class RawTrack + { + /// Track preamble, set to self-sync 0xFF, 36 bytes + public byte[] gap; + public RawSector[] sectors; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Floppy/Commodore.cs b/Aaru.Decoders/Floppy/Commodore.cs new file mode 100644 index 000000000..89eb514cc --- /dev/null +++ b/Aaru.Decoders/Floppy/Commodore.cs @@ -0,0 +1,84 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Commodore.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Commodore (pre-Amiga) floppy structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Decoders.Floppy; + +/// Methods and structures for Commodore GCR floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class Commodore +{ +#region Nested type: SectorData + + /// Decoded Commodore GCR sector data + public struct SectorData + { + /// Always 0x07 + public byte id; + /// User data + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + public byte data; + /// XOR of + public byte checksum; + /// Filled with 0x0F + public ushort fill; + } + +#endregion + +#region Nested type: SectorHeader + + /// Decoded Commodore GCR sector header + public struct SectorHeader + { + /// Always 0x08 + public byte id; + /// XOR of following fields + public byte checksum; + /// Sector number + public byte sector; + /// Track number + public byte track; + /// Format ID, unknown meaning + public ushort format; + /// Filled with 0x0F + public ushort fill; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Floppy/Enums.cs b/Aaru.Decoders/Floppy/Enums.cs new file mode 100644 index 000000000..f231b6248 --- /dev/null +++ b/Aaru.Decoders/Floppy/Enums.cs @@ -0,0 +1,81 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains various floppy enumerations. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.Floppy; + +/// In-sector code for sector size +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum IBMSectorSizeCode : byte +{ + /// 128 bytes/sector + EighthKilo = 0, + /// 256 bytes/sector + QuarterKilo = 1, + /// 512 bytes/sector + HalfKilo = 2, + /// 1024 bytes/sector + Kilo = 3, + /// 2048 bytes/sector + TwiceKilo = 4, + /// 4096 bytes/sector + FriceKilo = 5, + /// 8192 bytes/sector + TwiceFriceKilo = 6, + /// 16384 bytes/sector + FricelyFriceKilo = 7 +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum IBMIdType : byte +{ + IndexMark = 0xFC, + AddressMark = 0xFE, + DataMark = 0xFB, + DeletedDataMark = 0xF8 +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum AppleEncodedFormat : byte +{ + /// Disk is an Apple II 3.5" disk + AppleII = 0x96, + /// Disk is an Apple Lisa 3.5" disk + Lisa = 0x97, + /// Disk is an Apple Macintosh single-sided 3.5" disk + MacSingleSide = 0x9A, + /// Disk is an Apple Macintosh double-sided 3.5" disk + MacDoubleSide = 0xD9 +} \ No newline at end of file diff --git a/Aaru.Decoders/Floppy/ISO.cs b/Aaru.Decoders/Floppy/ISO.cs new file mode 100644 index 000000000..b02767fb7 --- /dev/null +++ b/Aaru.Decoders/Floppy/ISO.cs @@ -0,0 +1,139 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ISO.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes ISO/ECMA floppy structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Decoders.Floppy; + +// Information from: +// National Semiconductor PC87332VLJ datasheet +// SMsC FDC37C78 datasheet +// Intel 82078 datasheet +// Intel 82077AA datasheet +// Toshiba TC8566AF datasheet +// Fujitsu MB8876A datasheet +// ECMA-147 +// ECMA-100 + +/// Methods and structures for ISO floppy decoding (also used by Atari ST and others) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class ISO +{ +#region Nested type: AddressMark + + /// Sector address mark for IBM System 34 floppies, contains sync word + public struct AddressMark + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to + public IBMIdType type; + /// Track number + public byte track; + /// Side number + public byte side; + /// Sector number + public byte sector; + /// + /// + /// + public IBMSectorSizeCode sectorSize; + /// CRC16 from to end of + public ushort crc; + } + +#endregion + +#region Nested type: DataBlock + + /// Sector data block for IBM System 34 floppies + public struct DataBlock + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to or to + public IBMIdType type; + /// User data + public byte[] data; + /// CRC16 from to end of + public ushort crc; + } + +#endregion + +#region Nested type: Sector + + /// Raw demodulated format for IBM System 34 floppies + public struct Sector + { + /// Sector address mark + public AddressMark addressMark; + /// 22 bytes set to 0x4E, set to 0x22 on Commodore 1581 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)] + public byte[] innerGap; + /// Sector data block + public DataBlock dataBlock; + /// Variable bytes set to 0x4E, ECMA defines 54 + public byte[] outerGap; + } + +#endregion + +#region Nested type: Track + + /// ISO floppy track, also used by Atari ST and others + public struct Track + { + /// Start of track, 32 bytes set to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] innerGap; + /// Track sectors + public Sector[] sectors; + /// Undefined size + public byte[] gap; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Floppy/Perpendicular.cs b/Aaru.Decoders/Floppy/Perpendicular.cs new file mode 100644 index 000000000..afbbdb7d1 --- /dev/null +++ b/Aaru.Decoders/Floppy/Perpendicular.cs @@ -0,0 +1,161 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Perpendicular.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes perpendicular recording floppy structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Decoders.Floppy; + +// Information from: +// National Semiconductor PC87332VLJ datasheet +// SMsC FDC37C78 datasheet +// Intel 82078 datasheet +// Intel 82077AA datasheet +// Toshiba TC8566AF datasheet +// Fujitsu MB8876A datasheet +// ECMA-147 +// ECMA-100 + +/// Methods and structures for perpendicular MFM floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class Perpendicular +{ +#region Nested type: AddressMark + + /// Sector address mark for IBM System 34 floppies, contains sync word + public struct AddressMark + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to + public IBMIdType type; + /// Track number + public byte track; + /// Side number + public byte side; + /// Sector number + public byte sector; + /// + /// + /// + public IBMSectorSizeCode sectorSize; + /// CRC16 from to end of + public ushort crc; + } + +#endregion + +#region Nested type: DataBlock + + /// Sector data block for IBM System 34 floppies + public struct DataBlock + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to or to + public IBMIdType type; + /// User data + public byte[] data; + /// CRC16 from to end of + public ushort crc; + } + +#endregion + +#region Nested type: Sector + + /// Raw demodulated format for perpendicular floppies + public struct Sector + { + /// Sector address mark + public AddressMark addressMark; + /// 41 bytes set to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 41)] + public byte[] innerGap; + /// Sector data block + public DataBlock dataBlock; + /// Variable-sized inter-sector gap, ECMA defines 83 bytes + public byte[] outerGap; + } + +#endregion + +#region Nested type: Track + + /// Perpendicular floppy track + public struct Track + { + /// Start of track + public TrackPreamble trackStart; + /// Track sectors + public Sector[] sectors; + /// Undefined size + public byte[] gap; + } + +#endregion + +#region Nested type: TrackPreamble + + /// Start of IBM PC MFM floppy track Used by IBM PC, Apple Macintosh (high-density only), and a lot others + public struct TrackPreamble + { + /// Gap from index pulse, 80 bytes set to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] + public byte[] gap; + /// 12 bytes set to 0x00 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xC2 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] ctwo; + /// Set to + public IBMIdType type; + /// Gap until first sector, 50 bytes to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] + public byte[] gap1; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Floppy/System34.cs b/Aaru.Decoders/Floppy/System34.cs new file mode 100644 index 000000000..1944a3a37 --- /dev/null +++ b/Aaru.Decoders/Floppy/System34.cs @@ -0,0 +1,162 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : System34.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes IBM System 34 floppy structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Decoders.Floppy; + +// Information from: +// National Semiconductor PC87332VLJ datasheet +// SMsC FDC37C78 datasheet +// Intel 82078 datasheet +// Intel 82077AA datasheet +// Toshiba TC8566AF datasheet +// Fujitsu MB8876A datasheet +// ECMA-147 +// ECMA-100 + +/// Methods and structures for IBM System 34 floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class System34 +{ +#region Nested type: AddressMark + + /// Sector address mark for IBM System 34 floppies, contains sync word + public struct AddressMark + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to + public IBMIdType type; + /// Track number + public byte track; + /// Side number + public byte side; + /// Sector number + public byte sector; + /// + /// + /// + public IBMSectorSizeCode sectorSize; + /// CRC16 from to end of + public ushort crc; + } + +#endregion + +#region Nested type: DataBlock + + /// Sector data block for IBM System 34 floppies + public struct DataBlock + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to or to + public IBMIdType type; + /// User data + public byte[] data; + /// CRC16 from to end of + public ushort crc; + } + +#endregion + +#region Nested type: Sector + + /// Raw demodulated format for IBM System 34 floppies + public struct Sector + { + /// Sector address mark + public AddressMark addressMark; + /// 22 bytes set to 0x4E, set to 0x22 on Commodore 1581 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)] + public byte[] innerGap; + /// Sector data block + public DataBlock dataBlock; + /// Variable bytes set to 0x4E, ECMA defines 54 + public byte[] outerGap; + } + +#endregion + +#region Nested type: Track + + /// Track format for IBM System 34 floppy Used by IBM PC, Apple Macintosh (high-density only), and a lot others + public struct Track + { + /// Start of track + public TrackPreamble trackStart; + /// Track sectors + public Sector[] sectors; + /// Undefined size + public byte[] gap; + } + +#endregion + +#region Nested type: TrackPreamble + + /// Start of IBM PC MFM floppy track Used by IBM PC, Apple Macintosh (high-density only), and a lot others + public struct TrackPreamble + { + /// Gap from index pulse, 80 bytes set to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] + public byte[] gap; + /// 12 bytes set to 0x00 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xC2 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] ctwo; + /// Set to + public IBMIdType type; + /// Gap until first sector, 50 bytes to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] + public byte[] gap1; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Floppy/System3740.cs b/Aaru.Decoders/Floppy/System3740.cs new file mode 100644 index 000000000..e5fc2b23d --- /dev/null +++ b/Aaru.Decoders/Floppy/System3740.cs @@ -0,0 +1,152 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : System3740.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes IBM System 3740 floppy structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Decoders.Floppy; + +// Information from: +// National Semiconductor PC87332VLJ datasheet +// SMsC FDC37C78 datasheet +// Intel 82078 datasheet +// Intel 82077AA datasheet +// Toshiba TC8566AF datasheet +// Fujitsu MB8876A datasheet +// ECMA-147 +// ECMA-100 + +/// Methods and structures for IBM System 3740 floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class System3740 +{ +#region Nested type: AddressMark + + /// Sector address mark for IBM System 3740 floppies, contains sync word + public struct AddressMark + { + /// 6 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] zero; + /// Set to + public IBMIdType type; + /// Track number + public byte track; + /// Side number + public byte side; + /// Sector number + public byte sector; + /// + /// + /// + public IBMSectorSizeCode sectorSize; + /// CRC16 from to end of + public ushort crc; + } + +#endregion + +#region Nested type: DataBlock + + /// Sector data block for IBM System 3740 floppies + public struct DataBlock + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// Set to or to + public IBMIdType type; + /// User data + public byte[] data; + /// CRC16 from to end of + public ushort crc; + } + +#endregion + +#region Nested type: Sector + + /// Raw demodulated format for IBM System 3740 floppies + public struct Sector + { + /// Sector address mark + public AddressMark addressMark; + /// 11 bytes set to 0xFF + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] innerGap; + /// Sector data block + public DataBlock dataBlock; + /// Variable bytes set to 0xFF + public byte[] outerGap; + } + +#endregion + +#region Nested type: Track + + /// Track format for IBM System 3740 floppy + public struct Track + { + /// Start of track + public TrackPreamble trackStart; + /// Track sectors + public Sector[] sectors; + /// Undefined size + public byte[] gap; + } + +#endregion + +#region Nested type: TrackPreamble + + /// Start of IBM PC FM floppy track + public struct TrackPreamble + { + /// Gap from index pulse, 80 bytes set to 0xFF + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] + public byte[] gap; + /// 6 bytes set to 0x00 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] zero; + /// Set to + public IBMIdType type; + /// Gap until first sector, 26 bytes to 0xFF + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] + public byte[] gap1; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/LisaTag.cs b/Aaru.Decoders/LisaTag.cs new file mode 100644 index 000000000..e89349dcb --- /dev/null +++ b/Aaru.Decoders/LisaTag.cs @@ -0,0 +1,513 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : LisaTag.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Apple Lisa tags. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.Helpers; + +namespace Aaru.Decoders; + +/// Represents a Lisa Office 7/7 sector tag +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "StructMemberCanBeMadeReadOnly")] +public static class LisaTag +{ + /// Decodes tag from a 3.5" Sony micro-floppy + /// Byte array containing raw tag data + /// Decoded tag in Sony's format + public static SonyTag? DecodeSonyTag(byte[] tag) + { + if(tag is not { Length: 12 }) return null; + + var snTag = new SonyTag + { + Version = BigEndianBitConverter.ToUInt16(tag, 0), + Kind = (byte)((tag[2] & 0xC0) >> 6), + Reserved = (byte)(tag[2] & 0x3F), + Volume = tag[3], + FileId = BigEndianBitConverter.ToInt16(tag, 4), + RelPage = BigEndianBitConverter.ToUInt16(tag, 6), + NextBlock = (ushort)(BigEndianBitConverter.ToUInt16(tag, 8) & 0x7FF), + PrevBlock = (ushort)(BigEndianBitConverter.ToUInt16(tag, 10) & 0x7FF) + }; + + snTag.IsLast = snTag.NextBlock == 0x7FF; + snTag.IsFirst = snTag.PrevBlock == 0x7FF; + + return snTag; + } + + /// Decodes tag from a Profile + /// Byte array containing raw tag data + /// Decoded tag in Profile's format + public static ProfileTag? DecodeProfileTag(byte[] tag) + { + if(tag is not { Length: 20 }) return null; + + var phTag = new ProfileTag(); + + var tmp = new byte[4]; + + phTag.Version = BigEndianBitConverter.ToUInt16(tag, 0); + phTag.Kind = (byte)((tag[2] & 0xC0) >> 6); + phTag.Reserved = (byte)(tag[2] & 0x3F); + phTag.Volume = tag[3]; + phTag.FileId = BigEndianBitConverter.ToInt16(tag, 4); + phTag.ValidChk |= (tag[6] & 0x80) == 0x80; + phTag.UsedBytes = (ushort)(BigEndianBitConverter.ToUInt16(tag, 6) & 0x7FFF); + + tmp[0] = 0x00; + tmp[1] = tag[8]; + tmp[2] = tag[9]; + tmp[3] = tag[10]; + phTag.AbsPage = BigEndianBitConverter.ToUInt32(tmp, 0); + + phTag.Checksum = tag[11]; + phTag.RelPage = BigEndianBitConverter.ToUInt16(tag, 12); + + tmp[0] = 0x00; + tmp[1] = tag[14]; + tmp[2] = tag[15]; + tmp[3] = tag[16]; + phTag.NextBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + tmp[0] = 0x00; + tmp[1] = tag[17]; + tmp[2] = tag[18]; + tmp[3] = tag[19]; + phTag.PrevBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + phTag.IsLast = phTag.NextBlock == 0xFFFFFF; + phTag.IsFirst = phTag.PrevBlock == 0xFFFFFF; + + return phTag; + } + + /// Decodes tag from a Priam + /// Byte array containing raw tag data + /// Decoded tag in Priam's format + public static PriamTag? DecodePriamTag(byte[] tag) + { + if(tag is not { Length: 24 }) return null; + + var pmTag = new PriamTag(); + + var tmp = new byte[4]; + + pmTag.Version = BigEndianBitConverter.ToUInt16(tag, 0); + pmTag.Kind = (byte)((tag[2] & 0xC0) >> 6); + pmTag.Reserved = (byte)(tag[2] & 0x3F); + pmTag.Volume = tag[3]; + pmTag.FileId = BigEndianBitConverter.ToInt16(tag, 4); + pmTag.ValidChk |= (tag[6] & 0x80) == 0x80; + pmTag.UsedBytes = (ushort)(BigEndianBitConverter.ToUInt16(tag, 6) & 0x7FFF); + + tmp[0] = 0x00; + tmp[1] = tag[8]; + tmp[2] = tag[9]; + tmp[3] = tag[10]; + pmTag.AbsPage = BigEndianBitConverter.ToUInt32(tmp, 0); + + pmTag.Checksum = tag[11]; + pmTag.RelPage = BigEndianBitConverter.ToUInt16(tag, 12); + + tmp[0] = 0x00; + tmp[1] = tag[14]; + tmp[2] = tag[15]; + tmp[3] = tag[16]; + pmTag.NextBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + tmp[0] = 0x00; + tmp[1] = tag[17]; + tmp[2] = tag[18]; + tmp[3] = tag[19]; + pmTag.PrevBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + pmTag.DiskSize = BigEndianBitConverter.ToUInt32(tag, 20); + + pmTag.IsLast = pmTag.NextBlock == 0xFFFFFF; + pmTag.IsFirst = pmTag.PrevBlock == 0xFFFFFF; + + return pmTag; + } + + /// Decodes tag from any known format + /// Byte array containing raw tag data + /// Decoded tag in Priam's format + public static PriamTag? DecodeTag(byte[] tag) + { + if(tag == null) return null; + + PriamTag pmTag; + + switch(tag.Length) + { + case 12: + SonyTag? snTag = DecodeSonyTag(tag); + + if(snTag == null) return null; + + pmTag = new PriamTag + { + AbsPage = 0, + Checksum = 0, + DiskSize = 0, + FileId = snTag.Value.FileId, + Kind = snTag.Value.Kind, + NextBlock = snTag.Value.NextBlock, + PrevBlock = snTag.Value.PrevBlock, + RelPage = snTag.Value.RelPage, + Reserved = snTag.Value.Reserved, + UsedBytes = 0, + ValidChk = false, + Version = snTag.Value.Version, + Volume = snTag.Value.Volume, + IsFirst = snTag.Value.IsFirst, + IsLast = snTag.Value.IsLast + }; + + return pmTag; + case 20: + ProfileTag? phTag = DecodeProfileTag(tag); + + if(phTag == null) return null; + + pmTag = new PriamTag + { + AbsPage = phTag.Value.AbsPage, + Checksum = phTag.Value.Checksum, + DiskSize = 0, + FileId = phTag.Value.FileId, + Kind = phTag.Value.Kind, + NextBlock = phTag.Value.NextBlock, + PrevBlock = phTag.Value.PrevBlock, + RelPage = phTag.Value.RelPage, + Reserved = phTag.Value.Reserved, + UsedBytes = phTag.Value.UsedBytes, + ValidChk = phTag.Value.ValidChk, + Version = phTag.Value.Version, + Volume = phTag.Value.Volume, + IsFirst = phTag.Value.IsFirst, + IsLast = phTag.Value.IsLast + }; + + return pmTag; + case 24: + return DecodePriamTag(tag); + default: + return null; + } + } + +#region Nested type: PriamTag + + /// LisaOS tag as stored on Priam DataTower disks (24 bytes) + public struct PriamTag + { + /// 0x00, Lisa OS version number + public ushort Version; + /// 0x02 bits 7 to 6, kind of info in this block + public byte Kind; + /// 0x02 bits 5 to 0, reserved + public byte Reserved; + /// 0x03, disk volume number + public byte Volume; + /// 0x04, file ID + public short FileId; + /// 0x06 bit 7, checksum valid? + public bool ValidChk; + /// 0x06 bits 6 to 0, used bytes in block + public ushort UsedBytes; + /// 0x08, 3 bytes, absolute page number + public uint AbsPage; + /// 0x0B, checksum of data + public byte Checksum; + /// 0x0C, relative page number + public ushort RelPage; + /// 0x0E, 3 bytes, next block, 0xFFFFFF if it's last block + public uint NextBlock; + /// 0x11, 3 bytes, previous block, 0xFFFFFF if it's first block + public uint PrevBlock; + /// 0x14, disk size + public uint DiskSize; + + /// On-memory value for easy first block search. + public bool IsFirst; + /// On-memory value for easy last block search. + public bool IsLast; + + /// Converts this tag to Apple Profile format + public ProfileTag ToProfile() => new() + { + AbsPage = AbsPage, + Checksum = Checksum, + FileId = FileId, + IsFirst = IsFirst, + IsLast = IsLast, + Kind = Kind, + NextBlock = IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF, + PrevBlock = IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF, + RelPage = RelPage, + UsedBytes = UsedBytes, + ValidChk = ValidChk, + Version = Version, + Volume = Volume + }; + + /// Converts this tag to Sony format + public SonyTag ToSony() => new() + { + FileId = FileId, + IsFirst = IsFirst, + IsLast = IsLast, + Kind = Kind, + NextBlock = (ushort)(IsLast ? 0x7FF : NextBlock & 0x7FF), + PrevBlock = (ushort)(IsFirst ? 0x7FF : PrevBlock & 0x7FF), + RelPage = RelPage, + Version = Version, + Volume = Volume + }; + + /// Gets a byte array representation of this tag + public byte[] GetBytes() + { + var tagBytes = new byte[24]; + + byte[] tmp = BigEndianBitConverter.GetBytes(Version); + Array.Copy(tmp, 0, tagBytes, 0, 2); + tagBytes[2] = (byte)(Kind << 6); + tagBytes[3] = Volume; + tmp = BigEndianBitConverter.GetBytes(FileId); + Array.Copy(tmp, 0, tagBytes, 4, 2); + tmp = BigEndianBitConverter.GetBytes((ushort)(UsedBytes & 0x7FFF)); + Array.Copy(tmp, 0, tagBytes, 6, 2); + + if(ValidChk) tagBytes[6] += 0x80; + + tmp = BigEndianBitConverter.GetBytes(AbsPage); + Array.Copy(tmp, 1, tagBytes, 8, 3); + tagBytes[11] = Checksum; + tmp = BigEndianBitConverter.GetBytes(RelPage); + Array.Copy(tmp, 0, tagBytes, 12, 2); + tmp = BigEndianBitConverter.GetBytes(IsLast ? 0xFFFFFF : NextBlock); + Array.Copy(tmp, 1, tagBytes, 14, 3); + tmp = BigEndianBitConverter.GetBytes(IsFirst ? 0xFFFFFF : PrevBlock); + Array.Copy(tmp, 1, tagBytes, 17, 3); + tmp = BigEndianBitConverter.GetBytes(DiskSize); + Array.Copy(tmp, 0, tagBytes, 20, 4); + + return tagBytes; + } + } + +#endregion + +#region Nested type: ProfileTag + + /// LisaOS tag as stored on Apple Profile and FileWare disks (20 bytes) + public struct ProfileTag + { + /// 0x00, Lisa OS version number + public ushort Version; + /// 0x02 bits 7 to 6, kind of info in this block + public byte Kind; + /// 0x02 bits 5 to 0, reserved + public byte Reserved; + /// 0x03, disk volume number + public byte Volume; + /// 0x04, file ID + public short FileId; + /// 0x06 bit 7, checksum valid? + public bool ValidChk; + /// 0x06 bits 6 to 0, used bytes in block + public ushort UsedBytes; + /// 0x08, 3 bytes, absolute page number + public uint AbsPage; + /// 0x0B, checksum of data + public byte Checksum; + /// 0x0C, relative page number + public ushort RelPage; + /// 0x0E, 3 bytes, next block, 0xFFFFFF if it's last block + public uint NextBlock; + /// 0x11, 3 bytes, previous block, 0xFFFFFF if it's first block + public uint PrevBlock; + + /// On-memory value for easy first block search. + public bool IsFirst; + /// On-memory value for easy last block search. + public bool IsLast; + + /// Converts this tag to Priam DataTower format + public PriamTag ToPriam() => new() + { + AbsPage = AbsPage, + Checksum = Checksum, + FileId = FileId, + IsFirst = IsFirst, + IsLast = IsLast, + Kind = Kind, + NextBlock = IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF, + PrevBlock = IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF, + RelPage = RelPage, + UsedBytes = UsedBytes, + ValidChk = ValidChk, + Version = Version, + Volume = Volume + }; + + /// Converts this tag to Sony format + public SonyTag ToSony() => new() + { + FileId = FileId, + IsFirst = IsFirst, + IsLast = IsLast, + Kind = Kind, + NextBlock = (ushort)NextBlock, + PrevBlock = (ushort)PrevBlock, + RelPage = RelPage, + Version = Version, + Volume = Volume + }; + + /// Gets a byte array representation of this tag + public byte[] GetBytes() + { + var tagBytes = new byte[20]; + + byte[] tmp = BigEndianBitConverter.GetBytes(Version); + Array.Copy(tmp, 0, tagBytes, 0, 2); + tagBytes[2] = (byte)(Kind << 6); + tagBytes[3] = Volume; + tmp = BigEndianBitConverter.GetBytes(FileId); + Array.Copy(tmp, 0, tagBytes, 4, 2); + tmp = BigEndianBitConverter.GetBytes((ushort)(UsedBytes & 0x7FFF)); + Array.Copy(tmp, 0, tagBytes, 6, 2); + + if(ValidChk) tagBytes[6] += 0x80; + + tmp = BigEndianBitConverter.GetBytes(AbsPage); + Array.Copy(tmp, 1, tagBytes, 8, 3); + tagBytes[11] = Checksum; + tmp = BigEndianBitConverter.GetBytes(RelPage); + Array.Copy(tmp, 0, tagBytes, 12, 2); + tmp = BigEndianBitConverter.GetBytes(IsLast ? 0xFFFFFF : NextBlock); + Array.Copy(tmp, 1, tagBytes, 14, 3); + tmp = BigEndianBitConverter.GetBytes(IsFirst ? 0xFFFFFF : PrevBlock); + Array.Copy(tmp, 1, tagBytes, 17, 3); + + return tagBytes; + } + } + +#endregion + +#region Nested type: SonyTag + + /// LisaOS tag as stored on Apple Sony disks (12 bytes) + public struct SonyTag + { + /// 0x00, Lisa OS version number + public ushort Version; + /// 0x02 bits 7 to 6, kind of info in this block + public byte Kind; + /// 0x02 bits 5 to 0, reserved + public byte Reserved; + /// 0x03, disk volume number + public byte Volume; + /// 0x04, file ID + public short FileId; + /// 0x06, relative page number + public ushort RelPage; + /// 0x08, 3 bytes, next block, 0x7FF if it's last block, 0x8000 set if block is valid + public ushort NextBlock; + /// 0x0A, 3 bytes, previous block, 0x7FF if it's first block + public ushort PrevBlock; + + /// On-memory value for easy first block search. + public bool IsFirst; + /// On-memory value for easy last block search. + public bool IsLast; + + /// Converts this tag to Apple Profile format + public ProfileTag ToProfile() => new() + { + FileId = FileId, + IsFirst = IsFirst, + IsLast = IsLast, + Kind = Kind, + NextBlock = (uint)(IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF), + PrevBlock = (uint)(IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF), + RelPage = RelPage, + Version = Version, + Volume = Volume + }; + + /// Converts this tag to Priam DataTower format + public PriamTag ToPriam() => new() + { + FileId = FileId, + IsFirst = IsFirst, + IsLast = IsLast, + Kind = Kind, + NextBlock = (uint)(IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF), + PrevBlock = (uint)(IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF), + RelPage = RelPage, + Version = Version, + Volume = Volume + }; + + /// Gets a byte array representation of this tag + public byte[] GetBytes() + { + var tagBytes = new byte[12]; + + byte[] tmp = BigEndianBitConverter.GetBytes(Version); + Array.Copy(tmp, 0, tagBytes, 0, 2); + tagBytes[2] = (byte)(Kind << 6); + tagBytes[3] = Volume; + tmp = BigEndianBitConverter.GetBytes(FileId); + Array.Copy(tmp, 0, tagBytes, 4, 2); + tmp = BigEndianBitConverter.GetBytes(RelPage); + Array.Copy(tmp, 0, tagBytes, 6, 2); + tmp = BigEndianBitConverter.GetBytes(IsLast ? 0x7FF : NextBlock); + Array.Copy(tmp, 1, tagBytes, 8, 2); + tmp = BigEndianBitConverter.GetBytes(IsFirst ? 0x7FF : PrevBlock); + Array.Copy(tmp, 1, tagBytes, 10, 2); + + return tagBytes; + } + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Localization/Localization.Designer.cs b/Aaru.Decoders/Localization/Localization.Designer.cs new file mode 100644 index 000000000..f9fdfb43d --- /dev/null +++ b/Aaru.Decoders/Localization/Localization.Designer.cs @@ -0,0 +1,29039 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Aaru.Decoders { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Localization { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Localization() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aaru.Decoders.Localization.Localization", typeof(Localization).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to DEVICE RESET is supported. + /// + internal static string _ { + get { + return ResourceManager.GetString("", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} hours shall be between the start of a background scan operation and the next. + /// + internal static string _0__hours_shall_be_between_the_start_of_a_background_scan_operation_and_the_next { + get { + return ResourceManager.GetString("_0__hours_shall_be_between_the_start_of_a_background_scan_operation_and_the_next", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} additional partitions defined. + /// + internal static string _0_additional_partitions_defined { + get { + return ResourceManager.GetString("_0_additional_partitions_defined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} allocated spare blocks. + /// + internal static string _0_allocated_spare_blocks { + get { + return ResourceManager.GetString("_0_allocated_spare_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} allocated supplementary spare blocks. + /// + internal static string _0_allocated_supplementary_spare_blocks { + get { + return ResourceManager.GetString("_0_allocated_supplementary_spare_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} assigned tracks on the disc. + /// + internal static string _0_assigned_tracks_on_the_disc { + get { + return ResourceManager.GetString("_0_assigned_tracks_on_the_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks are {1} and are {2} bytes each. + /// + internal static string _0_blocks_are_1_and_are_2_bytes_each { + get { + return ResourceManager.GetString("_0_blocks_are_1_and_are_2_bytes_each", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks are {1} and have a variable length. + /// + internal static string _0_blocks_are_1_and_have_a_variable_length { + get { + return ResourceManager.GetString("_0_blocks_are_1_and_have_a_variable_length", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks are {1} bytes each. + /// + internal static string _0_blocks_are_1_bytes_each { + get { + return ResourceManager.GetString("_0_blocks_are_1_bytes_each", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks conform to {1} and are {2} bytes each. + /// + internal static string _0_blocks_conform_to_1_and_are_2_bytes_each { + get { + return ResourceManager.GetString("_0_blocks_conform_to_1_and_are_2_bytes_each", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks conform to {1} and have a variable length. + /// + internal static string _0_blocks_conform_to_1_and_have_a_variable_length { + get { + return ResourceManager.GetString("_0_blocks_conform_to_1_and_have_a_variable_length", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks have {1} and are {2} bytes each. + /// + internal static string _0_blocks_have_1_and_are_2_bytes_each { + get { + return ResourceManager.GetString("_0_blocks_have_1_and_are_2_bytes_each", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks have a variable length. + /// + internal static string _0_blocks_have_a_variable_length { + get { + return ResourceManager.GetString("_0_blocks_have_a_variable_length", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes count limit for ATAPI. + /// + internal static string _0_bytes_count_limit_for_ATAPI { + get { + return ResourceManager.GetString("_0_bytes_count_limit_for_ATAPI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes maximum can be transferred before disconnecting. + /// + internal static string _0_bytes_maximum_can_be_transferred_before_disconnecting { + get { + return ResourceManager.GetString("_0_bytes_maximum_can_be_transferred_before_disconnecting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes maximum can be transferred for a command along with the disconnect command. + /// + internal static string _0_bytes_maximum_can_be_transferred_for_a_command_along_with_the_disconnect_command { + get { + return ResourceManager.GetString("_0_bytes_maximum_can_be_transferred_for_a_command_along_with_the_disconnect_comma" + + "nd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per logical block. + /// + internal static string _0_bytes_per_logical_block { + get { + return ResourceManager.GetString("_0_bytes_per_logical_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} Bytes per physical sector. + /// + internal static string _0_Bytes_per_physical_sector { + get { + return ResourceManager.GetString("_0_Bytes_per_physical_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per sector. + /// + internal static string _0_bytes_per_sector { + get { + return ResourceManager.GetString("_0_bytes_per_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per unformatted sector. + /// + internal static string _0_bytes_per_unformatted_sector { + get { + return ResourceManager.GetString("_0_bytes_per_unformatted_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per unformatted track. + /// + internal static string _0_bytes_per_unformatted_track { + get { + return ResourceManager.GetString("_0_bytes_per_unformatted_track", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} current appendable tracks on the disc. + /// + internal static string _0_current_appendable_tracks_on_the_disc { + get { + return ResourceManager.GetString("_0_current_appendable_tracks_on_the_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} cylinders. + /// + internal static string _0_cylinders { + get { + return ResourceManager.GetString("_0_cylinders", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} depth of queue maximum. + /// + internal static string _0_depth_of_queue_maximum { + get { + return ResourceManager.GetString("_0_depth_of_queue_maximum", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} firmware sectors correctly programmed. + /// + internal static string _0_firmware_sectors_correctly_programmed { + get { + return ResourceManager.GetString("_0_firmware_sectors_correctly_programmed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} format layers recognized. + /// + internal static string _0_format_layers_recognized { + get { + return ResourceManager.GetString("_0_format_layers_recognized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free spare blocks. + /// + internal static string _0_free_spare_blocks { + get { + return ResourceManager.GetString("_0_free_spare_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} heads. + /// + internal static string _0_heads { + get { + return ResourceManager.GetString("_0_heads", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} KiB of dual ported multi sector buffer. + /// + internal static string _0_KiB_of_dual_ported_multi_sector_buffer { + get { + return ResourceManager.GetString("_0_KiB_of_dual_ported_multi_sector_buffer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} KiB of dual ported multi sector buffer with read caching. + /// + internal static string _0_KiB_of_dual_ported_multi_sector_buffer_with_read_caching { + get { + return ResourceManager.GetString("_0_KiB_of_dual_ported_multi_sector_buffer_with_read_caching", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} KiB of single ported single sector buffer. + /// + internal static string _0_KiB_of_single_ported_single_sector_buffer { + get { + return ResourceManager.GetString("_0_KiB_of_single_ported_single_sector_buffer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} KiB of unknown type {1} buffer. + /// + internal static string _0_KiB_of_unknown_type_1_buffer { + get { + return ResourceManager.GetString("_0_KiB_of_unknown_type_1_buffer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} logical blocks per media readable unit. + /// + internal static string _0_logical_blocks_per_media_readable_unit { + get { + return ResourceManager.GetString("_0_logical_blocks_per_media_readable_unit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} logical blocks per media writable unit. + /// + internal static string _0_logical_blocks_per_media_writable_unit { + get { + return ResourceManager.GetString("_0_logical_blocks_per_media_writable_unit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} maximum additional partitions. + /// + internal static string _0_maximum_additional_partitions { + get { + return ResourceManager.GetString("_0_maximum_additional_partitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} maximum possible appendable tracks on the disc. + /// + internal static string _0_maximum_possible_appendable_tracks_on_the_disc { + get { + return ResourceManager.GetString("_0_maximum_possible_appendable_tracks_on_the_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} maximum possible tracks on the disc. + /// + internal static string _0_maximum_possible_tracks_on_the_disc { + get { + return ResourceManager.GetString("_0_maximum_possible_tracks_on_the_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} media blocks are required for the binding nonce. + /// + internal static string _0_media_blocks_are_required_for_the_binding_nonce { + get { + return ResourceManager.GetString("_0_media_blocks_are_required_for_the_binding_nonce", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} microseconds of interseek delay for ISO-7779 acoustic testing. + /// + internal static string _0_microseconds_of_interseek_delay_for_ISO_7779_acoustic_testing { + get { + return ResourceManager.GetString("_0_microseconds_of_interseek_delay_for_ISO_7779_acoustic_testing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} minutes to complete enhanced secure erase. + /// + internal static string _0_minutes_to_complete_enhanced_secure_erase { + get { + return ResourceManager.GetString("_0_minutes_to_complete_enhanced_secure_erase", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} minutes to complete secure erase. + /// + internal static string _0_minutes_to_complete_secure_erase { + get { + return ResourceManager.GetString("_0_minutes_to_complete_secure_erase", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} ms before attempting asynchronous event notifications after initialization. + /// + internal static string _0_ms_before_attempting_asynchronous_event_notifications_after_initialization { + get { + return ResourceManager.GetString("_0_ms_before_attempting_asynchronous_event_notifications_after_initialization", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} ns. typical to clear BSY bit from receipt of SERVICE. + /// + internal static string _0_ns_typical_to_clear_BSY_bit_from_receipt_of_SERVICE { + get { + return ResourceManager.GetString("_0_ns_typical_to_clear_BSY_bit_from_receipt_of_SERVICE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} ns. typical to release bus from receipt of PACKET. + /// + internal static string _0_ns_typical_to_release_bus_from_receipt_of_PACKET { + get { + return ResourceManager.GetString("_0_ns_typical_to_release_bus_from_receipt_of_PACKET", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} physical sectors per track. + /// + internal static string _0_physical_sectors_per_track { + get { + return ResourceManager.GetString("_0_physical_sectors_per_track", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} ratio of buffer that shall be empty prior to attempting a reselection. + /// + internal static string _0_ratio_of_buffer_that_shall_be_empty_prior_to_attempting_a_reselection { + get { + return ResourceManager.GetString("_0_ratio_of_buffer_that_shall_be_empty_prior_to_attempting_a_reselection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} ratio of buffer that shall be full prior to attempting a reselection. + /// + internal static string _0_ratio_of_buffer_that_shall_be_full_prior_to_attempting_a_reselection { + get { + return ResourceManager.GetString("_0_ratio_of_buffer_that_shall_be_full_prior_to_attempting_a_reselection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} remaining POW reallocation map entries. + /// + internal static string _0_remaining_POW_reallocation_map_entries { + get { + return ResourceManager.GetString("_0_remaining_POW_reallocation_map_entries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} remaining POW replacements. + /// + internal static string _0_remaining_POW_replacements { + get { + return ResourceManager.GetString("_0_remaining_POW_replacements", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} remaining POW updates. + /// + internal static string _0_remaining_POW_updates { + get { + return ResourceManager.GetString("_0_remaining_POW_updates", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} seconds to complete extended self-test. + /// + internal static string _0_seconds_to_complete_extended_self_test { + get { + return ResourceManager.GetString("_0_seconds_to_complete_extended_self_test", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors between last block of a cylinder and first block of the next one. + /// + internal static string _0_sectors_between_last_block_of_a_cylinder_and_first_block_of_the_next_one { + get { + return ResourceManager.GetString("_0_sectors_between_last_block_of_a_cylinder_and_first_block_of_the_next_one", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors between last block of one track and first block of the next. + /// + internal static string _0_sectors_between_last_block_of_one_track_and_first_block_of_the_next { + get { + return ResourceManager.GetString("_0_sectors_between_last_block_of_one_track_and_first_block_of_the_next", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors for Write/Read/Verify mode 3. + /// + internal static string _0_sectors_for_Write_Read_Verify_mode_three { + get { + return ResourceManager.GetString("_0_sectors_for_Write_Read_Verify_mode_three", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors for Write/Read/Verify mode 2. + /// + internal static string _0_sectors_for_Write_Read_Verify_mode_two { + get { + return ResourceManager.GetString("_0_sectors_for_Write_Read_Verify_mode_two", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors in 28-bit LBA mode. + /// + internal static string _0_sectors_in_28_bit_LBA_mode { + get { + return ResourceManager.GetString("_0_sectors_in_28_bit_LBA_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors in 48-bit LBA mode. + /// + internal static string _0_sectors_in_48_bit_LBA_mode { + get { + return ResourceManager.GetString("_0_sectors_in_48_bit_LBA_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors in card. + /// + internal static string _0_sectors_in_card { + get { + return ResourceManager.GetString("_0_sectors_in_card", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors per track. + /// + internal static string _0_sectors_per_track { + get { + return ResourceManager.GetString("_0_sectors_per_track", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors per zone that shall be reserved for defect handling. + /// + internal static string _0_sectors_per_zone_that_shall_be_reserved_for_defect_handling { + get { + return ResourceManager.GetString("_0_sectors_per_zone_that_shall_be_reserved_for_defect_handling", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} tracks per LUN that shall be reserved for defect handling. + /// + internal static string _0_tracks_per_LUN_that_shall_be_reserved_for_defect_handling { + get { + return ResourceManager.GetString("_0_tracks_per_LUN_that_shall_be_reserved_for_defect_handling", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} tracks per zone that shall be reserved for defect handling. + /// + internal static string _0_tracks_per_zone_that_shall_be_reserved_for_defect_handling { + get { + return ResourceManager.GetString("_0_tracks_per_zone_that_shall_be_reserved_for_defect_handling", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors. + /// + internal static string _0_tracks_per_zone_to_use_in_dividing_the_capacity_for_the_purpose_of_allocating_alternate_sectors { + get { + return ResourceManager.GetString("_0_tracks_per_zone_to_use_in_dividing_the_capacity_for_the_purpose_of_allocating_" + + "alternate_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} unused primary spare blocks. + /// + internal static string _0_unused_primary_spare_blocks { + get { + return ResourceManager.GetString("_0_unused_primary_spare_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} unused supplementary spare blocks. + /// + internal static string _0_unused_supplementary_spare_blocks { + get { + return ResourceManager.GetString("_0_unused_supplementary_spare_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} wraps. + /// + internal static string _0_wraps { + get { + return ResourceManager.GetString("_0_wraps", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} µs allowed to use the bus before disconnecting, if granted the privilege and not restricted. + /// + internal static string _0_µs_allowed_to_use_the_bus_before_disconnecting_if_granted_the_privilege_and_not_restricted { + get { + return ResourceManager.GetString("_0_µs_allowed_to_use_the_bus_before_disconnecting_if_granted_the_privilege_and_no" + + "t_restricted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} µs maximum permitted to assert BSY without a REQ/ACK handshake. + /// + internal static string _0_µs_maximum_permitted_to_assert_BSY_without_a_REQ_ACK_handshake { + get { + return ResourceManager.GetString("_0_µs_maximum_permitted_to_assert_BSY_without_a_REQ_ACK_handshake", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} µs maximum permitted wait after releasing the bus before attempting reselection. + /// + internal static string _0_µs_maximum_permitted_wait_after_releasing_the_bus_before_attempting_reselection { + get { + return ResourceManager.GetString("_0_µs_maximum_permitted_wait_after_releasing_the_bus_before_attempting_reselectio" + + "n", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120mm. + /// + internal static string _120mm { + get { + return ResourceManager.GetString("_120mm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 13262 flux transitions per radian. + /// + internal static string _13262_ftprad { + get { + return ResourceManager.GetString("_13262_ftprad", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 15916 flux transitions per radian. + /// + internal static string _15916_ftprad { + get { + return ResourceManager.GetString("_15916_ftprad", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 1997 or 2013. + /// + internal static string _1997_or_2013 { + get { + return ResourceManager.GetString("_1997_or_2013", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 1998 or 2014. + /// + internal static string _1998_or_2014 { + get { + return ResourceManager.GetString("_1998_or_2014", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 1999 or 2015. + /// + internal static string _1999_or_2015 { + get { + return ResourceManager.GetString("_1999_or_2015", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2000 or 2016. + /// + internal static string _2000_or_2016 { + get { + return ResourceManager.GetString("_2000_or_2016", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2001 or 2017. + /// + internal static string _2001_or_2017 { + get { + return ResourceManager.GetString("_2001_or_2017", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2002 or 2018. + /// + internal static string _2002_or_2018 { + get { + return ResourceManager.GetString("_2002_or_2018", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2003 or 2019. + /// + internal static string _2003_or_2019 { + get { + return ResourceManager.GetString("_2003_or_2019", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2004 or 2020. + /// + internal static string _2004_or_2020 { + get { + return ResourceManager.GetString("_2004_or_2020", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2005 or 2021. + /// + internal static string _2005_or_2021 { + get { + return ResourceManager.GetString("_2005_or_2021", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2006 or 2022. + /// + internal static string _2006_or_2022 { + get { + return ResourceManager.GetString("_2006_or_2022", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2007 or 2023. + /// + internal static string _2007_or_2023 { + get { + return ResourceManager.GetString("_2007_or_2023", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2008 or 2024. + /// + internal static string _2008_or_2024 { + get { + return ResourceManager.GetString("_2008_or_2024", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2009 or 2025. + /// + internal static string _2009_or_2025 { + get { + return ResourceManager.GetString("_2009_or_2025", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 28-bit LBA is supported. + /// + internal static string _28_bit_LBA_is_supported { + get { + return ResourceManager.GetString("_28_bit_LBA_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 48-bit LBA is supported. + /// + internal static string _48_bit_LBA_is_supported { + get { + return ResourceManager.GetString("_48_bit_LBA_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 48-bit LBA is supported and enabled. + /// + internal static string _48_bit_LBA_is_supported_and_enabled { + get { + return ResourceManager.GetString("_48_bit_LBA_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 4-byte tag, user data plus auxiliary data. + /// + internal static string _4byte_tag_user_data_plus_auxiliary_data { + get { + return ResourceManager.GetString("_4byte_tag_user_data_plus_auxiliary_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 60mm. + /// + internal static string _60mm { + get { + return ResourceManager.GetString("_60mm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 7958 flux transitions per radian. + /// + internal static string _7958_ftprad { + get { + return ResourceManager.GetString("_7958_ftprad", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80mm. + /// + internal static string _80mm { + get { + return ResourceManager.GetString("_80mm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (active) . + /// + internal static string _active_ { + get { + return ResourceManager.GetString("_active_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to a combination of read-only and erasable optical. + /// + internal static string a_combination_of_read_only_and_erasable_optical { + get { + return ResourceManager.GetString("a_combination_of_read_only_and_erasable_optical", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to a combination of write-once and erasable optical. + /// + internal static string a_combination_of_write_once_and_erasable_optical { + get { + return ResourceManager.GetString("a_combination_of_write_once_and_erasable_optical", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A maximum of {0} blocks will be pre-fetched. + /// + internal static string A_maximum_of_0_blocks_will_be_pre_fetched { + get { + return ResourceManager.GetString("A_maximum_of_0_blocks_will_be_pre_fetched", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A maximum of {0} blocks will be pre-fetched even if it is commanded to pre-fetch more. + /// + internal static string A_maximum_of_0_blocks_will_be_pre_fetched_even_if_it_is_commanded_to_pre_fetch_more { + get { + return ResourceManager.GetString("A_maximum_of_0_blocks_will_be_pre_fetched_even_if_it_is_commanded_to_pre_fetch_mo" + + "re", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A maximum of {0} ms are allowed to remain busy. + /// + internal static string A_maximum_of_0_ms_are_allowed_to_remain_busy { + get { + return ResourceManager.GetString("A_maximum_of_0_ms_are_allowed_to_remain_busy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A maximum of {0} sectors can be transferred per interrupt on READ/WRITE MULTIPLE. + /// + internal static string A_maximum_of_0_sectors_can_be_transferred_per_interrupt_on_READ_WRITE_MULTIPLE { + get { + return ResourceManager.GetString("A_maximum_of_0_sectors_can_be_transferred_per_interrupt_on_READ_WRITE_MULTIPLE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A test informational exception will raise on next timer. + /// + internal static string A_test_informational_exception_will_raise_on_next_timer { + get { + return ResourceManager.GetString("A_test_informational_exception_will_raise_on_next_timer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A1 value: 0x{0:X6}. + /// + internal static string A1_value_0 { + get { + return ResourceManager.GetString("A1_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A2 value: 0x{0:X6}. + /// + internal static string A2_value_0 { + get { + return ResourceManager.GetString("A2_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A3 value: 0x{0:X6}. + /// + internal static string A3_value_0 { + get { + return ResourceManager.GetString("A3_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AACS Data Keys in hex follows:. + /// + internal static string AACS_Data_Keys_in_hex_follows { + get { + return ResourceManager.GetString("AACS_Data_Keys_in_hex_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AACS Media Identifier in hex follows:. + /// + internal static string AACS_Media_Identifier_in_hex_follows { + get { + return ResourceManager.GetString("AACS_Media_Identifier_in_hex_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AACS Media Key Blocks in hex follows:. + /// + internal static string AACS_Media_Key_Blocks_in_hex_follows { + get { + return ResourceManager.GetString("AACS_Media_Key_Blocks_in_hex_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AACS Media Serial Number in hex follows:. + /// + internal static string AACS_Media_Serial_Number_in_hex_follows { + get { + return ResourceManager.GetString("AACS_Media_Serial_Number_in_hex_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AACS Volume Identifier in hex follows:. + /// + internal static string AACS_Volume_Identifier_in_hex_follows { + get { + return ResourceManager.GetString("AACS_Volume_Identifier_in_hex_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Abort any write command without protection information. + /// + internal static string Abort_any_write_command_without_protection_information { + get { + return ResourceManager.GetString("Abort_any_write_command_without_protection_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Absolute time: {0:D2}:{1:D2}:{2:D2}. + /// + internal static string Absolute_time_0_1_2 { + get { + return ResourceManager.GetString("Absolute_time_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Absolute time: {3:D2}:{0:D2}:{1:D2}:{2:D2}. + /// + internal static string Absolute_time_3_0_1_2 { + get { + return ResourceManager.GetString("Absolute_time_3_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Accessible Max Address Configuration is supported. + /// + internal static string Accessible_Max_Address_Configuration_is_supported { + get { + return ResourceManager.GetString("Accessible_Max_Address_Configuration_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Accessible Max Address Configuration is supported and enabled. + /// + internal static string Accessible_Max_Address_Configuration_is_supported_and_enabled { + get { + return ResourceManager.GetString("Accessible_Max_Address_Configuration_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ACS-2 published, ANSI INCITS 482-2012. + /// + internal static string ACS_2_published_ANSI_INCITS_482_2012 { + get { + return ResourceManager.GetString("ACS_2_published_ANSI_INCITS_482_2012", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ACS-2 Revision 2. + /// + internal static string ACS_2_Revision_2 { + get { + return ResourceManager.GetString("ACS_2_Revision_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ACS-2 Revision 3. + /// + internal static string ACS_2_Revision_3 { + get { + return ResourceManager.GetString("ACS_2_Revision_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ACS-3 Revision 3b. + /// + internal static string ACS_3_Revision_3b { + get { + return ResourceManager.GetString("ACS_3_Revision_3b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ACS-3 Revision 4. + /// + internal static string ACS_3_Revision_4 { + get { + return ResourceManager.GetString("ACS_3_Revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ACS-3 Revision 5. + /// + internal static string ACS_3_Revision_5 { + get { + return ResourceManager.GetString("ACS_3_Revision_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Active format: {0}. + /// + internal static string Active_format_0 { + get { + return ResourceManager.GetString("Active_format_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Active partition: {0}. + /// + internal static string Active_partition_0 { + get { + return ResourceManager.GetString("Active_partition_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Actual retry count is {0}. + /// + internal static string Actual_retry_count_is_0 { + get { + return ResourceManager.GetString("Actual_retry_count_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Adding sector {0} of track {1}. + /// + internal static string Adding_sector_0_of_track_1 { + get { + return ResourceManager.GetString("Adding_sector_0_of_track_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Additional information:. + /// + internal static string Additional_information { + get { + return ResourceManager.GetString("Additional_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Additional product ID: {0}. + /// + internal static string Additional_product_ID_0 { + get { + return ResourceManager.GetString("Additional_product_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address for administrative configuration service: {0}. + /// + internal static string Address_for_administrative_configuration_service_0 { + get { + return ResourceManager.GetString("Address_for_administrative_configuration_service_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address for code download: {0}. + /// + internal static string Address_for_code_download_0 { + get { + return ResourceManager.GetString("Address_for_code_download_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address for copy service: {0}. + /// + internal static string Address_for_copy_service_0 { + get { + return ResourceManager.GetString("Address_for_copy_service_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address for diagnostics: {0}. + /// + internal static string Address_for_diagnostics_0 { + get { + return ResourceManager.GetString("Address_for_diagnostics_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address for logging: {0}. + /// + internal static string Address_for_logging_0 { + get { + return ResourceManager.GetString("Address_for_logging_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address for status: {0}. + /// + internal static string Address_for_status_0 { + get { + return ResourceManager.GetString("Address_for_status_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address for storage configuration service: {0}. + /// + internal static string Address_for_storage_configuration_service_0 { + get { + return ResourceManager.GetString("Address_for_storage_configuration_service_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address of unknown type {1}: {0}. + /// + internal static string Address_of_unknown_type_1_0 { + get { + return ResourceManager.GetString("Address_of_unknown_type_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address Offset Reserved Area Boot is supported. + /// + internal static string Address_Offset_Reserved_Area_Boot_is_supported { + get { + return ResourceManager.GetString("Address_Offset_Reserved_Area_Boot_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address Offset Reserved Area Boot is supported and enabled. + /// + internal static string Address_Offset_Reserved_Area_Boot_is_supported_and_enabled { + get { + return ResourceManager.GetString("Address_Offset_Reserved_Area_Boot_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Advanced PIO: . + /// + internal static string Advanced_PIO { + get { + return ResourceManager.GetString("Advanced_PIO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Advanced Power Management is supported. + /// + internal static string Advanced_Power_Management_is_supported { + get { + return ResourceManager.GetString("Advanced_Power_Management_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Advanced Power Management is supported and enabled with value {0}. + /// + internal static string Advanced_Power_Management_is_supported_and_enabled_with_value_0 { + get { + return ResourceManager.GetString("Advanced_Power_Management_is_supported_and_enabled_with_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Affected commands in the task set belonging with the CHECK CONDITION nexus shall be aborted. + /// + internal static string Affected_commands_in_the_task_set_belonging_with_the_CHECK_CONDITION_nexus_shall_be_aborted { + get { + return ResourceManager.GetString("Affected_commands_in_the_task_set_belonging_with_the_CHECK_CONDITION_nexus_shall_" + + "be_aborted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AIT-1. + /// + internal static string AIT1 { + get { + return ResourceManager.GetString("AIT1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AIT-2. + /// + internal static string AIT2 { + get { + return ResourceManager.GetString("AIT2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AIT-3. + /// + internal static string AIT3 { + get { + return ResourceManager.GetString("AIT3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to album. + /// + internal static string album { + get { + return ResourceManager.GetString("album", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Alerts are enabled. + /// + internal static string Alerts_are_enabled { + get { + return ResourceManager.GetString("Alerts_are_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All available recovery procedures will be used.. + /// + internal static string All_available_recovery_procedures_will_be_used { + get { + return ResourceManager.GetString("All_available_recovery_procedures_will_be_used", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All data and the response for a command shall be transferred within a single interconnect tenancy. + /// + internal static string All_data_and_the_response_for_a_command_shall_be_transferred_within_a_single_interconnect_tenancy { + get { + return ResourceManager.GetString("All_data_and_the_response_for_a_command_shall_be_transferred_within_a_single_inte" + + "rconnect_tenancy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All data for a command shall be transferred within a single interconnect tenancy. + /// + internal static string All_data_for_a_command_shall_be_transferred_within_a_single_interconnect_tenancy { + get { + return ResourceManager.GetString("All_data_for_a_command_shall_be_transferred_within_a_single_interconnect_tenancy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All remaining blocks are {0} and are {1} bytes each. + /// + internal static string All_remaining_blocks_are_0_and_are_1_bytes_each { + get { + return ResourceManager.GetString("All_remaining_blocks_are_0_and_are_1_bytes_each", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All remaining blocks are {0} and have a variable length. + /// + internal static string All_remaining_blocks_are_0_and_have_a_variable_length { + get { + return ResourceManager.GetString("All_remaining_blocks_are_0_and_have_a_variable_length", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All remaining blocks are {0} bytes each. + /// + internal static string All_remaining_blocks_are_0_bytes_each { + get { + return ResourceManager.GetString("All_remaining_blocks_are_0_bytes_each", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All remaining blocks conform to {0} and are {1} bytes each. + /// + internal static string All_remaining_blocks_conform_to_0_and_are_1_bytes_each { + get { + return ResourceManager.GetString("All_remaining_blocks_conform_to_0_and_are_1_bytes_each", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All remaining blocks conform to {0} and have a variable length. + /// + internal static string All_remaining_blocks_conform_to_0_and_have_a_variable_length { + get { + return ResourceManager.GetString("All_remaining_blocks_conform_to_0_and_have_a_variable_length", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All remaining blocks have {0} and are {1} bytes each. + /// + internal static string All_remaining_blocks_have_0_and_are_1_bytes_each { + get { + return ResourceManager.GetString("All_remaining_blocks_have_0_and_are_1_bytes_each", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All remaining blocks have a variable length. + /// + internal static string All_remaining_blocks_have_a_variable_length { + get { + return ResourceManager.GetString("All_remaining_blocks_have_a_variable_length", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate. + /// + internal static string All_tasks_received_in_nexus_with_ACA_ACTIVE_is_set_and_an_ACA_condition_is_established_shall_terminate { + get { + return ResourceManager.GetString("All_tasks_received_in_nexus_with_ACA_ACTIVE_is_set_and_an_ACA_condition_is_establ" + + "ished_shall_terminate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All the affected commands in the task set shall be aborted when CHECK CONDITION is returned. + /// + internal static string All_the_affected_commands_in_the_task_set_shall_be_aborted_when_CHECK_CONDITION_is_returned { + get { + return ResourceManager.GetString("All_the_affected_commands_in_the_task_set_shall_be_aborted_when_CHECK_CONDITION_i" + + "s_returned", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Always apply the verify operation. + /// + internal static string Always_apply_the_verify_operation { + get { + return ResourceManager.GetString("Always_apply_the_verify_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to an unknown algorithm coded {0}. + /// + internal static string an_unknown_algorithm_coded_0 { + get { + return ResourceManager.GetString("an_unknown_algorithm_coded_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to an unknown medium type 0x{0:X2}. + /// + internal static string an_unknown_medium_type_0 { + get { + return ResourceManager.GetString("an_unknown_medium_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to an unregistered compression algorithm. + /// + internal static string an_unregistered_compression_algorithm { + get { + return ResourceManager.GetString("an_unregistered_compression_algorithm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Application ID: {0}. + /// + internal static string Application_ID_0 { + get { + return ResourceManager.GetString("Application_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Application Tag mode page is enabled. + /// + internal static string Application_Tag_mode_page_is_enabled { + get { + return ResourceManager.GetString("Application_Tag_mode_page_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Apply the verify operation depending on the condition. + /// + internal static string Apply_the_verify_operation_depending_on_the_condition { + get { + return ResourceManager.GetString("Apply_the_verify_operation_depending_on_the_condition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array controller device. + /// + internal static string Array_controller_device { + get { + return ResourceManager.GetString("Array_controller_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ASC {0:X2}h WITH ASCQ {1:X2}h. + /// + internal static string ASC_0_WITH_ASCQ_1 { + get { + return ResourceManager.GetString("ASC_0_WITH_ASCQ_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ASC {0:X2}h WITH VENDOR-SPECIFIC ASCQ {1:X2}h. + /// + internal static string ASC_0_WITH_VENDOR_SPECIFIC_ASCQ_1 { + get { + return ResourceManager.GetString("ASC_0_WITH_VENDOR_SPECIFIC_ASCQ_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Asia NTSC.. + /// + internal static string Asia_NTSC { + get { + return ResourceManager.GetString("Asia_NTSC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Associated write protect is enabled. + /// + internal static string Associated_write_protect_is_enabled { + get { + return ResourceManager.GetString("Associated_write_protect_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Asynchronous data access time is {0}{1}. + /// + internal static string Asynchronous_data_access_time_is_0_1 { + get { + return ResourceManager.GetString("Asynchronous_data_access_time_is_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Asynchronous event reporting of informational exceptions. + /// + internal static string Asynchronous_event_reporting_of_informational_exceptions { + get { + return ResourceManager.GetString("Asynchronous_event_reporting_of_informational_exceptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Asynchronous notification is supported. + /// + internal static string Asynchronous_notification_is_supported { + get { + return ResourceManager.GetString("Asynchronous_notification_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Asynchronous notification is supported and enabled. + /// + internal static string Asynchronous_notification_is_supported_and_enabled { + get { + return ResourceManager.GetString("Asynchronous_notification_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AT Attachment Interface (ATA/ATAPI). + /// + internal static string AT_Attachment_Interface__ATA_ATAPI_ { + get { + return ResourceManager.GetString("AT_Attachment_Interface__ATA_ATAPI_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At least {0} blocks will be always pre-fetched. + /// + internal static string At_least_0_blocks_will_be_always_pre_fetched { + get { + return ResourceManager.GetString("At_least_0_blocks_will_be_always_pre_fetched", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At least {0} ms must be idle before resuming a suspended background scan operation. + /// + internal static string At_least_0_ms_must_be_idle_before_resuming_a_suspended_background_scan_operation { + get { + return ResourceManager.GetString("At_least_0_ms_must_be_idle_before_resuming_a_suspended_background_scan_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to at maximum volume. + /// + internal static string at_maximum_volume { + get { + return ResourceManager.GetString("at_maximum_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At minimum {0} ns. transfer cycle time per word in MDMA, {1} ns. recommended. + /// + internal static string At_minimum_0_ns_transfer_cycle_time_per_word_in_MDMA_1_ns_recommended { + get { + return ResourceManager.GetString("At_minimum_0_ns_transfer_cycle_time_per_word_in_MDMA_1_ns_recommended", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At minimum {0} ns. transfer cycle time per word in PIO, with IORDY flow control. + /// + internal static string At_minimum_0_ns_transfer_cycle_time_per_word_in_PIO_with_IORDY_flow_control { + get { + return ResourceManager.GetString("At_minimum_0_ns_transfer_cycle_time_per_word_in_PIO_with_IORDY_flow_control", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At minimum {0} ns. transfer cycle time per word in PIO, without flow control. + /// + internal static string At_minimum_0_ns_transfer_cycle_time_per_word_in_PIO_without_flow_control { + get { + return ResourceManager.GetString("At_minimum_0_ns_transfer_cycle_time_per_word_in_PIO_without_flow_control", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At most {0} ms must be before suspending a background scan operation and processing received commands. + /// + internal static string At_most_0_ms_must_be_before_suspending_a_background_scan_operation_and_processing_received_commands { + get { + return ResourceManager.GetString("At_most_0_ms_must_be_before_suspending_a_background_scan_operation_and_processing" + + "_received_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to at volume {0}. + /// + internal static string at_volume_0 { + get { + return ResourceManager.GetString("at_volume_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA-1 published, ANSI X3.221-1994. + /// + internal static string ATA_1_published_ANSI_X3_221_1994 { + get { + return ResourceManager.GetString("ATA_1_published_ANSI_X3_221_1994", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA-2 published, ANSI X3.279-1996. + /// + internal static string ATA_2_published_ANSI_X3_279_1996 { + get { + return ResourceManager.GetString("ATA_2_published_ANSI_X3_279_1996", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA-2 X3T10 948D prior to revision 2k. + /// + internal static string ATA_2_X3T10_948D_prior_to_revision_2k { + get { + return ResourceManager.GetString("ATA_2_X3T10_948D_prior_to_revision_2k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA-2 X3T10 948D revision 2k. + /// + internal static string ATA_2_X3T10_948D_revision_2k { + get { + return ResourceManager.GetString("ATA_2_X3T10_948D_revision_2k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA-2 X3T10 948D revision 3. + /// + internal static string ATA_2_X3T10_948D_revision_3 { + get { + return ResourceManager.GetString("ATA_2_X3T10_948D_revision_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA-3 published, ANSI X3.298-1997. + /// + internal static string ATA_3_published_ANSI_X3_298_1997 { + get { + return ResourceManager.GetString("ATA_3_published_ANSI_X3_298_1997", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA-3 X3T10 2008D revision 0. + /// + internal static string ATA_3_X3T10_2008D_revision_0 { + get { + return ResourceManager.GetString("ATA_3_X3T10_2008D_revision_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA-3 X3T10 2008D revision 1. + /// + internal static string ATA_3_X3T10_2008D_revision_1 { + get { + return ResourceManager.GetString("ATA_3_X3T10_2008D_revision_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA-3 X3T10 2008D revision 6. + /// + internal static string ATA_3_X3T10_2008D_revision_6 { + get { + return ResourceManager.GetString("ATA_3_X3T10_2008D_revision_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA-3 X3T13 2008D revision 7. + /// + internal static string ATA_3_X3T13_2008D_revision_7 { + get { + return ResourceManager.GetString("ATA_3_X3T13_2008D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA (ATA-1) X3T9.2 781D prior to revision 4. + /// + internal static string ATA_ATA_1_X3T9_2_781D_prior_to_revision_4 { + get { + return ResourceManager.GetString("ATA_ATA_1_X3T9_2_781D_prior_to_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA (ATA-1) X3T9.2 781D revision 4. + /// + internal static string ATA_ATA_1_X3T9_2_781D_revision_4 { + get { + return ResourceManager.GetString("ATA_ATA_1_X3T9_2_781D_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-4 published, ANSI INCITS 317-1998. + /// + internal static string ATA_ATAPI_4_published_ANSI_INCITS_317_1998 { + get { + return ResourceManager.GetString("ATA_ATAPI_4_published_ANSI_INCITS_317_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-4 T13 1153D revision 13. + /// + internal static string ATA_ATAPI_4_T13_1153D_revision_13 { + get { + return ResourceManager.GetString("ATA_ATAPI_4_T13_1153D_revision_13", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-4 T13 1153D revision 14. + /// + internal static string ATA_ATAPI_4_T13_1153D_revision_14 { + get { + return ResourceManager.GetString("ATA_ATAPI_4_T13_1153D_revision_14", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-4 T13 1153D revision 15. + /// + internal static string ATA_ATAPI_4_T13_1153D_revision_15 { + get { + return ResourceManager.GetString("ATA_ATAPI_4_T13_1153D_revision_15", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-4 T13 1153D revision 17. + /// + internal static string ATA_ATAPI_4_T13_1153D_revision_17 { + get { + return ResourceManager.GetString("ATA_ATAPI_4_T13_1153D_revision_17", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-4 T13 1153D revision 18. + /// + internal static string ATA_ATAPI_4_T13_1153D_revision_18 { + get { + return ResourceManager.GetString("ATA_ATAPI_4_T13_1153D_revision_18", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-4 X3T13 1153D revision 6. + /// + internal static string ATA_ATAPI_4_X3T13_1153D_revision_6 { + get { + return ResourceManager.GetString("ATA_ATAPI_4_X3T13_1153D_revision_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-4 X3T13 1153D revision 7. + /// + internal static string ATA_ATAPI_4_X3T13_1153D_revision_7 { + get { + return ResourceManager.GetString("ATA_ATAPI_4_X3T13_1153D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-5 published, ANSI INCITS 340-2000. + /// + internal static string ATA_ATAPI_5_published_ANSI_INCITS_340_2000 { + get { + return ResourceManager.GetString("ATA_ATAPI_5_published_ANSI_INCITS_340_2000", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-5 T13 1321D revision 1. + /// + internal static string ATA_ATAPI_5_T13_1321D_revision_1 { + get { + return ResourceManager.GetString("ATA_ATAPI_5_T13_1321D_revision_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-5 T13 1321D revision 3. + /// + internal static string ATA_ATAPI_5_T13_1321D_revision_3 { + get { + return ResourceManager.GetString("ATA_ATAPI_5_T13_1321D_revision_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-6 published, ANSI INCITS 361-2002. + /// + internal static string ATA_ATAPI_6_published_ANSI_INCITS_361_2002 { + get { + return ResourceManager.GetString("ATA_ATAPI_6_published_ANSI_INCITS_361_2002", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-6 T13 1410D revision 0. + /// + internal static string ATA_ATAPI_6_T13_1410D_revision_0 { + get { + return ResourceManager.GetString("ATA_ATAPI_6_T13_1410D_revision_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-6 T13 1410D revision 1. + /// + internal static string ATA_ATAPI_6_T13_1410D_revision_1 { + get { + return ResourceManager.GetString("ATA_ATAPI_6_T13_1410D_revision_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-6 T13 1410D revision 2. + /// + internal static string ATA_ATAPI_6_T13_1410D_revision_2 { + get { + return ResourceManager.GetString("ATA_ATAPI_6_T13_1410D_revision_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-6 T13 1410D revision 3a. + /// + internal static string ATA_ATAPI_6_T13_1410D_revision_3a { + get { + return ResourceManager.GetString("ATA_ATAPI_6_T13_1410D_revision_3a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-7 published ANSI INCITS 397-2005. + /// + internal static string ATA_ATAPI_7_published_ANSI_INCITS_397_2005 { + get { + return ResourceManager.GetString("ATA_ATAPI_7_published_ANSI_INCITS_397_2005", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-7 T13 1532D revision 0. + /// + internal static string ATA_ATAPI_7_T13_1532D_revision_0 { + get { + return ResourceManager.GetString("ATA_ATAPI_7_T13_1532D_revision_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-7 T13 1532D revision 1. + /// + internal static string ATA_ATAPI_7_T13_1532D_revision_1 { + get { + return ResourceManager.GetString("ATA_ATAPI_7_T13_1532D_revision_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA/ATAPI-7 T13 1532D revision 4a. + /// + internal static string ATA_ATAPI_7_T13_1532D_revision_4a { + get { + return ResourceManager.GetString("ATA_ATAPI_7_T13_1532D_revision_4a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA device. + /// + internal static string ATA_device { + get { + return ResourceManager.GetString("ATA_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA IDENTIFY information follows:. + /// + internal static string ATA_IDENTIFY_information_follows { + get { + return ResourceManager.GetString("ATA_IDENTIFY_information_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA8-ACS Revision 2d. + /// + internal static string ATA8_ACS_revision_2d { + get { + return ResourceManager.GetString("ATA8_ACS_revision_2d", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA8-ACS Revision 3b. + /// + internal static string ATA8_ACS_revision_3b { + get { + return ResourceManager.GetString("ATA8_ACS_revision_3b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA8-ACS Revision 3c. + /// + internal static string ATA8_ACS_revision_3c { + get { + return ResourceManager.GetString("ATA8_ACS_revision_3c", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA8-ACS Revision 3e. + /// + internal static string ATA8_ACS_Revision_3e { + get { + return ResourceManager.GetString("ATA8_ACS_Revision_3e", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA8-ACS Revision 3f. + /// + internal static string ATA8_ACS_Revision_3f { + get { + return ResourceManager.GetString("ATA8_ACS_Revision_3f", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA8-ACS Revision 4. + /// + internal static string ATA8_ACS_revision_4 { + get { + return ResourceManager.GetString("ATA8_ACS_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA8-ACS Revision 4c. + /// + internal static string ATA8_ACS_Revision_4c { + get { + return ResourceManager.GetString("ATA8_ACS_Revision_4c", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATA8-ACS Revision 6. + /// + internal static string ATA8_ACS_revision_6 { + get { + return ResourceManager.GetString("ATA8_ACS_revision_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Array controller device. + /// + internal static string ATAPI_Array_controller_device { + get { + return ResourceManager.GetString("ATAPI_Array_controller_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Automation/Drive Interface. + /// + internal static string ATAPI_Automation_Drive_Interface { + get { + return ResourceManager.GetString("ATAPI_Automation_Drive_Interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Bridging Expanders. + /// + internal static string ATAPI_Bridging_Expanders { + get { + return ResourceManager.GetString("ATAPI_Bridging_Expanders", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI CD-ROM/DVD/etc device. + /// + internal static string ATAPI_CD_ROM_DVD_etc_device { + get { + return ResourceManager.GetString("ATAPI_CD_ROM_DVD_etc_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Communications device. + /// + internal static string ATAPI_Communications_device { + get { + return ResourceManager.GetString("ATAPI_Communications_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI device. + /// + internal static string ATAPI_device { + get { + return ResourceManager.GetString("ATAPI_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI device requires ATA software reset. + /// + internal static string ATAPI_device_requires_ATA_software_reset { + get { + return ResourceManager.GetString("ATAPI_device_requires_ATA_software_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI device supports attention on slimline connected devices. + /// + internal static string ATAPI_device_supports_attention_on_slimline_connected_devices { + get { + return ResourceManager.GetString("ATAPI_device_supports_attention_on_slimline_connected_devices", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI device supports command queueing. + /// + internal static string ATAPI_device_supports_command_queueing { + get { + return ResourceManager.GetString("ATAPI_device_supports_command_queueing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI device supports host environment detection. + /// + internal static string ATAPI_device_supports_host_environment_detection { + get { + return ResourceManager.GetString("ATAPI_device_supports_host_environment_detection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI device supports interleaved DMA. + /// + internal static string ATAPI_device_supports_interleaved_DMA { + get { + return ResourceManager.GetString("ATAPI_device_supports_interleaved_DMA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI device supports overlapped operations. + /// + internal static string ATAPI_device_supports_overlapped_operations { + get { + return ResourceManager.GetString("ATAPI_device_supports_overlapped_operations", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI device uses 12 byte command packet. + /// + internal static string ATAPI_device_uses_12_byte_command_packet { + get { + return ResourceManager.GetString("ATAPI_device_uses_12_byte_command_packet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI device uses 16 byte command packet. + /// + internal static string ATAPI_device_uses_16_byte_command_packet { + get { + return ResourceManager.GetString("ATAPI_device_uses_16_byte_command_packet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Direct-access device. + /// + internal static string ATAPI_Direct_access_device { + get { + return ResourceManager.GetString("ATAPI_Direct_access_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Enclosure services device. + /// + internal static string ATAPI_Enclosure_services_device { + get { + return ResourceManager.GetString("ATAPI_Enclosure_services_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Graphics arts pre-press device (defined in ASC IT8). + /// + internal static string ATAPI_Graphics_arts_pre_press_device_defined_in_ASC_IT8 { + get { + return ResourceManager.GetString("ATAPI_Graphics_arts_pre_press_device_defined_in_ASC_IT8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Medium change device. + /// + internal static string ATAPI_Medium_change_device { + get { + return ResourceManager.GetString("ATAPI_Medium_change_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Object-based Storage Device. + /// + internal static string ATAPI_Object_based_Storage_Device { + get { + return ResourceManager.GetString("ATAPI_Object_based_Storage_Device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Optical card reader/writer device. + /// + internal static string ATAPI_Optical_card_reader_writer_device { + get { + return ResourceManager.GetString("ATAPI_Optical_card_reader_writer_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Optical memory device. + /// + internal static string ATAPI_Optical_memory_device { + get { + return ResourceManager.GetString("ATAPI_Optical_memory_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Printer device. + /// + internal static string ATAPI_Printer_device { + get { + return ResourceManager.GetString("ATAPI_Printer_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Processor device. + /// + internal static string ATAPI_Processor_device { + get { + return ResourceManager.GetString("ATAPI_Processor_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Scanner device. + /// + internal static string ATAPI_Scanner_device { + get { + return ResourceManager.GetString("ATAPI_Scanner_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Sequential-access device. + /// + internal static string ATAPI_Sequential_access_device { + get { + return ResourceManager.GetString("ATAPI_Sequential_access_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Simplified direct-access device. + /// + internal static string ATAPI_Simplified_direct_access_device { + get { + return ResourceManager.GetString("ATAPI_Simplified_direct_access_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Unknown device type field value 0x{0:X2}. + /// + internal static string ATAPI_Unknown_device_type_field_value_0 { + get { + return ResourceManager.GetString("ATAPI_Unknown_device_type_field_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Unknown or no device type. + /// + internal static string ATAPI_Unknown_or_no_device_type { + get { + return ResourceManager.GetString("ATAPI_Unknown_or_no_device_type", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Well known logical unit. + /// + internal static string ATAPI_Well_known_logical_unit { + get { + return ResourceManager.GetString("ATAPI_Well_known_logical_unit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATAPI Write-once device. + /// + internal static string ATAPI_Write_once_device { + get { + return ResourceManager.GetString("ATAPI_Write_once_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATIP Last possible start time of Lead-out: 0x{0:X6}. + /// + internal static string ATIP_Last_possible_start_time_of_Lead_out_0 { + get { + return ResourceManager.GetString("ATIP_Last_possible_start_time_of_Lead_out_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATIP Last possible start time of Lead-out: {0}:{1:D2}:{2:D2}. + /// + internal static string ATIP_Last_possible_start_time_of_Lead_out_0_1_2 { + get { + return ResourceManager.GetString("ATIP_Last_possible_start_time_of_Lead_out_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATIP Start time of Lead-in: 0x{0:X6}. + /// + internal static string ATIP_Start_time_of_Lead_in_0 { + get { + return ResourceManager.GetString("ATIP_Start_time_of_Lead_in_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ATIP Start time of Lead-in: {0}:{1:D2}:{2:D2}. + /// + internal static string ATIP_Start_time_of_Lead_in_0_1_2 { + get { + return ResourceManager.GetString("ATIP_Start_time_of_Lead_in_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Audio block.. + /// + internal static string Audio_block { + get { + return ResourceManager.GetString("Audio_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to audio information only. + /// + internal static string audio_information_only { + get { + return ResourceManager.GetString("audio_information_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Audio track {3} starts at: {0:D2}:{1:D2}:{2:D2} (. + /// + internal static string Audio_track_3_starts_at_0_1_2_open_parenthesis { + get { + return ResourceManager.GetString("Audio_track_3_starts_at_0_1_2_open_parenthesis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Audio track {3} starts at: {4:D2}:{0:D2}:{1:D2}:{2:D2} (. + /// + internal static string Audio_track_3_starts_at_4_0_1_2_open_parenthesis { + get { + return ResourceManager.GetString("Audio_track_3_starts_at_4_0_1_2_open_parenthesis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Audio/Visual data support mode is applied. + /// + internal static string Audio_Visual_data_support_mode_is_applied { + get { + return ResourceManager.GetString("Audio_Visual_data_support_mode_is_applied", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatic Acoustic Management is supported. + /// + internal static string Automatic_Acoustic_Management_is_supported { + get { + return ResourceManager.GetString("Automatic_Acoustic_Management_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatic Acoustic Management is supported and enabled with value {0} (vendor recommends {1}. + /// + internal static string Automatic_Acoustic_Management_is_supported_and_enabled_with_value_0_vendor_recommends_1 { + get { + return ResourceManager.GetString("Automatic_Acoustic_Management_is_supported_and_enabled_with_value_0_vendor_recomm" + + "ends_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatic Partial to Slumber transitions are enabled. + /// + internal static string Automatic_Partial_to_Slumber_transitions_are_enabled { + get { + return ResourceManager.GetString("Automatic_Partial_to_Slumber_transitions_are_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatic read reallocation is enabled. + /// + internal static string Automatic_read_reallocation_is_enabled { + get { + return ResourceManager.GetString("Automatic_read_reallocation_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatic write reallocation is enabled. + /// + internal static string Automatic_write_reallocation_is_enabled { + get { + return ResourceManager.GetString("Automatic_write_reallocation_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automation/Drive Interface. + /// + internal static string Automation_Drive_Interface { + get { + return ResourceManager.GetString("Automation_Drive_Interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automation/Drive Interface Transport. + /// + internal static string Automation_Drive_Interface_Transport { + get { + return ResourceManager.GetString("Automation_Drive_Interface_Transport", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automation is disabled. + /// + internal static string Automation_is_disabled { + get { + return ResourceManager.GetString("Automation_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Background functions are enabled. + /// + internal static string Background_functions_are_enabled { + get { + return ResourceManager.GetString("Background_functions_are_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Background medium scans are enabled. + /// + internal static string Background_medium_scans_are_enabled { + get { + return ResourceManager.GetString("Background_medium_scans_are_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Background pre-scan operations can take a maximum of {0} hours. + /// + internal static string Background_pre_scan_operations_can_take_a_maximum_of_0_hours { + get { + return ResourceManager.GetString("Background_pre_scan_operations_can_take_a_maximum_of_0_hours", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Background pre-scans are enabled. + /// + internal static string Background_pre_scans_are_enabled { + get { + return ResourceManager.GetString("Background_pre_scans_are_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Background scans will be halted if log is full. + /// + internal static string Background_scans_will_be_halted_if_log_is_full { + get { + return ResourceManager.GetString("Background_scans_will_be_halted_if_log_is_full", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Background scans will only be logged if they require intervention. + /// + internal static string Background_scans_will_only_be_logged_if_they_require_intervention { + get { + return ResourceManager.GetString("Background_scans_will_only_be_logged_if_they_require_intervention", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BGA device. + /// + internal static string BGA_device { + get { + return ResourceManager.GetString("BGA_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Binary contents: {0}. + /// + internal static string Binary_contents_0 { + get { + return ResourceManager.GetString("Binary_contents_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Blank checking during write is enabled. + /// + internal static string Blank_checking_during_write_is_enabled { + get { + return ResourceManager.GetString("Blank_checking_during_write_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BLOCK ERASE EXT is supported. + /// + internal static string BLOCK_ERASE_EXT_is_supported { + get { + return ResourceManager.GetString("BLOCK_ERASE_EXT_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Block number {0}. + /// + internal static string Block_number_0 { + get { + return ResourceManager.GetString("Block_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Blu-ray Burst Cutting Area in hex follows:. + /// + internal static string Blu_ray_Burst_Cutting_Area_in_hex_follows { + get { + return ResourceManager.GetString("Blu_ray_Burst_Cutting_Area_in_hex_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Blu-ray DDS Disc Type Specific Data in hex follows:. + /// + internal static string Blu_ray_DDS_Disc_Type_Specific_Data_in_hex_follows { + get { + return ResourceManager.GetString("Blu_ray_DDS_Disc_Type_Specific_Data_in_hex_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Blu-ray DDS Status Bits in hex follows:. + /// + internal static string Blu_ray_DDS_Status_Bits_in_hex_follows { + get { + return ResourceManager.GetString("Blu_ray_DDS_Status_Bits_in_hex_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Blu-ray DI Unit format dependent contents as hex follows:. + /// + internal static string Blu_ray_DI_Unit_format_dependent_contents_as_hex_follows { + get { + return ResourceManager.GetString("Blu_ray_DI_Unit_format_dependent_contents_as_hex_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Book type: 0x{0:X2}. + /// + internal static string Book_type_0 { + get { + return ResourceManager.GetString("Book_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area 1 is not protected. + /// + internal static string Boot_area_one_is_not_protected { + get { + return ResourceManager.GetString("Boot_area_one_is_not_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area 1 is permanently protected. + /// + internal static string Boot_area_one_is_permanently_protected { + get { + return ResourceManager.GetString("Boot_area_one_is_permanently_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area 1 is permanently write protected.. + /// + internal static string Boot_area_one_is_permanently_write_protected { + get { + return ResourceManager.GetString("Boot_area_one_is_permanently_write_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area 1 is power on protected. + /// + internal static string Boot_area_one_is_power_on_protected { + get { + return ResourceManager.GetString("Boot_area_one_is_power_on_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area 1 is write protected until next power cycle.. + /// + internal static string Boot_area_one_is_write_protected_until_next_power_cycle { + get { + return ResourceManager.GetString("Boot_area_one_is_write_protected_until_next_power_cycle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area 2 is not protected. + /// + internal static string Boot_area_two_is_not_protected { + get { + return ResourceManager.GetString("Boot_area_two_is_not_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area 2 is permanently protected. + /// + internal static string Boot_area_two_is_permanently_protected { + get { + return ResourceManager.GetString("Boot_area_two_is_permanently_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area 2 is permanently write protected.. + /// + internal static string Boot_area_two_is_permanently_write_protected { + get { + return ResourceManager.GetString("Boot_area_two_is_permanently_write_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area 2 is power on protected. + /// + internal static string Boot_area_two_is_power_on_protected { + get { + return ResourceManager.GetString("Boot_area_two_is_power_on_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area 2 is write protected until next power cycle.. + /// + internal static string Boot_area_two_is_write_protected_until_next_power_cycle { + get { + return ResourceManager.GetString("Boot_area_two_is_write_protected_until_next_power_cycle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot firmware version: {0}. + /// + internal static string Boot_firmware_version_0 { + get { + return ResourceManager.GetString("Boot_firmware_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Both boot areas are permanently write protected.. + /// + internal static string Both_boot_areas_are_permanently_write_protected { + get { + return ResourceManager.GetString("Both_boot_areas_are_permanently_write_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Both boot areas are write protected until next power cycle.. + /// + internal static string Both_boot_areas_are_write_protected_until_next_power_cycle { + get { + return ResourceManager.GetString("Both_boot_areas_are_write_protected_until_next_power_cycle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bridging Expanders. + /// + internal static string Bridging_Expanders { + get { + return ResourceManager.GetString("Bridging_Expanders", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to bytes. + /// + internal static string bytes { + get { + return ResourceManager.GetString("bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Caching analysis is permitted. + /// + internal static string Caching_analysis_is_permitted { + get { + return ResourceManager.GetString("Caching_analysis_is_permitted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Card ID: 0x{0:X4}. + /// + internal static string Card_ID_0 { + get { + return ResourceManager.GetString("Card_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Card indicates compliance with PC Card Standard Release {0}.{1}. + /// + internal static string Card_indicates_compliance_with_PC_Card_Standard_Release_0_1 { + get { + return ResourceManager.GetString("Card_indicates_compliance_with_PC_Card_Standard_Release_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cartridge has an uncompressed capability of {0} gigabytes. + /// + internal static string Cartridge_has_an_uncompressed_capability_of_0_gigabytes { + get { + return ResourceManager.GetString("Cartridge_has_an_uncompressed_capability_of_0_gigabytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cartridge is set to write protected. + /// + internal static string Cartridge_is_set_to_write_protected { + get { + return ResourceManager.GetString("Cartridge_is_set_to_write_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cartridge removable is prevented. + /// + internal static string Cartridge_removable_is_prevented { + get { + return ResourceManager.GetString("Cartridge_removable_is_prevented", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cartridge serial number: {0}. + /// + internal static string Cartridge_serial_number_0 { + get { + return ResourceManager.GetString("Cartridge_serial_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cartridge sets write protection. + /// + internal static string Cartridge_sets_write_protection { + get { + return ResourceManager.GetString("Cartridge_sets_write_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cartridge tape is threaded. + /// + internal static string Cartridge_tape_is_threaded { + get { + return ResourceManager.GetString("Cartridge_tape_is_threaded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cartridge will be loaded and threaded on insertion. + /// + internal static string Cartridge_will_be_loaded_and_threaded_on_insertion { + get { + return ResourceManager.GetString("Cartridge_will_be_loaded_and_threaded_on_insertion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cartridge will be loaded but not threaded on insertion. + /// + internal static string Cartridge_will_be_loaded_but_not_threaded_on_insertion { + get { + return ResourceManager.GetString("Cartridge_will_be_loaded_but_not_threaded_on_insertion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cartridge will not be loaded. + /// + internal static string Cartridge_will_not_be_loaded { + get { + return ResourceManager.GetString("Cartridge_will_not_be_loaded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Catalogue number: . + /// + internal static string Catalogue_number { + get { + return ResourceManager.GetString("Catalogue_number", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-ROM/DVD/etc device. + /// + internal static string CD_ROM_DVD_etc_device { + get { + return ResourceManager.GetString("CD_ROM_DVD_etc_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-ROM sector.. + /// + internal static string CD_ROM_sector { + get { + return ResourceManager.GetString("CD_ROM_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD sector.. + /// + internal static string CD_sector { + get { + return ResourceManager.GetString("CD_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains arranger for album. + /// + internal static string CD_Text_pack_contains_arranger_for_album { + get { + return ResourceManager.GetString("CD_Text_pack_contains_arranger_for_album", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains arranger for track {0}. + /// + internal static string CD_Text_pack_contains_arranger_for_track_0 { + get { + return ResourceManager.GetString("CD_Text_pack_contains_arranger_for_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains content provider's message for album. + /// + internal static string CD_Text_pack_contains_content_provider_message_for_album { + get { + return ResourceManager.GetString("CD_Text_pack_contains_content_provider_message_for_album", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains content provider's message for track {0}. + /// + internal static string CD_Text_pack_contains_content_provider_message_for_track_0 { + get { + return ResourceManager.GetString("CD_Text_pack_contains_content_provider_message_for_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains data reserved for content provider only. + /// + internal static string CD_Text_pack_contains_data_reserved_for_content_provider_only { + get { + return ResourceManager.GetString("CD_Text_pack_contains_data_reserved_for_content_provider_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains disc identification information. + /// + internal static string CD_Text_pack_contains_disc_identification_information { + get { + return ResourceManager.GetString("CD_Text_pack_contains_disc_identification_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains genre identification information. + /// + internal static string CD_Text_pack_contains_genre_identification_information { + get { + return ResourceManager.GetString("CD_Text_pack_contains_genre_identification_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains performer for album. + /// + internal static string CD_Text_pack_contains_performer_for_album { + get { + return ResourceManager.GetString("CD_Text_pack_contains_performer_for_album", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains performer for track {0}. + /// + internal static string CD_Text_pack_contains_performer_for_track_0 { + get { + return ResourceManager.GetString("CD_Text_pack_contains_performer_for_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains reserved data. + /// + internal static string CD_Text_pack_contains_reserved_data { + get { + return ResourceManager.GetString("CD_Text_pack_contains_reserved_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains second table of contents information. + /// + internal static string CD_Text_pack_contains_second_table_of_contents_information { + get { + return ResourceManager.GetString("CD_Text_pack_contains_second_table_of_contents_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains size block information. + /// + internal static string CD_Text_pack_contains_size_block_information { + get { + return ResourceManager.GetString("CD_Text_pack_contains_size_block_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains songwriter for album. + /// + internal static string CD_Text_pack_contains_songwriter_for_album { + get { + return ResourceManager.GetString("CD_Text_pack_contains_songwriter_for_album", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains songwriter for track {0}. + /// + internal static string CD_Text_pack_contains_songwriter_for_track_0 { + get { + return ResourceManager.GetString("CD_Text_pack_contains_songwriter_for_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains table of contents information. + /// + internal static string CD_Text_pack_contains_table_of_contents_information { + get { + return ResourceManager.GetString("CD_Text_pack_contains_table_of_contents_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains title for album. + /// + internal static string CD_Text_pack_contains_title_for_album { + get { + return ResourceManager.GetString("CD_Text_pack_contains_title_for_album", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains title for track {0}. + /// + internal static string CD_Text_pack_contains_title_for_track_0 { + get { + return ResourceManager.GetString("CD_Text_pack_contains_title_for_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-Text pack contains UPC. + /// + internal static string CD_Text_pack_contains_UPC { + get { + return ResourceManager.GetString("CD_Text_pack_contains_UPC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-V disc in NTSC format with digital bilingual sound. + /// + internal static string CD_V_disc_in_NTSC_format_with_digital_bilingual_sound { + get { + return ResourceManager.GetString("CD_V_disc_in_NTSC_format_with_digital_bilingual_sound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-V disc in NTSC format with digital stereo sound. + /// + internal static string CD_V_disc_in_NTSC_format_with_digital_stereo_sound { + get { + return ResourceManager.GetString("CD_V_disc_in_NTSC_format_with_digital_stereo_sound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-V disc in PAL format with digital bilingual sound. + /// + internal static string CD_V_disc_in_PAL_format_with_digital_bilingual_sound { + get { + return ResourceManager.GetString("CD_V_disc_in_PAL_format_with_digital_bilingual_sound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-V disc in PAL format with digital stereo sound. + /// + internal static string CD_V_disc_in_PAL_format_with_digital_stereo_sound { + get { + return ResourceManager.GetString("CD_V_disc_in_PAL_format_with_digital_stereo_sound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-V single in NTSC format with digital bilingual sound. + /// + internal static string CD_V_single_in_NTSC_format_with_digital_bilingual_sound { + get { + return ResourceManager.GetString("CD_V_single_in_NTSC_format_with_digital_bilingual_sound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-V single in NTSC format with digital stereo sound. + /// + internal static string CD_V_single_in_NTSC_format_with_digital_stereo_sound { + get { + return ResourceManager.GetString("CD_V_single_in_NTSC_format_with_digital_stereo_sound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-V single in PAL format with digital bilingual sound. + /// + internal static string CD_V_single_in_PAL_format_with_digital_bilingual_sound { + get { + return ResourceManager.GetString("CD_V_single_in_PAL_format_with_digital_bilingual_sound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-V single in PAL format with digital stereo sound. + /// + internal static string CD_V_single_in_PAL_format_with_digital_stereo_sound { + get { + return ResourceManager.GetString("CD_V_single_in_PAL_format_with_digital_stereo_sound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Base Mechanical Serial Number: {0}. + /// + internal static string Certance_Base_Mechanical_Serial_Number_0 { + get { + return ResourceManager.GetString("Certance_Base_Mechanical_Serial_Number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Board Serial Number: {0}. + /// + internal static string Certance_Board_Serial_Number_0 { + get { + return ResourceManager.GetString("Certance_Board_Serial_Number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Certance Drive Component Revision Levels page:. + /// + internal static string Certance_Certance_Drive_Component_Revision_Levels_page { + get { + return ResourceManager.GetString("Certance_Certance_Drive_Component_Revision_Levels_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Certance Drive Component Serial Number page:. + /// + internal static string Certance_Certance_Drive_Component_Serial_Number_page { + get { + return ResourceManager.GetString("Certance_Certance_Drive_Component_Serial_Number_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Component: {0}. + /// + internal static string Certance_Component_0 { + get { + return ResourceManager.GetString("Certance_Component_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Date: {0}. + /// + internal static string Certance_Date_0 { + get { + return ResourceManager.GetString("Certance_Date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Certance Drive Capabilities Control Mode Page:. + /// + internal static string Certance_Drive_Capabilities_Control_Mode_Page { + get { + return ResourceManager.GetString("Certance_Drive_Capabilities_Control_Mode_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Certance drive status page:. + /// + internal static string Certance_drive_status_page { + get { + return ResourceManager.GetString("Certance_drive_status_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Head Assembly Serial Number: {0}. + /// + internal static string Certance_Head_Assembly_Serial_Number_0 { + get { + return ResourceManager.GetString("Certance_Head_Assembly_Serial_Number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Certance Interface Control Mode Page:. + /// + internal static string Certance_Interface_Control_Mode_Page { + get { + return ResourceManager.GetString("Certance_Interface_Control_Mode_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reel Motor 1 Serial Number: {0}. + /// + internal static string Certance_Reel_Motor_1_Serial_Number_0 { + get { + return ResourceManager.GetString("Certance_Reel_Motor_1_Serial_Number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reel Motor 2 Serial Number: {0}. + /// + internal static string Certance_Reel_Motor_2_Serial_Number_0 { + get { + return ResourceManager.GetString("Certance_Reel_Motor_2_Serial_Number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Variant: {0}. + /// + internal static string Certance_Variant_0 { + get { + return ResourceManager.GetString("Certance_Variant_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version: {0}. + /// + internal static string Certance_Version_0 { + get { + return ResourceManager.GetString("Certance_Version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Challenge ID: {0}. + /// + internal static string Challenge_ID_0 { + get { + return ResourceManager.GetString("Challenge_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Challenge level: {0}. + /// + internal static string Challenge_level_0 { + get { + return ResourceManager.GetString("Challenge_level_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Challenge value: 0x{0:X8}. + /// + internal static string Challenge_value_0 { + get { + return ResourceManager.GetString("Challenge_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Change of the boot configuration register bits is disabled until the next power cycle.. + /// + internal static string Change_of_the_boot_configuration_register_bits_is_disabled_until_the_next_power_cycle { + get { + return ResourceManager.GetString("Change_of_the_boot_configuration_register_bits_is_disabled_until_the_next_power_c" + + "ycle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Change of the boot configuration register bits is permanently disabled.. + /// + internal static string Change_of_the_boot_configuration_register_bits_is_permanently_disabled { + get { + return ResourceManager.GetString("Change_of_the_boot_configuration_register_bits_is_permanently_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Channel number: {0}. + /// + internal static string Channel_number_0 { + get { + return ResourceManager.GetString("Channel_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Character position {0}. + /// + internal static string Character_position_0 { + get { + return ResourceManager.GetString("Character_position_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CHECK CONDITION should be reported rather than a long busy condition. + /// + internal static string CHECK_CONDITION_should_be_reported_rather_than_a_long_busy_condition { + get { + return ResourceManager.GetString("CHECK_CONDITION_should_be_reported_rather_than_a_long_busy_condition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Checksum {0}. + /// + internal static string Checksum_0 { + get { + return ResourceManager.GetString("Checksum_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CID CRC: 0x{0:X2}. + /// + internal static string CID_CRC_0 { + get { + return ResourceManager.GetString("CID_CRC_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cleaning behaviour is normal. + /// + internal static string Cleaning_behaviour_is_normal { + get { + return ResourceManager.GetString("Cleaning_behaviour_is_normal", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cleaning cartridge inserted. + /// + internal static string Cleaning_cartridge_inserted { + get { + return ResourceManager.GetString("Cleaning_cartridge_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Clock dependent part of data access is {0} clock cycles. + /// + internal static string Clock_dependent_part_of_data_access_is_0_clock_cycles { + get { + return ResourceManager.GetString("Clock_dependent_part_of_data_access_is_0_clock_cycles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ). + /// + internal static string close_parenthesis { + get { + return ResourceManager.GetString("close_parenthesis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Code name: {0}. + /// + internal static string Code_name_0 { + get { + return ResourceManager.GetString("Code_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Coding information number: {0}. + /// + internal static string Coding_information_number_0 { + get { + return ResourceManager.GetString("Coding_information_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Command forwarding is disabled. + /// + internal static string Command_forwarding_is_disabled { + get { + return ResourceManager.GetString("Command_forwarding_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Command forwarding is enabled. + /// + internal static string Command_forwarding_is_enabled { + get { + return ResourceManager.GetString("Command_forwarding_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Command set and features:. + /// + internal static string Command_set_and_features { + get { + return ResourceManager.GetString("Command_set_and_features", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Commands can be reordered in any manner. + /// + internal static string Commands_can_be_reordered_in_any_manner { + get { + return ResourceManager.GetString("Commands_can_be_reordered_in_any_manner", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Commands should be sent strictly ordered. + /// + internal static string Commands_should_be_sent_strictly_ordered { + get { + return ResourceManager.GetString("Commands_should_be_sent_strictly_ordered", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Communications device. + /// + internal static string Communications_device { + get { + return ResourceManager.GetString("Communications_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CompactFlash device. + /// + internal static string CompactFlash_device { + get { + return ResourceManager.GetString("CompactFlash_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CompactFlash device supports power mode 1. + /// + internal static string CompactFlash_device_supports_power_mode_1 { + get { + return ResourceManager.GetString("CompactFlash_device_supports_power_mode_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CompactFlash device uses a maximum of {0} mA. + /// + internal static string CompactFlash_device_uses_a_maximum_of_0_mA { + get { + return ResourceManager.GetString("CompactFlash_device_uses_a_maximum_of_0_mA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CompactFlash feature set is supported. + /// + internal static string CompactFlash_feature_set_is_supported { + get { + return ResourceManager.GetString("CompactFlash_feature_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CompactFlash feature set is supported and enabled. + /// + internal static string CompactFlash_feature_set_is_supported_and_enabled { + get { + return ResourceManager.GetString("CompactFlash_feature_set_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CompactFlash power mode 1 is disabled. + /// + internal static string CompactFlash_power_mode_1_is_disabled { + get { + return ResourceManager.GetString("CompactFlash_power_mode_1_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CompactFlash power mode 1 required for one or more commands. + /// + internal static string CompactFlash_power_mode_1_required_for_one_or_more_commands { + get { + return ResourceManager.GetString("CompactFlash_power_mode_1_required_for_one_or_more_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compression is controlled using mode pages 0Fh and 10h. + /// + internal static string Compression_is_controlled_using_mode_pages_0Fh_and_10h { + get { + return ResourceManager.GetString("Compression_is_controlled_using_mode_pages_0Fh_and_10h", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compression is disabled and not controllable. + /// + internal static string Compression_is_disabled_and_not_controllable { + get { + return ResourceManager.GetString("Compression_is_disabled_and_not_controllable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compression is enabled and not controllable. + /// + internal static string Compression_is_enabled_and_not_controllable { + get { + return ResourceManager.GetString("Compression_is_enabled_and_not_controllable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Conditionally generate recovered error on informational exceptions. + /// + internal static string Conditionally_generate_recovered_error_on_informational_exceptions { + get { + return ResourceManager.GetString("Conditionally_generate_recovered_error_on_informational_exceptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Consumer purpose disc for use in consumer purpose drives. + /// + internal static string Consumer_purpose_disc_for_use_in_consumer_purpose_drives { + get { + return ResourceManager.GetString("Consumer_purpose_disc_for_use_in_consumer_purpose_drives", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Control Data Zone is pre-recorded. + /// + internal static string Control_Data_Zone_is_pre_recorded { + get { + return ResourceManager.GetString("Control_Data_Zone_is_pre_recorded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Controller firmware version: {0}. + /// + internal static string Controller_firmware_version_0 { + get { + return ResourceManager.GetString("Controller_firmware_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Controller hardware version: {0}. + /// + internal static string Controller_hardware_version_0 { + get { + return ResourceManager.GetString("Controller_hardware_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Copy of information of A1 from ATIP found. + /// + internal static string Copy_of_information_of_A1_from_ATIP_found { + get { + return ResourceManager.GetString("Copy_of_information_of_A1_from_ATIP_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Copyright: {0}. + /// + internal static string Copyright_0 { + get { + return ResourceManager.GetString("Copyright_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Correct ECC P.. + /// + internal static string Correct_ECC_P { + get { + return ResourceManager.GetString("Correct_ECC_P", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Correct ECC Q.. + /// + internal static string Correct_ECC_Q { + get { + return ResourceManager.GetString("Correct_ECC_Q", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Correct EDC.. + /// + internal static string Correct_EDC { + get { + return ResourceManager.GetString("Correct_EDC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Correct sector contents.. + /// + internal static string Correct_sector_contents { + get { + return ResourceManager.GetString("Correct_sector_contents", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Correct zero fill.. + /// + internal static string Correct_zero_fill { + get { + return ResourceManager.GetString("Correct_zero_fill", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not decode ATA IDENTIFY information. + /// + internal static string Could_not_decode_ATA_IDENTIFY_information { + get { + return ResourceManager.GetString("Could_not_decode_ATA_IDENTIFY_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CPRM Media Key Blocks in hex follows:. + /// + internal static string CPRM_Media_Key_Blocks_in_hex_follows { + get { + return ResourceManager.GetString("CPRM_Media_Key_Blocks_in_hex_follows", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CRC: 0x{0:X4}. + /// + internal static string CRC_0_X4 { + get { + return ResourceManager.GetString("CRC_0_X4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CRYPTO SCRAMBLE EXT is supported. + /// + internal static string CRYPTO_SCRAMBLE_EXT_is_supported { + get { + return ResourceManager.GetString("CRYPTO_SCRAMBLE_EXT_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CSD CRC: 0x{0:X2}. + /// + internal static string CSD_CRC_0 { + get { + return ResourceManager.GetString("CSD_CRC_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CSD version 1.{0} revision 1.{1}. + /// + internal static string CSD_version_one_0_revision_one_1 { + get { + return ResourceManager.GetString("CSD_version_one_0_revision_one_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CompactTape I. + /// + internal static string CT1 { + get { + return ResourceManager.GetString("CT1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CompactTape II. + /// + internal static string CT2 { + get { + return ResourceManager.GetString("CT2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (current). + /// + internal static string current { + get { + return ResourceManager.GetString("current", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current Border-Out first sector is PSN {0:X}h. + /// + internal static string Current_Border_Out_first_sector_is_PSN_0 { + get { + return ResourceManager.GetString("Current_Border_Out_first_sector_is_PSN_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current media has a {0} bytes link available. + /// + internal static string Current_media_has_a_0_bytes_link_available { + get { + return ResourceManager.GetString("Current_media_has_a_0_bytes_link_available", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current media is initialized with TCG OSSC. + /// + internal static string Current_media_is_initialized_with_TCG_OSSC { + get { + return ResourceManager.GetString("Current_media_is_initialized_with_TCG_OSSC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current operating definition: {0}. + /// + internal static string Current_operating_definition_0 { + get { + return ResourceManager.GetString("Current_operating_definition_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current RMD in extra Border zone starts at PSN {0:X}h. + /// + internal static string Current_RMD_in_extra_Border_zone_starts_at_PSN_0 { + get { + return ResourceManager.GetString("Current_RMD_in_extra_Border_zone_starts_at_PSN_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current Write/Read/Verify mode: {0}. + /// + internal static string Current_Write_Read_Verify_mode_0 { + get { + return ResourceManager.GetString("Current_Write_Read_Verify_mode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cylinders: {0}. + /// + internal static string Cylinders_0 { + get { + return ResourceManager.GetString("Cylinders_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cylinders: {0} max., {1} current. + /// + internal static string Cylinders_0_max_1_current { + get { + return ResourceManager.GetString("Cylinders_0_max_1_current", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 200 mm optical disc. + /// + internal static string D407 { + get { + return ResourceManager.GetString("D407", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 89 mm Read/Write double-sided optical disc with 12500 tracks. + /// + internal static string D581 { + get { + return ResourceManager.GetString("D581", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data area ends at PSN {0:X}h. + /// + internal static string Data_area_ends_at_PSN_0 { + get { + return ResourceManager.GetString("Data_area_ends_at_PSN_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data area starts at PSN {0:X}h. + /// + internal static string Data_area_starts_at_PSN_0 { + get { + return ResourceManager.GetString("Data_area_starts_at_PSN_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data block.. + /// + internal static string Data_block { + get { + return ResourceManager.GetString("Data_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data compression is enabled with . + /// + internal static string Data_compression_is_enabled_with { + get { + return ResourceManager.GetString("Data_compression_is_enabled_with", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data decompression is enabled. + /// + internal static string Data_decompression_is_enabled { + get { + return ResourceManager.GetString("Data_decompression_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data has {0} bytes. + /// + internal static string Data_has_0_bytes { + get { + return ResourceManager.GetString("Data_has_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data not recovered within limits shall be transferred back before a CHECK CONDITION. + /// + internal static string Data_not_recovered_within_limits_shall_be_transferred_back_before_a_CHECK_CONDITION { + get { + return ResourceManager.GetString("Data_not_recovered_within_limits_shall_be_transferred_back_before_a_CHECK_CONDITI" + + "ON", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data put by READ commands should be evicted from cache sooner than data put in read cache by other means. + /// + internal static string Data_put_by_READ_commands_should_be_evicted_from_cache_sooner_than_data_put_in_read_cache_by_other_means { + get { + return ResourceManager.GetString("Data_put_by_READ_commands_should_be_evicted_from_cache_sooner_than_data_put_in_re" + + "ad_cache_by_other_means", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data put by READ commands should not be evicted if there is data cached by other means that can be evicted. + /// + internal static string Data_put_by_READ_commands_should_not_be_evicted_if_there_is_data_cached_by_other_means_that_can_be_evicted { + get { + return ResourceManager.GetString("Data_put_by_READ_commands_should_not_be_evicted_if_there_is_data_cached_by_other_" + + "means_that_can_be_evicted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data put by WRITE commands should be evicted from cache sooner than data put in write cache by other means. + /// + internal static string Data_put_by_WRITE_commands_should_be_evicted_from_cache_sooner_than_data_put_in_write_cache_by_other_means { + get { + return ResourceManager.GetString("Data_put_by_WRITE_commands_should_be_evicted_from_cache_sooner_than_data_put_in_w" + + "rite_cache_by_other_means", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data put by WRITE commands should not be evicted if there is data cached by other means that can be evicted. + /// + internal static string Data_put_by_WRITE_commands_should_not_be_evicted_if_there_is_data_cached_by_other_means_that_can_be_evicted { + get { + return ResourceManager.GetString("Data_put_by_WRITE_commands_should_not_be_evicted_if_there_is_data_cached_by_other" + + "_means_that_can_be_evicted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DATA SET MANAGEMENT can receive a maximum of {0} blocks of 512 bytes. + /// + internal static string DATA_SET_MANAGEMENT_can_receive_a_maximum_of_0_blocks_of_512_bytes { + get { + return ResourceManager.GetString("DATA_SET_MANAGEMENT_can_receive_a_maximum_of_0_blocks_of_512_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data strobe offset option is available. + /// + internal static string Data_strobe_offset_option_is_available { + get { + return ResourceManager.GetString("Data_strobe_offset_option_is_available", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data tapes will be threaded at beginning, rest will be unloaded. + /// + internal static string Data_tapes_will_be_threaded_at_beginning_rest_will_be_unloaded { + get { + return ResourceManager.GetString("Data_tapes_will_be_threaded_at_beginning_rest_will_be_unloaded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data track {3} starts at: {0:D2}:{1:D2}:{2:D2} (. + /// + internal static string Data_track_3_starts_at_0_1_2_open_parenthesis { + get { + return ResourceManager.GetString("Data_track_3_starts_at_0_1_2_open_parenthesis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data track {3} starts at: {4:D2}:{0:D2}:{1:D2}:{2:D2} (. + /// + internal static string Data_track_3_starts_at_4_0_1_2_open_parenthesis { + get { + return ResourceManager.GetString("Data_track_3_starts_at_4_0_1_2_open_parenthesis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data track, recorded incrementally. + /// + internal static string Data_track_recorded_incrementally { + get { + return ResourceManager.GetString("Data_track_recorded_incrementally", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data track, recorded uninterrupted. + /// + internal static string Data_track_recorded_uninterrupted { + get { + return ResourceManager.GetString("Data_track_recorded_uninterrupted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data transfer disconnect control is not used. + /// + internal static string Data_transfer_disconnect_control_is_not_used { + get { + return ResourceManager.GetString("Data_transfer_disconnect_control_is_not_used", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DC-9200. + /// + internal static string DC9200 { + get { + return ResourceManager.GetString("DC9200", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DC-9250. + /// + internal static string DC9250 { + get { + return ResourceManager.GetString("DC9250", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DCLZ. + /// + internal static string DCLZ { + get { + return ResourceManager.GetString("DCLZ", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DDS Format: 0x{0:X2}. + /// + internal static string DDS_Format_0 { + get { + return ResourceManager.GetString("DDS_Format_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DDS has been updated {0} times. + /// + internal static string DDS_has_been_updated_0_times { + get { + return ResourceManager.GetString("DDS_has_been_updated_0_times", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DDS-2. + /// + internal static string DDS2 { + get { + return ResourceManager.GetString("DDS2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DDS-3. + /// + internal static string DDS3 { + get { + return ResourceManager.GetString("DDS3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DDS-4. + /// + internal static string DDS4 { + get { + return ResourceManager.GetString("DDS4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Default operating definition: {0}. + /// + internal static string Default_operating_definition_0 { + get { + return ResourceManager.GetString("Default_operating_definition_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Density "{0}" defined by "{1}".. + /// + internal static string Density_0_defined_by_1 { + get { + return ResourceManager.GetString("Density_0_defined_by_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Density description: {0}. + /// + internal static string Density_description_0 { + get { + return ResourceManager.GetString("Density_description_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Density has {0} bits per mm, with {1} tracks in a {2} mm width tape. + /// + internal static string Density_has_0_bits_per_mm__with_1_tracks_in_a_2_mm_width_tape { + get { + return ResourceManager.GetString("Density_has_0_bits_per_mm__with_1_tracks_in_a_2_mm_width_tape", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Density maximum capacity is {0} megabytes. + /// + internal static string Density_maximum_capacity_is_0_megabytes { + get { + return ResourceManager.GetString("Density_maximum_capacity_is_0_megabytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Descriptor refers to {0} protocol. + /// + internal static string Descriptor_refers_to_0_protocol { + get { + return ResourceManager.GetString("Descriptor_refers_to_0_protocol", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Developer code: {0}. + /// + internal static string Developer_code_0 { + get { + return ResourceManager.GetString("Developer_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device allows reading partial blocks. + /// + internal static string Device_allows_reading_partial_blocks { + get { + return ResourceManager.GetString("Device_allows_reading_partial_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device allows writing partial blocks. + /// + internal static string Device_allows_writing_partial_blocks { + get { + return ResourceManager.GetString("Device_allows_writing_partial_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device boot partition 1 is enabled. + /// + internal static string Device_boot_partition_one_is_enabled { + get { + return ResourceManager.GetString("Device_boot_partition_one_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device boot partition 2 is enabled. + /// + internal static string Device_boot_partition_two_is_enabled { + get { + return ResourceManager.GetString("Device_boot_partition_two_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can achieve a minimum of {0}MB/s reading in DDR 52Mhz mode. + /// + internal static string Device_can_achieve_a_minimum_of_0_MB_s_reading_in_DDR_52Mhz_mode { + get { + return ResourceManager.GetString("Device_can_achieve_a_minimum_of_0_MB_s_reading_in_DDR_52Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can achieve a minimum of {0}MB/s reading in SDR 26Mhz 4-bit mode. + /// + internal static string Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_26Mhz_4_bit_mode { + get { + return ResourceManager.GetString("Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_26Mhz_4_bit_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can achieve a minimum of {0}MB/s reading in SDR 26Mhz mode. + /// + internal static string Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_26Mhz_mode { + get { + return ResourceManager.GetString("Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_26Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can achieve a minimum of {0}MB/s reading in SDR 52Mhz mode. + /// + internal static string Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_52Mhz_mode { + get { + return ResourceManager.GetString("Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_52Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can achieve a minimum of {0}MB/s writing in DDR 52Mhz mode. + /// + internal static string Device_can_achieve_a_minimum_of_0_MB_s_writing_in_DDR_52Mhz_mode { + get { + return ResourceManager.GetString("Device_can_achieve_a_minimum_of_0_MB_s_writing_in_DDR_52Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can achieve a minimum of {0}MB/s writing in SDR 26Mhz 4-bit mode. + /// + internal static string Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_26Mhz_4_bit_mode { + get { + return ResourceManager.GetString("Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_26Mhz_4_bit_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can achieve a minimum of {0}MB/s writing in SDR 26Mhz mode. + /// + internal static string Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_26Mhz_mode { + get { + return ResourceManager.GetString("Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_26Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can achieve a minimum of {0}MB/s writing in SDR 52Mhz mode. + /// + internal static string Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_52Mhz_mode { + get { + return ResourceManager.GetString("Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_52Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can erase a minimum of {0} blocks at a time. + /// + internal static string Device_can_erase_a_minimum_of_0_blocks_at_a_time { + get { + return ResourceManager.GetString("Device_can_erase_a_minimum_of_0_blocks_at_a_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can erase multiple blocks. + /// + internal static string Device_can_erase_multiple_blocks { + get { + return ResourceManager.GetString("Device_can_erase_multiple_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can have enhanced technological features in partitions and user data area. + /// + internal static string Device_can_have_enhanced_technological_features_in_partitions_and_user_data_area { + get { + return ResourceManager.GetString("Device_can_have_enhanced_technological_features_in_partitions_and_user_data_area", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can have extended partitions attribute.. + /// + internal static string Device_can_have_extended_partitions_attribute { + get { + return ResourceManager.GetString("Device_can_have_extended_partitions_attribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can switch to work with 1.8V supply. + /// + internal static string Device_can_switch_to_work_with_1_8V_supply { + get { + return ResourceManager.GetString("Device_can_switch_to_work_with_1_8V_supply", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can take a maximum of {0} ms when releasing from an interrupt. + /// + internal static string Device_can_take_a_maximum_of_0_ms_when_releasing_from_an_interrupt { + get { + return ResourceManager.GetString("Device_can_take_a_maximum_of_0_ms_when_releasing_from_an_interrupt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can take a maximum of {0} ms when switching partitions. + /// + internal static string Device_can_take_a_maximum_of_0_ms_when_switching_partitions { + get { + return ResourceManager.GetString("Device_can_take_a_maximum_of_0_ms_when_switching_partitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 1.65~1.95V. + /// + internal static string Device_can_work_with_supply_1_65_1_95V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_1_65_1_95V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 2.0~2.1V. + /// + internal static string Device_can_work_with_supply_2_0_2_1V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_2_0_2_1V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 2.1~2.2V. + /// + internal static string Device_can_work_with_supply_2_1_2_2V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_2_1_2_2V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 2.2~2.3V. + /// + internal static string Device_can_work_with_supply_2_2_2_3V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_2_2_2_3V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 2.3~2.4V. + /// + internal static string Device_can_work_with_supply_2_3_2_4V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_2_3_2_4V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 2.4~2.5V. + /// + internal static string Device_can_work_with_supply_2_4_2_5V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_2_4_2_5V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 2.5~2.6V. + /// + internal static string Device_can_work_with_supply_2_5_2_6V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_2_5_2_6V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 2.6~2.7V. + /// + internal static string Device_can_work_with_supply_2_6_2_7V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_2_6_2_7V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 2.7~2.8V. + /// + internal static string Device_can_work_with_supply_2_7_2_8V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_2_7_2_8V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 2.8~2.9V. + /// + internal static string Device_can_work_with_supply_2_8_2_9V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_2_8_2_9V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 2.9~3.0V. + /// + internal static string Device_can_work_with_supply_2_9_3_0V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_2_9_3_0V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 3.1~3.2V. + /// + internal static string Device_can_work_with_supply_3_1_3_2V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_3_1_3_2V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 3.2~3.3V. + /// + internal static string Device_can_work_with_supply_3_2_3_3V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_3_2_3_3V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 3.3~3.4V. + /// + internal static string Device_can_work_with_supply_3_3_3_4V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_3_3_3_4V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 3.4~3.5V. + /// + internal static string Device_can_work_with_supply_3_4_3_5V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_3_4_3_5V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can work with supply 3.5~3.6V. + /// + internal static string Device_can_work_with_supply_3_5_3_6V { + get { + return ResourceManager.GetString("Device_can_work_with_supply_3_5_3_6V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can write protect a minimum of {0} blocks at a time. + /// + internal static string Device_can_write_protect_a_minimum_of_0_blocks_at_a_time { + get { + return ResourceManager.GetString("Device_can_write_protect_a_minimum_of_0_blocks_at_a_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can write protect regions. + /// + internal static string Device_can_write_protect_regions { + get { + return ResourceManager.GetString("Device_can_write_protect_regions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device cannot achieve 2.4MB/s reading in SDR 26Mhz 4-bit mode. + /// + internal static string Device_cannot_achieve_2_4MB_s_reading_in_SDR_26Mhz_4_bit_mode { + get { + return ResourceManager.GetString("Device_cannot_achieve_2_4MB_s_reading_in_SDR_26Mhz_4_bit_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device cannot achieve 2.4MB/s reading in SDR 26Mhz mode. + /// + internal static string Device_cannot_achieve_2_4MB_s_reading_in_SDR_26Mhz_mode { + get { + return ResourceManager.GetString("Device_cannot_achieve_2_4MB_s_reading_in_SDR_26Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device cannot achieve 2.4MB/s reading in SDR 52Mhz mode. + /// + internal static string Device_cannot_achieve_2_4MB_s_reading_in_SDR_52Mhz_mode { + get { + return ResourceManager.GetString("Device_cannot_achieve_2_4MB_s_reading_in_SDR_52Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device cannot achieve 2.4MB/s writing in SDR 26Mhz 4-bit mode. + /// + internal static string Device_cannot_achieve_2_4MB_s_writing_in_SDR_26Mhz_4_bit_mode { + get { + return ResourceManager.GetString("Device_cannot_achieve_2_4MB_s_writing_in_SDR_26Mhz_4_bit_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device cannot achieve 2.4MB/s writing in SDR 26Mhz mode. + /// + internal static string Device_cannot_achieve_2_4MB_s_writing_in_SDR_26Mhz_mode { + get { + return ResourceManager.GetString("Device_cannot_achieve_2_4MB_s_writing_in_SDR_26Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device cannot achieve 2.4MB/s writing in SDR 52Mhz mode. + /// + internal static string Device_cannot_achieve_2_4MB_s_writing_in_SDR_52Mhz_mode { + get { + return ResourceManager.GetString("Device_cannot_achieve_2_4MB_s_writing_in_SDR_52Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device cannot achieve 4.8MB/s reading in DDR 52Mhz mode. + /// + internal static string Device_cannot_achieve_4_8MB_s_reading_in_DDR_52Mhz_mode { + get { + return ResourceManager.GetString("Device_cannot_achieve_4_8MB_s_reading_in_DDR_52Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device cannot achieve 4.8MB/s writing in DDR 52Mhz mode. + /// + internal static string Device_cannot_achieve_4_8MB_s_writing_in_DDR_52Mhz_mode { + get { + return ResourceManager.GetString("Device_cannot_achieve_4_8MB_s_writing_in_DDR_52Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device can't write protect regions. + /// + internal static string Device_cant_write_protect_regions { + get { + return ResourceManager.GetString("Device_cant_write_protect_regions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device capabilities:. + /// + internal static string Device_capabilities { + get { + return ResourceManager.GetString("Device_capabilities", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device checks the logical block application tag. + /// + internal static string Device_checks_the_logical_block_application_tag { + get { + return ResourceManager.GetString("Device_checks_the_logical_block_application_tag", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device checks the logical block guard. + /// + internal static string Device_checks_the_logical_block_guard { + get { + return ResourceManager.GetString("Device_checks_the_logical_block_guard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device checks the logical block reference tag. + /// + internal static string Device_checks_the_logical_block_reference_tag { + get { + return ResourceManager.GetString("Device_checks_the_logical_block_reference_tag", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply ECMA-111: Small Computer System Interface SCSI. + /// + internal static string Device_claims_to_comply_ECMA_111_Small_Computer_System_Interface_SCSI { + get { + return ResourceManager.GetString("Device_claims_to_comply_ECMA_111_Small_Computer_System_Interface_SCSI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply with ANSI X3.131:1986 (SCSI-1). + /// + internal static string Device_claims_to_comply_with_ANSI_X3_131_1986_SCSI_1 { + get { + return ResourceManager.GetString("Device_claims_to_comply_with_ANSI_X3_131_1986_SCSI_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply with ANSI X3.131:1994 (SCSI-2). + /// + internal static string Device_claims_to_comply_with_ANSI_X3_131_1994_SCSI_2 { + get { + return ResourceManager.GetString("Device_claims_to_comply_with_ANSI_X3_131_1994_SCSI_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply with ANSI X3.301:1997 (SPC-1). + /// + internal static string Device_claims_to_comply_with_ANSI_X3_301_1997_SPC_1 { + get { + return ResourceManager.GetString("Device_claims_to_comply_with_ANSI_X3_301_1997_SPC_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply with ANSI X3.351:2001 (SPC-2). + /// + internal static string Device_claims_to_comply_with_ANSI_X3_351_2001_SPC_2 { + get { + return ResourceManager.GetString("Device_claims_to_comply_with_ANSI_X3_351_2001_SPC_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply with ANSI X3.408:2005 (SPC-3). + /// + internal static string Device_claims_to_comply_with_ANSI_X3_408_2005_SPC_3 { + get { + return ResourceManager.GetString("Device_claims_to_comply_with_ANSI_X3_408_2005_SPC_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply with ANSI X3.408:2005 (SPC-4). + /// + internal static string Device_claims_to_comply_with_ANSI_X3_408_2005_SPC_4 { + get { + return ResourceManager.GetString("Device_claims_to_comply_with_ANSI_X3_408_2005_SPC_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply with ISO/IEC 9316:1995. + /// + internal static string Device_claims_to_comply_with_ISO_IEC_9316_1995 { + get { + return ResourceManager.GetString("Device_claims_to_comply_with_ISO_IEC_9316_1995", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply with unknown SCSI ANSI standard value 0x{0:X2}). + /// + internal static string Device_claims_to_comply_with_unknown_SCSI_ANSI_standard_value_0 { + get { + return ResourceManager.GetString("Device_claims_to_comply_with_unknown_SCSI_ANSI_standard_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply with unknown SCSI ECMA standard value 0x{0:X2}). + /// + internal static string Device_claims_to_comply_with_unknown_SCSI_ECMA_standard_value_0 { + get { + return ResourceManager.GetString("Device_claims_to_comply_with_unknown_SCSI_ECMA_standard_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device claims to comply with unknown SCSI ISO/IEC standard value 0x{0:X2}). + /// + internal static string Device_claims_to_comply_with_unknown_SCSI_ISO_IEC_standard_value_0 { + get { + return ResourceManager.GetString("Device_claims_to_comply_with_unknown_SCSI_ISO_IEC_standard_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device clears any unit attention condition in all LUNs after reporting for any LUN. + /// + internal static string Device_clears_any_unit_attention_condition_in_all_LUNs_after_reporting_for_any_LUN { + get { + return ResourceManager.GetString("Device_clears_any_unit_attention_condition_in_all_LUNs_after_reporting_for_any_LU" + + "N", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ACS-2 ANSI INCITS 482-2013. + /// + internal static string Device_complies_with_ACS_2_ANSI_INCITS_482_2013 { + get { + return ResourceManager.GetString("Device_complies_with_ACS_2_ANSI_INCITS_482_2013", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ACS-2 (no version claimed). + /// + internal static string Device_complies_with_ACS_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ACS_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ACS-3 (no version claimed). + /// + internal static string Device_complies_with_ACS_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ACS_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC-2 ANSI INCITS 441-2008. + /// + internal static string Device_complies_with_ADC_2_ANSI_INCITS_441_2008 { + get { + return ResourceManager.GetString("Device_complies_with_ADC_2_ANSI_INCITS_441_2008", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC-2 (no version claimed). + /// + internal static string Device_complies_with_ADC_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ADC_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC-2 T10/1741-D revision 7. + /// + internal static string Device_complies_with_ADC_2_T10_1741_D_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_ADC_2_T10_1741_D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC-2 T10/1741-D revision 8. + /// + internal static string Device_complies_with_ADC_2_T10_1741_D_revision_8 { + get { + return ResourceManager.GetString("Device_complies_with_ADC_2_T10_1741_D_revision_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC-3 ANSI INCITS 497-2012. + /// + internal static string Device_complies_with_ADC_3_ANSI_INCITS_497_2012 { + get { + return ResourceManager.GetString("Device_complies_with_ADC_3_ANSI_INCITS_497_2012", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC-3 (no version claimed). + /// + internal static string Device_complies_with_ADC_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ADC_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC-3 T10/1895-D revision 04. + /// + internal static string Device_complies_with_ADC_3_T10_1895_D_revision_04 { + get { + return ResourceManager.GetString("Device_complies_with_ADC_3_T10_1895_D_revision_04", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC-3 T10/1895-D revision 05. + /// + internal static string Device_complies_with_ADC_3_T10_1895_D_revision_05 { + get { + return ResourceManager.GetString("Device_complies_with_ADC_3_T10_1895_D_revision_05", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC-3 T10/1895-D revision 05a. + /// + internal static string Device_complies_with_ADC_3_T10_1895_D_revision_05a { + get { + return ResourceManager.GetString("Device_complies_with_ADC_3_T10_1895_D_revision_05a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC-4 (no version claimed). + /// + internal static string Device_complies_with_ADC_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ADC_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC ANSI INCITS 403-2005. + /// + internal static string Device_complies_with_ADC_ANSI_INCITS_403_2005 { + get { + return ResourceManager.GetString("Device_complies_with_ADC_ANSI_INCITS_403_2005", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC (no version claimed). + /// + internal static string Device_complies_with_ADC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ADC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC T10/1558-D revision 6. + /// + internal static string Device_complies_with_ADC_T10_1558_D_revision_6 { + get { + return ResourceManager.GetString("Device_complies_with_ADC_T10_1558_D_revision_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADC T10/1558-D revision 7. + /// + internal static string Device_complies_with_ADC_T10_1558_D_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_ADC_T10_1558_D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADP (no version claimed). + /// + internal static string Device_complies_with_ADP_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ADP_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADT-2 ANSI INCITS 472-2011. + /// + internal static string Device_complies_with_ADT_2_ANSI_INCITS_472_2011 { + get { + return ResourceManager.GetString("Device_complies_with_ADT_2_ANSI_INCITS_472_2011", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADT-2 (no version claimed). + /// + internal static string Device_complies_with_ADT_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ADT_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADT-2 T10/1742-D revision 06. + /// + internal static string Device_complies_with_ADT_2_T10_1742_D_revision_06 { + get { + return ResourceManager.GetString("Device_complies_with_ADT_2_T10_1742_D_revision_06", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADT-2 T10/1742-D revision 08. + /// + internal static string Device_complies_with_ADT_2_T10_1742_D_revision_08 { + get { + return ResourceManager.GetString("Device_complies_with_ADT_2_T10_1742_D_revision_08", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADT-2 T10/1742-D revision 09. + /// + internal static string Device_complies_with_ADT_2_T10_1742_D_revision_09 { + get { + return ResourceManager.GetString("Device_complies_with_ADT_2_T10_1742_D_revision_09", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADT-3 (no version claimed). + /// + internal static string Device_complies_with_ADT_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ADT_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADT ANSI INCITS 406-2005. + /// + internal static string Device_complies_with_ADT_ANSI_INCITS_406_2005 { + get { + return ResourceManager.GetString("Device_complies_with_ADT_ANSI_INCITS_406_2005", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADT (no version claimed). + /// + internal static string Device_complies_with_ADT_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ADT_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADT T10/1557-D revision 11. + /// + internal static string Device_complies_with_ADT_T10_1557_D_revision_11 { + get { + return ResourceManager.GetString("Device_complies_with_ADT_T10_1557_D_revision_11", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ADT T10/1557-D revision 14. + /// + internal static string Device_complies_with_ADT_T10_1557_D_revision_14 { + get { + return ResourceManager.GetString("Device_complies_with_ADT_T10_1557_D_revision_14", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ANSI IEEE 1394-1995. + /// + internal static string Device_complies_with_ANSI_IEEE_1394_1995 { + get { + return ResourceManager.GetString("Device_complies_with_ANSI_IEEE_1394_1995", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-6 ANSI INCITS 361-2002. + /// + internal static string Device_complies_with_ATA_ATAPI_6_ANSI_INCITS_361_2002 { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_6_ANSI_INCITS_361_2002", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-6 (no version claimed). + /// + internal static string Device_complies_with_ATA_ATAPI_6_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_6_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-7 ANSI INCITS 397-2005. + /// + internal static string Device_complies_with_ATA_ATAPI_7_ANSI_INCITS_397_2005 { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_7_ANSI_INCITS_397_2005", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-7 ISO/IEC 24739. + /// + internal static string Device_complies_with_ATA_ATAPI_7_ISO_IEC_24739 { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_7_ISO_IEC_24739", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-7 (no version claimed). + /// + internal static string Device_complies_with_ATA_ATAPI_7_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_7_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-7 T13/1532-D revision 3. + /// + internal static string Device_complies_with_ATA_ATAPI_7_T13_1532_D_revision_3 { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_7_T13_1532_D_revision_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-8 ATA8-AAM ANSI INCITS 451-2008. + /// + internal static string Device_complies_with_ATA_ATAPI_8_ATA8_AAM_ANSI_INCITS_451_2008 { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_8_ATA8_AAM_ANSI_INCITS_451_2008", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-8 ATA8-AAM (no version claimed). + /// + internal static string Device_complies_with_ATA_ATAPI_8_ATA8_AAM_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_8_ATA8_AAM_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-8 ATA8-ACS ANSI INCITS 452-2009 w/ Amendment 1. + /// + internal static string Device_complies_with_ATA_ATAPI_8_ATA8_ACS_ANSI_INCITS_452_2009_w__Amendment_1 { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_8_ATA8_ACS_ANSI_INCITS_452_2009_w__Amendment_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-8 ATA8-ACS ATA/ATAPI Command Set (no version claimed). + /// + internal static string Device_complies_with_ATA_ATAPI_8_ATA8_ACS_ATA_ATAPI_Command_Set_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_8_ATA8_ACS_ATA_ATAPI_Command_Set_no_version_claime" + + "d", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-8 ATA8-APT Parallel Transport (no version claimed). + /// + internal static string Device_complies_with_ATA_ATAPI_8_ATA8_APT_Parallel_Transport_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_8_ATA8_APT_Parallel_Transport_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ATA/ATAPI-8 ATA8-AST Serial Transport (no version claimed). + /// + internal static string Device_complies_with_ATA_ATAPI_8_ATA8_AST_Serial_Transport_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ATA_ATAPI_8_ATA8_AST_Serial_Transport_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with BCC (no version claimed). + /// + internal static string Device_complies_with_BCC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_BCC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with EPI ANSI INCITS TR-23 1999. + /// + internal static string Device_complies_with_EPI_ANSI_INCITS_TR_23_1999 { + get { + return ResourceManager.GetString("Device_complies_with_EPI_ANSI_INCITS_TR_23_1999", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with EPI (no version claimed). + /// + internal static string Device_complies_with_EPI_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_EPI_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with EPI T10/1134 revision 16. + /// + internal static string Device_complies_with_EPI_T10_1134_revision_16 { + get { + return ResourceManager.GetString("Device_complies_with_EPI_T10_1134_revision_16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with Fast-20 ANSI INCITS 277-1996. + /// + internal static string Device_complies_with_Fast_20_ANSI_INCITS_277_1996 { + get { + return ResourceManager.GetString("Device_complies_with_Fast_20_ANSI_INCITS_277_1996", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with Fast-20 (no version claimed). + /// + internal static string Device_complies_with_Fast_20_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_Fast_20_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with Fast-20 T10/1071 revision 06. + /// + internal static string Device_complies_with_Fast_20_T10_1071_revision_06 { + get { + return ResourceManager.GetString("Device_complies_with_Fast_20_T10_1071_revision_06", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC 10GFC ANSI INCITS 364-2003. + /// + internal static string Device_complies_with_FC_10GFC_ANSI_INCITS_364_2003 { + get { + return ResourceManager.GetString("Device_complies_with_FC_10GFC_ANSI_INCITS_364_2003", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC 10GFC ANSI INCITS 364-2003 with AM1 ANSI INCITS 364/AM1-2007. + /// + internal static string Device_complies_with_FC_10GFC_ANSI_INCITS_364_2003_with_AM1_ANSI_INCITS_364_AM1_2007 { + get { + return ResourceManager.GetString("Device_complies_with_FC_10GFC_ANSI_INCITS_364_2003_with_AM1_ANSI_INCITS_364_AM1_2" + + "007", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC 10GFC ISO/IEC 14165-116. + /// + internal static string Device_complies_with_FC_10GFC_ISO_IEC_14165_116 { + get { + return ResourceManager.GetString("Device_complies_with_FC_10GFC_ISO_IEC_14165_116", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC 10GFC ISO/IEC 14165-116 with AM1. + /// + internal static string Device_complies_with_FC_10GFC_ISO_IEC_14165_116_with_AM1 { + get { + return ResourceManager.GetString("Device_complies_with_FC_10GFC_ISO_IEC_14165_116_with_AM1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC 10GFC (no version claimed). + /// + internal static string Device_complies_with_FC_10GFC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_10GFC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-AL-2 ANSI INCITS 332-1999. + /// + internal static string Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999 { + get { + return ResourceManager.GetString("Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-AL-2 ANSI INCITS 332-1999 with AM1-2003 & AM2-2006. + /// + internal static string Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999_with_AM1_2003___AM2_2006 { + get { + return ResourceManager.GetString("Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999_with_AM1_2003___AM2_2006", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-AL-2 ANSI INCITS 332-1999 with Amnd 1 AM1-2003. + /// + internal static string Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999_with_Amnd_1_AM1_2003 { + get { + return ResourceManager.GetString("Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999_with_Amnd_1_AM1_2003", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-AL-2 ANSI INCITS 332-1999 with Amnd 2 AM2-2006. + /// + internal static string Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999_with_Amnd_2_AM2_2006 { + get { + return ResourceManager.GetString("Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999_with_Amnd_2_AM2_2006", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-AL-2 ISO/IEC 14165-122 with AM1 & AM2. + /// + internal static string Device_complies_with_FC_AL_2_ISO_IEC_14165_122_with_AM1___AM2 { + get { + return ResourceManager.GetString("Device_complies_with_FC_AL_2_ISO_IEC_14165_122_with_AM1___AM2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-AL-2 (no version claimed). + /// + internal static string Device_complies_with_FC_AL_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_AL_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-AL-2 T11/1133-D revision 7.0. + /// + internal static string Device_complies_with_FC_AL_2_T11_1133_D_revision_7_0 { + get { + return ResourceManager.GetString("Device_complies_with_FC_AL_2_T11_1133_D_revision_7_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-AL ANSI INCITS 272-1996. + /// + internal static string Device_complies_with_FC_AL_ANSI_INCITS_272_1996 { + get { + return ResourceManager.GetString("Device_complies_with_FC_AL_ANSI_INCITS_272_1996", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-AL (no version claimed). + /// + internal static string Device_complies_with_FC_AL_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_AL_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-DA-2 INCITS TR-49 2012. + /// + internal static string Device_complies_with_FC_DA_2_INCITS_TR_49_2012 { + get { + return ResourceManager.GetString("Device_complies_with_FC_DA_2_INCITS_TR_49_2012", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-DA-2 (no version claimed). + /// + internal static string Device_complies_with_FC_DA_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_DA_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-DA-2 T11/1870DT revision 1.04. + /// + internal static string Device_complies_with_FC_DA_2_T11_1870DT_revision_1_04 { + get { + return ResourceManager.GetString("Device_complies_with_FC_DA_2_T11_1870DT_revision_1_04", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-DA-2 T11/1870DT revision 1.06. + /// + internal static string Device_complies_with_FC_DA_2_T11_1870DT_revision_1_06 { + get { + return ResourceManager.GetString("Device_complies_with_FC_DA_2_T11_1870DT_revision_1_06", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-DA ANSI INCITS TR-36 2004. + /// + internal static string Device_complies_with_FC_DA_ANSI_INCITS_TR_36_2004 { + get { + return ResourceManager.GetString("Device_complies_with_FC_DA_ANSI_INCITS_TR_36_2004", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-DA ISO/IEC 14165-341. + /// + internal static string Device_complies_with_FC_DA_ISO_IEC_14165_341 { + get { + return ResourceManager.GetString("Device_complies_with_FC_DA_ISO_IEC_14165_341", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-DA (no version claimed). + /// + internal static string Device_complies_with_FC_DA_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_DA_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-DA T11/1513-DT revision 3.1. + /// + internal static string Device_complies_with_FC_DA_T11_1513_DT_revision_3_1 { + get { + return ResourceManager.GetString("Device_complies_with_FC_DA_T11_1513_DT_revision_3_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FLA ANSI INCITS TR-20 1998. + /// + internal static string Device_complies_with_FC_FLA_ANSI_INCITS_TR_20_1998 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FLA_ANSI_INCITS_TR_20_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FLA (no version claimed). + /// + internal static string Device_complies_with_FC_FLA_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_FLA_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FLA T11/1235 revision 7. + /// + internal static string Device_complies_with_FC_FLA_T11_1235_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FLA_T11_1235_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS-2 ANSI INCITS 242-2007. + /// + internal static string Device_complies_with_FC_FS_2_ANSI_INCITS_242_2007 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_2_ANSI_INCITS_242_2007", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS-2 ANSI INCITS 242-2007 with AM1 ANSI INCITS 242/AM1-2007. + /// + internal static string Device_complies_with_FC_FS_2_ANSI_INCITS_242_2007_with_AM1_ANSI_INCITS_242_AM1_2007 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_2_ANSI_INCITS_242_2007_with_AM1_ANSI_INCITS_242_AM1_20" + + "07", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS-2 (no version claimed). + /// + internal static string Device_complies_with_FC_FS_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS-3 ANSI INCITS 470-2011. + /// + internal static string Device_complies_with_FC_FS_3_ANSI_INCITS_470_2011 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_3_ANSI_INCITS_470_2011", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS-3 (no version claimed). + /// + internal static string Device_complies_with_FC_FS_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS-3 T11/1861-D revision 0.9. + /// + internal static string Device_complies_with_FC_FS_3_T11_1861_D_revision_0_9 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_3_T11_1861_D_revision_0_9", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS-3 T11/1861-D revision 1.0. + /// + internal static string Device_complies_with_FC_FS_3_T11_1861_D_revision_1_0 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_3_T11_1861_D_revision_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS-3 T11/1861-D revision 1.10. + /// + internal static string Device_complies_with_FC_FS_3_T11_1861_D_revision_1_10 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_3_T11_1861_D_revision_1_10", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS-4 (no version claimed). + /// + internal static string Device_complies_with_FC_FS_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS ANSI INCITS 373-2003. + /// + internal static string Device_complies_with_FC_FS_ANSI_INCITS_373_2003 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_ANSI_INCITS_373_2003", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS ISO/IEC 14165-251. + /// + internal static string Device_complies_with_FC_FS_ISO_IEC_14165_251 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_ISO_IEC_14165_251", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS (no version claimed). + /// + internal static string Device_complies_with_FC_FS_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS T11/1331-D revision 1.2. + /// + internal static string Device_complies_with_FC_FS_T11_1331_D_revision_1_2 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_T11_1331_D_revision_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-FS T11/1331-D revision 1.7. + /// + internal static string Device_complies_with_FC_FS_T11_1331_D_revision_1_7 { + get { + return ResourceManager.GetString("Device_complies_with_FC_FS_T11_1331_D_revision_1_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-LS-2 ANSI INCITS 477-2011. + /// + internal static string Device_complies_with_FC_LS_2_ANSI_INCITS_477_2011 { + get { + return ResourceManager.GetString("Device_complies_with_FC_LS_2_ANSI_INCITS_477_2011", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-LS-2 (no version claimed). + /// + internal static string Device_complies_with_FC_LS_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_LS_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-LS-2 T11/2103-D revision 2.11. + /// + internal static string Device_complies_with_FC_LS_2_T11_2103_D_revision_2_11 { + get { + return ResourceManager.GetString("Device_complies_with_FC_LS_2_T11_2103_D_revision_2_11", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-LS-2 T11/2103-D revision 2.21. + /// + internal static string Device_complies_with_FC_LS_2_T11_2103_D_revision_2_21 { + get { + return ResourceManager.GetString("Device_complies_with_FC_LS_2_T11_2103_D_revision_2_21", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-LS-3 (no version claimed). + /// + internal static string Device_complies_with_FC_LS_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_LS_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-LS ANSI INCITS 433-2007. + /// + internal static string Device_complies_with_FC_LS_ANSI_INCITS_433_2007 { + get { + return ResourceManager.GetString("Device_complies_with_FC_LS_ANSI_INCITS_433_2007", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-LS (no version claimed). + /// + internal static string Device_complies_with_FC_LS_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_LS_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-LS T11/1620-D revision 1.62. + /// + internal static string Device_complies_with_FC_LS_T11_1620_D_revision_1_62 { + get { + return ResourceManager.GetString("Device_complies_with_FC_LS_T11_1620_D_revision_1_62", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PH-3 ANSI INCITS 303-1998. + /// + internal static string Device_complies_with_FC_PH_3_ANSI_INCITS_303_1998 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PH_3_ANSI_INCITS_303_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PH-3 (no version claimed). + /// + internal static string Device_complies_with_FC_PH_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_PH_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PH ANSI INCITS 230-1994. + /// + internal static string Device_complies_with_FC_PH_ANSI_INCITS_230_1994 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PH_ANSI_INCITS_230_1994", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PH ANSI INCITS 230-1994 with Amnd 1 ANSI INCITS 230/AM1-1996. + /// + internal static string Device_complies_with_FC_PH_ANSI_INCITS_230_1994_with_Amnd_1_ANSI_INCITS_230_AM1_1996 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PH_ANSI_INCITS_230_1994_with_Amnd_1_ANSI_INCITS_230_AM1_1" + + "996", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PH (no version claimed). + /// + internal static string Device_complies_with_FC_PH_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_PH_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-2 ANSI INCITS 404-2006. + /// + internal static string Device_complies_with_FC_PI_2_ANSI_INCITS_404_2006 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_2_ANSI_INCITS_404_2006", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-2 (no version claimed). + /// + internal static string Device_complies_with_FC_PI_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-2 T11/1506-D revision 5.0. + /// + internal static string Device_complies_with_FC_PI_2_T11_1506_D_revision_5_0 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_2_T11_1506_D_revision_5_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-3 ANSI INCITS 460-2011. + /// + internal static string Device_complies_with_FC_PI_3_ANSI_INCITS_460_2011 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_3_ANSI_INCITS_460_2011", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-3 (no version claimed). + /// + internal static string Device_complies_with_FC_PI_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-3 T11/1625-D revision 2.0. + /// + internal static string Device_complies_with_FC_PI_3_T11_1625_D_revision_2_0 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_3_T11_1625_D_revision_2_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-3 T11/1625-D revision 2.1. + /// + internal static string Device_complies_with_FC_PI_3_T11_1625_D_revision_2_1 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_3_T11_1625_D_revision_2_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-3 T11/1625-D revision 4.0. + /// + internal static string Device_complies_with_FC_PI_3_T11_1625_D_revision_4_0 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_3_T11_1625_D_revision_4_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-4 ANSI INCITS 450-2009. + /// + internal static string Device_complies_with_FC_PI_4_ANSI_INCITS_450_2009 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_4_ANSI_INCITS_450_2009", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-4 (no version claimed). + /// + internal static string Device_complies_with_FC_PI_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-4 T11/1647-D revision 8.0. + /// + internal static string Device_complies_with_FC_PI_4_T11_1647_D_revision_8_0 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_4_T11_1647_D_revision_8_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-5 ANSI INCITS 479-2011. + /// + internal static string Device_complies_with_FC_PI_5_ANSI_INCITS_479_2011 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_5_ANSI_INCITS_479_2011", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-5 (no version claimed). + /// + internal static string Device_complies_with_FC_PI_5_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_5_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-5 T11/2118-D revision 2.00. + /// + internal static string Device_complies_with_FC_PI_5_T11_2118_D_revision_2_00 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_5_T11_2118_D_revision_2_00", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-5 T11/2118-D revision 3.00. + /// + internal static string Device_complies_with_FC_PI_5_T11_2118_D_revision_3_00 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_5_T11_2118_D_revision_3_00", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-5 T11/2118-D revision 6.00. + /// + internal static string Device_complies_with_FC_PI_5_T11_2118_D_revision_6_00 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_5_T11_2118_D_revision_6_00", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-5 T11/2118-D revision 6.10. + /// + internal static string Device_complies_with_FC_PI_5_T11_2118_D_revision_6_10 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_5_T11_2118_D_revision_6_10", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI-6 (no version claimed). + /// + internal static string Device_complies_with_FC_PI_6_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_6_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI ANSI INCITS 352-2002. + /// + internal static string Device_complies_with_FC_PI_ANSI_INCITS_352_2002 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_ANSI_INCITS_352_2002", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PI (no version claimed). + /// + internal static string Device_complies_with_FC_PI_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_PI_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PLDA ANSI INCITS TR-19 1998. + /// + internal static string Device_complies_with_FC_PLDA_ANSI_INCITS_TR_19_1998 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PLDA_ANSI_INCITS_TR_19_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PLDA (no version claimed). + /// + internal static string Device_complies_with_FC_PLDA_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_PLDA_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-PLDA T11/1162 revision 2.1. + /// + internal static string Device_complies_with_FC_PLDA_T11_1162_revision_2_1 { + get { + return ResourceManager.GetString("Device_complies_with_FC_PLDA_T11_1162_revision_2_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-SCM INCITS TR-47 2012. + /// + internal static string Device_complies_with_FC_SCM_INCITS_TR_47_2012 { + get { + return ResourceManager.GetString("Device_complies_with_FC_SCM_INCITS_TR_47_2012", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-SCM (no version claimed). + /// + internal static string Device_complies_with_FC_SCM_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_SCM_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-SCM T11/1824DT revision 1.0. + /// + internal static string Device_complies_with_FC_SCM_T11_1824DT_revision_1_0 { + get { + return ResourceManager.GetString("Device_complies_with_FC_SCM_T11_1824DT_revision_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-SCM T11/1824DT revision 1.1. + /// + internal static string Device_complies_with_FC_SCM_T11_1824DT_revision_1_1 { + get { + return ResourceManager.GetString("Device_complies_with_FC_SCM_T11_1824DT_revision_1_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-SCM T11/1824DT revision 1.4. + /// + internal static string Device_complies_with_FC_SCM_T11_1824DT_revision_1_4 { + get { + return ResourceManager.GetString("Device_complies_with_FC_SCM_T11_1824DT_revision_1_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-SP-2 (no version claimed). + /// + internal static string Device_complies_with_FC_SP_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_SP_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-SP ANSI INCITS 426-2007. + /// + internal static string Device_complies_with_FC_SP_ANSI_INCITS_426_2007 { + get { + return ResourceManager.GetString("Device_complies_with_FC_SP_ANSI_INCITS_426_2007", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-SP (no version claimed). + /// + internal static string Device_complies_with_FC_SP_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_SP_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-SP T11/1570-D revision 1.6. + /// + internal static string Device_complies_with_FC_SP_T11_1570_D_revision_1_6 { + get { + return ResourceManager.GetString("Device_complies_with_FC_SP_T11_1570_D_revision_1_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-Tape ANSI INCITS TR-24 1999. + /// + internal static string Device_complies_with_FC_Tape_ANSI_INCITS_TR_24_1999 { + get { + return ResourceManager.GetString("Device_complies_with_FC_Tape_ANSI_INCITS_TR_24_1999", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-Tape (no version claimed). + /// + internal static string Device_complies_with_FC_Tape_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FC_Tape_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-Tape T11/1315 revision 1.16. + /// + internal static string Device_complies_with_FC_Tape_T11_1315_revision_1_16 { + get { + return ResourceManager.GetString("Device_complies_with_FC_Tape_T11_1315_revision_1_16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FC-Tape T11/1315 revision 1.17. + /// + internal static string Device_complies_with_FC_Tape_T11_1315_revision_1_17 { + get { + return ResourceManager.GetString("Device_complies_with_FC_Tape_T11_1315_revision_1_17", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-2 ANSI INCITS 350-2003. + /// + internal static string Device_complies_with_FCP_2_ANSI_INCITS_350_2003 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_2_ANSI_INCITS_350_2003", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-2 (no version claimed). + /// + internal static string Device_complies_with_FCP_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FCP_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-2 T10/1144-D revision 4. + /// + internal static string Device_complies_with_FCP_2_T10_1144_D_revision_4 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_2_T10_1144_D_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-2 T10/1144-D revision 7. + /// + internal static string Device_complies_with_FCP_2_T10_1144_D_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_2_T10_1144_D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-2 T10/1144-D revision 7a. + /// + internal static string Device_complies_with_FCP_2_T10_1144_D_revision_7a { + get { + return ResourceManager.GetString("Device_complies_with_FCP_2_T10_1144_D_revision_7a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-2 T10/1144-D revision 8. + /// + internal static string Device_complies_with_FCP_2_T10_1144_D_revision_8 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_2_T10_1144_D_revision_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-3 ANSI INCITS 416-2006. + /// + internal static string Device_complies_with_FCP_3_ANSI_INCITS_416_2006 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_3_ANSI_INCITS_416_2006", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-3 ISO/IEC 14776-223. + /// + internal static string Device_complies_with_FCP_3_ISO_IEC_14776_223 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_3_ISO_IEC_14776_223", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-3 (no version claimed). + /// + internal static string Device_complies_with_FCP_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FCP_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-3 T10/1560-D revision 3f. + /// + internal static string Device_complies_with_FCP_3_T10_1560_D_revision_3f { + get { + return ResourceManager.GetString("Device_complies_with_FCP_3_T10_1560_D_revision_3f", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-3 T10/1560-D revision 4. + /// + internal static string Device_complies_with_FCP_3_T10_1560_D_revision_4 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_3_T10_1560_D_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-4 ANSI INCITS 481-2012. + /// + internal static string Device_complies_with_FCP_4_ANSI_INCITS_481_2012 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_4_ANSI_INCITS_481_2012", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-4 (no version claimed). + /// + internal static string Device_complies_with_FCP_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FCP_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-4 T10/1828-D revision 01. + /// + internal static string Device_complies_with_FCP_4_T10_1828_D_revision_01 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_4_T10_1828_D_revision_01", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-4 T10/1828-D revision 02. + /// + internal static string Device_complies_with_FCP_4_T10_1828_D_revision_02 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_4_T10_1828_D_revision_02", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP-4 T10/1828-D revision 02b. + /// + internal static string Device_complies_with_FCP_4_T10_1828_D_revision_02b { + get { + return ResourceManager.GetString("Device_complies_with_FCP_4_T10_1828_D_revision_02b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP ANSI INCITS 269-1996. + /// + internal static string Device_complies_with_FCP_ANSI_INCITS_269_1996 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_ANSI_INCITS_269_1996", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP (no version claimed). + /// + internal static string Device_complies_with_FCP_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_FCP_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with FCP T10/0993-D revision 12. + /// + internal static string Device_complies_with_FCP_T10_0993_D_revision_12 { + get { + return ResourceManager.GetString("Device_complies_with_FCP_T10_0993_D_revision_12", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with IEEE 1394 (no version claimed). + /// + internal static string Device_complies_with_IEEE_1394_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_IEEE_1394_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with IEEE 1394a (no version claimed). + /// + internal static string Device_complies_with_IEEE_1394a_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_IEEE_1394a_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with IEEE 1394b (no version claimed). + /// + internal static string Device_complies_with_IEEE_1394b_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_IEEE_1394b_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with IEEE 1667-2006. + /// + internal static string Device_complies_with_IEEE_1667_2006 { + get { + return ResourceManager.GetString("Device_complies_with_IEEE_1667_2006", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with IEEE 1667-2009. + /// + internal static string Device_complies_with_IEEE_1667_2009 { + get { + return ResourceManager.GetString("Device_complies_with_IEEE_1667_2009", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with IEEE 1667 (no version claimed). + /// + internal static string Device_complies_with_IEEE_1667_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_IEEE_1667_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with iSCSI (no version claimed). + /// + internal static string Device_complies_with_iSCSI_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_iSCSI_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with iSCSI revision {0}. + /// + internal static string Device_complies_with_iSCSI_revision_0 { + get { + return ResourceManager.GetString("Device_complies_with_iSCSI_revision_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-2 ANSI INCITS 333-2000. + /// + internal static string Device_complies_with_MMC_2_ANSI_INCITS_333_2000 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_2_ANSI_INCITS_333_2000", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-2 (no version claimed). + /// + internal static string Device_complies_with_MMC_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_MMC_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-2 T10/1228-D revision 11. + /// + internal static string Device_complies_with_MMC_2_T10_1228_D_revision_11 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_2_T10_1228_D_revision_11", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-2 T10/1228-D revision 11a. + /// + internal static string Device_complies_with_MMC_2_T10_1228_D_revision_11a { + get { + return ResourceManager.GetString("Device_complies_with_MMC_2_T10_1228_D_revision_11a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-3 ANSI INCITS 360-2002. + /// + internal static string Device_complies_with_MMC_3_ANSI_INCITS_360_2002 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_3_ANSI_INCITS_360_2002", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-3 (no version claimed). + /// + internal static string Device_complies_with_MMC_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_MMC_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-3 T10/1363-D revision 10g. + /// + internal static string Device_complies_with_MMC_3_T10_1363_D_revision_10g { + get { + return ResourceManager.GetString("Device_complies_with_MMC_3_T10_1363_D_revision_10g", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-3 T10/1363-D revision 9. + /// + internal static string Device_complies_with_MMC_3_T10_1363_D_revision_9 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_3_T10_1363_D_revision_9", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-4 ANSI INCITS 401-2005. + /// + internal static string Device_complies_with_MMC_4_ANSI_INCITS_401_2005 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_4_ANSI_INCITS_401_2005", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-4 (no version claimed). + /// + internal static string Device_complies_with_MMC_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_MMC_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-4 T10/1545-D revision 3. + /// + internal static string Device_complies_with_MMC_4_T10_1545_D_revision_3 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_4_T10_1545_D_revision_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-4 T10/1545-D revision 3d. + /// + internal static string Device_complies_with_MMC_4_T10_1545_D_revision_3d { + get { + return ResourceManager.GetString("Device_complies_with_MMC_4_T10_1545_D_revision_3d", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-4 T10/1545-D revision 5. + /// + internal static string Device_complies_with_MMC_4_T10_1545_D_revision_5 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_4_T10_1545_D_revision_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-4 T10/1545-D revision 5a. + /// + internal static string Device_complies_with_MMC_4_T10_1545_D_revision_5a { + get { + return ResourceManager.GetString("Device_complies_with_MMC_4_T10_1545_D_revision_5a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-5 ANSI INCITS 430-2007. + /// + internal static string Device_complies_with_MMC_5_ANSI_INCITS_430_2007 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_5_ANSI_INCITS_430_2007", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-5 (no version claimed). + /// + internal static string Device_complies_with_MMC_5_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_MMC_5_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-5 T10/1675-D revision 03. + /// + internal static string Device_complies_with_MMC_5_T10_1675_D_revision_03 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_5_T10_1675_D_revision_03", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-5 T10/1675-D revision 03b. + /// + internal static string Device_complies_with_MMC_5_T10_1675_D_revision_03b { + get { + return ResourceManager.GetString("Device_complies_with_MMC_5_T10_1675_D_revision_03b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-5 T10/1675-D revision 04. + /// + internal static string Device_complies_with_MMC_5_T10_1675_D_revision_04 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_5_T10_1675_D_revision_04", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-6 ANSI INCITS 468-2010. + /// + internal static string Device_complies_with_MMC_6_ANSI_INCITS_468_2010 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_6_ANSI_INCITS_468_2010", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-6 ANSI INCITS 468-2010 + MMC-6/AM1 ANSI INCITS 468-2010/AM 1. + /// + internal static string Device_complies_with_MMC_6_ANSI_INCITS_468_2010_MMC_6_AM1_ANSI_INCITS_468_2010_AM_1 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_6_ANSI_INCITS_468_2010_MMC_6_AM1_ANSI_INCITS_468_2010_AM" + + "_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-6 (no version claimed). + /// + internal static string Device_complies_with_MMC_6_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_MMC_6_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-6 T10/1836-D revision 02b. + /// + internal static string Device_complies_with_MMC_6_T10_1836_D_revision_02b { + get { + return ResourceManager.GetString("Device_complies_with_MMC_6_T10_1836_D_revision_02b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC-6 T10/1836-D revision 02g. + /// + internal static string Device_complies_with_MMC_6_T10_1836_D_revision_02g { + get { + return ResourceManager.GetString("Device_complies_with_MMC_6_T10_1836_D_revision_02g", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC ANSI INCITS 304-1997. + /// + internal static string Device_complies_with_MMC_ANSI_INCITS_304_1997 { + get { + return ResourceManager.GetString("Device_complies_with_MMC_ANSI_INCITS_304_1997", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC (no version claimed). + /// + internal static string Device_complies_with_MMC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_MMC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with MMC T10/1048-D revision 10a. + /// + internal static string Device_complies_with_MMC_T10_1048_D_revision_10a { + get { + return ResourceManager.GetString("Device_complies_with_MMC_T10_1048_D_revision_10a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OCRW ISO/IEC 14776-381. + /// + internal static string Device_complies_with_OCRW_ISO_IEC_14776_381 { + get { + return ResourceManager.GetString("Device_complies_with_OCRW_ISO_IEC_14776_381", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OCRW (no version claimed). + /// + internal static string Device_complies_with_OCRW_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_OCRW_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD-2 ANSI INCITS 458-2011. + /// + internal static string Device_complies_with_OSD_2_ANSI_INCITS_458_2011 { + get { + return ResourceManager.GetString("Device_complies_with_OSD_2_ANSI_INCITS_458_2011", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD-2 (no version claimed). + /// + internal static string Device_complies_with_OSD_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_OSD_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD-2 T10/1729-D revision 4. + /// + internal static string Device_complies_with_OSD_2_T10_1729_D_revision_4 { + get { + return ResourceManager.GetString("Device_complies_with_OSD_2_T10_1729_D_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD-2 T10/1729-D revision 5. + /// + internal static string Device_complies_with_OSD_2_T10_1729_D_revision_5 { + get { + return ResourceManager.GetString("Device_complies_with_OSD_2_T10_1729_D_revision_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD-3 (no version claimed). + /// + internal static string Device_complies_with_OSD_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_OSD_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD ANSI INCITS 400-2004. + /// + internal static string Device_complies_with_OSD_ANSI_INCITS_400_2004 { + get { + return ResourceManager.GetString("Device_complies_with_OSD_ANSI_INCITS_400_2004", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD (no version claimed). + /// + internal static string Device_complies_with_OSD_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_OSD_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD T10/1355-D revision 0. + /// + internal static string Device_complies_with_OSD_T10_1355_D_revision_0 { + get { + return ResourceManager.GetString("Device_complies_with_OSD_T10_1355_D_revision_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD T10/1355-D revision 10. + /// + internal static string Device_complies_with_OSD_T10_1355_D_revision_10 { + get { + return ResourceManager.GetString("Device_complies_with_OSD_T10_1355_D_revision_10", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD T10/1355-D revision 7a. + /// + internal static string Device_complies_with_OSD_T10_1355_D_revision_7a { + get { + return ResourceManager.GetString("Device_complies_with_OSD_T10_1355_D_revision_7a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD T10/1355-D revision 8. + /// + internal static string Device_complies_with_OSD_T10_1355_D_revision_8 { + get { + return ResourceManager.GetString("Device_complies_with_OSD_T10_1355_D_revision_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with OSD T10/1355-D revision 9. + /// + internal static string Device_complies_with_OSD_T10_1355_D_revision_9 { + get { + return ResourceManager.GetString("Device_complies_with_OSD_T10_1355_D_revision_9", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with PQI-2 (no version claimed). + /// + internal static string Device_complies_with_PQI_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_PQI_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with PQI ANSI INCITS 490-2014. + /// + internal static string Device_complies_with_PQI_ANSI_INCITS_490_2014 { + get { + return ResourceManager.GetString("Device_complies_with_PQI_ANSI_INCITS_490_2014", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with PQI (no version claimed). + /// + internal static string Device_complies_with_PQI_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_PQI_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with PQI T10/BSR INCITS 490 revision 6. + /// + internal static string Device_complies_with_PQI_T10_BSR_INCITS_490_revision_6 { + get { + return ResourceManager.GetString("Device_complies_with_PQI_T10_BSR_INCITS_490_revision_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with PQI T10/BSR INCITS 490 revision 7. + /// + internal static string Device_complies_with_PQI_T10_BSR_INCITS_490_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_PQI_T10_BSR_INCITS_490_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with RBC ANSI INCITS 330-2000. + /// + internal static string Device_complies_with_RBC_ANSI_INCITS_330_2000 { + get { + return ResourceManager.GetString("Device_complies_with_RBC_ANSI_INCITS_330_2000", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with RBC (no version claimed). + /// + internal static string Device_complies_with_RBC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_RBC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with RBC T10/1240-D revision 10a. + /// + internal static string Device_complies_with_RBC_T10_1240_D_revision_10a { + get { + return ResourceManager.GetString("Device_complies_with_RBC_T10_1240_D_revision_10a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-2 ANSI INCITS 366-2003. + /// + internal static string Device_complies_with_SAM_2_ANSI_INCITS_366_2003 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_2_ANSI_INCITS_366_2003", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-2 ISO/IEC 14776-412. + /// + internal static string Device_complies_with_SAM_2_ISO_IEC_14776_412 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_2_ISO_IEC_14776_412", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-2 (no version claimed). + /// + internal static string Device_complies_with_SAM_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAM_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-2 T10/1157-D revision 23. + /// + internal static string Device_complies_with_SAM_2_T10_1157_D_revision_23 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_2_T10_1157_D_revision_23", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-2 T10/1157-D revision 24. + /// + internal static string Device_complies_with_SAM_2_T10_1157_D_revision_24 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_2_T10_1157_D_revision_24", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-3 ANSI INCITS 402-2005. + /// + internal static string Device_complies_with_SAM_3_ANSI_INCITS_402_2005 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_3_ANSI_INCITS_402_2005", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-3 (no version claimed). + /// + internal static string Device_complies_with_SAM_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAM_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-3 T10/1561-D revision 13. + /// + internal static string Device_complies_with_SAM_3_T10_1561_D_revision_13 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_3_T10_1561_D_revision_13", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-3 T10/1561-D revision 14. + /// + internal static string Device_complies_with_SAM_3_T10_1561_D_revision_14 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_3_T10_1561_D_revision_14", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-3 T10/1561-D revision 7. + /// + internal static string Device_complies_with_SAM_3_T10_1561_D_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_3_T10_1561_D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-4 ANSI INCITS 447-2008. + /// + internal static string Device_complies_with_SAM_4_ANSI_INCITS_447_2008 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_4_ANSI_INCITS_447_2008", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-4 ISO/IEC 14776-414. + /// + internal static string Device_complies_with_SAM_4_ISO_IEC_14776_414 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_4_ISO_IEC_14776_414", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-4 (no version claimed). + /// + internal static string Device_complies_with_SAM_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAM_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-4 T10/1683-D revision 13. + /// + internal static string Device_complies_with_SAM_4_T10_1683_D_revision_13 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_4_T10_1683_D_revision_13", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-4 T10/1683-D revision 14. + /// + internal static string Device_complies_with_SAM_4_T10_1683_D_revision_14 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_4_T10_1683_D_revision_14", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-5 (no version claimed). + /// + internal static string Device_complies_with_SAM_5_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAM_5_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-5 T10/2104-D revision 20. + /// + internal static string Device_complies_with_SAM_5_T10_2104_D_revision_20 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_5_T10_2104_D_revision_20", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-5 T10/2104-D revision 21. + /// + internal static string Device_complies_with_SAM_5_T10_2104_D_revision_21 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_5_T10_2104_D_revision_21", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-5 T10/2104-D revision 4. + /// + internal static string Device_complies_with_SAM_5_T10_2104_D_revision_4 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_5_T10_2104_D_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM-6 (no version claimed). + /// + internal static string Device_complies_with_SAM_6_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAM_6_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM ANSI INCITS 270-1996. + /// + internal static string Device_complies_with_SAM_ANSI_INCITS_270_1996 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_ANSI_INCITS_270_1996", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM (no version claimed). + /// + internal static string Device_complies_with_SAM_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAM_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAM T10/0994-D revision 18. + /// + internal static string Device_complies_with_SAM_T10_0994_D_revision_18 { + get { + return ResourceManager.GetString("Device_complies_with_SAM_T10_0994_D_revision_18", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-1.1 ANSI INCITS 417-2006. + /// + internal static string Device_complies_with_SAS_1_1_ANSI_INCITS_417_2006 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_1_1_ANSI_INCITS_417_2006", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-1.1 ISO/IEC 14776-151. + /// + internal static string Device_complies_with_SAS_1_1_ISO_IEC_14776_151 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_1_1_ISO_IEC_14776_151", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-1.1 (no version claimed). + /// + internal static string Device_complies_with_SAS_1_1_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAS_1_1_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-1.1 T10/1601-D revision 10. + /// + internal static string Device_complies_with_SAS_1_1_T10_1601_D_revision_10 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_1_1_T10_1601_D_revision_10", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-1.1 T10/1601-D revision 9. + /// + internal static string Device_complies_with_SAS_1_1_T10_1601_D_revision_9 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_1_1_T10_1601_D_revision_9", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2.1 ANSI INCITS 478-2011. + /// + internal static string Device_complies_with_SAS_2_1_ANSI_INCITS_478_2011 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_1_ANSI_INCITS_478_2011", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2.1 ANSI INCITS 478-2011 w/ Amnd 1 ANSI INCITS 478/AM1-2014. + /// + internal static string Device_complies_with_SAS_2_1_ANSI_INCITS_478_2011_w__Amnd_1_ANSI_INCITS_478_AM1_2014 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_1_ANSI_INCITS_478_2011_w__Amnd_1_ANSI_INCITS_478_AM1_2" + + "014", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2.1 ISO/IEC 14776-153. + /// + internal static string Device_complies_with_SAS_2_1_ISO_IEC_14776_153 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_1_ISO_IEC_14776_153", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2.1 (no version claimed). + /// + internal static string Device_complies_with_SAS_2_1_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_1_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2.1 T10/2125-D revision 04. + /// + internal static string Device_complies_with_SAS_2_1_T10_2125_D_revision_04 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_1_T10_2125_D_revision_04", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2.1 T10/2125-D revision 06. + /// + internal static string Device_complies_with_SAS_2_1_T10_2125_D_revision_06 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_1_T10_2125_D_revision_06", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2.1 T10/2125-D revision 07. + /// + internal static string Device_complies_with_SAS_2_1_T10_2125_D_revision_07 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_1_T10_2125_D_revision_07", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2 ANSI INCITS 457-2010. + /// + internal static string Device_complies_with_SAS_2_ANSI_INCITS_457_2010 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_ANSI_INCITS_457_2010", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2 (no version claimed). + /// + internal static string Device_complies_with_SAS_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2 T10/1760-D revision 14. + /// + internal static string Device_complies_with_SAS_2_T10_1760_D_revision_14 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_T10_1760_D_revision_14", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2 T10/1760-D revision 15. + /// + internal static string Device_complies_with_SAS_2_T10_1760_D_revision_15 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_T10_1760_D_revision_15", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-2 T10/1760-D revision 16. + /// + internal static string Device_complies_with_SAS_2_T10_1760_D_revision_16 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_2_T10_1760_D_revision_16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-3 ANSI INCITS 519-2014. + /// + internal static string Device_complies_with_SAS_3_ANSI_INCITS_519_2014 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_3_ANSI_INCITS_519_2014", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-3 (no version claimed). + /// + internal static string Device_complies_with_SAS_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAS_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-3 T10/BSR INCITS 519 revision 05a. + /// + internal static string Device_complies_with_SAS_3_T10_BSR_INCITS_519_revision_05a { + get { + return ResourceManager.GetString("Device_complies_with_SAS_3_T10_BSR_INCITS_519_revision_05a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-3 T10/BSR INCITS 519 revision 06. + /// + internal static string Device_complies_with_SAS_3_T10_BSR_INCITS_519_revision_06 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_3_T10_BSR_INCITS_519_revision_06", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS-4 (no version claimed). + /// + internal static string Device_complies_with_SAS_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAS_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS ANSI INCITS 376-2003. + /// + internal static string Device_complies_with_SAS_ANSI_INCITS_376_2003 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_ANSI_INCITS_376_2003", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS (no version claimed). + /// + internal static string Device_complies_with_SAS_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAS_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS T10/1562-D revision 01. + /// + internal static string Device_complies_with_SAS_T10_1562_D_revision_01 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_T10_1562_D_revision_01", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS T10/1562-D revision 03. + /// + internal static string Device_complies_with_SAS_T10_1562_D_revision_03 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_T10_1562_D_revision_03", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS T10/1562-D revision 04. + /// + internal static string Device_complies_with_SAS_T10_1562_D_revision_04 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_T10_1562_D_revision_04", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAS T10/1562-D revision 05. + /// + internal static string Device_complies_with_SAS_T10_1562_D_revision_05 { + get { + return ResourceManager.GetString("Device_complies_with_SAS_T10_1562_D_revision_05", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT-2 ANSI INCITS 465-2010. + /// + internal static string Device_complies_with_SAT_2_ANSI_INCITS_465_2010 { + get { + return ResourceManager.GetString("Device_complies_with_SAT_2_ANSI_INCITS_465_2010", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT-2 (no version claimed). + /// + internal static string Device_complies_with_SAT_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAT_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT-2 T10/1826-D revision 06. + /// + internal static string Device_complies_with_SAT_2_T10_1826_D_revision_06 { + get { + return ResourceManager.GetString("Device_complies_with_SAT_2_T10_1826_D_revision_06", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT-2 T10/1826-D revision 09. + /// + internal static string Device_complies_with_SAT_2_T10_1826_D_revision_09 { + get { + return ResourceManager.GetString("Device_complies_with_SAT_2_T10_1826_D_revision_09", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT-3 ANSI INCITS 517-2015. + /// + internal static string Device_complies_with_SAT_3_ANSI_INCITS_517_2015 { + get { + return ResourceManager.GetString("Device_complies_with_SAT_3_ANSI_INCITS_517_2015", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT-3 (no version claimed). + /// + internal static string Device_complies_with_SAT_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAT_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT-3 T10/BSR INCITS 517 revision 4. + /// + internal static string Device_complies_with_SAT_3_T10_BSR_INCITS_517_revision_4 { + get { + return ResourceManager.GetString("Device_complies_with_SAT_3_T10_BSR_INCITS_517_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT-3 T10/BSR INCITS 517 revision 7. + /// + internal static string Device_complies_with_SAT_3_T10_BSR_INCITS_517_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_SAT_3_T10_BSR_INCITS_517_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT-4 (no version claimed). + /// + internal static string Device_complies_with_SAT_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAT_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT ANSI INCITS 431-2007. + /// + internal static string Device_complies_with_SAT_ANSI_INCITS_431_2007 { + get { + return ResourceManager.GetString("Device_complies_with_SAT_ANSI_INCITS_431_2007", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT (no version claimed). + /// + internal static string Device_complies_with_SAT_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SAT_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT T10/1711-D revision 8. + /// + internal static string Device_complies_with_SAT_T10_1711_D_revision_8 { + get { + return ResourceManager.GetString("Device_complies_with_SAT_T10_1711_D_revision_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SAT T10/1711-D revision 9. + /// + internal static string Device_complies_with_SAT_T10_1711_D_revision_9 { + get { + return ResourceManager.GetString("Device_complies_with_SAT_T10_1711_D_revision_9", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-2 ANSI INCITS 405-2005. + /// + internal static string Device_complies_with_SBC_2_ANSI_INCITS_405_2005 { + get { + return ResourceManager.GetString("Device_complies_with_SBC_2_ANSI_INCITS_405_2005", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-2 ISO/IEC 14776-322. + /// + internal static string Device_complies_with_SBC_2_ISO_IEC_14776_322 { + get { + return ResourceManager.GetString("Device_complies_with_SBC_2_ISO_IEC_14776_322", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-2 (no version claimed). + /// + internal static string Device_complies_with_SBC_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SBC_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-2 T10/1417-D revision 15. + /// + internal static string Device_complies_with_SBC_2_T10_1417_D_revision_15 { + get { + return ResourceManager.GetString("Device_complies_with_SBC_2_T10_1417_D_revision_15", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-2 T10/1417-D revision 16. + /// + internal static string Device_complies_with_SBC_2_T10_1417_D_revision_16 { + get { + return ResourceManager.GetString("Device_complies_with_SBC_2_T10_1417_D_revision_16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-2 T10/1417-D revision 5a. + /// + internal static string Device_complies_with_SBC_2_T10_1417_D_revision_5a { + get { + return ResourceManager.GetString("Device_complies_with_SBC_2_T10_1417_D_revision_5a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-3 ANSI INCITS 514-2014. + /// + internal static string Device_complies_with_SBC_3_ANSI_INCITS_514_2014 { + get { + return ResourceManager.GetString("Device_complies_with_SBC_3_ANSI_INCITS_514_2014", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-3 (no version claimed). + /// + internal static string Device_complies_with_SBC_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SBC_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-3 T10/BSR INCITS 514 revision 35. + /// + internal static string Device_complies_with_SBC_3_T10_BSR_INCITS_514_revision_35 { + get { + return ResourceManager.GetString("Device_complies_with_SBC_3_T10_BSR_INCITS_514_revision_35", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-3 T10/BSR INCITS 514 revision 36. + /// + internal static string Device_complies_with_SBC_3_T10_BSR_INCITS_514_revision_36 { + get { + return ResourceManager.GetString("Device_complies_with_SBC_3_T10_BSR_INCITS_514_revision_36", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC-4 (no version claimed). + /// + internal static string Device_complies_with_SBC_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SBC_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC ANSI INCITS 306-1998. + /// + internal static string Device_complies_with_SBC_ANSI_INCITS_306_1998 { + get { + return ResourceManager.GetString("Device_complies_with_SBC_ANSI_INCITS_306_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC (no version claimed). + /// + internal static string Device_complies_with_SBC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SBC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBC T10/0996-D revision 08c. + /// + internal static string Device_complies_with_SBC_T10_0996_D_revision_08c { + get { + return ResourceManager.GetString("Device_complies_with_SBC_T10_0996_D_revision_08c", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBP-2 ANSI INCITS 325-1998. + /// + internal static string Device_complies_with_SBP_2_ANSI_INCITS_325_1998 { + get { + return ResourceManager.GetString("Device_complies_with_SBP_2_ANSI_INCITS_325_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBP-2 (no version claimed). + /// + internal static string Device_complies_with_SBP_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SBP_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBP-2 T10/1155-D revision 04. + /// + internal static string Device_complies_with_SBP_2_T10_1155_D_revision_04 { + get { + return ResourceManager.GetString("Device_complies_with_SBP_2_T10_1155_D_revision_04", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBP-3 ANSI INCITS 375-2004. + /// + internal static string Device_complies_with_SBP_3_ANSI_INCITS_375_2004 { + get { + return ResourceManager.GetString("Device_complies_with_SBP_3_ANSI_INCITS_375_2004", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBP-3 (no version claimed). + /// + internal static string Device_complies_with_SBP_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SBP_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBP-3 T10/1467-D revision 1f. + /// + internal static string Device_complies_with_SBP_3_T10_1467_D_revision_1f { + get { + return ResourceManager.GetString("Device_complies_with_SBP_3_T10_1467_D_revision_1f", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBP-3 T10/1467-D revision 3. + /// + internal static string Device_complies_with_SBP_3_T10_1467_D_revision_3 { + get { + return ResourceManager.GetString("Device_complies_with_SBP_3_T10_1467_D_revision_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBP-3 T10/1467-D revision 4. + /// + internal static string Device_complies_with_SBP_3_T10_1467_D_revision_4 { + get { + return ResourceManager.GetString("Device_complies_with_SBP_3_T10_1467_D_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SBP-3 T10/1467-D revision 5. + /// + internal static string Device_complies_with_SBP_3_T10_1467_D_revision_5 { + get { + return ResourceManager.GetString("Device_complies_with_SBP_3_T10_1467_D_revision_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SCC-2 ANSI INCITS 318-1998. + /// + internal static string Device_complies_with_SCC_2_ANSI_INCITS_318_1998 { + get { + return ResourceManager.GetString("Device_complies_with_SCC_2_ANSI_INCITS_318_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SCC-2 (no version claimed). + /// + internal static string Device_complies_with_SCC_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SCC_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SCC-2 T10/1125-D revision 04. + /// + internal static string Device_complies_with_SCC_2_T10_1125_D_revision_04 { + get { + return ResourceManager.GetString("Device_complies_with_SCC_2_T10_1125_D_revision_04", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SCC ANSI INCITS 276-1997. + /// + internal static string Device_complies_with_SCC_ANSI_INCITS_276_1997 { + get { + return ResourceManager.GetString("Device_complies_with_SCC_ANSI_INCITS_276_1997", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SCC (no version claimed). + /// + internal static string Device_complies_with_SCC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SCC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SCC T10/1047-D revision 06c. + /// + internal static string Device_complies_with_SCC_T10_1047_D_revision_06c { + get { + return ResourceManager.GetString("Device_complies_with_SCC_T10_1047_D_revision_06c", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES-2 ANSI INCITS 448-2008. + /// + internal static string Device_complies_with_SES_2_ANSI_INCITS_448_2008 { + get { + return ResourceManager.GetString("Device_complies_with_SES_2_ANSI_INCITS_448_2008", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES-2 ISO/IEC 14776-372. + /// + internal static string Device_complies_with_SES_2_ISO_IEC_14776_372 { + get { + return ResourceManager.GetString("Device_complies_with_SES_2_ISO_IEC_14776_372", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES-2 (no version claimed). + /// + internal static string Device_complies_with_SES_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SES_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES-2 T10/1559-D revision 16. + /// + internal static string Device_complies_with_SES_2_T10_1559_D_revision_16 { + get { + return ResourceManager.GetString("Device_complies_with_SES_2_T10_1559_D_revision_16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES-2 T10/1559-D revision 19. + /// + internal static string Device_complies_with_SES_2_T10_1559_D_revision_19 { + get { + return ResourceManager.GetString("Device_complies_with_SES_2_T10_1559_D_revision_19", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES-2 T10/1559-D revision 20. + /// + internal static string Device_complies_with_SES_2_T10_1559_D_revision_20 { + get { + return ResourceManager.GetString("Device_complies_with_SES_2_T10_1559_D_revision_20", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES-3 (no version claimed). + /// + internal static string Device_complies_with_SES_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SES_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES ANSI INCITS 305-1998. + /// + internal static string Device_complies_with_SES_ANSI_INCITS_305_1998 { + get { + return ResourceManager.GetString("Device_complies_with_SES_ANSI_INCITS_305_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES ANSI INCITS 305-1998 w/ Amendment ANSI INCITS.305/AM1-2000. + /// + internal static string Device_complies_with_SES_ANSI_INCITS_305_1998_Amendment_ANSI_INCITS_305_AM1_2000 { + get { + return ResourceManager.GetString("Device_complies_with_SES_ANSI_INCITS_305_1998_Amendment_ANSI_INCITS_305_AM1_2000", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES (no version claimed). + /// + internal static string Device_complies_with_SES_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SES_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES T10/1212-D revision 08b. + /// + internal static string Device_complies_with_SES_T10_1212_D_revision_08b { + get { + return ResourceManager.GetString("Device_complies_with_SES_T10_1212_D_revision_08b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SES T10/1212 revision 08b w/ Amendment ANSI INCITS.305/AM1-2000. + /// + internal static string Device_complies_with_SES_T10_1212_revision_08b_Amendment_ANSI_INCITS_305_AM1_2000 { + get { + return ResourceManager.GetString("Device_complies_with_SES_T10_1212_revision_08b_Amendment_ANSI_INCITS_305_AM1_2000" + + "", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SFSC BSR INCITS 501 revision 01. + /// + internal static string Device_complies_with_SFSC_BSR_INCITS_501_revision_01 { + get { + return ResourceManager.GetString("Device_complies_with_SFSC_BSR_INCITS_501_revision_01", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SFSC (no version claimed). + /// + internal static string Device_complies_with_SFSC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SFSC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SIP ANSI INCITS 292-1997. + /// + internal static string Device_complies_with_SIP_ANSI_INCITS_292_1997 { + get { + return ResourceManager.GetString("Device_complies_with_SIP_ANSI_INCITS_292_1997", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SIP (no version claimed). + /// + internal static string Device_complies_with_SIP_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SIP_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SIP T10/0856-D revision 10. + /// + internal static string Device_complies_with_SIP_T10_0856_D_revision_10 { + get { + return ResourceManager.GetString("Device_complies_with_SIP_T10_0856_D_revision_10", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC-2 ANSI INCITS 382-2004. + /// + internal static string Device_complies_with_SMC_2_ANSI_INCITS_382_2004 { + get { + return ResourceManager.GetString("Device_complies_with_SMC_2_ANSI_INCITS_382_2004", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC-2 (no version claimed). + /// + internal static string Device_complies_with_SMC_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SMC_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC-2 T10/1383-D revision 5. + /// + internal static string Device_complies_with_SMC_2_T10_1383_D_revision_5 { + get { + return ResourceManager.GetString("Device_complies_with_SMC_2_T10_1383_D_revision_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC-2 T10/1383-D revision 6. + /// + internal static string Device_complies_with_SMC_2_T10_1383_D_revision_6 { + get { + return ResourceManager.GetString("Device_complies_with_SMC_2_T10_1383_D_revision_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC-2 T10/1383-D revision 7. + /// + internal static string Device_complies_with_SMC_2_T10_1383_D_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_SMC_2_T10_1383_D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC-3 ANSI INCITS 484-2012. + /// + internal static string Device_complies_with_SMC_3_ANSI_INCITS_484_2012 { + get { + return ResourceManager.GetString("Device_complies_with_SMC_3_ANSI_INCITS_484_2012", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC-3 (no version claimed). + /// + internal static string Device_complies_with_SMC_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SMC_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC-3 T10/1730-D revision 15. + /// + internal static string Device_complies_with_SMC_3_T10_1730_D_revision_15 { + get { + return ResourceManager.GetString("Device_complies_with_SMC_3_T10_1730_D_revision_15", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC-3 T10/1730-D revision 16. + /// + internal static string Device_complies_with_SMC_3_T10_1730_D_revision_16 { + get { + return ResourceManager.GetString("Device_complies_with_SMC_3_T10_1730_D_revision_16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC ANSI INCITS 314-1998. + /// + internal static string Device_complies_with_SMC_ANSI_INCITS_314_1998 { + get { + return ResourceManager.GetString("Device_complies_with_SMC_ANSI_INCITS_314_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC ISO/IEC 14776-351. + /// + internal static string Device_complies_with_SMC_ISO_IEC_14776_351 { + get { + return ResourceManager.GetString("Device_complies_with_SMC_ISO_IEC_14776_351", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC (no version claimed). + /// + internal static string Device_complies_with_SMC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SMC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SMC T10/0999-D revision 10a. + /// + internal static string Device_complies_with_SMC_T10_0999_D_revision_10a { + get { + return ResourceManager.GetString("Device_complies_with_SMC_T10_0999_D_revision_10a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SOP-2 (no version claimed). + /// + internal static string Device_complies_with_SOP_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SOP_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SOP ANSI INCITS 489-2014. + /// + internal static string Device_complies_with_SOP_ANSI_INCITS_489_2014 { + get { + return ResourceManager.GetString("Device_complies_with_SOP_ANSI_INCITS_489_2014", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SOP (no version claimed). + /// + internal static string Device_complies_with_SOP_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SOP_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SOP T10/BSR INCITS 489 revision 4. + /// + internal static string Device_complies_with_SOP_T10_BSR_INCITS_489_revision_4 { + get { + return ResourceManager.GetString("Device_complies_with_SOP_T10_BSR_INCITS_489_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SOP T10/BSR INCITS 489 revision 5. + /// + internal static string Device_complies_with_SOP_T10_BSR_INCITS_489_revision_5 { + get { + return ResourceManager.GetString("Device_complies_with_SOP_T10_BSR_INCITS_489_revision_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-2 ANSI INCITS 351-2001. + /// + internal static string Device_complies_with_SPC_2_ANSI_INCITS_351_2001 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_2_ANSI_INCITS_351_2001", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-2 ISO/IEC 14776-452. + /// + internal static string Device_complies_with_SPC_2_ISO_IEC_14776_452 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_2_ISO_IEC_14776_452", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-2 (no version claimed). + /// + internal static string Device_complies_with_SPC_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPC_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-2 T10/1236-D revision 12. + /// + internal static string Device_complies_with_SPC_2_T10_1236_D_revision_12 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_2_T10_1236_D_revision_12", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-2 T10/1236-D revision 18. + /// + internal static string Device_complies_with_SPC_2_T10_1236_D_revision_18 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_2_T10_1236_D_revision_18", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-2 T10/1236-D revision 19. + /// + internal static string Device_complies_with_SPC_2_T10_1236_D_revision_19 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_2_T10_1236_D_revision_19", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-2 T10/1236-D revision 20. + /// + internal static string Device_complies_with_SPC_2_T10_1236_D_revision_20 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_2_T10_1236_D_revision_20", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-3 ANSI INCITS 408-2005. + /// + internal static string Device_complies_with_SPC_3_ANSI_INCITS_408_2005 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_3_ANSI_INCITS_408_2005", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-3 ISO/IEC 14776-453. + /// + internal static string Device_complies_with_SPC_3_ISO_IEC_14776_453 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_3_ISO_IEC_14776_453", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-3 (no version claimed). + /// + internal static string Device_complies_with_SPC_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPC_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-3 T10/1416-D revision 21. + /// + internal static string Device_complies_with_SPC_3_T10_1416_D_revision_21 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_3_T10_1416_D_revision_21", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-3 T10/1416-D revision 22. + /// + internal static string Device_complies_with_SPC_3_T10_1416_D_revision_22 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_3_T10_1416_D_revision_22", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-3 T10/1416-D revision 23. + /// + internal static string Device_complies_with_SPC_3_T10_1416_D_revision_23 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_3_T10_1416_D_revision_23", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-3 T10/1416-D revision 7. + /// + internal static string Device_complies_with_SPC_3_T10_1416_D_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_3_T10_1416_D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-4 ANSI INCITS 513-2015. + /// + internal static string Device_complies_with_SPC_4_ANSI_INCITS_513_2015 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_4_ANSI_INCITS_513_2015", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-4 (no version claimed). + /// + internal static string Device_complies_with_SPC_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPC_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-4 T10/BSR INCITS 513 revision 16. + /// + internal static string Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_16 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-4 T10/BSR INCITS 513 revision 18. + /// + internal static string Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_18 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_18", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-4 T10/BSR INCITS 513 revision 23. + /// + internal static string Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_23 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_23", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-4 T10/BSR INCITS 513 revision 36. + /// + internal static string Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_36 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_36", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-4 T10/BSR INCITS 513 revision 37. + /// + internal static string Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_37 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_37", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-4 T10/BSR INCITS 513 revision 37a. + /// + internal static string Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_37a { + get { + return ResourceManager.GetString("Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_37a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC-5 (no version claimed). + /// + internal static string Device_complies_with_SPC_5_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPC_5_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC ANSI INCITS 301-1997. + /// + internal static string Device_complies_with_SPC_ANSI_INCITS_301_1997 { + get { + return ResourceManager.GetString("Device_complies_with_SPC_ANSI_INCITS_301_1997", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC (no version claimed). + /// + internal static string Device_complies_with_SPC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPC T10/0995-D revision 11a. + /// + internal static string Device_complies_with_SPC_T10_0995_D_revision_11a { + get { + return ResourceManager.GetString("Device_complies_with_SPC_T10_0995_D_revision_11a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-2 ANSI INCITS 302-1999. + /// + internal static string Device_complies_with_SPI_2_ANSI_INCITS_302_1999 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_2_ANSI_INCITS_302_1999", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-2 (no version claimed). + /// + internal static string Device_complies_with_SPI_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPI_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-2 T10/1142-D revision 20b. + /// + internal static string Device_complies_with_SPI_2_T10_1142_D_revision_20b { + get { + return ResourceManager.GetString("Device_complies_with_SPI_2_T10_1142_D_revision_20b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-3 ANSI INCITS 336-2000. + /// + internal static string Device_complies_with_SPI_3_ANSI_INCITS_336_2000 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_3_ANSI_INCITS_336_2000", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-3 (no version claimed). + /// + internal static string Device_complies_with_SPI_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPI_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-3 T10/1302-D revision 10. + /// + internal static string Device_complies_with_SPI_3_T10_1302_D_revision_10 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_3_T10_1302_D_revision_10", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-3 T10/1302-D revision 13a. + /// + internal static string Device_complies_with_SPI_3_T10_1302_D_revision_13a { + get { + return ResourceManager.GetString("Device_complies_with_SPI_3_T10_1302_D_revision_13a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-3 T10/1302-D revision 14. + /// + internal static string Device_complies_with_SPI_3_T10_1302_D_revision_14 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_3_T10_1302_D_revision_14", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-4 ANSI INCITS 362-2002. + /// + internal static string Device_complies_with_SPI_4_ANSI_INCITS_362_2002 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_4_ANSI_INCITS_362_2002", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-4 (no version claimed). + /// + internal static string Device_complies_with_SPI_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPI_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-4 T10/1365-D revision 10. + /// + internal static string Device_complies_with_SPI_4_T10_1365_D_revision_10 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_4_T10_1365_D_revision_10", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-4 T10/1365-D revision 7. + /// + internal static string Device_complies_with_SPI_4_T10_1365_D_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_4_T10_1365_D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-4 T10/1365-D revision 9. + /// + internal static string Device_complies_with_SPI_4_T10_1365_D_revision_9 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_4_T10_1365_D_revision_9", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-5 ANSI INCITS 367-2003. + /// + internal static string Device_complies_with_SPI_5_ANSI_INCITS_367_2003 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_5_ANSI_INCITS_367_2003", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-5 (no version claimed). + /// + internal static string Device_complies_with_SPI_5_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPI_5_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-5 T10/1525-D revision 3. + /// + internal static string Device_complies_with_SPI_5_T10_1525_D_revision_3 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_5_T10_1525_D_revision_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-5 T10/1525-D revision 5. + /// + internal static string Device_complies_with_SPI_5_T10_1525_D_revision_5 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_5_T10_1525_D_revision_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI-5 T10/1525-D revision 6. + /// + internal static string Device_complies_with_SPI_5_T10_1525_D_revision_6 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_5_T10_1525_D_revision_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI ANSI INCITS 253-1995. + /// + internal static string Device_complies_with_SPI_ANSI_INCITS_253_1995 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_ANSI_INCITS_253_1995", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI ANSI INCITS 253-1995 with SPI Amnd ANSI INCITS 253/AM1-1998. + /// + internal static string Device_complies_with_SPI_ANSI_INCITS_253_1995_with_SPI_Amnd_ANSI_INCITS_253_AM1_1998 { + get { + return ResourceManager.GetString("Device_complies_with_SPI_ANSI_INCITS_253_1995_with_SPI_Amnd_ANSI_INCITS_253_AM1_1" + + "998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI (no version claimed). + /// + internal static string Device_complies_with_SPI_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPI_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI T10/0855-D revision 15a. + /// + internal static string Device_complies_with_SPI_T10_0855_D_revision_15a { + get { + return ResourceManager.GetString("Device_complies_with_SPI_T10_0855_D_revision_15a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPI T10/0855-D revision 15a with SPI Amnd revision 3a. + /// + internal static string Device_complies_with_SPI_T10_0855_D_revision_15a_with_SPI_Amnd_revision_3a { + get { + return ResourceManager.GetString("Device_complies_with_SPI_T10_0855_D_revision_15a_with_SPI_Amnd_revision_3a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL-2 ANSI INCITS 505-2013. + /// + internal static string Device_complies_with_SPL_2_ANSI_INCITS_505_2013 { + get { + return ResourceManager.GetString("Device_complies_with_SPL_2_ANSI_INCITS_505_2013", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL-2 (no version claimed). + /// + internal static string Device_complies_with_SPL_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPL_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL-2 T10/BSR INCITS 505 revision 4. + /// + internal static string Device_complies_with_SPL_2_T10_BSR_INCITS_505_revision_4 { + get { + return ResourceManager.GetString("Device_complies_with_SPL_2_T10_BSR_INCITS_505_revision_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL-2 T10/BSR INCITS 505 revision 5. + /// + internal static string Device_complies_with_SPL_2_T10_BSR_INCITS_505_revision_5 { + get { + return ResourceManager.GetString("Device_complies_with_SPL_2_T10_BSR_INCITS_505_revision_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL-3 ANSI INCITS 492-2015. + /// + internal static string Device_complies_with_SPL_3_ANSI_INCITS_492_2015 { + get { + return ResourceManager.GetString("Device_complies_with_SPL_3_ANSI_INCITS_492_2015", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL-3 (no version claimed). + /// + internal static string Device_complies_with_SPL_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPL_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL-3 T10/BSR INCITS 492 revision 6. + /// + internal static string Device_complies_with_SPL_3_T10_BSR_INCITS_492_revision_6 { + get { + return ResourceManager.GetString("Device_complies_with_SPL_3_T10_BSR_INCITS_492_revision_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL-3 T10/BSR INCITS 492 revision 7. + /// + internal static string Device_complies_with_SPL_3_T10_BSR_INCITS_492_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_SPL_3_T10_BSR_INCITS_492_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL-4 (no version claimed). + /// + internal static string Device_complies_with_SPL_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPL_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL ANSI INCITS 476-2011. + /// + internal static string Device_complies_with_SPL_ANSI_INCITS_476_2011 { + get { + return ResourceManager.GetString("Device_complies_with_SPL_ANSI_INCITS_476_2011", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL ANSI INCITS 476-2011 + SPL AM1 INCITS 476/AM1 2012. + /// + internal static string Device_complies_with_SPL_ANSI_INCITS_476_2011_SPL_AM1_INCITS_476_AM1_2012 { + get { + return ResourceManager.GetString("Device_complies_with_SPL_ANSI_INCITS_476_2011_SPL_AM1_INCITS_476_AM1_2012", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL ISO/IEC 14776-261:2012. + /// + internal static string Device_complies_with_SPL_ISO_IEC_14776_261_2012 { + get { + return ResourceManager.GetString("Device_complies_with_SPL_ISO_IEC_14776_261_2012", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL (no version claimed). + /// + internal static string Device_complies_with_SPL_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SPL_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL T10/2124-D revision 6a. + /// + internal static string Device_complies_with_SPL_T10_2124_D_revision_6a { + get { + return ResourceManager.GetString("Device_complies_with_SPL_T10_2124_D_revision_6a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SPL T10/2124-D revision 7. + /// + internal static string Device_complies_with_SPL_T10_2124_D_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_SPL_T10_2124_D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SRP ANSI INCITS 365-2002. + /// + internal static string Device_complies_with_SRP_ANSI_INCITS_365_2002 { + get { + return ResourceManager.GetString("Device_complies_with_SRP_ANSI_INCITS_365_2002", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SRP (no version claimed). + /// + internal static string Device_complies_with_SRP_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SRP_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SRP T10/1415-D revision 10. + /// + internal static string Device_complies_with_SRP_T10_1415_D_revision_10 { + get { + return ResourceManager.GetString("Device_complies_with_SRP_T10_1415_D_revision_10", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SRP T10/1415-D revision 16a. + /// + internal static string Device_complies_with_SRP_T10_1415_D_revision_16a { + get { + return ResourceManager.GetString("Device_complies_with_SRP_T10_1415_D_revision_16a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-PH2 ANSI INCITS 293-1996. + /// + internal static string Device_complies_with_SSA_PH2_ANSI_INCITS_293_1996 { + get { + return ResourceManager.GetString("Device_complies_with_SSA_PH2_ANSI_INCITS_293_1996", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-PH2 (no version claimed). + /// + internal static string Device_complies_with_SSA_PH2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSA_PH2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-PH2 T10.1/1145-D revision 09c. + /// + internal static string Device_complies_with_SSA_PH2_T10_1_1145_D_revision_09c { + get { + return ResourceManager.GetString("Device_complies_with_SSA_PH2_T10_1_1145_D_revision_09c", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-PH3 ANSI INCITS 307-1998. + /// + internal static string Device_complies_with_SSA_PH3_ANSI_INCITS_307_1998 { + get { + return ResourceManager.GetString("Device_complies_with_SSA_PH3_ANSI_INCITS_307_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-PH3 (no version claimed). + /// + internal static string Device_complies_with_SSA_PH3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSA_PH3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-PH3 T10.1/1146-D revision 05b. + /// + internal static string Device_complies_with_SSA_PH3_T10_1_1146_D_revision_05b { + get { + return ResourceManager.GetString("Device_complies_with_SSA_PH3_T10_1_1146_D_revision_05b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-S2P ANSI INCITS 294-1996. + /// + internal static string Device_complies_with_SSA_S2P_ANSI_INCITS_294_1996 { + get { + return ResourceManager.GetString("Device_complies_with_SSA_S2P_ANSI_INCITS_294_1996", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-S2P (no version claimed). + /// + internal static string Device_complies_with_SSA_S2P_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSA_S2P_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-S2P T10.1/1121-D revision 07b. + /// + internal static string Device_complies_with_SSA_S2P_T10_1_1121_D_revision_07b { + get { + return ResourceManager.GetString("Device_complies_with_SSA_S2P_T10_1_1121_D_revision_07b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-S3P ANSI INCITS 309-1998. + /// + internal static string Device_complies_with_SSA_S3P_ANSI_INCITS_309_1998 { + get { + return ResourceManager.GetString("Device_complies_with_SSA_S3P_ANSI_INCITS_309_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-S3P (no version claimed). + /// + internal static string Device_complies_with_SSA_S3P_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSA_S3P_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-S3P T10.1/1051-D revision 05b. + /// + internal static string Device_complies_with_SSA_S3P_T10_1_1051_D_revision_05b { + get { + return ResourceManager.GetString("Device_complies_with_SSA_S3P_T10_1_1051_D_revision_05b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-TL1 ANSI INCITS 295-1996. + /// + internal static string Device_complies_with_SSA_TL1_ANSI_INCITS_295_1996 { + get { + return ResourceManager.GetString("Device_complies_with_SSA_TL1_ANSI_INCITS_295_1996", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-TL1 (no version claimed). + /// + internal static string Device_complies_with_SSA_TL1_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSA_TL1_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-TL1 T10.1/0989-D revision 10b. + /// + internal static string Device_complies_with_SSA_TL1_T10_1_0989_D_revision_10b { + get { + return ResourceManager.GetString("Device_complies_with_SSA_TL1_T10_1_0989_D_revision_10b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-TL2 ANSI INCITS 308-1998. + /// + internal static string Device_complies_with_SSA_TL2_ANSI_INCITS_308_1998 { + get { + return ResourceManager.GetString("Device_complies_with_SSA_TL2_ANSI_INCITS_308_1998", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-TL2 (no version claimed). + /// + internal static string Device_complies_with_SSA_TL2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSA_TL2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSA-TL2 T10.1/1147-D revision 05b. + /// + internal static string Device_complies_with_SSA_TL2_T10_1_1147_D_revision_05b { + get { + return ResourceManager.GetString("Device_complies_with_SSA_TL2_T10_1_1147_D_revision_05b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-2 ANSI INCITS 380-2003. + /// + internal static string Device_complies_with_SSC_2_ANSI_INCITS_380_2003 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_2_ANSI_INCITS_380_2003", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-2 (no version claimed). + /// + internal static string Device_complies_with_SSC_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSC_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-2 T10/1434-D revision 7. + /// + internal static string Device_complies_with_SSC_2_T10_1434_D_revision_7 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_2_T10_1434_D_revision_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-2 T10/1434-D revision 9. + /// + internal static string Device_complies_with_SSC_2_T10_1434_D_revision_9 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_2_T10_1434_D_revision_9", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-3 ANSI INCITS 467-2011. + /// + internal static string Device_complies_with_SSC_3_ANSI_INCITS_467_2011 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_3_ANSI_INCITS_467_2011", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-3 ISO/IEC 14776-333:2013. + /// + internal static string Device_complies_with_SSC_3_ISO_IEC_14776_333_2013 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_3_ISO_IEC_14776_333_2013", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-3 (no version claimed). + /// + internal static string Device_complies_with_SSC_3_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSC_3_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-3 T10/1611-D revision 04a. + /// + internal static string Device_complies_with_SSC_3_T10_1611_D_revision_04a { + get { + return ResourceManager.GetString("Device_complies_with_SSC_3_T10_1611_D_revision_04a", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-3 T10/1611-D revision 05. + /// + internal static string Device_complies_with_SSC_3_T10_1611_D_revision_05 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_3_T10_1611_D_revision_05", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-4 ANSI INCITS 516-2013. + /// + internal static string Device_complies_with_SSC_4_ANSI_INCITS_516_2013 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_4_ANSI_INCITS_516_2013", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-4 (no version claimed). + /// + internal static string Device_complies_with_SSC_4_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSC_4_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-4 T10/BSR INCITS 516 revision 2. + /// + internal static string Device_complies_with_SSC_4_T10_BSR_INCITS_516_revision_2 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_4_T10_BSR_INCITS_516_revision_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-4 T10/BSR INCITS 516 revision 3. + /// + internal static string Device_complies_with_SSC_4_T10_BSR_INCITS_516_revision_3 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_4_T10_BSR_INCITS_516_revision_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC-5 (no version claimed). + /// + internal static string Device_complies_with_SSC_5_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSC_5_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC ANSI INCITS 335-2000. + /// + internal static string Device_complies_with_SSC_ANSI_INCITS_335_2000 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_ANSI_INCITS_335_2000", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC (no version claimed). + /// + internal static string Device_complies_with_SSC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SSC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC T10/0997-D revision 17. + /// + internal static string Device_complies_with_SSC_T10_0997_D_revision_17 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_T10_0997_D_revision_17", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SSC T10/0997-D revision 22. + /// + internal static string Device_complies_with_SSC_T10_0997_D_revision_22 { + get { + return ResourceManager.GetString("Device_complies_with_SSC_T10_0997_D_revision_22", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SST (no version claimed). + /// + internal static string Device_complies_with_SST_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_SST_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with SST T10/1380-D revision 8b. + /// + internal static string Device_complies_with_SST_T10_1380_D_revision_8b { + get { + return ResourceManager.GetString("Device_complies_with_SST_T10_1380_D_revision_8b", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with UAS-2 (no version claimed). + /// + internal static string Device_complies_with_UAS_2_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_UAS_2_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with UAS ANSI INCITS 471-2010. + /// + internal static string Device_complies_with_UAS_ANSI_INCITS_471_2010 { + get { + return ResourceManager.GetString("Device_complies_with_UAS_ANSI_INCITS_471_2010", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with UAS ISO/IEC 14776-251:2014. + /// + internal static string Device_complies_with_UAS_ISO_IEC_14776_251_2014 { + get { + return ResourceManager.GetString("Device_complies_with_UAS_ISO_IEC_14776_251_2014", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with UAS (no version claimed). + /// + internal static string Device_complies_with_UAS_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_UAS_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with UAS T10/2095-D revision 02. + /// + internal static string Device_complies_with_UAS_T10_2095_D_revision_02 { + get { + return ResourceManager.GetString("Device_complies_with_UAS_T10_2095_D_revision_02", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with UAS T10/2095-D revision 04. + /// + internal static string Device_complies_with_UAS_T10_2095_D_revision_04 { + get { + return ResourceManager.GetString("Device_complies_with_UAS_T10_2095_D_revision_04", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with Universal Serial Bus Specification, Revision 1.1. + /// + internal static string Device_complies_with_Universal_Serial_Bus_Specification__Revision_1_1 { + get { + return ResourceManager.GetString("Device_complies_with_Universal_Serial_Bus_Specification__Revision_1_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with Universal Serial Bus Specification, Revision 2.0. + /// + internal static string Device_complies_with_Universal_Serial_Bus_Specification__Revision_2_0 { + get { + return ResourceManager.GetString("Device_complies_with_Universal_Serial_Bus_Specification__Revision_2_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with unknown standard code 0x{0:X4}. + /// + internal static string Device_complies_with_unknown_standard_code_0 { + get { + return ResourceManager.GetString("Device_complies_with_unknown_standard_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with USB Mass Storage Class Bulk-Only Transport, Revision 1.0. + /// + internal static string Device_complies_with_USB_Mass_Storage_Class_Bulk_Only_Transport__Revision_1_0 { + get { + return ResourceManager.GetString("Device_complies_with_USB_Mass_Storage_Class_Bulk_Only_Transport__Revision_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ZBC BSR INCITS 536 revision 02. + /// + internal static string Device_complies_with_ZBC_BSR_INCITS_536_revision_02 { + get { + return ResourceManager.GetString("Device_complies_with_ZBC_BSR_INCITS_536_revision_02", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device complies with ZBC (no version claimed). + /// + internal static string Device_complies_with_ZBC_no_version_claimed { + get { + return ResourceManager.GetString("Device_complies_with_ZBC_no_version_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DEVICE CONFIGURATION IDENTIFY DMA and DEVICE CONFIGURATION SET DMA are supported. + /// + internal static string DEVICE_CONFIGURATION_IDENTIFY_DMA_and_DEVICE_CONFIGURATION_SET_DMA_are_supported { + get { + return ResourceManager.GetString("DEVICE_CONFIGURATION_IDENTIFY_DMA_and_DEVICE_CONFIGURATION_SET_DMA_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device Configuration Overlay feature set is supported. + /// + internal static string Device_Configuration_Overlay_feature_set_is_supported { + get { + return ResourceManager.GetString("Device_Configuration_Overlay_feature_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device Configuration Overlay feature set is supported and enabled. + /// + internal static string Device_Configuration_Overlay_feature_set_is_supported_and_enabled { + get { + return ResourceManager.GetString("Device_Configuration_Overlay_feature_set_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device contains an Access Control Coordinator. + /// + internal static string Device_contains_an_Access_Control_Coordinator { + get { + return ResourceManager.GetString("Device_contains_an_Access_Control_Coordinator", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device contains an embedded enclosure services component. + /// + internal static string Device_contains_an_embedded_enclosure_services_component { + get { + return ResourceManager.GetString("Device_contains_an_embedded_enclosure_services_component", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device contains an embedded storage array controller. + /// + internal static string Device_contains_an_embedded_storage_array_controller { + get { + return ResourceManager.GetString("Device_contains_an_embedded_storage_array_controller", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device contains or is attached to a medium changer. + /// + internal static string Device_contains_or_is_attached_to_a_medium_changer { + get { + return ResourceManager.GetString("Device_contains_or_is_attached_to_a_medium_changer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device contents are original. + /// + internal static string Device_contents_are_original { + get { + return ResourceManager.GetString("Device_contents_are_original", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device currently addresses 4096 byte sectors. + /// + internal static string Device_currently_addresses_4096_byte_sectors { + get { + return ResourceManager.GetString("Device_currently_addresses_4096_byte_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device currently addresses 512 byte sectors. + /// + internal static string Device_currently_addresses_512_byte_sectors { + get { + return ResourceManager.GetString("Device_currently_addresses_512_byte_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device currently addresses unknown sector size indicated by code {0}. + /// + internal static string Device_currently_addresses_unknown_sector_size_indicated_by_code_0 { + get { + return ResourceManager.GetString("Device_currently_addresses_unknown_sector_size_indicated_by_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device currently uses BCH(542, 512) ECC. + /// + internal static string Device_currently_uses_BCH_542_512_ECC { + get { + return ResourceManager.GetString("Device_currently_uses_BCH_542_512_ECC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device currently uses no ECC. + /// + internal static string Device_currently_uses_no_ECC { + get { + return ResourceManager.GetString("Device_currently_uses_no_ECC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device currently uses unknown ECC code {0}. + /// + internal static string Device_currently_uses_unknown_ECC_code_0 { + get { + return ResourceManager.GetString("Device_currently_uses_unknown_ECC_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not claim to comply with any SCSI ANSI standard. + /// + internal static string Device_does_not_claim_to_comply_with_any_SCSI_ANSI_standard { + get { + return ResourceManager.GetString("Device_does_not_claim_to_comply_with_any_SCSI_ANSI_standard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not claim to comply with any SCSI ECMA standard. + /// + internal static string Device_does_not_claim_to_comply_with_any_SCSI_ECMA_standard { + get { + return ResourceManager.GetString("Device_does_not_claim_to_comply_with_any_SCSI_ECMA_standard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not claim to comply with any SCSI ISO/IEC standard. + /// + internal static string Device_does_not_claim_to_comply_with_any_SCSI_ISO_IEC_standard { + get { + return ResourceManager.GetString("Device_does_not_claim_to_comply_with_any_SCSI_ISO_IEC_standard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not report an optimal read size. + /// + internal static string Device_does_not_report_an_optimal_read_size { + get { + return ResourceManager.GetString("Device_does_not_report_an_optimal_read_size", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not report an optimal trim size. + /// + internal static string Device_does_not_report_an_optimal_trim_size { + get { + return ResourceManager.GetString("Device_does_not_report_an_optimal_trim_size", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not report an optimal write size. + /// + internal static string Device_does_not_report_an_optimal_write_size { + get { + return ResourceManager.GetString("Device_does_not_report_an_optimal_write_size", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not require SET FEATURES to spin up and IDENTIFY DEVICE response is complete.. + /// + internal static string Device_does_not_require_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_complete { + get { + return ResourceManager.GetString("Device_does_not_require_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_c" + + "omplete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not require SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete.. + /// + internal static string Device_does_not_require_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_incomplete { + get { + return ResourceManager.GetString("Device_does_not_require_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_i" + + "ncomplete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not rotate.. + /// + internal static string Device_does_not_rotate { + get { + return ResourceManager.GetString("Device_does_not_rotate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not support asymmetrical access. + /// + internal static string Device_does_not_support_asymmetrical_access { + get { + return ResourceManager.GetString("Device_does_not_support_asymmetrical_access", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not support CPRM. + /// + internal static string Device_does_not_support_CPRM { + get { + return ResourceManager.GetString("Device_does_not_support_CPRM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device does not use CPRM. + /// + internal static string Device_does_not_use_CPRM { + get { + return ResourceManager.GetString("Device_does_not_use_CPRM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device emulates unknown sector size indicated by code {0}. + /// + internal static string Device_emulates_unknown_sector_size_indicated_by_code_0 { + get { + return ResourceManager.GetString("Device_emulates_unknown_sector_size_indicated_by_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device encrypts all user data. + /// + internal static string Device_encrypts_all_user_data { + get { + return ResourceManager.GetString("Device_encrypts_all_user_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device erase groups are {0} KiB. + /// + internal static string Device_erase_groups_are_0_KiB { + get { + return ResourceManager.GetString("Device_erase_groups_are_0_KiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device exceeded its maximum estimated life time. + /// + internal static string Device_exceeded_its_maximum_estimated_life_time { + get { + return ResourceManager.GetString("Device_exceeded_its_maximum_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows CFast specification. + /// + internal static string Device_follows_CFast_specification { + get { + return ResourceManager.GetString("Device_follows_CFast_specification", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows compatibility MMC command set.. + /// + internal static string Device_follows_compatibility_MMC_command_set { + get { + return ResourceManager.GetString("Device_follows_compatibility_MMC_command_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows IEEE-1667. + /// + internal static string Device_follows_IEEE_1667 { + get { + return ResourceManager.GetString("Device_follows_IEEE_1667", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows SecureDigital Physical Layer Specification version 1.0x. + /// + internal static string Device_follows_SecureDigital_Physical_Layer_Specification_version_1_0x { + get { + return ResourceManager.GetString("Device_follows_SecureDigital_Physical_Layer_Specification_version_1_0x", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows SecureDigital Physical Layer Specification version 1.10. + /// + internal static string Device_follows_SecureDigital_Physical_Layer_Specification_version_1_10 { + get { + return ResourceManager.GetString("Device_follows_SecureDigital_Physical_Layer_Specification_version_1_10", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows SecureDigital Physical Layer Specification version 2.00. + /// + internal static string Device_follows_SecureDigital_Physical_Layer_Specification_version_2_00 { + get { + return ResourceManager.GetString("Device_follows_SecureDigital_Physical_Layer_Specification_version_2_00", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows SecureDigital Physical Layer Specification version 3.0x. + /// + internal static string Device_follows_SecureDigital_Physical_Layer_Specification_version_3_0x { + get { + return ResourceManager.GetString("Device_follows_SecureDigital_Physical_Layer_Specification_version_3_0x", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows SecureDigital Physical Layer Specification version 4.xx. + /// + internal static string Device_follows_SecureDigital_Physical_Layer_Specification_version_4_xx { + get { + return ResourceManager.GetString("Device_follows_SecureDigital_Physical_Layer_Specification_version_4_xx", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows SecureDigital Physical Layer Specification version 5.xx. + /// + internal static string Device_follows_SecureDigital_Physical_Layer_Specification_version_5_xx { + get { + return ResourceManager.GetString("Device_follows_SecureDigital_Physical_Layer_Specification_version_5_xx", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows SecureDigital Physical Layer Specification version 6.xx. + /// + internal static string Device_follows_SecureDigital_Physical_Layer_Specification_version_6_xx { + get { + return ResourceManager.GetString("Device_follows_SecureDigital_Physical_Layer_Specification_version_6_xx", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows SecureDigital Physical Layer Specification version 7.xx. + /// + internal static string Device_follows_SecureDigital_Physical_Layer_Specification_version_7_xx { + get { + return ResourceManager.GetString("Device_follows_SecureDigital_Physical_Layer_Specification_version_7_xx", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows SecureDigital Physical Layer Specification version 8.xx. + /// + internal static string Device_follows_SecureDigital_Physical_Layer_Specification_version_8_xx { + get { + return ResourceManager.GetString("Device_follows_SecureDigital_Physical_Layer_Specification_version_8_xx", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows SecureDigital Physical Layer Specification with unknown version {0}.{1}.{2}.{3}. + /// + internal static string Device_follows_SecureDigital_Physical_Layer_Specification_with_unknown_version_0_1_2_3 { + get { + return ResourceManager.GetString("Device_follows_SecureDigital_Physical_Layer_Specification_with_unknown_version_0_" + + "1_2_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows standard MMC command set v4.0.. + /// + internal static string Device_follows_standard_MMC_command_set_v4_0 { + get { + return ResourceManager.GetString("Device_follows_standard_MMC_command_set_v4_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows standard MMC command set with unknown version code {0}.. + /// + internal static string Device_follows_standard_MMC_command_set_with_unknown_version_code_0 { + get { + return ResourceManager.GetString("Device_follows_standard_MMC_command_set_with_unknown_version_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device follows unknown MMC command set code {0} with revision code {1}.. + /// + internal static string Device_follows_unknown_MMC_command_set_code_0_with_revision_code_1 { + get { + return ResourceManager.GetString("Device_follows_unknown_MMC_command_set_code_0_with_revision_code_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has {0} blocks. + /// + internal static string Device_has_0_blocks { + get { + return ResourceManager.GetString("Device_has_0_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has {0} bytes. + /// + internal static string Device_has_0_bytes { + get { + return ResourceManager.GetString("Device_has_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has {0} GiB. + /// + internal static string Device_has_0_GiB { + get { + return ResourceManager.GetString("Device_has_0_GiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has {0} KiB. + /// + internal static string Device_has_0_KiB { + get { + return ResourceManager.GetString("Device_has_0_KiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has {0} KiB of cache. + /// + internal static string Device_has_0_KiB_of_cache { + get { + return ResourceManager.GetString("Device_has_0_KiB_of_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has {0} MiB. + /// + internal static string Device_has_0_MiB { + get { + return ResourceManager.GetString("Device_has_0_MiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has {0} sectors. + /// + internal static string Device_has_0_sectors { + get { + return ResourceManager.GetString("Device_has_0_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has {0} TiB. + /// + internal static string Device_has_0_TiB { + get { + return ResourceManager.GetString("Device_has_0_TiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has a {0} KiB boot partition. + /// + internal static string Device_has_a_0_KiB_boot_partition { + get { + return ResourceManager.GetString("Device_has_a_0_KiB_boot_partition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has a {0} KiB replay protected memory block. + /// + internal static string Device_has_a_0_KiB_replay_protected_memory_block { + get { + return ResourceManager.GetString("Device_has_a_0_KiB_replay_protected_memory_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has a non-volatile cache. + /// + internal static string Device_has_a_non_volatile_cache { + get { + return ResourceManager.GetString("Device_has_a_non_volatile_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has a page size of {0} KiB. + /// + internal static string Device_has_a_page_size_of_0_KiB { + get { + return ResourceManager.GetString("Device_has_a_page_size_of_0_KiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has a volatile cache. + /// + internal static string Device_has_a_volatile_cache { + get { + return ResourceManager.GetString("Device_has_a_volatile_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has a World Wide Name. + /// + internal static string Device_has_a_World_Wide_Name { + get { + return ResourceManager.GetString("Device_has_a_World_Wide_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has critical operations outstanding. + /// + internal static string Device_has_critical_operations_outstanding { + get { + return ResourceManager.GetString("Device_has_critical_operations_outstanding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has disabled protection information checks. + /// + internal static string Device_has_disabled_protection_information_checks { + get { + return ResourceManager.GetString("Device_has_disabled_protection_information_checks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has enabled command queuing. + /// + internal static string Device_has_enabled_command_queuing { + get { + return ResourceManager.GetString("Device_has_enabled_command_queuing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has no cache. + /// + internal static string Device_has_no_cache { + get { + return ResourceManager.GetString("Device_has_no_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has no pending background operations. + /// + internal static string Device_has_no_pending_background_operations { + get { + return ResourceManager.GetString("Device_has_no_pending_background_operations", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has non critical operations outstanding. + /// + internal static string Device_has_non_critical_operations_outstanding { + get { + return ResourceManager.GetString("Device_has_non_critical_operations_outstanding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has performance impacted operations outstanding. + /// + internal static string Device_has_performance_impacted_operations_outstanding { + get { + return ResourceManager.GetString("Device_has_performance_impacted_operations_outstanding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has secure write protection enabled. + /// + internal static string Device_has_secure_write_protection_enabled { + get { + return ResourceManager.GetString("Device_has_secure_write_protection_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device has unknown timing mode {0}.. + /// + internal static string Device_has_unknown_timing_mode_0 { + get { + return ResourceManager.GetString("Device_has_unknown_timing_mode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device implements alternate reset handling. + /// + internal static string Device_implements_alternate_reset_handling { + get { + return ResourceManager.GetString("Device_implements_alternate_reset_handling", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device implements configurable driver stage. + /// + internal static string Device_implements_configurable_driver_stage { + get { + return ResourceManager.GetString("Device_implements_configurable_driver_stage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device implements HPI using CMD12. + /// + internal static string Device_implements_HPI_using_CMD12 { + get { + return ResourceManager.GetString("Device_implements_HPI_using_CMD12", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device implements HPI using CMD13. + /// + internal static string Device_implements_HPI_using_CMD13 { + get { + return ResourceManager.GetString("Device_implements_HPI_using_CMD13", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device implements RESET as a soft reset. + /// + internal static string Device_implements_RESET_as_a_soft_reset { + get { + return ResourceManager.GetString("Device_implements_RESET_as_a_soft_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device indicates a specific minimum standby timer value. + /// + internal static string Device_indicates_a_specific_minimum_standby_timer_value { + get { + return ResourceManager.GetString("Device_indicates_a_specific_minimum_standby_timer_value", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device informs it should be replace immediately. + /// + internal static string Device_informs_it_should_be_replace_immediately { + get { + return ResourceManager.GetString("Device_informs_it_should_be_replace_immediately", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device informs it should be replaced soon. + /// + internal static string Device_informs_it_should_be_replaced_soon { + get { + return ResourceManager.GetString("Device_informs_it_should_be_replaced_soon", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device informs it's in good health. + /// + internal static string Device_informs_its_in_good_health { + get { + return ResourceManager.GetString("Device_informs_its_in_good_health", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device-initiated power management is supported. + /// + internal static string Device_initiated_power_management_is_supported { + get { + return ResourceManager.GetString("Device_initiated_power_management_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device-initiated power management is supported and enabled. + /// + internal static string Device_initiated_power_management_is_supported_and_enabled { + get { + return ResourceManager.GetString("Device_initiated_power_management_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is a dual device supporting CD and Non-CD Optical. + /// + internal static string Device_is_a_dual_device_supporting_CD_and_Non_CD_Optical { + get { + return ResourceManager.GetString("Device_is_a_dual_device_supporting_CD_and_Non_CD_Optical", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is byte addressed. + /// + internal static string Device_is_byte_addressed { + get { + return ResourceManager.GetString("Device_is_byte_addressed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is capable of recognizing both medium partitions and format. + /// + internal static string Device_is_capable_of_recognizing_both_medium_partitions_and_format { + get { + return ResourceManager.GetString("Device_is_capable_of_recognizing_both_medium_partitions_and_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is capable of recognizing medium format. + /// + internal static string Device_is_capable_of_recognizing_medium_format { + get { + return ResourceManager.GetString("Device_is_capable_of_recognizing_medium_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is capable of recognizing medium partitions. + /// + internal static string Device_is_capable_of_recognizing_medium_partitions { + get { + return ResourceManager.GetString("Device_is_capable_of_recognizing_medium_partitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is connected and supported.. + /// + internal static string Device_is_connected_and_supported { + get { + return ResourceManager.GetString("Device_is_connected_and_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is connected but unsupported.. + /// + internal static string Device_is_connected_but_unsupported { + get { + return ResourceManager.GetString("Device_is_connected_but_unsupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is emulating 512 byte sectors. + /// + internal static string Device_is_emulating_512_byte_sectors { + get { + return ResourceManager.GetString("Device_is_emulating_512_byte_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is fixed. + /// + internal static string Device_is_fixed { + get { + return ResourceManager.GetString("Device_is_fixed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is formatted like a floppy disk using Microsoft FAT. + /// + internal static string Device_is_formatted_like_a_floppy_disk_using_Microsoft_FAT { + get { + return ResourceManager.GetString("Device_is_formatted_like_a_floppy_disk_using_Microsoft_FAT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is formatted like a hard disk. + /// + internal static string Device_is_formatted_like_a_hard_disk { + get { + return ResourceManager.GetString("Device_is_formatted_like_a_hard_disk", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is hard sectored. + /// + internal static string Device_is_hard_sectored { + get { + return ResourceManager.GetString("Device_is_hard_sectored", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is in High Speed mode.. + /// + internal static string Device_is_in_High_Speed_mode { + get { + return ResourceManager.GetString("Device_is_in_High_Speed_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is in highest relative power consumption level. + /// + internal static string Device_is_in_highest_relative_power_consumption_level { + get { + return ResourceManager.GetString("Device_is_in_highest_relative_power_consumption_level", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is in HS-200 mode.. + /// + internal static string Device_is_in_HS200_mode { + get { + return ResourceManager.GetString("Device_is_in_HS200_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is in HS-400 mode.. + /// + internal static string Device_is_in_HS400_mode { + get { + return ResourceManager.GetString("Device_is_in_HS400_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is in intermediate relative power consumption level. + /// + internal static string Device_is_in_intermediate_relative_power_consumption_level { + get { + return ResourceManager.GetString("Device_is_in_intermediate_relative_power_consumption_level", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is in low power mode. + /// + internal static string Device_is_in_low_power_mode { + get { + return ResourceManager.GetString("Device_is_in_low_power_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is in lowest relative power consumption level. + /// + internal static string Device_is_in_lowest_relative_power_consumption_level { + get { + return ResourceManager.GetString("Device_is_in_lowest_relative_power_consumption_level", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is not boot enabled. + /// + internal static string Device_is_not_boot_enabled { + get { + return ResourceManager.GetString("Device_is_not_boot_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is not capable of recognizing neither medium partitions nor format. + /// + internal static string Device_is_not_capable_of_recognizing_neither_medium_partitions_nor_format { + get { + return ResourceManager.GetString("Device_is_not_capable_of_recognizing_neither_medium_partitions_nor_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is not MFM encoded. + /// + internal static string Device_is_not_MFM_encoded { + get { + return ResourceManager.GetString("Device_is_not_MFM_encoded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is permanently write protected. + /// + internal static string Device_is_permanently_write_protected { + get { + return ResourceManager.GetString("Device_is_permanently_write_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is powering up. + /// + internal static string Device_is_powering_up { + get { + return ResourceManager.GetString("Device_is_powering_up", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is removable. + /// + internal static string Device_is_removable { + get { + return ResourceManager.GetString("Device_is_removable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is SDHC, SDXC or higher. + /// + internal static string Device_is_SDHC_SDXC_or_higher { + get { + return ResourceManager.GetString("Device_is_SDHC_SDXC_or_higher", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is sector addressed. + /// + internal static string Device_is_sector_addressed { + get { + return ResourceManager.GetString("Device_is_sector_addressed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is soft sectored. + /// + internal static string Device_is_soft_sectored { + get { + return ResourceManager.GetString("Device_is_soft_sectored", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is supported but not connected.. + /// + internal static string Device_is_supported_but_not_connected { + get { + return ResourceManager.GetString("Device_is_supported_but_not_connected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is temporarily write protected. + /// + internal static string Device_is_temporarily_write_protected { + get { + return ResourceManager.GetString("Device_is_temporarily_write_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is UHS-II or higher. + /// + internal static string Device_is_UHS_II_or_higher { + get { + return ResourceManager.GetString("Device_is_UHS_II_or_higher", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is using 1-bit data bus. + /// + internal static string Device_is_using_1bit_data_bus { + get { + return ResourceManager.GetString("Device_is_using_1bit_data_bus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is using 4-bit data bus. + /// + internal static string Device_is_using_4bit_data_bus { + get { + return ResourceManager.GetString("Device_is_using_4bit_data_bus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is using 4-bit DDR data bus. + /// + internal static string Device_is_using_4bit_DDR_data_bus { + get { + return ResourceManager.GetString("Device_is_using_4bit_DDR_data_bus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is using 8-bit data bus. + /// + internal static string Device_is_using_8bit_data_bus { + get { + return ResourceManager.GetString("Device_is_using_8bit_data_bus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is using 8-bit DDR data bus. + /// + internal static string Device_is_using_8bit_DDR_data_bus { + get { + return ResourceManager.GetString("Device_is_using_8bit_DDR_data_bus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is using natively sized sectors. + /// + internal static string Device_is_using_natively_sized_sectors { + get { + return ResourceManager.GetString("Device_is_using_natively_sized_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is using unknown data bus code {0}. + /// + internal static string Device_is_using_unknown_data_bus_code_0 { + get { + return ResourceManager.GetString("Device_is_using_unknown_data_bus_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is zoned. + /// + internal static string Device_is_zoned { + get { + return ResourceManager.GetString("Device_is_zoned", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device manufactured month {0} of {1}. + /// + internal static string Device_manufactured_month_0_of_1 { + get { + return ResourceManager.GetString("Device_manufactured_month_0_of_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device may be bigger than 2GiB and have its real size defined in the extended CSD. + /// + internal static string Device_may_be_bigger_than_2GiB_and_have_its_real_size_defined_in_the_extended_CSD { + get { + return ResourceManager.GetString("Device_may_be_bigger_than_2GiB_and_have_its_real_size_defined_in_the_extended_CSD" + + "", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device may erase any or all partitions on MODE SELECT for partitioning. + /// + internal static string Device_may_erase_any_or_all_partitions_on_MODE_SELECT_for_partitioning { + get { + return ResourceManager.GetString("Device_may_erase_any_or_all_partitions_on_MODE_SELECT_for_partitioning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device must erase a minimum of {0} blocks at a time. + /// + internal static string Device_must_erase_a_minimum_of_0_blocks_at_a_time { + get { + return ResourceManager.GetString("Device_must_erase_a_minimum_of_0_blocks_at_a_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device name: {0}. + /// + internal static string Device_name_0 { + get { + return ResourceManager.GetString("Device_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device natively uses 4096 byte sectors. + /// + internal static string Device_natively_uses_4096_byte_sectors { + get { + return ResourceManager.GetString("Device_natively_uses_4096_byte_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device natively uses 512 byte sectors. + /// + internal static string Device_natively_uses_512_byte_sectors { + get { + return ResourceManager.GetString("Device_natively_uses_512_byte_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device natively uses unknown sector size indicated by code {0}. + /// + internal static string Device_natively_uses_unknown_sector_size_indicated_by_code_0 { + get { + return ResourceManager.GetString("Device_natively_uses_unknown_sector_size_indicated_by_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device needs cleaning cartridge. + /// + internal static string Device_needs_cleaning_cartridge { + get { + return ResourceManager.GetString("Device_needs_cleaning_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device nominal size field value {0} is unknown. + /// + internal static string Device_nominal_size_field_value_0_is_unknown { + get { + return ResourceManager.GetString("Device_nominal_size_field_value_0_is_unknown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device nominal size is 1.8". + /// + internal static string Device_nominal_size_is_1_8 { + get { + return ResourceManager.GetString("Device_nominal_size_is_1_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device nominal size is 2.5". + /// + internal static string Device_nominal_size_is_2_5 { + get { + return ResourceManager.GetString("Device_nominal_size_is_2_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device nominal size is 3.5". + /// + internal static string Device_nominal_size_is_3_5 { + get { + return ResourceManager.GetString("Device_nominal_size_is_3_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device nominal size is 5.25". + /// + internal static string Device_nominal_size_is_5_25 { + get { + return ResourceManager.GetString("Device_nominal_size_is_5_25", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device nominal size is smaller than 1.8". + /// + internal static string Device_nominal_size_is_smaller_than_1_8 { + get { + return ResourceManager.GetString("Device_nominal_size_is_smaller_than_1_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device only supports explicit asymmetrical access. + /// + internal static string Device_only_supports_explicit_asymmetrical_access { + get { + return ResourceManager.GetString("Device_only_supports_explicit_asymmetrical_access", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device only supports implicit asymmetrical access. + /// + internal static string Device_only_supports_implicit_asymmetrical_access { + get { + return ResourceManager.GetString("Device_only_supports_implicit_asymmetrical_access", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device power consumption is dictated by identifier {0} of Power Consumption VPD. + /// + internal static string Device_power_consumption_is_dictated_by_identifier_0_of_Power_Consumption_VPD { + get { + return ResourceManager.GetString("Device_power_consumption_is_dictated_by_identifier_0_of_Power_Consumption_VPD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device prints directly. + /// + internal static string Device_prints_directly { + get { + return ResourceManager.GetString("Device_prints_directly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device recognizes one single partition spanning whole medium. + /// + internal static string Device_recognizes_one_single_partition_spanning_whole_medium { + get { + return ResourceManager.GetString("Device_recognizes_one_single_partition_spanning_whole_medium", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device release level: {0}. + /// + internal static string Device_release_level_0 { + get { + return ResourceManager.GetString("Device_release_level_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is complete.. + /// + internal static string Device_requires_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_complete { + get { + return ResourceManager.GetString("Device_requires_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_complete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete.. + /// + internal static string Device_requires_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_incomplete { + get { + return ResourceManager.GetString("Device_requires_SET_FEATURES_to_spin_up_and_IDENTIFY_DEVICE_response_is_incomplet" + + "e", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DEVICE RESET is supported and enabled. + /// + internal static string DEVICE_RESET_is_supported_and_enabled { + get { + return ResourceManager.GetString("DEVICE_RESET_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device responded to ATA command {0:X2}h. + /// + internal static string Device_responded_to_ATA_command_0 { + get { + return ResourceManager.GetString("Device_responded_to_ATA_command_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device responded to ATA IDENTIFY DEVICE command.. + /// + internal static string Device_responded_to_ATA_IDENTIFY_DEVICE_command { + get { + return ResourceManager.GetString("Device_responded_to_ATA_IDENTIFY_DEVICE_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device responded to ATA IDENTIFY PACKET DEVICE command.. + /// + internal static string Device_responded_to_ATA_IDENTIFY_PACKET_DEVICE_command { + get { + return ResourceManager.GetString("Device_responded_to_ATA_IDENTIFY_PACKET_DEVICE_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device rotates at {0} rpm.. + /// + internal static string Device_rotates_at_0_rpm { + get { + return ResourceManager.GetString("Device_rotates_at_0_rpm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device's clock frequency: {0}{1}. + /// + internal static string Device_s_clock_frequency_0_1 { + get { + return ResourceManager.GetString("Device_s_clock_frequency_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device's write cache is non-volatile. + /// + internal static string Device_s_write_cache_is_non_volatile { + get { + return ResourceManager.GetString("Device_s_write_cache_is_non_volatile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device sends boot acknowledge. + /// + internal static string Device_sends_boot_acknowledge { + get { + return ResourceManager.GetString("Device_sends_boot_acknowledge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device shall assert INTRQ when DRQ is set to one. + /// + internal static string Device_shall_assert_INTRQ_when_DRQ_is_set_to_one { + get { + return ResourceManager.GetString("Device_shall_assert_INTRQ_when_DRQ_is_set_to_one", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device shall erase all partitions differing on size on MODE SELECT for partitioning. + /// + internal static string Device_shall_erase_all_partitions_differing_on_size_on_MODE_SELECT_for_partitioning { + get { + return ResourceManager.GetString("Device_shall_erase_all_partitions_differing_on_size_on_MODE_SELECT_for_partitioni" + + "ng", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device shall erase all partitions on MODE SELECT for partitioning. + /// + internal static string Device_shall_erase_all_partitions_on_MODE_SELECT_for_partitioning { + get { + return ResourceManager.GetString("Device_shall_erase_all_partitions_on_MODE_SELECT_for_partitioning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device shall not erase any partition on MODE SELECT for partitioning. + /// + internal static string Device_shall_not_erase_any_partition_on_MODE_SELECT_for_partitioning { + get { + return ResourceManager.GetString("Device_shall_not_erase_any_partition_on_MODE_SELECT_for_partitioning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device shall return descriptor format sense data when returning sense data in the same transactions as a CHECK CONDITION. + /// + internal static string Device_shall_return_descriptor_format_sense_data_when_returning_sense_data_in_the_same_transactions_as_a_CHECK_CONDITION { + get { + return ResourceManager.GetString("Device_shall_return_descriptor_format_sense_data_when_returning_sense_data_in_the" + + "_same_transactions_as_a_CHECK_CONDITION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device shall set DRQ within 3 ms of receiving PACKET. + /// + internal static string Device_shall_set_DRQ_within_3_ms_of_receiving_PACKET { + get { + return ResourceManager.GetString("Device_shall_set_DRQ_within_3_ms_of_receiving_PACKET", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device shall set DRQ within 50 µs of receiving PACKET. + /// + internal static string Device_shall_set_DRQ_within_50_µs_of_receiving_PACKET { + get { + return ResourceManager.GetString("Device_shall_set_DRQ_within_50_µs_of_receiving_PACKET", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device should use number of cache segments or cache segment size for caching. + /// + internal static string Device_should_use_number_of_cache_segments_or_cache_segment_size_for_caching { + get { + return ResourceManager.GetString("Device_should_use_number_of_cache_segments_or_cache_segment_size_for_caching", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device size in 28-bit LBA mode: {0} bytes, {1} Gb, {2} GiB. + /// + internal static string Device_size_in_28_bit_LBA_mode_0_bytes_1_Gb_2_GiB { + get { + return ResourceManager.GetString("Device_size_in_28_bit_LBA_mode_0_bytes_1_Gb_2_GiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device size in 28-bit LBA mode: {0} bytes, {1} Mb, {2} MiB. + /// + internal static string Device_size_in_28_bit_LBA_mode_0_bytes_1_Mb_2_MiB { + get { + return ResourceManager.GetString("Device_size_in_28_bit_LBA_mode_0_bytes_1_Mb_2_MiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device size in 28-bit LBA mode: {0} bytes, {1} Tb, {2} TiB. + /// + internal static string Device_size_in_28_bit_LBA_mode_0_bytes_1_Tb_2_TiB { + get { + return ResourceManager.GetString("Device_size_in_28_bit_LBA_mode_0_bytes_1_Tb_2_TiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device size in 48-bit LBA mode: {0} bytes, {1} Gb, {2} GiB. + /// + internal static string Device_size_in_48_bit_LBA_mode_0_bytes_1_Gb_2_GiB { + get { + return ResourceManager.GetString("Device_size_in_48_bit_LBA_mode_0_bytes_1_Gb_2_GiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device size in 48-bit LBA mode: {0} bytes, {1} Mb, {2} MiB. + /// + internal static string Device_size_in_48_bit_LBA_mode_0_bytes_1_Mb_2_MiB { + get { + return ResourceManager.GetString("Device_size_in_48_bit_LBA_mode_0_bytes_1_Mb_2_MiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device size in 48-bit LBA mode: {0} bytes, {1} Tb, {2} TiB. + /// + internal static string Device_size_in_48_bit_LBA_mode_0_bytes_1_Tb_2_TiB { + get { + return ResourceManager.GetString("Device_size_in_48_bit_LBA_mode_0_bytes_1_Tb_2_TiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device size in CHS mode: {0} bytes, {1} Mb, {2} MiB. + /// + internal static string Device_size_in_CHS_mode_0_bytes_1_Mb_2_MiB { + get { + return ResourceManager.GetString("Device_size_in_CHS_mode_0_bytes_1_Mb_2_MiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device smallest write protect group is made of {0} erase groups. + /// + internal static string Device_smallest_write_protect_group_is_made_of_0_erase_groups { + get { + return ResourceManager.GetString("Device_smallest_write_protect_group_is_made_of_0_erase_groups", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device support command classes {0}. + /// + internal static string Device_support_command_classes_0 { + get { + return ResourceManager.GetString("Device_support_command_classes_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports 1-bit data bus. + /// + internal static string Device_supports_1_bit_data_bus { + get { + return ResourceManager.GetString("Device_supports_1_bit_data_bus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports 16-bit wide data transfers. + /// + internal static string Device_supports_16_bit_wide_data_transfers { + get { + return ResourceManager.GetString("Device_supports_16_bit_wide_data_transfers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports 16-bit wide SCSI addresses. + /// + internal static string Device_supports_16_bit_wide_SCSI_addresses { + get { + return ResourceManager.GetString("Device_supports_16_bit_wide_SCSI_addresses", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports 26 Mhz mode. + /// + internal static string Device_supports_26_Mhz_mode { + get { + return ResourceManager.GetString("Device_supports_26_Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports 32-bit wide data transfers. + /// + internal static string Device_supports_32_bit_wide_data_transfers { + get { + return ResourceManager.GetString("Device_supports_32_bit_wide_data_transfers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports 32-bit wide SCSI addresses. + /// + internal static string Device_supports_32_bit_wide_SCSI_addresses { + get { + return ResourceManager.GetString("Device_supports_32_bit_wide_SCSI_addresses", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports 4-bit data bus. + /// + internal static string Device_supports_4_bit_data_bus { + get { + return ResourceManager.GetString("Device_supports_4_bit_data_bus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports 52 Mhz mode. + /// + internal static string Device_supports_52_Mhz_mode { + get { + return ResourceManager.GetString("Device_supports_52_Mhz_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports a maximum of {0} bytes for sense data. + /// + internal static string Device_supports_a_maximum_of_0_bytes_for_sense_data { + get { + return ResourceManager.GetString("Device_supports_a_maximum_of_0_bytes_for_sense_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports a maximum of {0} packed reads and {1} packed writes. + /// + internal static string Device_supports_a_maximum_of_0_packed_reads_and_1_packed_writes { + get { + return ResourceManager.GetString("Device_supports_a_maximum_of_0_packed_reads_and_1_packed_writes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports alternative boot method. + /// + internal static string Device_supports_alternative_boot_method { + get { + return ResourceManager.GetString("Device_supports_alternative_boot_method", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports Asynchronous Event Reporting Capability. + /// + internal static string Device_supports_Asynchronous_Event_Reporting_Capability { + get { + return ResourceManager.GetString("Device_supports_Asynchronous_Event_Reporting_Capability", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports automatic erase on retired defective blocks. + /// + internal static string Device_supports_automatic_erase_on_retired_defective_blocks { + get { + return ResourceManager.GetString("Device_supports_automatic_erase_on_retired_defective_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports background operations. + /// + internal static string Device_supports_background_operations { + get { + return ResourceManager.GetString("Device_supports_background_operations", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports basic queueing. + /// + internal static string Device_supports_basic_queueing { + get { + return ResourceManager.GetString("Device_supports_basic_queueing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports capability-based command security. + /// + internal static string Device_supports_capability_based_command_security { + get { + return ResourceManager.GetString("Device_supports_capability_based_command_security", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports command queuing with a depth of {0}. + /// + internal static string Device_supports_command_queuing_with_a_depth_of_0 { + get { + return ResourceManager.GetString("Device_supports_command_queuing_with_a_depth_of_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports content protection. + /// + internal static string Device_supports_content_protection { + get { + return ResourceManager.GetString("Device_supports_content_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports CONTINUE TASK and TARGET TRANSFER DISABLE commands. + /// + internal static string Device_supports_CONTINUE_TASK_and_TARGET_TRANSFER_DISABLE_commands { + get { + return ResourceManager.GetString("Device_supports_CONTINUE_TASK_and_TARGET_TRANSFER_DISABLE_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports Data Tag. + /// + internal static string Device_supports_Data_Tag { + get { + return ResourceManager.GetString("Device_supports_Data_Tag", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports DDR 52 Mhz mode 1.2V. + /// + internal static string Device_supports_DDR_52_Mhz_mode_1_2V { + get { + return ResourceManager.GetString("Device_supports_DDR_52_Mhz_mode_1_2V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports DDR 52 Mhz mode at 1.8V or 3V. + /// + internal static string Device_supports_DDR_52_Mhz_mode_at_1_8V_or_3V { + get { + return ResourceManager.GetString("Device_supports_DDR_52_Mhz_mode_at_1_8V_or_3V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports disabling correction with WRITE LONG. + /// + internal static string Device_supports_disabling_correction_with_WRITE_LONG { + get { + return ResourceManager.GetString("Device_supports_disabling_correction_with_WRITE_LONG", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports doubleword I/O. + /// + internal static string Device_supports_doubleword_IO { + get { + return ResourceManager.GetString("Device_supports_doubleword_IO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports dual data rate on boot. + /// + internal static string Device_supports_dual_data_rate_on_boot { + get { + return ResourceManager.GetString("Device_supports_dual_data_rate_on_boot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports enhanced strobe mode. + /// + internal static string Device_supports_enhanced_strobe_mode { + get { + return ResourceManager.GetString("Device_supports_enhanced_strobe_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports extended security. + /// + internal static string Device_supports_extended_security { + get { + return ResourceManager.GetString("Device_supports_extended_security", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports extension register multi-block commands. + /// + internal static string Device_supports_extension_register_multi_block_commands { + get { + return ResourceManager.GetString("Device_supports_extension_register_multi_block_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports extension register single-block commands. + /// + internal static string Device_supports_extension_register_single_block_commands { + get { + return ResourceManager.GetString("Device_supports_extension_register_single_block_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports FFU. + /// + internal static string Device_supports_FFU { + get { + return ResourceManager.GetString("Device_supports_FFU", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports grouping. + /// + internal static string Device_supports_grouping { + get { + return ResourceManager.GetString("Device_supports_grouping", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports hard reset activation for new microcode. + /// + internal static string Device_supports_hard_reset_activation_for_new_microcode { + get { + return ResourceManager.GetString("Device_supports_hard_reset_activation_for_new_microcode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports head of queue. + /// + internal static string Device_supports_head_of_queue { + get { + return ResourceManager.GetString("Device_supports_head_of_queue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports high speed timing on boot. + /// + internal static string Device_supports_high_speed_timing_on_boot { + get { + return ResourceManager.GetString("Device_supports_high_speed_timing_on_boot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports HS-200 mode (SDR 200Mhz) at 1.2V. + /// + internal static string Device_supports_HS_200_mode_SDR_200Mhz_at_1_2V { + get { + return ResourceManager.GetString("Device_supports_HS_200_mode_SDR_200Mhz_at_1_2V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports HS-200 mode (SDR 200Mhz) at 1.8V. + /// + internal static string Device_supports_HS_200_mode_SDR_200Mhz_at_1_8V { + get { + return ResourceManager.GetString("Device_supports_HS_200_mode_SDR_200Mhz_at_1_8V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports HS-400 mode (DDR 200Mhz) at 1.2V. + /// + internal static string Device_supports_HS_400_mode_DDR_200Mhz_at_1_2V { + get { + return ResourceManager.GetString("Device_supports_HS_400_mode_DDR_200Mhz_at_1_2V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports HS-400 mode (DDR 200Mhz) at 1.8V. + /// + internal static string Device_supports_HS_400_mode_DDR_200Mhz_at_1_8V { + get { + return ResourceManager.GetString("Device_supports_HS_400_mode_DDR_200Mhz_at_1_8V", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports implicit and explicit asymmetrical access. + /// + internal static string Device_supports_implicit_and_explicit_asymmetrical_access { + get { + return ResourceManager.GetString("Device_supports_implicit_and_explicit_asymmetrical_access", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports information unit transfers. + /// + internal static string Device_supports_information_unit_transfers { + get { + return ResourceManager.GetString("Device_supports_information_unit_transfers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports I/O driver strength type 4.. + /// + internal static string Device_supports_IO_driver_strength_type_four { + get { + return ResourceManager.GetString("Device_supports_IO_driver_strength_type_four", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports I/O driver strength type 1.. + /// + internal static string Device_supports_IO_driver_strength_type_one { + get { + return ResourceManager.GetString("Device_supports_IO_driver_strength_type_one", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports I/O driver strength type 3.. + /// + internal static string Device_supports_IO_driver_strength_type_three { + get { + return ResourceManager.GetString("Device_supports_IO_driver_strength_type_three", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports I/O driver strength type 2.. + /// + internal static string Device_supports_IO_driver_strength_type_two { + get { + return ResourceManager.GetString("Device_supports_IO_driver_strength_type_two", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports I/O driver strength type 0.. + /// + internal static string Device_supports_IO_driver_strength_type_zero { + get { + return ResourceManager.GetString("Device_supports_IO_driver_strength_type_zero", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports linked commands. + /// + internal static string Device_supports_linked_commands { + get { + return ResourceManager.GetString("Device_supports_linked_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports Long Physical Sector Alignment Error Reporting Control. + /// + internal static string Device_supports_Long_Physical_Sector_Alignment_Error_Reporting_Control { + get { + return ResourceManager.GetString("Device_supports_Long_Physical_Sector_Alignment_Error_Reporting_Control", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports LUN hierarchical addressing. + /// + internal static string Device_supports_LUN_hierarchical_addressing { + get { + return ResourceManager.GetString("Device_supports_LUN_hierarchical_addressing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports marking a block as uncorrectable with WRITE LONG. + /// + internal static string Device_supports_marking_a_block_as_uncorrectable_with_WRITE_LONG { + get { + return ResourceManager.GetString("Device_supports_marking_a_block_as_uncorrectable_with_WRITE_LONG", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports non-persistent extended partitions. + /// + internal static string Device_supports_non_persistent_extended_partitions { + get { + return ResourceManager.GetString("Device_supports_non_persistent_extended_partitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports only DT clocking. + /// + internal static string Device_supports_only_DT_clocking { + get { + return ResourceManager.GetString("Device_supports_only_DT_clocking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports only ST clocking. + /// + internal static string Device_supports_only_ST_clocking { + get { + return ResourceManager.GetString("Device_supports_only_ST_clocking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports partitioning features. + /// + internal static string Device_supports_partitioning_features { + get { + return ResourceManager.GetString("Device_supports_partitioning_features", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports power-on activation for new microcode. + /// + internal static string Device_supports_power_on_activation_for_new_microcode { + get { + return ResourceManager.GetString("Device_supports_power_on_activation_for_new_microcode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports priority. + /// + internal static string Device_supports_priority { + get { + return ResourceManager.GetString("Device_supports_priority", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports protection information. + /// + internal static string Device_supports_protection_information { + get { + return ResourceManager.GetString("Device_supports_protection_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports protection information intervals. + /// + internal static string Device_supports_protection_information_intervals { + get { + return ResourceManager.GetString("Device_supports_protection_information_intervals", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports Quick Arbitration and Selection. + /// + internal static string Device_supports_Quick_Arbitration_and_Selection { + get { + return ResourceManager.GetString("Device_supports_Quick_Arbitration_and_Selection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports referrals. + /// + internal static string Device_supports_referrals { + get { + return ResourceManager.GetString("Device_supports_referrals", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports relative addressing. + /// + internal static string Device_supports_relative_addressing { + get { + return ResourceManager.GetString("Device_supports_relative_addressing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports request and acknowledge handshakes. + /// + internal static string Device_supports_request_and_acknowledge_handshakes { + get { + return ResourceManager.GetString("Device_supports_request_and_acknowledge_handshakes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports secure purge operations. + /// + internal static string Device_supports_secure_purge_operations { + get { + return ResourceManager.GetString("Device_supports_secure_purge_operations", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports secure write protection. + /// + internal static string Device_supports_secure_write_protection { + get { + return ResourceManager.GetString("Device_supports_secure_write_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports set block count command. + /// + internal static string Device_supports_set_block_count_command { + get { + return ResourceManager.GetString("Device_supports_set_block_count_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports setting a maximum of {0} sectors. + /// + internal static string Device_supports_setting_a_maximum_of_0_sectors { + get { + return ResourceManager.GetString("Device_supports_setting_a_maximum_of_0_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports setting Normal ACA. + /// + internal static string Device_supports_setting_Normal_ACA { + get { + return ResourceManager.GetString("Device_supports_setting_Normal_ACA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports speed class control command. + /// + internal static string Device_supports_speed_class_control_command { + get { + return ResourceManager.GetString("Device_supports_speed_class_control_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports ST and DT clocking. + /// + internal static string Device_supports_ST_and_DT_clocking { + get { + return ResourceManager.GetString("Device_supports_ST_and_DT_clocking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports standard MMC command set. + /// + internal static string Device_supports_standard_MMC_command_set { + get { + return ResourceManager.GetString("Device_supports_standard_MMC_command_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports supports the secure and insecure trim operations. + /// + internal static string Device_supports_supports_the_secure_and_insecure_trim_operations { + get { + return ResourceManager.GetString("Device_supports_supports_the_secure_and_insecure_trim_operations", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports synchronous data transfer. + /// + internal static string Device_supports_synchronous_data_transfer { + get { + return ResourceManager.GetString("Device_supports_synchronous_data_transfer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports system code extended partitions. + /// + internal static string Device_supports_system_code_extended_partitions { + get { + return ResourceManager.GetString("Device_supports_system_code_extended_partitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports Tape Disaster Recovery. + /// + internal static string Device_supports_Tape_Disaster_Recovery { + get { + return ResourceManager.GetString("Device_supports_Tape_Disaster_Recovery", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports Tape Stream Mirroring. + /// + internal static string Device_supports_Tape_Stream_Mirroring { + get { + return ResourceManager.GetString("Device_supports_Tape_Stream_Mirroring", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports TCQ queue. + /// + internal static string Device_supports_TCQ_queue { + get { + return ResourceManager.GetString("Device_supports_TCQ_queue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports TERMINATE TASK command. + /// + internal static string Device_supports_TERMINATE_TASK_command { + get { + return ResourceManager.GetString("Device_supports_TERMINATE_TASK_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports the barrier command. + /// + internal static string Device_supports_the_barrier_command { + get { + return ResourceManager.GetString("Device_supports_the_barrier_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports the ORDERED task attribute. + /// + internal static string Device_supports_the_ORDERED_task_attribute { + get { + return ResourceManager.GetString("Device_supports_the_ORDERED_task_attribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports the sanitize operation. + /// + internal static string Device_supports_the_sanitize_operation { + get { + return ResourceManager.GetString("Device_supports_the_sanitize_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports the SIMPLE task attribute. + /// + internal static string Device_supports_the_SIMPLE_task_attribute { + get { + return ResourceManager.GetString("Device_supports_the_SIMPLE_task_attribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports third-party copy commands. + /// + internal static string Device_supports_third_party_copy_commands { + get { + return ResourceManager.GetString("Device_supports_third_party_copy_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports unit attention condition sense key specific data. + /// + internal static string Device_supports_unit_attention_condition_sense_key_specific_data { + get { + return ResourceManager.GetString("Device_supports_unit_attention_condition_sense_key_specific_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports unknown command sets 0x{0:X2}. + /// + internal static string Device_supports_unknown_command_sets_0 { + get { + return ResourceManager.GetString("Device_supports_unknown_command_sets_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports vendor specific activation for new microcode. + /// + internal static string Device_supports_vendor_specific_activation_for_new_microcode { + get { + return ResourceManager.GetString("Device_supports_vendor_specific_activation_for_new_microcode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports Vendor Specific Mode. + /// + internal static string Device_supports_Vendor_Specific_Mode { + get { + return ResourceManager.GetString("Device_supports_Vendor_Specific_Mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports WORM media. + /// + internal static string Device_supports_WORM_media { + get { + return ResourceManager.GetString("Device_supports_WORM_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device supports WORM version {0}. + /// + internal static string Device_supports_WORM_version_0 { + get { + return ResourceManager.GetString("Device_supports_WORM_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} by default to power off from a SWITCH command notification. + /// + internal static string Device_takes_a_maximum_of_0_by_default_to_power_off_from_a_SWITCH_command_notification { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_by_default_to_power_off_from_a_SWITCH_command_notific" + + "ation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} ms by default for a SWITCH command. + /// + internal static string Device_takes_a_maximum_of_0_ms_by_default_for_a_SWITCH_command { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_ms_by_default_for_a_SWITCH_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} ms for erasing a single erase group. + /// + internal static string Device_takes_a_maximum_of_0_ms_for_erasing_a_single_erase_group { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_ms_for_erasing_a_single_erase_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} ms for initialization after partition. + /// + internal static string Device_takes_a_maximum_of_0_ms_for_initialization_after_partition { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_ms_for_initialization_after_partition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} ms for securely erasing a single erase group. + /// + internal static string Device_takes_a_maximum_of_0_ms_for_securely_erasing_a_single_erase_group { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_ms_for_securely_erasing_a_single_erase_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} ms for securely trimming a single erase group. + /// + internal static string Device_takes_a_maximum_of_0_ms_for_securely_trimming_a_single_erase_group { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_ms_for_securely_trimming_a_single_erase_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} ms for trimming a single erase group. + /// + internal static string Device_takes_a_maximum_of_0_ms_for_trimming_a_single_erase_group { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_ms_for_trimming_a_single_erase_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} ms to move to sleep state. + /// + internal static string Device_takes_a_maximum_of_0_ms_to_move_to_sleep_state { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_ms_to_move_to_sleep_state", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} ms to switch production state awareness. + /// + internal static string Device_takes_a_maximum_of_0_ms_to_switch_production_state_awareness { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_ms_to_switch_production_state_awareness", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} ms to transition between sleep and standby states. + /// + internal static string Device_takes_a_maximum_of_0_ms_to_transition_between_sleep_and_standby_states { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_ms_to_transition_between_sleep_and_standby_states", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} ns to transition between sleep and standby states. + /// + internal static string Device_takes_a_maximum_of_0_ns_to_transition_between_sleep_and_standby_states { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_ns_to_transition_between_sleep_and_standby_states", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} s to move to sleep state. + /// + internal static string Device_takes_a_maximum_of_0_s_to_move_to_sleep_state { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_s_to_move_to_sleep_state", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} s to switch production state awareness. + /// + internal static string Device_takes_a_maximum_of_0_s_to_switch_production_state_awareness { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_s_to_switch_production_state_awareness", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} μs to move to sleep state. + /// + internal static string Device_takes_a_maximum_of_0_μs_to_move_to_sleep_state { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_μs_to_move_to_sleep_state", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} μs to switch production state awareness. + /// + internal static string Device_takes_a_maximum_of_0_μs_to_switch_production_state_awareness { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_μs_to_switch_production_state_awareness", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device takes a maximum of {0} μs to transition between sleep and standby states. + /// + internal static string Device_takes_a_maximum_of_0_μs_to_transition_between_sleep_and_standby_states { + get { + return ResourceManager.GetString("Device_takes_a_maximum_of_0_μs_to_transition_between_sleep_and_standby_states", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device transfer rate is > 5 Mb/s but <= 10 Mb/s. + /// + internal static string Device_transfer_rate_is_more_5_Mbs_less_10_Mbs { + get { + return ResourceManager.GetString("Device_transfer_rate_is_more_5_Mbs_less_10_Mbs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device transfer rate is <= 5 Mb/s. + /// + internal static string Device_transfer_rate_less_than_5_Mbs { + get { + return ResourceManager.GetString("Device_transfer_rate_less_than_5_Mbs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device transfer rate is > 10 Mb/s. + /// + internal static string Device_transfer_rate_more_than_10_Mbs { + get { + return ResourceManager.GetString("Device_transfer_rate_more_than_10_Mbs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device's transfer speed: {0}{1}. + /// + internal static string Device_transfer_speed_0_1 { + get { + return ResourceManager.GetString("Device_transfer_speed_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device used between 10% and 20% of its estimated life time. + /// + internal static string Device_used_between_10_and_20_of_its_estimated_life_time { + get { + return ResourceManager.GetString("Device_used_between_10_and_20_of_its_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device used between 20% and 30% of its estimated life time. + /// + internal static string Device_used_between_20_and_30_of_its_estimated_life_time { + get { + return ResourceManager.GetString("Device_used_between_20_and_30_of_its_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device used between 30% and 40% of its estimated life time. + /// + internal static string Device_used_between_30_and_40_of_its_estimated_life_time { + get { + return ResourceManager.GetString("Device_used_between_30_and_40_of_its_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device used between 40% and 50% of its estimated life time. + /// + internal static string Device_used_between_40_and_50_of_its_estimated_life_time { + get { + return ResourceManager.GetString("Device_used_between_40_and_50_of_its_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device used between 50% and 60% of its estimated life time. + /// + internal static string Device_used_between_50_and_60_of_its_estimated_life_time { + get { + return ResourceManager.GetString("Device_used_between_50_and_60_of_its_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device used between 60% and 70% of its estimated life time. + /// + internal static string Device_used_between_60_and_70_of_its_estimated_life_time { + get { + return ResourceManager.GetString("Device_used_between_60_and_70_of_its_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device used between 70% and 80% of its estimated life time. + /// + internal static string Device_used_between_70_and_80_of_its_estimated_life_time { + get { + return ResourceManager.GetString("Device_used_between_70_and_80_of_its_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device used between 80% and 90% of its estimated life time. + /// + internal static string Device_used_between_80_and_90_of_its_estimated_life_time { + get { + return ResourceManager.GetString("Device_used_between_80_and_90_of_its_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device used between 90% and 100% of its estimated life time. + /// + internal static string Device_used_between_90_and_100_of_its_estimated_life_time { + get { + return ResourceManager.GetString("Device_used_between_90_and_100_of_its_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device used between 0% and 10% of its estimated life time. + /// + internal static string Device_used_between_zero_and_10_of_its_estimated_life_time { + get { + return ResourceManager.GetString("Device_used_between_zero_and_10_of_its_estimated_life_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device user area is enable for boot. + /// + internal static string Device_user_area_is_enable_for_boot { + get { + return ResourceManager.GetString("Device_user_area_is_enable_for_boot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses {0} mA on Vcc when sleeping. + /// + internal static string Device_uses_0_mA_on_Vcc_when_sleeping { + get { + return ResourceManager.GetString("Device_uses_0_mA_on_Vcc_when_sleeping", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses {0} mA on Vccq when sleeping. + /// + internal static string Device_uses_0_mA_on_Vccq_when_sleeping { + get { + return ResourceManager.GetString("Device_uses_0_mA_on_Vccq_when_sleeping", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses {0} μA on Vcc when sleeping. + /// + internal static string Device_uses_0_μA_on_Vcc_when_sleeping { + get { + return ResourceManager.GetString("Device_uses_0_μA_on_Vcc_when_sleeping", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses {0} μA on Vccq when sleeping. + /// + internal static string Device_uses_0_μA_on_Vccq_when_sleeping { + get { + return ResourceManager.GetString("Device_uses_0_μA_on_Vccq_when_sleeping", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a FIFO policy for cache flushing. + /// + internal static string Device_uses_a_FIFO_policy_for_cache_flushing { + get { + return ResourceManager.GetString("Device_uses_a_FIFO_policy_for_cache_flushing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 0.5mA for reading at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_0_5mA_for_reading_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_0_5mA_for_reading_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 0.5mA for writing at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_0_5mA_for_writing_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_0_5mA_for_writing_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 100mA for reading at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_100mA_for_reading_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_100mA_for_reading_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 100mA for writing at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_100mA_for_writing_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_100mA_for_writing_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 10mA for reading at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_10mA_for_reading_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_10mA_for_reading_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 10mA for reading at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_10mA_for_reading_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_10mA_for_reading_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 10mA for writing at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_10mA_for_writing_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_10mA_for_writing_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 10mA for writing at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_10mA_for_writing_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_10mA_for_writing_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 1mA for reading at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_1mA_for_reading_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_1mA_for_reading_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 1mA for reading at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_1mA_for_reading_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_1mA_for_reading_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 1mA for writing at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_1mA_for_writing_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_1mA_for_writing_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 1mA for writing at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_1mA_for_writing_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_1mA_for_writing_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 200mA for reading at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_200mA_for_reading_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_200mA_for_reading_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 200mA for writing at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_200mA_for_writing_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_200mA_for_writing_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 25mA for reading at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_25mA_for_reading_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_25mA_for_reading_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 25mA for reading at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_25mA_for_reading_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_25mA_for_reading_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 25mA for writing at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_25mA_for_writing_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_25mA_for_writing_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 25mA for writing at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_25mA_for_writing_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_25mA_for_writing_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 35mA for reading at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_35mA_for_reading_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_35mA_for_reading_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 35mA for reading at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_35mA_for_reading_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_35mA_for_reading_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 35mA for writing at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_35mA_for_writing_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_35mA_for_writing_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 35mA for writing at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_35mA_for_writing_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_35mA_for_writing_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 45mA for reading at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_45mA_for_reading_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_45mA_for_reading_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 45mA for writing at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_45mA_for_writing_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_45mA_for_writing_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 5mA for reading at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_5mA_for_reading_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_5mA_for_reading_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 5mA for reading at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_5mA_for_reading_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_5mA_for_reading_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 5mA for writing at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_5mA_for_writing_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_5mA_for_writing_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 5mA for writing at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_5mA_for_writing_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_5mA_for_writing_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 60mA for reading at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_60mA_for_reading_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_60mA_for_reading_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 60mA for writing at minimum voltage. + /// + internal static string Device_uses_a_maximum_of_60mA_for_writing_at_minimum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_60mA_for_writing_at_minimum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 80mA for reading at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_80mA_for_reading_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_80mA_for_reading_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a maximum of 80mA for writing at maximum voltage. + /// + internal static string Device_uses_a_maximum_of_80mA_for_writing_at_maximum_voltage { + get { + return ResourceManager.GetString("Device_uses_a_maximum_of_80mA_for_writing_at_maximum_voltage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a print cache. + /// + internal static string Device_uses_a_print_cache { + get { + return ResourceManager.GetString("Device_uses_a_print_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a write cache. + /// + internal static string Device_uses_a_write_cache { + get { + return ResourceManager.GetString("Device_uses_a_write_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses a write cache but doesn't return until cache is flushed. + /// + internal static string Device_uses_a_write_cache_but_doesn_t_return_until_cache_is_flushed { + get { + return ResourceManager.GetString("Device_uses_a_write_cache_but_doesn_t_return_until_cache_is_flushed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses BCH(542, 512) ECC by default. + /// + internal static string Device_uses_BCH_542_512_ECC_by_default { + get { + return ResourceManager.GetString("Device_uses_BCH_542_512_ECC_by_default", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses CPRM according to specification version 1.01. + /// + internal static string Device_uses_CPRM_according_to_specification_version_1_01 { + get { + return ResourceManager.GetString("Device_uses_CPRM_according_to_specification_version_1_01", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses CPRM according to specification version 2.00. + /// + internal static string Device_uses_CPRM_according_to_specification_version_2_00 { + get { + return ResourceManager.GetString("Device_uses_CPRM_according_to_specification_version_2_00", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses CPRM according to specification version 3.xx. + /// + internal static string Device_uses_CPRM_according_to_specification_version_3_xx { + get { + return ResourceManager.GetString("Device_uses_CPRM_according_to_specification_version_3_xx", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses default speed. + /// + internal static string Device_uses_default_speed { + get { + return ResourceManager.GetString("Device_uses_default_speed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses no ECC by default. + /// + internal static string Device_uses_no_ECC_by_default { + get { + return ResourceManager.GetString("Device_uses_no_ECC_by_default", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses non-magnetic media. + /// + internal static string Device_uses_non_magnetic_media { + get { + return ResourceManager.GetString("Device_uses_non_magnetic_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses Parallel ATA.. + /// + internal static string Device_uses_Parallel_ATA { + get { + return ResourceManager.GetString("Device_uses_Parallel_ATA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses Serial ATA.. + /// + internal static string Device_uses_Serial_ATA { + get { + return ResourceManager.GetString("Device_uses_Serial_ATA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses speed {0}. + /// + internal static string Device_uses_speed_0 { + get { + return ResourceManager.GetString("Device_uses_speed_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses strobe during Data Out and CRC responses. + /// + internal static string Device_uses_strobe_during_Data_Out_and_CRC_responses { + get { + return ResourceManager.GetString("Device_uses_strobe_during_Data_Out_and_CRC_responses", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses strobe during Data Out, CRC and CMD responses. + /// + internal static string Device_uses_strobe_during_Data_Out_CRC_and_CMD_responses { + get { + return ResourceManager.GetString("Device_uses_strobe_during_Data_Out_CRC_and_CMD_responses", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses Universal File Format. + /// + internal static string Device_uses_Universal_File_Format { + get { + return ResourceManager.GetString("Device_uses_Universal_File_Format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses unknown CPRM specification with code {0}. + /// + internal static string Device_uses_unknown_CPRM_specification_with_code_0 { + get { + return ResourceManager.GetString("Device_uses_unknown_CPRM_specification_with_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses unknown ECC code {0} by default. + /// + internal static string Device_uses_unknown_ECC_code_0_by_default { + get { + return ResourceManager.GetString("Device_uses_unknown_ECC_code_0_by_default", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses unknown file format code {0}. + /// + internal static string Device_uses_unknown_file_format_code_0 { + get { + return ResourceManager.GetString("Device_uses_unknown_file_format_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses unknown file format code {0} and file format group 1. + /// + internal static string Device_uses_unknown_file_format_code_0_and_file_format_group_1 { + get { + return ResourceManager.GetString("Device_uses_unknown_file_format_code_0_and_file_format_group_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses unknown transport with code {0}. + /// + internal static string Device_uses_unknown_transport_with_code_0 { + get { + return ResourceManager.GetString("Device_uses_unknown_transport_with_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device vendor: {0}. + /// + internal static string Device_vendor_0 { + get { + return ResourceManager.GetString("Device_vendor_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device version: {0}. + /// + internal static string Device_version_0 { + get { + return ResourceManager.GetString("Device_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device width: {0} bits. + /// + internal static string Device_width_0_bits { + get { + return ResourceManager.GetString("Device_width_0_bits", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will boot up in x1 SDR or x4 DDR bus width.. + /// + internal static string Device_will_boot_up_in_x1_SDR_or_x4_DDR_bus_width { + get { + return ResourceManager.GetString("Device_will_boot_up_in_x1_SDR_or_x4_DDR_bus_width", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will boot up in x4 SDR or DDR bus width.. + /// + internal static string Device_will_boot_up_in_x4_SDR_or_DDR_bus_width { + get { + return ResourceManager.GetString("Device_will_boot_up_in_x4_SDR_or_DDR_bus_width", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will boot up in x8 SDR or DDR bus width.. + /// + internal static string Device_will_boot_up_in_x8_SDR_or_DDR_bus_width { + get { + return ResourceManager.GetString("Device_will_boot_up_in_x8_SDR_or_DDR_bus_width", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will not degrade performance to extend its life. + /// + internal static string Device_will_not_degrade_performance_to_extend_its_life { + get { + return ResourceManager.GetString("Device_will_not_degrade_performance_to_extend_its_life", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will reset boot conditions to compatibility mode after boot operation.. + /// + internal static string Device_will_reset_boot_conditions_to_compatibility_mode_after_boot_operation { + get { + return ResourceManager.GetString("Device_will_reset_boot_conditions_to_compatibility_mode_after_boot_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will retain boot conditions after boot operation.. + /// + internal static string Device_will_retain_boot_conditions_after_boot_operation { + get { + return ResourceManager.GetString("Device_will_retain_boot_conditions_after_boot_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will use dual data rate in boot operation.. + /// + internal static string Device_will_use_dual_data_rate_in_boot_operation { + get { + return ResourceManager.GetString("Device_will_use_dual_data_rate_in_boot_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will use high capacity erase unit size, timeout and write protect group size definitions.. + /// + internal static string Device_will_use_high_capacity_erase_unit_size__timeout_and_write_protect_group_size_definitions { + get { + return ResourceManager.GetString("Device_will_use_high_capacity_erase_unit_size__timeout_and_write_protect_group_si" + + "ze_definitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will use single data rate with compatible timings in boot operation.. + /// + internal static string Device_will_use_single_data_rate_with_compatible_timings_in_boot_operation { + get { + return ResourceManager.GetString("Device_will_use_single_data_rate_with_compatible_timings_in_boot_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will use single data rate with high speed timings in boot operation.. + /// + internal static string Device_will_use_single_data_rate_with_high_speed_timings_in_boot_operation { + get { + return ResourceManager.GetString("Device_will_use_single_data_rate_with_high_speed_timings_in_boot_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device will use unknown boot mode with code 3.. + /// + internal static string Device_will_use_unknown_boot_mode_with_code_three { + get { + return ResourceManager.GetString("Device_will_use_unknown_boot_mode_with_code_three", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device writes directly to media. + /// + internal static string Device_writes_directly_to_media { + get { + return ResourceManager.GetString("Device_writes_directly_to_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device's cache is enabled. + /// + internal static string Devices_cache_is_enabled { + get { + return ResourceManager.GetString("Devices_cache_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DI Unit Format: 0x{0:X2}. + /// + internal static string DI_Unit_Format_0 { + get { + return ResourceManager.GetString("DI_Unit_Format_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DI Unit is {0} bytes. + /// + internal static string DI_Unit_is_0_bytes { + get { + return ResourceManager.GetString("DI_Unit_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DI Unit Sequence: {0}. + /// + internal static string DI_Unit_Sequence_0 { + get { + return ResourceManager.GetString("DI_Unit_Sequence_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Digital copy of track is permitted. + /// + internal static string Digital_copy_of_track_is_permitted { + get { + return ResourceManager.GetString("Digital_copy_of_track_is_permitted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Digital copy of track is prohibited. + /// + internal static string Digital_copy_of_track_is_prohibited { + get { + return ResourceManager.GetString("Digital_copy_of_track_is_prohibited", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Direct-access device. + /// + internal static string Direct_access_device { + get { + return ResourceManager.GetString("Direct_access_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc application code: {0}. + /// + internal static string Disc_application_code_0 { + get { + return ResourceManager.GetString("Disc_application_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc barcode: {0:X16}. + /// + internal static string Disc_barcode_0 { + get { + return ResourceManager.GetString("Disc_barcode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc book type is {0}. + /// + internal static string Disc_book_type_is_0 { + get { + return ResourceManager.GetString("Disc_book_type_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc boots natively.. + /// + internal static string Disc_boots_natively { + get { + return ResourceManager.GetString("Disc_boots_natively", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc boots using unknown loader: {0}.. + /// + internal static string Disc_boots_using_unknown_loader_0 { + get { + return ResourceManager.GetString("Disc_boots_using_unknown_loader_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc boots using Windows CE.. + /// + internal static string Disc_boots_using_Windows_CE { + get { + return ResourceManager.GetString("Disc_boots_using_Windows_CE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc can be played in any region.. + /// + internal static string Disc_can_be_played_in_any_region { + get { + return ResourceManager.GetString("Disc_can_be_played_in_any_region", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc can be played in the following regions:. + /// + internal static string Disc_can_be_played_in_the_following_regions { + get { + return ResourceManager.GetString("Disc_can_be_played_in_the_following_regions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc can be recorded with or without a case. + /// + internal static string Disc_can_be_recorded_with_or_without_a_case { + get { + return ResourceManager.GetString("Disc_can_be_recorded_with_or_without_a_case", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc cannot be played in any region at all.. + /// + internal static string Disc_cannot_be_played_in_any_region_at_all { + get { + return ResourceManager.GetString("Disc_cannot_be_played_in_any_region_at_all", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-267. + /// + internal static string Disc_claims_conformation_to_ECMA_267 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_267", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-268. + /// + internal static string Disc_claims_conformation_to_ECMA_268 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_268", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-272. + /// + internal static string Disc_claims_conformation_to_ECMA_272 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_272", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-274. + /// + internal static string Disc_claims_conformation_to_ECMA_274 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_274", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-279. + /// + internal static string Disc_claims_conformation_to_ECMA_279 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_279", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-330. + /// + internal static string Disc_claims_conformation_to_ECMA_330 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_330", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-337. + /// + internal static string Disc_claims_conformation_to_ECMA_337 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_337", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-338. + /// + internal static string Disc_claims_conformation_to_ECMA_338 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_338", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-349. + /// + internal static string Disc_claims_conformation_to_ECMA_349 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_349", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-359. + /// + internal static string Disc_claims_conformation_to_ECMA_359 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_359", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-364. + /// + internal static string Disc_claims_conformation_to_ECMA_364 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_364", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-365. + /// + internal static string Disc_claims_conformation_to_ECMA_365 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_365", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-371. + /// + internal static string Disc_claims_conformation_to_ECMA_371 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_371", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-374. + /// + internal static string Disc_claims_conformation_to_ECMA_374 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_374", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-382. + /// + internal static string Disc_claims_conformation_to_ECMA_382 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_382", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc claims conformation to ECMA-384. + /// + internal static string Disc_claims_conformation_to_ECMA_384 { + get { + return ResourceManager.GetString("Disc_claims_conformation_to_ECMA_384", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc class: {0}. + /// + internal static string Disc_class_0 { + get { + return ResourceManager.GetString("Disc_class_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc comes in a cartridge. + /// + internal static string Disc_comes_in_a_cartridge { + get { + return ResourceManager.GetString("Disc_comes_in_a_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc contains extended information for VCPS. + /// + internal static string Disc_contains_extended_information_for_VCPS { + get { + return ResourceManager.GetString("Disc_contains_extended_information_for_VCPS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc does not specify a maximum transfer rate.. + /// + internal static string Disc_does_not_specify_a_maximum_transfer_rate { + get { + return ResourceManager.GetString("Disc_does_not_specify_a_maximum_transfer_rate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc doesn't have a BCA.. + /// + internal static string Disc_doesn_t_have_a_BCA { + get { + return ResourceManager.GetString("Disc_doesn_t_have_a_BCA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc for restricted use.. + /// + internal static string Disc_for_restricted_use { + get { + return ResourceManager.GetString("Disc_for_restricted_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc for unrestricted use.. + /// + internal static string Disc_for_unrestricted_use { + get { + return ResourceManager.GetString("Disc_for_unrestricted_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc for use in special drives according with purpose value {0}. + /// + internal static string Disc_for_use_in_special_drives_according_with_purpose_value_0 { + get { + return ResourceManager.GetString("Disc_for_use_in_special_drives_according_with_purpose_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has {0} layers. + /// + internal static string Disc_has_0_layers { + get { + return ResourceManager.GetString("Disc_has_0_layers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has {0} sessions. + /// + internal static string Disc_has_0_sessions { + get { + return ResourceManager.GetString("Disc_has_0_sessions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has {0} zones. + /// + internal static string Disc_has_0_zones { + get { + return ResourceManager.GetString("Disc_has_0_zones", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has 120mm diameter. + /// + internal static string Disc_has_120mm_diameter { + get { + return ResourceManager.GetString("Disc_has_120mm_diameter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has 80mm diameter. + /// + internal static string Disc_has_80mm_diameter { + get { + return ResourceManager.GetString("Disc_has_80mm_diameter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has a BCA.. + /// + internal static string Disc_has_a_BCA { + get { + return ResourceManager.GetString("Disc_has_a_BCA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has a maximum transfer rate of {0} Mbit/sec.. + /// + internal static string Disc_has_a_maximum_transfer_rate_of_0_Mbit_sec { + get { + return ResourceManager.GetString("Disc_has_a_maximum_transfer_rate_of_0_Mbit_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has been certified by a manufacturer. + /// + internal static string Disc_has_been_certified_by_a_manufacturer { + get { + return ResourceManager.GetString("Disc_has_been_certified_by_a_manufacturer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has been certified by a user. + /// + internal static string Disc_has_been_certified_by_a_user { + get { + return ResourceManager.GetString("Disc_has_been_certified_by_a_user", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has been extracted from the cartridge. + /// + internal static string Disc_has_been_extracted_from_the_cartridge { + get { + return ResourceManager.GetString("Disc_has_been_extracted_from_the_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has no encryption.. + /// + internal static string Disc_has_no_encryption { + get { + return ResourceManager.GetString("Disc_has_no_encryption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc has unknown reason {0} for write inhibition. + /// + internal static string Disc_has_unknown_reason_0_for_write_inhibition { + get { + return ResourceManager.GetString("Disc_has_unknown_reason_0_for_write_inhibition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc ID: {0:X6}. + /// + internal static string Disc_ID_0_X6 { + get { + return ResourceManager.GetString("Disc_ID_0_X6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is a {0} {1} version {2}. + /// + internal static string Disc_is_a_0_1_version_2 { + get { + return ResourceManager.GetString("Disc_is_a_0_1_version_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is a Nintendo Gamecube Optical Disc (GOD). + /// + internal static string Disc_is_a_Nintendo_Gamecube_Optical_Disc_GOD { + get { + return ResourceManager.GetString("Disc_is_a_Nintendo_Gamecube_Optical_Disc_GOD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is a Nintendo Wii Optical Disc (WOD). + /// + internal static string Disc_is_a_Nintendo_Wii_Optical_Disc_WOD { + get { + return ResourceManager.GetString("Disc_is_a_Nintendo_Wii_Optical_Disc_WOD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is CD-R. + /// + internal static string Disc_is_CD_R { + get { + return ResourceManager.GetString("Disc_is_CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is CD-RW. + /// + internal static string Disc_is_CD_RW { + get { + return ResourceManager.GetString("Disc_is_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is DDCD-R. + /// + internal static string Disc_is_DDCD_R { + get { + return ResourceManager.GetString("Disc_is_DDCD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is DDCD-RW. + /// + internal static string Disc_is_DDCD_RW { + get { + return ResourceManager.GetString("Disc_is_DDCD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is defined for restricted use. + /// + internal static string Disc_is_defined_for_restricted_use { + get { + return ResourceManager.GetString("Disc_is_defined_for_restricted_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is defined for unrestricted use. + /// + internal static string Disc_is_defined_for_unrestricted_use { + get { + return ResourceManager.GetString("Disc_is_defined_for_unrestricted_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is empty. + /// + internal static string Disc_is_empty { + get { + return ResourceManager.GetString("Disc_is_empty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is encrypted using AACS.. + /// + internal static string Disc_is_encrypted_using_AACS { + get { + return ResourceManager.GetString("Disc_is_encrypted_using_AACS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is encrypted using CPRM.. + /// + internal static string Disc_is_encrypted_using_CPRM { + get { + return ResourceManager.GetString("Disc_is_encrypted_using_CPRM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is encrypted using CSS or CPPM.. + /// + internal static string Disc_is_encrypted_using_CSS_or_CPPM { + get { + return ResourceManager.GetString("Disc_is_encrypted_using_CSS_or_CPPM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is encrypted using unknown algorithm with ID {0}.. + /// + internal static string Disc_is_encrypted_using_unknown_algorithm_with_ID_0 { + get { + return ResourceManager.GetString("Disc_is_encrypted_using_unknown_algorithm_with_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is erasable. + /// + internal static string Disc_is_erasable { + get { + return ResourceManager.GetString("Disc_is_erasable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is finalized. + /// + internal static string Disc_is_finalized { + get { + return ResourceManager.GetString("Disc_is_finalized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is high speed (CAV) CD-R. + /// + internal static string Disc_is_high_speed_CAV_CD_R { + get { + return ResourceManager.GetString("Disc_is_high_speed_CAV_CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is High-Speed CD-RW. + /// + internal static string Disc_is_High_Speed_CD_RW { + get { + return ResourceManager.GetString("Disc_is_High_Speed_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is incomplete. + /// + internal static string Disc_is_incomplete { + get { + return ResourceManager.GetString("Disc_is_incomplete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is medium type A, high beta category (A+) CD-R. + /// + internal static string Disc_is_medium_type_A_high_beta_category_CD_R { + get { + return ResourceManager.GetString("Disc_is_medium_type_A_high_beta_category_CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is medium type A, low beta category (A-) CD-R. + /// + internal static string Disc_is_medium_type_A_low_beta_category_CD_R { + get { + return ResourceManager.GetString("Disc_is_medium_type_A_low_beta_category_CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is medium type B, high beta category (B+) CD-R. + /// + internal static string Disc_is_medium_type_B_high_beta_category__CD_R { + get { + return ResourceManager.GetString("Disc_is_medium_type_B_high_beta_category__CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is medium type B, high beta category (B+) CD-RW. + /// + internal static string Disc_is_medium_type_B_high_beta_category_CD_RW { + get { + return ResourceManager.GetString("Disc_is_medium_type_B_high_beta_category_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is medium type B, low beta category (B-) CD-R. + /// + internal static string Disc_is_medium_type_B_low_beta_category_CD_R { + get { + return ResourceManager.GetString("Disc_is_medium_type_B_low_beta_category_CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is medium type B, low beta category (B-) CD-RW. + /// + internal static string Disc_is_medium_type_B_low_beta_category_CD_RW { + get { + return ResourceManager.GetString("Disc_is_medium_type_B_low_beta_category_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is medium type C, high beta category (C+) CD-R. + /// + internal static string Disc_is_medium_type_C_high_beta_category__CD_R { + get { + return ResourceManager.GetString("Disc_is_medium_type_C_high_beta_category__CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is medium type C, high beta category (C+) CD-RW. + /// + internal static string Disc_is_medium_type_C_high_beta_category_CD_RW { + get { + return ResourceManager.GetString("Disc_is_medium_type_C_high_beta_category_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is medium type C, low beta category (C-) CD-R. + /// + internal static string Disc_is_medium_type_C_low_beta_category__CD_R { + get { + return ResourceManager.GetString("Disc_is_medium_type_C_low_beta_category__CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is medium type C, low beta category (C-) CD-RW. + /// + internal static string Disc_is_medium_type_C_low_beta_category_CD_RW { + get { + return ResourceManager.GetString("Disc_is_medium_type_C_low_beta_category_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is normal speed (CLV) CD-R. + /// + internal static string Disc_is_normal_speed_CLV_CD_R { + get { + return ResourceManager.GetString("Disc_is_normal_speed_CLV_CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is R (recordable). + /// + internal static string Disc_is_R_recordable { + get { + return ResourceManager.GetString("Disc_is_R_recordable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is RW (rewritable). + /// + internal static string Disc_is_RW_rewritable { + get { + return ResourceManager.GetString("Disc_is_RW_rewritable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is Ultra-Speed CD-RW. + /// + internal static string Disc_is_Ultra_Speed_CD_RW { + get { + return ResourceManager.GetString("Disc_is_Ultra_Speed_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is Ultra-Speed+ CD-RW. + /// + internal static string Disc_is_Ultra_Speed_Plus_CD_RW { + get { + return ResourceManager.GetString("Disc_is_Ultra_Speed_Plus_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is write inhibited because it has been extracted from the cartridge. + /// + internal static string Disc_is_write_inhibited_because_it_has_been_extracted_from_the_cartridge { + get { + return ResourceManager.GetString("Disc_is_write_inhibited_because_it_has_been_extracted_from_the_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is write inhibited for an unspecified reason. + /// + internal static string Disc_is_write_inhibited_for_an_unspecified_reason { + get { + return ResourceManager.GetString("Disc_is_write_inhibited_for_an_unspecified_reason", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc manufactured by: {0}. + /// + internal static string Disc_manufactured_by_0 { + get { + return ResourceManager.GetString("Disc_manufactured_by_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc manufacturer ID: "{0}". + /// + internal static string Disc_manufacturer_ID_0 { + get { + return ResourceManager.GetString("Disc_manufacturer_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc manufacturer is {0}. + /// + internal static string Disc_manufacturer_is_0 { + get { + return ResourceManager.GetString("Disc_manufacturer_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc manufacturer supplementary information is {0}. + /// + internal static string Disc_manufacturer_supplementary_information_is_0 { + get { + return ResourceManager.GetString("Disc_manufacturer_supplementary_information_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc maximum transfer rate is 10.08 Mbit/sec.. + /// + internal static string Disc_maximum_transfer_rate_is_10_08_Mbit_sec { + get { + return ResourceManager.GetString("Disc_maximum_transfer_rate_is_10_08_Mbit_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc maximum transfer rate is 2.52 Mbit/sec.. + /// + internal static string Disc_maximum_transfer_rate_is_2_52_Mbit_sec { + get { + return ResourceManager.GetString("Disc_maximum_transfer_rate_is_2_52_Mbit_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc maximum transfer rate is 20.16 Mbit/sec.. + /// + internal static string Disc_maximum_transfer_rate_is_20_16_Mbit_sec { + get { + return ResourceManager.GetString("Disc_maximum_transfer_rate_is_20_16_Mbit_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc maximum transfer rate is 30.24 Mbit/sec.. + /// + internal static string Disc_maximum_transfer_rate_is_30_24_Mbit_sec { + get { + return ResourceManager.GetString("Disc_maximum_transfer_rate_is_30_24_Mbit_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc maximum transfer rate is 5.04 Mbit/sec.. + /// + internal static string Disc_maximum_transfer_rate_is_5_04_Mbit_sec { + get { + return ResourceManager.GetString("Disc_maximum_transfer_rate_is_5_04_Mbit_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc maximum transfer rate is specified by unknown key {0}. + /// + internal static string Disc_maximum_transfer_rate_is_specified_by_unknown_key_0 { + get { + return ResourceManager.GetString("Disc_maximum_transfer_rate_is_specified_by_unknown_key_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc maximum transfer rate is unspecified.. + /// + internal static string Disc_maximum_transfer_rate_is_unspecified { + get { + return ResourceManager.GetString("Disc_maximum_transfer_rate_is_unspecified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc may be written without a cartridge. + /// + internal static string Disc_may_be_written_without_a_cartridge { + get { + return ResourceManager.GetString("Disc_may_be_written_without_a_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc media: {0}. + /// + internal static string Disc_media_0 { + get { + return ResourceManager.GetString("Disc_media_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc media type ID: "{0}". + /// + internal static string Disc_media_type_ID_0 { + get { + return ResourceManager.GetString("Disc_media_type_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc media type is {0}. + /// + internal static string Disc_media_type_is_0 { + get { + return ResourceManager.GetString("Disc_media_type_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc number {0} of {1}. + /// + internal static string Disc_number_0_of_1 { + get { + return ResourceManager.GetString("Disc_number_0_of_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc product revision is {0}. + /// + internal static string Disc_product_revision_is_0 { + get { + return ResourceManager.GetString("Disc_product_revision_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc product revision number: {0}. + /// + internal static string Disc_product_revision_number_0 { + get { + return ResourceManager.GetString("Disc_product_revision_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc reflectivity is between 18% and 30%. + /// + internal static string Disc_reflectivity_is_between_18_and_30 { + get { + return ResourceManager.GetString("Disc_reflectivity_is_between_18_and_30", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc reflectivity is between 45% and 85%. + /// + internal static string Disc_reflectivity_is_between_45_and_85 { + get { + return ResourceManager.GetString("Disc_reflectivity_is_between_45_and_85", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc shall be recorded with a case. + /// + internal static string Disc_shall_be_recorded_with_a_case { + get { + return ResourceManager.GetString("Disc_shall_be_recorded_with_a_case", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc shall not be written without a cartridge. + /// + internal static string Disc_shall_not_be_written_without_a_cartridge { + get { + return ResourceManager.GetString("Disc_shall_not_be_written_without_a_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc size: 120mm. + /// + internal static string Disc_size_120mm { + get { + return ResourceManager.GetString("Disc_size_120mm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc size: 80mm. + /// + internal static string Disc_size_80mm { + get { + return ResourceManager.GetString("Disc_size_80mm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc size: Unknown code {0}. + /// + internal static string Disc_size_Unknown_code_0 { + get { + return ResourceManager.GetString("Disc_size_Unknown_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc surface is set to write protected status. + /// + internal static string Disc_surface_is_set_to_write_protected_status { + get { + return ResourceManager.GetString("Disc_surface_is_set_to_write_protected_status", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc timestamp: 0x{0:X2}. + /// + internal static string Disc_timestamp_0 { + get { + return ResourceManager.GetString("Disc_timestamp_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc track pitch is 0.74 μm. + /// + internal static string Disc_track_pitch_is_0_74_μm { + get { + return ResourceManager.GetString("Disc_track_pitch_is_0_74_μm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc type: {0}. + /// + internal static string Disc_type_0 { + get { + return ResourceManager.GetString("Disc_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc type declared as CD-DA or CD-ROM. + /// + internal static string Disc_type_declared_as_CD_DA_or_CD_ROM { + get { + return ResourceManager.GetString("Disc_type_declared_as_CD_DA_or_CD_ROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc type declared as CD-i. + /// + internal static string Disc_type_declared_as_CD_i { + get { + return ResourceManager.GetString("Disc_type_declared_as_CD_i", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc type declared as CD-ROM XA. + /// + internal static string Disc_type_declared_as_CD_ROM_XA { + get { + return ResourceManager.GetString("Disc_type_declared_as_CD_ROM_XA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc type identifier: "{0}". + /// + internal static string Disc_type_identifier_0 { + get { + return ResourceManager.GetString("Disc_type_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc type is undefined. + /// + internal static string Disc_type_is_undefined { + get { + return ResourceManager.GetString("Disc_type_is_undefined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc Type Specific Field 1: 0x{0:X2}. + /// + internal static string Disc_Type_Specific_Field_1_0 { + get { + return ResourceManager.GetString("Disc_Type_Specific_Field_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc Type Specific Field 2: 0x{0:X8}. + /// + internal static string Disc_Type_Specific_Field_2_0 { + get { + return ResourceManager.GetString("Disc_Type_Specific_Field_2_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc use is restricted. + /// + internal static string Disc_use_is_restricted { + get { + return ResourceManager.GetString("Disc_use_is_restricted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc use is unrestricted. + /// + internal static string Disc_use_is_unrestricted { + get { + return ResourceManager.GetString("Disc_use_is_unrestricted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses a 69.0nm channel giving 27 Gb per layer.. + /// + internal static string Disc_uses_a_69_0nm_channel_giving_27_Gb_per_layer { + get { + return ResourceManager.GetString("Disc_uses_a_69_0nm_channel_giving_27_Gb_per_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses a 74.5nm channel giving 25 Gb per layer.. + /// + internal static string Disc_uses_a_74_5nm_channel_giving_25_Gb_per_layer { + get { + return ResourceManager.GetString("Disc_uses_a_74_5nm_channel_giving_25_Gb_per_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses long strategy type dye (Cyanine, AZO, etc...). + /// + internal static string Disc_uses_long_strategy_type_dye_Cyanine_AZO_etc { + get { + return ResourceManager.GetString("Disc_uses_long_strategy_type_dye_Cyanine_AZO_etc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses negative polarity.. + /// + internal static string Disc_uses_negative_polarity { + get { + return ResourceManager.GetString("Disc_uses_negative_polarity", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses phase change. + /// + internal static string Disc_uses_phase_change { + get { + return ResourceManager.GetString("Disc_uses_phase_change", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses positive polarity.. + /// + internal static string Disc_uses_positive_polarity { + get { + return ResourceManager.GetString("Disc_uses_positive_polarity", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses short strategy type dye (Phthalocyanine, etc...). + /// + internal static string Disc_uses_short_strategy_type_dye_Phthalocyanine_etc { + get { + return ResourceManager.GetString("Disc_uses_short_strategy_type_dye_Phthalocyanine_etc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses unknown BCA code {0}. + /// + internal static string Disc_uses_unknown_BCA_code_0 { + get { + return ResourceManager.GetString("Disc_uses_unknown_BCA_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses unknown channel length with code {0}. + /// + internal static string Disc_uses_unknown_channel_length_with_code_0 { + get { + return ResourceManager.GetString("Disc_uses_unknown_channel_length_with_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses unknown polarity with code {0}. + /// + internal static string Disc_uses_unknown_polarity_with_code_0 { + get { + return ResourceManager.GetString("Disc_uses_unknown_polarity_with_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc uses unknown recorded reflectivity polarity with code {0}. + /// + internal static string Disc_uses_unknown_recorded_reflectivity_polarity_with_code_0 { + get { + return ResourceManager.GetString("Disc_uses_unknown_recorded_reflectivity_polarity_with_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc version: {0}. + /// + internal static string Disc_version_0 { + get { + return ResourceManager.GetString("Disc_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape III at 42500 bpi. + /// + internal static string DLT3_42k { + get { + return ResourceManager.GetString("DLT3_42k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape III with 56 tracks. + /// + internal static string DLT3_56t { + get { + return ResourceManager.GetString("DLT3_56t", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape III at 62500 bpi. + /// + internal static string DLT3_62k { + get { + return ResourceManager.GetString("DLT3_62k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape IIIxt. + /// + internal static string DLT3_XT { + get { + return ResourceManager.GetString("DLT3_XT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape IIIxt compressed. + /// + internal static string DLT3_XT_compressed { + get { + return ResourceManager.GetString("DLT3_XT_compressed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape III compressed. + /// + internal static string DLT3c { + get { + return ResourceManager.GetString("DLT3c", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape IV. + /// + internal static string DLT4 { + get { + return ResourceManager.GetString("DLT4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape IV at 123090 bpi. + /// + internal static string DLT4_123k { + get { + return ResourceManager.GetString("DLT4_123k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape IV at 85937 bpi. + /// + internal static string DLT4_85k { + get { + return ResourceManager.GetString("DLT4_85k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape IV at 98250 bpi. + /// + internal static string DLT4_98k { + get { + return ResourceManager.GetString("DLT4_98k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape IV compressed. + /// + internal static string DLT4c { + get { + return ResourceManager.GetString("DLT4c", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape IV at 123090 bpi compressed. + /// + internal static string DLT4c_123k { + get { + return ResourceManager.GetString("DLT4c_123k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape IV at 85937 bpi compressed. + /// + internal static string DLT4c_85k { + get { + return ResourceManager.GetString("DLT4c_85k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape IV at 98250 bpi compressed. + /// + internal static string DLT4c_98k { + get { + return ResourceManager.GetString("DLT4c_98k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DMA is supported. + /// + internal static string DMA_is_supported { + get { + return ResourceManager.GetString("DMA_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DMA Setup auto-activation is supported. + /// + internal static string DMA_Setup_auto_activation_is_supported { + get { + return ResourceManager.GetString("DMA_Setup_auto_activation_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DMA Setup auto-activation is supported and enabled. + /// + internal static string DMA_Setup_auto_activation_is_supported_and_enabled { + get { + return ResourceManager.GetString("DMA_Setup_auto_activation_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DMA timing mode: {0}. + /// + internal static string DMA_timing_mode_0 { + get { + return ResourceManager.GetString("DMA_timing_mode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Domestic title: {0}. + /// + internal static string Domestic_title_0 { + get { + return ResourceManager.GetString("Domestic_title_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Double Byte Character Code is used. + /// + internal static string Double_Byte_Character_Code_is_used { + get { + return ResourceManager.GetString("Double_Byte_Character_Code_is_used", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DOWNLOAD MICROCODE DMA is supported. + /// + internal static string DOWNLOAD_MICROCODE_DMA_is_supported { + get { + return ResourceManager.GetString("DOWNLOAD_MICROCODE_DMA_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DOWNLOAD MICROCODE is supported. + /// + internal static string DOWNLOAD_MICROCODE_is_supported { + get { + return ResourceManager.GetString("DOWNLOAD_MICROCODE_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DOWNLOAD MICROCODE is supported and enabled. + /// + internal static string DOWNLOAD_MICROCODE_is_supported_and_enabled { + get { + return ResourceManager.GetString("DOWNLOAD_MICROCODE_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive accepts a maximum of {0} blocks in a READ command during rebuild. + /// + internal static string Drive_accepts_a_maximum_of_0_blocks_in_a_READ_command_during_rebuild { + get { + return ResourceManager.GetString("Drive_accepts_a_maximum_of_0_blocks_in_a_READ_command_during_rebuild", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive accepts a maximum of {0} blocks in a REGENERATE command. + /// + internal static string Drive_accepts_a_maximum_of_0_blocks_in_a_REGENERATE_command { + get { + return ResourceManager.GetString("Drive_accepts_a_maximum_of_0_blocks_in_a_REGENERATE_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive accepts a maximum of {0} blocks in a single XOR WRITE command. + /// + internal static string Drive_accepts_a_maximum_of_0_blocks_in_a_single_XOR_WRITE_command { + get { + return ResourceManager.GetString("Drive_accepts_a_maximum_of_0_blocks_in_a_single_XOR_WRITE_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive accepts Packed R-W subchannel data. + /// + internal static string Drive_accepts_Packed_R_W_subchannel_data { + get { + return ResourceManager.GetString("Drive_accepts_Packed_R_W_subchannel_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive accepts RAW R-W subchannel data. + /// + internal static string Drive_accepts_RAW_R_W_subchannel_data { + get { + return ResourceManager.GetString("Drive_accepts_RAW_R_W_subchannel_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive allows a tape header to be overwritten. + /// + internal static string Drive_allows_a_tape_header_to_be_overwritten { + get { + return ResourceManager.GetString("Drive_allows_a_tape_header_to_be_overwritten", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive allows all format labels to be overwritten. + /// + internal static string Drive_allows_all_format_labels_to_be_overwritten { + get { + return ResourceManager.GetString("Drive_allows_all_format_labels_to_be_overwritten", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read raw R-W subchannel from the Lead-In. + /// + internal static string Drive_an_read_raw_R_W_subchannel_from_the_Lead_In { + get { + return ResourceManager.GetString("Drive_an_read_raw_R_W_subchannel_from_the_Lead_In", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive and currently inserted media support SecurDisc. + /// + internal static string Drive_and_currently_inserted_media_support_SecurDisc { + get { + return ResourceManager.GetString("Drive_and_currently_inserted_media_support_SecurDisc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive and currently inserted media support VCPS. + /// + internal static string Drive_and_currently_inserted_media_support_VCPS { + get { + return ResourceManager.GetString("Drive_and_currently_inserted_media_support_VCPS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive and read DVD+MRW and read and write CD-MRW. + /// + internal static string Drive_and_read_DVD_MRW_and_read_and_write_CD_MRW { + get { + return ResourceManager.GetString("Drive_and_read_DVD_MRW_and_read_and_write_CD_MRW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive cache segments should be {0} blocks long. + /// + internal static string Drive_cache_segments_should_be_0_blocks_long { + get { + return ResourceManager.GetString("Drive_cache_segments_should_be_0_blocks_long", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive cache segments should be {0} bytes long. + /// + internal static string Drive_cache_segments_should_be_0_bytes_long { + get { + return ResourceManager.GetString("Drive_cache_segments_should_be_0_bytes_long", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can be used as a system floppy device. + /// + internal static string Drive_can_be_used_as_a_system_floppy_device { + get { + return ResourceManager.GetString("Drive_can_be_used_as_a_system_floppy_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can change disc side. + /// + internal static string Drive_can_change_disc_side { + get { + return ResourceManager.GetString("Drive_can_change_disc_side", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can continue from streaming loss. + /// + internal static string Drive_can_continue_from_streaming_loss { + get { + return ResourceManager.GetString("Drive_can_continue_from_streaming_loss", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can deliver a composite audio and video data stream. + /// + internal static string Drive_can_deliver_a_composite_audio_and_video_data_stream { + get { + return ResourceManager.GetString("Drive_can_deliver_a_composite_audio_and_video_data_stream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can do a quick start formatting. + /// + internal static string Drive_can_do_a_quick_start_formatting { + get { + return ResourceManager.GetString("Drive_can_do_a_quick_start_formatting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can do a test writing. + /// + internal static string Drive_can_do_a_test_writing { + get { + return ResourceManager.GetString("Drive_can_do_a_test_writing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can eject media. + /// + internal static string Drive_can_eject_media { + get { + return ResourceManager.GetString("Drive_can_eject_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can expand the spare area on a formatted BD-RE disc. + /// + internal static string Drive_can_expand_the_spare_area_on_a_formatted_BD_RE_disc { + get { + return ResourceManager.GetString("Drive_can_expand_the_spare_area_on_a_formatted_BD_RE_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can fast re-format BD-RE discs. + /// + internal static string Drive_can_fast_re_format_BD_RE_discs { + get { + return ResourceManager.GetString("Drive_can_fast_re_format_BD_RE_discs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can format BD-R discs with RRM format. + /// + internal static string Drive_can_format_BD_R_discs_with_RRM_format { + get { + return ResourceManager.GetString("Drive_can_format_BD_R_discs_with_RRM_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can format BD-RE discs with full certification. + /// + internal static string Drive_can_format_BD_RE_discs_with_full_certification { + get { + return ResourceManager.GetString("Drive_can_format_BD_RE_discs_with_full_certification", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can format BD-RE discs with quick certification. + /// + internal static string Drive_can_format_BD_RE_discs_with_quick_certification { + get { + return ResourceManager.GetString("Drive_can_format_BD_RE_discs_with_quick_certification", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can format BD-RE with no spares allocated. + /// + internal static string Drive_can_format_BD_RE_with_no_spares_allocated { + get { + return ResourceManager.GetString("Drive_can_format_BD_RE_with_no_spares_allocated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can format media into logical blocks. + /// + internal static string Drive_can_format_media_into_logical_blocks { + get { + return ResourceManager.GetString("Drive_can_format_media_into_logical_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can generate Defect Status data during formatting. + /// + internal static string Drive_can_generate_Defect_Status_data_during_formatting { + get { + return ResourceManager.GetString("Drive_can_generate_Defect_Status_data_during_formatting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can lock media. + /// + internal static string Drive_can_lock_media { + get { + return ResourceManager.GetString("Drive_can_lock_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can overwrite a TAO track with another in CD-RWs. + /// + internal static string Drive_can_overwrite_a_TAO_track_with_another_in_CD_RWs { + get { + return ResourceManager.GetString("Drive_can_overwrite_a_TAO_track_with_another_in_CD_RWs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can play audio. + /// + internal static string Drive_can_play_audio { + get { + return ResourceManager.GetString("Drive_can_play_audio", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read, deinterleave and correct R-W subchannels. + /// + internal static string Drive_can_read__deinterleave_and_correct_R_W_subchannels { + get { + return ResourceManager.GetString("Drive_can_read__deinterleave_and_correct_R_W_subchannels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write CD-MRW. + /// + internal static string Drive_can_read_and_write_CD_MRW { + get { + return ResourceManager.GetString("Drive_can_read_and_write_CD_MRW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write CD-MRW and DVD+MRW. + /// + internal static string Drive_can_read_and_write_CD_MRW_and_DVD_MRW { + get { + return ResourceManager.GetString("Drive_can_read_and_write_CD_MRW_and_DVD_MRW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write CD-R. + /// + internal static string Drive_can_read_and_write_CD_R { + get { + return ResourceManager.GetString("Drive_can_read_and_write_CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write CD-RW. + /// + internal static string Drive_can_read_and_write_CD_RW { + get { + return ResourceManager.GetString("Drive_can_read_and_write_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write DVD+MRW. + /// + internal static string Drive_can_read_and_write_DVD_MRW { + get { + return ResourceManager.GetString("Drive_can_read_and_write_DVD_MRW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write DVD+R. + /// + internal static string Drive_can_read_and_write_DVD_Plus_R { + get { + return ResourceManager.GetString("Drive_can_read_and_write_DVD_Plus_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write DVD+R DL. + /// + internal static string Drive_can_read_and_write_DVD_Plus_R_DL { + get { + return ResourceManager.GetString("Drive_can_read_and_write_DVD_Plus_R_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write DVD+RW DL. + /// + internal static string Drive_can_read_and_write_DVD_Plus_RW_DL { + get { + return ResourceManager.GetString("Drive_can_read_and_write_DVD_Plus_RW_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write DVD-R. + /// + internal static string Drive_can_read_and_write_DVD_R { + get { + return ResourceManager.GetString("Drive_can_read_and_write_DVD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write DVD-RAM. + /// + internal static string Drive_can_read_and_write_DVD_RAM { + get { + return ResourceManager.GetString("Drive_can_read_and_write_DVD_RAM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read and write DVD+RW. + /// + internal static string Drive_can_read_and_write_DVD_RW { + get { + return ResourceManager.GetString("Drive_can_read_and_write_DVD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read barcode. + /// + internal static string Drive_can_read_barcode { + get { + return ResourceManager.GetString("Drive_can_read_barcode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read BD-R pre-1.0. + /// + internal static string Drive_can_read_BD_R_pre_1_0 { + get { + return ResourceManager.GetString("Drive_can_read_BD_R_pre_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read BD-R Ver.1. + /// + internal static string Drive_can_read_BD_R_Ver_1 { + get { + return ResourceManager.GetString("Drive_can_read_BD_R_Ver_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read BD-RE pre-1.0. + /// + internal static string Drive_can_read_BD_RE_pre_1_0 { + get { + return ResourceManager.GetString("Drive_can_read_BD_RE_pre_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read BD-RE Ver.1. + /// + internal static string Drive_can_read_BD_RE_Ver_1 { + get { + return ResourceManager.GetString("Drive_can_read_BD_RE_Ver_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read BD-RE Ver.2. + /// + internal static string Drive_can_read_BD_RE_Ver_2 { + get { + return ResourceManager.GetString("Drive_can_read_BD_RE_Ver_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read BD-ROM pre-1.0. + /// + internal static string Drive_can_read_BD_ROM_pre_1_0 { + get { + return ResourceManager.GetString("Drive_can_read_BD_ROM_pre_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read BD-ROM Ver.1. + /// + internal static string Drive_can_read_BD_ROM_Ver_1 { + get { + return ResourceManager.GetString("Drive_can_read_BD_ROM_Ver_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read BD's Burst Cutting Area. + /// + internal static string Drive_can_read_BDs_Burst_Cutting_Area { + get { + return ResourceManager.GetString("Drive_can_read_BDs_Burst_Cutting_Area", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read both sides of a disc. + /// + internal static string Drive_can_read_both_sides_of_a_disc { + get { + return ResourceManager.GetString("Drive_can_read_both_sides_of_a_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read CD-MRW. + /// + internal static string Drive_can_read_CD_MRW { + get { + return ResourceManager.GetString("Drive_can_read_CD_MRW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read CD-MRW and DVD+MRW. + /// + internal static string Drive_can_read_CD_MRW_and_DVD_MRW { + get { + return ResourceManager.GetString("Drive_can_read_CD_MRW_and_DVD_MRW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read CD-R. + /// + internal static string Drive_can_read_CD_R { + get { + return ResourceManager.GetString("Drive_can_read_CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read CD-RW. + /// + internal static string Drive_can_read_CD_RW { + get { + return ResourceManager.GetString("Drive_can_read_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DDCDs. + /// + internal static string Drive_can_read_DDCDs { + get { + return ResourceManager.GetString("Drive_can_read_DDCDs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read Defect Status data recorded on the medium. + /// + internal static string Drive_can_read_Defect_Status_data_recorded_on_the_medium { + get { + return ResourceManager.GetString("Drive_can_read_Defect_Status_data_recorded_on_the_medium", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read digital audio. + /// + internal static string Drive_can_read_digital_audio { + get { + return ResourceManager.GetString("Drive_can_read_digital_audio", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DVD media. + /// + internal static string Drive_can_read_DVD_media { + get { + return ResourceManager.GetString("Drive_can_read_DVD_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DVD+R. + /// + internal static string Drive_can_read_DVD_Plus_R { + get { + return ResourceManager.GetString("Drive_can_read_DVD_Plus_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DVD+RW. + /// + internal static string Drive_can_read_DVD_Plus_RW { + get { + return ResourceManager.GetString("Drive_can_read_DVD_Plus_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DVD+RW DL. + /// + internal static string Drive_can_read_DVD_Plus_RW_DL { + get { + return ResourceManager.GetString("Drive_can_read_DVD_Plus_RW_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DVD-R. + /// + internal static string Drive_can_read_DVD_R { + get { + return ResourceManager.GetString("Drive_can_read_DVD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DVD-R DL from all recording modes. + /// + internal static string Drive_can_read_DVD_R_DL_from_all_recording_modes { + get { + return ResourceManager.GetString("Drive_can_read_DVD_R_DL_from_all_recording_modes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DVD-RAM. + /// + internal static string Drive_can_read_DVD_RAM { + get { + return ResourceManager.GetString("Drive_can_read_DVD_RAM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DVD-ROM. + /// + internal static string Drive_can_read_DVD_ROM { + get { + return ResourceManager.GetString("Drive_can_read_DVD_ROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DVD-RW DL from all recording modes. + /// + internal static string Drive_can_read_DVD_RW_DL_from_all_recording_modes { + get { + return ResourceManager.GetString("Drive_can_read_DVD_RW_DL_from_all_recording_modes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read HD DVD-ROM and HD DVD-RW. + /// + internal static string Drive_can_read_HD_DVD_ROM_and_HD_DVD_RW { + get { + return ResourceManager.GetString("Drive_can_read_HD_DVD_ROM_and_HD_DVD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read HD DVD-ROM, HD DVD-RW and HD DVD-R. + /// + internal static string Drive_can_read_HD_DVD_ROM_HD_DVD_RW_and_HD_DVD_R { + get { + return ResourceManager.GetString("Drive_can_read_HD_DVD_ROM_HD_DVD_RW_and_HD_DVD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read HD DVD-ROM, HD DVD-RW and HD DVD-RAM. + /// + internal static string Drive_can_read_HD_DVD_ROM_HD_DVD_RW_and_HD_DVD_RAM { + get { + return ResourceManager.GetString("Drive_can_read_HD_DVD_ROM_HD_DVD_RW_and_HD_DVD_RAM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read HD DVD-ROM, HD DVD-RW, HD DVD-R and HD DVD-RAM. + /// + internal static string Drive_can_read_HD_DVD_ROM_HD_DVD_RW_HD_DVD_R_and_HD_DVD_RAM { + get { + return ResourceManager.GetString("Drive_can_read_HD_DVD_ROM_HD_DVD_RW_HD_DVD_R_and_HD_DVD_RAM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read ISRC. + /// + internal static string Drive_can_read_ISRC { + get { + return ResourceManager.GetString("Drive_can_read_ISRC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read Media Catalogue Number. + /// + internal static string Drive_can_read_Media_Catalogue_Number { + get { + return ResourceManager.GetString("Drive_can_read_Media_Catalogue_Number", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read sectors in Mode 2 Form 1 format. + /// + internal static string Drive_can_read_sectors_in_Mode_2_Form_1_format { + get { + return ResourceManager.GetString("Drive_can_read_sectors_in_Mode_2_Form_1_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read sectors in Mode 2 Form 2 format. + /// + internal static string Drive_can_read_sectors_in_Mode_2_Form_2_format { + get { + return ResourceManager.GetString("Drive_can_read_sectors_in_Mode_2_Form_2_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read uncorrected and interleaved R-W subchannels. + /// + internal static string Drive_can_read_uncorrected_and_interleaved_R_W_subchannels { + get { + return ResourceManager.GetString("Drive_can_read_uncorrected_and_interleaved_R_W_subchannels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can return CD-Text from Lead-In. + /// + internal static string Drive_can_return_CD_Text_from_Lead_In { + get { + return ResourceManager.GetString("Drive_can_return_CD_Text_from_Lead_In", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can return Spare Area Information. + /// + internal static string Drive_can_return_Spare_Area_Information { + get { + return ResourceManager.GetString("Drive_can_return_Spare_Area_Information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can stop a long immediate operation. + /// + internal static string Drive_can_stop_a_long_immediate_operation { + get { + return ResourceManager.GetString("Drive_can_stop_a_long_immediate_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can store {0} LBA Extents. + /// + internal static string Drive_can_store_0_LBA_Extents { + get { + return ResourceManager.GetString("Drive_can_store_0_LBA_Extents", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can store 256 LBA Extents. + /// + internal static string Drive_can_store_256_LBA_Extents { + get { + return ResourceManager.GetString("Drive_can_store_256_LBA_Extents", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write BD-R on Pseudo-OVerwrite SRM mode. + /// + internal static string Drive_can_write_BD_R_on_Pseudo_OVerwrite_SRM_mode { + get { + return ResourceManager.GetString("Drive_can_write_BD_R_on_Pseudo_OVerwrite_SRM_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write BD-R pre-1.0. + /// + internal static string Drive_can_write_BD_R_pre_1_0 { + get { + return ResourceManager.GetString("Drive_can_write_BD_R_pre_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write BD-R Ver.1. + /// + internal static string Drive_can_write_BD_R_Ver_1 { + get { + return ResourceManager.GetString("Drive_can_write_BD_R_Ver_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write BD-RE pre-1.0. + /// + internal static string Drive_can_write_BD_RE_pre_1_0 { + get { + return ResourceManager.GetString("Drive_can_write_BD_RE_pre_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write BD-RE Ver.1. + /// + internal static string Drive_can_write_BD_RE_Ver_1 { + get { + return ResourceManager.GetString("Drive_can_write_BD_RE_Ver_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write BD-RE Ver.2. + /// + internal static string Drive_can_write_BD_RE_Ver_2 { + get { + return ResourceManager.GetString("Drive_can_write_BD_RE_Ver_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write CD-RW. + /// + internal static string Drive_can_write_CD_RW { + get { + return ResourceManager.GetString("Drive_can_write_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write CDs in raw Mode:. + /// + internal static string Drive_can_write_CDs_in_raw_Mode { + get { + return ResourceManager.GetString("Drive_can_write_CDs_in_raw_Mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write CDs in Session at Once and in Raw Modes:. + /// + internal static string Drive_can_write_CDs_in_Session_at_Once_and_in_Raw_Modes { + get { + return ResourceManager.GetString("Drive_can_write_CDs_in_Session_at_Once_and_in_Raw_Modes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write CDs in Session at Once Mode:. + /// + internal static string Drive_can_write_CDs_in_Session_at_Once_Mode { + get { + return ResourceManager.GetString("Drive_can_write_CDs_in_Session_at_Once_Mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write CDs in Track at Once Mode:. + /// + internal static string Drive_can_write_CDs_in_Track_at_Once_Mode { + get { + return ResourceManager.GetString("Drive_can_write_CDs_in_Track_at_Once_Mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write HD DVD-RW. + /// + internal static string Drive_can_write_HD_DVD_RW { + get { + return ResourceManager.GetString("Drive_can_write_HD_DVD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write HD DVD-RW and HD DVD-R. + /// + internal static string Drive_can_write_HD_DVD_RW_and_HD_DVD_R { + get { + return ResourceManager.GetString("Drive_can_write_HD_DVD_RW_and_HD_DVD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write HD DVD-RW and HD DVD-RAM. + /// + internal static string Drive_can_write_HD_DVD_RW_and_HD_DVD_RAM { + get { + return ResourceManager.GetString("Drive_can_write_HD_DVD_RW_and_HD_DVD_RAM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write HD DVD-RW, HD DVD-R and HD DVD-RAM. + /// + internal static string Drive_can_write_HD_DVD_RW_HD_DVD_R_and_HD_DVD_RAM { + get { + return ResourceManager.GetString("Drive_can_write_HD_DVD_RW_HD_DVD_R_and_HD_DVD_RAM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write High-Speed CD-RW. + /// + internal static string Drive_can_write_High_Speed_CD_RW { + get { + return ResourceManager.GetString("Drive_can_write_High_Speed_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write multi-session CDs in raw mode. + /// + internal static string Drive_can_write_multi_session_CDs_in_raw_mode { + get { + return ResourceManager.GetString("Drive_can_write_multi_session_CDs_in_raw_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write this density. + /// + internal static string Drive_can_write_this_density { + get { + return ResourceManager.GetString("Drive_can_write_this_density", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can write user provided data in the R-W subchannels. + /// + internal static string Drive_can_write_user_provided_data_in_the_R_W_subchannels { + get { + return ResourceManager.GetString("Drive_can_write_user_provided_data_in_the_R_W_subchannels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive cannot store LBA Extents. + /// + internal static string Drive_cannot_store_LBA_Extents { + get { + return ResourceManager.GetString("Drive_cannot_store_LBA_Extents", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive claims capability to read all CD formats according to OSTA Multi-Read Specification + ///. + /// + internal static string Drive_claims_capability_to_read_all_CD_formats_according_to_OSTA_Multi_Read_Specification { + get { + return ResourceManager.GetString("Drive_claims_capability_to_read_all_CD_formats_according_to_OSTA_Multi_Read_Speci" + + "fication", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive claims support to report Track Resources Information. + /// + internal static string Drive_claims_support_to_report_Track_Resources_Information { + get { + return ResourceManager.GetString("Drive_claims_support_to_report_Track_Resources_Information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive conforms to DVD Multi Drive Read-only Specifications. + /// + internal static string Drive_conforms_to_DVD_Multi_Drive_Read_only_Specifications { + get { + return ResourceManager.GetString("Drive_conforms_to_DVD_Multi_Drive_Read_only_Specifications", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive contains a changer that can report the exact contents of the slots. + /// + internal static string Drive_contains_a_changer_that_can_report_the_exact_contents_of_the_slots { + get { + return ResourceManager.GetString("Drive_contains_a_changer_that_can_report_the_exact_contents_of_the_slots", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive copyright: {0}. + /// + internal static string Drive_copyright_0 { + get { + return ResourceManager.GetString("Drive_copyright_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive's current reading speed is {0} Kbyte/sec.. + /// + internal static string Drive_current_reading_speed_is_0_Kbyte_sec { + get { + return ResourceManager.GetString("Drive_current_reading_speed_is_0_Kbyte_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive's current writing speed is {0} Kbyte/sec.. + /// + internal static string Drive_current_writing_speed_is_0_Kbyte_sec { + get { + return ResourceManager.GetString("Drive_current_writing_speed_is_0_Kbyte_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive's current writing speed is {0} Kbyte/sec. in CLV mode. + /// + internal static string Drive_current_writing_speed_is_0_Kbyte_sec_in_CLV_mode { + get { + return ResourceManager.GetString("Drive_current_writing_speed_is_0_Kbyte_sec_in_CLV_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive's current writing speed is {0} Kbyte/sec. in pure CAV mode. + /// + internal static string Drive_current_writing_speed_is_0_Kbyte_sec_in_pure_CAV_mode { + get { + return ResourceManager.GetString("Drive_current_writing_speed_is_0_Kbyte_sec_in_pure_CAV_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive's date/time is: {0}. + /// + internal static string Drive_date_time_is_0 { + get { + return ResourceManager.GetString("Drive_date_time_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive does not allow any logical blocks to be overwritten. + /// + internal static string Drive_does_not_allow_any_logical_blocks_to_be_overwritten { + get { + return ResourceManager.GetString("Drive_does_not_allow_any_logical_blocks_to_be_overwritten", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive does not distinguish between cached read data. + /// + internal static string Drive_does_not_distinguish_between_cached_read_data { + get { + return ResourceManager.GetString("Drive_does_not_distinguish_between_cached_read_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive does not distinguish between cached write data. + /// + internal static string Drive_does_not_distinguish_between_cached_write_data { + get { + return ResourceManager.GetString("Drive_does_not_distinguish_between_cached_write_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive does not support data compression. + /// + internal static string Drive_does_not_support_data_compression { + get { + return ResourceManager.GetString("Drive_does_not_support_data_compression", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive does not use compression. + /// + internal static string Drive_does_not_use_compression { + get { + return ResourceManager.GetString("Drive_does_not_use_compression", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive EEPROM version: {0}. + /// + internal static string Drive_EEPROM_version_0 { + get { + return ResourceManager.GetString("Drive_EEPROM_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive firmware is dated {0}. + /// + internal static string Drive_firmware_is_dated_0 { + get { + return ResourceManager.GetString("Drive_firmware_is_dated_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive generates end-of-data. + /// + internal static string Drive_generates_end_of_data { + get { + return ResourceManager.GetString("Drive_generates_end_of_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive hardware version: {0}. + /// + internal static string Drive_hardware_version_0 { + get { + return ResourceManager.GetString("Drive_hardware_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has {0} DBI cache zones. + /// + internal static string Drive_has_0_DBI_cache_zones { + get { + return ResourceManager.GetString("Drive_has_0_DBI_cache_zones", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has {0} DBI entries. + /// + internal static string Drive_has_0_DBI_entries { + get { + return ResourceManager.GetString("Drive_has_0_DBI_entries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has {0} increase of Group 3 time unit. + /// + internal static string Drive_has_0_increase_of_Group_3_time_unit { + get { + return ResourceManager.GetString("Drive_has_0_increase_of_Group_3_time_unit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has {0} Kbyte of buffer. + /// + internal static string Drive_has_0_Kbyte_of_buffer { + get { + return ResourceManager.GetString("Drive_has_0_Kbyte_of_buffer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has {0} slots. + /// + internal static string Drive_has_0_slots { + get { + return ResourceManager.GetString("Drive_has_0_slots", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has {0} user controlled changes available.. + /// + internal static string Drive_has_0_user_controlled_changes_available { + get { + return ResourceManager.GetString("Drive_has_0_user_controlled_changes_available", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has {0} vendor resets available.. + /// + internal static string Drive_has_0_vendor_resets_available { + get { + return ResourceManager.GetString("Drive_has_0_vendor_resets_available", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has {0} volume levels. + /// + internal static string Drive_has_0_volume_levels { + get { + return ResourceManager.GetString("Drive_has_0_volume_levels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has an analogue audio output. + /// + internal static string Drive_has_an_analogue_audio_output { + get { + return ResourceManager.GetString("Drive_has_an_analogue_audio_output", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has been operating {0}. + /// + internal static string Drive_has_been_operating_0 { + get { + return ResourceManager.GetString("Drive_has_been_operating_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has been powered up {0} times. + /// + internal static string Drive_has_been_powered_up_0_times { + get { + return ResourceManager.GetString("Drive_has_been_powered_up_0_times", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has been powered up a total of {0} seconds. + /// + internal static string Drive_has_been_powered_up_a_total_of_0_seconds { + get { + return ResourceManager.GetString("Drive_has_been_powered_up_a_total_of_0_seconds", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has been powered up since {0} seconds ago this time. + /// + internal static string Drive_has_been_powered_up_since_0_seconds_ago_this_time { + get { + return ResourceManager.GetString("Drive_has_been_powered_up_since_0_seconds_ago_this_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has encryption enabled. + /// + internal static string Drive_has_encryption_enabled { + get { + return ResourceManager.GetString("Drive_has_encryption_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has no region set.. + /// + internal static string Drive_has_no_region_set { + get { + return ResourceManager.GetString("Drive_has_no_region_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has the following regions set:. + /// + internal static string Drive_has_the_following_regions_set { + get { + return ResourceManager.GetString("Drive_has_the_following_regions_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive has two LUNs with rewritable being . + /// + internal static string Drive_has_two_LUNs_with_rewritable_being { + get { + return ResourceManager.GetString("Drive_has_two_LUNs_with_rewritable_being", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive informs of unknown profile 0x{0:X4}. + /// + internal static string Drive_informs_of_unknown_profile_0 { + get { + return ResourceManager.GetString("Drive_informs_of_unknown_profile_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is a changer using cartridges. + /// + internal static string Drive_is_a_changer_using_cartridges { + get { + return ResourceManager.GetString("Drive_is_a_changer_using_cartridges", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is a changer with individually changeable discs. + /// + internal static string Drive_is_a_changer_with_individually_changeable_discs { + get { + return ResourceManager.GetString("Drive_is_a_changer_with_individually_changeable_discs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is a Non-CD Optical Device. + /// + internal static string Drive_is_a_Non_CD_Optical_Device { + get { + return ResourceManager.GetString("Drive_is_a_Non_CD_Optical_Device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is able to access Hybrid discs. + /// + internal static string Drive_is_able_to_access_Hybrid_discs { + get { + return ResourceManager.GetString("Drive_is_able_to_access_Hybrid_discs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is able to maintain the online format layer through reset and power cycling. + /// + internal static string Drive_is_able_to_maintain_the_online_format_layer_through_reset_and_power_cycling { + get { + return ResourceManager.GetString("Drive_is_able_to_maintain_the_online_format_layer_through_reset_and_power_cycling" + + "", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is able to mute channels separately. + /// + internal static string Drive_is_able_to_mute_channels_separately { + get { + return ResourceManager.GetString("Drive_is_able_to_mute_channels_separately", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is able to perform host and drive directed power management. + /// + internal static string Drive_is_able_to_perform_host_and_drive_directed_power_management { + get { + return ResourceManager.GetString("Drive_is_able_to_perform_host_and_drive_directed_power_management", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is able to read media serial number. + /// + internal static string Drive_is_able_to_read_media_serial_number { + get { + return ResourceManager.GetString("Drive_is_able_to_read_media_serial_number", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is able to report slots contents after a reset or change. + /// + internal static string Drive_is_able_to_report_slots_contents_after_a_reset_or_change { + get { + return ResourceManager.GetString("Drive_is_able_to_report_slots_contents_after_a_reset_or_change", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is capable of zero loss linking. + /// + internal static string Drive_is_capable_of_zero_loss_linking { + get { + return ResourceManager.GetString("Drive_is_capable_of_zero_loss_linking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is disabled until power is cycled. + /// + internal static string Drive_is_disabled_until_power_is_cycled { + get { + return ResourceManager.GetString("Drive_is_disabled_until_power_is_cycled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is emulating a CD-ROM drive. + /// + internal static string Drive_is_emulating_a_CD_ROM_drive { + get { + return ResourceManager.GetString("Drive_is_emulating_a_CD_ROM_drive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is flashed with Kreon firmware {0}.. + /// + internal static string Drive_is_flashed_with_Kreon_firmware_0 { + get { + return ResourceManager.GetString("Drive_is_flashed_with_Kreon_firmware_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is locked, media cannot be ejected, but if empty, can be inserted. + /// + internal static string Drive_is_locked__media_cannot_be_ejected__but_if_empty__can_be_inserted { + get { + return ResourceManager.GetString("Drive_is_locked__media_cannot_be_ejected__but_if_empty__can_be_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is locked, media cannot be ejected or inserted. + /// + internal static string Drive_is_locked__media_cannot_be_ejected_or_inserted { + get { + return ResourceManager.GetString("Drive_is_locked__media_cannot_be_ejected_or_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is not conforming to any profile. + /// + internal static string Drive_is_not_conforming_to_any_profile { + get { + return ResourceManager.GetString("Drive_is_not_conforming_to_any_profile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is not emulating a CD-ROM drive. + /// + internal static string Drive_is_not_emulating_a_CD_ROM_drive { + get { + return ResourceManager.GetString("Drive_is_not_emulating_a_CD_ROM_drive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is not locked, media can be ejected and inserted. + /// + internal static string Drive_is_not_locked__media_can_be_ejected_and_inserted { + get { + return ResourceManager.GetString("Drive_is_not_locked__media_can_be_ejected_and_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is operating in WORM mode. + /// + internal static string Drive_is_operating_in_WORM_mode { + get { + return ResourceManager.GetString("Drive_is_operating_in_WORM_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is pop-up. + /// + internal static string Drive_is_pop_up { + get { + return ResourceManager.GetString("Drive_is_pop_up", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is region free.. + /// + internal static string Drive_is_region_free { + get { + return ResourceManager.GetString("Drive_is_region_free", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is software write-protected until powered down. + /// + internal static string Drive_is_software_write_protected_until_powered_down { + get { + return ResourceManager.GetString("Drive_is_software_write_protected_until_powered_down", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive jumpers choose SCSI ID {0}. + /// + internal static string Drive_jumpers_choose_SCSI_ID_0 { + get { + return ResourceManager.GetString("Drive_jumpers_choose_SCSI_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive's maximum reading speed is {0} Kbyte/sec.. + /// + internal static string Drive_maximum_reading_speed_is_0_Kbyte_sec { + get { + return ResourceManager.GetString("Drive_maximum_reading_speed_is_0_Kbyte_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive's maximum writing speed is {0} Kbyte/sec.. + /// + internal static string Drive_maximum_writing_speed_is_0_Kbyte_sec { + get { + return ResourceManager.GetString("Drive_maximum_writing_speed_is_0_Kbyte_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive media is removable. + /// + internal static string Drive_media_is_removable { + get { + return ResourceManager.GetString("Drive_media_is_removable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive needs a minimum of {0} ms between READ commands during rebuild. + /// + internal static string Drive_needs_a_minimum_of_0_ms_between_READ_commands_during_rebuild { + get { + return ResourceManager.GetString("Drive_needs_a_minimum_of_0_ms_between_READ_commands_during_rebuild", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive needs to do {0} step pulses per cylinder. + /// + internal static string Drive_needs_to_do_0_step_pulses_per_cylinder { + get { + return ResourceManager.GetString("Drive_needs_to_do_0_step_pulses_per_cylinder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive operates using explicit address mode. + /// + internal static string Drive_operates_using_explicit_address_mode { + get { + return ResourceManager.GetString("Drive_operates_using_explicit_address_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive operates using implicit address mode. + /// + internal static string Drive_operates_using_implicit_address_mode { + get { + return ResourceManager.GetString("Drive_operates_using_implicit_address_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive power ups locked. + /// + internal static string Drive_power_ups_locked { + get { + return ResourceManager.GetString("Drive_power_ups_locked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive region has been set permanently, but may be reset by the vendor if necessary.. + /// + internal static string Drive_region_has_been_set_permanently_but_may_be_reset_by_the_vendor_if_necessary { + get { + return ResourceManager.GetString("Drive_region_has_been_set_permanently_but_may_be_reset_by_the_vendor_if_necessary" + + "", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive region is set.. + /// + internal static string Drive_region_is_set { + get { + return ResourceManager.GetString("Drive_region_is_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive region is set, with additional restrictions required to make a change.. + /// + internal static string Drive_region_is_set_with_additional_restrictions_required_to_make_a_change { + get { + return ResourceManager.GetString("Drive_region_is_set_with_additional_restrictions_required_to_make_a_change", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive reported a reserved profile number. + /// + internal static string Drive_reported_a_reserved_profile_number { + get { + return ResourceManager.GetString("Drive_reported_a_reserved_profile_number", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive reports early warnings. + /// + internal static string Drive_reports_early_warnings { + get { + return ResourceManager.GetString("Drive_reports_early_warnings", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive reports setmarks. + /// + internal static string Drive_reports_setmarks { + get { + return ResourceManager.GetString("Drive_reports_setmarks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive responds to SCSI ID {0}. + /// + internal static string Drive_responds_to_SCSI_ID_0 { + get { + return ResourceManager.GetString("Drive_responds_to_SCSI_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive servo part number: {0}. + /// + internal static string Drive_servo_part_number_0 { + get { + return ResourceManager.GetString("Drive_servo_part_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive shall allocate {0} bytes to buffer even when all cached data cannot be evicted. + /// + internal static string Drive_shall_allocate_0_bytes_to_buffer_even_when_all_cached_data_cannot_be_evicted { + get { + return ResourceManager.GetString("Drive_shall_allocate_0_bytes_to_buffer_even_when_all_cached_data_cannot_be_evicte" + + "d", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive shall be able to provide a defect-free contiguous address space. + /// + internal static string Drive_shall_be_able_to_provide_a_defect_free_contiguous_address_space { + get { + return ResourceManager.GetString("Drive_shall_be_able_to_provide_a_defect_free_contiguous_address_space", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive shall have the ability to overwrite logical blocks only in fixed sets at a time. + /// + internal static string Drive_shall_have_the_ability_to_overwrite_logical_blocks_only_in_fixed_sets_at_a_time { + get { + return ResourceManager.GetString("Drive_shall_have_the_ability_to_overwrite_logical_blocks_only_in_fixed_sets_at_a_" + + "time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive shall log informational exception conditions. + /// + internal static string Drive_shall_log_informational_exception_conditions { + get { + return ResourceManager.GetString("Drive_shall_log_informational_exception_conditions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive shall maintain its position on reset. + /// + internal static string Drive_shall_maintain_its_position_on_reset { + get { + return ResourceManager.GetString("Drive_shall_maintain_its_position_on_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive shall position to beginning of default data partition on reset. + /// + internal static string Drive_shall_position_to_beginning_of_default_data_partition_on_reset { + get { + return ResourceManager.GetString("Drive_shall_position_to_beginning_of_default_data_partition_on_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive shall report Read/Write Error Recovery mode page. + /// + internal static string Drive_shall_report_Read_Write_Error_Recovery_mode_page { + get { + return ResourceManager.GetString("Drive_shall_report_Read_Write_Error_Recovery_mode_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive shall report recovered errors. + /// + internal static string Drive_shall_report_recovered_errors { + get { + return ResourceManager.GetString("Drive_shall_report_recovered_errors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive should have {0} cache segments. + /// + internal static string Drive_should_have_0_cache_segments { + get { + return ResourceManager.GetString("Drive_should_have_0_cache_segments", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive should not reorder the sequence of write commands to be faster. + /// + internal static string Drive_should_not_reorder_the_sequence_of_write_commands_to_be_faster { + get { + return ResourceManager.GetString("Drive_should_not_reorder_the_sequence_of_write_commands_to_be_faster", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive steps in {0} ns. + /// + internal static string Drive_steps_in_0_ns { + get { + return ResourceManager.GetString("Drive_steps_in_0_ns", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive steps in {0} μs. + /// + internal static string Drive_steps_in_0_μs { + get { + return ResourceManager.GetString("Drive_steps_in_0_μs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports {0} AGIDs concurrently. + /// + internal static string Drive_supports_0_AGIDs_concurrently { + get { + return ResourceManager.GetString("Drive_supports_0_AGIDs_concurrently", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports {0} LUNs. + /// + internal static string Drive_supports_0_LUNs { + get { + return ResourceManager.GetString("Drive_supports_0_LUNs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports {0} volume levels. + /// + internal static string Drive_supports_0_volume_levels { + get { + return ResourceManager.GetString("Drive_supports_0_volume_levels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports a maximum of {0} bytes in a single cue sheet. + /// + internal static string Drive_supports_a_maximum_of_0_bytes_in_a_single_cue_sheet { + get { + return ResourceManager.GetString("Drive_supports_a_maximum_of_0_bytes_in_a_single_cue_sheet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports AACS version {0}. + /// + internal static string Drive_supports_AACS_version_0 { + get { + return ResourceManager.GetString("Drive_supports_AACS_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports AACS version {0} and current disc is encrypted. + /// + internal static string Drive_supports_AACS_version_0_and_current_disc_is_encrypted { + get { + return ResourceManager.GetString("Drive_supports_AACS_version_0_and_current_disc_is_encrypted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports address mode reservation on the RESERVE TRACK command. + /// + internal static string Drive_supports_address_mode_reservation_on_the_RESERVE_TRACK_command { + get { + return ResourceManager.GetString("Drive_supports_address_mode_reservation_on_the_RESERVE_TRACK_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports Advanced Storage - Magneto-Optical. + /// + internal static string Drive_supports_Advanced_Storage_Magneto_Optical { + get { + return ResourceManager.GetString("Drive_supports_Advanced_Storage_Magneto_Optical", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports BD-R RRM. + /// + internal static string Drive_supports_BD_R_RRM { + get { + return ResourceManager.GetString("Drive_supports_BD_R_RRM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports BD-R SRM. + /// + internal static string Drive_supports_BD_R_SRM { + get { + return ResourceManager.GetString("Drive_supports_BD_R_SRM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports BD-RE. + /// + internal static string Drive_supports_BD_RE { + get { + return ResourceManager.GetString("Drive_supports_BD_RE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports BD-ROM. + /// + internal static string Drive_supports_BD_ROM { + get { + return ResourceManager.GetString("Drive_supports_BD_ROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports both forms of background format stopping. + /// + internal static string Drive_supports_both_forms_of_background_format_stopping { + get { + return ResourceManager.GetString("Drive_supports_both_forms_of_background_format_stopping", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports buffer under-run free recording. + /// + internal static string Drive_supports_buffer_under_run_free_recording { + get { + return ResourceManager.GetString("Drive_supports_buffer_under_run_free_recording", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports bus encryption. + /// + internal static string Drive_supports_bus_encryption { + get { + return ResourceManager.GetString("Drive_supports_bus_encryption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports C2 Error Pointers. + /// + internal static string Drive_supports_C2_Error_Pointers { + get { + return ResourceManager.GetString("Drive_supports_C2_Error_Pointers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports C2 pointers. + /// + internal static string Drive_supports_C2_pointers { + get { + return ResourceManager.GetString("Drive_supports_C2_pointers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports CD-R. + /// + internal static string Drive_supports_CD_R { + get { + return ResourceManager.GetString("Drive_supports_CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports CD-ROM. + /// + internal static string Drive_supports_CD_ROM { + get { + return ResourceManager.GetString("Drive_supports_CD_ROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports CD-RW. + /// + internal static string Drive_supports_CD_RW { + get { + return ResourceManager.GetString("Drive_supports_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports CD-RW subtypes. + /// + internal static string Drive_supports_CD_RW_subtypes { + get { + return ResourceManager.GetString("Drive_supports_CD_RW_subtypes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports data block types:. + /// + internal static string Drive_supports_data_block_types { + get { + return ResourceManager.GetString("Drive_supports_data_block_types", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports data compression. + /// + internal static string Drive_supports_data_compression { + get { + return ResourceManager.GetString("Drive_supports_data_compression", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DCB {0:X8}h. + /// + internal static string Drive_supports_DCB_0 { + get { + return ResourceManager.GetString("Drive_supports_DCB_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DDCD-R. + /// + internal static string Drive_supports_DDCD_R { + get { + return ResourceManager.GetString("Drive_supports_DDCD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DDCD-ROM. + /// + internal static string Drive_supports_DDCD_ROM { + get { + return ResourceManager.GetString("Drive_supports_DDCD_ROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DDCD-RW. + /// + internal static string Drive_supports_DDCD_RW { + get { + return ResourceManager.GetString("Drive_supports_DDCD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports Device Busy events. + /// + internal static string Drive_supports_Device_Busy_events { + get { + return ResourceManager.GetString("Drive_supports_Device_Busy_events", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DPO and FUA bits. + /// + internal static string Drive_supports_DPO_and_FUA_bits { + get { + return ResourceManager.GetString("Drive_supports_DPO_and_FUA_bits", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DRT-DM mode. + /// + internal static string Drive_supports_DRT_DM_mode { + get { + return ResourceManager.GetString("Drive_supports_DRT_DM_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD CPRM version {0}. + /// + internal static string Drive_supports_DVD_CPRM_version_0 { + get { + return ResourceManager.GetString("Drive_supports_DVD_CPRM_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD CPRM version {0} and current disc is or can be encrypted. + /// + internal static string Drive_supports_DVD_CPRM_version_0_and_current_disc_is_or_can_be_encrypted { + get { + return ResourceManager.GetString("Drive_supports_DVD_CPRM_version_0_and_current_disc_is_or_can_be_encrypted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD CSS and/or DVD CPPM. + /// + internal static string Drive_supports_DVD_CSS_and_or_DVD_CPPM { + get { + return ResourceManager.GetString("Drive_supports_DVD_CSS_and_or_DVD_CPPM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD CSS/CPPM version {0}. + /// + internal static string Drive_supports_DVD_CSS_CPPM_version_0 { + get { + return ResourceManager.GetString("Drive_supports_DVD_CSS_CPPM_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD CSS/CPPM version {0} and current disc is encrypted. + /// + internal static string Drive_supports_DVD_CSS_CPPM_version_0_and_current_disc_is_encrypted { + get { + return ResourceManager.GetString("Drive_supports_DVD_CSS_CPPM_version_0_and_current_disc_is_encrypted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD-Download. + /// + internal static string Drive_supports_DVD_Download { + get { + return ResourceManager.GetString("Drive_supports_DVD_Download", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD+R. + /// + internal static string Drive_supports_DVD_Plus_R { + get { + return ResourceManager.GetString("Drive_supports_DVD_Plus_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD+R DL. + /// + internal static string Drive_supports_DVD_Plus_R_DL { + get { + return ResourceManager.GetString("Drive_supports_DVD_Plus_R_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD+RW. + /// + internal static string Drive_supports_DVD_Plus_RW { + get { + return ResourceManager.GetString("Drive_supports_DVD_Plus_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD+RW DL. + /// + internal static string Drive_supports_DVD_Plus_RW_DL { + get { + return ResourceManager.GetString("Drive_supports_DVD_Plus_RW_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD-R. + /// + internal static string Drive_supports_DVD_R { + get { + return ResourceManager.GetString("Drive_supports_DVD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD-RAM. + /// + internal static string Drive_supports_DVD_RAM { + get { + return ResourceManager.GetString("Drive_supports_DVD_RAM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD-ROM. + /// + internal static string Drive_supports_DVD_ROM { + get { + return ResourceManager.GetString("Drive_supports_DVD_ROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports DVD-RW DL. + /// + internal static string Drive_supports_DVD_RW_DL { + get { + return ResourceManager.GetString("Drive_supports_DVD_RW_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports encryption. + /// + internal static string Drive_supports_encryption { + get { + return ResourceManager.GetString("Drive_supports_encryption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports EVPD, Page Code and 16-bit Allocation Length as described in SPC-3. + /// + internal static string Drive_supports_EVPD_Page_Code_and_16_bit_Allocation_Length_as_described_in_SPC_3 { + get { + return ResourceManager.GetString("Drive_supports_EVPD_Page_Code_and_16_bit_Allocation_Length_as_described_in_SPC_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports generating the binding nonce. + /// + internal static string Drive_supports_generating_the_binding_nonce { + get { + return ResourceManager.GetString("Drive_supports_generating_the_binding_nonce", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports hard-sectoring format. + /// + internal static string Drive_supports_hard_sectoring_format { + get { + return ResourceManager.GetString("Drive_supports_hard_sectoring_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports HD DVD-R. + /// + internal static string Drive_supports_HD_DVD_R { + get { + return ResourceManager.GetString("Drive_supports_HD_DVD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports HD DVD-R DL. + /// + internal static string Drive_supports_HD_DVD_R_DL { + get { + return ResourceManager.GetString("Drive_supports_HD_DVD_R_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports HD DVD-RAM. + /// + internal static string Drive_supports_HD_DVD_RAM { + get { + return ResourceManager.GetString("Drive_supports_HD_DVD_RAM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports HD DVD-ROM. + /// + internal static string Drive_supports_HD_DVD_ROM { + get { + return ResourceManager.GetString("Drive_supports_HD_DVD_ROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports HD DVD-RW. + /// + internal static string Drive_supports_HD_DVD_RW { + get { + return ResourceManager.GetString("Drive_supports_HD_DVD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports HD DVD-RW DL. + /// + internal static string Drive_supports_HD_DVD_RW_DL { + get { + return ResourceManager.GetString("Drive_supports_HD_DVD_RW_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports HDBurn CD-R. + /// + internal static string Drive_supports_HDBurn_CD_R { + get { + return ResourceManager.GetString("Drive_supports_HDBurn_CD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports HDBurn CD-ROM. + /// + internal static string Drive_supports_HDBurn_CD_ROM { + get { + return ResourceManager.GetString("Drive_supports_HDBurn_CD_ROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports HDBurn CD-RW. + /// + internal static string Drive_supports_HDBurn_CD_RW { + get { + return ResourceManager.GetString("Drive_supports_HDBurn_CD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports IEC-958 digital output on port 1. + /// + internal static string Drive_supports_IEC_958_digital_output_on_port_1 { + get { + return ResourceManager.GetString("Drive_supports_IEC_958_digital_output_on_port_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports IEC-958 digital output on port 2. + /// + internal static string Drive_supports_IEC_958_digital_output_on_port_2 { + get { + return ResourceManager.GetString("Drive_supports_IEC_958_digital_output_on_port_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports layer jump recorded DVD-R DL. + /// + internal static string Drive_supports_layer_jump_recorded_DVD_R_DL { + get { + return ResourceManager.GetString("Drive_supports_layer_jump_recorded_DVD_R_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports linked OSPBs. + /// + internal static string Drive_supports_linked_OSPBs { + get { + return ResourceManager.GetString("Drive_supports_linked_OSPBs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports Magneto-Optical media. + /// + internal static string Drive_supports_Magneto_Optical_media { + get { + return ResourceManager.GetString("Drive_supports_Magneto_Optical_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports media that require erasing before writing. + /// + internal static string Drive_supports_media_that_require_erasing_before_writing { + get { + return ResourceManager.GetString("Drive_supports_media_that_require_erasing_before_writing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports Microcode Upgrade. + /// + internal static string Drive_supports_Microcode_Upgrade { + get { + return ResourceManager.GetString("Drive_supports_Microcode_Upgrade", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports multi-session discs and/or Photo-CD. + /// + internal static string Drive_supports_multi_session_discs_and_or_Photo_CD { + get { + return ResourceManager.GetString("Drive_supports_multi_session_discs_and_or_Photo_CD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports non-removable changeable media. + /// + internal static string Drive_supports_non_removable_changeable_media { + get { + return ResourceManager.GetString("Drive_supports_non_removable_changeable_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports only polling GET EVENT STATUS NOTIFICATION. + /// + internal static string Drive_supports_only_polling_GET_EVENT_STATUS_NOTIFICATION { + get { + return ResourceManager.GetString("Drive_supports_only_polling_GET_EVENT_STATUS_NOTIFICATION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports only the read compatibility stop. + /// + internal static string Drive_supports_only_the_read_compatibility_stop { + get { + return ResourceManager.GetString("Drive_supports_only_the_read_compatibility_stop", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports operational change request / notification class events. + /// + internal static string Drive_supports_operational_change_request_notification_class_events { + get { + return ResourceManager.GetString("Drive_supports_operational_change_request_notification_class_events", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports optical write-once media. + /// + internal static string Drive_supports_optical_write_once_media { + get { + return ResourceManager.GetString("Drive_supports_optical_write_once_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports Persistent-DM mode. + /// + internal static string Drive_supports_Persistent_DM_mode { + get { + return ResourceManager.GetString("Drive_supports_Persistent_DM_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports polling and asynchronous GET EVENT STATUS NOTIFICATION. + /// + internal static string Drive_supports_polling_and_asynchronous_GET_EVENT_STATUS_NOTIFICATION { + get { + return ResourceManager.GetString("Drive_supports_polling_and_asynchronous_GET_EVENT_STATUS_NOTIFICATION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports PSA updates on write-once media. + /// + internal static string Drive_supports_PSA_updates_on_write_once_media { + get { + return ResourceManager.GetString("Drive_supports_PSA_updates_on_write_once_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports quick formatting. + /// + internal static string Drive_supports_quick_formatting { + get { + return ResourceManager.GetString("Drive_supports_quick_formatting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports reading CD-R packet media. + /// + internal static string Drive_supports_reading_CD_R_packet_media { + get { + return ResourceManager.GetString("Drive_supports_reading_CD_R_packet_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports reading Media Key Block of CPRM. + /// + internal static string Drive_supports_reading_Media_Key_Block_of_CPRM { + get { + return ResourceManager.GetString("Drive_supports_reading_Media_Key_Block_of_CPRM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports reading the Drive Certificate. + /// + internal static string Drive_supports_reading_the_Drive_Certificate { + get { + return ResourceManager.GetString("Drive_supports_reading_the_Drive_Certificate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports reading/writing the Disc Write Protect PAC on BD-R/-RE media. + /// + internal static string Drive_supports_reading_writing_the_Disc_Write_Protect_PAC_on_BD_R_RE_media { + get { + return ResourceManager.GetString("Drive_supports_reading_writing_the_Disc_Write_Protect_PAC_on_BD_R_RE_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports recovering data from buffer. + /// + internal static string Drive_supports_recovering_data_from_buffer { + get { + return ResourceManager.GetString("Drive_supports_recovering_data_from_buffer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports reporting progress of format. + /// + internal static string Drive_supports_reporting_progress_of_format { + get { + return ResourceManager.GetString("Drive_supports_reporting_progress_of_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports restricted overwrite DVD-RW. + /// + internal static string Drive_supports_restricted_overwrite_DVD_RW { + get { + return ResourceManager.GetString("Drive_supports_restricted_overwrite_DVD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports rewritable and removable media. + /// + internal static string Drive_supports_rewritable_and_removable_media { + get { + return ResourceManager.GetString("Drive_supports_rewritable_and_removable_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports SecurDisc. + /// + internal static string Drive_supports_SecurDisc { + get { + return ResourceManager.GetString("Drive_supports_SecurDisc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports separate volume per channel. + /// + internal static string Drive_supports_separate_volume_per_channel { + get { + return ResourceManager.GetString("Drive_supports_separate_volume_per_channel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports sequentially recorded DVD-R DL. + /// + internal static string Drive_supports_sequentially_recorded_DVD_R_DL { + get { + return ResourceManager.GetString("Drive_supports_sequentially_recorded_DVD_R_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports sequentially recorded DVD-RW. + /// + internal static string Drive_supports_sequentially_recorded_DVD_RW { + get { + return ResourceManager.GetString("Drive_supports_sequentially_recorded_DVD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports Set Minimum Performance with the SET STREAMING command. + /// + internal static string Drive_supports_Set_Minimum_Performance_with_the_SET_STREAMING_command { + get { + return ResourceManager.GetString("Drive_supports_Set_Minimum_Performance_with_the_SET_STREAMING_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports set/release of PWP status. + /// + internal static string Drive_supports_set_release_of_PWP_status { + get { + return ResourceManager.GetString("Drive_supports_set_release_of_PWP_status", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports S.M.A.R.T.. + /// + internal static string Drive_supports_SMART { + get { + return ResourceManager.GetString("Drive_supports_SMART", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports soft-sectoring format. + /// + internal static string Drive_supports_soft_sectoring_format { + get { + return ResourceManager.GetString("Drive_supports_soft_sectoring_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports stream recording. + /// + internal static string Drive_supports_stream_recording { + get { + return ResourceManager.GetString("Drive_supports_stream_recording", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports test writing. + /// + internal static string Drive_supports_test_writing { + get { + return ResourceManager.GetString("Drive_supports_test_writing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the BLANK command. + /// + internal static string Drive_supports_the_BLANK_command { + get { + return ResourceManager.GetString("Drive_supports_the_BLANK_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the block bit in the READ BUFFER CAPACITY command. + /// + internal static string Drive_supports_the_block_bit_in_the_READ_BUFFER_CAPACITY_command { + get { + return ResourceManager.GetString("Drive_supports_the_block_bit_in_the_READ_BUFFER_CAPACITY_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the DAP bit in the READ CD and READ CD MSF commands. + /// + internal static string Drive_supports_the_DAP_bit_in_the_READ_CD_and_READ_CD_MSF_commands { + get { + return ResourceManager.GetString("Drive_supports_the_DAP_bit_in_the_READ_CD_and_READ_CD_MSF_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the Group3 in Timeout & Protect mode page 1Dh. + /// + internal static string Drive_supports_the_Group3_in_Timeout_Protect_mode_page_1Dh { + get { + return ResourceManager.GetString("Drive_supports_the_Group3_in_Timeout_Protect_mode_page_1Dh", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the Informational Exceptions Control mode page 1Ch. + /// + internal static string Drive_supports_the_Informational_Exceptions_Control_mode_page_1Ch { + get { + return ResourceManager.GetString("Drive_supports_the_Informational_Exceptions_Control_mode_page_1Ch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the SCAN command. + /// + internal static string Drive_supports_the_SCAN_command { + get { + return ResourceManager.GetString("Drive_supports_the_SCAN_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the SET CD SPEED command. + /// + internal static string Drive_supports_the_SET_CD_SPEED_command { + get { + return ResourceManager.GetString("Drive_supports_the_SET_CD_SPEED_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the SWPP bit of the Timeout and Protect mode page. + /// + internal static string Drive_supports_the_SWPP_bit_of_the_Timeout_and_Protect_mode_page { + get { + return ResourceManager.GetString("Drive_supports_the_SWPP_bit_of_the_Timeout_and_Protect_mode_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the Trusted Computing Group Optical Security Subsystem Class. + /// + internal static string Drive_supports_the_Trusted_Computing_Group_Optical_Security_Subsystem_Class { + get { + return ResourceManager.GetString("Drive_supports_the_Trusted_Computing_Group_Optical_Security_Subsystem_Class", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the Write Speed data of GET PERFORMANCE and the WRC field of SET STREAMING. + /// + internal static string Drive_supports_the_Write_Speed_data_of_GET_PERFORMANCE_and_the_WRC_field_of_SET_STREAMING { + get { + return ResourceManager.GetString("Drive_supports_the_Write_Speed_data_of_GET_PERFORMANCE_and_the_WRC_field_of_SET_S" + + "TREAMING", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports the Write Speed Performance Descriptor Blocks in the MMC mode page 2Ah. + /// + internal static string Drive_supports_the_Write_Speed_Performance_Descriptor_Blocks_in_the_MMC_mode_page_2Ah { + get { + return ResourceManager.GetString("Drive_supports_the_Write_Speed_Performance_Descriptor_Blocks_in_the_MMC_mode_page" + + "_2Ah", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports Timeout & Protect mode page 1Dh. + /// + internal static string Drive_supports_Timeout_Protect_mode_page_1Dh { + get { + return ResourceManager.GetString("Drive_supports_Timeout_Protect_mode_page_1Dh", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports validating the 5-bit Mode of the READ BUFFER and WRITE BUFFER commands. + /// + internal static string Drive_supports_validating_the_5_bit_Mode_of_the_READ_BUFFER_and_WRITE_BUFFER_commands { + get { + return ResourceManager.GetString("Drive_supports_validating_the_5_bit_Mode_of_the_READ_BUFFER_and_WRITE_BUFFER_comm" + + "ands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports VCPS. + /// + internal static string Drive_supports_VCPS { + get { + return ResourceManager.GetString("Drive_supports_VCPS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports write without verify requirement. + /// + internal static string Drive_supports_write_without_verify_requirement { + get { + return ResourceManager.GetString("Drive_supports_write_without_verify_requirement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing at {0} Kbyte/sec. in CLV mode. + /// + internal static string Drive_supports_writing_at_0_Kbyte_sec_in_CLV_mode { + get { + return ResourceManager.GetString("Drive_supports_writing_at_0_Kbyte_sec_in_CLV_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing at {0} Kbyte/sec. in pure CAV mode. + /// + internal static string Drive_supports_writing_at_is_0_Kbyte_sec_in_pure_CAV_mode { + get { + return ResourceManager.GetString("Drive_supports_writing_at_is_0_Kbyte_sec_in_pure_CAV_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing DDCD-R. + /// + internal static string Drive_supports_writing_DDCD_R { + get { + return ResourceManager.GetString("Drive_supports_writing_DDCD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing DDCD-RW. + /// + internal static string Drive_supports_writing_DDCD_RW { + get { + return ResourceManager.GetString("Drive_supports_writing_DDCD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing DVD-R. + /// + internal static string Drive_supports_writing_DVD_R { + get { + return ResourceManager.GetString("Drive_supports_writing_DVD_R", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing DVD-R and DVD-R DL. + /// + internal static string Drive_supports_writing_DVD_R_and_DVD_R_DL { + get { + return ResourceManager.GetString("Drive_supports_writing_DVD_R_and_DVD_R_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing DVD-R and DVD-RW. + /// + internal static string Drive_supports_writing_DVD_R_and_DVD_RW { + get { + return ResourceManager.GetString("Drive_supports_writing_DVD_R_and_DVD_RW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing DVD-R, DVD-RW and DVD-R DL. + /// + internal static string Drive_supports_writing_DVD_R_DVD_RW_and_DVD_R_DL { + get { + return ResourceManager.GetString("Drive_supports_writing_DVD_R_DVD_RW_and_DVD_R_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing on an intermediate state session and quick formatting. + /// + internal static string Drive_supports_writing_on_an_intermediate_state_session_and_quick_formatting { + get { + return ResourceManager.GetString("Drive_supports_writing_on_an_intermediate_state_session_and_quick_formatting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing the Write Inhibit DCB on DVD+RW media. + /// + internal static string Drive_supports_writing_the_Write_Inhibit_DCB_on_DVD_RW_media { + get { + return ResourceManager.GetString("Drive_supports_writing_the_Write_Inhibit_DCB_on_DVD_RW_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports writing with bus encryption. + /// + internal static string Drive_supports_writing_with_bus_encryption { + get { + return ResourceManager.GetString("Drive_supports_writing_with_bus_encryption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive supports zero loss linking. + /// + internal static string Drive_supports_zero_loss_linking { + get { + return ResourceManager.GetString("Drive_supports_zero_loss_linking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive's time is synchronized with a NTP source. + /// + internal static string Drive_time_is_synchronized_with_a_NTP_source { + get { + return ResourceManager.GetString("Drive_time_is_synchronized_with_a_NTP_source", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive's time is UTC. + /// + internal static string Drive_time_is_UTC { + get { + return ResourceManager.GetString("Drive_time_is_UTC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses a Fibre Channel interface. + /// + internal static string Drive_uses_a_Fibre_Channel_interface { + get { + return ResourceManager.GetString("Drive_uses_a_Fibre_Channel_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses a SCSI interface. + /// + internal static string Drive_uses_a_SCSI_interface { + get { + return ResourceManager.GetString("Drive_uses_a_SCSI_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses a Serial ATAPI interface. + /// + internal static string Drive_uses_a_Serial_ATAPI_interface { + get { + return ResourceManager.GetString("Drive_uses_a_Serial_ATAPI_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses a tray. + /// + internal static string Drive_uses_a_tray { + get { + return ResourceManager.GetString("Drive_uses_a_tray", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses a vendor unique interface. + /// + internal static string Drive_uses_a_vendor_unique_interface { + get { + return ResourceManager.GetString("Drive_uses_a_vendor_unique_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses an ATAPI interface. + /// + internal static string Drive_uses_an_ATAPI_interface { + get { + return ResourceManager.GetString("Drive_uses_an_ATAPI_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses an IEEE-1394 interface. + /// + internal static string Drive_uses_an_IEEE_1394_interface { + get { + return ResourceManager.GetString("Drive_uses_an_IEEE_1394_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses an IEEE-1394A interface. + /// + internal static string Drive_uses_an_IEEE_1394A_interface { + get { + return ResourceManager.GetString("Drive_uses_an_IEEE_1394A_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses an IEEE-1394B interface. + /// + internal static string Drive_uses_an_IEEE_1394B_interface { + get { + return ResourceManager.GetString("Drive_uses_an_IEEE_1394B_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses an unknown interface with code {0}. + /// + internal static string Drive_uses_an_unknown_interface_with_code_0 { + get { + return ResourceManager.GetString("Drive_uses_an_unknown_interface_with_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses an unspecified physical interface. + /// + internal static string Drive_uses_an_unspecified_physical_interface { + get { + return ResourceManager.GetString("Drive_uses_an_unspecified_physical_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses an USB interface. + /// + internal static string Drive_uses_an_USB_interface { + get { + return ResourceManager.GetString("Drive_uses_an_USB_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses default compression. + /// + internal static string Drive_uses_default_compression { + get { + return ResourceManager.GetString("Drive_uses_default_compression", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses media caddy. + /// + internal static string Drive_uses_media_caddy { + get { + return ResourceManager.GetString("Drive_uses_media_caddy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses unknown compression {0}. + /// + internal static string Drive_uses_unknown_compression_0 { + get { + return ResourceManager.GetString("Drive_uses_unknown_compression_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses unknown loading mechanism type {0}. + /// + internal static string Drive_uses_unknown_loading_mechanism_type__0_ { + get { + return ResourceManager.GetString("Drive_uses_unknown_loading_mechanism_type__0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will abort when a writing error is detected. + /// + internal static string Drive_will_abort_when_a_writing_error_is_detected { + get { + return ResourceManager.GetString("Drive_will_abort_when_a_writing_error_is_detected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will delay {0} ms before buffered data is forcefully written to the medium even before buffer is full. + /// + internal static string Drive_will_delay_0_ms_before_buffered_data_is_forcefully_written_to_the_medium_even_before_buffer_is_full { + get { + return ResourceManager.GetString("Drive_will_delay_0_ms_before_buffered_data_is_forcefully_written_to_the_medium_ev" + + "en_before_buffer_is_full", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will do nothing on WORM tampered medium. + /// + internal static string Drive_will_do_nothing_on_WORM_tampered_medium { + get { + return ResourceManager.GetString("Drive_will_do_nothing_on_WORM_tampered_medium", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will eject cleaning cartridges on error. + /// + internal static string Drive_will_eject_cleaning_cartridges_on_error { + get { + return ResourceManager.GetString("Drive_will_eject_cleaning_cartridges_on_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will eject data cartridges on error. + /// + internal static string Drive_will_eject_data_cartridges_on_error { + get { + return ResourceManager.GetString("Drive_will_eject_data_cartridges_on_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will eject firmware cartridges on error. + /// + internal static string Drive_will_eject_firmware_cartridges_on_error { + get { + return ResourceManager.GetString("Drive_will_eject_firmware_cartridges_on_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will employ a maximum of {0} ms to recover data. + /// + internal static string Drive_will_employ_a_maximum_of_0_ms_to_recover_data { + get { + return ResourceManager.GetString("Drive_will_employ_a_maximum_of_0_ms_to_recover_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will flush and position itself on a LUN or target reset. + /// + internal static string Drive_will_flush_and_position_itself_on_a_LUN_or_target_reset { + get { + return ResourceManager.GetString("Drive_will_flush_and_position_itself_on_a_LUN_or_target_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will maintain position on a LUN or target reset. + /// + internal static string Drive_will_maintain_position_on_a_LUN_or_target_reset { + get { + return ResourceManager.GetString("Drive_will_maintain_position_on_a_LUN_or_target_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will not accept downlevel firmware via an FMR tape. + /// + internal static string Drive_will_not_accept_downlevel_firmware_via_an_FMR_tape { + get { + return ResourceManager.GetString("Drive_will_not_accept_downlevel_firmware_via_an_FMR_tape", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will not exit emulation automatically. + /// + internal static string Drive_will_not_exit_emulation_automatically { + get { + return ResourceManager.GetString("Drive_will_not_exit_emulation_automatically", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will only record on the OSSC Disc Format. + /// + internal static string Drive_will_only_record_on_the_OSSC_Disc_Format { + get { + return ResourceManager.GetString("Drive_will_only_record_on_the_OSSC_Disc_Format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will only respond to commands if it has received a reservation. + /// + internal static string Drive_will_only_respond_to_commands_if_it_has_received_a_reservation { + get { + return ResourceManager.GetString("Drive_will_only_respond_to_commands_if_it_has_received_a_reservation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will periodically request cleaning. + /// + internal static string Drive_will_periodically_request_cleaning { + get { + return ResourceManager.GetString("Drive_will_periodically_request_cleaning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will pre-read until buffer is full. + /// + internal static string Drive_will_pre_read_until_buffer_is_full { + get { + return ResourceManager.GetString("Drive_will_pre_read_until_buffer_is_full", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will pre-read until one filemark is detected. + /// + internal static string Drive_will_pre_read_until_one_filemark_is_detected { + get { + return ResourceManager.GetString("Drive_will_pre_read_until_one_filemark_is_detected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will pre-read until three filemark is detected. + /// + internal static string Drive_will_pre_read_until_three_filemark_is_detected { + get { + return ResourceManager.GetString("Drive_will_pre_read_until_three_filemark_is_detected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will pre-read until two filemark is detected. + /// + internal static string Drive_will_pre_read_until_two_filemark_is_detected { + get { + return ResourceManager.GetString("Drive_will_pre_read_until_two_filemark_is_detected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 1 minute after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_1_minute_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_1_minute_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 1 second after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_1_second_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_1_second_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 125 ms after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_125_ms_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_125_ms_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 16 minutes after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_16_minutes_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_16_minutes_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 16 seconds after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_16_seconds_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_16_seconds_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 2 minutes after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_2_minutes_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_2_minutes_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 2 seconds after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_2_seconds_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_2_seconds_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 250 ms after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_250_ms_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_250_ms_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 32 minutes after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_32_minutes_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_32_minutes_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 32 seconds after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_32_seconds_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_32_seconds_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 4 minutes after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_4_minutes_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_4_minutes_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 4 seconds after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_4_seconds_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_4_seconds_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 500 ms after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_500_ms_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_500_ms_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 8 minutes after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_8_minutes_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_8_minutes_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status 8 seconds after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_8_seconds_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_8_seconds_after_a_seek_read_or_write_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in same status a vendor-specified time after a seek, read or write operation. + /// + internal static string Drive_will_remain_in_same_status_a_vendor_specified_time_after_a_seek_read_or_write_operation { + get { + return ResourceManager.GetString("Drive_will_remain_in_same_status_a_vendor_specified_time_after_a_seek_read_or_wri" + + "te_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 1 minute after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_1_minute_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_1_minute_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 1 second after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_1_second_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_1_second_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 125 ms after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_125_ms_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_125_ms_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 16 minutes after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_16_minutes_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_16_minutes_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 16 seconds after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_16_seconds_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_16_seconds_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 2 minutes after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_2_minutes_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_2_minutes_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 2 seconds after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_2_seconds_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_2_seconds_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 250 ms after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_250_ms_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_250_ms_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 32 minutes after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_32_minutes_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_32_minutes_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 32 seconds after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_32_seconds_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_32_seconds_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 4 minutes after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_4_minutes_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_4_minutes_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 4 seconds after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_4_seconds_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_4_seconds_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 500 ms after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_500_ms_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_500_ms_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 8 minutes after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_8_minutes_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_8_minutes_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state 8 seconds after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_8_seconds_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_8_seconds_after_a_seek_or_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will remain in track hold state a vendor-specified time after a seek or read. + /// + internal static string Drive_will_remain_in_track_hold_state_a_vendor_specified_time_after_a_seek_or_read { + get { + return ResourceManager.GetString("Drive_will_remain_in_track_hold_state_a_vendor_specified_time_after_a_seek_or_rea" + + "d", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will repeat read operations {0} times. + /// + internal static string Drive_will_repeat_read_operations_0_times { + get { + return ResourceManager.GetString("Drive_will_repeat_read_operations_0_times", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will repeat verify operations {0} times. + /// + internal static string Drive_will_repeat_verify_operations_0_times { + get { + return ResourceManager.GetString("Drive_will_repeat_verify_operations_0_times", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will repeat write operations {0} times. + /// + internal static string Drive_will_repeat_write_operations_0_times { + get { + return ResourceManager.GetString("Drive_will_repeat_write_operations_0_times", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will report background self-test errors. + /// + internal static string Drive_will_report_background_self_test_errors { + get { + return ResourceManager.GetString("Drive_will_report_background_self_test_errors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will respond to SCSI ID {0} on Port A enabling. + /// + internal static string Drive_will_respond_to_SCSI_ID_0_on_Port_A_enabling { + get { + return ResourceManager.GetString("Drive_will_respond_to_SCSI_ID_0_on_Port_A_enabling", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will return CHECK CONDITION on WORM tampered medium. + /// + internal static string Drive_will_return_CHECK_CONDITION_on_WORM_tampered_medium { + get { + return ResourceManager.GetString("Drive_will_return_CHECK_CONDITION_on_WORM_tampered_medium", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will return from playback command immediately. + /// + internal static string Drive_will_return_from_playback_command_immediately { + get { + return ResourceManager.GetString("Drive_will_return_from_playback_command_immediately", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will return from playback command when playback ends. + /// + internal static string Drive_will_return_from_playback_command_when_playback_ends { + get { + return ResourceManager.GetString("Drive_will_return_from_playback_command_when_playback_ends", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will set CHECK CONDITION when cleaning is needed. + /// + internal static string Drive_will_set_Check_Condition_when_cleaning_is_needed { + get { + return ResourceManager.GetString("Drive_will_set_Check_Condition_when_cleaning_is_needed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will set CHECK CONDITION when the criteria for Dead Media is met. + /// + internal static string Drive_will_set_Check_Condition_when_the_criteria_for_Dead_Media_is_met { + get { + return ResourceManager.GetString("Drive_will_set_Check_Condition_when_the_criteria_for_Dead_Media_is_met", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will stop playback on track end. + /// + internal static string Drive_will_stop_playback_on_track_end { + get { + return ResourceManager.GetString("Drive_will_stop_playback_on_track_end", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will synchronize buffer to medium on early warnings. + /// + internal static string Drive_will_synchronize_buffer_to_medium_on_early_warnings { + get { + return ResourceManager.GetString("Drive_will_synchronize_buffer_to_medium_on_early_warnings", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will transfer the entire requested length without delaying to perform error recovery. + /// + internal static string Drive_will_transfer_the_entire_requested_length_without_delaying_to_perform_error_recovery { + get { + return ResourceManager.GetString("Drive_will_transfer_the_entire_requested_length_without_delaying_to_perform_error" + + "_recovery", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive will use the most expedient form of error recovery first. + /// + internal static string Drive_will_use_the_most_expedient_form_of_error_recovery_first { + get { + return ResourceManager.GetString("Drive_will_use_the_most_expedient_form_of_error_recovery_first", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DSN feature set is supported. + /// + internal static string DSN_feature_set_is_supported { + get { + return ResourceManager.GetString("DSN_feature_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DSN feature set is supported and enabled. + /// + internal static string DSN_feature_set_is_supported_and_enabled { + get { + return ResourceManager.GetString("DSN_feature_set_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DT1825 is supported. + /// + internal static string DT1825_is_supported { + get { + return ResourceManager.GetString("DT1825_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DT1825 is supported and enabled. + /// + internal static string DT1825_is_supported_and_enabled { + get { + return ResourceManager.GetString("DT1825_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dye is organic. + /// + internal static string Dye_is_organic { + get { + return ResourceManager.GetString("Dye_is_organic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dye is phase change. + /// + internal static string Dye_is_phase_change { + get { + return ResourceManager.GetString("Dye_is_phase_change", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Each channel can be muted independently. + /// + internal static string Each_channel_can_be_muted_independently { + get { + return ResourceManager.GetString("Each_channel_can_be_muted_independently", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Each channel's volume can be controlled independently. + /// + internal static string Each_channel_s_volume_can_be_controlled_independently { + get { + return ResourceManager.GetString("Each_channel_s_volume_can_be_controlled_independently", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Each minute has {0} seconds. + /// + internal static string Each_minute_has_0_seconds { + get { + return ResourceManager.GetString("Each_minute_has_0_seconds", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Each second has {0} frames. + /// + internal static string Each_second_has_0_frames { + get { + return ResourceManager.GetString("Each_second_has_0_frames", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Each step pulse is {0} ms. + /// + internal static string Each_step_pulse_is_0_ms { + get { + return ResourceManager.GetString("Each_step_pulse_is_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA TC17: 8 mm Magnetic Tape Cassette, 1789 bpmm, RLL. + /// + internal static string ECMA_TC17 { + get { + return ResourceManager.GetString("ECMA_TC17", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-46 & ANSI X3.56-1986: 6.30 mm Magnetic Tape Cartridge, Phase Encoding, 63 bpmm. + /// + internal static string ECMA46 { + get { + return ResourceManager.GetString("ECMA46", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-62 & ANSI X3.22-1983: 12.7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZI, 32 cpmm. + /// + internal static string ECMA62 { + get { + return ResourceManager.GetString("ECMA62", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-62 & ANSI X3.54-1986: 12.7 mm 9-Track Magnetic Tape, 356 ftpmm, NRZI, 245 cpmm GCR. + /// + internal static string ECMA62_GCR { + get { + return ResourceManager.GetString("ECMA62_GCR", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-62 & ANSI X3.39-1986: 12.7 mm 9-Track Magnetic Tape, 126 ftpmm, Phase Encoding, 63 cpmm. + /// + internal static string ECMA62_Phase { + get { + return ResourceManager.GetString("ECMA62_Phase", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-79 & ANSI X3.116-1986: 6.30 mm Magnetic Tape Cartridge, 252 ftpmm, MFM. + /// + internal static string ECMA79 { + get { + return ResourceManager.GetString("ECMA79", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-98: 6.30 mm Magnetic Tape Cartridge, NRZI, 394 ftpmm. + /// + internal static string ECMA98 { + get { + return ResourceManager.GetString("ECMA98", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EEPROM format version: {0}.{1}. + /// + internal static string EEPROM_format_version_0_1 { + get { + return ResourceManager.GetString("EEPROM_format_version_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enclosure services device. + /// + internal static string Enclosure_services_device { + get { + return ResourceManager.GetString("Enclosure_services_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to End of file.. + /// + internal static string End_of_file { + get { + return ResourceManager.GetString("End_of_file", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to End-of-medium/partition found. + /// + internal static string End_of_medium_partition_found { + get { + return ResourceManager.GetString("End_of_medium_partition_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to End of record.. + /// + internal static string End_of_record { + get { + return ResourceManager.GetString("End_of_record", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ending time for interval that should be skipped: {0:D2}:{1:D2}:{2:D2}. + /// + internal static string Ending_time_for_interval_that_should_be_skipped_0_1_2 { + get { + return ResourceManager.GetString("Ending_time_for_interval_that_should_be_skipped_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Epilogue {0:X2}{1:X2}{2:X2}. + /// + internal static string Epilogue_0_1_2 { + get { + return ResourceManager.GetString("Epilogue_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Erase block: {0} bytes. + /// + internal static string Erase_block_0_bytes { + get { + return ResourceManager.GetString("Erase_block_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Erased memory range shall be '{0}'.. + /// + internal static string Erased_memory_range_shall_be_0 { + get { + return ResourceManager.GetString("Erased_memory_range_shall_be_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Erasing power ratio is not specified. + /// + internal static string Erasing_power_ratio_is_not_specified { + get { + return ResourceManager.GetString("Erasing_power_ratio_is_not_specified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error class {0} type {1}. + /// + internal static string Error_class_0_type_1 { + get { + return ResourceManager.GetString("Error_class_0_type_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error class {0} type {1} happened on block {2}. + /// + internal static string Error_class_0_type_1_happened_on_block_2 { + get { + return ResourceManager.GetString("Error_class_0_type_1_happened_on_block_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error correction is disabled. + /// + internal static string Error_correction_is_disabled { + get { + return ResourceManager.GetString("Error_correction_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Europe PAL.. + /// + internal static string Europe_PAL { + get { + return ResourceManager.GetString("Europe_PAL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EXB-8200. + /// + internal static string EXB8200 { + get { + return ResourceManager.GetString("EXB8200", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EXB-8200 compressed. + /// + internal static string EXB8200_compressed { + get { + return ResourceManager.GetString("EXB8200_compressed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EXB-8500. + /// + internal static string EXB8500 { + get { + return ResourceManager.GetString("EXB8500", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EXB-8500 compressed. + /// + internal static string EXB8500_compressed { + get { + return ResourceManager.GetString("EXB8500_compressed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected CD ATIP size (32 bytes) is not received size ({0} bytes), not decoding. + /// + internal static string Expected_CD_ATIP_size_32_bytes_is_not_received_size_0_bytes_not_decoding { + get { + return ResourceManager.GetString("Expected_CD_ATIP_size_32_bytes_is_not_received_size_0_bytes_not_decoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected CD PMA size ({0} bytes) is not received size ({1} bytes), not decoding. + /// + internal static string Expected_CD_PMA_size_0_bytes_is_not_received_size_1_bytes_not_decoding { + get { + return ResourceManager.GetString("Expected_CD_PMA_size_0_bytes_is_not_received_size_1_bytes_not_decoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected CD-TEXT size ({0} bytes) is not received size ({1} bytes), not decoding. + /// + internal static string Expected_CD_TEXT_size_0_bytes_is_not_received_size_1_bytes_not_decoding { + get { + return ResourceManager.GetString("Expected_CD_TEXT_size_0_bytes_is_not_received_size_1_bytes_not_decoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected CD TOC size ({0} bytes) is not received size ({1} bytes), not decoding. + /// + internal static string Expected_CD_TOC_size_0_bytes_is_not_received_size_1_bytes_not_decoding { + get { + return ResourceManager.GetString("Expected_CD_TOC_size_0_bytes_is_not_received_size_1_bytes_not_decoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected CDFullTOC size ({0} bytes) is not received size ({1} bytes), not decoding. + /// + internal static string Expected_CDFullTOC_size_0_bytes_is_not_received_size_1_bytes_not_decoding { + get { + return ResourceManager.GetString("Expected_CDFullTOC_size_0_bytes_is_not_received_size_1_bytes_not_decoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected CDSessionInfo size ({0} bytes) is not received size ({1} bytes), not decoding. + /// + internal static string Expected_CDSessionInfo_size_0_bytes_is_not_received_size_1_bytes_not_decoding { + get { + return ResourceManager.GetString("Expected_CDSessionInfo_size_0_bytes_is_not_received_size_1_bytes_not_decoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extended Contingent Allegiance is enabled. + /// + internal static string Extended_Contingent_Allegiance_is_enabled { + get { + return ResourceManager.GetString("Extended_Contingent_Allegiance_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extended Power Conditions are supported. + /// + internal static string Extended_Power_Conditions_are_supported { + get { + return ResourceManager.GetString("Extended_Power_Conditions_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extended Power Conditions are supported and enabled. + /// + internal static string Extended_Power_Conditions_are_supported_and_enabled { + get { + return ResourceManager.GetString("Extended_Power_Conditions_are_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extended self-test takes {0} to complete. + /// + internal static string Extended_self_test_takes_0_to_complete { + get { + return ResourceManager.GetString("Extended_self_test_takes_0_to_complete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extended Status Reporting is supported. + /// + internal static string Extended_Status_Reporting_is_supported { + get { + return ResourceManager.GetString("Extended_Status_Reporting_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extended Status Reporting is supported and enabled. + /// + internal static string Extended_Status_Reporting_is_supported_and_enabled { + get { + return ResourceManager.GetString("Extended_Status_Reporting_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extent starts at PSN {0:X6}h and ends at PSN {1:X6}h. + /// + internal static string Extent_starts_at_PSN_0_and_ends_at_PSN_1 { + get { + return ResourceManager.GetString("Extent_starts_at_PSN_0_and_ends_at_PSN_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Factory test code 1 is disabled. + /// + internal static string Factory_test_code_1_is_disabled { + get { + return ResourceManager.GetString("Factory_test_code_1_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Factory test code 2 is disabled. + /// + internal static string Factory_test_code_2_is_disabled { + get { + return ResourceManager.GetString("Factory_test_code_2_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Factory test code is disabled. + /// + internal static string Factory_test_code_is_disabled { + get { + return ResourceManager.GetString("Factory_test_code_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can eject media. + /// + internal static string Features_Prettify_0003_Drive_can_eject_media { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_can_eject_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can load media. + /// + internal static string Features_Prettify_0003_Drive_can_load_media { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_can_load_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can lock media. + /// + internal static string Features_Prettify_0003_Drive_can_lock_media { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_can_lock_media", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is a changer using cartridges. + /// + internal static string Features_Prettify_0003_Drive_is_a_changer_using_cartridges { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_is_a_changer_using_cartridges", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is a changer with individually changeable discs. + /// + internal static string Features_Prettify_0003_Drive_is_a_changer_with_individually_changeable_discs { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_is_a_changer_with_individually_changeable_discs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is pop-up. + /// + internal static string Features_Prettify_0003_Drive_is_pop_up { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_is_pop_up", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive power ups locked. + /// + internal static string Features_Prettify_0003_Drive_power_ups_locked { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_power_ups_locked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive reports Device Busy Class events during medium loading/unloading. + /// + internal static string Features_Prettify_0003_Drive_reports_Device_Busy_Class_events_during_medium_loading_unloading { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_reports_Device_Busy_Class_events_during_medium_loadi" + + "ng_unloading", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses a tray. + /// + internal static string Features_Prettify_0003_Drive_uses_a_tray { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_uses_a_tray", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses media caddy. + /// + internal static string Features_Prettify_0003_Drive_uses_media_caddy { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_uses_media_caddy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive uses unknown loading mechanism type {0}. + /// + internal static string Features_Prettify_0003_Drive_uses_unknown_loading_mechanism_type_0 { + get { + return ResourceManager.GetString("Features_Prettify_0003_Drive_uses_unknown_loading_mechanism_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Removable Medium:. + /// + internal static string Features_Prettify_0003_MMC_Removable_Medium { + get { + return ResourceManager.GetString("Features_Prettify_0003_MMC_Removable_Medium", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive can read DVD+R DL. + /// + internal static string Features_Prettify_003B_Drive_can_read_DVD_Plus_R_DL { + get { + return ResourceManager.GetString("Features_Prettify_003B_Drive_can_read_DVD_Plus_R_DL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive is able to detect and report defective writable unit and behave accordingly. + /// + internal static string Features_Prettify_0042_Drive_is_able_to_detect_and_report_defective_writable_unit_and_behave_accordingly { + get { + return ResourceManager.GetString("Features_Prettify_0042_Drive_is_able_to_detect_and_report_defective_writable_unit" + + "_and_behave_accordingly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fence behaviour is normal. + /// + internal static string Fence_behaviour_is_normal { + get { + return ResourceManager.GetString("Fence_behaviour_is_normal", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fibre Channel. + /// + internal static string Fibre_Channel { + get { + return ResourceManager.GetString("Fibre_Channel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File number: {0}. + /// + internal static string File_number_0 { + get { + return ResourceManager.GetString("File_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filemark or setmark found. + /// + internal static string Filemark_or_setmark_found { + get { + return ResourceManager.GetString("Filemark_or_setmark_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Finished sector at {0}. + /// + internal static string Finished_sector_at_0 { + get { + return ResourceManager.GetString("Finished_sector_at_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Firmware cartridge inserted. + /// + internal static string Firmware_cartridge_inserted { + get { + return ResourceManager.GetString("Firmware_cartridge_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Firmware personality: {0}. + /// + internal static string Firmware_personality_0 { + get { + return ResourceManager.GetString("Firmware_personality_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Firmware sub-personality: {0}. + /// + internal static string Firmware_sub_personality_0 { + get { + return ResourceManager.GetString("Firmware_sub_personality_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Firmware updates are permanently disabled. + /// + internal static string Firmware_updates_are_permanently_disabled { + get { + return ResourceManager.GetString("Firmware_updates_are_permanently_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Firmware version: {0}. + /// + internal static string Firmware_version_0 { + get { + return ResourceManager.GetString("Firmware_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Firmware version: {0}.{1}. + /// + internal static string Firmware_version_0_1 { + get { + return ResourceManager.GetString("Firmware_version_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First address unit number of data zone in this layer: {0}. + /// + internal static string First_address_unit_number_of_data_zone_in_this_layer_0 { + get { + return ResourceManager.GetString("First_address_unit_number_of_data_zone_in_this_layer_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First complete session number: {0}. + /// + internal static string First_complete_session_number_0 { + get { + return ResourceManager.GetString("First_complete_session_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First PSN of Defect List: 0x{0:X8}. + /// + internal static string First_PSN_of_Defect_List_0 { + get { + return ResourceManager.GetString("First_PSN_of_Defect_List_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First PSN of Drive Area: 0x{0:X8}. + /// + internal static string First_PSN_of_Drive_Area_0 { + get { + return ResourceManager.GetString("First_PSN_of_Drive_Area_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First run-in block. + /// + internal static string First_run_in_block { + get { + return ResourceManager.GetString("First_run_in_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First run-out block. + /// + internal static string First_run_out_block { + get { + return ResourceManager.GetString("First_run_out_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First track in last session is track {0}. + /// + internal static string First_track_in_last_session_is_track_0 { + get { + return ResourceManager.GetString("First_track_in_last_session_is_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First track number: {0} (. + /// + internal static string First_track_number_0_open_parenthesis { + get { + return ResourceManager.GetString("First_track_number_0_open_parenthesis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First track number in first complete session: {0}. + /// + internal static string First_track_number_in_first_complete_session_0 { + get { + return ResourceManager.GetString("First_track_number_in_first_complete_session_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First track number in last complete session: {0}. + /// + internal static string First_track_number_in_last_complete_session_0 { + get { + return ResourceManager.GetString("First_track_number_in_last_complete_session_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First track on disc is track {0}. + /// + internal static string First_track_on_disc_is_track_0 { + get { + return ResourceManager.GetString("First_track_on_disc_is_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First video track number: {0}. + /// + internal static string First_video_track_number_0 { + get { + return ResourceManager.GetString("First_video_track_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FLUSH CACHE EXT is supported. + /// + internal static string FLUSH_CACHE_EXT_is_supported { + get { + return ResourceManager.GetString("FLUSH_CACHE_EXT_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FLUSH CACHE EXT is supported and enabled. + /// + internal static string FLUSH_CACHE_EXT_is_supported_and_enabled { + get { + return ResourceManager.GetString("FLUSH_CACHE_EXT_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FLUSH CACHE is supported. + /// + internal static string FLUSH_CACHE_is_supported { + get { + return ResourceManager.GetString("FLUSH_CACHE_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FLUSH CACHE is supported and enabled. + /// + internal static string FLUSH_CACHE_is_supported_and_enabled { + get { + return ResourceManager.GetString("FLUSH_CACHE_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Form 1.. + /// + internal static string Form_1 { + get { + return ResourceManager.GetString("Form_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Form 2.. + /// + internal static string Form_2 { + get { + return ResourceManager.GetString("Form_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Format progress {0:P}. + /// + internal static string Format_progress_0 { + get { + return ResourceManager.GetString("Format_progress_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Format speed tolerance gap is required. + /// + internal static string Format_speed_tolerance_gap_is_required { + get { + return ResourceManager.GetString("Format_speed_tolerance_gap_is_required", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Formatting in progress.. + /// + internal static string Formatting_in_progress { + get { + return ResourceManager.GetString("Formatting_in_progress", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Formatting is only using partial certification. + /// + internal static string Formatting_is_only_using_partial_certification { + get { + return ResourceManager.GetString("Formatting_is_only_using_partial_certification", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found incorrect Blu-ray BCA size ({0} bytes). + /// + internal static string Found_incorrect_Blu_ray_BCA_size_0_bytes { + get { + return ResourceManager.GetString("Found_incorrect_Blu_ray_BCA_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found incorrect Blu-ray Cartridge Status size ({0} bytes). + /// + internal static string Found_incorrect_Blu_ray_Cartridge_Status_size_0_bytes { + get { + return ResourceManager.GetString("Found_incorrect_Blu_ray_Cartridge_Status_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found incorrect Blu-ray Disc Information size ({0} bytes). + /// + internal static string Found_incorrect_Blu_ray_Disc_Information_size_0_bytes { + get { + return ResourceManager.GetString("Found_incorrect_Blu_ray_Disc_Information_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found incorrect DDS signature (0x{0:X4}). + /// + internal static string Found_incorrect_DDS_signature_0 { + get { + return ResourceManager.GetString("Found_incorrect_DDS_signature_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found unknown disc type identifier "{0}". + /// + internal static string Found_unknown_disc_type_identifier_0 { + get { + return ResourceManager.GetString("Found_unknown_disc_type_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fourth run-in block. + /// + internal static string Fourth_run_in_block { + get { + return ResourceManager.GetString("Fourth_run_in_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Free-fall control feature set is supported. + /// + internal static string Free_fall_control_feature_set_is_supported { + get { + return ResourceManager.GetString("Free_fall_control_feature_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Free-fall control feature set is supported and enabled. + /// + internal static string Free_fall_control_feature_set_is_supported_and_enabled { + get { + return ResourceManager.GetString("Free_fall_control_feature_set_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Free-fall sensitivity set to {0}. + /// + internal static string Free_fall_sensitivity_set_to_0 { + get { + return ResourceManager.GetString("Free_fall_sensitivity_set_to_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fujitsu Verify Control Page:. + /// + internal static string Fujitsu_Verify_Control_Page { + get { + return ResourceManager.GetString("Fujitsu_Verify_Control_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires A + B + Start buttons and D-Pad.. + /// + internal static string Game_requires_A_B_Start_buttons_and_D_Pad { + get { + return ResourceManager.GetString("Game_requires_A_B_Start_buttons_and_D_Pad", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires analog horizontal controller.. + /// + internal static string Game_requires_analog_horizontal_controller { + get { + return ResourceManager.GetString("Game_requires_analog_horizontal_controller", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires analog L trigger.. + /// + internal static string Game_requires_analog_L_trigger { + get { + return ResourceManager.GetString("Game_requires_analog_L_trigger", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires analog R trigger.. + /// + internal static string Game_requires_analog_R_trigger { + get { + return ResourceManager.GetString("Game_requires_analog_R_trigger", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires analog vertical controller.. + /// + internal static string Game_requires_analog_vertical_controller { + get { + return ResourceManager.GetString("Game_requires_analog_vertical_controller", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires C button.. + /// + internal static string Game_requires_C_button { + get { + return ResourceManager.GetString("Game_requires_C_button", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires D button.. + /// + internal static string Game_requires_D_button { + get { + return ResourceManager.GetString("Game_requires_D_button", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires expanded analog horizontal controller.. + /// + internal static string Game_requires_expanded_analog_horizontal_controller { + get { + return ResourceManager.GetString("Game_requires_expanded_analog_horizontal_controller", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires expanded analog vertical controller.. + /// + internal static string Game_requires_expanded_analog_vertical_controller { + get { + return ResourceManager.GetString("Game_requires_expanded_analog_vertical_controller", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires expanded direction buttons.. + /// + internal static string Game_requires_expanded_direction_buttons { + get { + return ResourceManager.GetString("Game_requires_expanded_direction_buttons", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires X button.. + /// + internal static string Game_requires_X_button { + get { + return ResourceManager.GetString("Game_requires_X_button", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires Y button.. + /// + internal static string Game_requires_Y_button { + get { + return ResourceManager.GetString("Game_requires_Y_button", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game requires Z button.. + /// + internal static string Game_requires_Z_button { + get { + return ResourceManager.GetString("Game_requires_Z_button", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports analog controller.. + /// + internal static string Game_supports_analog_controller { + get { + return ResourceManager.GetString("Game_supports_analog_controller", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports analog steering controller.. + /// + internal static string Game_supports_analog_steering_controller { + get { + return ResourceManager.GetString("Game_supports_analog_steering_controller", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports Gun.. + /// + internal static string Game_supports_Gun { + get { + return ResourceManager.GetString("Game_supports_Gun", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports JoyPad.. + /// + internal static string Game_supports_JoyPad { + get { + return ResourceManager.GetString("Game_supports_JoyPad", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports Keyboard.. + /// + internal static string Game_supports_keyboard { + get { + return ResourceManager.GetString("Game_supports_keyboard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports light gun.. + /// + internal static string Game_supports_light_gun { + get { + return ResourceManager.GetString("Game_supports_light_gun", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports Master System's JoyPad.. + /// + internal static string Game_supports_Master_System_JoyPad { + get { + return ResourceManager.GetString("Game_supports_Master_System_JoyPad", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports Memory Card.. + /// + internal static string Game_supports_Memory_Card { + get { + return ResourceManager.GetString("Game_supports_Memory_Card", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports Mike Device.. + /// + internal static string Game_supports_Mike_Device { + get { + return ResourceManager.GetString("Game_supports_Mike_Device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports Mouse.. + /// + internal static string Game_supports_mouse { + get { + return ResourceManager.GetString("Game_supports_mouse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports multitap.. + /// + internal static string Game_supports_multitap { + get { + return ResourceManager.GetString("Game_supports_multitap", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports other expansion.. + /// + internal static string Game_supports_other_expansion { + get { + return ResourceManager.GetString("Game_supports_other_expansion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports paddle controller.. + /// + internal static string Game_supports_paddle_controller { + get { + return ResourceManager.GetString("Game_supports_paddle_controller", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports printer interface.. + /// + internal static string Game_supports_printer_interface { + get { + return ResourceManager.GetString("Game_supports_printer_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports Puru Puru pack.. + /// + internal static string Game_supports_Puru_Puru_pack { + get { + return ResourceManager.GetString("Game_supports_Puru_Puru_pack", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports serial (RS-232C) interface.. + /// + internal static string Game_supports_serial_RS_232C_interface { + get { + return ResourceManager.GetString("Game_supports_serial_RS_232C_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports tablet interface.. + /// + internal static string Game_supports_tablet_interface { + get { + return ResourceManager.GetString("Game_supports_tablet_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports the VGA Box.. + /// + internal static string Game_supports_the_VGA_Box { + get { + return ResourceManager.GetString("Game_supports_the_VGA_Box", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports trackball.. + /// + internal static string Game_supports_trackball { + get { + return ResourceManager.GetString("Game_supports_trackball", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports unknown peripheral {0}.. + /// + internal static string Game_supports_unknown_peripheral_0 { + get { + return ResourceManager.GetString("Game_supports_unknown_peripheral_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports unknown peripherals mask {0:X2}. + /// + internal static string Game_supports_unknown_peripherals_mask_0 { + get { + return ResourceManager.GetString("Game_supports_unknown_peripherals_mask_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game supports unknown region {0}.. + /// + internal static string Game_supports_unknown_region_0 { + get { + return ResourceManager.GetString("Game_supports_unknown_region_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game uses Windows CE.. + /// + internal static string Game_uses_Windows_CE { + get { + return ResourceManager.GetString("Game_uses_Windows_CE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to General purpose disc for use in general purpose drives. + /// + internal static string General_purpose_disc_for_use_in_general_purpose_drives { + get { + return ResourceManager.GetString("General_purpose_disc_for_use_in_general_purpose_drives", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to General Purpose Logging is supported. + /// + internal static string General_Purpose_Logging_is_supported { + get { + return ResourceManager.GetString("General_Purpose_Logging_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to General Purpose Logging is supported and enabled. + /// + internal static string General_Purpose_Logging_is_supported_and_enabled { + get { + return ResourceManager.GetString("General_Purpose_Logging_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Generate no sense on informational exceptions. + /// + internal static string Generate_no_sense_on_informational_exceptions { + get { + return ResourceManager.GetString("Generate_no_sense_on_informational_exceptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Generate unit attention on informational exceptions. + /// + internal static string Generate_unit_attention_on_informational_exceptions { + get { + return ResourceManager.GetString("Generate_unit_attention_on_informational_exceptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Geometry:. + /// + internal static string Geometry { + get { + return ResourceManager.GetString("Geometry", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to a direct-overwrite optical. + /// + internal static string GetMediumTypeDescription_DOW { + get { + return ResourceManager.GetString("GetMediumTypeDescription_DOW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-100 & ANSI X3.137: 90 mm Flexible Disk Cartridge using MFM Recording at 7859 ftprad on Both Sides; 5.3 Tracks per mm. + /// + internal static string GetMediumTypeDescription_ECMA_100 { + get { + return ResourceManager.GetString("GetMediumTypeDescription_ECMA_100", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-54: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on One Side. + /// + internal static string GetMediumTypeDescription_ECMA_54 { + get { + return ResourceManager.GetString("GetMediumTypeDescription_ECMA_54", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-59 & ANSI X3.121-1984: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on Both Sides. + /// + internal static string GetMediumTypeDescription_ECMA_59 { + get { + return ResourceManager.GetString("GetMediumTypeDescription_ECMA_59", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-66: 130 mm Flexible Disk Cartridge using Two-Frequency Recording at 7958 ftprad on One Side. + /// + internal static string GetMediumTypeDescription_ECMA_66 { + get { + return ResourceManager.GetString("GetMediumTypeDescription_ECMA_66", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-69: 200 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides. + /// + internal static string GetMediumTypeDescription_ECMA_69 { + get { + return ResourceManager.GetString("GetMediumTypeDescription_ECMA_69", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-70 & ANSI X3.125-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 1.9 Tracks per mm. + /// + internal static string GetMediumTypeDescription_ECMA_70 { + get { + return ResourceManager.GetString("GetMediumTypeDescription_ECMA_70", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-78 & ANSI X3.126-1986: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 3.8 Tracks per mm. + /// + internal static string GetMediumTypeDescription_ECMA_78 { + get { + return ResourceManager.GetString("GetMediumTypeDescription_ECMA_78", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-99 & ISO 8630-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides; 3.8 Tracks per mm. + /// + internal static string GetMediumTypeDescription_ECMA_99 { + get { + return ResourceManager.GetString("GetMediumTypeDescription_ECMA_99", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to a Erasable optical. + /// + internal static string GetMediumTypeDescription_Erasable { + get { + return ResourceManager.GetString("GetMediumTypeDescription_Erasable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 3.5-inch, 135 tpi, 15916 bits/radian, double-sided MFM (aka 1.44Mb). + /// + internal static string GetMediumTypeDescription_HDFloppy { + get { + return ResourceManager.GetString("GetMediumTypeDescription_HDFloppy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to a Sony Hi-MD disc. + /// + internal static string GetMediumTypeDescription_HiMD { + get { + return ResourceManager.GetString("GetMediumTypeDescription_HiMD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to a Read-only optical. + /// + internal static string GetMediumTypeDescription_ReadOnly { + get { + return ResourceManager.GetString("GetMediumTypeDescription_ReadOnly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to a combination of read-only and write-once optical. + /// + internal static string GetMediumTypeDescription_RO_WORM { + get { + return ResourceManager.GetString("GetMediumTypeDescription_RO_WORM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 3.5-inch, 135 tpi, 12362 bits/radian, double-sided MFM (aka 1.25Mb). + /// + internal static string GetMediumTypeDescription_Type3Floppy { + get { + return ResourceManager.GetString("GetMediumTypeDescription_Type3Floppy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to a Write-once Read-many optical. + /// + internal static string GetMediumTypeDescription_WORM { + get { + return ResourceManager.GetString("GetMediumTypeDescription_WORM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.73-1980: 200 mm, 6631 ftprad, 1.9 Tracks per mm, 1 side. + /// + internal static string GetMediumTypeDescription_X3_73 { + get { + return ResourceManager.GetString("GetMediumTypeDescription_X3_73", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.73-1980: 200 mm, 6631 ftprad, 1.9 Tracks per mm, 2 sides. + /// + internal static string GetMediumTypeDescription_X3_73_DS { + get { + return ResourceManager.GetString("GetMediumTypeDescription_X3_73_DS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.80-1980: 130 mm, 3979 ftprad, 1.9 Tracks per mm, 1 side. + /// + internal static string GetMediumTypeDescription_X3_82 { + get { + return ResourceManager.GetString("GetMediumTypeDescription_X3_82", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Global logging target save disabled. + /// + internal static string Global_logging_target_save_disabled { + get { + return ResourceManager.GetString("Global_logging_target_save_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Got {0} bytes of gap. + /// + internal static string Got_0_bytes_of_gap { + get { + return ResourceManager.GetString("Got_0_bytes_of_gap", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Graphics arts pre-press device (defined in ASC IT8). + /// + internal static string Graphics_arts_pre_press_device_defined_in_ASC_IT8 { + get { + return ResourceManager.GetString("Graphics_arts_pre_press_device_defined_in_ASC_IT8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Group {0} has been certified by an user. + /// + internal static string Group_0_has_been_certified_by_an_user { + get { + return ResourceManager.GetString("Group_0_has_been_certified_by_an_user", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Group {0} is being certified partially. + /// + internal static string Group_0_is_being_certified_partially { + get { + return ResourceManager.GetString("Group_0_is_being_certified_partially", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Group {0} is being formatted. + /// + internal static string Group_0_is_being_formatted { + get { + return ResourceManager.GetString("Group_0_is_being_formatted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hardware Feature Control is supported. + /// + internal static string Hardware_Feature_Control_is_supported { + get { + return ResourceManager.GetString("Hardware_Feature_Control_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hardware Feature Control is supported and enabled. + /// + internal static string Hardware_Feature_Control_is_supported_and_enabled { + get { + return ResourceManager.GetString("Hardware_Feature_Control_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hardware ID: {0}. + /// + internal static string Hardware_ID_0 { + get { + return ResourceManager.GetString("Hardware_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Head switch time is bigger than 15 µs.. + /// + internal static string Head_switch_time_is_bigger_than_15_µs { + get { + return ResourceManager.GetString("Head_switch_time_is_bigger_than_15_µs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Head takes {0} ms to load. + /// + internal static string Head_takes_0_ms_to_load { + get { + return ResourceManager.GetString("Head_takes_0_ms_to_load", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Head takes {0} ms to unload. + /// + internal static string Head_takes_0_ms_to_unload { + get { + return ResourceManager.GetString("Head_takes_0_ms_to_unload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Heads: {0}. + /// + internal static string Heads_0 { + get { + return ResourceManager.GetString("Heads_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Heads: {0} max., {1} current. + /// + internal static string Heads_0_max_1_current { + get { + return ResourceManager.GetString("Heads_0_max_1_current", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Heads park in cylinder {0}. + /// + internal static string Heads_park_in_cylinder_0 { + get { + return ResourceManager.GetString("Heads_park_in_cylinder_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Heads settles in {0} μs. + /// + internal static string Heads_settles_in_0_μs { + get { + return ResourceManager.GetString("Heads_settles_in_0_μs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hi-MD device.. + /// + internal static string Hi_MD_device_ { + get { + return ResourceManager.GetString("Hi_MD_device_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hi-MD specific bytes 44 to 55. + /// + internal static string Hi_MD_specific_bytes_44_to_55 { + get { + return ResourceManager.GetString("Hi_MD_specific_bytes_44_to_55", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HI-TC1: 12.7 mm 24-Track Magnetic Tape Cartridge, 500 bpmm, GCR. + /// + internal static string HiTC1 { + get { + return ResourceManager.GetString("HiTC1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HI-TC2: 12.7 mm 24-Track Magnetic Tape Cartridge, 999 bpmm, GCR. + /// + internal static string HiTC2 { + get { + return ResourceManager.GetString("HiTC2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Host managed zoned block device. + /// + internal static string Host_managed_zoned_block_device { + get { + return ResourceManager.GetString("Host_managed_zoned_block_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Host Protected Area is supported. + /// + internal static string Host_Protected_Area_is_supported { + get { + return ResourceManager.GetString("Host_Protected_Area_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Host Protected Area is supported and enabled. + /// + internal static string Host_Protected_Area_is_supported_and_enabled { + get { + return ResourceManager.GetString("Host_Protected_Area_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How should tapes be unloaded in a power cycle, tape incompatibility, firmware download or cleaning end: . + /// + internal static string How_should_tapes_be_unloaded_in_a_power_cycle_tape_incompatibility_firmware_download_or_cleaning_end { + get { + return ResourceManager.GetString("How_should_tapes_be_unloaded_in_a_power_cycle_tape_incompatibility_firmware_downl" + + "oad_or_cleaning_end", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP CD-ROM Emulation/Disaster Recovery Mode Page:. + /// + internal static string HP_CD_ROM_Emulation_Disaster_Recovery_Mode_Page { + get { + return ResourceManager.GetString("HP_CD_ROM_Emulation_Disaster_Recovery_Mode_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Device Time Mode Page:. + /// + internal static string HP_Device_Time_Mode_Page { + get { + return ResourceManager.GetString("HP_Device_Time_Mode_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Drive ACI Revision Levels page:. + /// + internal static string HP_Drive_ACI_Revision_Levels_page { + get { + return ResourceManager.GetString("HP_Drive_ACI_Revision_Levels_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Drive Firmware Revision Levels page:. + /// + internal static string HP_Drive_Firmware_Revision_Levels_page { + get { + return ResourceManager.GetString("HP_Drive_Firmware_Revision_Levels_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Drive Hardware Revision Levels page:. + /// + internal static string HP_Drive_Hardware_Revision_Levels_page { + get { + return ResourceManager.GetString("HP_Drive_Hardware_Revision_Levels_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Drive Head Assembly Revision Levels page:. + /// + internal static string HP_Drive_Head_Assembly_Revision_Levels_page { + get { + return ResourceManager.GetString("HP_Drive_Head_Assembly_Revision_Levels_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Drive Mechanism Revision Levels page:. + /// + internal static string HP_Drive_Mechanism_Revision_Levels_page { + get { + return ResourceManager.GetString("HP_Drive_Mechanism_Revision_Levels_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Drive PCA Revision Levels page:. + /// + internal static string HP_Drive_PCA_Revision_Levels_page { + get { + return ResourceManager.GetString("HP_Drive_PCA_Revision_Levels_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Extended Reset Mode Page:. + /// + internal static string HP_Extended_Reset_Mode_Page { + get { + return ResourceManager.GetString("HP_Extended_Reset_Mode_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Serial Number Override Mode Page:. + /// + internal static string HP_Serial_Number_Override_Mode_Page { + get { + return ResourceManager.GetString("HP_Serial_Number_Override_Mode_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP vendor-specific information:. + /// + internal static string HP_vendor_specific_information { + get { + return ResourceManager.GetString("HP_vendor_specific_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM ALDC with 1024 byte buffer. + /// + internal static string IBM_ALDC_with_1024_byte_buffer { + get { + return ResourceManager.GetString("IBM_ALDC_with_1024_byte_buffer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM ALDC with 2048 byte buffer. + /// + internal static string IBM_ALDC_with_2048_byte_buffer { + get { + return ResourceManager.GetString("IBM_ALDC_with_2048_byte_buffer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM ALDC with 512 byte buffer. + /// + internal static string IBM_ALDC_with_512_byte_buffer { + get { + return ResourceManager.GetString("IBM_ALDC_with_512_byte_buffer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM Behaviour Configuration Mode Page:. + /// + internal static string IBM_Behaviour_Configuration_Mode_Page { + get { + return ResourceManager.GetString("IBM_Behaviour_Configuration_Mode_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM Drive Component Revision Levels page:. + /// + internal static string IBM_Drive_Component_Revision_Levels_page { + get { + return ResourceManager.GetString("IBM_Drive_Component_Revision_Levels_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM Drive Serial Numbers page:. + /// + internal static string IBM_Drive_Serial_Numbers_page { + get { + return ResourceManager.GetString("IBM_Drive_Serial_Numbers_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM IDRC. + /// + internal static string IBM_IDRC { + get { + return ResourceManager.GetString("IBM_IDRC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM LEOT Mode Page:. + /// + internal static string IBM_LEOT_Mode_Page { + get { + return ResourceManager.GetString("IBM_LEOT_Mode_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM OEM Specific Field: {0}. + /// + internal static string IBM_OEM_Specific_Field_0 { + get { + return ResourceManager.GetString("IBM_OEM_Specific_Field_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM Vendor-Specific Control Mode Page:. + /// + internal static string IBM_Vendor_Specific_Control_Mode_Page { + get { + return ResourceManager.GetString("IBM_Vendor_Specific_Control_Mode_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM vendor-specific information:. + /// + internal static string IBM_vendor_specific_information { + get { + return ResourceManager.GetString("IBM_vendor_specific_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Draft ECMA & ANSI X3B5/87-099: 12.7 mm 18-Track Magnetic Tape Cartridge, 1944 ftpmm, IFM, GCR (IBM 3480, 3490, 3490E). + /// + internal static string IBM3480 { + get { + return ResourceManager.GetString("IBM3480", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM 3490E. + /// + internal static string IBM3490E { + get { + return ResourceManager.GetString("IBM3490E", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM 3590. + /// + internal static string IBM3590 { + get { + return ResourceManager.GetString("IBM3590", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM 3590 extended. + /// + internal static string IBM3590_extended { + get { + return ResourceManager.GetString("IBM3590_extended", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM 3590E. + /// + internal static string IBM3590E { + get { + return ResourceManager.GetString("IBM3590E", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IBM 3590E extended. + /// + internal static string IBM3590E_extended { + get { + return ResourceManager.GetString("IBM3590E_extended", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identifier belongs to addressed logical unit. + /// + internal static string Identifier_belongs_to_addressed_logical_unit { + get { + return ResourceManager.GetString("Identifier_belongs_to_addressed_logical_unit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identifier belongs to target device that contains the addressed logical unit. + /// + internal static string Identifier_belongs_to_target_device_that_contains_the_addressed_logical_unit { + get { + return ResourceManager.GetString("Identifier_belongs_to_target_device_that_contains_the_addressed_logical_unit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identifier belongs to target port. + /// + internal static string Identifier_belongs_to_target_port { + get { + return ResourceManager.GetString("Identifier_belongs_to_target_port", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identifier has unknown association with code {0}. + /// + internal static string Identifier_has_unknown_association_with_code_0 { + get { + return ResourceManager.GetString("Identifier_has_unknown_association_with_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IDLE IMMEDIATE with UNLOAD FEATURE is supported. + /// + internal static string IDLE_IMMEDIATE_with_UNLOAD_FEATURE_is_supported { + get { + return ResourceManager.GetString("IDLE_IMMEDIATE_with_UNLOAD_FEATURE_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IDLE IMMEDIATE with UNLOAD FEATURE is supported and enabled. + /// + internal static string IDLE_IMMEDIATE_with_UNLOAD_FEATURE_is_supported_and_enabled { + get { + return ResourceManager.GetString("IDLE_IMMEDIATE_with_UNLOAD_FEATURE_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IEEE 1394. + /// + internal static string IEEE_1394 { + get { + return ResourceManager.GetString("IEEE_1394", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IEEE EUI-64: {0}. + /// + internal static string IEEE_EUI_64_0 { + get { + return ResourceManager.GetString("IEEE_EUI_64_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IEEE EUI-64: {0:X2}. + /// + internal static string IEEE_EUI_64_0_X2 { + get { + return ResourceManager.GetString("IEEE_EUI_64_0_X2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If ACA is established, the task set commands shall resume after it is cleared, otherwise they shall terminate with CHECK CONDITION. + /// + internal static string If_ACA_is_established_the_task_set_commands_shall_resume_after_it_is_cleared_otherwise_they_shall_terminate_with_CHECK_CONDITION { + get { + return ResourceManager.GetString("If_ACA_is_established_the_task_set_commands_shall_resume_after_it_is_cleared_othe" + + "rwise_they_shall_terminate_with_CHECK_CONDITION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If set, target shall report log exception conditions. + /// + internal static string If_set_target_shall_report_log_exception_conditions { + get { + return ResourceManager.GetString("If_set_target_shall_report_log_exception_conditions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Illegal field in CDB. + /// + internal static string Illegal_field_in_CDB { + get { + return ResourceManager.GetString("Illegal_field_in_CDB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Illegal field in data parameters. + /// + internal static string Illegal_field_in_data_parameters { + get { + return ResourceManager.GetString("Illegal_field_in_data_parameters", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Implicit Asymmetric Logical Unit Access is enabled. + /// + internal static string Implicit_Asymmetric_Logical_Unit_Access_is_enabled { + get { + return ResourceManager.GetString("Implicit_Asymmetric_Logical_Unit_Access_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In-order data delivery is supported. + /// + internal static string In_order_data_delivery_is_supported { + get { + return ResourceManager.GetString("In_order_data_delivery_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In-order data delivery is supported and enabled. + /// + internal static string In_order_data_delivery_is_supported_and_enabled { + get { + return ResourceManager.GetString("In_order_data_delivery_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incomplete identify response. + /// + internal static string Incomplete_identify_response { + get { + return ResourceManager.GetString("Incomplete_identify_response", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect CD-Text pack type {0}, not decoding. + /// + internal static string Incorrect_CD_Text_pack_type_0_not_decoding { + get { + return ResourceManager.GetString("Incorrect_CD_Text_pack_type_0_not_decoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect ECC P.. + /// + internal static string Incorrect_ECC_P { + get { + return ResourceManager.GetString("Incorrect_ECC_P", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect ECC Q.. + /// + internal static string Incorrect_ECC_Q { + get { + return ResourceManager.GetString("Incorrect_ECC_Q", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect EDC.. + /// + internal static string Incorrect_EDC { + get { + return ResourceManager.GetString("Incorrect_EDC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect length indicator. + /// + internal static string Incorrect_length_indicator { + get { + return ResourceManager.GetString("Incorrect_length_indicator", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect sector contents.. + /// + internal static string Incorrect_sector_contents { + get { + return ResourceManager.GetString("Incorrect_sector_contents", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect zero fill.. + /// + internal static string Incorrect_zero_fill { + get { + return ResourceManager.GetString("Incorrect_zero_fill", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Indicative Target Writing Power: 0x{0:X2}. + /// + internal static string Indicative_Target_Writing_Power_0 { + get { + return ResourceManager.GetString("Indicative_Target_Writing_Power_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Informational exception conditions will be reported a maximum of {0} times. + /// + internal static string Informational_exception_conditions_will_be_reported_a_maximum_of_0_times { + get { + return ResourceManager.GetString("Informational_exception_conditions_will_be_reported_a_maximum_of_0_times", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Informational exceptions are disabled. + /// + internal static string Informational_exceptions_are_disabled { + get { + return ResourceManager.GetString("Informational_exceptions_are_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Informational exceptions are enabled. + /// + internal static string Informational_exceptions_are_enabled { + get { + return ResourceManager.GetString("Informational_exceptions_are_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Informational exceptions reporting should not affect drive performance. + /// + internal static string Informational_exceptions_reporting_should_not_affect_drive_performance { + get { + return ResourceManager.GetString("Informational_exceptions_reporting_should_not_affect_drive_performance", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Initial priority is {0}. + /// + internal static string Initial_priority_is_0 { + get { + return ResourceManager.GetString("Initial_priority_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Initial program address: 0x{0:X8}. + /// + internal static string Initial_program_address_0 { + get { + return ResourceManager.GetString("Initial_program_address_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Initial program entry address: 0x{0:X8}. + /// + internal static string Initial_program_entry_address_0 { + get { + return ResourceManager.GetString("Initial_program_entry_address_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Initial program load size: {0} bytes. + /// + internal static string Initial_program_load_size_0 { + get { + return ResourceManager.GetString("Initial_program_load_size_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Initial program work RAM: {0} bytes. + /// + internal static string Initial_program_work_RAM_0 { + get { + return ResourceManager.GetString("Initial_program_work_RAM_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inner gap has {0} bytes. + /// + internal static string Inner_gap_has_0_bytes { + get { + return ResourceManager.GetString("Inner_gap_has_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inquiry descriptor contains: {0}. + /// + internal static string Inquiry_descriptor_contains_0 { + get { + return ResourceManager.GetString("Inquiry_descriptor_contains_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inquiry descriptor contains binary data (hex): {0}. + /// + internal static string Inquiry_descriptor_contains_binary_data_hex_0 { + get { + return ResourceManager.GetString("Inquiry_descriptor_contains_binary_data_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inquiry descriptor contains unknown kind {1} of data (hex): {0}. + /// + internal static string Inquiry_descriptor_contains_unknown_kind_1_of_data_hex_0 { + get { + return ResourceManager.GetString("Inquiry_descriptor_contains_unknown_kind_1_of_data_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inquiry descriptor type {2} contains unknown kind {1} of data (hex): {0}. + /// + internal static string Inquiry_descriptor_type_2_contains_unknown_kind_1_of_data_hex_0 { + get { + return ResourceManager.GetString("Inquiry_descriptor_type_2_contains_unknown_kind_1_of_data_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inserted cartridge is LTO. + /// + internal static string Inserted_cartridge_is_LTO { + get { + return ResourceManager.GetString("Inserted_cartridge_is_LTO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inter-block gap is {0} times the device's defined gap size. + /// + internal static string Inter_block_gap_is_0_times_the_device_defined_gap_size { + get { + return ResourceManager.GetString("Inter_block_gap_is_0_times_the_device_defined_gap_size", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inter-block gap is long enough to support update in place. + /// + internal static string Inter_block_gap_is_long_enough_to_support_update_in_place { + get { + return ResourceManager.GetString("Inter_block_gap_is_long_enough_to_support_update_in_place", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inter-block gap is unknown value {0}. + /// + internal static string Inter_block_gap_is_unknown_value_0 { + get { + return ResourceManager.GetString("Inter_block_gap_is_unknown_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Internet SCSI. + /// + internal static string Internet_SCSI { + get { + return ResourceManager.GetString("Internet_SCSI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid mode 3.. + /// + internal static string Invalid_mode_3 { + get { + return ResourceManager.GetString("Invalid_mode_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid purpose field with value {0}. + /// + internal static string Invalid_purpose_field_with_value_0 { + get { + return ResourceManager.GetString("Invalid_purpose_field_with_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to invalid size. + /// + internal static string invalid_size { + get { + return ResourceManager.GetString("invalid_size", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid value in bit {0} in field {1} of CDB. + /// + internal static string Invalid_value_in_bit_0_in_field_1_of_CDB { + get { + return ResourceManager.GetString("Invalid_value_in_bit_0_in_field_1_of_CDB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid value in field {0} of CDB. + /// + internal static string Invalid_value_in_field_0_of_CDB { + get { + return ResourceManager.GetString("Invalid_value_in_field_0_of_CDB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IORDY is supported. + /// + internal static string IORDY_is_supported { + get { + return ResourceManager.GetString("IORDY_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IORDY is supported and can be disabled. + /// + internal static string IORDY_is_supported_and_can_be_disabled { + get { + return ResourceManager.GetString("IORDY_is_supported_and_can_be_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ISA0 size: {0}. + /// + internal static string ISA0_size_0 { + get { + return ResourceManager.GetString("ISA0_size_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ISA1 size: {0}. + /// + internal static string ISA1_size_0 { + get { + return ResourceManager.GetString("ISA1_size_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ISO/IEC 10090: 86 mm Read/Write single-sided optical disc with 12500 tracks. + /// + internal static string ISO10090 { + get { + return ResourceManager.GetString("ISO10090", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ISO/IEC 13614: 300 mm double-sided optical disc. + /// + internal static string ISO13614 { + get { + return ResourceManager.GetString("ISO13614", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Japanese NTSC.. + /// + internal static string Japanese_NTSC { + get { + return ResourceManager.GetString("Japanese_NTSC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to kilobytes. + /// + internal static string kilobytes { + get { + return ResourceManager.GetString("kilobytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Large unit maximum multiplier is {0}.. + /// + internal static string Large_unit_maximum_multiplier_is_0 { + get { + return ResourceManager.GetString("Large_unit_maximum_multiplier_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Large unit size is {0} MiB. + /// + internal static string Large_unit_size_is_0_MiB { + get { + return ResourceManager.GetString("Large_unit_size_is_0_MiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last address unit number of data zone in this layer: {0}. + /// + internal static string Last_address_unit_number_of_data_zone_in_this_layer_0 { + get { + return ResourceManager.GetString("Last_address_unit_number_of_data_zone_in_this_layer_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last addressable logical block is {0}. + /// + internal static string Last_addressable_logical_block_is_0 { + get { + return ResourceManager.GetString("Last_addressable_logical_block_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last complete session number: {0}. + /// + internal static string Last_complete_session_number_0 { + get { + return ResourceManager.GetString("Last_complete_session_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last data read was compressed with . + /// + internal static string Last_data_read_was_compressed_with_ { + get { + return ResourceManager.GetString("Last_data_read_was_compressed_with_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last data read was uncompressed. + /// + internal static string Last_data_read_was_uncompressed { + get { + return ResourceManager.GetString("Last_data_read_was_uncompressed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last extended security error was {0}. + /// + internal static string Last_extended_security_error_was_0 { + get { + return ResourceManager.GetString("Last_extended_security_error_was_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last possible Lead-Out address is {0} (as LBA) or {1:X2}:{2:X2}:{3:X2}. + /// + internal static string Last_possible_Lead_Out_address_is_0_as_LBA_or_1_2_3 { + get { + return ResourceManager.GetString("Last_possible_Lead_Out_address_is_0_as_LBA_or_1_2_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last session is complete. + /// + internal static string Last_session_is_complete { + get { + return ResourceManager.GetString("Last_session_is_complete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last session is damaged. + /// + internal static string Last_session_is_damaged { + get { + return ResourceManager.GetString("Last_session_is_damaged", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last session is empty. + /// + internal static string Last_session_is_empty { + get { + return ResourceManager.GetString("Last_session_is_empty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last session is incomplete. + /// + internal static string Last_session_is_incomplete { + get { + return ResourceManager.GetString("Last_session_is_incomplete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last session Lead-In address is {0} (as LBA) or {1:X2}:{2:X2}:{3:X2}. + /// + internal static string Last_session_Lead_In_address_is_0_as_LBA_or_1_2_3 { + get { + return ResourceManager.GetString("Last_session_Lead_In_address_is_0_as_LBA_or_1_2_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last track in last session is track {0}. + /// + internal static string Last_track_in_last_session_is_track_0 { + get { + return ResourceManager.GetString("Last_track_in_last_session_is_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last track number: {0} (. + /// + internal static string Last_track_number_0_open_parenthesis { + get { + return ResourceManager.GetString("Last_track_number_0_open_parenthesis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last track number in last complete session: {0}. + /// + internal static string Last_track_number_in_last_complete_session_0 { + get { + return ResourceManager.GetString("Last_track_number_in_last_complete_session_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last User Data Area's LSN 0: 0x{0:X8}. + /// + internal static string Last_User_Data_Areas_LSN_0_0 { + get { + return ResourceManager.GetString("Last_User_Data_Areas_LSN_0_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last user data PSN for disc: {0}. + /// + internal static string Last_user_data_PSN_for_disc_0 { + get { + return ResourceManager.GetString("Last_user_data_PSN_for_disc_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last video track number: {0}. + /// + internal static string Last_video_track_number_0 { + get { + return ResourceManager.GetString("Last_video_track_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last writable ECC block address: 0x{0:X6}. + /// + internal static string Last_writable_ECC_block_address_0_X6_ { + get { + return ResourceManager.GetString("Last_writable_ECC_block_address_0_X6_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last WRITE MULTIPLE command correctly programmed {0} sectors. + /// + internal static string Last_WRITE_MULTIPLE_command_correctly_programmed_0_sectors { + get { + return ResourceManager.GetString("Last_WRITE_MULTIPLE_command_correctly_programmed_0_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Layer {0} is of type Blu-ray. + /// + internal static string Layer_0_is_of_type_Blu_ray { + get { + return ResourceManager.GetString("Layer_0_is_of_type_Blu_ray", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Layer {0} is of type CD. + /// + internal static string Layer_0_is_of_type_CD { + get { + return ResourceManager.GetString("Layer_0_is_of_type_CD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Layer {0} is of type DVD. + /// + internal static string Layer_0_is_of_type_DVD { + get { + return ResourceManager.GetString("Layer_0_is_of_type_DVD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Layer {0} is of type HD DVD. + /// + internal static string Layer_0_is_of_type_HD_DVD { + get { + return ResourceManager.GetString("Layer_0_is_of_type_HD_DVD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Layer {0} is of unknown type 0x{1:X4}. + /// + internal static string Layer_0_is_of_unknown_type_1 { + get { + return ResourceManager.GetString("Layer_0_is_of_unknown_type_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Layer 0 ends at PSN {0:X}h. + /// + internal static string Layer_zero_ends_at_PSN_0 { + get { + return ResourceManager.GetString("Layer_zero_ends_at_PSN_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Layers are in opposite track path. + /// + internal static string Layers_are_in_opposite_track_path { + get { + return ResourceManager.GetString("Layers_are_in_opposite_track_path", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Layers are in parallel track path. + /// + internal static string Layers_are_in_parallel_track_path { + get { + return ResourceManager.GetString("Layers_are_in_parallel_track_path", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LBA Extent {0} starts at LBA {1} and goes for {2} sectors. + /// + internal static string LBA_Extent_0_starts_at_LBA_1_and_goes_for_2_sectors { + get { + return ResourceManager.GetString("LBA_Extent_0_starts_at_LBA_1_and_goes_for_2_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lead-In is pre-recorded. + /// + internal static string Lead_In_is_pre_recorded { + get { + return ResourceManager.GetString("Lead_In_is_pre_recorded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lead-Out is audio type. + /// + internal static string Lead_out_is_audio_type { + get { + return ResourceManager.GetString("Lead_out_is_audio_type", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lead-Out is data type. + /// + internal static string Lead_out_is_data_type { + get { + return ResourceManager.GetString("Lead_out_is_data_type", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lead-Out is pre-recorded. + /// + internal static string Lead_Out_is_pre_recorded { + get { + return ResourceManager.GetString("Lead_Out_is_pre_recorded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lead-Out start position: {0:D2}:{1:D2}:{2:D2}. + /// + internal static string Lead_out_start_position_0_1_2 { + get { + return ResourceManager.GetString("Lead_out_start_position_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lead-Out start position: {3:D2}:{0:D2}:{1:D2}:{2:D2}. + /// + internal static string Lead_out_start_position_3_0_1_2 { + get { + return ResourceManager.GetString("Lead_out_start_position_3_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Legacy value: 0x{0:X2}. + /// + internal static string Legacy_value_0 { + get { + return ResourceManager.GetString("Legacy_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Library interface transmits 1 stop bits per byte. + /// + internal static string Library_interface_transmits_1_stop_bits_per_byte { + get { + return ResourceManager.GetString("Library_interface_transmits_1_stop_bits_per_byte", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Library interface transmits 2 stop bits per byte. + /// + internal static string Library_interface_transmits_2_stop_bits_per_byte { + get { + return ResourceManager.GetString("Library_interface_transmits_2_stop_bits_per_byte", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Library interface will operate at 115200 baud on next reset. + /// + internal static string Library_interface_will_operate_at_115200_baud_on_next_reset { + get { + return ResourceManager.GetString("Library_interface_will_operate_at_115200_baud_on_next_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Library interface will operate at 19200 baud on next reset. + /// + internal static string Library_interface_will_operate_at_19200_baud_on_next_reset { + get { + return ResourceManager.GetString("Library_interface_will_operate_at_19200_baud_on_next_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Library interface will operate at 38400 baud on next reset. + /// + internal static string Library_interface_will_operate_at_38400_baud_on_next_reset { + get { + return ResourceManager.GetString("Library_interface_will_operate_at_38400_baud_on_next_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Library interface will operate at 57600 baud on next reset. + /// + internal static string Library_interface_will_operate_at_57600_baud_on_next_reset { + get { + return ResourceManager.GetString("Library_interface_will_operate_at_57600_baud_on_next_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Library interface will operate at 9600 baud on next reset. + /// + internal static string Library_interface_will_operate_at_9600_baud_on_next_reset { + get { + return ResourceManager.GetString("Library_interface_will_operate_at_9600_baud_on_next_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Library is present. + /// + internal static string Library_is_present { + get { + return ResourceManager.GetString("Library_is_present", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Library time is {0}. + /// + internal static string Library_time_is_0 { + get { + return ResourceManager.GetString("Library_time_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Link block. + /// + internal static string Link_block { + get { + return ResourceManager.GetString("Link_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LOGICAL BLOCK APPLICATION TAG should not be modified. + /// + internal static string LOGICAL_BLOCK_APPLICATION_TAG_should_not_be_modified { + get { + return ResourceManager.GetString("LOGICAL_BLOCK_APPLICATION_TAG_should_not_be_modified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical block provisioning error reporting is enabled. + /// + internal static string Logical_block_provisioning_error_reporting_is_enabled { + get { + return ResourceManager.GetString("Logical_block_provisioning_error_reporting_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical sector size: {0} bytes. + /// + internal static string Logical_sector_size_0_bytes { + get { + return ResourceManager.GetString("Logical_sector_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical sector starts at offset {0} from physical sector. + /// + internal static string Logical_sector_starts_at_offset_0_from_physical_sector { + get { + return ResourceManager.GetString("Logical_sector_starts_at_offset_0_from_physical_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical unit group identifier: {0}. + /// + internal static string Logical_unit_group_identifier_0 { + get { + return ResourceManager.GetString("Logical_unit_group_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical unit supports logical block protection. + /// + internal static string Logical_unit_supports_logical_block_protection { + get { + return ResourceManager.GetString("Logical_unit_supports_logical_block_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical unit supports type 1 protection. + /// + internal static string Logical_unit_supports_type_1_protection { + get { + return ResourceManager.GetString("Logical_unit_supports_type_1_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical unit supports type 2 protection. + /// + internal static string Logical_unit_supports_type_2_protection { + get { + return ResourceManager.GetString("Logical_unit_supports_type_2_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical unit supports type 3 protection. + /// + internal static string Logical_unit_supports_type_3_protection { + get { + return ResourceManager.GetString("Logical_unit_supports_type_3_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical unit supports types 1, 2 and 3 protection. + /// + internal static string Logical_unit_supports_types_1_2_and_3_protection { + get { + return ResourceManager.GetString("Logical_unit_supports_types_1_2_and_3_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical unit supports types 1 and 2 protection. + /// + internal static string Logical_unit_supports_types_1_and_2_protection { + get { + return ResourceManager.GetString("Logical_unit_supports_types_1_and_2_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical unit supports types 1 and 3 protection. + /// + internal static string Logical_unit_supports_types_1_and_3_protection { + get { + return ResourceManager.GetString("Logical_unit_supports_types_1_and_3_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical unit supports types 2 and 3 protection. + /// + internal static string Logical_unit_supports_types_2_and_3_protection { + get { + return ResourceManager.GetString("Logical_unit_supports_types_2_and_3_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logical unit supports unknown protection defined by code {0}. + /// + internal static string Logical_unit_supports_unknown_protection_defined_by_code_0 { + get { + return ResourceManager.GetString("Logical_unit_supports_unknown_protection_defined_by_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Long Physical Alignment setting is {0}. + /// + internal static string Long_Physical_Alignment_setting_is_0 { + get { + return ResourceManager.GetString("Long_Physical_Alignment_setting_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Look-ahead read is supported. + /// + internal static string Look_ahead_read_is_supported { + get { + return ResourceManager.GetString("Look_ahead_read_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Look-ahead read is supported and enabled. + /// + internal static string Look_ahead_read_is_supported_and_enabled { + get { + return ResourceManager.GetString("Look_ahead_read_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LSN 0 is at PSN {0:X}h. + /// + internal static string LSN_zero_is_at_PSN_0 { + get { + return ResourceManager.GetString("LSN_zero_is_at_PSN_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO in CD-ROM emulation mode. + /// + internal static string LTO_in_CD_ROM_emulation_mode { + get { + return ResourceManager.GetString("LTO_in_CD_ROM_emulation_mode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium or Super AIT-1. + /// + internal static string LTO_or_SAIT1 { + get { + return ResourceManager.GetString("LTO_or_SAIT1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium 1 Type A cartridge inserted. + /// + internal static string LTO_Ultrium_1_Type_A_cartridge_inserted { + get { + return ResourceManager.GetString("LTO_Ultrium_1_Type_A_cartridge_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium 1 Type B cartridge inserted. + /// + internal static string LTO_Ultrium_1_Type_B_cartridge_inserted { + get { + return ResourceManager.GetString("LTO_Ultrium_1_Type_B_cartridge_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium 1 Type C cartridge inserted. + /// + internal static string LTO_Ultrium_1_Type_C_cartridge_inserted { + get { + return ResourceManager.GetString("LTO_Ultrium_1_Type_C_cartridge_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium 1 Type D cartridge inserted. + /// + internal static string LTO_Ultrium_1_Type_D_cartridge_inserted { + get { + return ResourceManager.GetString("LTO_Ultrium_1_Type_D_cartridge_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium 2 cartridge inserted. + /// + internal static string LTO_Ultrium_2_cartridge_inserted { + get { + return ResourceManager.GetString("LTO_Ultrium_2_cartridge_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium cleaning cartridge. + /// + internal static string LTO_Ultrium_cleaning_cartridge { + get { + return ResourceManager.GetString("LTO_Ultrium_cleaning_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-2 in CD emulation mode. + /// + internal static string LTO2_CDemu { + get { + return ResourceManager.GetString("LTO2_CDemu", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-2 or T9840. + /// + internal static string LTO2_or_T9840 { + get { + return ResourceManager.GetString("LTO2_or_T9840", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-3 in CD emulation mode. + /// + internal static string LTO3_CDemu { + get { + return ResourceManager.GetString("LTO3_CDemu", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-3 or T9940. + /// + internal static string LTO3_or_T9940 { + get { + return ResourceManager.GetString("LTO3_or_T9940", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-4 in CD emulation mode. + /// + internal static string LTO4_CDemu { + get { + return ResourceManager.GetString("LTO4_CDemu", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-4 or T9840D. + /// + internal static string LTO4_or_T9840D { + get { + return ResourceManager.GetString("LTO4_or_T9840D", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-5 in CD emulation mode. + /// + internal static string LTO5_CDemu { + get { + return ResourceManager.GetString("LTO5_CDemu", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LUN shall clear unit attention condition reported in the same nexus. + /// + internal static string LUN_shall_clear_unit_attention_condition_reported_in_the_same_nexus { + get { + return ResourceManager.GetString("LUN_shall_clear_unit_attention_condition_reported_in_the_same_nexus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LUN shall not clear unit attention condition reported in the same nexus. + /// + internal static string LUN_shall_not_clear_unit_attention_condition_reported_in_the_same_nexus { + get { + return ResourceManager.GetString("LUN_shall_not_clear_unit_attention_condition_reported_in_the_same_nexus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LUN shall not clear unit attention condition reported in the same nexus and shall establish a unit attention condition for the initiator. + /// + internal static string LUN_shall_not_clear_unit_attention_condition_reported_in_the_same_nexus_and_shall_establish_a_unit_attention_condition_for_the_initiator { + get { + return ResourceManager.GetString("LUN_shall_not_clear_unit_attention_condition_reported_in_the_same_nexus_and_shall" + + "_establish_a_unit_attention_condition_for_the_initiator", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mammoth-2. + /// + internal static string Mammoth2 { + get { + return ResourceManager.GetString("Mammoth2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Manufacturer: {0}. + /// + internal static string Manufacturer_0 { + get { + return ResourceManager.GetString("Manufacturer_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Manufacturer ID: {0}. + /// + internal static string Manufacturer_ID_0 { + get { + return ResourceManager.GetString("Manufacturer_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PCMCIA Manufacturer Identification Tuple:. + /// + internal static string Manufacturer_Identification_Tuple { + get { + return ResourceManager.GetString("Manufacturer_Identification_Tuple", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Manufacturing serial number: {0}. + /// + internal static string Manufacturing_serial_number_0 { + get { + return ResourceManager.GetString("Manufacturing_serial_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Master password revision code: {0}. + /// + internal static string Master_password_revision_code_0 { + get { + return ResourceManager.GetString("Master_password_revision_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Material type: 0x{0:X2}. + /// + internal static string Material_type_0 { + get { + return ResourceManager.GetString("Material_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Max context ID is {0}.. + /// + internal static string Max_context_ID_is_0 { + get { + return ResourceManager.GetString("Max_context_ID_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum {0} scramble extent information entries. + /// + internal static string Maximum_0_scramble_extent_information_entries { + get { + return ResourceManager.GetString("Maximum_0_scramble_extent_information_entries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum ATA revision supported: . + /// + internal static string Maximum_ATA_revision_supported { + get { + return ResourceManager.GetString("Maximum_ATA_revision_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum sense data would be {0} bytes. + /// + internal static string Maximum_sense_data_would_be_0_bytes { + get { + return ResourceManager.GetString("Maximum_sense_data_would_be_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum start of outermost Lead-Out in the recordable area of the disc: {0:D2}:{1:D2}:{2:D2}. + /// + internal static string Maximum_start_of_outermost_Lead_out_in_the_recordable_area_of_the_disc_0_1_2 { + get { + return ResourceManager.GetString("Maximum_start_of_outermost_Lead_out_in_the_recordable_area_of_the_disc_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum start of outermost Lead-Out in the recordable area of the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2}. + /// + internal static string Maximum_start_of_outermost_Lead_out_in_the_recordable_area_of_the_disc_3_0_1_2 { + get { + return ResourceManager.GetString("Maximum_start_of_outermost_Lead_out_in_the_recordable_area_of_the_disc_3_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}ms. + /// + internal static string Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_codes_field_is_0_ms { + get { + return ResourceManager.GetString("Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_cod" + + "es_field_is_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}s. + /// + internal static string Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_codes_field_is_0_s { + get { + return ResourceManager.GetString("Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_cod" + + "es_field_is_0_s", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}µs. + /// + internal static string Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_codes_field_is_0_µs { + get { + return ResourceManager.GetString("Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_cod" + + "es_field_is_0_µs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MBit/s. + /// + internal static string MBit_s { + get { + return ResourceManager.GetString("MBit_s", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MD5 logical unit identifier: {0}. + /// + internal static string MD5_logical_unit_identifier_0 { + get { + return ResourceManager.GetString("MD5_logical_unit_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MD5 logical unit identifier: {0:x2}. + /// + internal static string MD5_logical_unit_identifier_0_x2 { + get { + return ResourceManager.GetString("MD5_logical_unit_identifier_0_x2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media attribute is {0}. + /// + internal static string Media_attribute_is_0 { + get { + return ResourceManager.GetString("Media_attribute_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media background formatting has completed. + /// + internal static string Media_background_formatting_has_completed { + get { + return ResourceManager.GetString("Media_background_formatting_has_completed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media Card Pass Through command set is supported. + /// + internal static string Media_Card_Pass_Through_command_set_is_supported { + get { + return ResourceManager.GetString("Media_Card_Pass_Through_command_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media Card Pass Through command set is supported and enabled. + /// + internal static string Media_Card_Pass_Through_command_set_is_supported_and_enabled { + get { + return ResourceManager.GetString("Media_Card_Pass_Through_command_set_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media has been taken out, or inserted in, the cartridge. + /// + internal static string Media_has_been_taken_out_or_inserted_in_the_cartridge { + get { + return ResourceManager.GetString("Media_has_been_taken_out_or_inserted_in_the_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media has out bit marked, shouldn't. + /// + internal static string Media_has_out_bit_marked_shouldnt { + get { + return ResourceManager.GetString("Media_has_out_bit_marked_shouldnt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media has write protection bit marked, shouldn't. + /// + internal static string Media_has_write_protection_bit_marked_shouldnt { + get { + return ResourceManager.GetString("Media_has_write_protection_bit_marked_shouldnt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media ID: . + /// + internal static string Media_ID { + get { + return ResourceManager.GetString("Media_ID", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media is currently being formatted in the background. + /// + internal static string Media_is_currently_being_formatted_in_the_background { + get { + return ResourceManager.GetString("Media_is_currently_being_formatted_in_the_background", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media is inserted in a cartridge. + /// + internal static string Media_is_inserted_in_a_cartridge { + get { + return ResourceManager.GetString("Media_is_inserted_in_a_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media is not in a cartridge. + /// + internal static string Media_is_not_in_a_cartridge { + get { + return ResourceManager.GetString("Media_is_not_in_a_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media is write protected. + /// + internal static string Media_is_write_protected { + get { + return ResourceManager.GetString("Media_is_write_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media loader firmware version: {0}. + /// + internal static string Media_loader_firmware_version_0 { + get { + return ResourceManager.GetString("Media_loader_firmware_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media loader hardware version: {0}. + /// + internal static string Media_loader_hardware_version_0 { + get { + return ResourceManager.GetString("Media_loader_hardware_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media loader is present. + /// + internal static string Media_loader_is_present { + get { + return ResourceManager.GetString("Media_loader_is_present", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media loader mechanical version: {0}. + /// + internal static string Media_loader_mechanical_version_0 { + get { + return ResourceManager.GetString("Media_loader_mechanical_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media Serial is supported. + /// + internal static string Media_Serial_is_supported { + get { + return ResourceManager.GetString("Media_Serial_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media Serial is supported and valid. + /// + internal static string Media_Serial_is_supported_and_valid { + get { + return ResourceManager.GetString("Media_Serial_is_supported_and_valid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media surface sets write protection. + /// + internal static string Media_surface_sets_write_protection { + get { + return ResourceManager.GetString("Media_surface_sets_write_protection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media was being formatted in the background but it is stopped and incomplete. + /// + internal static string Media_was_being_formatted_in_the_background_but_it_is_stopped_and_incomplete { + get { + return ResourceManager.GetString("Media_was_being_formatted_in_the_background_but_it_is_stopped_and_incomplete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium change device. + /// + internal static string Medium_change_device { + get { + return ResourceManager.GetString("Medium_change_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium description: {0}. + /// + internal static string Medium_description_0 { + get { + return ResourceManager.GetString("Medium_description_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium has a nominal length of {0} m in a {1} mm width tape. + /// + internal static string Medium_has_a_nominal_length_of_0_m_in_a_1_mm_width_tape { + get { + return ResourceManager.GetString("Medium_has_a_nominal_length_of_0_m_in_a_1_mm_width_tape", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium has defined {0} partitions. + /// + internal static string Medium_has_defined_0_partitions { + get { + return ResourceManager.GetString("Medium_has_defined_0_partitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium is . + /// + internal static string Medium_is_ { + get { + return ResourceManager.GetString("Medium_is_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium is {0}. + /// + internal static string Medium_is_0 { + get { + return ResourceManager.GetString("Medium_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium is write protected. + /// + internal static string Medium_is_write_protected { + get { + return ResourceManager.GetString("Medium_is_write_protected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium rotates at {0} rpm. + /// + internal static string Medium_rotates_at_0_rpm { + get { + return ResourceManager.GetString("Medium_rotates_at_0_rpm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium supports block IDs. + /// + internal static string Medium_supports_block_IDs { + get { + return ResourceManager.GetString("Medium_supports_block_IDs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium supports following density codes:. + /// + internal static string Medium_supports_following_density_codes { + get { + return ResourceManager.GetString("Medium_supports_following_density_codes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium type "{0}" defined by "{1}".. + /// + internal static string Medium_type_0_defined_by_1 { + get { + return ResourceManager.GetString("Medium_type_0_defined_by_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Medium type code: {0:X2}h. + /// + internal static string Medium_type_code_0 { + get { + return ResourceManager.GetString("Medium_type_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CompactTape I, Exatape 28m, CompactTape II, VXA-2 or VXA-3. + /// + internal static string MediumType_CT1 { + get { + return ResourceManager.GetString("MediumType_CT1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DAT-72. + /// + internal static string MediumType_DAT72 { + get { + return ResourceManager.GetString("MediumType_DAT72", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DC-2900SL. + /// + internal static string MediumType_DC2900SL { + get { + return ResourceManager.GetString("MediumType_DC2900SL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DC-9200 or DDS-4. + /// + internal static string MediumType_DC9200 { + get { + return ResourceManager.GetString("MediumType_DC9200", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DDS cleaning cartridge. + /// + internal static string MediumType_DDSCleaning { + get { + return ResourceManager.GetString("MediumType_DDSCleaning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DLTtape S4. + /// + internal static string MediumType_DLTtapeS4 { + get { + return ResourceManager.GetString("MediumType_DLTtapeS4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 106m, DLTtape IV or Travan 5. + /// + internal static string MediumType_Exatape106m { + get { + return ResourceManager.GetString("MediumType_Exatape106m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 160m XL or Super DLTtape I. + /// + internal static string MediumType_Exatape106mXL { + get { + return ResourceManager.GetString("MediumType_Exatape106mXL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 112m. + /// + internal static string MediumType_Exatape112m { + get { + return ResourceManager.GetString("MediumType_Exatape112m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 125m. + /// + internal static string MediumType_Exatape125m { + get { + return ResourceManager.GetString("MediumType_Exatape125m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 150m. + /// + internal static string MediumType_Exatape150m { + get { + return ResourceManager.GetString("MediumType_Exatape150m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 15m, IBM MagStar or VXA. + /// + internal static string MediumType_Exatape15m { + get { + return ResourceManager.GetString("MediumType_Exatape15m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 170m. + /// + internal static string MediumType_Exatape170m { + get { + return ResourceManager.GetString("MediumType_Exatape170m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 225m. + /// + internal static string MediumType_Exatape225m { + get { + return ResourceManager.GetString("MediumType_Exatape225m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 22m. + /// + internal static string MediumType_Exatape22m { + get { + return ResourceManager.GetString("MediumType_Exatape22m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 22m AME. + /// + internal static string MediumType_Exatape22mAME { + get { + return ResourceManager.GetString("MediumType_Exatape22mAME", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 40m. + /// + internal static string MediumType_Exatape40m { + get { + return ResourceManager.GetString("MediumType_Exatape40m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 45m. + /// + internal static string MediumType_Exatape45m { + get { + return ResourceManager.GetString("MediumType_Exatape45m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 54m or DLTtape III. + /// + internal static string MediumType_Exatape54m { + get { + return ResourceManager.GetString("MediumType_Exatape54m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 75m. + /// + internal static string MediumType_Exatape75m { + get { + return ResourceManager.GetString("MediumType_Exatape75m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 76m. + /// + internal static string MediumType_Exatape76m { + get { + return ResourceManager.GetString("MediumType_Exatape76m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exatape 80m or DLTtape IIIxt. + /// + internal static string MediumType_Exatape80m { + get { + return ResourceManager.GetString("MediumType_Exatape80m", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium. + /// + internal static string MediumType_LTO { + get { + return ResourceManager.GetString("MediumType_LTO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-2. + /// + internal static string MediumType_LTO2 { + get { + return ResourceManager.GetString("MediumType_LTO2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-3. + /// + internal static string MediumType_LTO3 { + get { + return ResourceManager.GetString("MediumType_LTO3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-3 WORM. + /// + internal static string MediumType_LTO3WORM { + get { + return ResourceManager.GetString("MediumType_LTO3WORM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-4. + /// + internal static string MediumType_LTO4 { + get { + return ResourceManager.GetString("MediumType_LTO4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-4 WORM. + /// + internal static string MediumType_LTO4WORM { + get { + return ResourceManager.GetString("MediumType_LTO4WORM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-5. + /// + internal static string MediumType_LTO5 { + get { + return ResourceManager.GetString("MediumType_LTO5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-5 WORM. + /// + internal static string MediumType_LTO5WORM { + get { + return ResourceManager.GetString("MediumType_LTO5WORM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-6. + /// + internal static string MediumType_LTO6 { + get { + return ResourceManager.GetString("MediumType_LTO6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-6 WORM. + /// + internal static string MediumType_LTO6WORM { + get { + return ResourceManager.GetString("MediumType_LTO6WORM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-7. + /// + internal static string MediumType_LTO7 { + get { + return ResourceManager.GetString("MediumType_LTO7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium-7 WORM. + /// + internal static string MediumType_LTO7WORM { + get { + return ResourceManager.GetString("MediumType_LTO7WORM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LTO Ultrium WORM or cleaning cartridge. + /// + internal static string MediumType_LTOWORM { + get { + return ResourceManager.GetString("MediumType_LTOWORM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MLR1-26GB or DDS-3. + /// + internal static string MediumType_MLR1 { + get { + return ResourceManager.GetString("MediumType_MLR1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Super DLTtape II. + /// + internal static string MediumType_SDLT2 { + get { + return ResourceManager.GetString("MediumType_SDLT2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLR-32. + /// + internal static string MediumType_SLR32 { + get { + return ResourceManager.GetString("MediumType_SLR32", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLR-32SL. + /// + internal static string MediumType_SLR32SL { + get { + return ResourceManager.GetString("MediumType_SLR32SL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLR-40, SLR-60 or SLR-100. + /// + internal static string MediumType_SLR40_60_100 { + get { + return ResourceManager.GetString("MediumType_SLR40_60_100", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLR-5. + /// + internal static string MediumType_SLR5 { + get { + return ResourceManager.GetString("MediumType_SLR5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLR-5SL. + /// + internal static string MediumType_SLR5SL { + get { + return ResourceManager.GetString("MediumType_SLR5SL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLRtape-100. + /// + internal static string MediumType_SLRtape100 { + get { + return ResourceManager.GetString("MediumType_SLRtape100", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLRtape-140. + /// + internal static string MediumType_SLRtape140 { + get { + return ResourceManager.GetString("MediumType_SLRtape140", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLRtape-24. + /// + internal static string MediumType_SLRtape24 { + get { + return ResourceManager.GetString("MediumType_SLRtape24", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLRtape-24 SL. + /// + internal static string MediumType_SLRtape24SL { + get { + return ResourceManager.GetString("MediumType_SLRtape24SL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLRtape-40. + /// + internal static string MediumType_SLRtape40 { + get { + return ResourceManager.GetString("MediumType_SLRtape40", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLRtape-50. + /// + internal static string MediumType_SLRtape50 { + get { + return ResourceManager.GetString("MediumType_SLRtape50", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLRtape-50 SL. + /// + internal static string MediumType_SLRtape50SL { + get { + return ResourceManager.GetString("MediumType_SLRtape50SL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLRtape-60 or SLRtape-75. + /// + internal static string MediumType_SLRtape60 { + get { + return ResourceManager.GetString("MediumType_SLRtape60", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLRtape-7. + /// + internal static string MediumType_SLRtape7 { + get { + return ResourceManager.GetString("MediumType_SLRtape7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLRtape-7 SL. + /// + internal static string MediumType_SLRtape7SL { + get { + return ResourceManager.GetString("MediumType_SLRtape7SL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 6.3 mm tape with 12 tracks at 394 ftpmm or DC-9250. + /// + internal static string MediumType_Tape12 { + get { + return ResourceManager.GetString("MediumType_Tape12", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 6.3 mm tape with 24 tracks at 394 ftpmm or MLR1-26GBSL. + /// + internal static string MediumType_Tape24 { + get { + return ResourceManager.GetString("MediumType_Tape24", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Travan 7. + /// + internal static string MediumType_Travan7 { + get { + return ResourceManager.GetString("MediumType_Travan7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to undefined. + /// + internal static string MediumType_undefined { + get { + return ResourceManager.GetString("MediumType_undefined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to VStape I. + /// + internal static string MediumType_VStapeI { + get { + return ResourceManager.GetString("MediumType_VStapeI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm Compact Disc Digital Audio. + /// + internal static string MediumTypes_CDDA { + get { + return ResourceManager.GetString("MediumTypes_CDDA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm Compact Disc Digital Audio. + /// + internal static string MediumTypes_CDDA_80 { + get { + return ResourceManager.GetString("MediumTypes_CDDA_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm CD-R with data only. + /// + internal static string MediumTypes_CDR { + get { + return ResourceManager.GetString("MediumTypes_CDR", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm CD-R with data only. + /// + internal static string MediumTypes_CDR_80 { + get { + return ResourceManager.GetString("MediumTypes_CDR_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm CD-R with audio only. + /// + internal static string MediumTypes_CDR_DA { + get { + return ResourceManager.GetString("MediumTypes_CDR_DA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm CD-R with audio only. + /// + internal static string MediumTypes_CDR_DA_80 { + get { + return ResourceManager.GetString("MediumTypes_CDR_DA_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm CD-R with data and audio. + /// + internal static string MediumTypes_CDR_Mixed { + get { + return ResourceManager.GetString("MediumTypes_CDR_Mixed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm CD-ROM. + /// + internal static string MediumTypes_CDROM { + get { + return ResourceManager.GetString("MediumTypes_CDROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm CD-ROM. + /// + internal static string MediumTypes_CDROM_80 { + get { + return ResourceManager.GetString("MediumTypes_CDROM_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm CD-RW with data only. + /// + internal static string MediumTypes_CDRW { + get { + return ResourceManager.GetString("MediumTypes_CDRW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm CD-RW with data only. + /// + internal static string MediumTypes_CDRW_80 { + get { + return ResourceManager.GetString("MediumTypes_CDRW_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm CD-RW with audio only. + /// + internal static string MediumTypes_CDRW_DA { + get { + return ResourceManager.GetString("MediumTypes_CDRW_DA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm CD-RW with audio only. + /// + internal static string MediumTypes_CDRW_DA_80 { + get { + return ResourceManager.GetString("MediumTypes_CDRW_DA_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm CD-RW with data and audio. + /// + internal static string MediumTypes_CDRW_Mixed { + get { + return ResourceManager.GetString("MediumTypes_CDRW_Mixed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm CD-RW with data and audio. + /// + internal static string MediumTypes_CDRW_Mixed_80 { + get { + return ResourceManager.GetString("MediumTypes_CDRW_Mixed_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm HD disc. + /// + internal static string MediumTypes_HD { + get { + return ResourceManager.GetString("MediumTypes_HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm HD disc. + /// + internal static string MediumTypes_HD_80 { + get { + return ResourceManager.GetString("MediumTypes_HD_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm Hybrid disc (Photo CD). + /// + internal static string MediumTypes_HybridCD { + get { + return ResourceManager.GetString("MediumTypes_HybridCD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm Hybrid CD-R (Photo CD). + /// + internal static string MediumTypes_HybridCDR { + get { + return ResourceManager.GetString("MediumTypes_HybridCDR", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm Hybrid CD-R (Photo CD). + /// + internal static string MediumTypes_HybridCDR_80 { + get { + return ResourceManager.GetString("MediumTypes_HybridCDR_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm Hybrid CD-RW (Photo CD). + /// + internal static string MediumTypes_HybridCDRW { + get { + return ResourceManager.GetString("MediumTypes_HybridCDRW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm Hybrid CD-RW (Photo CD). + /// + internal static string MediumTypes_HybridCDRW_80 { + get { + return ResourceManager.GetString("MediumTypes_HybridCDRW_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 120 mm Compact Disc with data and audio. + /// + internal static string MediumTypes_MixedCD { + get { + return ResourceManager.GetString("MediumTypes_MixedCD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 80 mm Compact Disc with data and audio. + /// + internal static string MediumTypes_MixedCD_80 { + get { + return ResourceManager.GetString("MediumTypes_MixedCD_80", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown size CD-R. + /// + internal static string MediumTypes_Unknown_CDR { + get { + return ResourceManager.GetString("MediumTypes_Unknown_CDR", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown size CD-RW. + /// + internal static string MediumTypes_Unknown_CDRW { + get { + return ResourceManager.GetString("MediumTypes_Unknown_CDRW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown size HD disc. + /// + internal static string MediumTypes_Unknown_HD { + get { + return ResourceManager.GetString("MediumTypes_Unknown_HD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to megabytes. + /// + internal static string megabytes { + get { + return ResourceManager.GetString("megabytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Minimum request size is {0}. + /// + internal static string Minimum_request_size_is_0 { + get { + return ResourceManager.GetString("Minimum_request_size_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Minor ATA version not specified. + /// + internal static string Minor_ATA_version_not_specified { + get { + return ResourceManager.GetString("Minor_ATA_version_not_specified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MLR1-26GB. + /// + internal static string MLR1_26GB { + get { + return ResourceManager.GetString("MLR1_26GB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MLR1-26GBSL. + /// + internal static string MLR1_26GBSL { + get { + return ResourceManager.GetString("MLR1_26GBSL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC BD Read. + /// + internal static string MMC_BD_Read { + get { + return ResourceManager.GetString("MMC_BD_Read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC BD Write. + /// + internal static string MMC_BD_Write { + get { + return ResourceManager.GetString("MMC_BD_Write", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC CD Read. + /// + internal static string MMC_CD_Read { + get { + return ResourceManager.GetString("MMC_CD_Read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Core Feature:. + /// + internal static string MMC_Core_Feature { + get { + return ResourceManager.GetString("MMC_Core_Feature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC DVD Read. + /// + internal static string MMC_DVD_Read { + get { + return ResourceManager.GetString("MMC_DVD_Read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Embedded Changer:. + /// + internal static string MMC_Embedded_Changer { + get { + return ResourceManager.GetString("MMC_Embedded_Changer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Enhanced Defect Reporting Feature:. + /// + internal static string MMC_Enhanced_Defect_Reporting_Feature { + get { + return ResourceManager.GetString("MMC_Enhanced_Defect_Reporting_Feature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Formattable:. + /// + internal static string MMC_Formattable { + get { + return ResourceManager.GetString("MMC_Formattable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Hardware Defect Management:. + /// + internal static string MMC_Hardware_Defect_Management { + get { + return ResourceManager.GetString("MMC_Hardware_Defect_Management", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Incremental Streaming Writable:. + /// + internal static string MMC_Incremental_Streaming_Writable { + get { + return ResourceManager.GetString("MMC_Incremental_Streaming_Writable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Layer Jump Recording:. + /// + internal static string MMC_Layer_Jump_Recording { + get { + return ResourceManager.GetString("MMC_Layer_Jump_Recording", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Morphing:. + /// + internal static string MMC_Morphing { + get { + return ResourceManager.GetString("MMC_Morphing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Random Readable. + /// + internal static string MMC_Random_Readable { + get { + return ResourceManager.GetString("MMC_Random_Readable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Random Writable:. + /// + internal static string MMC_Random_Writable { + get { + return ResourceManager.GetString("MMC_Random_Writable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Real Time Streaming:. + /// + internal static string MMC_Real_Time_Streaming_ { + get { + return ResourceManager.GetString("MMC_Real_Time_Streaming_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Rigid Restricted Overwrite. + /// + internal static string MMC_Rigid_Restricted_Overwrite { + get { + return ResourceManager.GetString("MMC_Rigid_Restricted_Overwrite", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Supported Profiles:. + /// + internal static string MMC_Supported_Profiles { + get { + return ResourceManager.GetString("MMC_Supported_Profiles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Write Once. + /// + internal static string MMC_Write_Once { + get { + return ResourceManager.GetString("MMC_Write_Once", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MMC Write Protect:. + /// + internal static string MMC_Write_Protect { + get { + return ResourceManager.GetString("MMC_Write_Protect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mode 0.. + /// + internal static string Mode_0 { + get { + return ResourceManager.GetString("Mode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mode 1.. + /// + internal static string Mode_1 { + get { + return ResourceManager.GetString("Mode_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mode 2.. + /// + internal static string Mode_2 { + get { + return ResourceManager.GetString("Mode_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Module revision: {0}. + /// + internal static string Module_revision_0 { + get { + return ResourceManager.GetString("Module_revision_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Moment of inertia: 0x{0:X2}. + /// + internal static string Moment_of_inertia_0 { + get { + return ResourceManager.GetString("Moment_of_inertia_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MRW is dirty. + /// + internal static string MRW_is_dirty { + get { + return ResourceManager.GetString("MRW_is_dirty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multi-port device. + /// + internal static string Multi_port_device { + get { + return ResourceManager.GetString("Multi_port_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multi-word DMA: . + /// + internal static string Multi_word_DMA { + get { + return ResourceManager.GetString("Multi_word_DMA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MultiMediaCard Device Identification Register:. + /// + internal static string MultiMediaCard_Device_Identification_Register { + get { + return ResourceManager.GetString("MultiMediaCard_Device_Identification_Register", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MultiMediaCard Device Specific Data Register:. + /// + internal static string MultiMediaCard_Device_Specific_Data_Register_ { + get { + return ResourceManager.GetString("MultiMediaCard_Device_Specific_Data_Register_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MultiMediaCard Extended Device Specific Data Register:. + /// + internal static string MultiMediaCard_Extended_Device_Specific_Data_Register { + get { + return ResourceManager.GetString("MultiMediaCard_Extended_Device_Specific_Data_Register", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MultiMediaCard Operation Conditions Register:. + /// + internal static string MultiMediaCard_Operation_Conditions_Register { + get { + return ResourceManager.GetString("MultiMediaCard_Operation_Conditions_Register", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to muted. + /// + internal static string muted { + get { + return ResourceManager.GetString("muted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NAA: {0}. + /// + internal static string NAA_0 { + get { + return ResourceManager.GetString("NAA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NAA: {0:X2}. + /// + internal static string NAA_0_X2 { + get { + return ResourceManager.GetString("NAA_0_X2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NCQ Autosense is supported. + /// + internal static string NCQ_Autosense_is_supported { + get { + return ResourceManager.GetString("NCQ_Autosense_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NCQ is supported. + /// + internal static string NCQ_is_supported { + get { + return ResourceManager.GetString("NCQ_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NCQ priority is supported. + /// + internal static string NCQ_priority_is_supported { + get { + return ResourceManager.GetString("NCQ_priority_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NCQ queue management is supported. + /// + internal static string NCQ_queue_management_is_supported { + get { + return ResourceManager.GetString("NCQ_queue_management_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NCQ streaming is supported. + /// + internal static string NCQ_streaming_is_supported { + get { + return ResourceManager.GetString("NCQ_streaming_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Never apply the verify operation. + /// + internal static string Never_apply_the_verify_operation { + get { + return ResourceManager.GetString("Never_apply_the_verify_operation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Next Border-In first sector is PSN {0:X}h. + /// + internal static string Next_Border_In_first_sector_is_PSN_0 { + get { + return ResourceManager.GetString("Next_Border_In_first_sector_is_PSN_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No additional information.. + /// + internal static string No_additional_information { + get { + return ResourceManager.GetString("No_additional_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No deferred error will be reported to a rewind command. + /// + internal static string No_deferred_error_will_be_reported_to_a_rewind_command { + get { + return ResourceManager.GetString("No_deferred_error_will_be_reported_to_a_rewind_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No disc inserted, tray closed or caddy inserted. + /// + internal static string No_disc_inserted_tray_closed_or_caddy_inserted { + get { + return ResourceManager.GetString("No_disc_inserted_tray_closed_or_caddy_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No drive region setting.. + /// + internal static string No_drive_region_setting { + get { + return ResourceManager.GetString("No_drive_region_setting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No manufacturer information string.. + /// + internal static string No_manufacturer_information_string { + get { + return ResourceManager.GetString("No_manufacturer_information_string", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No pre-fetch will be done. + /// + internal static string No_pre_fetch_will_be_done { + get { + return ResourceManager.GetString("No_pre_fetch_will_be_done", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No product name string.. + /// + internal static string No_product_name_string { + get { + return ResourceManager.GetString("No_product_name_string", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No reporting of informational exception condition. + /// + internal static string No_reporting_of_informational_exception_condition { + get { + return ResourceManager.GetString("No_reporting_of_informational_exception_condition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to no specific. + /// + internal static string no_specific_protocol { + get { + return ResourceManager.GetString("no_specific_protocol", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No unit attention on release. + /// + internal static string No_unit_attention_on_release { + get { + return ResourceManager.GetString("No_unit_attention_on_release", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-Volatile Cache:. + /// + internal static string Non_Volatile_Cache { + get { + return ResourceManager.GetString("Non_Volatile_Cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-Volatile Cache is {0} bytes. + /// + internal static string Non_Volatile_Cache_is_0_bytes { + get { + return ResourceManager.GetString("Non_Volatile_Cache_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-Volatile cache is disabled. + /// + internal static string Non_Volatile_cache_is_disabled { + get { + return ResourceManager.GetString("Non_Volatile_cache_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-zero buffer offsets are supported. + /// + internal static string Non_zero_buffer_offsets_are_supported { + get { + return ResourceManager.GetString("Non_zero_buffer_offsets_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-zero buffer offsets are supported and enabled. + /// + internal static string Non_zero_buffer_offsets_are_supported_and_enabled { + get { + return ResourceManager.GetString("Non_zero_buffer_offsets_are_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NOP is supported. + /// + internal static string NOP_is_supported { + get { + return ResourceManager.GetString("NOP_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NOP is supported and enabled. + /// + internal static string NOP_is_supported_and_enabled { + get { + return ResourceManager.GetString("NOP_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Normal reset behaviour. + /// + internal static string Normal_reset_behaviour { + get { + return ResourceManager.GetString("Normal_reset_behaviour", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to North America NTSC.. + /// + internal static string North_America_NTSC { + get { + return ResourceManager.GetString("North_America_NTSC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not all 28-bit commands are supported. + /// + internal static string Not_all_28_bit_commands_are_supported { + get { + return ResourceManager.GetString("Not_all_28_bit_commands_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Number and size of partitions can be manually defined. + /// + internal static string Number_and_size_of_partitions_can_be_manually_defined { + get { + return ResourceManager.GetString("Number_and_size_of_partitions_can_be_manually_defined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Number of partitions can be defined but their size is defined by the device. + /// + internal static string Number_of_partitions_can_be_defined_but_their_size_is_defined_by_the_device { + get { + return ResourceManager.GetString("Number_of_partitions_can_be_defined_but_their_size_is_defined_by_the_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Number of skip interval pointers: {0}. + /// + internal static string Number_of_skip_interval_pointers_0 { + get { + return ResourceManager.GetString("Number_of_skip_interval_pointers_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Number of skip track pointers: {0}. + /// + internal static string Number_of_skip_track_pointers_0 { + get { + return ResourceManager.GetString("Number_of_skip_track_pointers_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Object-based Storage Device. + /// + internal static string Object_based_Storage_Device { + get { + return ResourceManager.GetString("Object_based_Storage_Device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On logical block {0}. + /// + internal static string On_logical_block_0 { + get { + return ResourceManager.GetString("On_logical_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On medium insertion, it shall be loaded for auxiliary memory access only. + /// + internal static string On_medium_insertion_it_shall_be_loaded_for_auxiliary_memory_access_only { + get { + return ResourceManager.GetString("On_medium_insertion_it_shall_be_loaded_for_auxiliary_memory_access_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On medium insertion, it shall be loaded for full access. + /// + internal static string On_medium_insertion_it_shall_be_loaded_for_full_access { + get { + return ResourceManager.GetString("On_medium_insertion_it_shall_be_loaded_for_full_access", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On medium insertion, it shall not be loaded. + /// + internal static string On_medium_insertion_it_shall_not_be_loaded { + get { + return ResourceManager.GetString("On_medium_insertion_it_shall_not_be_loaded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On reading an updated block drive will return RECOVERED ERROR. + /// + internal static string On_reading_an_updated_block_drive_will_return_RECOVERED_ERROR { + get { + return ResourceManager.GetString("On_reading_an_updated_block_drive_will_return_RECOVERED_ERROR", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On segment {0}. + /// + internal static string On_segment_0 { + get { + return ResourceManager.GetString("On_segment_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only a group is being formatted. + /// + internal static string Only_a_group_is_being_formatted { + get { + return ResourceManager.GetString("Only_a_group_is_being_formatted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only report informational exception condition on request. + /// + internal static string Only_report_informational_exception_condition_on_request { + get { + return ResourceManager.GetString("Only_report_informational_exception_condition_on_request", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only retries and CIRC are used.. + /// + internal static string Only_retries_and_CIRC_are_used { + get { + return ResourceManager.GetString("Only_retries_and_CIRC_are_used", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only retries are used.. + /// + internal static string Only_retries_are_used { + get { + return ResourceManager.GetString("Only_retries_are_used", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OPC values for {0}Kbit/sec.: {1}, {2}, {3}, {4}, {5}, {6}. + /// + internal static string OPC_values_for_0_Kbit_sec_1_2_3_4_5_6 { + get { + return ResourceManager.GetString("OPC_values_for_0_Kbit_sec_1_2_3_4_5_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Operating systems support is standard LTO. + /// + internal static string Operating_systems_support_is_standard_LTO { + get { + return ResourceManager.GetString("Operating_systems_support_is_standard_LTO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Operating systems support is unknown code {0}. + /// + internal static string Operating_systems_support_is_unknown_code_0 { + get { + return ResourceManager.GetString("Operating_systems_support_is_unknown_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Optical card reader/writer device. + /// + internal static string Optical_card_reader_writer_device { + get { + return ResourceManager.GetString("Optical_card_reader_writer_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Optical memory device. + /// + internal static string Optical_memory_device { + get { + return ResourceManager.GetString("Optical_memory_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Optimal read size is {0} KiB. + /// + internal static string Optimal_read_size_is_0_KiB { + get { + return ResourceManager.GetString("Optimal_read_size_is_0_KiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Optimal trim size is {0} KiB. + /// + internal static string Optimal_trim_size_is_0_KiB { + get { + return ResourceManager.GetString("Optimal_trim_size_is_0_KiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Optimal write size is {0} KiB. + /// + internal static string Optimal_write_size_is_0_KiB { + get { + return ResourceManager.GetString("Optimal_write_size_is_0_KiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Optimum recording power: 0x{0:X2}. + /// + internal static string Optimum_recording_power_0 { + get { + return ResourceManager.GetString("Optimum_recording_power_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OSA size: {0}. + /// + internal static string OSA_size_0 { + get { + return ResourceManager.GetString("OSA_size_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Output port 0 has channels . + /// + internal static string Output_port_0_has_channels { + get { + return ResourceManager.GetString("Output_port_0_has_channels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Output port 1 has channels . + /// + internal static string Output_port_1_has_channels { + get { + return ResourceManager.GetString("Output_port_1_has_channels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Output port 2 has channels . + /// + internal static string Output_port_2_has_channels { + get { + return ResourceManager.GetString("Output_port_2_has_channels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Output port 3 has channels . + /// + internal static string Output_port_3_has_channels { + get { + return ResourceManager.GetString("Output_port_3_has_channels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Overseas title: {0}. + /// + internal static string Overseas_title_0 { + get { + return ResourceManager.GetString("Overseas_title_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OVERWRITE EXT is supported. + /// + internal static string OVERWRITE_EXT_is_supported { + get { + return ResourceManager.GetString("OVERWRITE_EXT_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PACKET is supported. + /// + internal static string PACKET_is_supported { + get { + return ResourceManager.GetString("PACKET_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PACKET is supported and enabled. + /// + internal static string PACKET_is_supported_and_enabled { + get { + return ResourceManager.GetString("PACKET_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Panic fence behaviour is enabled. + /// + internal static string Panic_fence_behaviour_is_enabled { + get { + return ResourceManager.GetString("Panic_fence_behaviour_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parallel ATA device: . + /// + internal static string Parallel_ATA_device { + get { + return ResourceManager.GetString("Parallel_ATA_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parallel SCSI. + /// + internal static string Parallel_SCSI { + get { + return ResourceManager.GetString("Parallel_SCSI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parameters can be saved. + /// + internal static string Parameters_can_be_saved { + get { + return ResourceManager.GetString("Parameters_can_be_saved", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Part version {0}. + /// + internal static string Part_version_0 { + get { + return ResourceManager.GetString("Part_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partition {0} is {1} {2} long. + /// + internal static string Partition_0_is_1_2_long { + get { + return ResourceManager.GetString("Partition_0_is_1_2_long", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partition {0} is {1} units long. + /// + internal static string Partition_0_is_1_units_long { + get { + return ResourceManager.GetString("Partition_0_is_1_units_long", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partition {0} runs for rest of medium. + /// + internal static string Partition_0_runs_for_rest_of_medium { + get { + return ResourceManager.GetString("Partition_0_runs_for_rest_of_medium", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partition alignment: {0} bytes. + /// + internal static string Partition_alignment_0_bytes { + get { + return ResourceManager.GetString("Partition_alignment_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partition parameters will not be applied until a FORMAT MEDIUM command is received. + /// + internal static string Partition_parameters_will_not_be_applied_until_a_FORMAT_MEDIUM_command_is_received { + get { + return ResourceManager.GetString("Partition_parameters_will_not_be_applied_until_a_FORMAT_MEDIUM_command_is_receive" + + "d", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partitions are defined in bytes. + /// + internal static string Partitions_are_defined_in_bytes { + get { + return ResourceManager.GetString("Partitions_are_defined_in_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partitions are defined in kilobytes. + /// + internal static string Partitions_are_defined_in_kilobytes { + get { + return ResourceManager.GetString("Partitions_are_defined_in_kilobytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partitions are defined in megabytes. + /// + internal static string Partitions_are_defined_in_megabytes { + get { + return ResourceManager.GetString("Partitions_are_defined_in_megabytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partitions are defined in units of {0} bytes. + /// + internal static string Partitions_are_defined_in_units_of_0_bytes { + get { + return ResourceManager.GetString("Partitions_are_defined_in_units_of_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partitions are fixed under device definitions. + /// + internal static string Partitions_are_fixed_under_device_definitions { + get { + return ResourceManager.GetString("Partitions_are_fixed_under_device_definitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PCI Express. + /// + internal static string PCI_Express { + get { + return ResourceManager.GetString("PCI_Express", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PCMCIA Device Geometry Tuples:. + /// + internal static string PCMCIA_Device_Geometry_Tuples { + get { + return ResourceManager.GetString("PCMCIA_Device_Geometry_Tuples", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PCMCIA Level 1 Version / Product Information Tuple:. + /// + internal static string PCMCIA_Level_1_Version_Product_Information_Tuple { + get { + return ResourceManager.GetString("PCMCIA_Level_1_Version_Product_Information_Tuple", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performance is limited using factor {0}. + /// + internal static string Performance_is_limited_using_factor_0 { + get { + return ResourceManager.GetString("Performance_is_limited_using_factor_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performance is not limited. + /// + internal static string Performance_is_not_limited { + get { + return ResourceManager.GetString("Performance_is_not_limited", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Peripherals:. + /// + internal static string Peripherals { + get { + return ResourceManager.GetString("Peripherals", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Permanent write protect is enabled. + /// + internal static string Permanent_write_protect_is_enabled { + get { + return ResourceManager.GetString("Permanent_write_protect_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Permanent write protection is disabled.. + /// + internal static string Permanent_write_protection_is_disabled { + get { + return ResourceManager.GetString("Permanent_write_protection_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Permanent write protection of boot areas is disabled.. + /// + internal static string Permanent_write_protection_of_boot_areas_is_disabled { + get { + return ResourceManager.GetString("Permanent_write_protection_of_boot_areas_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Permanent write protection will be applied to selected group.. + /// + internal static string Permanent_write_protection_will_be_applied_to_selected_group { + get { + return ResourceManager.GetString("Permanent_write_protection_will_be_applied_to_selected_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Persistent write protect is enabled. + /// + internal static string Persistent_write_protect_is_enabled { + get { + return ResourceManager.GetString("Persistent_write_protect_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PFI in extra Border zone starts at PSN {0:X}h. + /// + internal static string PFI_in_extra_Border_zone_starts_at_PSN_0 { + get { + return ResourceManager.GetString("PFI_in_extra_Border_zone_starts_at_PSN_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PHY Event counters are supported. + /// + internal static string PHY_Event_counters_are_supported { + get { + return ResourceManager.GetString("PHY_Event_counters_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Physical sector size: {0} bytes. + /// + internal static string Physical_sector_size_0_bytes { + get { + return ResourceManager.GetString("Physical_sector_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 1 indicates disk change reset when active high. + /// + internal static string Pin_1_indicates_disk_change_reset_when_active_high { + get { + return ResourceManager.GetString("Pin_1_indicates_disk_change_reset_when_active_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 1 indicates disk change reset when active low. + /// + internal static string Pin_1_indicates_disk_change_reset_when_active_low { + get { + return ResourceManager.GetString("Pin_1_indicates_disk_change_reset_when_active_low", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 1 indicates unknown function {0} when active high. + /// + internal static string Pin_1_indicates_unknown_function_0_when_active_high { + get { + return ResourceManager.GetString("Pin_1_indicates_unknown_function_0_when_active_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 1 indicates unknown function {0} when active low. + /// + internal static string Pin_1_indicates_unknown_function_0_when_active_low { + get { + return ResourceManager.GetString("Pin_1_indicates_unknown_function_0_when_active_low", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 1 is unconnected. + /// + internal static string Pin_1_is_unconnected { + get { + return ResourceManager.GetString("Pin_1_is_unconnected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 2 indicates unknown function {0} when active high. + /// + internal static string Pin_2_indicates_unknown_function_0_when_active_high { + get { + return ResourceManager.GetString("Pin_2_indicates_unknown_function_0_when_active_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 2 indicates unknown function {0} when active low. + /// + internal static string Pin_2_indicates_unknown_function_0_when_active_low { + get { + return ResourceManager.GetString("Pin_2_indicates_unknown_function_0_when_active_low", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 2 is unconnected. + /// + internal static string Pin_2_is_unconnected { + get { + return ResourceManager.GetString("Pin_2_is_unconnected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 34 indicates disk has changed when active high. + /// + internal static string Pin_34_indicates_disk_has_changed_when_active_high { + get { + return ResourceManager.GetString("Pin_34_indicates_disk_has_changed_when_active_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 34 indicates disk has changed when active low. + /// + internal static string Pin_34_indicates_disk_has_changed_when_active_low { + get { + return ResourceManager.GetString("Pin_34_indicates_disk_has_changed_when_active_low", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 34 indicates drive is ready when active high. + /// + internal static string Pin_34_indicates_drive_is_ready_when_active_high { + get { + return ResourceManager.GetString("Pin_34_indicates_drive_is_ready_when_active_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 34 indicates drive is ready when active low. + /// + internal static string Pin_34_indicates_drive_is_ready_when_active_low { + get { + return ResourceManager.GetString("Pin_34_indicates_drive_is_ready_when_active_low", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 34 indicates unknown function {0} when active high. + /// + internal static string Pin_34_indicates_unknown_function_0_when_active_high { + get { + return ResourceManager.GetString("Pin_34_indicates_unknown_function_0_when_active_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 34 indicates unknown function {0} when active low. + /// + internal static string Pin_34_indicates_unknown_function_0_when_active_low { + get { + return ResourceManager.GetString("Pin_34_indicates_unknown_function_0_when_active_low", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 34 is unconnected. + /// + internal static string Pin_34_is_unconnected { + get { + return ResourceManager.GetString("Pin_34_is_unconnected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 4 indicates drive is in use when active high. + /// + internal static string Pin_4_indicates_drive_is_in_use_when_active_high { + get { + return ResourceManager.GetString("Pin_4_indicates_drive_is_in_use_when_active_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 4 indicates drive is in use when active low. + /// + internal static string Pin_4_indicates_drive_is_in_use_when_active_low { + get { + return ResourceManager.GetString("Pin_4_indicates_drive_is_in_use_when_active_low", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 4 indicates eject when active high. + /// + internal static string Pin_4_indicates_eject_when_active_high { + get { + return ResourceManager.GetString("Pin_4_indicates_eject_when_active_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 4 indicates eject when active low. + /// + internal static string Pin_4_indicates_eject_when_active_low { + get { + return ResourceManager.GetString("Pin_4_indicates_eject_when_active_low", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 4 indicates head load when active high. + /// + internal static string Pin_4_indicates_head_load_when_active_high { + get { + return ResourceManager.GetString("Pin_4_indicates_head_load_when_active_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 4 indicates head load when active low. + /// + internal static string Pin_4_indicates_head_load_when_active_low { + get { + return ResourceManager.GetString("Pin_4_indicates_head_load_when_active_low", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 4 indicates unknown function {0} when active high. + /// + internal static string Pin_4_indicates_unknown_function_0_when_active_high { + get { + return ResourceManager.GetString("Pin_4_indicates_unknown_function_0_when_active_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 4 indicates unknown function {0} when active low. + /// + internal static string Pin_4_indicates_unknown_function_0_when_active_low { + get { + return ResourceManager.GetString("Pin_4_indicates_unknown_function_0_when_active_low", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pin 4 is unconnected. + /// + internal static string Pin_4_is_unconnected { + get { + return ResourceManager.GetString("Pin_4_is_unconnected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PIO timing mode: {0}. + /// + internal static string PIO_timing_mode_0 { + get { + return ResourceManager.GetString("PIO_timing_mode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pitch size is 0.147 μm/bit. + /// + internal static string Pitch_size_is_0_147_μm_bit { + get { + return ResourceManager.GetString("Pitch_size_is_0_147_μm_bit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pitch size is 0.153 μm/bit. + /// + internal static string Pitch_size_is_0_153_μm_bit { + get { + return ResourceManager.GetString("Pitch_size_is_0_153_μm_bit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pitch size is 0.267 μm/bit. + /// + internal static string Pitch_size_is_0_267_μm_bit { + get { + return ResourceManager.GetString("Pitch_size_is_0_267_μm_bit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pitch size is 0.353 μm/bit. + /// + internal static string Pitch_size_is_0_353_μm_bit { + get { + return ResourceManager.GetString("Pitch_size_is_0_353_μm_bit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pitch size is between 0.130 μm/bit and 0.140 μm/bit. + /// + internal static string Pitch_size_is_between_0_130_μm_bit_and_0_140_μm_bit { + get { + return ResourceManager.GetString("Pitch_size_is_between_0_130_μm_bit_and_0_140_μm_bit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pitch size is between 0.140 μm/bit and 0.148 μm/bit. + /// + internal static string Pitch_size_is_between_0_140_μm_bit_and_0_148_μm_bit { + get { + return ResourceManager.GetString("Pitch_size_is_between_0_140_μm_bit_and_0_148_μm_bit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pitch size is between 0.409 μm/bit and 0.435 μm/bit. + /// + internal static string Pitch_size_is_between_0_409_μm_bit_and_0_435_μm_bit { + get { + return ResourceManager.GetString("Pitch_size_is_between_0_409_μm_bit_and_0_435_μm_bit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to POP device. + /// + internal static string POP_device { + get { + return ResourceManager.GetString("POP_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Port A link is down. + /// + internal static string Port_A_link_is_down { + get { + return ResourceManager.GetString("Port_A_link_is_down", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Port A uses Parallel SCSI Ultra-160 interface. + /// + internal static string Port_A_uses_Parallel_SCSI_Ultra_160_interface { + get { + return ResourceManager.GetString("Port_A_uses_Parallel_SCSI_Ultra_160_interface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Position {0:X2}:{1:X2}:{2:X2} (LBA {3}). + /// + internal static string Position_0_1_2_LBA_3 { + get { + return ResourceManager.GetString("Position_0_1_2_LBA_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power cycled write protection is disabled.. + /// + internal static string Power_cycled_write_protection_is_disabled { + get { + return ResourceManager.GetString("Power_cycled_write_protection_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power cycled write protection of boot areas is disabled.. + /// + internal static string Power_cycled_write_protection_of_boot_areas_is_disabled { + get { + return ResourceManager.GetString("Power_cycled_write_protection_of_boot_areas_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power cycled write protection will be applied to selected group.. + /// + internal static string Power_cycled_write_protection_will_be_applied_to_selected_group { + get { + return ResourceManager.GetString("Power_cycled_write_protection_will_be_applied_to_selected_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power management is supported. + /// + internal static string Power_management_is_supported { + get { + return ResourceManager.GetString("Power_management_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power management is supported and enabled. + /// + internal static string Power_management_is_supported_and_enabled { + get { + return ResourceManager.GetString("Power_management_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power mode feature set is supported. + /// + internal static string Power_mode_feature_set_is_supported { + get { + return ResourceManager.GetString("Power_mode_feature_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power mode feature set is supported and enabled. + /// + internal static string Power_mode_feature_set_is_supported_and_enabled { + get { + return ResourceManager.GetString("Power_mode_feature_set_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power-On Self-Test is disabled. + /// + internal static string Power_On_Self_Test_is_disabled { + get { + return ResourceManager.GetString("Power_On_Self_Test_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power-On Self-Test is enabled. + /// + internal static string Power_On_Self_Test_is_enabled { + get { + return ResourceManager.GetString("Power_On_Self_Test_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power-up in standby is supported. + /// + internal static string Power_up_in_standby_is_supported { + get { + return ResourceManager.GetString("Power_up_in_standby_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Power-up in standby is supported and enabled. + /// + internal static string Power_up_in_standby_is_supported_and_enabled { + get { + return ResourceManager.GetString("Power_up_in_standby_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pre-fetch can continue across discontinuities (such as cylinders or tracks). + /// + internal static string Pre_fetch_can_continue_across_discontinuities_such_as_cylinders_or_tracks { + get { + return ResourceManager.GetString("Pre_fetch_can_continue_across_discontinuities_such_as_cylinders_or_tracks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pre-fetch should be aborted upon receiving a new command. + /// + internal static string Pre_fetch_should_be_aborted_upon_receiving_a_new_command { + get { + return ResourceManager.GetString("Pre_fetch_should_be_aborted_upon_receiving_a_new_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pre-fetch values indicate a block multiplier. + /// + internal static string Pre_fetch_values_indicate_a_block_multiplier { + get { + return ResourceManager.GetString("Pre_fetch_values_indicate_a_block_multiplier", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pre-fetch will be done for READ commands of {0} blocks or less. + /// + internal static string Pre_fetch_will_be_done_for_READ_commands_of_0_blocks_or_less { + get { + return ResourceManager.GetString("Pre_fetch_will_be_done_for_READ_commands_of_0_blocks_or_less", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Primary code: {0:X2}h. + /// + internal static string Primary_code_0 { + get { + return ResourceManager.GetString("Primary_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Primary Spare Area stats at PSN {0:X}h and ends at PSN {1:X}h, inclusively. + /// + internal static string Primary_Spare_Area_stats_at_PSN_0_and_ends_at_PSN_1_inclusively { + get { + return ResourceManager.GetString("Primary_Spare_Area_stats_at_PSN_0_and_ends_at_PSN_1_inclusively", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Printer device. + /// + internal static string Printer_device { + get { + return ResourceManager.GetString("Printer_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Processor device. + /// + internal static string Processor_device { + get { + return ResourceManager.GetString("Processor_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Producer: {0}. + /// + internal static string Producer_0 { + get { + return ResourceManager.GetString("Producer_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product code: {0}. + /// + internal static string Product_code_0 { + get { + return ResourceManager.GetString("Product_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product CRC: 0x{0:X8}. + /// + internal static string Product_CRC_0 { + get { + return ResourceManager.GetString("Product_CRC_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product family: {0}. + /// + internal static string Product_family_0 { + get { + return ResourceManager.GetString("Product_family_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product family is 10.0/20.0 GB. + /// + internal static string Product_family_is_10_0_20_0_GB { + get { + return ResourceManager.GetString("Product_family_is_10_0_20_0_GB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product family is 15.0/30.0 GB. + /// + internal static string Product_family_is_15_0_30_0_GB { + get { + return ResourceManager.GetString("Product_family_is_15_0_30_0_GB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product family is 2.6 GB. + /// + internal static string Product_family_is_2_6_GB { + get { + return ResourceManager.GetString("Product_family_is_2_6_GB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product family is 20.0/40.0 GB. + /// + internal static string Product_family_is_20_0_40_0_GB { + get { + return ResourceManager.GetString("Product_family_is_20_0_40_0_GB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product family is 6.0 GB. + /// + internal static string Product_family_is_6_0_GB { + get { + return ResourceManager.GetString("Product_family_is_6_0_GB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product family is not specified. + /// + internal static string Product_family_is_not_specified { + get { + return ResourceManager.GetString("Product_family_is_not_specified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product name: {0}. + /// + internal static string Product_name_0 { + get { + return ResourceManager.GetString("Product_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product revision: {0:X2}.{1:X2}. + /// + internal static string Product_revision_0_1 { + get { + return ResourceManager.GetString("Product_revision_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product serial number: {0}. + /// + internal static string Product_serial_number_0 { + get { + return ResourceManager.GetString("Product_serial_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Product version: {0}. + /// + internal static string Product_version_0 { + get { + return ResourceManager.GetString("Product_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Profile {0}: {1}. + /// + internal static string Profile_0_1 { + get { + return ResourceManager.GetString("Profile_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prologue found at {0}. + /// + internal static string Prologue_found_at_0 { + get { + return ResourceManager.GetString("Prologue_found_at_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protector information checking is disabled. + /// + internal static string Protector_information_checking_is_disabled { + get { + return ResourceManager.GetString("Protector_information_checking_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (ATA/ATAPI) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_ATA_ATAPI_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_ATA_ATAPI_specific_descriptor_with_unknown_format_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (Automation/Drive Interface Transport) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_Automation_Drive_Interface_Transport_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_Automation_Drive_Interface_Transport_specific_descriptor_with_unknown_fo" + + "rmat_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (Fibre Channel) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_Fibre_Channel_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_Fibre_Channel_specific_descriptor_with_unknown_format_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (IEEE 1394) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_IEEE_1394_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_IEEE_1394_specific_descriptor_with_unknown_format_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (Internet SCSI) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_Internet_SCSI_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_Internet_SCSI_specific_descriptor_with_unknown_format_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (Parallel SCSI) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_Parallel_SCSI_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_Parallel_SCSI_specific_descriptor_with_unknown_format_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (PCI Express) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_PCI_Express_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_PCI_Express_specific_descriptor_with_unknown_format_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (SCSI Remote Direct Memory Access) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_SCSI_Remote_Direct_Memory_Access_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_SCSI_Remote_Direct_Memory_Access_specific_descriptor_with_unknown_format" + + "_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (SCSIe) specific descriptor: Routing ID is {0}. + /// + internal static string Protocol_SCSIe_specific_descriptor_Routing_ID_is_0 { + get { + return ResourceManager.GetString("Protocol_SCSIe_specific_descriptor_Routing_ID_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (Serial Attachment SCSI) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_Serial_Attachment_SCSI_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_Serial_Attachment_SCSI_specific_descriptor_with_unknown_format_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (SSA) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_SSA_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_SSA_specific_descriptor_with_unknown_format_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (UAS) specific descriptor: USB address {0} interface {1}. + /// + internal static string Protocol_UAS_specific_descriptor_USB_address_0_interface_1 { + get { + return ResourceManager.GetString("Protocol_UAS_specific_descriptor_USB_address_0_interface_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (unknown code {0}) specific descriptor with unknown format (hex): {1}. + /// + internal static string Protocol_unknown_code_0_specific_descriptor_with_unknown_format_hex_1 { + get { + return ResourceManager.GetString("Protocol_unknown_code_0_specific_descriptor_with_unknown_format_hex_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol (unknown) specific descriptor with unknown format (hex): {0}. + /// + internal static string Protocol_unknown_specific_descriptor_with_unknown_format_hex_0 { + get { + return ResourceManager.GetString("Protocol_unknown_specific_descriptor_with_unknown_format_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PSN of User Data Area's LSN 0: 0x{0:X8}. + /// + internal static string PSN_of_User_Data_Areas_LSN_0_0 { + get { + return ResourceManager.GetString("PSN_of_User_Data_Areas_LSN_0_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Q subchannel mode {0}. + /// + internal static string Q_subchannel_mode_0 { + get { + return ResourceManager.GetString("Q_subchannel_mode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Q subchannel mode not given. + /// + internal static string Q_subchannel_mode_not_given { + get { + return ResourceManager.GetString("Q_subchannel_mode_not_given", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Q subchannel stores current position. + /// + internal static string Q_subchannel_stores_current_position { + get { + return ResourceManager.GetString("Q_subchannel_stores_current_position", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Q subchannel stores ISRC. + /// + internal static string Q_subchannel_stores_ISRC { + get { + return ResourceManager.GetString("Q_subchannel_stores_ISRC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Q subchannel stores media catalog number. + /// + internal static string Q_subchannel_stores_media_catalog_number { + get { + return ResourceManager.GetString("Q_subchannel_stores_media_catalog_number", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Q subchannel stores track pointer. + /// + internal static string Q_subchannel_stores_track_pointer { + get { + return ResourceManager.GetString("Q_subchannel_stores_track_pointer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Q subchannel stores video track pointer. + /// + internal static string Q_subchannel_stores_video_track_pointer { + get { + return ResourceManager.GetString("Q_subchannel_stores_video_track_pointer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to QIC-11. + /// + internal static string QIC11 { + get { + return ResourceManager.GetString("QIC11", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to QIC-120: 6.3 mm 15-Track Magnetic Tape Cartridge, 394 bpmm, GCR. + /// + internal static string QIC120 { + get { + return ResourceManager.GetString("QIC120", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to QIC-1350: 6.3 mm 30-Track Magnetic Tape Cartridge, 2034 bpmm, RLL. + /// + internal static string QIC1350 { + get { + return ResourceManager.GetString("QIC1350", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to QIC-150: 6.3 mm 18-Track Magnetic Tape Cartridge, 394 bpmm, GCR. + /// + internal static string QIC150 { + get { + return ResourceManager.GetString("QIC150", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to QIC-320: 6.3 mm 26-Track Magnetic Tape Cartridge, 630 bpmm, GCR. + /// + internal static string QIC320 { + get { + return ResourceManager.GetString("QIC320", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quadraphonic audio track with 50/15 μs pre-emphasis. + /// + internal static string Quadraphonic_audio_track_with_50_15_us_pre_emphasis { + get { + return ResourceManager.GetString("Quadraphonic_audio_track_with_50_15_us_pre_emphasis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quadraphonic audio track with no pre-emphasis. + /// + internal static string Quadraphonic_audio_track_with_no_pre_emphasis { + get { + return ResourceManager.GetString("Quadraphonic_audio_track_with_no_pre_emphasis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EEPROM firmware checksum: 0x{0:X4}. + /// + internal static string Quantum_EEPROM_firmware_checksum_0 { + get { + return ResourceManager.GetString("Quantum_EEPROM_firmware_checksum_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quantum Firmware Build Information page:. + /// + internal static string Quantum_Quantum_Firmware_Build_Information_page { + get { + return ResourceManager.GetString("Quantum_Quantum_Firmware_Build_Information_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read/write firmware build date: {0}. + /// + internal static string Quantum_Read_write_firmware_build_date_0 { + get { + return ResourceManager.GetString("Quantum_Read_write_firmware_build_date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read/write firmware checksum: 0x{0:X8}. + /// + internal static string Quantum_Read_write_firmware_checksum_0 { + get { + return ResourceManager.GetString("Quantum_Read_write_firmware_checksum_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Servo firmware checksum: 0x{0:X4}. + /// + internal static string Quantum_Servo_firmware_checksum_0 { + get { + return ResourceManager.GetString("Quantum_Servo_firmware_checksum_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quantum vendor-specific information:. + /// + internal static string Quantum_vendor_specific_information { + get { + return ResourceManager.GetString("Quantum_vendor_specific_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read after TRIM is deterministic. + /// + internal static string Read_after_TRIM_is_deterministic { + get { + return ResourceManager.GetString("Read_after_TRIM_is_deterministic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read after TRIM returns empty data. + /// + internal static string Read_after_TRIM_returns_empty_data { + get { + return ResourceManager.GetString("Read_after_TRIM_returns_empty_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read-ahead is disabled. + /// + internal static string Read_ahead_is_disabled { + get { + return ResourceManager.GetString("Read_ahead_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read block: {0} bytes. + /// + internal static string Read_block_0_bytes { + get { + return ResourceManager.GetString("Read_block_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read block length is {0} bytes. + /// + internal static string Read_block_length_is_0_bytes { + get { + return ResourceManager.GetString("Read_block_length_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read block length size is defined in extended CSD. + /// + internal static string Read_block_length_size_is_defined_in_extended_CSD { + get { + return ResourceManager.GetString("Read_block_length_size_is_defined_in_extended_CSD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ BUFFER DMA is supported. + /// + internal static string READ_BUFFER_DMA_is_supported { + get { + return ResourceManager.GetString("READ_BUFFER_DMA_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ BUFFER is supported. + /// + internal static string READ_BUFFER_is_supported { + get { + return ResourceManager.GetString("READ_BUFFER_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ BUFFER is supported and enabled. + /// + internal static string READ_BUFFER_is_supported_and_enabled { + get { + return ResourceManager.GetString("READ_BUFFER_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read buffer shall have an empty ratio of {0} before more data is read from medium. + /// + internal static string Read_buffer_shall_have_an_empty_ratio_of_0_before_more_data_is_read_from_medium { + get { + return ResourceManager.GetString("Read_buffer_shall_have_an_empty_ratio_of_0_before_more_data_is_read_from_medium", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read-cache is enabled. + /// + internal static string Read_cache_is_enabled { + get { + return ResourceManager.GetString("Read_cache_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read commands can cross physical block boundaries. + /// + internal static string Read_commands_can_cross_physical_block_boundaries { + get { + return ResourceManager.GetString("Read_commands_can_cross_physical_block_boundaries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ DMA QUEUED and WRITE DMA QUEUED are supported. + /// + internal static string READ_DMA_QUEUED_and_WRITE_DMA_QUEUED_are_supported { + get { + return ResourceManager.GetString("READ_DMA_QUEUED_and_WRITE_DMA_QUEUED_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ DMA QUEUED and WRITE DMA QUEUED are supported and enabled. + /// + internal static string READ_DMA_QUEUED_and_WRITE_DMA_QUEUED_are_supported_and_enabled { + get { + return ResourceManager.GetString("READ_DMA_QUEUED_and_WRITE_DMA_QUEUED_are_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ LOG DMA EXT is supported. + /// + internal static string READ_LOG_DMA_EXT_is_supported { + get { + return ResourceManager.GetString("READ_LOG_DMA_EXT_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read-only block device. + /// + internal static string Read_only_block_device { + get { + return ResourceManager.GetString("Read_only_block_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read/Write block device. + /// + internal static string Read_Write_block_device { + get { + return ResourceManager.GetString("Read_Write_block_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ/WRITE DMA EXT GPL are supported. + /// + internal static string READ_WRITE_DMA_EXT_GPL_are_supported { + get { + return ResourceManager.GetString("READ_WRITE_DMA_EXT_GPL_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ/WRITE DMA EXT GPL are supported and enabled. + /// + internal static string READ_WRITE_DMA_EXT_GPL_are_supported_and_enabled { + get { + return ResourceManager.GetString("READ_WRITE_DMA_EXT_GPL_are_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ/WRITE LONG has {0} extra bytes. + /// + internal static string READ_WRITE_LONG_has_0_extra_bytes { + get { + return ResourceManager.GetString("READ_WRITE_LONG_has_0_extra_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Real-time block.. + /// + internal static string Real_time_block { + get { + return ResourceManager.GetString("Real_time_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Receipt of host initiated power management requests is supported. + /// + internal static string Receipt_of_host_initiated_power_management_requests_is_supported { + get { + return ResourceManager.GetString("Receipt_of_host_initiated_power_management_requests_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to RECEIVE FPDMA QUEUED and SEND FPDMA QUEUED are supported. + /// + internal static string RECEIVE_FPDMA_QUEUED_and_SEND_FPDMA_QUEUED_are_supported { + get { + return ResourceManager.GetString("RECEIVE_FPDMA_QUEUED_and_SEND_FPDMA_QUEUED_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recommended erasing power ratio is {0} ε. + /// + internal static string Recommended_erasing_power_ratio_is_0 { + get { + return ResourceManager.GetString("Recommended_erasing_power_ratio_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recommended recording power is {0} mW. + /// + internal static string Recommended_recording_power_is_0_mW { + get { + return ResourceManager.GetString("Recommended_recording_power_is_0_mW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recorded marks have a higher reflectivity than unrecorded ones (LTH disc).. + /// + internal static string Recorded_marks_have_a_higher_reflectivity_than_unrecorded_ones_LTH_disc { + get { + return ResourceManager.GetString("Recorded_marks_have_a_higher_reflectivity_than_unrecorded_ones_LTH_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recorded marks have a lower reflectivity than unrecorded ones (HTL disc).. + /// + internal static string Recorded_marks_have_a_lower_reflectivity_than_unrecorded_ones_HTL_disc { + get { + return ResourceManager.GetString("Recorded_marks_have_a_lower_reflectivity_than_unrecorded_ones_HTL_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recording power is not specified. + /// + internal static string Recording_power_is_not_specified { + get { + return ResourceManager.GetString("Recording_power_is_not_specified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recovered buffer data comes in FIFO order. + /// + internal static string Recovered_buffer_data_comes_in_FIFO_order { + get { + return ResourceManager.GetString("Recovered_buffer_data_comes_in_FIFO_order", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recovered buffer data comes in LIFO order. + /// + internal static string Recovered_buffer_data_comes_in_LIFO_order { + get { + return ResourceManager.GetString("Recovered_buffer_data_comes_in_LIFO_order", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recovered errors will be reported.. + /// + internal static string Recovered_errors_will_be_reported { + get { + return ResourceManager.GetString("Recovered_errors_will_be_reported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recovered errors will be reported and aborted with CHECK CONDITION.. + /// + internal static string Recovered_errors_will_be_reported_and_aborted_with_CHECK_CONDITION { + get { + return ResourceManager.GetString("Recovered_errors_will_be_reported_and_aborted_with_CHECK_CONDITION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recovered errors will not be reported.. + /// + internal static string Recovered_errors_will_not_be_reported { + get { + return ResourceManager.GetString("Recovered_errors_will_not_be_reported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reference speed is 2x. + /// + internal static string Reference_speed_is_2x { + get { + return ResourceManager.GetString("Reference_speed_is_2x", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reference speed is 4x. + /// + internal static string Reference_speed_is_4x { + get { + return ResourceManager.GetString("Reference_speed_is_4x", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reference speed is 8x. + /// + internal static string Reference_speed_is_8x { + get { + return ResourceManager.GetString("Reference_speed_is_8x", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reference speed set is unknown: {0}. + /// + internal static string Reference_speed_set_is_unknown_0 { + get { + return ResourceManager.GetString("Reference_speed_set_is_unknown_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reference velocity is 3.49 m/s. + /// + internal static string Reference_velocity_is_3_49_m_s { + get { + return ResourceManager.GetString("Reference_velocity_is_3_49_m_s", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Regions supported:. + /// + internal static string Regions_supported { + get { + return ResourceManager.GetString("Regions_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Register version 1.0. + /// + internal static string Register_version_1_0 { + get { + return ResourceManager.GetString("Register_version_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Register version 1.1. + /// + internal static string Register_version_1_1 { + get { + return ResourceManager.GetString("Register_version_1_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Register version 1.2. + /// + internal static string Register_version_1_2 { + get { + return ResourceManager.GetString("Register_version_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Register version 2.0. + /// + internal static string Register_version_2_0 { + get { + return ResourceManager.GetString("Register_version_2_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Register version is defined in Extended Device Specific Data Register. + /// + internal static string Register_version_is_defined_in_Extended_Device_Specific_Data_Register { + get { + return ResourceManager.GetString("Register_version_is_defined_in_Extended_Device_Specific_Data_Register", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Relative target port identifier: {0}. + /// + internal static string Relative_target_port_identifier_0 { + get { + return ResourceManager.GetString("Relative_target_port_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Release date: {0}. + /// + internal static string Release_date_0 { + get { + return ResourceManager.GetString("Release_date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Release firmware: {0}. + /// + internal static string Release_firmware_0 { + get { + return ResourceManager.GetString("Release_firmware_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Release is supported. + /// + internal static string Release_is_supported { + get { + return ResourceManager.GetString("Release_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Release is supported and enabled. + /// + internal static string Release_is_supported_and_enabled { + get { + return ResourceManager.GetString("Release_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removable device. + /// + internal static string Removable_device { + get { + return ResourceManager.GetString("Removable_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removable media feature set is supported. + /// + internal static string Removable_media_feature_set_is_supported { + get { + return ResourceManager.GetString("Removable_media_feature_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removable media feature set is supported and enabled. + /// + internal static string Removable_media_feature_set_is_supported_and_enabled { + get { + return ResourceManager.GetString("Removable_media_feature_set_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removable Media Status Notification feature set is supported. + /// + internal static string Removable_Media_Status_Notification_feature_set_is_supported { + get { + return ResourceManager.GetString("Removable_Media_Status_Notification_feature_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removable Media Status Notification is supported. + /// + internal static string Removable_Media_Status_Notification_is_supported { + get { + return ResourceManager.GetString("Removable_Media_Status_Notification_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removable Media Status Notification is supported and enabled. + /// + internal static string Removable_Media_Status_Notification_is_supported_and_enabled { + get { + return ResourceManager.GetString("Removable_Media_Status_Notification_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Report exception on compression is set to {0}. + /// + internal static string Report_exception_on_compression_is_set_to_0 { + get { + return ResourceManager.GetString("Report_exception_on_compression_is_set_to_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reported serial number: {0}. + /// + internal static string Reported_serial_number_0 { + get { + return ResourceManager.GetString("Reported_serial_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved3 = 0x{0:X2}. + /// + internal static string Reserved_3_equals_0_X2 { + get { + return ResourceManager.GetString("Reserved_3_equals_0_X2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved4 = 0x{0:X2}. + /// + internal static string Reserved_4_equals_0_X2 { + get { + return ResourceManager.GetString("Reserved_4_equals_0_X2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved5 = 0x{0:X2}. + /// + internal static string Reserved_5_equals_0_X2 { + get { + return ResourceManager.GetString("Reserved_5_equals_0_X2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved6 = 0x{0:X2}. + /// + internal static string Reserved_6_equals_0_X2 { + get { + return ResourceManager.GetString("Reserved_6_equals_0_X2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved autoload mode {0} set. + /// + internal static string Reserved_autoload_mode_0_set { + get { + return ResourceManager.GetString("Reserved_autoload_mode_0_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved byte 56, bits 7 to 4 = 0x{0:X2}. + /// + internal static string Reserved_byte_56_bits_seven_to_four_0 { + get { + return ResourceManager.GetString("Reserved_byte_56_bits_seven_to_four_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved byte 57 = 0x{0:X2}. + /// + internal static string Reserved_byte_57 { + get { + return ResourceManager.GetString("Reserved_byte_57", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved byte 5, bits 2 to 1 = 0x{0:X2}. + /// + internal static string Reserved_byte_five_bits_two_to_one_0 { + get { + return ResourceManager.GetString("Reserved_byte_five_bits_two_to_one_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved bytes 74 to 95. + /// + internal static string Reserved_bytes_74_to_95 { + get { + return ResourceManager.GetString("Reserved_bytes_74_to_95", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved data transfer disconnect control value {0}. + /// + internal static string Reserved_data_transfer_disconnect_control_value_0 { + get { + return ResourceManager.GetString("Reserved_data_transfer_disconnect_control_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved = 0x{0:X2}. + /// + internal static string Reserved_equals_0_X2 { + get { + return ResourceManager.GetString("Reserved_equals_0_X2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved flags 0x{0:X2} set. + /// + internal static string Reserved_flags_0_set { + get { + return ResourceManager.GetString("Reserved_flags_0_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved QErr value 2 is set. + /// + internal static string Reserved_QErr_value_2_is_set { + get { + return ResourceManager.GetString("Reserved_QErr_value_2_is_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved UA_INTLCK_CTRL value 1 is set. + /// + internal static string Reserved_UA_INTLCK_CTRL_value_1_is_set { + get { + return ResourceManager.GetString("Reserved_UA_INTLCK_CTRL_value_1_is_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved value 0x02 found in SPI clocking field. + /// + internal static string Reserved_value_0x02_found_in_SPI_clocking_field { + get { + return ResourceManager.GetString("Reserved_value_0x02_found_in_SPI_clocking_field", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved value set in Peripheral Qualifier field.. + /// + internal static string Reserved_value_set_in_Peripheral_Qualifier_field { + get { + return ResourceManager.GetString("Reserved_value_set_in_Peripheral_Qualifier_field", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved1 = 0x{0:X2}. + /// + internal static string Reserved1_equals_0_X8 { + get { + return ResourceManager.GetString("Reserved1_equals_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved2 = 0x{0:X2}. + /// + internal static string Reserved2_equals_0_X8 { + get { + return ResourceManager.GetString("Reserved2_equals_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved3 = 0x{0:X8}. + /// + internal static string Reserved3_equals_0_X8 { + get { + return ResourceManager.GetString("Reserved3_equals_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved4 = 0x{0:X16}. + /// + internal static string Reserved4_equals_0_X16 { + get { + return ResourceManager.GetString("Reserved4_equals_0_X16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved4 = 0x{0:X8}. + /// + internal static string Reserved4_equals_0_X8 { + get { + return ResourceManager.GetString("Reserved4_equals_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved5 = 0x{0:X8}. + /// + internal static string Reserved5_equals_0_X8 { + get { + return ResourceManager.GetString("Reserved5_equals_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved6 = 0x{0:X8}. + /// + internal static string Reserved6_equals_0_X8 { + get { + return ResourceManager.GetString("Reserved6_equals_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved7 = 0x{0:X2}. + /// + internal static string Reserved7_equals_0_X2 { + get { + return ResourceManager.GetString("Reserved7_equals_0_X2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved7 = 0x{0:X8}. + /// + internal static string Reserved7_equals_0_X8 { + get { + return ResourceManager.GetString("Reserved7_equals_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved8 = 0x{0:X2}. + /// + internal static string Reserved8_equals_0_X2 { + get { + return ResourceManager.GetString("Reserved8_equals_0_X2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved9 = 0x{0:X8}. + /// + internal static string Reserved9_equals_0_X8 { + get { + return ResourceManager.GetString("Reserved9_equals_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Response modifier: {0}. + /// + internal static string Response_modifier_0 { + get { + return ResourceManager.GetString("Response_modifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Response value: 0x{0:X8}. + /// + internal static string Response_value_0 { + get { + return ResourceManager.GetString("Response_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rotational speed tolerance is higher than 0.5%. + /// + internal static string Rotational_speed_tolerance_is_higher_than_0_5_percent { + get { + return ResourceManager.GetString("Rotational_speed_tolerance_is_higher_than_0_5_percent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Timestamp can be initialized by methods outside of the SCSI standards, but SCSI's SET TIMESTAMP shall take precedence over them. + /// + internal static string S01_Timestamp_can_be_initialized_by_methods_outside_of_the_SCSI_standards_but_SCSI_SET_TIMESTAMP_shall_take_precedence_over_them { + get { + return ResourceManager.GetString("S01_Timestamp_can_be_initialized_by_methods_outside_of_the_SCSI_standards_but_SCS" + + "I_SET_TIMESTAMP_shall_take_precedence_over_them", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to S4 value: 0x{0:X6}. + /// + internal static string S4_value_0 { + get { + return ResourceManager.GetString("S4_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SANITIZE ANTIFREEZE LOCK EXT is supported. + /// + internal static string SANITIZE_ANTIFREEZE_LOCK_EXT_is_supported { + get { + return ResourceManager.GetString("SANITIZE_ANTIFREEZE_LOCK_EXT_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sanitize commands are specified by ACS-2. + /// + internal static string Sanitize_commands_are_specified_by_ACS_2 { + get { + return ResourceManager.GetString("Sanitize_commands_are_specified_by_ACS_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sanitize commands are specified by ACS-3 or higher. + /// + internal static string Sanitize_commands_are_specified_by_ACS_3_or_higher { + get { + return ResourceManager.GetString("Sanitize_commands_are_specified_by_ACS_3_or_higher", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sanitize feature set is supported. + /// + internal static string Sanitize_feature_set_is_supported { + get { + return ResourceManager.GetString("Sanitize_feature_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SATA 1.5Gb/s is supported. + /// + internal static string SATA_1_5Gbs_is_supported { + get { + return ResourceManager.GetString("SATA_1_5Gbs_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SATA 3.0Gb/s is supported. + /// + internal static string SATA_3_0Gbs_is_supported { + get { + return ResourceManager.GetString("SATA_3_0Gbs_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SATA 6.0Gb/s is supported. + /// + internal static string SATA_6_0Gbs_is_supported { + get { + return ResourceManager.GetString("SATA_6_0Gbs_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SATA Express device. + /// + internal static string SATA_Express_device { + get { + return ResourceManager.GetString("SATA_Express_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Scanner device. + /// + internal static string Scanner_device { + get { + return ResourceManager.GetString("Scanner_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Background Control page:. + /// + internal static string SCSI_Background_Control_page { + get { + return ResourceManager.GetString("SCSI_Background_Control_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Caching mode page:. + /// + internal static string SCSI_Caching_mode_page { + get { + return ResourceManager.GetString("SCSI_Caching_mode_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI CD-ROM audio control parameters page:. + /// + internal static string SCSI_CD_ROM_audio_control_parameters_page { + get { + return ResourceManager.GetString("SCSI_CD_ROM_audio_control_parameters_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI CD-ROM capabilities page:. + /// + internal static string SCSI_CD_ROM_capabilities_page { + get { + return ResourceManager.GetString("SCSI_CD_ROM_capabilities_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI CD-ROM parameters page:. + /// + internal static string SCSI_CD_ROM_parameters_page { + get { + return ResourceManager.GetString("SCSI_CD_ROM_parameters_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Control extension page:. + /// + internal static string SCSI_Control_extension_page { + get { + return ResourceManager.GetString("SCSI_Control_extension_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Control mode page:. + /// + internal static string SCSI_Control_mode_page { + get { + return ResourceManager.GetString("SCSI_Control_mode_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Data compression page:. + /// + internal static string SCSI_Data_compression_page { + get { + return ResourceManager.GetString("SCSI_Data_compression_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Device configuration page:. + /// + internal static string SCSI_Device_configuration_page { + get { + return ResourceManager.GetString("SCSI_Device_configuration_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Device identification:. + /// + internal static string SCSI_Device_identification { + get { + return ResourceManager.GetString("SCSI_Device_identification", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Disconnect-Reconnect mode page:. + /// + internal static string SCSI_Disconnect_Reconnect_mode_page { + get { + return ResourceManager.GetString("SCSI_Disconnect_Reconnect_mode_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Drive Operation Mode page:. + /// + internal static string SCSI_Drive_Operation_Mode_page { + get { + return ResourceManager.GetString("SCSI_Drive_Operation_Mode_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Extended INQUIRY Data:. + /// + internal static string SCSI_Extended_INQUIRY_Data { + get { + return ResourceManager.GetString("SCSI_Extended_INQUIRY_Data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Flexible disk page:. + /// + internal static string SCSI_Flexible_disk_page { + get { + return ResourceManager.GetString("SCSI_Flexible_disk_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Format device page:. + /// + internal static string SCSI_Format_device_page { + get { + return ResourceManager.GetString("SCSI_Format_device_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Implemented operating definitions:. + /// + internal static string SCSI_Implemented_operating_definitions { + get { + return ResourceManager.GetString("SCSI_Implemented_operating_definitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Informational exceptions control page:. + /// + internal static string SCSI_Informational_exceptions_control_page { + get { + return ResourceManager.GetString("SCSI_Informational_exceptions_control_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Management Network Addresses:. + /// + internal static string SCSI_Management_Network_Addresses { + get { + return ResourceManager.GetString("SCSI_Management_Network_Addresses", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Medium Configuration Mode Page:. + /// + internal static string SCSI_Medium_Configuration_Mode_Page { + get { + return ResourceManager.GetString("SCSI_Medium_Configuration_Mode_Page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium partition page:. + /// + internal static string SCSI_medium_partition_page { + get { + return ResourceManager.GetString("SCSI_medium_partition_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI medium partition page (extra):. + /// + internal static string SCSI_medium_partition_page_extra { + get { + return ResourceManager.GetString("SCSI_medium_partition_page_extra", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Medium types supported page:. + /// + internal static string SCSI_Medium_types_supported_page { + get { + return ResourceManager.GetString("SCSI_Medium_types_supported_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Mode Sense Header:. + /// + internal static string SCSI_Mode_Sense_Header { + get { + return ResourceManager.GetString("SCSI_Mode_Sense_Header", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI name string identifier: {0}. + /// + internal static string SCSI_name_string_identifier_0 { + get { + return ResourceManager.GetString("SCSI_name_string_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI name string identifier (hex): {0}. + /// + internal static string SCSI_name_string_identifier_hex_0 { + get { + return ResourceManager.GetString("SCSI_name_string_identifier_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI optical memory:. + /// + internal static string SCSI_optical_memory { + get { + return ResourceManager.GetString("SCSI_optical_memory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI over PCI Express. + /// + internal static string SCSI_over_PCI_Express { + get { + return ResourceManager.GetString("SCSI_over_PCI_Express", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI port is disabled. + /// + internal static string SCSI_port_is_disabled { + get { + return ResourceManager.GetString("SCSI_port_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI port is enabled. + /// + internal static string SCSI_port_is_enabled { + get { + return ResourceManager.GetString("SCSI_port_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI port will be disabled on next power up. + /// + internal static string SCSI_port_will_be_disabled_on_next_power_up { + get { + return ResourceManager.GetString("SCSI_port_will_be_disabled_on_next_power_up", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI port will be enabled on next power up. + /// + internal static string SCSI_port_will_be_enabled_on_next_power_up { + get { + return ResourceManager.GetString("SCSI_port_will_be_enabled_on_next_power_up", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Power Consumption page:. + /// + internal static string SCSI_Power_Consumption_page { + get { + return ResourceManager.GetString("SCSI_Power_Consumption_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Read error recovery page for MultiMedia Devices:. + /// + internal static string SCSI_Read_error_recovery_page_for_MultiMedia_Devices { + get { + return ResourceManager.GetString("SCSI_Read_error_recovery_page_for_MultiMedia_Devices", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Read-write error recovery page:. + /// + internal static string SCSI_Read_write_error_recovery_page { + get { + return ResourceManager.GetString("SCSI_Read_write_error_recovery_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Remote Direct Memory Access. + /// + internal static string SCSI_Remote_Direct_Memory_Access { + get { + return ResourceManager.GetString("SCSI_Remote_Direct_Memory_Access", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Removable Block Access Capabilities page:. + /// + internal static string SCSI_Removable_Block_Access_Capabilities_page { + get { + return ResourceManager.GetString("SCSI_Removable_Block_Access_Capabilities_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Rigid disk drive geometry page:. + /// + internal static string SCSI_Rigid_disk_drive_geometry_page { + get { + return ResourceManager.GetString("SCSI_Rigid_disk_drive_geometry_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI SENSE: {0}. + /// + internal static string SCSI_SENSE_0 { + get { + return ResourceManager.GetString("SCSI_SENSE_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Sequential-access Device Capabilities:. + /// + internal static string SCSI_Sequential_access_Device_Capabilities { + get { + return ResourceManager.GetString("SCSI_Sequential_access_Device_Capabilities", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Software Interface Identifiers:. + /// + internal static string SCSI_Software_Interface_Identifiers { + get { + return ResourceManager.GetString("SCSI_Software_Interface_Identifiers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Timer & Protect page:. + /// + internal static string SCSI_Timer_Protect_page { + get { + return ResourceManager.GetString("SCSI_Timer_Protect_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI to ATA Translation Layer Data:. + /// + internal static string SCSI_to_ATA_Translation_Layer_Data { + get { + return ResourceManager.GetString("SCSI_to_ATA_Translation_Layer_Data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI UNLOAD command will not eject the cartridge. + /// + internal static string SCSI_UNLOAD_command_will_not_eject_the_cartridge { + get { + return ResourceManager.GetString("SCSI_UNLOAD_command_will_not_eject_the_cartridge", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Verify error recovery page:. + /// + internal static string SCSI_Verify_error_recovery_page { + get { + return ResourceManager.GetString("SCSI_Verify_error_recovery_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI Verify error recovery page for MultiMedia Devices:. + /// + internal static string SCSI_Verify_error_recovery_page_for_MultiMedia_Devices { + get { + return ResourceManager.GetString("SCSI_Verify_error_recovery_page_for_MultiMedia_Devices", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCSI XOR control mode page:. + /// + internal static string SCSI_XOR_control_mode_page { + get { + return ResourceManager.GetString("SCSI_XOR_control_mode_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCT Data Tables are supported. + /// + internal static string SCT_Data_Tables_are_supported { + get { + return ResourceManager.GetString("SCT_Data_Tables_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCT Error Recovery Control is supported. + /// + internal static string SCT_Error_Recovery_Control_is_supported { + get { + return ResourceManager.GetString("SCT_Error_Recovery_Control_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCT Features Control is supported. + /// + internal static string SCT_Features_Control_is_supported { + get { + return ResourceManager.GetString("SCT_Features_Control_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCT Long Sector Address is supported. + /// + internal static string SCT_Long_Sector_Address_is_supported { + get { + return ResourceManager.GetString("SCT_Long_Sector_Address_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SCT Write Same is supported. + /// + internal static string SCT_Write_Same_is_supported { + get { + return ResourceManager.GetString("SCT_Write_Same_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Super DLTtape I. + /// + internal static string SDLT1 { + get { + return ResourceManager.GetString("SDLT1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Super DLTtape I at 133000 bpi. + /// + internal static string SDLT1_133k { + get { + return ResourceManager.GetString("SDLT1_133k", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Super DLTtape I compressed. + /// + internal static string SDLT1c { + get { + return ResourceManager.GetString("SDLT1c", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Seagate Firmware Numbers page:. + /// + internal static string Seagate_Firmware_Numbers_page { + get { + return ResourceManager.GetString("Seagate_Firmware_Numbers_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Seagate vendor-specific information:. + /// + internal static string Seagate_vendor_specific_information { + get { + return ResourceManager.GetString("Seagate_vendor_specific_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Second run-in block. + /// + internal static string Second_run_in_block { + get { + return ResourceManager.GetString("Second_run_in_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Second run-out block. + /// + internal static string Second_run_out_block { + get { + return ResourceManager.GetString("Second_run_out_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Secondary code: {0:X2}h. + /// + internal static string Secondary_code_0 { + get { + return ResourceManager.GetString("Secondary_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector {0}. + /// + internal static string Sector_0 { + get { + return ResourceManager.GetString("Sector_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector addressing is progressively incremented in one cylinder before going to the next. + /// + internal static string Sector_addressing_is_progressively_incremented_in_one_cylinder_before_going_to_the_next { + get { + return ResourceManager.GetString("Sector_addressing_is_progressively_incremented_in_one_cylinder_before_going_to_th" + + "e_next", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector addressing is progressively incremented in one surface before going to the next. + /// + internal static string Sector_addressing_is_progressively_incremented_in_one_surface_before_going_to_the_next { + get { + return ResourceManager.GetString("Sector_addressing_is_progressively_incremented_in_one_surface_before_going_to_the" + + "_next", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sectors addressable in CHS mode: {0}. + /// + internal static string Sectors_addressable_in_CHS_mode_0 { + get { + return ResourceManager.GetString("Sectors_addressable_in_CHS_mode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sectors addressable in CHS mode: {0} max., {1} current. + /// + internal static string Sectors_addressable_in_CHS_mode_0_max_1_current { + get { + return ResourceManager.GetString("Sectors_addressable_in_CHS_mode_0_max_1_current", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sectors per track: {0}. + /// + internal static string Sectors_per_track_0 { + get { + return ResourceManager.GetString("Sectors_per_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sectors per track: {0} max., {1} current. + /// + internal static string Sectors_per_track_0_max_1_current { + get { + return ResourceManager.GetString("Sectors_per_track_0_max_1_current", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sectors start at 1. + /// + internal static string Sectors_start_at_1 { + get { + return ResourceManager.GetString("Sectors_start_at_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SecureDigital Device Configuration Register:. + /// + internal static string SecureDigital_Device_Configuration_Register { + get { + return ResourceManager.GetString("SecureDigital_Device_Configuration_Register", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SecureDigital Device Identification Register:. + /// + internal static string SecureDigital_Device_Identification_Register { + get { + return ResourceManager.GetString("SecureDigital_Device_Identification_Register", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SecureDigital Device Specific Data Register:. + /// + internal static string SecureDigital_Device_Specific_Data_Register { + get { + return ResourceManager.GetString("SecureDigital_Device_Specific_Data_Register", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SecureDigital Operation Conditions Register:. + /// + internal static string SecureDigital_Operation_Conditions_Register { + get { + return ResourceManager.GetString("SecureDigital_Operation_Conditions_Register", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security:. + /// + internal static string Security { + get { + return ResourceManager.GetString("Security", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security count has expired. + /// + internal static string Security_count_has_expired { + get { + return ResourceManager.GetString("Security_count_has_expired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security count has not expired. + /// + internal static string Security_count_has_not_expired { + get { + return ResourceManager.GetString("Security_count_has_not_expired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security is enabled. + /// + internal static string Security_is_enabled { + get { + return ResourceManager.GetString("Security_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security is frozen. + /// + internal static string Security_is_frozen { + get { + return ResourceManager.GetString("Security_is_frozen", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security is locked. + /// + internal static string Security_is_locked { + get { + return ResourceManager.GetString("Security_is_locked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security is not enabled. + /// + internal static string Security_is_not_enabled { + get { + return ResourceManager.GetString("Security_is_not_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security is not frozen. + /// + internal static string Security_is_not_frozen { + get { + return ResourceManager.GetString("Security_is_not_frozen", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security is not locked. + /// + internal static string Security_is_not_locked { + get { + return ResourceManager.GetString("Security_is_not_locked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security level is high. + /// + internal static string Security_level_is_high { + get { + return ResourceManager.GetString("Security_level_is_high", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security level is maximum. + /// + internal static string Security_level_is_maximum { + get { + return ResourceManager.GetString("Security_level_is_maximum", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security Manager Device. + /// + internal static string Security_Manager_Device { + get { + return ResourceManager.GetString("Security_Manager_Device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security mode is supported. + /// + internal static string Security_mode_is_supported { + get { + return ResourceManager.GetString("Security_mode_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security mode is supported and enabled. + /// + internal static string Security_mode_is_supported_and_enabled { + get { + return ResourceManager.GetString("Security_mode_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEGA IP.BIN INFORMATION:. + /// + internal static string SEGA_IP_BIN_INFORMATION { + get { + return ResourceManager.GetString("SEGA_IP_BIN_INFORMATION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Segmented feature in DOWNLOAD MICROCODE is supported. + /// + internal static string Segmented_feature_in_DOWNLOAD_MICROCODE_is_supported { + get { + return ResourceManager.GetString("Segmented_feature_in_DOWNLOAD_MICROCODE_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Segmented feature in DOWNLOAD MICROCODE is supported and enabled. + /// + internal static string Segmented_feature_in_DOWNLOAD_MICROCODE_is_supported_and_enabled { + get { + return ResourceManager.GetString("Segmented_feature_in_DOWNLOAD_MICROCODE_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Selected driver strength is type {0}.. + /// + internal static string Selected_driver_strength_is_type_0 { + get { + return ResourceManager.GetString("Selected_driver_strength_is_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On logical block {0}. + /// + internal static string Sense_PrettifyDescriptor00_On_logical_block_0 { + get { + return ResourceManager.GetString("Sense_PrettifyDescriptor00_On_logical_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sequential-access device. + /// + internal static string Sequential_access_device { + get { + return ResourceManager.GetString("Sequential_access_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serial ATA device: . + /// + internal static string Serial_ATA_device { + get { + return ResourceManager.GetString("Serial_ATA_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serial Attachment SCSI. + /// + internal static string Serial_Attachment_SCSI { + get { + return ResourceManager.GetString("Serial_Attachment_SCSI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serial number: {0}. + /// + internal static string Serial_number_0 { + get { + return ResourceManager.GetString("Serial_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serial number is not the manufacturer's default value. + /// + internal static string Serial_number_is_not_the_manufacturer_default_value { + get { + return ResourceManager.GetString("Serial_number_is_not_the_manufacturer_default_value", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serial number is the manufacturer's default value. + /// + internal static string Serial_number_is_the_manufacturer_default_value { + get { + return ResourceManager.GetString("Serial_number_is_the_manufacturer_default_value", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SERVICE interrupt is supported. + /// + internal static string SERVICE_interrupt_is_supported { + get { + return ResourceManager.GetString("SERVICE_interrupt_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SERVICE interrupt is supported and enabled. + /// + internal static string SERVICE_interrupt_is_supported_and_enabled { + get { + return ResourceManager.GetString("SERVICE_interrupt_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Servo firmware version: {0}. + /// + internal static string Servo_firmware_version_0 { + get { + return ResourceManager.GetString("Servo_firmware_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Session {0}. + /// + internal static string Session_0 { + get { + return ResourceManager.GetString("Session_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SET FEATURES is required before spin-up. + /// + internal static string SET_FEATURES_is_required_before_spin_up { + get { + return ResourceManager.GetString("SET_FEATURES_is_required_before_spin_up", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SET MAX security extension is supported. + /// + internal static string SET_MAX_security_extension_is_supported { + get { + return ResourceManager.GetString("SET_MAX_security_extension_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SET MAX security extension is supported and enabled. + /// + internal static string SET_MAX_security_extension_is_supported_and_enabled { + get { + return ResourceManager.GetString("SET_MAX_security_extension_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SET PASSWORD DMA and SET UNLOCK DMA are supported. + /// + internal static string SET_PASSWORD_DMA_and_SET_UNLOCK_DMA_are_supported { + get { + return ResourceManager.GetString("SET_PASSWORD_DMA_and_SET_UNLOCK_DMA_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Simplified direct-access device. + /// + internal static string Simplified_direct_access_device { + get { + return ResourceManager.GetString("Simplified_direct_access_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Single-word DMA: . + /// + internal static string Single_word_DMA { + get { + return ResourceManager.GetString("Single_word_DMA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Skip time interval assignment {0} says that from {1:D2}:{2:D2}:{3:D2} to {4:D2}:{5:D2}:{6:D2} should be skipped. + /// + internal static string Skip_time_interval_assignment_0_says_that_from_1_2_3_to_4_5_6_should_be_skipped { + get { + return ResourceManager.GetString("Skip_time_interval_assignment_0_says_that_from_1_2_3_to_4_5_6_should_be_skipped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Skip time interval assignment {0} says that from {4}:{1:D2}:{2:D2}:{3:D2} to {8}:{5:D2}:{6:D2}:{7:D2} should be skipped. + /// + internal static string Skip_time_interval_assignment_0_says_that_from_4_1_2_3_to_8_5_6_7_should_be_skipped { + get { + return ResourceManager.GetString("Skip_time_interval_assignment_0_says_that_from_4_1_2_3_to_8_5_6_7_should_be_skipp" + + "ed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Skip track {0}. + /// + internal static string Skip_track_0 { + get { + return ResourceManager.GetString("Skip_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Skip track assignment {0} says that tracks {1} should be skipped. + /// + internal static string Skip_track_assignment_0_says_that_tracks_1_should_be_skipped { + get { + return ResourceManager.GetString("Skip_track_assignment_0_says_that_tracks_1_should_be_skipped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLR-32 SL. + /// + internal static string SLR32SL { + get { + return ResourceManager.GetString("SLR32SL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLR40, SLR60 or SLR100. + /// + internal static string SLR40_60_100 { + get { + return ResourceManager.GetString("SLR40_60_100", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SLR-5 SL. + /// + internal static string SLR5SL { + get { + return ResourceManager.GetString("SLR5SL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to S.M.A.R.T. Command Transport is supported. + /// + internal static string SMART_Command_Transport_is_supported { + get { + return ResourceManager.GetString("SMART_Command_Transport_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to S.M.A.R.T. Command Transport (SCT):. + /// + internal static string SMART_Command_Transport_SCT { + get { + return ResourceManager.GetString("SMART_Command_Transport_SCT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to S.M.A.R.T. error logging is supported. + /// + internal static string SMART_error_logging_is_supported { + get { + return ResourceManager.GetString("SMART_error_logging_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to S.M.A.R.T. error logging is supported and enabled. + /// + internal static string SMART_error_logging_is_supported_and_enabled { + get { + return ResourceManager.GetString("SMART_error_logging_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to S.M.A.R.T. is supported. + /// + internal static string SMART_is_supported { + get { + return ResourceManager.GetString("SMART_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to S.M.A.R.T. is supported and enabled. + /// + internal static string SMART_is_supported_and_enabled { + get { + return ResourceManager.GetString("SMART_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to S.M.A.R.T. self-testing is supported. + /// + internal static string SMART_self_testing_is_supported { + get { + return ResourceManager.GetString("SMART_self_testing_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to S.M.A.R.T. self-testing is supported and enabled. + /// + internal static string SMART_self_testing_is_supported_and_enabled { + get { + return ResourceManager.GetString("SMART_self_testing_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Software Settings Preservation is supported. + /// + internal static string Software_Settings_Preservation_is_supported { + get { + return ResourceManager.GetString("Software_Settings_Preservation_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Software Settings Preservation is supported and enabled. + /// + internal static string Software_Settings_Preservation_is_supported_and_enabled { + get { + return ResourceManager.GetString("Software_Settings_Preservation_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Software write protect is enabled. + /// + internal static string Software_write_protect_is_enabled { + get { + return ResourceManager.GetString("Software_write_protect_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Software write protection is set until power down. + /// + internal static string Software_write_protection_is_set_until_power_down { + get { + return ResourceManager.GetString("Software_write_protection_is_set_until_power_down", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Spare Area Full Flags: 0x{0:X2}. + /// + internal static string Spare_Area_Full_Flags_0 { + get { + return ResourceManager.GetString("Spare_Area_Full_Flags_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found incorrect Blu-ray Spare Area Information size ({0} bytes). + /// + internal static string Spare_Decode_Found_incorrect_Blu_ray_Spare_Area_Information_size_0_bytes { + get { + return ResourceManager.GetString("Spare_Decode_Found_incorrect_Blu_ray_Spare_Area_Information_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Spindle motor control is implemented. + /// + internal static string Spindle_motor_control_is_implemented { + get { + return ResourceManager.GetString("Spindle_motor_control_is_implemented", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Spindle synchronization is disabled or unsupported. + /// + internal static string Spindle_synchronization_is_disabled_or_unsupported { + get { + return ResourceManager.GetString("Spindle_synchronization_is_disabled_or_unsupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SSA. + /// + internal static string SSA { + get { + return ResourceManager.GetString("SSA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Standby time values are standard. + /// + internal static string Standby_time_values_are_standard { + get { + return ResourceManager.GetString("Standby_time_values_are_standard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start of next possible program in the recordable area of the disc: {0:D2}:{1:D2}:{2:D2}. + /// + internal static string Start_of_next_possible_program_in_the_recordable_area_of_the_disc_0_1_2 { + get { + return ResourceManager.GetString("Start_of_next_possible_program_in_the_recordable_area_of_the_disc_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start of next possible program in the recordable area of the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2}. + /// + internal static string Start_of_next_possible_program_in_the_recordable_area_of_the_disc_3_0_1_2 { + get { + return ResourceManager.GetString("Start_of_next_possible_program_in_the_recordable_area_of_the_disc_3_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start position of outer part lead-in area: {0:D2}:{1:D2}:{2:D2}. + /// + internal static string Start_position_of_outer_part_lead_in_area_0_1_2 { + get { + return ResourceManager.GetString("Start_position_of_outer_part_lead_in_area_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start position of outer part lead-in area: {3:D2}:{0:D2}:{1:D2}:{2:D2}. + /// + internal static string Start_position_of_outer_part_lead_in_area_3_0_1_2 { + get { + return ResourceManager.GetString("Start_position_of_outer_part_lead_in_area_3_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start time for interval that should be skipped: {0:D2}:{1:D2}:{2:D2}. + /// + internal static string Start_time_for_interval_that_should_be_skipped_0_1_2 { + get { + return ResourceManager.GetString("Start_time_for_interval_that_should_be_skipped_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start time of the first Lead-in area in the disc: {0:D2}:{1:D2}:{2:D2}. + /// + internal static string Start_time_of_the_first_Lead_in_area_in_the_disc_0_1_2 { + get { + return ResourceManager.GetString("Start_time_of_the_first_Lead_in_area_in_the_disc_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start time of the first Lead-in area in the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2}. + /// + internal static string Start_time_of_the_first_Lead_in_area_in_the_disc_3_0_1_2 { + get { + return ResourceManager.GetString("Start_time_of_the_first_Lead_in_area_in_the_disc_3_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stereo audio track with 50/15 μs pre-emphasis. + /// + internal static string Stereo_audio_track_with_50_15_us_pre_emphasis { + get { + return ResourceManager.GetString("Stereo_audio_track_with_50_15_us_pre_emphasis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stereo audio track with no pre-emphasis. + /// + internal static string Stereo_audio_track_with_no_pre_emphasis { + get { + return ResourceManager.GetString("Stereo_audio_track_with_no_pre_emphasis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stop position of inner part lead-out area: {0:D2}:{1:D2}:{2:D2}. + /// + internal static string Stop_position_of_inner_part_lead_out_area_0_1_2 { + get { + return ResourceManager.GetString("Stop_position_of_inner_part_lead_out_area_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stop position of inner part lead-out area: {3:D2}:{0:D2}:{1:D2}:{2:D2}. + /// + internal static string Stop_position_of_inner_part_lead_out_area_3_0_1_2 { + get { + return ResourceManager.GetString("Stop_position_of_inner_part_lead_out_area_3_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Streaming:. + /// + internal static string Streaming { + get { + return ResourceManager.GetString("Streaming", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Streaming access latency is {0}. + /// + internal static string Streaming_access_latency_is_0 { + get { + return ResourceManager.GetString("Streaming_access_latency_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Streaming feature set is supported. + /// + internal static string Streaming_feature_set_is_supported { + get { + return ResourceManager.GetString("Streaming_feature_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Streaming feature set is supported and enabled. + /// + internal static string Streaming_feature_set_is_supported_and_enabled { + get { + return ResourceManager.GetString("Streaming_feature_set_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Streaming performance granularity is {0}. + /// + internal static string Streaming_performance_granularity_is_0 { + get { + return ResourceManager.GetString("Streaming_performance_granularity_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Streaming transfer time in DMA is {0}. + /// + internal static string Streaming_transfer_time_in_DMA_is_0 { + get { + return ResourceManager.GetString("Streaming_transfer_time_in_DMA_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Streaming transfer time in PIO is {0}. + /// + internal static string Streaming_transfer_time_in_PIO_is_0 { + get { + return ResourceManager.GetString("Streaming_transfer_time_in_PIO_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q: {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} {13:X2} {14:X2} {15:X2} {16:X2} {17:X2} CRC 0x{18:X2}{19:X2} ({20}), R-W {21}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_8_9_10_11_12_13_14_15_16_17_CRC_18_19_20_R_W_21 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_8_9_10_11_12_13_14_15_16_17_CRC_1" + + "8_19_20_R_W_21", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8}, {9} skip interval pointers, {10} skip track assignments, CRC 0x{11:X2}{12:X2} ({13}), R-W {14}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_9_skip_interval_pointers_10_skip_track_assignments_CRC_11_12_13_R_W_14 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_9_skip_interval_pointers_1" + + "0_skip_track_assignments_CRC_11_12_13_R_W_14", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8}, ATIP values {9:X2}, {10:X2}, {11:X2}, first disc Lead-in starts at {12:X2}{13:X2}{14:X2} (LBA {15}), CRC 0x{16:X2}{17:X2} ({18}), R-W {19}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_ATIP_values_9_10_11_first_disc_Lead_in_starts_at_12_13_14_LBA_15_CRC_16_17_18_R_W_19 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_ATIP_values_9_10_11_first_" + + "disc_Lead_in_starts_at_12_13_14_LBA_15_CRC_16_17_18_R_W_19", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} ISRC: {9} frame {10:X2} CRC 0x{11:X2}{12:X2} ({13}), R-W {14}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_ISRC_9_frame_10_CRC_11_12_13_R_W_14 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_ISRC_9_frame_10_CRC_11_12_" + + "13_R_W_14", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} MCN: {9} frame {10:X2} CRC 0x{11:X2}{12:X2} ({13}), R-W {14}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_MCN_9_frame_10_CRC_11_12_13_R_W_14 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_MCN_9_frame_10_CRC_11_12_1" + + "3_R_W_14", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} next program area can start at {9:X2}:{10:X2}:{11:X2} (LBA {12}), last-session, {13} mode 5 pointers, CRC 0x{14:X2}{15:X2} ({16}), R-W {17}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_next_program_area_can_start_at_9_10_11_LBA_12_last_session_13_mode_5_pointers_CRC_14_15_16_R_W_17 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_next_program_area_can_star" + + "t_at_9_10_11_LBA_12_last_session_13_mode_5_pointers_CRC_14_15_16_R_W_17", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} next program area can start at {9:X2}:{10:X2}:{11:X2} (LBA {12}), maximum Lead-out at {13:X2}:{14:X2}:{15:X2} (LBA {16}), {17} mode 5 pointers, CRC 0x{18:X2}{19:X2} ({20}), R-W {21}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_next_program_area_can_start_at_9_10_11_LBA_12_maximum_Lead_out_at_13_14_15_LBA_16_17_mode_5_pointers_CRC_18_19_20_R_W_21 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_next_program_area_can_star" + + "t_at_9_10_11_LBA_12_maximum_Lead_out_at_13_14_15_LBA_16_17_mode_5_pointers_CRC_1" + + "8_19_20_R_W_21", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} position: {9:X2}:{10:X2}:{11:X2} (LBA {12}), track {13:X} is first program area track in {14} format, Q CRC 0x{15:X2}{16:X2} ({17}), R-W {18}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_9_10_11_LBA_12_track_13_is_first_program_area_track_in_14_format_Q_CRC_15_16_17_R_W_18 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_9_10_11_LBA_12_tr" + + "ack_13_is_first_program_area_track_in_14_format_Q_CRC_15_16_17_R_W_18", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} position: {9:X2}:{10:X2}:{11:X2} (LBA {12}), track {13:X} is last program area track, Q CRC 0x{14:X2}{15:X2} ({16}), R-W {17}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_9_10_11_LBA_12_track_13_is_last_program_area_track_Q_CRC_14_15_16_R_W_17 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_9_10_11_LBA_12_tr" + + "ack_13_is_last_program_area_track_Q_CRC_14_15_16_R_W_17", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} position: {9:X2}:{10:X2}:{11:X2} (LBA {12}), track {13:X} starts at {14:X2}:{15:X2}:{16:X2} (LBA {17}), Q CRC 0x{18:X2}{19:X2} ({20}), R-W {21}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_9_10_11_LBA_12_track_13_starts_at_14_15_16_LBA_17_Q_CRC_18_19_20_R_W_21 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_9_10_11_LBA_12_tr" + + "ack_13_starts_at_14_15_16_LBA_17_Q_CRC_18_19_20_R_W_21", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} skip interval start time {9:X2}{10:X2}{11:X2}, skip interval stop time {12:X2}{13:X2}{14:X2}, CRC 0x{15:X2}{16:X2} ({17}), R-W {18}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_skip_interval_start_time_9_10_11_skip_interval_stop_time_12_13_14_CRC_15_16_17_R_W_18 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_skip_interval_start_time_9" + + "_10_11_skip_interval_stop_time_12_13_14_CRC_15_16_17_R_W_18", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8}, tracks {9} to be skipped, CRC 0x{10:X2}{11:X2} ({12}), R-W {13}. + /// + internal static string Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_tracks_9_to_be_skipped_CRC_10_11_12_R_W_13 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_1_2_LBA_3_4_area_5_6_7_Q_mode_8_tracks_9_to_be_skipped_CRC" + + "_10_11_12_R_W_13", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} position: track {9:X} index {10:X} relative position {11:X2}:{12:X2}:{13:X2} (LBA {14}), absolute position {15:X2}:{16:X2}:{17:X2} (LBA {18}), Q CRC 0x{19:X2}{20:X2} ({21}), R-W {22}. + /// + internal static string Subchannel_PrettifyQ_0_D2_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_track_9_index_10_relative_position_11_12_13_LBA_14_absolute_position_15_16_17_LBA_18_Q_CRC_19_20_21_R_W_22 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_0_D2_1_2_LBA_3_4_area_5_6_7_Q_mode_8_position_track_9_index_" + + "10_relative_position_11_12_13_LBA_14_absolute_position_15_16_17_LBA_18_Q_CRC_19_" + + "20_21_R_W_22", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BAD. + /// + internal static string Subchannel_PrettifyQ_BAD { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_BAD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-DA / CD-ROM. + /// + internal static string Subchannel_PrettifyQ_CD_DA_CD_ROM { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_CD_DA_CD_ROM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-i. + /// + internal static string Subchannel_PrettifyQ_CD_i { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_CD_i", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-ROM XA. + /// + internal static string Subchannel_PrettifyQ_CD_ROM_XA { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_CD_ROM_XA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to copy permitted. + /// + internal static string Subchannel_PrettifyQ_copy_permitted { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_copy_permitted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to copy prohibited. + /// + internal static string Subchannel_PrettifyQ_copy_prohibited { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_copy_prohibited", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to corrupted pause. + /// + internal static string Subchannel_PrettifyQ_corrupted_pause { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_corrupted_pause", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to empty. + /// + internal static string Subchannel_PrettifyQ_empty { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_empty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to incremental data. + /// + internal static string Subchannel_PrettifyQ_incremental_data { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_incremental_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lead-In. + /// + internal static string Subchannel_PrettifyQ_Lead_In { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_Lead_In", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lead-Out. + /// + internal static string Subchannel_PrettifyQ_Lead_out { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_Lead_out", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to not empty. + /// + internal static string Subchannel_PrettifyQ_not_empty { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_not_empty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to not pause. + /// + internal static string Subchannel_PrettifyQ_not_pause { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_not_pause", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OK. + /// + internal static string Subchannel_PrettifyQ_OK { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_OK", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to pause. + /// + internal static string Subchannel_PrettifyQ_pause { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_pause", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Program. + /// + internal static string Subchannel_PrettifyQ_Program { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_Program", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to quadraphonic audio with pre-emphasis. + /// + internal static string Subchannel_PrettifyQ_quadraphonic_audio_with_pre_emphasis { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_quadraphonic_audio_with_pre_emphasis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to quadraphonic audio without pre-emphasis. + /// + internal static string Subchannel_PrettifyQ_quadraphonic_audio_without_pre_emphasis { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_quadraphonic_audio_without_pre_emphasis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to reserved control value {0}. + /// + internal static string Subchannel_PrettifyQ_reserved_control_value__0_ { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_reserved_control_value__0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to stereo audio with pre-emphasis. + /// + internal static string Subchannel_PrettifyQ_stereo_audio_with_pre_emphasis { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_stereo_audio_with_pre_emphasis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to stereo audio without pre-emphasis. + /// + internal static string Subchannel_PrettifyQ_stereo_audio_without_pre_emphasis { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_stereo_audio_without_pre_emphasis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to uninterrupted data. + /// + internal static string Subchannel_PrettifyQ_uninterrupted_data { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_uninterrupted_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown {0:X2}. + /// + internal static string Subchannel_PrettifyQ_unknown_0 { + get { + return ResourceManager.GetString("Subchannel_PrettifyQ_unknown_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Subheader copies differ.. + /// + internal static string Subheader_copies_differ { + get { + return ResourceManager.GetString("Subheader_copies_differ", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supported ATA versions: . + /// + internal static string Supported_ATA_versions { + get { + return ResourceManager.GetString("Supported_ATA_versions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supported medium type four: {0}. + /// + internal static string Supported_medium_type_four_0 { + get { + return ResourceManager.GetString("Supported_medium_type_four_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supported medium type one: {0}. + /// + internal static string Supported_medium_type_one_0 { + get { + return ResourceManager.GetString("Supported_medium_type_one_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supported medium type three: {0}. + /// + internal static string Supported_medium_type_three_0 { + get { + return ResourceManager.GetString("Supported_medium_type_three_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supported medium type two: {0}. + /// + internal static string Supported_medium_type_two_0 { + get { + return ResourceManager.GetString("Supported_medium_type_two_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supported operating definitions:. + /// + internal static string Supported_operating_definitions { + get { + return ResourceManager.GetString("Supported_operating_definitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supports block lengths and protection information. + /// + internal static string Supports_block_lengths_and_protection_information { + get { + return ResourceManager.GetString("Supports_block_lengths_and_protection_information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supports device automatic partial to slumber transitions is supported. + /// + internal static string Supports_device_automatic_partial_to_slumber_transitions_is_supported { + get { + return ResourceManager.GetString("Supports_device_automatic_partial_to_slumber_transitions_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supports enhanced security erase. + /// + internal static string Supports_enhanced_security_erase { + get { + return ResourceManager.GetString("Supports_enhanced_security_erase", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supports host automatic partial to slumber transitions is supported. + /// + internal static string Supports_host_automatic_partial_to_slumber_transitions_is_supported { + get { + return ResourceManager.GetString("Supports_host_automatic_partial_to_slumber_transitions_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System name: {0}. + /// + internal static string System_name_0 { + get { + return ResourceManager.GetString("System_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System program address: 0x{0:X8}. + /// + internal static string System_program_address_0 { + get { + return ResourceManager.GetString("System_program_address_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System program entry address: 0x{0:X8}. + /// + internal static string System_program_entry_address_0 { + get { + return ResourceManager.GetString("System_program_entry_address_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System program load size: {0} bytes. + /// + internal static string System_program_load_size_0 { + get { + return ResourceManager.GetString("System_program_load_size_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System program work RAM: {0} bytes. + /// + internal static string System_program_work_RAM_0 { + get { + return ResourceManager.GetString("System_program_work_RAM_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to T10000A. + /// + internal static string T10000A { + get { + return ResourceManager.GetString("T10000A", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to T10000B. + /// + internal static string T10000B { + get { + return ResourceManager.GetString("T10000B", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to T10000C. + /// + internal static string T10000C { + get { + return ResourceManager.GetString("T10000C", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to T10000D. + /// + internal static string T10000D { + get { + return ResourceManager.GetString("T10000D", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to T9840C. + /// + internal static string T9840C { + get { + return ResourceManager.GetString("T9840C", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to T9940. + /// + internal static string T9940 { + get { + return ResourceManager.GetString("T9940", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tag resources size is {0}.. + /// + internal static string Tag_resources_size_is_0 { + get { + return ResourceManager.GetString("Tag_resources_size_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tagged queuing is disabled. + /// + internal static string Tagged_queuing_is_disabled { + get { + return ResourceManager.GetString("Tagged_queuing_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tags must be in units of {0} sectors. + /// + internal static string Tags_must_be_in_units_of_0_sectors { + get { + return ResourceManager.GetString("Tags_must_be_in_units_of_0_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tape directory format version: {0}. + /// + internal static string Tape_directory_format_version_0 { + get { + return ResourceManager.GetString("Tape_directory_format_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tape will be unthreaded. + /// + internal static string Tape_will_be_unthreaded { + get { + return ResourceManager.GetString("Tape_will_be_unthreaded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tape will be unthreaded and unloaded. + /// + internal static string Tape_will_be_unthreaded_and_unloaded { + get { + return ResourceManager.GetString("Tape_will_be_unthreaded_and_unloaded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tape will stay threaded at beginning. + /// + internal static string Tape_will_stay_threaded_at_beginning { + get { + return ResourceManager.GetString("Tape_will_stay_threaded_at_beginning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mammoth. + /// + internal static string TapeName_Mammoth { + get { + return ResourceManager.GetString("TapeName_Mammoth", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target-dependent interleave value is {0}. + /// + internal static string Target_dependent_interleave_value_is_0 { + get { + return ResourceManager.GetString("Target_dependent_interleave_value_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target group identifier: {0}. + /// + internal static string Target_group_identifier_0 { + get { + return ResourceManager.GetString("Target_group_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target is allowed to re-order the data transfer. + /// + internal static string Target_is_allowed_to_reorder_the_data_transfer { + get { + return ResourceManager.GetString("Target_is_allowed_to_reorder_the_data_transfer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target may issue an asynchronous event notification instead of a deferred error. + /// + internal static string Target_may_issue_an_asynchronous_event_notification_instead_of_a_deferred_error { + get { + return ResourceManager.GetString("Target_may_issue_an_asynchronous_event_notification_instead_of_a_deferred_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target may issue an asynchronous event notification instead of a unit attention condition. + /// + internal static string Target_may_issue_an_asynchronous_event_notification_instead_of_a_unit_attention_condition { + get { + return ResourceManager.GetString("Target_may_issue_an_asynchronous_event_notification_instead_of_a_unit_attention_c" + + "ondition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target may issue an asynchronous event notification upon completing its initialization. + /// + internal static string Target_may_issue_an_asynchronous_event_notification_upon_completing_its_initialization { + get { + return ResourceManager.GetString("Target_may_issue_an_asynchronous_event_notification_upon_completing_its_initializ" + + "ation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target operates as a synchronized-spindle master. + /// + internal static string Target_operates_as_a_synchronized_spindle_master { + get { + return ResourceManager.GetString("Target_operates_as_a_synchronized_spindle_master", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target operates as a synchronized-spindle master control. + /// + internal static string Target_operates_as_a_synchronized_spindle_master_control { + get { + return ResourceManager.GetString("Target_operates_as_a_synchronized_spindle_master_control", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target operates as a synchronized-spindle slave. + /// + internal static string Target_operates_as_a_synchronized_spindle_slave { + get { + return ResourceManager.GetString("Target_operates_as_a_synchronized_spindle_slave", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target shall never release the motor on signal. + /// + internal static string Target_shall_never_release_the_motor_on_signal { + get { + return ResourceManager.GetString("Target_shall_never_release_the_motor_on_signal", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target shall not transfer data for a command during the same interconnect tenancy. + /// + internal static string Target_shall_not_transfer_data_for_a_command_during_the_same_interconnect_tenancy { + get { + return ResourceManager.GetString("Target_shall_not_transfer_data_for_a_command_during_the_same_interconnect_tenancy" + + "", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target shall wait {0} seconds after drive is ready before aborting medium access attempts. + /// + internal static string Target_shall_wait_0_seconds_after_drive_is_ready_before_aborting_medium_access_attempts { + get { + return ResourceManager.GetString("Target_shall_wait_0_seconds_after_drive_is_ready_before_aborting_medium_access_at" + + "tempts", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target shall wait {0} seconds before attempting to access the medium after motor on is asserted. + /// + internal static string Target_shall_wait_0_seconds_before_attempting_to_access_the_medium_after_motor_on_is_asserted { + get { + return ResourceManager.GetString("Target_shall_wait_0_seconds_before_attempting_to_access_the_medium_after_motor_on" + + "_is_asserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target shall wait {0} seconds before releasing the motor on signal after becoming idle. + /// + internal static string Target_shall_wait_0_seconds_before_releasing_the_motor_on_signal_after_becoming_idle { + get { + return ResourceManager.GetString("Target_shall_wait_0_seconds_before_releasing_the_motor_on_signal_after_becoming_i" + + "dle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tasks aborted by other initiator's actions should be terminated with TASK ABORTED. + /// + internal static string Tasks_aborted_by_other_initiator_s_actions_should_be_terminated_with_TASK_ABORTED { + get { + return ResourceManager.GetString("Tasks_aborted_by_other_initiator_s_actions_should_be_terminated_with_TASK_ABORTED" + + "", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test write operation is restricted during read or write operations.. + /// + internal static string Test_write_operation_is_restricted_during_read_or_write_operations { + get { + return ResourceManager.GetString("Test_write_operation_is_restricted_during_read_or_write_operations", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Text field: "{0}". + /// + internal static string Text_field_0 { + get { + return ResourceManager.GetString("Text_field_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The device type that would be provided in the INQUIRY response is {0}. + /// + internal static string The_device_type_that_would_be_provided_in_the_INQUIRY_response_is_0 { + get { + return ResourceManager.GetString("The_device_type_that_would_be_provided_in_the_INQUIRY_response_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The Logical Unit does not enforce Region Playback Controls (RPC).. + /// + internal static string The_Logical_Unit_does_not_enforce_Region_Playback_Controls_RPC { + get { + return ResourceManager.GetString("The_Logical_Unit_does_not_enforce_Region_Playback_Controls_RPC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The logical unit maintains one task set for all nexuses. + /// + internal static string The_logical_unit_maintains_one_task_set_for_all_nexuses { + get { + return ResourceManager.GetString("The_logical_unit_maintains_one_task_set_for_all_nexuses", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The logical unit maintains separate task sets for each nexus. + /// + internal static string The_logical_unit_maintains_separate_task_sets_for_each_nexus { + get { + return ResourceManager.GetString("The_logical_unit_maintains_separate_task_sets_for_each_nexus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The Logical Unit shall adhere to the specification and all requirements of the CSS license agreement concerning RPC.. + /// + internal static string The_Logical_Unit_shall_adhere_to_the_specification_and_all_requirements_of_the_CSS_license_agreement_concerning_RPC { + get { + return ResourceManager.GetString("The_Logical_Unit_shall_adhere_to_the_specification_and_all_requirements_of_the_CS" + + "S_license_agreement_concerning_RPC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The Logical Unit uses an unknown region enforcement scheme.. + /// + internal static string The_Logical_Unit_uses_an_unknown_region_enforcement_scheme { + get { + return ResourceManager.GetString("The_Logical_Unit_uses_an_unknown_region_enforcement_scheme", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The motor on signal shall remain released. + /// + internal static string The_motor_on_signal_shall_remain_released { + get { + return ResourceManager.GetString("The_motor_on_signal_shall_remain_released", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are {0} blocks per each second of audio. + /// + internal static string There_are_0_blocks_per_each_second_of_audio { + get { + return ResourceManager.GetString("There_are_0_blocks_per_each_second_of_audio", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are {0} per block. + /// + internal static string There_are_0_per_block { + get { + return ResourceManager.GetString("There_are_0_per_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are commands pending to be forwarded. + /// + internal static string There_are_commands_pending_to_be_forwarded { + get { + return ResourceManager.GetString("There_are_commands_pending_to_be_forwarded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are no addresses. + /// + internal static string There_are_no_addresses { + get { + return ResourceManager.GetString("There_are_no_addresses", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are no identifiers. + /// + internal static string There_are_no_identifiers { + get { + return ResourceManager.GetString("There_are_no_identifiers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are no supported definitions. + /// + internal static string There_are_no_supported_definitions { + get { + return ResourceManager.GetString("There_are_no_supported_definitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is a drive ready signal. + /// + internal static string There_is_a_drive_ready_signal { + get { + return ResourceManager.GetString("There_is_a_drive_ready_signal", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is access to general purpose partition {0}. + /// + internal static string There_is_access_to_general_purpose_partition_0 { + get { + return ResourceManager.GetString("There_is_access_to_general_purpose_partition_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is no access to boot partition. + /// + internal static string There_is_no_access_to_boot_partition { + get { + return ResourceManager.GetString("There_is_no_access_to_boot_partition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is no cartridge inserted. + /// + internal static string There_is_no_cartridge_inserted { + get { + return ResourceManager.GetString("There_is_no_cartridge_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is no limit on the maximum time that is allowed to remain busy. + /// + internal static string There_is_no_limit_on_the_maximum_time_that_is_allowed_to_remain_busy { + get { + return ResourceManager.GetString("There_is_no_limit_on_the_maximum_time_that_is_allowed_to_remain_busy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is read/write access to boot partition 1. + /// + internal static string There_is_read_write_access_to_boot_partition_one { + get { + return ResourceManager.GetString("There_is_read_write_access_to_boot_partition_one", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is read/write access to boot partition 2. + /// + internal static string There_is_read_write_access_to_boot_partition_two { + get { + return ResourceManager.GetString("There_is_read_write_access_to_boot_partition_two", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is read/write access to replay protected memory block. + /// + internal static string There_is_read_write_access_to_replay_protected_memory_block { + get { + return ResourceManager.GetString("There_is_read_write_access_to_replay_protected_memory_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Third run-in block. + /// + internal static string Third_run_in_block { + get { + return ResourceManager.GetString("Third_run_in_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This descriptor is duplicated. + /// + internal static string This_descriptor_is_duplicated { + get { + return ResourceManager.GetString("This_descriptor_is_duplicated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This DI continues previous unit. + /// + internal static string This_DI_continues_previous_unit { + get { + return ResourceManager.GetString("This_DI_continues_previous_unit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This DI refers to layer {0}. + /// + internal static string This_DI_refers_to_layer_0 { + get { + return ResourceManager.GetString("This_DI_refers_to_layer_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This DI starts a new unit. + /// + internal static string This_DI_starts_a_new_unit { + get { + return ResourceManager.GetString("This_DI_starts_a_new_unit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This disc contains a CD-R layer.. + /// + internal static string This_disc_contains_a_CD_R_layer { + get { + return ResourceManager.GetString("This_disc_contains_a_CD_R_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This disc contains a CD-ROM layer.. + /// + internal static string This_disc_contains_a_CD_ROM_layer { + get { + return ResourceManager.GetString("This_disc_contains_a_CD_ROM_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This disc contains a CD-RW layer.. + /// + internal static string This_disc_contains_a_CD_RW_layer { + get { + return ResourceManager.GetString("This_disc_contains_a_CD_RW_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This disc contains a DVD-R layer.. + /// + internal static string This_disc_contains_a_DVD_R_layer { + get { + return ResourceManager.GetString("This_disc_contains_a_DVD_R_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This disc contains a DVD-ROM layer.. + /// + internal static string This_disc_contains_a_DVD_ROM_layer { + get { + return ResourceManager.GetString("This_disc_contains_a_DVD_ROM_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This disc contains a DVD-RW layer.. + /// + internal static string This_disc_contains_a_DVD_RW_layer { + get { + return ResourceManager.GetString("This_disc_contains_a_DVD_RW_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This disc does not contain a CD layer.. + /// + internal static string This_disc_does_not_contain_a_CD_layer { + get { + return ResourceManager.GetString("This_disc_does_not_contain_a_CD_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This disc does not contain a DVD layer.. + /// + internal static string This_disc_does_not_contain_a_DVD_layer { + get { + return ResourceManager.GetString("This_disc_does_not_contain_a_DVD_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This disc has {0} layers. + /// + internal static string This_disc_has_0_layers { + get { + return ResourceManager.GetString("This_disc_has_0_layers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is the default density on the drive. + /// + internal static string This_is_the_default_density_on_the_drive { + get { + return ResourceManager.GetString("This_is_the_default_density_on_the_drive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is the default layer.. + /// + internal static string This_is_the_default_layer { + get { + return ResourceManager.GetString("This_is_the_default_layer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is the layer actually in use.. + /// + internal static string This_is_the_layer_actually_in_use { + get { + return ResourceManager.GetString("This_is_the_layer_actually_in_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Timer interval is {0} ms. + /// + internal static string Timer_interval_is_0_ms { + get { + return ResourceManager.GetString("Timer_interval_is_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Timer interval is vendor-specific. + /// + internal static string Timer_interval_is_vendor_specific { + get { + return ResourceManager.GetString("Timer_interval_is_vendor_specific", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Timestamp: {0}. + /// + internal static string Timestamp_0 { + get { + return ResourceManager.GetString("Timestamp_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Timestamp can be initialized by methods outside of the SCSI standards. + /// + internal static string Timestamp_can_be_initialized_by_methods_outside_of_the_SCSI_standards { + get { + return ResourceManager.GetString("Timestamp_can_be_initialized_by_methods_outside_of_the_SCSI_standards", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Total number of CPRM Media Key Blocks available to transfer: {0}. + /// + internal static string Total_number_of_CPRM_Media_Key_Blocks_available_to_transfer_0 { + get { + return ResourceManager.GetString("Total_number_of_CPRM_Media_Key_Blocks_available_to_transfer_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Total number of media key blocks available to transfer {0}. + /// + internal static string Total_number_of_media_key_blocks_available_to_transfer_0 { + get { + return ResourceManager.GetString("Total_number_of_media_key_blocks_available_to_transfer_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to track {0}. + /// + internal static string track_0 { + get { + return ResourceManager.GetString("track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Data track, recorded incrementally) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2}. + /// + internal static string Track_0_Data_track_recorded_incrementally_starts_at_1_2_3_and_ends_at_4_5_6 { + get { + return ResourceManager.GetString("Track_0_Data_track_recorded_incrementally_starts_at_1_2_3_and_ends_at_4_5_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Data track, recorded incrementally) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2}. + /// + internal static string Track_0_Data_track_recorded_incrementally_starts_at_4_1_2_3_and_ends_at_8_5_6_7 { + get { + return ResourceManager.GetString("Track_0_Data_track_recorded_incrementally_starts_at_4_1_2_3_and_ends_at_8_5_6_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Data track, recorded uninterrupted) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2}. + /// + internal static string Track_0_Data_track_recorded_uninterrupted_starts_at_1_2_3_and_ends_at_4_5_6 { + get { + return ResourceManager.GetString("Track_0_Data_track_recorded_uninterrupted_starts_at_1_2_3_and_ends_at_4_5_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Data track, recorded uninterrupted) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2}. + /// + internal static string Track_0_Data_track_recorded_uninterrupted_starts_at_4_1_2_3_and_ends_at_8_5_6_7 { + get { + return ResourceManager.GetString("Track_0_Data_track_recorded_uninterrupted_starts_at_4_1_2_3_and_ends_at_8_5_6_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Quadraphonic audio track with 50/15 μs pre-emphasis) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2}. + /// + internal static string Track_0_Quadraphonic_audio_track_with_50_15_us_pre_emphasis_starts_at_1_2_3_and_ends_at_4_5_6 { + get { + return ResourceManager.GetString("Track_0_Quadraphonic_audio_track_with_50_15_us_pre_emphasis_starts_at_1_2_3_and_e" + + "nds_at_4_5_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Quadraphonic audio track with 50/15 μs pre-emphasis) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2}. + /// + internal static string Track_0_Quadraphonic_audio_track_with_50_15_us_pre_emphasis_starts_at_4_1_2_3_and_ends_at_8_5_6_7 { + get { + return ResourceManager.GetString("Track_0_Quadraphonic_audio_track_with_50_15_us_pre_emphasis_starts_at_4_1_2_3_and" + + "_ends_at_8_5_6_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Quadraphonic audio track with no pre-emphasis) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2}. + /// + internal static string Track_0_Quadraphonic_audio_track_with_no_pre_emphasis_starts_at_1_2_3_and_ends_at_4_5_6 { + get { + return ResourceManager.GetString("Track_0_Quadraphonic_audio_track_with_no_pre_emphasis_starts_at_1_2_3_and_ends_at" + + "_4_5_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Quadraphonic audio track with no pre-emphasis) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2}. + /// + internal static string Track_0_Quadraphonic_audio_track_with_no_pre_emphasis_starts_at_4_1_2_3_and_ends_at_8_5_6_7 { + get { + return ResourceManager.GetString("Track_0_Quadraphonic_audio_track_with_no_pre_emphasis_starts_at_4_1_2_3_and_ends_" + + "at_8_5_6_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Stereo audio track with 50/15 μs pre-emphasis) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2}. + /// + internal static string Track_0_Stereo_audio_track_with_50_15_s_pre_emphasis_starts_at_4_1_2_3_and_ends_at_8_5_6_7 { + get { + return ResourceManager.GetString("Track_0_Stereo_audio_track_with_50_15_s_pre_emphasis_starts_at_4_1_2_3_and_ends_a" + + "t_8_5_6_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Stereo audio track with 50/15 μs pre-emphasis) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2}. + /// + internal static string Track_0_Stereo_audio_track_with_50_15_us_pre_emphasis_starts_at_1_2_3_and_ends_at_4_5_6 { + get { + return ResourceManager.GetString("Track_0_Stereo_audio_track_with_50_15_us_pre_emphasis_starts_at_1_2_3_and_ends_at" + + "_4_5_6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Stereo audio track with no pre-emphasis) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2}. + /// + internal static string Track_0_Stereo_audio_track_with_no_pre_emphasis_starts_at_1_2_3_and_ends_at_4_5_6 { + get { + return ResourceManager.GetString("Track_0_Stereo_audio_track_with_no_pre_emphasis_starts_at_1_2_3_and_ends_at_4_5_6" + + "", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track {0} (Stereo audio track with no pre-emphasis) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2}. + /// + internal static string Track_0_Stereo_audio_track_with_no_pre_emphasis_starts_at_4_1_2_3_and_ends_at_8_5_6_7 { + get { + return ResourceManager.GetString("Track_0_Stereo_audio_track_with_no_pre_emphasis_starts_at_4_1_2_3_and_ends_at_8_5" + + "_6_7", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track number: {0}. + /// + internal static string Track_number_0 { + get { + return ResourceManager.GetString("Track_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track number: Lead-Out. + /// + internal static string Track_number_Lead_Out { + get { + return ResourceManager.GetString("Track_number_Lead_Out", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track offset option is available. + /// + internal static string Track_offset_option_is_available { + get { + return ResourceManager.GetString("Track_offset_option_is_available", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track size is 0.34 μm. + /// + internal static string Track_size_is_0_34_μm { + get { + return ResourceManager.GetString("Track_size_is_0_34_μm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track size is 0.40 μm. + /// + internal static string Track_size_is_0_40_μm { + get { + return ResourceManager.GetString("Track_size_is_0_40_μm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track size is 0.615 μm. + /// + internal static string Track_size_is_0_615_μm { + get { + return ResourceManager.GetString("Track_size_is_0_615_μm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track size is 0.74 μm. + /// + internal static string Track_size_is_0_74_μm { + get { + return ResourceManager.GetString("Track_size_is_0_74_μm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track size is 0.80 μm. + /// + internal static string Track_size_is_0_80_μm { + get { + return ResourceManager.GetString("Track_size_is_0_80_μm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track starts at LBA {0}, or MSF {1:X2}:{2:X2}:{3:X2}. + /// + internal static string Track_starts_at_LBA_0_or_MSF_2_3 { + get { + return ResourceManager.GetString("Track_starts_at_LBA_0_or_MSF_2_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Transfer rate: {0} kbit/s. + /// + internal static string Transfer_rate_0_kbits { + get { + return ResourceManager.GetString("Transfer_rate_0_kbits", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Transfer will be terminated upon error detection. + /// + internal static string Transfer_will_be_terminated_upon_error_detection { + get { + return ResourceManager.GetString("Transfer_will_be_terminated_upon_error_detection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Translation layer name: {0}. + /// + internal static string Translation_layer_name_0 { + get { + return ResourceManager.GetString("Translation_layer_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Translation layer release level: {0}. + /// + internal static string Translation_layer_release_level_0 { + get { + return ResourceManager.GetString("Translation_layer_release_level_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Translation layer vendor: {0}. + /// + internal static string Translation_layer_vendor_0 { + get { + return ResourceManager.GetString("Translation_layer_vendor_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Travan 5. + /// + internal static string Travan5 { + get { + return ResourceManager.GetString("Travan5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tray closed or caddy inserted but medium error. + /// + internal static string Tray_closed_or_caddy_inserted_but_medium_error { + get { + return ResourceManager.GetString("Tray_closed_or_caddy_inserted_but_medium_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tray open or no caddy inserted. + /// + internal static string Tray_open_or_no_caddy_inserted { + get { + return ResourceManager.GetString("Tray_open_or_no_caddy_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trigger block.. + /// + internal static string Trigger_block { + get { + return ResourceManager.GetString("Trigger_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trusted Computing feature set is supported. + /// + internal static string Trusted_Computing_feature_set_is_supported { + get { + return ResourceManager.GetString("Trusted_Computing_feature_set_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ultra DMA: . + /// + internal static string Ultra_DMA { + get { + return ResourceManager.GetString("Ultra_DMA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unconditionally generate recovered error on informational exceptions. + /// + internal static string Unconditionally_generate_recovered_error_on_informational_exceptions { + get { + return ResourceManager.GetString("Unconditionally_generate_recovered_error_on_informational_exceptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unit is reserved by initiator ID {0:X16}. + /// + internal static string Unit_is_reserved_by_initiator_ID_0 { + get { + return ResourceManager.GetString("Unit_is_reserved_by_initiator_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MHz. + /// + internal static string unit_MHz { + get { + return ResourceManager.GetString("unit_MHz", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ms. + /// + internal static string unit_ms { + get { + return ResourceManager.GetString("unit_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ns. + /// + internal static string unit_ns { + get { + return ResourceManager.GetString("unit_ns", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown. + /// + internal static string unit_unknown { + get { + return ResourceManager.GetString("unit_unknown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to μs. + /// + internal static string unit_μs { + get { + return ResourceManager.GetString("unit_μs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to units. + /// + internal static string units { + get { + return ResourceManager.GetString("units", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to units of {0} bytes. + /// + internal static string units_of_0_bytes { + get { + return ResourceManager.GetString("units_of_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown ATA revision 0x{0:X4}. + /// + internal static string Unknown_ATA_revision_0 { + get { + return ResourceManager.GetString("Unknown_ATA_revision_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown ATAPI DRQ behaviour code {0}. + /// + internal static string Unknown_ATAPI_DRQ_behaviour_code_0 { + get { + return ResourceManager.GetString("Unknown_ATAPI_DRQ_behaviour_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown ATAPI packet size code {0}. + /// + internal static string Unknown_ATAPI_packet_size_code_0 { + get { + return ResourceManager.GetString("Unknown_ATAPI_packet_size_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown auto unload code {0}. + /// + internal static string Unknown_auto_unload_code_0 { + get { + return ResourceManager.GetString("Unknown_auto_unload_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown autoloading mode code {0}. + /// + internal static string Unknown_autoloading_mode_code_0 { + get { + return ResourceManager.GetString("Unknown_autoloading_mode_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown block device. + /// + internal static string Unknown_block_device { + get { + return ResourceManager.GetString("Unknown_block_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown boot condition for bus width with code 3.. + /// + internal static string Unknown_boot_condition_for_bus_width_with_code_three { + get { + return ResourceManager.GetString("Unknown_boot_condition_for_bus_width_with_code_three", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown buffered mode code 0x{0:X2}. + /// + internal static string Unknown_buffered_mode_code_0 { + get { + return ResourceManager.GetString("Unknown_buffered_mode_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown cartridge format code {0}. + /// + internal static string Unknown_cartridge_format_code_0 { + get { + return ResourceManager.GetString("Unknown_cartridge_format_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown cartridge type code {0}. + /// + internal static string Unknown_cartridge_type_code_0 { + get { + return ResourceManager.GetString("Unknown_cartridge_type_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown CD-R disc subtype: {0}. + /// + internal static string Unknown_CD_R_disc_subtype_0 { + get { + return ResourceManager.GetString("Unknown_CD_R_disc_subtype_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown CD-RW disc subtype: {0}. + /// + internal static string Unknown_CD_RW_disc_subtype_0 { + get { + return ResourceManager.GetString("Unknown_CD_RW_disc_subtype_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown cleaning behaviour code {0}. + /// + internal static string Unknown_cleaning_behaviour_code_0 { + get { + return ResourceManager.GetString("Unknown_cleaning_behaviour_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown code {0}. + /// + internal static string unknown_code_protocol_0 { + get { + return ResourceManager.GetString("unknown_code_protocol_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown command forwarding code {0}. + /// + internal static string Unknown_command_forwarding_code_0 { + get { + return ResourceManager.GetString("Unknown_command_forwarding_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown compression control code {0}. + /// + internal static string Unknown_compression_control_code_0 { + get { + return ResourceManager.GetString("Unknown_compression_control_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown data cartridge inserted. + /// + internal static string Unknown_data_cartridge_inserted { + get { + return ResourceManager.GetString("Unknown_data_cartridge_inserted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown demand read retention priority value {0}. + /// + internal static string Unknown_demand_read_retention_priority_value_0 { + get { + return ResourceManager.GetString("Unknown_demand_read_retention_priority_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown demand write retention priority value {0}. + /// + internal static string Unknown_demand_write_retention_priority_value_0 { + get { + return ResourceManager.GetString("Unknown_demand_write_retention_priority_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown density code 0x{0:X2}. + /// + internal static string unknown_density_code_0 { + get { + return ResourceManager.GetString("unknown_density_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown descriptor type {1} contains: {0}. + /// + internal static string Unknown_descriptor_type_1_contains_0 { + get { + return ResourceManager.GetString("Unknown_descriptor_type_1_contains_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown descriptor type {1} contains binary data (hex): {0}. + /// + internal static string Unknown_descriptor_type_1_contains_binary_data_hex_0 { + get { + return ResourceManager.GetString("Unknown_descriptor_type_1_contains_binary_data_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown device access mode {0}. + /// + internal static string Unknown_device_access_mode_0 { + get { + return ResourceManager.GetString("Unknown_device_access_mode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown device specific configuration 0x{0:X4}. + /// + internal static string Unknown_device_specific_configuration_0 { + get { + return ResourceManager.GetString("Unknown_device_specific_configuration_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown device type field value 0x{0:X2}. + /// + internal static string Unknown_device_type_field_value_0 { + get { + return ResourceManager.GetString("Unknown_device_type_field_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown disc type. + /// + internal static string unknown_disc_type { + get { + return ResourceManager.GetString("unknown_disc_type", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown disc type {0:X2}h. + /// + internal static string Unknown_disc_type_0 { + get { + return ResourceManager.GetString("Unknown_disc_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown disc type id {0}. + /// + internal static string Unknown_disc_type_id_0 { + get { + return ResourceManager.GetString("Unknown_disc_type_id_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown DVD-RAM case type key {0}. + /// + internal static string Unknown_DVD_RAM_case_type_key_0 { + get { + return ResourceManager.GetString("Unknown_DVD_RAM_case_type_key_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown enabled boot partition code {0}. + /// + internal static string Unknown_enabled_boot_partition_code_0 { + get { + return ResourceManager.GetString("Unknown_enabled_boot_partition_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown erased memory content code {0}. + /// + internal static string Unknown_erased_memory_content_code_0 { + get { + return ResourceManager.GetString("Unknown_erased_memory_content_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown factory test code {0}. + /// + internal static string Unknown_factory_test_code_0 { + get { + return ResourceManager.GetString("Unknown_factory_test_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown fence behaviour code {0}. + /// + internal static string Unknown_fence_behaviour_code_0 { + get { + return ResourceManager.GetString("Unknown_fence_behaviour_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown library interface baud rate code {0}. + /// + internal static string Unknown_library_interface_baud_rate_code_0 { + get { + return ResourceManager.GetString("Unknown_library_interface_baud_rate_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown manufacturer ID 0x{0:X2}. + /// + internal static string Unknown_manufacturer_ID_0 { + get { + return ResourceManager.GetString("Unknown_manufacturer_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown medium recognition code {0}. + /// + internal static string Unknown_medium_recognition_code_0 { + get { + return ResourceManager.GetString("Unknown_medium_recognition_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown medium type. + /// + internal static string Unknown_medium_type { + get { + return ResourceManager.GetString("Unknown_medium_type", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown medium type 0x{0:X2}. + /// + internal static string Unknown_medium_type_0 { + get { + return ResourceManager.GetString("Unknown_medium_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown method of reporting {0}. + /// + internal static string Unknown_method_of_reporting_0 { + get { + return ResourceManager.GetString("Unknown_method_of_reporting_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown or no device type. + /// + internal static string Unknown_or_no_device_type { + get { + return ResourceManager.GetString("Unknown_or_no_device_type", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown partition size unit code {0}. + /// + internal static string Unknown_partition_size_unit_code_0 { + get { + return ResourceManager.GetString("Unknown_partition_size_unit_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown pitch size key {0}. + /// + internal static string Unknown_pitch_size_key_0 { + get { + return ResourceManager.GetString("Unknown_pitch_size_key_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown port A transport type code {0}. + /// + internal static string Unknown_port_A_transport_type_code_0 { + get { + return ResourceManager.GetString("Unknown_port_A_transport_type_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown Power-On Self-Test code {0}. + /// + internal static string Unknown_Power_On_Self_Test_code_0 { + get { + return ResourceManager.GetString("Unknown_Power_On_Self_Test_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown Queue Algorithm Modifier {0}. + /// + internal static string Unknown_Queue_Algorithm_Modifier_0 { + get { + return ResourceManager.GetString("Unknown_Queue_Algorithm_Modifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown recovery parameter 0x{0:X2}. + /// + internal static string Unknown_recovery_parameter_0 { + get { + return ResourceManager.GetString("Unknown_recovery_parameter_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown reference velocity. + /// + internal static string Unknown_reference_velocity { + get { + return ResourceManager.GetString("Unknown_reference_velocity", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown register version {0}. + /// + internal static string Unknown_register_version_0 { + get { + return ResourceManager.GetString("Unknown_register_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown sense data behaviour code {0}. + /// + internal static string Unknown_sense_data_behaviour_code_0 { + get { + return ResourceManager.GetString("Unknown_sense_data_behaviour_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown size identifier {0}. + /// + internal static string unknown_size_identifier_0 { + get { + return ResourceManager.GetString("unknown_size_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown Task set type {0}. + /// + internal static string Unknown_Task_set_type_0 { + get { + return ResourceManager.GetString("Unknown_Task_set_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown TOC entry format, printing values as-is. + /// + internal static string Unknown_TOC_entry_format_printing_values_as_is { + get { + return ResourceManager.GetString("Unknown_TOC_entry_format_printing_values_as_is", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown track pitch. + /// + internal static string Unknown_track_pitch { + get { + return ResourceManager.GetString("Unknown_track_pitch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown track size key {0}. + /// + internal static string Unknown_track_size_key__0_ { + get { + return ResourceManager.GetString("Unknown_track_size_key__0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown transport type 0x{0:X1}. + /// + internal static string Unknown_transport_type_0 { + get { + return ResourceManager.GetString("Unknown_transport_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown value in SPI clocking field 0x{0:X2}. + /// + internal static string Unknown_value_in_SPI_clocking_field_0 { + get { + return ResourceManager.GetString("Unknown_value_in_SPI_clocking_field_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown value in TPGS field 0x{0:X2}. + /// + internal static string Unknown_value_in_TPGS_field_0 { + get { + return ResourceManager.GetString("Unknown_value_in_TPGS_field_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown vendor id 0x{0:X4}. + /// + internal static string Unknown_vendor_id_0 { + get { + return ResourceManager.GetString("Unknown_vendor_id_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown wavelength. + /// + internal static string Unknown_wavelength { + get { + return ResourceManager.GetString("Unknown_wavelength", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown WORM emulation code {0}. + /// + internal static string Unknown_WORM_emulation_code_0 { + get { + return ResourceManager.GetString("Unknown_WORM_emulation_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown WORM mode label restrictions code {0}. + /// + internal static string Unknown_WORM_mode_label_restrictions_code_0 { + get { + return ResourceManager.GetString("Unknown_WORM_mode_label_restrictions_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unload is supported with outstanding NCQ commands. + /// + internal static string Unload_is_supported_with_outstanding_NCQ_commands { + get { + return ResourceManager.GetString("Unload_is_supported_with_outstanding_NCQ_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unrecovered CIRC errors will not abort the transfer.. + /// + internal static string Unrecovered_CIRC_errors_will_not_abort_the_transfer { + get { + return ResourceManager.GetString("Unrecovered_CIRC_errors_will_not_abort_the_transfer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unrecovered CIRC errors will return CHECK CONDITION.. + /// + internal static string Unrecovered_CIRC_errors_will_return_CHECK_CONDITION { + get { + return ResourceManager.GetString("Unrecovered_CIRC_errors_will_return_CHECK_CONDITION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unrecovered CIRC errors will return CHECK CONDITION and the uncorrected data.. + /// + internal static string Unrecovered_CIRC_errors_will_return_CHECK_CONDITION_and_the_uncorrected_data { + get { + return ResourceManager.GetString("Unrecovered_CIRC_errors_will_return_CHECK_CONDITION_and_the_uncorrected_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unrecovered ECC errors will not abort the transfer.. + /// + internal static string Unrecovered_ECC_errors_will_not_abort_the_transfer { + get { + return ResourceManager.GetString("Unrecovered_ECC_errors_will_not_abort_the_transfer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unrecovered ECC errors will return CHECK CONDITION.. + /// + internal static string Unrecovered_ECC_errors_will_return_CHECK_CONDITION { + get { + return ResourceManager.GetString("Unrecovered_ECC_errors_will_return_CHECK_CONDITION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unrecovered ECC errors will return CHECK CONDITION and the uncorrected data.. + /// + internal static string Unrecovered_ECC_errors_will_return_CHECK_CONDITION_and_the_uncorrected_data { + get { + return ResourceManager.GetString("Unrecovered_ECC_errors_will_return_CHECK_CONDITION_and_the_uncorrected_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unskip time interval assignment {0} says that from {1:D2}:{2:D2}:{3:D2} to {4:D2}:{5:D2}:{6:D2} should not be skipped. + /// + internal static string Unskip_time_interval_assignment_0_says_that_from_1_2_3_to_4_5_6_should_not_be_skipped { + get { + return ResourceManager.GetString("Unskip_time_interval_assignment_0_says_that_from_1_2_3_to_4_5_6_should_not_be_ski" + + "pped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unskip time interval assignment {0} says that from {4}:{1:D2}:{2:D2}:{3:D2} to {8}:{5:D2}:{6:D2}:{7:D2} should not be skipped. + /// + internal static string Unskip_time_interval_assignment_0_says_that_from_4_1_2_3_to_8_5_6_7_should_not_be_skipped { + get { + return ResourceManager.GetString("Unskip_time_interval_assignment_0_says_that_from_4_1_2_3_to_8_5_6_7_should_not_be" + + "_skipped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unskip track assignment {0} says that tracks {1} should not be skipped. + /// + internal static string Unskip_track_assignment_0_says_that_tracks_1_should_not_be_skipped { + get { + return ResourceManager.GetString("Unskip_track_assignment_0_says_that_tracks_1_should_not_be_skipped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unspecified address: {0}. + /// + internal static string Unspecified_address_0 { + get { + return ResourceManager.GetString("Unspecified_address_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to URG bit is supported in READ STREAM DMA EXT and READ STREAM EXT. + /// + internal static string URG_bit_is_supported_in_READ_STREAM_DMA_EXT_and_READ_STREAM_EXT { + get { + return ResourceManager.GetString("URG_bit_is_supported_in_READ_STREAM_DMA_EXT_and_READ_STREAM_EXT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to URG bit is supported in WRITE STREAM DMA EXT and WRITE STREAM EXT. + /// + internal static string URG_bit_is_supported_in_WRITE_STREAM_DMA_EXT_and_WRITE_STREAM_EXT { + get { + return ResourceManager.GetString("URG_bit_is_supported_in_WRITE_STREAM_DMA_EXT_and_WRITE_STREAM_EXT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to USA NTSC.. + /// + internal static string USA_NTSC { + get { + return ResourceManager.GetString("USA_NTSC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to USB Attached SCSI. + /// + internal static string USB_Attached_SCSI { + get { + return ResourceManager.GetString("USB_Attached_SCSI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use of password protection features is permanently disabled.. + /// + internal static string Use_of_password_protection_features_is_permanently_disabled { + get { + return ResourceManager.GetString("Use_of_password_protection_features_is_permanently_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use of permanent write protection is disabled.. + /// + internal static string Use_of_permanent_write_protection_is_disabled { + get { + return ResourceManager.GetString("Use_of_permanent_write_protection_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User data block. + /// + internal static string User_data_block { + get { + return ResourceManager.GetString("User_data_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to user data only. + /// + internal static string user_data_only { + get { + return ResourceManager.GetString("user_data_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to user data plus auxiliary data. + /// + internal static string user_data_plus_auxiliary_data { + get { + return ResourceManager.GetString("user_data_plus_auxiliary_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Uses 35-bytes sense data. + /// + internal static string Uses_35_bytes_sense_data { + get { + return ResourceManager.GetString("Uses_35_bytes_sense_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Uses 96-bytes sense data. + /// + internal static string Uses_96_bytes_sense_data { + get { + return ResourceManager.GetString("Uses_96_bytes_sense_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor descriptor contains: {0}. + /// + internal static string Vendor_descriptor_contains_0 { + get { + return ResourceManager.GetString("Vendor_descriptor_contains_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor descriptor contains binary data (hex): {0}. + /// + internal static string Vendor_descriptor_contains_binary_data_hex_0 { + get { + return ResourceManager.GetString("Vendor_descriptor_contains_binary_data_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor descriptor contains unknown kind {1} of data (hex): {0}. + /// + internal static string Vendor_descriptor_contains_unknown_kind_1_of_data_hex_0 { + get { + return ResourceManager.GetString("Vendor_descriptor_contains_unknown_kind_1_of_data_hex_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor's device type modifier = 0x{0:X2}. + /// + internal static string Vendor_device_type_modifier_0 { + get { + return ResourceManager.GetString("Vendor_device_type_modifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to VENDOR-SPECIFIC ASC {0:X2}h WITH ASCQ {1:X2}h. + /// + internal static string VENDOR_SPECIFIC_ASC_0_WITH_ASCQ_1 { + get { + return ResourceManager.GetString("VENDOR_SPECIFIC_ASC_0_WITH_ASCQ_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to VENDOR-SPECIFIC ASC {0:X2}h WITH VENDOR-SPECIFIC ASCQ {1:X2}h. + /// + internal static string VENDOR_SPECIFIC_ASC_0_WITH_VENDOR_SPECIFIC_ASCQ_1 { + get { + return ResourceManager.GetString("VENDOR_SPECIFIC_ASC_0_WITH_VENDOR_SPECIFIC_ASCQ_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor specific bit 5 on byte 6 of INQUIRY response is set. + /// + internal static string Vendor_specific_bit_5_on_byte_6_of_INQUIRY_response_is_set { + get { + return ResourceManager.GetString("Vendor_specific_bit_5_on_byte_6_of_INQUIRY_response_is_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor-specific bytes 36 to 55. + /// + internal static string Vendor_specific_bytes_36_to_55 { + get { + return ResourceManager.GetString("Vendor_specific_bytes_36_to_55", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor-specific bytes 47 to 55. + /// + internal static string Vendor_specific_bytes_47_to_55 { + get { + return ResourceManager.GetString("Vendor_specific_bytes_47_to_55", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor-specific bytes 96 to {0}. + /// + internal static string Vendor_specific_bytes_96_to_0 { + get { + return ResourceManager.GetString("Vendor_specific_bytes_96_to_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor-specific mode control: {0}. + /// + internal static string Vendor_specific_mode_control_0 { + get { + return ResourceManager.GetString("Vendor_specific_mode_control_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor-specific velocity setting: {0}. + /// + internal static string Vendor_specific_velocity_setting_0 { + get { + return ResourceManager.GetString("Vendor_specific_velocity_setting_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vendor value {0} set in Peripheral Qualifier field.. + /// + internal static string Vendor_value_0_set_in_Peripheral_Qualifier_field { + get { + return ResourceManager.GetString("Vendor_value_0_set_in_Peripheral_Qualifier_field", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Verifying after writing is disabled. + /// + internal static string Verifying_after_writing_is_disabled { + get { + return ResourceManager.GetString("Verifying_after_writing_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version {0}. + /// + internal static string Version_0 { + get { + return ResourceManager.GetString("Version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Video block.. + /// + internal static string Video_block { + get { + return ResourceManager.GetString("Video_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Video track {3} starts at: {0:D2}:{1:D2}:{2:D2}. + /// + internal static string Video_track_3_starts_at_0_1_2 { + get { + return ResourceManager.GetString("Video_track_3_starts_at_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume {0}. + /// + internal static string Volume_0 { + get { + return ResourceManager.GetString("Volume_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to VStape I compressed. + /// + internal static string VStape1c { + get { + return ResourceManager.GetString("VStape1c", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to VXA-1. + /// + internal static string VXA1 { + get { + return ResourceManager.GetString("VXA1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to VXA-2. + /// + internal static string VXA2 { + get { + return ResourceManager.GetString("VXA2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to VXA-3. + /// + internal static string VXA3 { + get { + return ResourceManager.GetString("VXA3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warning reporting is enabled. + /// + internal static string Warning_reporting_is_enabled { + get { + return ResourceManager.GetString("Warning_reporting_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wavelength is 650nm. + /// + internal static string Wavelength_is_650nm { + get { + return ResourceManager.GetString("Wavelength_is_650nm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Well known logical unit. + /// + internal static string Well_known_logical_unit { + get { + return ResourceManager.GetString("Well_known_logical_unit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to with unknown density code 0x{0:X2}. + /// + internal static string with_unknown_density_code_0 { + get { + return ResourceManager.GetString("with_unknown_density_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word {1}: 0x{0:X4}. + /// + internal static string Word_1_0 { + get { + return ResourceManager.GetString("Word_1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word {1} (CE-ATA): 0x{0:X4}. + /// + internal static string Word_1_CE_ATA_0 { + get { + return ResourceManager.GetString("Word_1_CE_ATA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word {1} (CFA): 0x{0:X4}. + /// + internal static string Word_1_CFA_0 { + get { + return ResourceManager.GetString("Word_1_CFA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 116: 0x{0:X4}. + /// + internal static string Word_116_0 { + get { + return ResourceManager.GetString("Word_116_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 174: 0x{0:X4}. + /// + internal static string Word_174_0 { + get { + return ResourceManager.GetString("Word_174_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 175: 0x{0:X4}. + /// + internal static string Word_175_0 { + get { + return ResourceManager.GetString("Word_175_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 207 (CE-ATA): 0x{0:X4}. + /// + internal static string Word_207_CE_ATA_0 { + get { + return ResourceManager.GetString("Word_207_CE_ATA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 208 (CE-ATA): 0x{0:X4}. + /// + internal static string Word_208_CE_ATA_0 { + get { + return ResourceManager.GetString("Word_208_CE_ATA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 219 bits 15 to 8: 0x{0:X2}. + /// + internal static string Word_219_bits_15_to_8_0 { + get { + return ResourceManager.GetString("Word_219_bits_15_to_8_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 220 bits 15 to 8: 0x{0:X2}. + /// + internal static string Word_220_bits_15_to_8_0 { + get { + return ResourceManager.GetString("Word_220_bits_15_to_8_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 221: 0x{0:X4}. + /// + internal static string Word_221_0 { + get { + return ResourceManager.GetString("Word_221_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 47 bits 15 to 8: 0x{0:X2}. + /// + internal static string Word_47_bits_15_to_8_0 { + get { + return ResourceManager.GetString("Word_47_bits_15_to_8_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 51 bits 7 to 0: 0x{0:X2}. + /// + internal static string Word_51_bits_7_to_0_0 { + get { + return ResourceManager.GetString("Word_51_bits_7_to_0_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 52 bits 7 to 0: 0x{0:X2}. + /// + internal static string Word_52_bits_7_to_0_0 { + get { + return ResourceManager.GetString("Word_52_bits_7_to_0_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 64 bits 15 to 8: 0x{0:X2}. + /// + internal static string Word_64_bits_15_to_8_0 { + get { + return ResourceManager.GetString("Word_64_bits_15_to_8_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 70: 0x{0:X4}. + /// + internal static string Word_70_0 { + get { + return ResourceManager.GetString("Word_70_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 73: 0x{0:X4}. + /// + internal static string Word_73_0 { + get { + return ResourceManager.GetString("Word_73_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 74: 0x{0:X4}. + /// + internal static string Word_74_0 { + get { + return ResourceManager.GetString("Word_74_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word 9: 0x{0:X4}. + /// + internal static string Word_nine_0 { + get { + return ResourceManager.GetString("Word_nine_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to World Wide Name: {0:X16}. + /// + internal static string World_Wide_Name_0 { + get { + return ResourceManager.GetString("World_Wide_Name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WORM emulation is disabled. + /// + internal static string WORM_emulation_is_disabled { + get { + return ResourceManager.GetString("WORM_emulation_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WORM emulation is enabled. + /// + internal static string WORM_emulation_is_enabled { + get { + return ResourceManager.GetString("WORM_emulation_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write block: {0} bytes. + /// + internal static string Write_block_0_bytes { + get { + return ResourceManager.GetString("Write_block_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write block length is {0} bytes. + /// + internal static string Write_block_length_is_0_bytes { + get { + return ResourceManager.GetString("Write_block_length_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write block length size is defined in extended CSD. + /// + internal static string Write_block_length_size_is_defined_in_extended_CSD { + get { + return ResourceManager.GetString("Write_block_length_size_is_defined_in_extended_CSD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WRITE BUFFER DMA is supported. + /// + internal static string WRITE_BUFFER_DMA_is_supported { + get { + return ResourceManager.GetString("WRITE_BUFFER_DMA_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WRITE BUFFER is supported. + /// + internal static string WRITE_BUFFER_is_supported { + get { + return ResourceManager.GetString("WRITE_BUFFER_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WRITE BUFFER is supported and enabled. + /// + internal static string WRITE_BUFFER_is_supported_and_enabled { + get { + return ResourceManager.GetString("WRITE_BUFFER_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write buffer shall have a full ratio of {0} before being flushed to medium. + /// + internal static string Write_buffer_shall_have_a_full_ratio_of_0_before_being_flushed_to_medium { + get { + return ResourceManager.GetString("Write_buffer_shall_have_a_full_ratio_of_0_before_being_flushed_to_medium", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write-cache is enabled. + /// + internal static string Write_cache_is_enabled { + get { + return ResourceManager.GetString("Write_cache_is_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write cache is supported. + /// + internal static string Write_cache_is_supported { + get { + return ResourceManager.GetString("Write_cache_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write cache is supported and enabled. + /// + internal static string Write_cache_is_supported_and_enabled { + get { + return ResourceManager.GetString("Write_cache_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write commands can cross physical block boundaries. + /// + internal static string Write_commands_can_cross_physical_block_boundaries { + get { + return ResourceManager.GetString("Write_commands_can_cross_physical_block_boundaries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write current reduction starts at cylinder {0}. + /// + internal static string Write_current_reduction_starts_at_cylinder_0 { + get { + return ResourceManager.GetString("Write_current_reduction_starts_at_cylinder_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WRITE DMA FUA EXT and WRITE MULTIPLE FUA EXT are supported. + /// + internal static string WRITE_DMA_FUA_EXT_and_WRITE_MULTIPLE_FUA_EXT_are_supported { + get { + return ResourceManager.GetString("WRITE_DMA_FUA_EXT_and_WRITE_MULTIPLE_FUA_EXT_are_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WRITE DMA FUA EXT and WRITE MULTIPLE FUA EXT are supported and enabled. + /// + internal static string WRITE_DMA_FUA_EXT_and_WRITE_MULTIPLE_FUA_EXT_are_supported_and_enabled { + get { + return ResourceManager.GetString("WRITE_DMA_FUA_EXT_and_WRITE_MULTIPLE_FUA_EXT_are_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WRITE DMA QUEUED FUA EXT is supported. + /// + internal static string WRITE_DMA_QUEUED_FUA_EXT_is_supported { + get { + return ResourceManager.GetString("WRITE_DMA_QUEUED_FUA_EXT_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WRITE DMA QUEUED FUA EXT is supported and enabled. + /// + internal static string WRITE_DMA_QUEUED_FUA_EXT_is_supported_and_enabled { + get { + return ResourceManager.GetString("WRITE_DMA_QUEUED_FUA_EXT_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write-once device. + /// + internal static string Write_once_device { + get { + return ResourceManager.GetString("Write_once_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write pre-compensation is {0}. + /// + internal static string Write_pre_compensation_is_0 { + get { + return ResourceManager.GetString("Write_pre_compensation_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write pre-compensation starts at cylinder {0}. + /// + internal static string Write_pre_compensation_starts_at_cylinder_0 { + get { + return ResourceManager.GetString("Write_pre_compensation_starts_at_cylinder_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write/Read/Verify is supported. + /// + internal static string Write_Read_Verify_is_supported { + get { + return ResourceManager.GetString("Write_Read_Verify_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write/Read/Verify is supported and enabled. + /// + internal static string Write_Read_Verify_is_supported_and_enabled { + get { + return ResourceManager.GetString("Write_Read_Verify_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WRITE UNCORRECTABLE is supported. + /// + internal static string WRITE_UNCORRECTABLE_is_supported { + get { + return ResourceManager.GetString("WRITE_UNCORRECTABLE_is_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WRITE UNCORRECTABLE is supported and enabled. + /// + internal static string WRITE_UNCORRECTABLE_is_supported_and_enabled { + get { + return ResourceManager.GetString("WRITE_UNCORRECTABLE_is_supported_and_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Writing inhibited by media specific reason. + /// + internal static string Writing_inhibited_by_media_specific_reason { + get { + return ResourceManager.GetString("Writing_inhibited_by_media_specific_reason", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Writing is {0} times slower than reading. + /// + internal static string Writing_is_0_times_slower_than_reading { + get { + return ResourceManager.GetString("Writing_is_0_times_slower_than_reading", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.136-1986: 6.3 mm 4 or 9-Track Magnetic Tape Cartridge, 315 bpmm, GCR (QIC-24). + /// + internal static string X3_136 { + get { + return ResourceManager.GetString("X3_136", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.157-1987: 12.7 mm 9-Track Magnetic Tape, 126 bpmm, Phase Encoding. + /// + internal static string X3_157 { + get { + return ResourceManager.GetString("X3_157", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.158-1987: 3.81 mm 4-Track Magnetic Tape Cassette, 315 bpmm, GCR. + /// + internal static string X3_158 { + get { + return ResourceManager.GetString("X3_158", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.191: 130 mm Write-Once double-sided optical disc with 30000 tracks. + /// + internal static string X3_191 { + get { + return ResourceManager.GetString("X3_191", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.193-1990: 12.7 mm 48-Track Magnetic Tape Cartridge, 394 bpmm, MFM. + /// + internal static string X3_193 { + get { + return ResourceManager.GetString("X3_193", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.200: 356 mm double-sided optical disc with 56350 tracks. + /// + internal static string X3_200 { + get { + return ResourceManager.GetString("X3_200", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.202-1991: 8 mm Magnetic Tape Cassette, 1703 bpmm, RLL. + /// + internal static string X3_202 { + get { + return ResourceManager.GetString("X3_202", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.211: 130 mm Write-Once double-sided optical disc with 18750 tracks. + /// + internal static string X3_211 { + get { + return ResourceManager.GetString("X3_211", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.212: 130 mm Read/Write double-sided optical disc with 18750 tracks. + /// + internal static string X3_212 { + get { + return ResourceManager.GetString("X3_212", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3.214: 130 mm Write-Once double-sided optical disc with 20000 tracks. + /// + internal static string X3_214 { + get { + return ResourceManager.GetString("X3_214", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3B5/86-199: 12.7 mm 22-Track Magnetic Tape Cartridge, 262 bpmm, MFM. + /// + internal static string X3B5_86 { + get { + return ResourceManager.GetString("X3B5_86", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3B5/88-185A: 3.81 mm Magnetic Tape Cassette, 2400 bpmm, DDS. + /// + internal static string X3B5_88 { + get { + return ResourceManager.GetString("X3B5_88", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ANSI X3B5/97-174: 12.7 mm 48-Track Magnetic Tape Cartridge, 1673 bpmm, MFM. + /// + internal static string X3B5_91 { + get { + return ResourceManager.GetString("X3B5_91", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Xbox 360 Game Disc. + /// + internal static string Xbox_360_Game_Disc { + get { + return ResourceManager.GetString("Xbox_360_Game_Disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Xbox Game Disc. + /// + internal static string Xbox_Game_Disc { + get { + return ResourceManager.GetString("Xbox_Game_Disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XOR operations are disabled. + /// + internal static string XOR_operations_are_disabled { + get { + return ResourceManager.GetString("XOR_operations_are_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Zone {0} starts at LSN {1}. + /// + internal static string Zone_0_starts_at_LSN_1 { + get { + return ResourceManager.GetString("Zone_0_starts_at_LSN_1", resourceCulture); + } + } + } +} diff --git a/Aaru.Decoders/Localization/Localization.es.resx b/Aaru.Decoders/Localization/Localization.es.resx new file mode 100644 index 000000000..1a9b82f99 --- /dev/null +++ b/Aaru.Decoders/Localization/Localization.es.resx @@ -0,0 +1,9749 @@ + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + DEVICE RESET está soportado + + + Valor A1: 0x{0:X6} + + + Valor A2: 0x{0:X6} + + + Valor A3: 0x{0:X6} + + + AACS Data Keys en hexadecimal a continuación: + + + AACS Media Identifier en hexadecimal a continuación: + + + AACS Media Key Blocks en hexadecimal a continuación: + + + AACS Media Serial Number en hexadecimal a continuación: + + + AACS Volume Identifier en hexadecimal a continuación: + + + Abortar cualquier comando de escritura sin información de protección + + + Tiempo absoluto: {0:D2}:{1:D2}:{2:D2} + + + Tiempo absoluto: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Accessible Max Address Configuration está soportada + + + Accessible Max Address Configuration está soportada y activada + + + ACS-2 publicado, ANSI INCITS 482-2012 + + + ACS-2 revisión 2 + + + ACS-2 revisión 3 + + + ACS-2 revisión 3b + + + ACS-3 revisión 4 + + + ACS-3 revisión 5 + + + Formato activo: {0} + + + Partición activa: {0} + + + Reintentos actuales: {0} + + + Añadiendo sector {0} de la pista {1} + + + Información adicional: + + + ID de producto adicional: {0} + + + Dirección para el servicio de configuración administrativa: {0} + + + Dirección para descarga de código: {0} + + + Dirección para servicio de copia: {0} + + + Dirección para diagnósticos: {0} + + + Dirección para anotaciones: {0} + + + Dirección para el servicio de configuración de almacenamiento: {0} + + + Dirección para estado: {0} + + + Address Offset Reserved Area Boot está soportado + + + Address Offset Reserved Area Boot está soportado y activado + + + Dirección de tipo {1} desconocido: {0} + + + PIO avanzado: + + + La Gestión Avanzada de Energía (APM) está soportada + + + La Gestión Avanzada de Energía (APM) está soportada y activada con valor {0} + + + Los comandos afectados en la tarea con el nexus en CHECK CONDITION se abortarán + + + AIT-1 + + + AIT-2 + + + AIT-3 + + + álbum + + + Las alertas están activadas + + + Se intentarán todos los procedimientos de recuperación. + + + Todos los datos y la respuesta a un comando se transferirán en una interconexión única + + + Todos los datos de un comando se transferirán en una interconexión única + + + Todos los bloques restantes son {0} y tienen {1} bytes cada uno + + + Todos los bloques restantes son {0} y tienen una longitud variable + + + Todos los bloques restantes tienen {0} bytes cada uno + + + Todos los bloques restantes son conformes a {0} y tienen {1} bytes cada uno + + + Todos los bloques restantes son conformes a {0} y tienen una longitud variable + + + Todos los bloques restantes tienen {0} y tienen {1} bytes cada uno + + + Todos los bloques restantes tienen una longitud variable + + + Todas las tareas recibidas en el nexto con ACA ACTIVE establecido y en condición ACA deben terminar + + + Todos los comandos afectados en el conjunto de tarea deberán abortarse cuando se devuelva CHECK CONDITION + + + Siempre aplicar la operación de verificación + + + un algorithmo de código {0} desconocido + + + un tipo de medio 0x{0:X2} desconocido + + + un algoritmo de compresión no registrado + + + ID de aplicación: {0} + + + La página de modos de Marca de Aplicación está activada + + + Aplicar la operación de verificación dependiendo de la condición + + + Dispositivo controlador de colección + + + ASC {0:X2}h CON ASCQ {1:X2}h + + + ASC {0:X2}h CON ASCQ DE FABRICANTE {1:X2}h + + + NTSC (Asia) + + + La protección contra escritura asociada está activada + + + El tiempo de acceso de datos asíncrono es {0}{1} + + + Evento asíncrono de reporte de excepciones informativas + + + La notificación asíncrona está soportada + + + La notificación asíncrona está soportada y activada + + + ATA8-ACS revisión 2d + + + ATA8-ACS revisión 3b + + + ATA8-ACS revisión 3c + + + ATA8-ACS revisión 3e + + + ATA8-ACS revisión 3f + + + ATA8-ACS revisión 4 + + + ATA8-ACS revisión 4c + + + ATA8-ACS revisión 6 + + + Dispositivo ATAPI controlador de colecciones + + + Interfaz ATAPI de automatización + + + Expansores puente ATAPI + + + Dispositivo ATAPI CD-ROM/DVD/etc + + + Dispositivo ATAPI de comunicaciones + + + Dispositivo ATAPI + + + El dispositivo ATAPI requiere restablecimiento ATA por software + + + El dispositivo ATAPI soporta atención de dispositivos conectados + + + El dispositivo ATAPI soporta encolado de comandos + + + El dispositivo ATAPI soporta detectar el entorno anfitrión + + + El dispositivo ATAPI soporta DMA entrelazado + + + El dispositivo ATAPI soporta operaciones superpuestas + + + El dispositivo ATAPI usa paquetes de comandos de 12 bytes + + + El dispositivo ATAPI usa paquetes de comandos de 16 bytes + + + Dispositivo ATAPI de acceso directo + + + Dispositivo ATAPI de servicios de carcasas + + + Dispositivo ATAPI de artes gráficas pre-prensa (definido en ASC IT8) + + + Dispositivo ATAPI de cambio de medios + + + Dispositivo ATAPI de almacenamiento basado en objetos + + + Dispositivo ATAPI de lector/escritor de tarjeta óptica + + + Dispositivo ATAPI de memoria óptica + + + Dispositivo ATAPI de impresora + + + Dispositivo ATAPI de procesador + + + Dispositivo ATAPI de escáner + + + Dispositivo ATAPI de acceso secuencial + + + Dispositivo ATAPI simplificado de acceso directo + + + Dispositivo ATAPI con valor de tipo 0x{0:X2} desconocido + + + Dispositivo ATAPI desconocido o sin tipo + + + Dispositivo ATAPI de unidad lógica conocida + + + Dispositivo ATAPI de escritura única + + + ATA-1 publicado, ANSI X3.221-1994 + + + ATA-2 publicado, ANSI X3.279-1996 + + + ATA-2 X3T10 948D anterior a revisión 2k + + + ATA-2 X3T10 948D revisión 2k + + + ATA-2 X3T10 948D revisión 3 + + + ATA-3 publicado, ANSI X3.298-1997 + + + ATA-3 X3T10 2008D revisión 0 + + + ATA-3 X3T10 2008D revisión 1 + + + ATA-3 X3T10 2008D revisión 6 + + + ATA-3 X3T13 2008D revisión 7 + + + ATA/ATAPI-4 publicado, ANSI INCITS 317-1998 + + + ATA/ATAPI-4 T13 1153D revisión 13 + + + ATA/ATAPI-4 T13 1153D revisión 14 + + + ATA/ATAPI-4 T13 1153D revisión 15 + + + ATA/ATAPI-4 T13 1153D revisión 17 + + + ATA/ATAPI-4 T13 1153D revisión 18 + + + ATA/ATAPI-4 X3T13 1153D revisión 6 + + + ATA/ATAPI-4 X3T13 1153D revisión 7 + + + ATA/ATAPI-5 publicado, ANSI INCITS 340-2000 + + + ATA/ATAPI-5 T13 1321D revisión 1 + + + ATA/ATAPI-5 T13 1321D revisión 3 + + + ATA/ATAPI-6 publicado, ANSI INCITS 361-2002 + + + ATA/ATAPI-6 T13 1410D revisión 0 + + + ATA/ATAPI-6 T13 1410D revisión 1 + + + ATA/ATAPI-6 T13 1410D revisión 2 + + + ATA/ATAPI-6 T13 1410D revisión 3a + + + ATA/ATAPI-7 publicado ANSI INCITS 397-2005 + + + ATA/ATAPI-7 T13 1523D revisión 0 + + + ATA/ATAPI-7 T13 1523D revisión 1 + + + ATA/ATAPI-7 T13 1523D revisión 4a + + + ATA (ATA-1) X3T9.2 781D anterior a la revisión 4 + + + ATA (ATA-1) X3T9.2 781D revisión 4 + + + Dispositivo ATA + + + Información de ATA IDENTIFY a continuación: + + + Último tiempo de comienzo posible del Lead-out según ATIP: 0x{0:X6} + + + Último tiempo de comienzo posible del Lead-out según ATIP: {0}:{1:D2}:{2:D2} + + + Tiempo de comienzo del Lead-in según ATIP: 0x{0:X6} + + + Tiempo de comienzo del Lead-in según ATIP: {0}:{1:D2}:{2:D2} + + + Interfaz de conexión AT (ATA/ATAPI) + + + Siempre se pre-leerán al menos {0} bloques + + + Debe estar inactivo al menos {0} ms antes de resumir una operación de escaneo en segundo plano + + + al volumen máximo + + + Mínimo {0} ns. de tiempo del ciclo de transferencia por palabra en MDMA, {1} ns. recomendados + + + Mínimo {0} ns. de tiempo del ciclo de transferencia por palabra en PIO, sin control de flujo + + + Mínimo {0} ns. de tiempo del ciclo de transferencia por palabra en PIO, con control de flujo IORDY + + + Como mucho {0} ms deben pasar antes de suspender una operación de escaneo en segundo plano y procesando los comandos recibidos + + + al volumen {0} + + + Bloque de audio. + + + sólo información de audio + + + La pista de audio {3} comienza en: {0:D2}:{1:D2}:{2:D2} ( + + + La pista de audio {3} comienza en: {4:D2}:{0:D2}:{1:D2}:{2:D2} ( + + + El soporte del modo de datos audiovisual está aplicado + + + La gestión acústica automática (AAM) está soportada + + + La gestión acústica automática (AAM) está soportada y activada con el valor {0} (el fabricante recomienda {1} + + + Las transiciones automáticas de parcial a inactividad están activadas + + + La recolocación automática en lectura está activada + + + La recolocación automática en escritura está activada + + + Interfaz de automatización/unidad + + + Interfaz de transporte de automatización/unidad + + + La automatización está desactivada + + + una combinación de óptico de sólo lectura y borrable + + + una combinación de óptico de escritura única y borrable + + + Se pre-leerán un máximo de {0} bloques + + + Se pre-leerán un máximo de {0} bloques incluso si se piden más + + + Se permite un máximo de {0} ms ocupado + + + Se transferirán un máximo de {0} sectores por interrupción en READ/WRITE MULTIPLE + + + Una excepción informacional de prueba se lanzará en el siguiente temporizador + + + Las funciones en segundo plano están activadas + + + El escaneo del medio en segundo plano está activado + + + Los pre-escaneos en segundo plano están activados + + + Las operaciones en segundo plano pueden tomar un máximo de {0} horas + + + Los escaneos en segundo plano se pararán si las anotaciones están llenas + + + Sólo se notaran los escaneos en segundo plano que requieran intervención + + + Dispositivo BGA + + + Contenidos en binario: {0} + + + La comprobación de estar en blanco está activada al escribir + + + BLOCK ERASE EXT está soportado + + + Bloque número {0} + + + Burst Cutting Area de Blu-ray en hexadecimal a continuación: + + + Datos específicos del tipo de disco Blu-ray en hexadecimal a continuación: + + + Bits de estado del descriptor de disco Blu-ray en hexadecimal a continuación: + + + Contenidos de información de disco dependiente del formato de Blu-ray en hexadecimal a continuación: + + + Tipo de libro: 0x{0:X2} + + + El área de arranque 1 no está protegida + + + El área de arranque 1 está protegida permanentemente + + + El área de arranque 1 está protegida contra escritura permanentemente + + + El área de arranque 1 está protegida en el encendido + + + El área de arranque 1 está protegida contra escritura hasta el próximo ciclo de corriente + + + El área de arranque 2 no está protegida + + + El área de arranque 2 está protegida permanentemente + + + El área de arranque 2 está protegida contra escritura permanentemente + + + El área de arranque 2 está protegida contra escritura hasta el próximo ciclo de corriente + + + El área de arranque 2 está protegida en el encendido + + + Versión del firmware de arranque: {0} + + + Ambas áreas de arranque están protegidas contra escritura permanentemente + + + Ambas áreas de arranque están protegidas contra escritura hasta el próximo ciclo de corriente + + + Expansores puente + + + bytes + + + El análisis de la caché está permitido + + + ID de tarjeta: 0x{0:X4} + + + La tarjeta indica cumplimiento del estandar PC Card versión {0}.{1} + + + El cartucho tiene una capacidad sin comprimir de {0} gigabytes + + + El cartucho está protegido contra escritura + + + La extracción del cartucho está prevenida + + + Número de serie del cartucho: {0} + + + El cartucho decide la protección contra escritura + + + La cinta del cartucho está enroscada + + + El cartucho se cargará y enroscará en su inserción + + + El cartucho se cargará pero no se enroscará en su inserción + + + El cartucho no se cargará + + + Número de catálogo: + + + Dispositivo CD-ROM/DVD/etc + + + Sector CD-ROM. + + + Sector CD. + + + El paquete de CD-Text contiene el arreglista del álbum + + + El paquete de CD-Text contiene el arreglista de la pista {0} + + + El paquete de CD-Text contiene mensaje del proveedor para el álbum + + + El paquete de CD-Text contiene mensaje del proveedor para la pista {0} + + + El paquete de CD-Text contiene datos reservados para el proveedor + + + El paquete de CD-Text contiene información de identificación del disco + + + El paquete de CD-Text contiene información de identificación del género + + + El paquete de CD-Text contiene el intérprete del álbum + + + El paquete de CD-Text contiene el intérprete de la pista {0} + + + El paquete de CD-Text contiene datos reservados + + + El paquete de CD-Text contiene información de una segunda tabla de contenidos + + + El paquete de CD-Text contiene información del tamaño del bloque + + + El paquete de CD-Text contiene el compositor del álbum + + + El paquete de CD-Text contiene el compositor de la pista {0} + + + El paquete de CD-Text contiene información de una tabla de contenidos + + + El paquete de CD-Text contiene el título del álbum + + + El paquete de CD-Text contiene el título de la pista {0} + + + El paquete de CD-Text contiene el UPC + + + Disco CD-V en formato NTSC con sonido digital bilingüe + + + Disco CD-V en formato NTSC con sonido digital estéreo + + + Disco CD-V en formato PAL con sonido digital bilingüe + + + Disco CD-V en formato PAL con sonido digital estéreo + + + Single CD-V en formato NTSC con conido digital bilingüe + + + Single CD-V en formato NTSC con sonido digital estéreo + + + Single CD-V en formato PAL con sonido digital bilingüe + + + Single CD-V en formato PAL con sonido digital estéreo + + + Número de serie de la base mécanica: {0} + + + Número de serie de la placa: {0} + + + Página de niveles de revisión de los componentes de la unidad Certance: + + + Página de números de serie de los componentes de la unidad Certance: + + + Componente: {0} + + + Fecha: {0} + + + Página de control de capacidades de la unidad Certance: + + + Página de estado de la unidad Certance: + + + Número de serie del emsamblado del cabezal: {0} + + + Página de control de modos de la interfaz Central: + + + Número de serie del motor del carrete 1: {0} + + + Número de serie del motor del carrete 2: {0} + + + Variante: {0} + + + Versión: {0} + + + ID del desafío: {0} + + + Nivel del desafío: {0} + + + Valor del desafío: 0x{0:X8} + + + El cambio de los bits de registro de la configuración de arranque está desactivado hasta el próximo ciclo de corriente. + + + El cambio de los bits de registro de la configuración de arranque está desactivado permanentemente. + + + Canal número: {0} + + + Posición del carácter {0} + + + Checksum {0} + + + Se debe reportar CHECK CONDITION en lugar de una condición de ocupación larga + + + CID CRC: 0x{0:X2} + + + El comportamiento de limpieza es normal + + + Está insertado un cartucho de limpieza + + + El acceso a datos dependiente del reloj es de {0} ciclos del reloj + + + ) + + + Nombre del código: {0} + + + Número de información de codificación: {0} + + + Los comandos pueden reordenarse de cualquier forma + + + Los comandos deben mandar estrictamente ordenados + + + El reenvío de comandos está desactivado + + + El reenvío de comandos está activado + + + Conjunto de comandos y funciones: + + + Dispositivo de comunicaciones + + + Dispositivo CompactFlash + + + El dispositivo CompactFlash soporta el modo de energía 1 + + + El dispositivo CompactFlash usa un máximo de {0} mA + + + El conjunto de funciones CompactFlash está soportado + + + El conjunto de funciones CompactFlash está soportado y activado + + + El modo de energía 1 de CompactFlash está desactivado + + + El modo de energía 1 de CompactFlash se requiere para algunos comandos + + + La compresión se controla con las páginas de modo 0Fh y 10h + + + La compresión está desactivada y no es controlable + + + La compresión está activada y no es controlable + + + Condicionalmente generar errores recuperables en excepciones informativas + + + Disco de uso de consumidor para uso en unidades de consumidor + + + Versión de firmware del controlador: {0} + + + Versión de hardware del controlador: {0} + + + La zona de control de datos está pre-grabada + + + Copyright: {0} + + + Encontrada copia de la información A1 del ATIP + + + ECC P correcto. + + + ECC Q correcto. + + + EDC correcto. + + + Contenido del sector correcto. + + + Relleno de ceros correcto. + + + No se pudo descodificar la información de ATA IDENTIFY. + + + CPRM Media Key Blocks en hexadecimal a continuación: + + + CRC: 0x{0:X4} + + + CRYPTO SCRAMBLE EXT está soportado + + + CSD CRC: 0x{0:X2} + + + CSD versión 1.{0} revisión 1.{1} + + + CompactTape I + + + CompactTape II + + + (actual) + + + El primer sector actual del Border-Out es el PSN {0:X}h + + + El medio actual tiene disponibles {0} bytes de enlace + + + El medio actual está inicializado con TCG OSSC + + + Definición de operación actual: {0} + + + El RMD en la zona borde extra comienza en el PSN {0:X}h + + + Modo Escritura/Lectura/Verificación actual: {0} + + + Cilindros: {0} + + + Cilindros: {0} máx., {1} actualmente + + + disco óptico de 200 mm + + + disco óptico de 89 mm de lectura/escritura y doble cara con 12500 pistas + + + El área de datos comienzo en el PSN {0:X}h + + + El área de datos finaliza en el PSN {0:X}h + + + Bloque de datos. + + + La compresión de datos está activada con + + + La descompresión de datos está activada + + + Los datos tienen {0} bytes + + + Los datos no recuperados dentro de los límites deben transferirse de vuelta antes de un CHECK CONDITION + + + Los datos recogidos por los comandos READ deben eliminarse de la caché antes que los datos puestos en la caché de lectura por otros medios + + + Los datos recogidos por los comandos READ no deben eliminarse si hay datos puestos en la caché por otros medios que pueden ser eliminados + + + Los datos puestos por los comandos WRITE deben eliminarse de la caché antes que los datos puestos en la caché de escritura por otros medios + + + Los datos puestos por los comandos WRITE no deben eliminarse si hay datos puestos en la caché por otros medios que pueden ser eliminados + + + DATA SET MANAGEMENT puede recibir un máximo de {0} bloques de 512 bytes + + + La opción de compensación de datos intermitentes está disponible + + + Las cintas de datos se enroscarán al principio, y las demás se descargarán + + + Pista de datos {3} comienza en: {0:D2}:{1:D2}:{2:D2} ( + + + Pista de datos {3} comienza en: {4:D2}:{1:D2}:{2:D2} ( + + + Pista de datos, grabada incrementalmente + + + Pista de datos, graba ininterrumpidamente + + + El control de desconexión de la transferencia de datos no se usa + + + DC-9200 + + + DC-9250 + + + DCLZ + + + DDS-2 + + + DDS-3 + + + DDS-4 + + + Formato DDS: 0x{0:X2} + + + El DDS se ha actualizado {0} veces + + + Definición de operación por defecto: {0} + + + Densidad "{0}" definida por "{1}". + + + Descripción de densidad: {0} + + + La densidad tiene {0} bits por mm, con {1} pistas en una cinta de {2} mm de ancho + + + La capacidad máxima de la densidad es {0} megabytes + + + El descriptor se refiere al protocolo {0} + + + Código del desarrollador: {0} + + + La caché del dispostivo está activada + + + El dispositivo permite leer bloques parciales + + + El dispositivo permite escribir bloques parciales + + + La partición de arranque 1 del dispositivo está activada + + + La partición de arranque 2 del dispositivo está activada + + + El dispositivo no puede alcanzar 2,4MB/s leyendo en el modo SDR 26MHz de 4-bit + + + El dispositivo no puede alcanzar 2,4MB/s leyendo en el modo SDR 26MHz + + + El dispositivo no puede alcanzar 2,4MB/s leyendo en el modo SDR 52MHz + + + El dispositivo no puede alcanzar 2,4MB/s escribiendo en el modo SDR 26MHz de 4-bit + + + El dispositivo no puede alcanzar 2,4MB/s escribiendo en el modo SDR 26MHz + + + El dispositivo no puede alcanzar 2,4MB/s escribiendo en el modo SDR 52MHz + + + El dispositivo no puede alcanzar 4,8MB/s leyendo en el modo DDR 52MHz + + + El dispositivo no puede alcanzar 4,8MB/s escribiendo en el modo DDR 52MHz + + + El dispositivo no puede proteger regiones contra escritura + + + El dispositivo puede alcanzar un mínimo de {0}MB/s leyendo en el modo DDR 52MHz + + + El dispositivo puede alcanzar un mínimo de {0}MB/s leyendo en el modo SDR 26MHz de 4-bit + + + El dispositivo puede alcanzar un mínimo de {0}MB/s leyendo en el modo SDR 26MHz + + + El dispositivo puede alcanzar un mínimo de {0}MB/s leyendo en el modo SDR 52MHz + + + El dispositivo puede alcanzar un mínimo de {0}MB/s escribiendo en el modo DDR 52MHz + + + El dispositivo puede alcanzar un mínimo de {0}MB/s escribiendo en el modo SDR 26MHz de 4-bit + + + El dispositivo puede alcanzar un mínimo de {0}MB/s escribiendo en el modo SDR 26MHz + + + El dispositivo puede alcanzar un mínimo de {0}MB/s escribiendo en el modo SDR 52MHz + + + El dispositivo puede borrar un mínimo de {0} bloques a la vez + + + El dispositivo puede borrar múltiples bloques + + + El dispositivo tiene mejores tecnológicas en las particiones y el área de datos de usuario + + + El dispositivo puede tener el atributo de particiones extendidas + + + El dispositivo puede cambiar a funcionar con un suministro de 1,8V + + + El dispositivo toma un máximo de {0} ms para liberarse de una interrupción + + + El dispositivo toma un máximo de {0} ms para cambiar de partición + + + El dispositivo puede funcionar con un suministro de 3,5~3,6V + + + El dispositivo puede funcionar con un suministro de 3,4~3,5V + + + El dispositivo puede funcionar con un suministro de 3,3~3,4V + + + El dispositivo puede funcionar con un suministro de 3,2~3,3V + + + El dispositivo puede funcionar con un suministro de 3,1~3,2V + + + El dispositivo puede funcionar con un suministro de 2,9~3,0V + + + El dispositivo puede funcionar con un suministro de 2,8~2,9V + + + El dispositivo puede funcionar con un suministro de 2,7~2,8V + + + El dispositivo puede funcionar con un suministro de 2,6~2,7V + + + El dispositivo puede funcionar con un suministro de 2,5~2,6V + + + El dispositivo puede funcionar con un suministro de 2,4~2,5V + + + El dispositivo puede funcionar con un suministro de 2,3~2,4V + + + El dispositivo puede funcionar con un suministro de 2,2~2,3V + + + El dispositivo puede funcionar con un suministro de 2,1~2,2V + + + El dispositivo puede funcionar con un suministro de 2,0~2,1V + + + El dispositivo puede funcionar con un suministro de 1,65~1,95V + + + El dispositivo puede proteger contra escritura un mínimo de {0} bloques a la vez + + + El dispositivo puede proteger regiones contra escritura + + + Capacidades del dispositivo: + + + El dispositivo comprueba la etiqueta de aplicación del bloque lógico + + + El dispositivo comprueba la etiqueta de guarda del bloque lógico + + + El dispositivo comprueba la etiqueta de referencia del bloque lógico + + + El dispositivo es conforme con SAM (versión no especificada) + + + El dispositivo es conforme con SAM T10/0994-D revisión 18 + + + El dispositivo es conforme con SAM ANSI INCITS 270-1996 + + + El dispositivo es conforme con SAM-2 (versión no especificada) + + + El dispositivo es conforme con SAM-2 T10/1157-D revisión 23 + + + El dispositivo es conforme con SAM-2 T10/1157-D revisión 24 + + + El dispositivo es conforme con SAM-2 ANSI INCITS 366-2003 + + + El dispositivo es conforme con SAM-2 ISO/IEC 14776-412 + + + El dispositivo es conforme con SAM-3 (versión no especificada) + + + El dispositivo es conforme con SAM-3 T10/1561-D revisión 7 + + + El dispositivo es conforme con SAM-3 T10/1561-D revisión 13 + + + El dispositivo es conforme con SAM-3 T10/1561-D revisión 14 + + + El dispositivo es conforme con SAM-3 ANSI INCITS 402-2005 + + + El dispositivo es conforme con SAM-4 (versión no especificada) + + + El dispositivo es conforme con SAM-4 T10/1683-D revisión 13 + + + El dispositivo es conforme con SAM-4 T10/1683-D revisión 14 + + + El dispositivo es conforme con SAM-4 ANSI INCITS 447-2008 + + + El dispositivo es conforme con SAM-4 ISO/IEC 14776-414 + + + El dispositivo es conforme con SAM-5 (versión no especificada) + + + El dispositivo es conforme con SAM-5 T10/2104-D revisión 4 + + + El dispositivo es conforme con SAM-5 T10/2104-D revisión 20 + + + El dispositivo es conforme con SAM-5 T10/2104-D revisión 21 + + + El dispositivo es conforme con SAM-6 (versión no especificada) + + + El dispositivo es conforme con SPC (versión no especificada) + + + El dispositivo es conforme con SPC T10/0995-D revisión 11a + + + El dispositivo es conforme con SPC ANSI INCITS 301-1997 + + + El dispositivo es conforme con MMC (versión no especificada) + + + El dispositivo es conforme con MMC T10/1048-D revisión 10a + + + El dispositivo es conforme con MMC ANSI INCITS 304-1997 + + + El dispositivo es conforme con SCC (versión no especificada) + + + El dispositivo es conforme con SCC T10/1047-D revisión 06c + + + El dispositivo es conforme con SCC ANSI INCITS 276-1997 + + + El dispositivo es conforme con SBC (versión no especificada) + + + El dispositivo es conforme con SBC T10/0996-D revisión 08c + + + El dispositivo es conforme con SBC ANSI INCITS 306-1998 + + + El dispositivo es conforme con SMC (versión no especificada) + + + El dispositivo es conforme con SMC T10/0999-D revisión 10a + + + El dispositivo es conforme con SMC ANSI INCITS 314-1998 + + + El dispositivo es conforme con SMC ISO/IEC 14776-351 + + + El dispositivo es conforme con SES (versión no especificada) + + + El dispositivo es conforme con SES T10/1212-D revisión 08b + + + El dispositivo es conforme con SES ANSI INCITS 305-1998 + + + El dispositivo es conforme con SES T10/1212 revisión 08b con Anexo ANSI INCITS.305/AM1-2000 + + + El dispositivo es conforme con SES ANSI INCITS 305-1998 con Anexo ANSI INCITS.305/AM1-2000 + + + El dispositivo es conforme con SCC-2 (versión no especificada) + + + El dispositivo es conforme con SCC-2 T10/1125-D revisión 04 + + + El dispositivo es conforme con SCC-2 ANSI INCITS 318-1998 + + + El dispositivo es conforme con SSC (versión no especificada) + + + El dispositivo es conforme con SSC T10/0997-D revisión 17 + + + El dispositivo es conforme con SSC T10/0997-D revisión 22 + + + El dispositivo es conforme con SSC ANSI INCITS 335-2000 + + + El dispositivo es conforme con RBC (versión no especificada) + + + El dispositivo es conforme con RBC T10/1240-D revisión 10a + + + El dispositivo es conforme con RBC ANSI INCITS 330-2000 + + + El dispositivo es conforme con MMC-2 (versión no especificada) + + + El dispositivo es conforme con MMC-2 T10/1228-D revisión 11 + + + El dispositivo es conforme con MMC-2 T10/1228-D revisión 11a + + + El dispositivo es conforme con MMC-2 ANSI INCITS 333-2000 + + + El dispositivo es conforme con SPC-2 (versión no especificada) + + + El dispositivo es conforme con SPC-2 T10/1236-D revisión 12 + + + El dispositivo es conforme con SPC-2 T10/1236-D revisión 18 + + + El dispositivo es conforme con SPC-2 T10/1236-D revisión 19 + + + El dispositivo es conforme con SPC-2 T10/1236-D revisión 20 + + + El dispositivo es conforme con SPC-2 ANSI INCITS 351-2001 + + + El dispositivo es conforme con SPC-2 ISO/IEC 14776-452 + + + El dispositivo es conforme con OCRW (versión no especificada) + + + El dispositivo es conforme con OCRW ISO/IEC 14776-381 + + + El dispositivo es conforme con MMC-3 (versión no especificada) + + + El dispositivo es conforme con MMC-3 T10/1363-D revisión 9 + + + El dispositivo es conforme con MMC-3 T10/1363-D revisión 10g + + + El dispositivo es conforme con MMC-3 ANSI INCITS 360-2002 + + + El dispositivo es conforme con SMC-2 (versión no especificada) + + + El dispositivo es conforme con SMC-2 T10/1383-D revisión 5 + + + El dispositivo es conforme con SMC-2 T10/1383-D revisión 6 + + + El dispositivo es conforme con SMC-2 T10/1383-D revisión 7 + + + El dispositivo es conforme con SMC-2 ANSI INCITS 382-2004 + + + El dispositivo es conforme con SPC-3 (versión no especificada) + + + El dispositivo es conforme con SPC-3 T10/1416-D revisión 7 + + + El dispositivo es conforme con SPC-3 T10/1416-D revisión 21 + + + El dispositivo es conforme con SPC-3 T10/1416-D revisión 22 + + + El dispositivo es conforme con SPC-3 T10/1416-D revisión 23 + + + El dispositivo es conforme con SPC-3 ANSI INCITS 408-2005 + + + El dispositivo es conforme con SPC-3 ISO/IEC 14776-453 + + + El dispositivo es conforme con SBC-2 (versión no especificada) + + + El dispositivo es conforme con SBC-2 T10/1417-D revisión 5a + + + El dispositivo es conforme con SBC-2 T10/1417-D revisión 15 + + + El dispositivo es conforme con SBC-2 T10/1417-D revisión 16 + + + El dispositivo es conforme con SBC-2 ANSI INCITS 405-2005 + + + El dispositivo es conforme con SBC-2 ISO/IEC 14776-322 + + + El dispositivo es conforme con OSD (versión no especificada) + + + El dispositivo es conforme con OSD T10/1355-D revisión 0 + + + El dispositivo es conforme con OSD T10/1355-D revisión 7a + + + El dispositivo es conforme con OSD T10/1355-D revisión 8 + + + El dispositivo es conforme con OSD T10/1355-D revisión 9 + + + El dispositivo es conforme con OSD T10/1355-D revisión 10 + + + El dispositivo es conforme con OSD ANSI INCITS 400-2004 + + + El dispositivo es conforme con SSC-2 (versión no especificada) + + + El dispositivo es conforme con SSC-2 T10/1434-D revisión 7 + + + El dispositivo es conforme con SSC-2 T10/1434-D revisión 9 + + + El dispositivo es conforme con SSC-2 ANSI INCITS 380-2003 + + + El dispositivo es conforme con BCC (versión no especificada) + + + El dispositivo es conforme con MMC-4 (versión no especificada) + + + El dispositivo es conforme con MMC-4 T10/1545-D revisión 5 + + + El dispositivo es conforme con MMC-4 T10/1545-D revisión 5a + + + El dispositivo es conforme con MMC-4 T10/1545-D revisión 3 + + + El dispositivo es conforme con MMC-4 T10/1545-D revisión 3d + + + El dispositivo es conforme con MMC-4 ANSI INCITS 401-2005 + + + El dispositivo es conforme con ADC (versión no especificada) + + + El dispositivo es conforme con ADC T10/1558-D revisión 6 + + + El dispositivo es conforme con ADC T10/1558-D revisión 7 + + + El dispositivo es conforme con ADC ANSI INCITS 403-2005 + + + El dispositivo es conforme con SES-2 (versión no especificada) + + + El dispositivo es conforme con SES-2 T10/1559-D revisión 16 + + + El dispositivo es conforme con SES-2 T10/1559-D revisión 19 + + + El dispositivo es conforme con SES-2 T10/1559-D revisión 20 + + + El dispositivo es conforme con SES-2 ANSI INCITS 448-2008 + + + El dispositivo es conforme con SES-2 ISO/IEC 14776-372 + + + El dispositivo es conforme con SSC-3 (versión no especificada) + + + El dispositivo es conforme con SSC-3 T10/1611-D revisión 04a + + + El dispositivo es conforme con SSC-3 T10/1611-D revisión 05 + + + El dispositivo es conforme con SSC-3 ANSI INCITS 467-2011 + + + El dispositivo es conforme con SSC-3 ISO/IEC 14776-333:2013 + + + El dispositivo es conforme con MMC-5 (versión no especificada) + + + El dispositivo es conforme con MMC-5 T10/1675-D revisión 03 + + + El dispositivo es conforme con MMC-5 T10/1675-D revisión 03b + + + El dispositivo es conforme con MMC-5 T10/1675-D revisión 04 + + + El dispositivo es conforme con MMC-5 ANSI INCITS 430-2007 + + + El dispositivo es conforme con OSD-2 (versión no especificada) + + + El dispositivo es conforme con OSD-2 T10/1729-D revisión 4 + + + El dispositivo es conforme con OSD-2 T10/1729-D revisión 5 + + + El dispositivo es conforme con OSD-2 ANSI INCITS 458-2011 + + + El dispositivo es conforme con SPC-4 (versión no especificada) + + + El dispositivo es conforme con SPC-4 T10/BSR INCITS 513 revisión 16 + + + El dispositivo es conforme con SPC-4 T10/BSR INCITS 513 revisión 18 + + + El dispositivo es conforme con SPC-4 T10/BSR INCITS 513 revisión 23 + + + El dispositivo es conforme con SPC-4 T10/BSR INCITS 513 revisión 36 + + + El dispositivo es conforme con SPC-4 T10/BSR INCITS 513 revisión 37 + + + El dispositivo es conforme con SPC-4 T10/BSR INCITS 513 revisión 37a + + + El dispositivo es conforme con SPC-4 ANSI INCITS 513-2015 + + + El dispositivo es conforme con SMC-3 (versión no especificada) + + + El dispositivo es conforme con SMC-3 T10/1730-D revisión 15 + + + El dispositivo es conforme con SMC-3 T10/1730-D revisión 16 + + + El dispositivo es conforme con SMC-3 ANSI INCITS 484-2012 + + + El dispositivo es conforme con ADC-2 (versión no especificada) + + + El dispositivo es conforme con ADC-2 T10/1741-D revisión 7 + + + El dispositivo es conforme con ADC-2 T10/1741-D revisión 8 + + + El dispositivo es conforme con ADC-2 ANSI INCITS 441-2008 + + + El dispositivo es conforme con SBC-3 (versión no especificada) + + + El dispositivo es conforme con SBC-3 T10/BSR INCITS 514 revisión 35 + + + El dispositivo es conforme con SBC-3 T10/BSR INCITS 514 revisión 36 + + + El dispositivo es conforme con SBC-3 ANSI INCITS 514-2014 + + + El dispositivo es conforme con MMC-6 (versión no especificada) + + + El dispositivo es conforme con MMC-6 T10/1836-D revisión 02b + + + El dispositivo es conforme con MMC-6 T10/1836-D revisión 02g + + + El dispositivo es conforme con MMC-6 ANSI INCITS 468-2010 + + + El dispositivo es conforme con MMC-6 ANSI INCITS 468-2010 + MMC-6/AM1 ANSI INCITS 468-2010/AM 1 + + + El dispositivo es conforme con ADC-3 (versión no especificada) + + + El dispositivo es conforme con ADC-3 T10/1895-D revisión 04 + + + El dispositivo es conforme con ADC-3 T10/1895-D revisión 05 + + + El dispositivo es conforme con ADC-3 T10/1895-D revisión 05a + + + El dispositivo es conforme con ADC-3 ANSI INCITS 497-2012 + + + El dispositivo es conforme con SSC-4 (versión no especificada) + + + El dispositivo es conforme con SSC-4 T10/BSR INCITS 516 revisión 2 + + + El dispositivo es conforme con SSC-4 T10/BSR INCITS 516 revisión 3 + + + El dispositivo es conforme con SSC-4 ANSI INCITS 516-2013 + + + El dispositivo es conforme con OSD-3 (versión no especificada) + + + El dispositivo es conforme con SES-3 (versión no especificada) + + + El dispositivo es conforme con SSC-5 (versión no especificada) + + + El dispositivo es conforme con SPC-5 (versión no especificada) + + + El dispositivo es conforme con SFSC (versión no especificada) + + + El dispositivo es conforme con SFSC BSR INCITS 501 revisión 01 + + + El dispositivo es conforme con SBC-4 (versión no especificada) + + + El dispositivo es conforme con ZBC (versión no especificada) + + + El dispositivo es conforme con ZBC BSR INCITS 536 revisión 02 + + + El dispositivo es conforme con ADC-4 (versión no especificada) + + + El dispositivo es conforme con SSA-TL2 (versión no especificada) + + + El dispositivo es conforme con SSA-TL2 T10.1/1147-D revisión 05b + + + El dispositivo es conforme con SSA-TL2 ANSI INCITS 308-1998 + + + El dispositivo es conforme con SSA-TL1 (versión no especificada) + + + El dispositivo es conforme con SSA-TL1 T10.1/0989-D revisión 10b + + + El dispositivo es conforme con SSA-TL1 ANSI INCITS 295-1996 + + + El dispositivo es conforme con SSA-S3P (versión no especificada) + + + El dispositivo es conforme con SSA-S3P T10.1/1051-D revisión 05b + + + El dispositivo es conforme con SSA-S3P ANSI INCITS 309-1998 + + + El dispositivo es conforme con SSA-S2P (versión no especificada) + + + El dispositivo es conforme con SSA-S2P T10.1/1121-D revisión 07b + + + El dispositivo es conforme con SSA-S2P ANSI INCITS 294-1996 + + + El dispositivo es conforme con SIP (versión no especificada) + + + El dispositivo es conforme con SIP T10/0856-D revisión 10 + + + El dispositivo es conforme con SIP ANSI INCITS 292-1997 + + + El dispositivo es conforme con FCP (versión no especificada) + + + El dispositivo es conforme con FCP T10/0993-D revisión 12 + + + El dispositivo es conforme con FCP ANSI INCITS 269-1996 + + + El dispositivo es conforme con SBP-2 (versión no especificada) + + + El dispositivo es conforme con SBP-2 T10/1155-D revisión 04 + + + El dispositivo es conforme con SBP-2 ANSI INCITS 325-1998 + + + El dispositivo es conforme con FCP-2 (versión no especificada) + + + El dispositivo es conforme con FCP-2 T10/1144-D revisión 4 + + + El dispositivo es conforme con FCP-2 T10/1144-D revisión 7 + + + El dispositivo es conforme con FCP-2 T10/1144-D revisión 7a + + + El dispositivo es conforme con FCP-2 ANSI INCITS 350-2003 + + + El dispositivo es conforme con FCP-2 T10/1144-D revisión 8 + + + El dispositivo es conforme con SST (versión no especificada) + + + El dispositivo es conforme con SST T10/1380-D revisión 8b + + + El dispositivo es conforme con SRP (versión no especificada) + + + El dispositivo es conforme con SRP T10/1415-D revisión 10 + + + El dispositivo es conforme con SRP T10/1415-D revisión 16a + + + El dispositivo es conforme con SRP ANSI INCITS 365-2002 + + + El dispositivo es conforme con iSCSI (versión no especificada) + + + El dispositivo es conforme con iSCSI revisión {0} + + + El dispositivo es conforme con SBP-3 (versión no especificada) + + + El dispositivo es conforme con SBP-3 T10/1467-D revisión 1f + + + El dispositivo es conforme con SBP-3 T10/1467-D revisión 3 + + + El dispositivo es conforme con SBP-3 T10/1467-D revisión 4 + + + El dispositivo es conforme con SBP-3 T10/1467-D revisión 5 + + + El dispositivo es conforme con SBP-3 ANSI INCITS 375-2004 + + + El dispositivo es conforme con ADP (versión no especificada) + + + El dispositivo es conforme con ADT (versión no especificada) + + + El dispositivo es conforme con ADT T10/1557-D revisión 11 + + + El dispositivo es conforme con ADT T10/1557-D revisión 14 + + + El dispositivo es conforme con ADT ANSI INCITS 406-2005 + + + El dispositivo es conforme con FCP-3 (versión no especificada) + + + El dispositivo es conforme con FCP-3 T10/1560-D revisión 3f + + + El dispositivo es conforme con FCP-3 T10/1560-D revisión 4 + + + El dispositivo es conforme con FCP-3 ANSI INCITS 416-2006 + + + El dispositivo es conforme con FCP-3 ISO/IEC 14776-223 + + + El dispositivo es conforme con ADT-2 (versión no especificada) + + + El dispositivo es conforme con ADT-2 T10/1742-D revisión 06 + + + El dispositivo es conforme con ADT-2 T10/1742-D revisión 08 + + + El dispositivo es conforme con ADT-2 T10/1742-D revisión 09 + + + El dispositivo es conforme con ADT-2 ANSI INCITS 472-2011 + + + El dispositivo es conforme con FCP-4 (versión no especificada) + + + El dispositivo es conforme con FCP-4 T10/1828-D revisión 01 + + + El dispositivo es conforme con FCP-4 T10/1828-D revisión 02 + + + El dispositivo es conforme con FCP-4 T10/1828-D revisión 02b + + + El dispositivo es conforme con FCP-4 ANSI INCITS 481-2012 + + + El dispositivo es conforme con ADT-3 (versión no especificada) + + + El dispositivo es conforme con SPI (versión no especificada) + + + El dispositivo es conforme con SPI T10/0855-D revisión 15a + + + El dispositivo es conforme con SPI ANSI INCITS 253-1995 + + + El dispositivo es conforme con SPI T10/0855-D revisión 15a con SPI Amnd revisión 3a + + + El dispositivo es conforme con SPI ANSI INCITS 253-1995 con SPI Amnd ANSI INCITS 253/AM1-1998 + + + El dispositivo es conforme con Fast-20 (versión no especificada) + + + El dispositivo es conforme con Fast-20 T10/1071 revisión 06 + + + El dispositivo es conforme con Fast-20 ANSI INCITS 277-1996 + + + El dispositivo es conforme con SPI-2 (versión no especificada) + + + El dispositivo es conforme con SPI-2 T10/1142-D revisión 20b + + + El dispositivo es conforme con SPI-2 ANSI INCITS 302-1999 + + + El dispositivo es conforme con SPI-3 (versión no especificada) + + + El dispositivo es conforme con SPI-3 T10/1302-D revisión 10 + + + El dispositivo es conforme con SPI-3 T10/1302-D revisión 13a + + + El dispositivo es conforme con SPI-3 T10/1302-D revisión 14 + + + El dispositivo es conforme con SPI-3 ANSI INCITS 336-2000 + + + El dispositivo es conforme con EPI (versión no especificada) + + + El dispositivo es conforme con EPI T10/1134 revisión 16 + + + El dispositivo es conforme con EPI ANSI INCITS TR-23 1999 + + + El dispositivo es conforme con SPI-4 (versión no especificada) + + + El dispositivo es conforme con SPI-4 T10/1365-D revisión 7 + + + El dispositivo es conforme con SPI-4 T10/1365-D revisión 9 + + + El dispositivo es conforme con SPI-4 ANSI INCITS 362-2002 + + + El dispositivo es conforme con SPI-4 T10/1365-D revisión 10 + + + El dispositivo es conforme con SPI-5 (versión no especificada) + + + El dispositivo es conforme con SPI-5 T10/1525-D revisión 3 + + + El dispositivo es conforme con SPI-5 T10/1525-D revisión 5 + + + El dispositivo es conforme con SPI-5 T10/1525-D revisión 6 + + + El dispositivo es conforme con SPI-5 ANSI INCITS 367-2003 + + + El dispositivo es conforme con SAS (versión no especificada) + + + El dispositivo es conforme con SAS T10/1562-D revisión 01 + + + El dispositivo es conforme con SAS T10/1562-D revisión 03 + + + El dispositivo es conforme con SAS T10/1562-D revisión 04 + + + El dispositivo es conforme con SAS T10/1562-D revisión 05 + + + El dispositivo es conforme con SAS ANSI INCITS 376-2003 + + + El dispositivo es conforme con SAS-1.1 (versión no especificada) + + + El dispositivo es conforme con SAS-1.1 T10/1601-D revisión 9 + + + El dispositivo es conforme con SAS-1.1 T10/1601-D revisión 10 + + + El dispositivo es conforme con SAS-1.1 ANSI INCITS 417-2006 + + + El dispositivo es conforme con SAS-1.1 ISO/IEC 14776-151 + + + El dispositivo es conforme con SAS-2 (versión no especificada) + + + El dispositivo es conforme con SAS-2 T10/1760-D revisión 14 + + + El dispositivo es conforme con SAS-2 T10/1760-D revisión 15 + + + El dispositivo es conforme con SAS-2 T10/1760-D revisión 16 + + + El dispositivo es conforme con SAS-2 ANSI INCITS 457-2010 + + + El dispositivo es conforme con SAS-2.1 (versión no especificada) + + + El dispositivo es conforme con SAS-2.1 T10/2125-D revisión 04 + + + El dispositivo es conforme con SAS-2.1 T10/2125-D revisión 06 + + + El dispositivo es conforme con SAS-2.1 T10/2125-D revisión 07 + + + El dispositivo es conforme con SAS-2.1 ANSI INCITS 478-2011 + + + El dispositivo es conforme con SAS-2.1 ANSI INCITS 478-2011 con Amnd 1 ANSI INCITS 478/AM1-2014 + + + El dispositivo es conforme con SAS-2.1 ISO/IEC 14776-153 + + + El dispositivo es conforme con SAS-3 (versión no especificada) + + + El dispositivo es conforme con SAS-3 T10/BSR INCITS 519 revisión 05a + + + El dispositivo es conforme con SAS-3 T10/BSR INCITS 519 revisión 06 + + + El dispositivo es conforme con SAS-3 ANSI INCITS 519-2014 + + + El dispositivo es conforme con SAS-4 (versión no especificada) + + + El dispositivo es conforme con FC-PH (versión no especificada) + + + El dispositivo es conforme con FC-PH ANSI INCITS 230-1994 + + + El dispositivo es conforme con FC-PH ANSI INCITS 230-1994 with Amnd 1 ANSI INCITS 230/AM1-1996 + + + El dispositivo es conforme con FC-AL (versión no especificada) + + + El dispositivo es conforme con FC-AL ANSI INCITS 272-1996 + + + El dispositivo es conforme con FC-AL-2 (versión no especificada) + + + El dispositivo es conforme con FC-AL-2 T11/1133-D revisión 7.0 + + + El dispositivo es conforme con FC-AL-2 ANSI INCITS 332-1999 con AM1-2003 & AM2-2006 + + + El dispositivo es conforme con FC-AL-2 ANSI INCITS 332-1999 con Amnd 2 AM2-2006 + + + El dispositivo es conforme con FC-AL-2 ISO/IEC 14165-122 con AM1 y AM2 + + + El dispositivo es conforme con FC-AL-2 ANSI INCITS 332-1999 + + + El dispositivo es conforme con FC-AL-2 ANSI INCITS 332-1999 con Amnd 1 AM1-2003 + + + El dispositivo es conforme con FC-PH-3 (versión no especificada) + + + El dispositivo es conforme con FC-PH-3 ANSI INCITS 303-1998 + + + El dispositivo es conforme con FC-FS (versión no especificada) + + + El dispositivo es conforme con FC-FS T11/1331-D revisión 1.2 + + + El dispositivo es conforme con FC-FS T11/1331-D revisión 1.7 + + + El dispositivo es conforme con FC-FS ANSI INCITS 373-2003 + + + El dispositivo es conforme con FC-FS ISO/IEC 14165-251 + + + El dispositivo es conforme con FC-PI (versión no especificada) + + + El dispositivo es conforme con FC-PI ANSI INCITS 352-2002 + + + El dispositivo es conforme con FC-PI-2 (versión no especificada) + + + El dispositivo es conforme con FC-PI-2 T11/1506-D revisión 5.0 + + + El dispositivo es conforme con FC-PI-2 ANSI INCITS 404-2006 + + + El dispositivo es conforme con FC-FS-2 (versión no especificada) + + + El dispositivo es conforme con FC-FS-2 ANSI INCITS 242-2007 + + + El dispositivo es conforme con FC-FS-2 ANSI INCITS 242-2007 con AM1 ANSI INCITS 242/AM1-2007 + + + El dispositivo es conforme con FC-LS (versión no especificada) + + + El dispositivo es conforme con FC-LS T11/1620-D revisión 1.62 + + + El dispositivo es conforme con FC-LS ANSI INCITS 433-2007 + + + El dispositivo es conforme con FC-SP (versión no especificada) + + + El dispositivo es conforme con FC-SP T11/1570-D revisión 1.6 + + + El dispositivo es conforme con FC-SP ANSI INCITS 426-2007 + + + El dispositivo es conforme con FC-PI-3 (versión no especificada) + + + El dispositivo es conforme con FC-PI-3 T11/1625-D revisión 2.0 + + + El dispositivo es conforme con FC-PI-3 T11/1625-D revisión 2.1 + + + El dispositivo es conforme con FC-PI-3 T11/1625-D revisión 4.0 + + + El dispositivo es conforme con FC-PI-3 ANSI INCITS 460-2011 + + + El dispositivo es conforme con FC-PI-4 (versión no especificada) + + + El dispositivo es conforme con FC-PI-4 T11/1647-D revisión 8.0 + + + El dispositivo es conforme con FC-PI-4 ANSI INCITS 450-2009 + + + El dispositivo es conforme con FC 10GFC (versión no especificada) + + + El dispositivo es conforme con FC 10GFC ANSI INCITS 364-2003 + + + El dispositivo es conforme con FC 10GFC ISO/IEC 14165-116 + + + El dispositivo es conforme con FC 10GFC ISO/IEC 14165-116 con AM1 + + + El dispositivo es conforme con FC 10GFC ANSI INCITS 364-2003 con AM1 ANSI INCITS 364/AM1-2007 + + + El dispositivo es conforme con FC-SP-2 (versión no especificada) + + + El dispositivo es conforme con FC-FS-3 (versión no especificada) + + + El dispositivo es conforme con FC-FS-3 T11/1861-D revisión 0.9 + + + El dispositivo es conforme con FC-FS-3 T11/1861-D revisión 1.0 + + + El dispositivo es conforme con FC-FS-3 T11/1861-D revisión 1.10 + + + El dispositivo es conforme con FC-FS-3 ANSI INCITS 470-2011 + + + El dispositivo es conforme con FC-LS-2 (versión no especificada) + + + El dispositivo es conforme con FC-LS-2 T11/2103-D revisión 2.11 + + + El dispositivo es conforme con FC-LS-2 T11/2103-D revisión 2.21 + + + El dispositivo es conforme con FC-LS-2 ANSI INCITS 477-2011 + + + El dispositivo es conforme con FC-PI-5 (versión no especificada) + + + El dispositivo es conforme con FC-PI-5 T11/2118-D revisión 2.00 + + + El dispositivo es conforme con FC-PI-5 T11/2118-D revisión 3.00 + + + El dispositivo es conforme con FC-PI-5 T11/2118-D revisión 6.00 + + + El dispositivo es conforme con FC-PI-5 T11/2118-D revisión 6.10 + + + El dispositivo es conforme con FC-PI-5 ANSI INCITS 479-2011 + + + El dispositivo es conforme con FC-PI-6 (versión no especificada) + + + El dispositivo es conforme con FC-FS-4 (versión no especificada) + + + El dispositivo es conforme con FC-LS-3 (versión no especificada) + + + El dispositivo es conforme con FC-SCM (versión no especificada) + + + El dispositivo es conforme con FC-SCM T11/1824DT revisión 1.0 + + + El dispositivo es conforme con FC-SCM T11/1824DT revisión 1.1 + + + El dispositivo es conforme con FC-SCM T11/1824DT revisión 1.4 + + + El dispositivo es conforme con FC-SCM INCITS TR-47 2012 + + + El dispositivo es conforme con FC-DA-2 (versión no especificada) + + + El dispositivo es conforme con FC-DA-2 T11/1870DT revisión 1.04 + + + El dispositivo es conforme con FC-DA-2 T11/1870DT revisión 1.06 + + + El dispositivo es conforme con FC-DA-2 INCITS TR-49 2012 + + + El dispositivo es conforme con FC-DA (versión no especificada) + + + El dispositivo es conforme con FC-DA T11/1513-DT revisión 3.1 + + + El dispositivo es conforme con FC-DA ANSI INCITS TR-36 2004 + + + El dispositivo es conforme con FC-DA ISO/IEC 14165-341 + + + El dispositivo es conforme con FC-Tape (versión no especificada) + + + El dispositivo es conforme con FC-Tape T11/1315 revisión 1.16 + + + El dispositivo es conforme con FC-Tape T11/1315 revisión 1.17 + + + El dispositivo es conforme con FC-Tape ANSI INCITS TR-24 1999 + + + El dispositivo es conforme con FC-FLA (versión no especificada) + + + El dispositivo es conforme con FC-FLA T11/1235 revisión 7 + + + El dispositivo es conforme con FC-FLA ANSI INCITS TR-20 1998 + + + El dispositivo es conforme con FC-PLDA (versión no especificada) + + + El dispositivo es conforme con FC-PLDA T11/1162 revisión 2.1 + + + El dispositivo es conforme con FC-PLDA ANSI INCITS TR-19 1998 + + + El dispositivo es conforme con SSA-PH2 (versión no especificada) + + + El dispositivo es conforme con SSA-PH2 T10.1/1145-D revisión 09c + + + El dispositivo es conforme con SSA-PH2 ANSI INCITS 293-1996 + + + El dispositivo es conforme con SSA-PH3 (versión no especificada) + + + El dispositivo es conforme con SSA-PH3 T10.1/1146-D revisión 05b + + + El dispositivo es conforme con SSA-PH3 ANSI INCITS 307-1998 + + + El dispositivo es conforme con IEEE 1394 (versión no especificada) + + + El dispositivo es conforme con ANSI IEEE 1394-1995 + + + El dispositivo es conforme con IEEE 1394a (versión no especificada) + + + El dispositivo es conforme con IEEE 1394b (versión no especificada) + + + El dispositivo es conforme con ATA/ATAPI-6 (versión no especificada) + + + El dispositivo es conforme con ATA/ATAPI-6 ANSI INCITS 361-2002 + + + El dispositivo es conforme con ATA/ATAPI-7 (versión no especificada) + + + El dispositivo es conforme con ATA/ATAPI-7 T13/1532-D revisión 3 + + + El dispositivo es conforme con ATA/ATAPI-7 ANSI INCITS 397-2005 + + + El dispositivo es conforme con ATA/ATAPI-7 ISO/IEC 24739 + + + El dispositivo es conforme con ATA/ATAPI-8 ATA8-AAM (versión no especificada) + + + El dispositivo es conforme con ATA/ATAPI-8 ATA8-APT Parallel Transport (versión no especificada) + + + El dispositivo es conforme con ATA/ATAPI-8 ATA8-AST Serial Transport (versión no especificada) + + + El dispositivo es conforme con ATA/ATAPI-8 ATA8-ACS ATA/ATAPI Command Set (versión no especificada) + + + El dispositivo es conforme con ATA/ATAPI-8 ATA8-AAM ANSI INCITS 451-2008 + + + El dispositivo es conforme con ATA/ATAPI-8 ATA8-ACS ANSI INCITS 452-2009 con Anexo 1 + + + El dispositivo es conforme con Universal Serial Bus Specification, revisión 1.1 + + + El dispositivo es conforme con Universal Serial Bus Specification, revisión 2.0 + + + El dispositivo es conforme con USB Mass Storage Class Bulk-Only Transport, revisión 1.0 + + + El dispositivo es conforme con UAS (versión no especificada) + + + El dispositivo es conforme con UAS T10/2095-D revisión 02 + + + El dispositivo es conforme con UAS T10/2095-D revisión 04 + + + El dispositivo es conforme con UAS ANSI INCITS 471-2010 + + + El dispositivo es conforme con UAS ISO/IEC 14776-251:2014 + + + El dispositivo es conforme con ACS-2 (versión no especificada) + + + El dispositivo es conforme con ACS-2 ANSI INCITS 482-2013 + + + El dispositivo es conforme con ACS-3 (versión no especificada) + + + El dispositivo es conforme con UAS-2 (versión no especificada) + + + El dispositivo es conforme con SAT (versión no especificada) + + + El dispositivo es conforme con SAT T10/1711-D revisión 8 + + + El dispositivo es conforme con SAT T10/1711-D revisión 9 + + + El dispositivo es conforme con SAT ANSI INCITS 431-2007 + + + El dispositivo es conforme con SAT-2 (versión no especificada) + + + El dispositivo es conforme con SAT-2 T10/1826-D revisión 06 + + + El dispositivo es conforme con SAT-2 T10/1826-D revisión 09 + + + El dispositivo es conforme con SAT-2 ANSI INCITS 465-2010 + + + El dispositivo es conforme con SAT-3 (versión no especificada) + + + El dispositivo es conforme con SAT-3 T10/BSR INCITS 517 revisión 4 + + + El dispositivo es conforme con SAT-3 T10/BSR INCITS 517 revisión 7 + + + El dispositivo es conforme con SAT-3 ANSI INCITS 517-2015 + + + El dispositivo es conforme con SAT-4 (versión no especificada) + + + El dispositivo es conforme con SPL (versión no especificada) + + + El dispositivo es conforme con SPL T10/2124-D revisión 6a + + + El dispositivo es conforme con SPL T10/2124-D revisión 7 + + + El dispositivo es conforme con SPL ANSI INCITS 476-2011 + + + El dispositivo es conforme con SPL ANSI INCITS 476-2011 + SPL AM1 INCITS 476/AM1 2012 + + + El dispositivo es conforme con SPL ISO/IEC 14776-261:2012 + + + El dispositivo es conforme con SPL-2 (versión no especificada) + + + El dispositivo es conforme con SPL-2 T10/BSR INCITS 505 revisión 4 + + + El dispositivo es conforme con SPL-2 T10/BSR INCITS 505 revisión 5 + + + El dispositivo es conforme con SPL-2 ANSI INCITS 505-2013 + + + El dispositivo es conforme con SPL-3 (versión no especificada) + + + El dispositivo es conforme con SPL-3 T10/BSR INCITS 492 revisión 6 + + + El dispositivo es conforme con SPL-3 T10/BSR INCITS 492 revisión 7 + + + El dispositivo es conforme con SPL-3 ANSI INCITS 492-2015 + + + El dispositivo es conforme con SPL-4 (versión no especificada) + + + El dispositivo es conforme con SOP (versión no especificada) + + + El dispositivo es conforme con SOP T10/BSR INCITS 489 revisión 4 + + + El dispositivo es conforme con SOP T10/BSR INCITS 489 revisión 5 + + + El dispositivo es conforme con SOP ANSI INCITS 489-2014 + + + El dispositivo es conforme con PQI (versión no especificada) + + + El dispositivo es conforme con PQI T10/BSR INCITS 490 revisión 6 + + + El dispositivo es conforme con PQI T10/BSR INCITS 490 revisión 7 + + + El dispositivo es conforme con PQI ANSI INCITS 490-2014 + + + El dispositivo es conforme con SOP-2 (versión no especificada) + + + El dispositivo es conforme con PQI-2 (versión no especificada) + + + El dispositivo es conforme con IEEE 1667 (versión no especificada) + + + El dispositivo es conforme con IEEE 1667-2006 + + + El dispositivo es conforme con IEEE 1667-2009 + + + El dispositivo es conforme con estándar de código desconocido 0x{0:X4} + + + El dispositivo es conforme con ECMA-111: Interfaz de Sistema de Ordenadores Pequeños SCSI + + + El dispositivo es conforme con ANSI X3.131:1986 (SCSI-1) + + + El dispositivo es conforme con ANSI X3.131:1994 (SCSI-2) + + + El dispositivo es conforme con ANSI X3.301:1997 (SPC-1) + + + El dispositivo es conforme con ANSI X3.351:2001 (SPC-2) + + + El dispositivo es conforme con ANSI X3.408:2005 (SPC-3) + + + El dispositivo es conforma con ANSI X3.408:2005 (SPC-4) + + + El dispositivo es conforme con ISO/IEC 9316:1995 + + + El dispositivo es conforme con un estándar SCSI ANSI desconocido valor 0x{0:X2}) + + + El dispositivo es conforme con un estándar SCSI ECMA desconocido valor 0x{0:X2}) + + + El dispositivo es conforme con un estándar SCSI ISO/IEC desconocido valor 0x{0:X2}) + + + El dispositivo limpia cualquier condición de atención en todos los LUNs después de reportar sobre cualquier LUN + + + DEVICE CONFIGURATION IDENTIFY DMA y DEVICE CONFIGURATION SET DMA están soportados + + + El conjunto de funcionalidades de superposición de la configuración del dispositivo están soportadas + + + El conjunto de funcionalidades de superposición de la configuración del dispositivo están soportadas y activadas + + + El dispositivo contiene un coordinador de control de acceso + + + El dispositivo contiene un componente de servicios de carcasa integrado + + + El dispositivo contiene un componente de controlador de matriz de almacenamiento integrado + + + El dispositivo contiene o está conectado a un intercambiador de medios + + + El contenido del dispositivo es original + + + El dispositivo actualmente direcciona sectores de 4096 bytes + + + El dispositivo actualmente direcciona sectores de 512 bytes + + + El dispositivo actualmente direcciona sectores de tamaño desconocido indicado por el código {0} + + + El dispositivo actualmente usa ECC de tipo BCH(542, 512) + + + El dispositivo no usa ECC actualmente + + + El dispositivo actualmente usa ECC de tipo desconocido código {0} + + + El dispositivo no es conforme con ningún estándar SCSI ANSI + + + El dispositivo no es conforme con ningún estandar SCSI ECMA + + + El dispositivo no es conforme con ningún estándar SCSI ISO/IEC + + + El dispositivo no reporta un tamaño de lectura óptimo + + + El dispositivo no reporta un tamaño de recorte óptimo + + + El dispositivo no reporta un tamaño de escritura óptimo + + + El dispositivo no necesita SET FEATURES para iniciar y la respuesta de IDENTIFY DEVICE está completa. + + + El dispositivo no necesita SET FEATURES para iniciar y la respuesta de IDENTIFY DEVICE está incompleta. + + + El dispositivo no rota. + + + El dispositivo no soporta acceso asimétrico. + + + El dispositivo no soporta CPRM + + + El dispositivo no utiliza CPRM + + + El dispositivo emula un sector de tamaño desconocido indicado por el código {0} + + + El dispositivo encripta todos los datos de usuario + + + Los grupos de borrado del dispositivo son de {0} KiB + + + El dispositivo ha excedido su tiempo de vida estimado máximo + + + El dispositivo es conforme con la especificacón CFast + + + El dispositivo sigue el conjunto de comandos de compatibilidad MMC. + + + El dispositivo es conforme con IEEE-1667 + + + El dispositivo sigue la especificación Secure Digital Physical Layer versión 1.0x + + + El dispositivo sigue la especificación Secure Digital Physical Layer versión 1.10 + + + El dispositivo sigue la especificación Secure Digital Physical Layer versión 2.00 + + + El dispositivo sigue la especificación Secure Digital Physical Layer versión 3.0x + + + El dispositivo sigue la especificación Secure Digital Physical Layer versión 4.xx + + + El dispositivo sigue la especificación Secure Digital Physical Layer versión 5.xx + + + El dispositivo sigue la especificación Secure Digital Physical Layer versión 6.xx + + + El dispositivo sigue la especificación Secure Digital Physical Layer versión 7.xx + + + El dispositivo sigue la especificación Secure Digital Physical Layer versión 8.xx + + + El dispositivo sigue la especificación Secure Digital Physical Layer versión desconocida {0}.{1}.{2}.{3} + + + El dispositivo sigue el conjunto de comandos estándar MMC versión 4.0 + + + El dispositivo sigue el conjunto de comandos estándar MMC con código de versión desconocida {0}. + + + El dispositivo sigue el conjunto de comandos desconocido MMC con código {0} y revisión código {1}. + + + El dispositivo tiene {0} bloques + + + El dispositivo tiene {0} bytes + + + El dispositivo tiene {0} GiB + + + El dispositivo tiene {0} KiB + + + El dispositivo tiene {0} KiB de caché + + + El dispositivo tiene {0} MiB + + + El dispositivo tiene {0} sectores + + + El dispositivo tiene {0} TiB + + + El dispositivo tiene una partición de arranque de {0} KiB + + + El dispositivo tiene un bloque de memoria de repetición de {0} KiB + + + El dispositivo tiene una caché no-volátil + + + El dispositivo tiene un tamaño de página de {0} KiB + + + El dispositivo tiene una caché volátil + + + El dispositivo tiene un World Wide Name + + + El dispositivo tiene operaciones críticas pendientes + + + El dispositivo tiene desactivadas las comprobaciónes de protección de información + + + El dispositivo tiene activado el encolado de comandos + + + El dispositivo tiene operaciones no críticas pendientes + + + El dispositivo no tiene caché + + + El dispositivo no tiene operaciones pendientes en segundo plano + + + El dispositivo tiene operaciones pendientes que afectan al rendimiento + + + El dispositivo tiene activada la protección segura contra escritura + + + El dispositivo tiene un modo de tiempo desconocido {0}. + + + El dispositivo implementa manejo alternativo del reinicio + + + El dispositivo implementa fase configurable del controlador + + + El dispositivo implementa HPI usando CMD12 + + + El dispositivo implementa HPI usando CMD13 + + + El dispositivo implementa RESET como reinicio suave + + + El dispositivo indica un valor mínimo específico del temporizador de espera + + + El dispositivo informa estar en buena salud + + + El dispositivo informa que debería ser reemplazado pronto + + + El dispositivo informa que debería ser reemplazado inmediatamente + + + La gestión de energía iniciada por el dispositivo está soportada + + + La gestión de energía iniciada por el dispositivo está soportada y activada + + + El dispositivo es un dispositivo dual soportando ópticos CD y no-CD + + + El dispositivo se direcciona por bytes + + + El dispositivo es capaz de reconocer tanto particiones como formato de medios + + + El dispositivo es capaz de reconocer formato de medios + + + El dispositivo es capaz de reconocer particiones de medio + + + El dispositivo está conectado y soportado. + + + El dispositivo está conectado pero no soportado. + + + El dispositivo está emulando sectores de 512 bytes + + + El dispositivo es fijo + + + El dispositivo está formateado como un disquete usando Microsoft FAT + + + El dispositivo está formateado como un disco duro + + + El dispositivo usa sectores duros + + + El dispositivo está en el nivel de consumo de energía relativamente más alto + + + El dispositivo está en modo Alta Velocidad. + + + El dispositivo está en modo HS-200. + + + El dispositivo está en modo HS-400. + + + El dispositivo está en un nivel de consumo de energía relativamente intermedio + + + El dispositivo está en el nivel de consumo de energía relativamente más bajo + + + El dispositivo está en modo de bajo consumo + + + El dispositivo no está activado para arrancar + + + El dispositivo no es capaz de reconocer ni particiones ni formato del medio + + + El dispositivo no usa codificación MFM + + + El dispositivo está permanentemente protegido contra escritura + + + El dispositivo se está encendiendo + + + El dispositivo es extraíble + + + El dispositivo es SDHC, SDXC o superior + + + El dispositivo se direcciona por sectores + + + El dispositivo usa sectores flojos + + + El dispositivo está soportado pero no conectado. + + + El dispositivo está protegido contra escritura temporalmente + + + El dispositivo es UHS-II o superior + + + El dispositivo está usando un bus de datos de 1-bit + + + El dispositivo está usando un bus de datos de 4-bits + + + El dispositivo está usando un bus de datos DDR de 4-bits + + + El dispositivo está usando un bus de datos de 8-bits + + + El dispositivo está usando un bus de datos DDR de 8-bits + + + El dispositivo está usando sectores de tamaño nativo + + + El dispositivo está usando un bus de datos desconocido código {0} + + + El dispositivo está dividido en zonas + + + El dispositivo fue fabricado en el mes {0} de {1} + + + El dispositivo puede ser mayor de 2GiB y tener su tamaño real definido en el CSD extendido + + + El dispositivo puede borrar cualquiera o todas las particiones al recibir un MODE SELECT para particionado + + + El dispositivo debe borrar un mínimo de {0} bloques a la vez + + + Nombre del dispositivo: {0} + + + El dispositivo usa sectores de 4096 bytes nativamente + + + El dispositivo usa sectores de 512 bytes nativamente + + + El dispositivo usa nativamente sectores de un tamaño desconocido indicado por el código {0} + + + El dispositivo necesita un cartucho de limpieza + + + El tamaño nominal del dispositivo tiene el valor desconocido {0} + + + El tamaño nominal del dispositivo es 1,8" + + + El tamaño nominal del dispositivo es 2,5" + + + El tamaño nominal del dispositivo es 3,5" + + + El tamaño nominal del dispositivo es 5,25" + + + El tamaño nominal del dispositivo es de menos de 1,8" + + + El dispositivo sólo soporta el acceso asimétrico explícito + + + El dispositivo sólo soporta el acceso asimétrico implícito + + + El consumo de energía del dispositivo está dictaminado por el identificado {0} del VPD de consumo de energía + + + El dispositivo imprime directamente + + + El dispositivo reconoce una única partición que ocupa todo el medio + + + Nivel de versión del dispositivo: {0} + + + El dispositivo requiere SET FEATURES para iniciarse y la respuesta de IDENTIFY DEVICE está completa + + + El dispositivo requiere SET FEATURES para iniciarse y la respuesta de IDENTIFY DEVICE está incompleta + + + DEVICE RESET está soporta y activado + + + El dispositivo respondió al comando ATA {0:X2}h + + + El dispositivo respondió al comando ATA IDENTIFY DEVICE. + + + El dispositivo respondió al comando ATA IDENTIFY PACKET DEVICE. + + + El dispositivo rota a {0} rpm. + + + El dispositivo envía reconocimiento de arranque + + + El dispositivo debería activar INTRQ cuando DRQ esté puesto a uno + + + El dispositivo debería borrar todas las particiones de tamaño distinto en un MODE SELECT de particionado + + + El dispositivo debería borrar todas las particiones en un MODE SELECT de particionado + + + El dispositivo no debería borrar ninguna partición en un MODE SELECT de particionado + + + El dispositivo debería devolver información de datos sense en formato de descriptor al devolverlo en las mismas transacciones que un CHECK CONDITION + + + El dispositivo debería establecer DRQ en 3ms de la recepción de un PACKET + + + El dispositivo debería establecer DRQ en 50µs de la recepción de un PACKET + + + El dispositivo debería usar un número de segmentos de caché o un tamaño de segmento de caché + + + Tamaño del dispositivo en modo LBA de 28-bits: {0} bytes, {1} Gb, {2} GiB + + + Tamaño del dispositivo en modo LBA de 28-bits: {0} bytes, {1} Mb, {2} MiB + + + Tamaño del dispositivo en modo LBA de 28-bits: {0} bytes, {1} Tb, {2} TiB + + + Tamaño del dispositivo en modo LBA de 48-bits: {0} bytes, {1} Gb, {2} GiB + + + Tamaño del dispositivo en modo LBA de 48-bits: {0} bytes, {1} Mb, {2} MiB + + + Tamaño del dispositivo en modo LBA de 48-bits: {0} bytes, {1} Tb, {2} TiB + + + Tamaño del dispositivo en modo CHS: {0} bytes, {1} Mb, {2} MiB + + + El tamaño del grupo de protección contra escritura más pequeño del dispositivo consta de {0} grupos de borrado + + + El dispositivo soporta transferencias de datos de 16-bits de ancho + + + El dispositivo soporta direccionado SCSI de 16-bits de ancho + + + El dispositivo soporta el bus de datos de 1-bit + + + El dispositivo soporta el modo de 26MHz + + + El dispositivo soporta transferencias de datos de 32-bits de ancho + + + El dispositivo soporta direccionado SCSI de 32-bits de ancho + + + El dispositivo soporta el bus de datos de 4-bits + + + El dispositivo soporta el modo de 52MHz + + + El dispositivo soporta el método de arranque alternativo + + + El dispositivo soporta la Capacidad de Reporte Asíncrona de Eventos + + + El dispositivo soporta el borrado automático de los bloques defectuosos retirados + + + El dispositivo soporta un máximo de {0} bytes para datos de sense + + + El dispositivo soporta un máximo de {0} lecturas empaquetadas y {1} escrituras empaquetadas + + + El dispositivo soporta operaciones de segundo plano + + + El dispositivo soporta encolado básico + + + El dispositivo soporta comandos de seguridad basados en capacidades + + + El dispositivo soporta el encolado de comandos con una profundidad de {0} + + + El dispositivo soporta la protección de contenido + + + El dispositivo soporta los comandos CONTINUE TASK y TARGET TRANSFER DISABLE + + + El dispositivo soporta la etiqueta de datos + + + El dispositivo soporta el modo DDR de 52MHz a 1,2V + + + El dispositivo soporta el modo DDR de 52MHz a 1,8V o 3V + + + El dispositivo soporta desactivar la corrección con WRITE LONG + + + El dispositivo soporta E/S de doble palabra + + + El dispositivo soporta arrancar en ratio de datos dual + + + El dispositivo soporta el modo intermitente mejorado + + + El dispositivo soporta seguridad extendida + + + El dispositivo soporta comandos de extensión de registro multi-bloque + + + El dispositivo soporta comandos de extensión de registro de bloque único + + + El dispositivo soporta FFU + + + El dispositivo soporta agrupamiento + + + El dispositivo soporta la activación en reinicio duro para nuevo microcódigo + + + El dispositivo soporta cabeza de cola + + + El dispositivo soporta frecuencia de alta velocidad en el arranque + + + El dispositivo soporta el modo HS-200 (SDR 200MHz) a 1,2V + + + El dispositivo soporta el modo HS-200 (SDR 200MHz) a 1,8V + + + El dispositivo soporta el modo HS-400 (DDR 200MHz) a 1,2V + + + El dispositivo soporta el modo HS-400 (DDR 200MHz) a 1,8V + + + El dispositivo soporta los accesos asimétricos implícitos y explícitos + + + El dispositivo soporta la transferencia de unidades de información + + + El dispositivo soporta la fuera del controlador de E/S tipo 4. + + + El dispositivo soporta la fuera del controlador de E/S tipo 1. + + + El dispositivo soporta la fuera del controlador de E/S tipo 3. + + + El dispositivo soporta la fuera del controlador de E/S tipo 2. + + + El dispositivo soporta la fuera del controlador de E/S tipo 0. + + + El dispositivo soporta comandos enlazados + + + El dispositivo soporta Control de Reporte de Errores de Alineación de Sectores Físicos Largos + + + El dispositivo soporta el direccionamiento jerárquico de LUNs + + + El dispositivo soporta marcar un bloque como incorregible usando WRITE LONG + + + El dispositivo soporta particiones extendidas no persistendes + + + El dispositivo sólo soporta el reloj DT + + + El dispositivo sólo soporta el reloj ST + + + El dispositivo soporta las funcionalidades de particionamiento + + + El dispositivo soporta la activación en encendido para nuevo microcódigo + + + El dispositivo soporta prioridad + + + El dispositivo soporta información de protección + + + El dispositivo soporta intervalos de información de protección + + + El dispositivo soporta Selección y Arbitrio Rápidos + + + El dispositivo soporta referencias + + + El dispositivo soporta direccionado relativo + + + El dispositivo soporta intercambios de confirmaciónes y de solicitud + + + El dispositivo soporta operaciones de purga + + + El dispositivo soporta operaciones de escritura segura + + + El dispositivo soporta establecer un máximo de {0} sectores + + + El dispositivo soporta establecer ACA normal + + + El dispositivo soporta el comando de contar bloques + + + El dispositivo soporta el comando de control de clase de velocidad + + + El dispositivo soporta el conjunto de comandos estándar de MMC + + + El dispositivo soporta los relojes ST y DT + + + El dispositivo soporta las operaciones de recorte seguras e inseguras + + + El dispositivo soporta la transferencia de datos síncrona + + + El dispositivo soporta particiones extendidas con código de sistema + + + El dispositivo soporta Recuperación de Desastre de Cinta + + + El dispositivo soporta el Espejo de Transmisión de la Cinta + + + El dispositivo soporta la cola TCQ + + + El dispositivo soporta el comando TERMINATE TASK + + + El dispositivo soporta el comando de barrera + + + El dispositivo soporta el atributo de tarea ORDERED + + + El dispositivo soporta la operación de sanitización + + + El dispositivo soporta el atributo de tarea SIMPLE + + + El dispositivo soporta comandos de copia de terceras partes + + + El dispositivo soporta datos de sense con llave específica a la condición de atención de la unidad + + + El dispositivo soporta el conjunto de comandos desconocido 0x{0:X2} + + + El dispositivo soporta activación específica del fabricante para nuevo microcódigo + + + El dispositivo soporta un modo específico del fabricante + + + El dispositivo soporta medios WORM + + + El dispositivo soporta WORM versión {0} + + + El dispositivo soporta las clases de comando {0} + + + La frecuencia del reloj del dispositivo: {0}{1} + + + La caché de escritura del dispositivo no es volátil + + + El dispositivo toma un máximo de {0} por defecto para apagarse después de una notificación del comando SWITCH + + + El dispositivo toma un máximo de {0}ms por defecto en el comando SWITCH + + + El dispositivo toma un máximo de {0}ms para borrar un único grupo de borrado + + + El dispositivo toma un máximo de {0}ms para inicializar después del particionado + + + El dispositivo toma un máximo de {0}ms para borrar con seguridad un único grupo de borrado + + + El dispositivo toma un máximo de {0}ms para recortar con seguridad un único grupo de borrado + + + El dispositivo toma un máximo de {0}ms para recortar un único grupo de borrado + + + El dispositivo toma un máximo de {0}ms para moverse al estado de reposo + + + El dispositivo toma un máximo de {0}ms para cambiar el estado de alerta de producción + + + El dispositivo toma un máximo de {0}ms para transicionar entre los estados de reposo y espera + + + El dispositivo toma un máximo de {0}ns para transicionar entre los estados de reposo y espera + + + El dispositivo toma un máximo de {0}s para moverse al estado de reposo + + + El dispositivo toma un máximo de {0}s para cambiar el estado de alerta de producción + + + El dispositivo toma un máximo de {0}µs para moverse al estado de reposo + + + El dispositivo toma un máximo de {0}µs para cambiar el estado de alerta de producción + + + El dispositivo toma un máximo de {0}µs para transicionar entre los estados de reposo y espera + + + La velocidad de transferencia del dispositivo es > 5 Mb/s pero <= 10Mb/s + + + La velocidad de transferencia del dispositivo es <= 5 Mb/s + + + La velocidad de transferencia del dispositivo es > 10Mb/s + + + Velocidad de transferencia del dispositivo: {0}{1} + + + El dispositivo ha usado entre un 10% y un 20% de su vida útil estimada + + + El dispositivo ha usado entre un 20% y un 30% de su vida útil estimada + + + El dispositivo ha usado entre un 30% y un 40% de su vida útil estimada + + + El dispositivo ha usado entre un 40% y un 50% de su vida útil estimada + + + El dispositivo ha usado entre un 50% y un 60% de su vida útil estimada + + + El dispositivo ha usado entre un 60% y un 70% de su vida útil estimada + + + El dispositivo ha usado entre un 70% y un 80% de su vida útil estimada + + + El dispositivo ha usado entre un 80% y un 90% de su vida útil estimada + + + El dispositivo ha usado entre un 90% y un 100% de su vida útil estimada + + + El dispositivo ha usado entre un 0% y un 10% de su vida útil estimada + + + El área de usuario está activada para arrancar + + + El dispositivo usa {0} mA en Vccq en reposo + + + El dispositivo usa {0} mA en Vcc en reposo + + + El dispositivo usa {0} µA en Vccq en reposo + + + El dispositivo usa {0} µA en Vcc en reposo + + + El dispositivo usa una política FIFO para el vaciado de caché + + + El dispositivo usa un máximo de 0.5mA para leer al voltaje mínimo + + + El dispositivo usa un máximo de 1mA para leer al voltaje mínimo + + + El dispositivo usa un máximo de 5mA para leer al voltaje mínimo + + + El dispositivo usa un máximo de 10mA para leer al voltaje mínimo + + + El dispositivo usa un máximo de 25mA para leer al voltaje mínimo + + + El dispositivo usa un máximo de 35mA para leer al voltaje mínimo + + + El dispositivo usa un máximo de 60mA para leer al voltaje mínimo + + + El dispositivo usa un máximo de 100mA para leer al voltaje mínimo + + + El dispositivo usa un máximo de 1mA para leer al voltaje máximo + + + El dispositivo usa un máximo de 5mA para leer al voltaje máximo + + + El dispositivo usa un máximo de 10mA para leer al voltaje máximo + + + El dispositivo usa un máximo de 25mA para leer al voltaje máximo + + + El dispositivo usa un máximo de 35mA para leer al voltaje máximo + + + El dispositivo usa un máximo de 45mA para leer al voltaje máximo + + + El dispositivo usa un máximo de 80mA para leer al voltaje máximo + + + El dispositivo usa un máximo de 200mA para leer al voltaje máximo + + + El dispositivo usa un máximo de 0.5mA para escribir al voltaje mínimo + + + El dispositivo usa un máximo de 1mA para escribir al voltaje mínimo + + + El dispositivo usa un máximo de 5mA para escribir al voltaje mínimo + + + El dispositivo usa un máximo de 10mA para escribir al voltaje mínimo + + + El dispositivo usa un máximo de 25mA para escribir al voltaje mínimo + + + El dispositivo usa un máximo de 35mA para escribir al voltaje mínimo + + + El dispositivo usa un máximo de 60mA para escribir al voltaje mínimo + + + El dispositivo usa un máximo de 100mA para escribir al voltaje mínimo + + + El dispositivo usa un máximo de 1mA para escribir al voltaje máximo + + + El dispositivo usa un máximo de 5mA para escribir al voltaje máximo + + + El dispositivo usa un máximo de 10mA para escribir al voltaje máximo + + + El dispositivo usa un máximo de 25mA para escribir al voltaje máximo + + + El dispositivo usa un máximo de 35mA para escribir al voltaje máximo + + + El dispositivo usa un máximo de 45mA para escribir al voltaje máximo + + + El dispositivo usa un máximo de 80mA para escribir al voltaje máximo + + + El dispositivo usa un máximo de 200mA para escribir al voltaje máximo + + + El dispositivo usa una caché de impresión + + + El dispositivo usa una caché de escritura + + + El dispositivo usa una caché de escritura pero no vuelve hasta que la caché está vaciada + + + El dispositivo usa ECC de tipo BCH(542, 512) por defecto + + + El dispositivo usa CPRM según la especificación versión 1.01 + + + El dispositivo usa CPRM según la especificación versión 2.00 + + + El dispositivo usa CPRM según la especificación versión 3.xx + + + El dispositivo usa la velocidad por defecto + + + El dispositivo usa medios no magnéticos + + + El dispositivo no usa ECC por defecto + + + El dispositivo usa ATA paralelo. + + + El dispositivo usa ATA en serie. + + + El dispositivo usa la velocidad {0} + + + El dispositivo usa intermitencia durante las respuestas de salida de datos y CRC + + + El dispositivo usa intermitencia durante las respuestas de salida de datos, CRC y CMD + + + El dispositivo usa Formato Universal de Fichero + + + El dispositivo usa CPRM según la especificación desconocido con código {0} + + + El dispositivo usa ECC de tipo desconocido según código {0} por defecto + + + El dispositivo usa un formato de fichero desconocido según código {0} + + + El dispositivo usa un formato de fichero desconocido según código {0} y grupo del formato 1 + + + El dispositivo usa un transporte desconocido según código {0} + + + Fabricante: {0} + + + Versión: {0} + + + Ancho del dispositivo: {0} bits + + + El dispositivo arrancará con un ancho del bus hasta x1 SDR o x4 DDR + + + El dispositivo arrancará con un ancho del bus hasta x4 SDR o DDR + + + El dispositivo arrancará con un ancho del bus hasta x8 SDR o DDR + + + El dispositivo no reducirá su rendimiento para alargar su vida + + + El dispositivo reiniciará las condiciones de arranque al modo de compatibilidad después de la operación de arranque + + + El dispositivo mantendrá las condiciones de arranque después de la operación de arranque + + + El dispositivo usará el ratio de datos dual en la operación de arranque. + + + El dispositivo usa tamaño de unidades de borrado de alta capacidad, y definiciones de tiempo de espera y tamaño del grupo de protección contra escritura + + + El dispositivo usará el ratio de datos simple con reloj compatible en la operación de arranque + + + El dispositivo usará el ratio de datos simple con reloj de alta velocidad en la operación de arranque + + + El dispositivo usará un método desconocido de arranque con código 3. + + + El dispositivo escribe directamente en el medio + + + Se permite la copia digital de la pista + + + Se prohíbe la copia digital de la pista + + + Dispositivo de acceso directo + + + Código de aplicación del disco: {0} + + + Código de barras del disco: {0} + + + El tipo de libro del disco es {0} + + + El disco arranca nativamente. + + + El disco arranca usando el cargador desconocido: {0}. + + + El disco arranca usando Windows CE. + + + El disco no puede ser jugado en ninguna región. + + + El disco puede ser grabado con o sin carcasa + + + El disco puede ser jugado en las siguientes regiones: + + + El disco puede ser jugando en cualquier región. + + + El disco es conforme a ECMA-267 + + + El disco es conforme a ECMA-268 + + + El disco es conforme a ECMA-272 + + + El disco es conforme a ECMA-274 + + + El disco es conforme a ECMA-279 + + + El disco es conforme a ECMA-330 + + + El disco es conforme a ECMA-337 + + + El disco es conforme a ECMA-338 + + + El disco es conforme a ECMA-349 + + + El disco es conforme a ECMA-359 + + + El disco es conforme a ECMA-364 + + + El disco es conforme a ECMA-365 + + + El disco es conforme a ECMA-371 + + + El disco es conforme a ECMA-374 + + + El disco es conforme a ECMA-382 + + + El disco es conforme a ECMA-384 + + + Clase del disco: {0} + + + El disco viene en un cartucho + + + El disco contiene información extendida para VCPS + + + El disco no tiene una BCA. + + + El disco no especifica una velocidad de transferencia máxima. + + + Disco para uso restringido. + + + Disco para uso no restringido. + + + Disco para uso en unidades especiales según el valor de intención {0} + + + El disco tiene {0} capas + + + El disco tiene {0} sesiones + + + El disco tiene {0} zonas + + + El disco tiene un diámetro de 120mm + + + El disco tiene un diámetro de 80mm + + + El disco tiene una BCA. + + + El disco tiene una velocidad de transferencia máxima de {0} Mbit/seg. + + + El disco ha sido certificado por el fabricante + + + El disco ha sido certificado por un usuario + + + El disco ha sido extraído del cartucho + + + El disco no tiene encriptación. + + + El disco tiene inihibda la escritura por la razón desconocida {0} + + + ID del disco: {0:X6} + + + El disco es un {0} {1} versión {2} + + + El disco es un disco óptico de Nintendo Gamecube (GOD) + + + El disco es un disco óptico de Nintendo Wii (WOD) + + + El disco es un CD-R + + + El disco es un CD-RW + + + El disco es un DDCD-R + + + El disco es un DDCD-RW + + + El disco está definido para el uso restringido + + + El disco está definido para el uso no restringido + + + El disco está vacío + + + El disco está encriptado usando AACS. + + + El disco está encriptado usando CPRM. + + + El disco está encriptado usando CSS o CPPM. + + + El disco está encriptado usando un algoritmo desconocido con ID {0}. + + + El disco es borrable + + + El disco está finalizado + + + El disco es un CD-R de alta velocidad (CAV) + + + El disco es un CD-RW High-Speed + + + El disco está incompleto + + + El disco es un medio de tipo A, CD-R de categoría beta alta (A+) + + + El disco es un medio de tipo B, CD-RW de categoría beta alta (B+) + + + El disco es un medio de tipo B, CD-R de categoría beta alta (B+) + + + El disco es un medio de tipo C, CD-RW de categoría beta alta (C+) + + + El disco es un medio de tipo C, CD-R de categoría beta alta (C+) + + + El disco es un medio de tipo A, CD-R de categoría beta baja (A-) + + + El disco es un medio de tipo B, CD-R de categoría beta baja (B-) + + + El disco es un medio de tipo B, CD-RW de categoría beta baja (B-) + + + El disco es un medio de tipo C, CD-RW de categoría beta baja (C-) + + + El disco es un medio de tipo C, CD-R de categoría beta baja (C-) + + + El disco es un CD-R de velocidad normal (CLV) + + + El disco es RW (regrabable) + + + El disco es R (grabable) + + + El disco es un CD-RW Ultra-Speed + + + El disco es un CD-RW Ultra-Speed+ + + + El disco tiene inhibida la escritura por haber sido extraído del cartucho + + + El disco tiene inhibida la escritura por una razón desconocida + + + Disco fabricado por: {0} + + + ID del fabricante del disco: "{0}" + + + El fabricante del disco es {0} + + + La información suplementaria del fabricante del disco es {0} + + + La velocidad de transferencia máxima del disco es 10,08 Mbit/seg. + + + La velocidad de transferencia máxima del disco es 20,16 Mbit/seg. + + + La velocidad de transferencia máxima del disco es 2,52 Mbit/seg. + + + La velocidad de transferencia máxima del disco es 30,24 Mbit/seg. + + + La velocidad de transferencia máxima del disco es 5,04 Mbit/seg. + + + La velocidad de transferencia máxima del disco está especificada por el código desconocido {0} + + + La velocidad de transferencia máxima del disco no está especificada + + + El disco se puede escribir sin un cartucho + + + Medio del disco: {0} + + + El ID del tipo de medio del disco es: "{0}" + + + El tipo de medio del disco es {0} + + + Disco número {0} de {1} + + + La revisión de producto del disco es {0} + + + Número de revisión de producto del disco: {0} + + + La reflectividad del disco está entre el 18% y el 30% + + + La reflectividad del disco está entre el 45% y el 85% + + + El disco debería escribirse sin carcasa + + + El disco no debería escribirse sin un cartucho + + + Tamaño del disco: 120mm + + + Tamaño del disco: 80mm + + + Tamaño del disco: código desconocido {0} + + + La superficie del disco tiene el estado de protección contra escritura + + + Fechado del disco: 0x{0:X2} + + + La pendiente de pista es de 0,74µm + + + Tipo de disco: {0} + + + El disco está declarado como un CD-DA o un CD-ROM + + + El disco está declarado como un CD-i + + + El disco está declarado como un CD-ROM XA + + + Identificador del tipo de disco: "{0}" + + + El tipo de disco no está definido + + + 1er campo específico del tipo de disco: 0x{0:X2} + + + 2º campo específico del tipo de disco: 0x{0:X8} + + + El disco usa un canal de 69,0nm dando 27Gb por capa. + + + El disco usa un canal de 74,5nm dando 25Gb por capa. + + + El disco usa un tipo de colorante de larga estrategia (Cianina, AZO, etc...) + + + El disco usa polaridad negativa. + + + El disco usa cambio de fase + + + El disco usa polaridad positiva + + + El disco usa un tipo de colorante de corta estrategia (Ftalocianina, etc...) + + + El disco tiene un código de BCA desconocido: {0} + + + El disco usa una longitud de canal desconocido con código {0} + + + El disco usa una polaridad desconocida con código {0} + + + El disco usa una polaridad de reflectividad grabada desconocida con código {0} + + + El uso del disco es restringido + + + El uso del disco no es restringido + + + Versión del disco: {0} + + + Formato de la unidad DI: 0x{0:X2} + + + La unidad DI ocupa {0} bytes + + + Secuencia de la unidad DI: {0} + + + DLTtape III comprimida + + + DLTtape III a 42500 bpp + + + DLTtape III con 56 pistas + + + DLTtape III a 62500 bpp + + + DLTtape IIIxt + + + DLTtape IIIxt comprimida + + + DLTtape IV + + + DLTtape IV comprimida + + + DLTtape IV a 123090 bpp comprimida + + + DLTtape IV a 85937 bpp comprimida + + + DLTtape IV a 98250 bpp comprimida + + + DLTtape IV a 123090 bpp + + + DLTtape IV a 85937 bpp + + + DLTtape IV a 98250 bpp + + + DMA soportado + + + La auto-activación de la configuración DMA está soportada + + + La auto-activación de la configuración DMA está soportada y activada + + + Modo de reloj DMA: {0} + + + Título doméstico: {0} + + + Se utiliza un código de caracteres de doble byte + + + DOWNLOAD MICROCODE DMA está soportado + + + DOWNLOAD MICROCODE está soportado + + + DOWNLOAD MICROCODE está soportado y activado + + + La unidad acepta un máximo de {0} bloques en un comando READ durante una reconstrucción + + + La unidad acepta un máximo de {0} bloques en un comando REGENERATE + + + La unidad acepta un máximo de {0} bloques en un único comando XOR WRITE + + + La unidad acepta datos empaquetados del subcanal R-W + + + La unidad acepta datos sin procesar del subcanal R-W + + + La unidad permite sobreescribir todas las etiquetas de formato + + + La unidad permite sobreescribir una cabecera de pista + + + La unidad y el medio insertado soportan SecurDisc + + + La unidad y el medio insertado soportan VCPS + + + La unidad puede leer DVD+MRW así como leer y escribir CD-MRW + + + La unidad puede leer el subcanal R-W del Lead-In sin procesar + + + Los segmentos de caché de la unidad deberían ser {0} bloques de largo + + + Los segmentos de caché de la unidad deberían ser {0} bytes de largo + + + La unidad no puede almacenar extents de LBA + + + La unidad puede ser usada como un dispositivo de disquete de sistema + + + La unidad puede cambiar el lado del disco + + + La unidad puede continuar en una pérdida de transmisión + + + La unidad puede proveer una transmisión compuesta de audio y video + + + La unidad puede hacer un formateo de inicio rápido + + + La unidad puede hacer una prueba de escritura + + + La unidad puede expulsar el medio + + + La unidad puede ampliar el área de reserva en un disco BD-RE formateado + + + La unidad puede re-formatear rápidamente discos BD-RE + + + La unidad puede formatear discos BD-RE con certificación completa + + + La unidad puede formatear discos BD-RE con certificación rápida + + + La unidad puede formatear discos BD-RE sin asignar reservas + + + La unidad puede formatear discos BD-R en formato RRM + + + La unidad puede formatear el medio en bloques lógicos + + + La unidad puede generar datos de estado de defectos durante el formateo + + + La unidad puede bloquear el medio + + + La unidad puede sobreescribir una pista TAO con otra en los CD-RW + + + La unidad puede reproducir audio + + + La unidad puede leer y escribir CD-MRW + + + La unidad puede leer y escribir CD-MRW y DVD+MRW + + + La unidad puede leer y escribir CD-R + + + La unidad puede leer y escribir CD-RW + + + La unidad puede leer y escribir DVD+MRW + + + La unidad puede leer y escribir DVD+R + + + La unidad puede leer y escribir DVD+RW DL + + + La unidad puede leer y escribir DVD+R DL + + + La unidad puede leer y escribir DVD-R + + + La unidad puede leer y escribir DVD-RAM + + + La unidad puede leer y escribir DVD+RW + + + La unidad puede leer el código de barras + + + La unidad puede leer el Burst Cutting Area de un Blu-ray + + + La unidad puede leer BD-RE de versión anterior a la 1.0 + + + La unidad puede leer BD-RE versión 1 + + + La unidad puede leer BD-RE versión 2 + + + La unidad puede leer BD-ROM de versión anterior a la 1.0 + + + La unidad puede leer BD-ROM versión 1 + + + La unidad puede leer BD-R de versión anterior a la 1.0 + + + La unidad puede leer BD-R versión 1 + + + La unidad puede leer ambos lados de un disco + + + La unidad puede leer CD-MRW + + + La unidad puede leer CD-MRW y DVD+MRW + + + La unidad puede leer CD-R + + + La unidad puede leer CD-RW + + + La unidad puede leer DDCD + + + La unidad puede leer los datos de estado de defectos grabados en el medio + + + La unidad puede leer audio digital + + + La unidad puede leer medios DVD + + + La unidad puede leer DVD+R + + + La unidad puede leer DVD+RW + + + La unidad puede leer DVD+RW DL + + + La unidad puede leer DVD-R + + + La unidad puede leer DVD-RAM + + + La unidad puede leer DVD-ROM + + + La unidad puede leer DVD-RW DL en todos los modos de grabación + + + La unidad puede leer DVD-R DL en todos los modos de grabación + + + La unidad puede leer HD DVD-ROM y HD DVD-RW + + + La unidad puede leer HD DVD-ROM, HD DVD-RW y HD DVD-R + + + La unidad puede leer HD DVD-ROM, HD DVD-RW y HD DVD-RAM + + + La unidad puede leer HD DVD-ROM, HD DVD-RW, HD DVD-R y HD DVD-RAM + + + La unidad puede leer el ISRC + + + La unidad puede leer el número de catálogo del medio + + + La unidad puede leer sectores en formato Modo 2 Forma 1 + + + La unidad puede leer sectores en formato Modo 2 Forma 2 + + + La unidad puede leer los subcanales R-W sin corrección y entrelazados + + + La unidad puede leer, desentrelazar y corregir los subcanales R-W + + + La unidad puede devolver el CD-Text del Lead-In + + + La unidad puede devolver información sobre el área de reemplazo + + + La unidad puede parar una operación inmediata larga + + + La unidad puede almacenar {0} extents de LBA + + + La unidad puede almacenar 256 extents de LBA + + + La unidad puede escribir BD-RE de versión anterior a la 1.0 + + + La unidad puede escribir BD-RE versión 1 + + + La unidad puede escribir BD-RE versión 2 + + + La unidad puede escribir BD-R en modo Seudo-Sobre-Escritura SRM + + + La unidad puede escribir BD-R de versión anterior a la 1.0 + + + La unidad puede escribir BD-R versión 1 + + + La unidad puede escribir CDs en modo sin procesar: + + + La unidad puede escribir CDs en modos sin procesar y Sesión por Vez (SAO): + + + La unidad puede escribir CDs en modo Sesión por Vez (SAO): + + + La unidad puede escribir CDs en modo Pista por Vez (TAO): + + + La unidad puede escribir CD-RW + + + La unidad puede escribir HD DVD-RW + + + La unidad puede escribir HD DVD-RW y HD DVD-R + + + La unidad puede escribir HD DVD-RW y HD DVD-RAM + + + La unidad puede escribir HD DVD-RW, HD DVD-R y HD DVD-RAM + + + La unidad puede escribir CD-RW High-Speed + + + La unidad puede escribir CDs multi-sesión en modo sin procesar + + + La unidad puede escribir esta densidad + + + La unidad puede escribir datos provistos por el usuario en los subcanales R-W + + + La unidad clama la capacidad de leer todos los formatos de CD según la Especificación Multi-Lectura de OSTA + + + La unidad clama soporte de reportar la Información de Recursos de Pista + + + La unidad clama conformidad con la Especificacón de Unidad DVD de Multi Lectura + + + La unidad contiene un intercambiador que puede reportar el contenido exacto de las ranuras + + + Copyright de la unidad: {0} + + + La velocidad actual de lectura de la unidad es de {0} Kbyte/seg. + + + La velocidad actual de escritura de la unidad es de {0} Kbyte/seg. + + + La velocidad actual de escritura en modo CLV de la unidad es de {0} Kbyte/seg. + + + La velocidad actual de escritura en modo CAV puro de la unidad es de {0} Kbyte/seg. + + + La fecha/hora de la unidad es: {0} + + + La unidad no permite sobreescribir ningún bloque lógico + + + La unidad no hace distinción entre los datos leídos cacheados + + + La unidad no hace distinción entre los datos escritos cacheados + + + La unidad no soporta la compresión de datos + + + La unidad no usa la compresión + + + Versión de la EEPROM de la unidad: {0} + + + El firmware de la unidad está fechado a {0} + + + La unidad genera fin-de-datos + + + Versión del hardware de la unidad: {0} + + + La unidad tiene {0} zonas de caché DBI + + + La unidad tiene {0} entradas DBI + + + La unidad tiene un incremento {0} de unidad de tiempo del Grupo 3 + + + La unidad tiene {0} Kbyte de búfer + + + La unidad tiene {0} ranuras + + + La unidad tiene disponibles {0} cambios controlados por el usuario. + + + La unidad tiene disponibles {0} reinicios del fabricante. + + + La unidad tiene {0} niveles de volumen + + + La unidad tiene una salida de audio analógica + + + La unidad ha estado operando {0} + + + La unidad ha sido encendida {0} veces + + + La unidad ha estado encendida un total de {0} segundos + + + La unidad ha estado encendida esta vez los últimos {0} segundos + + + La unidad tiene la encriptación activada + + + La unidad no tiene una región establecida. + + + La unidad tiene establecidas las siguientes regiones: + + + La unidad tiene dos LUNs siendo el de reescritura el + + + La unidad informa de un perfil desconocido código 0x{0:X4} + + + La unidad es capaz de acceder a discos híbridos + + + La unidad es capaz de mantener la capa de formato en líne en un reinicio o apagado + + + La unidad puede silenciar los canales por separado + + + La unidad es capaz de realizar la gestión de energía controlada por sí misma y por el sistema + + + La unidad puede leer el número de serie del medio + + + La unidad puede reportar el contenido de las ranuras después de un reinicio o cambio + + + La unidad es un intercambiador con cartuchos + + + La unidad es un intercambiador de discos individuales + + + La unidad es un dispositivo óptico no CD + + + La unidad es capaz de vincular con pérdida cero + + + La unidad está desactivada hasta un ciclo de energía + + + La unidad está emulando una unidad de CD-ROM + + + La unidad ha sido escrita con el firmware Kreon {0}. + + + La unidad está bloqueada, el medio no puede ser expulsado ni insertado + + + La unidad está bloqueada, el medio no puede ser expulsado, pero si está vacía, sí puede ser insertado + + + La unidad no sigue ningún perfil + + + La unidad no está emulando una unidad de CD-ROM + + + La unidad no está bloqueada, el medio puede ser expulsado e insertado + + + La unidad está operando en modo WORM + + + La unidad se abre por arriba + + + La unidad está libre de regiones. + + + La unidad está protegida contra escritura a través de software hasta su apagado + + + Los puentes de la unidad eligen el ID SCSI {0} + + + La velocidad máxima de lectura de la unidad es de {0} Kbyte/seg. + + + La velocidad máxima de escritura de la unidad es de {0} Kbyte/seg. + + + El medio es extraíble + + + La unidad necesita un mínimo de {0} ms entre comandos READ durante una reconstrucción + + + La unidad necesita {0} pulsos de paso por cilindro + + + La unidad opera usando un modo de direccionamiento explícito + + + La unidad opera usando un modo de direccionamiento implícito + + + La unidad se enciende bloqueada + + + La región de la unidad está establecida permanentemente, pero puede reiniciarse por el fabricante si es necesario. + + + La región de la unidad está establecida. + + + La región de la unidad está establecida, con restricciones adicionales requeridas para cambiarla. + + + La unidad reporta un número de perfil reservado + + + La unidad reporta advertancias tempranas + + + La unidad reporta marcas + + + La unidad reponde al ID SCSI {0} + + + Número de parte del servo de la unidad: {0} + + + La unidad debería asignar {0} bytes al búfer incluso cuando no se puede expulsar ningún dato de la caché + + + La unidad debería ser capaz de proveer un espacio de direccionado libre de defectos contiguo + + + La unidad debería tener la abilidad de sobreescribir bloques lógicos sólo en conjuntos fijos cada vez + + + La unidad debería anotar condiciones de excepción informacionales + + + La unidad debería mantener su posición en un reinicio + + + La unidad debería posicionarse al principio de la partición de datos por defecto en un reinicio + + + La unidad debería reportar la página de Recuperación de Errores de Lectura/Escritura + + + La unidad debería reportar los errores corregidos + + + La unidad debería tener {0} segmentos de caché + + + La unidad no debería reordenar la secuencia de los comandos de escritura para ser más rápida + + + La unidad da pasos en {0} ns + + + La unidad da pasos en {0} µs + + + La unidad soporta {0} AGIDs concurrentemente + + + La unidad soporta {0} LUNs + + + La unidad soporta {0} niveles de volumen + + + La unidad soporta AACS versión {0} + + + La unidad soporta AACS versión {0} y el disco actual está encriptado + + + La unidad soporta el modo de reserva de direccionamiento en el comando RESERVE TRACK + + + La unidad soporta Almacenamiento Avanzado - Magneto-Óptico + + + La unidad soporta un máximo de {0} bytes en una sola hoja de referencia + + + La unidad soporta BD-RE + + + La unidad soporta BD-ROM + + + La unidad soporta BD-R RRM + + + La unidad soporta BD-R SRM + + + La unidad soporta ambas formar de parar un formateo en segundo plano + + + La unidad soporte la grabación libre de insuficiencias del búfer + + + La unidad soporta encriptación del bus + + + La unidad soporta Punteros de Error C2 + + + La unidad soporta punteros C2 + + + La unidad soporta CD-R + + + La unidad soporta CD-ROM + + + La unidad soporta CD-RW + + + La unidad soporta subtipos de CD-RW + + + La unidad soporta los tipos de bloque de datos: + + + La unidad soporta la compresión de datos + + + La unidad soporta el DCB {0:X8}h + + + La unidad soporta DDCD-R + + + La unidad soporta DDCD-ROM + + + La unidad soporta DDCD-RW + + + La unidad soporta eventos de dispositivo ocupado + + + La unidad soporta los bits DPO y FUA + + + La unidad soporta el modo DRT-DM + + + La unidad soporta CPRM para DVD versión {0} + + + La unidad soporta CPRM para DVD versión {0} y el disco actual está o puede ser encriptado + + + La unidad soporta CSS y/o CPPM para DVD + + + La unidad soporta CSS y/o CPPM para DVD versión {0} + + + La unidad soporta CSS y/o CPPM para DVD versión {0} y el disco actual está encriptado + + + La unidad soporta DVD-Download + + + La unidad soporta DVD+R + + + La unidad soporta DVD+RW + + + La unidad soporta DVD+RW DL + + + La unidad soporta DVD+R DL + + + La unidad soporta DVD-R + + + La unidad soporta DVD-RAM + + + La unidad soporta DVD-ROM + + + La unidad soporta DVD-RW DL + + + La unidad soporta encriptación + + + La unidad soporta EVPD, Código de Página y Longitud de Asignación de 16-bits tal como describe SPC-3 + + + La unidad soporta generar el nonce vinculante + + + La unidad soporta el formateo en sectores duros + + + La unidad soporta HDBurn CD-R + + + La unidad soporta HDBurn CD-ROM + + + La unidad soporta HDBurn CD-RW + + + La unidad soporta HD DVD-R + + + La unidad soporta HD DVD-RAM + + + La unidad soporta HD DVD-ROM + + + La unidad soporta HD DVD-RW + + + La unidad soporta HD DVD-RW DL + + + La unidad soporta HD DVD-R DL + + + La unidad soporta salida digital IEC-958 en el puerto 1 + + + La unidad soporta salida digital IEC-958 en el puerto 2 + + + La unidad soporta DVD-R grabados con salto de capa + + + La unidad soporta OSPBs vinculados + + + La unidad soporta medios Magneto-Ópticos + + + La unidad soporta medios que requieren borrando antes de su escritura + + + La unidad soporta actualizar el microcódigo + + + La unidad soporta discos multi-sesión y/o Photo-CD + + + La unidad soporta medios intercambiables no extraíbles + + + La unidad sólo soporta preguntar GET EVENT STATUS NOTIFICATION + + + La unidad sólo soporta la parada de lectura de compatibilidad + + + La unidad soporta eventos de solicitud / notificación de cambio operacional + + + La unidad soporta medios ópticos de escritura única + + + La unidad soporta el modo DM persistente + + + La unidad soporta GET EVENT STATUS NOTIFICATION preguntados y asíncronos + + + La unidad soporta actualizar el PSA en medios de escritura única + + + La unidad soporta el formateo rápido + + + La unidad soporta leer CD-R empaquetados + + + La unidad soporta leer el Media Key Block de CPRM + + + La unidad soporta leer el Certificado de la Unidad + + + La unidad soporte leer/escribir el PAC de protección contra escritura en medios BD-R y BD-RE + + + La unidad soporta recuperar datos del búfer + + + La unidad soporta reportar el progreso del formateo + + + La unidad soporta la sobreescritura restringida en DVD-RW + + + La unidad soporta medios reescribibles y estraíbles + + + La unidad soporta SecurDisc + + + La unidad soporta un volumen separado por canal + + + La unidad soporta DVD-RW grabados secuencialmente + + + La unidad soporta DVD-R DL grabados secuencialmente + + + La unidad soporta Establecer Rendimiento Mínimo con el comando SET STREAMING + + + La unidad soporta establecer/liberar el estado de PWP + + + La unidad soporta S.M.A.R.T. + + + La unidad soporta el formateo en sectores flojos + + + La unidad soporta la escritura en transmisión + + + La unidad soporta la prueba de escritura + + + La unidad soporta el comando BLANK + + + La unidad soporta el bit de bloqueo en el comando READ BUFFER CAPACITY + + + La unidad soporta el bit DAP en los comandos READ CD y READ CD MSF + + + La unidad soporte el Grupo 3 en la página de modo de Protección y Tiempo de espera 1Dh + + + La unidad soporta la página de modo de Control de Excepciones Informacionales 1Ch + + + La unidad soporta el comando SCAN + + + La unidad soporta el comando SET CD SPEED + + + La unidad soporta el bit SWPP de la página de modo de Protección y Tiempo de espera + + + La unidad soporta la Clase del Subsistema de Seguridad Óptica del Grupo de Computación Confiable + + + La unidad soporta los datos de velocidad de escritura en GET PERFORMANCE y el campo WRC en SET STREAMING + + + La unidad soporta los bloques de descripción del rendimiento de escritura en la página de modo MMC 2Ah + + + La unidad soporta la página de modo de Protección y Tiempo de espera 1Dh + + + La página soporta validad el Modo de 5-bits de los comandos READ BUFFER y WRITE BUFFER + + + La unidad soporta VCPS + + + La unidad soporta escribir sin ningún requisito de verificación + + + La unidad soporta escribir a {0} Kbyte/seg. en modo CLV + + + La unidad soporta escribir a {0} Kbyte/seg. en modo CAV puro + + + La unidad soporta escribir DDCD-R + + + La unidad soporta escribir DDCD-RW + + + La unidad soporta escribir DVD-R + + + La unidad soporta escribir DVD-R y DVD-RW + + + La unidad soporta escribir DVD-R y DVD-R DL + + + La unidad soporta escribir DVD-R, DVD-RW y DVD-R DL + + + La unidad soporta escribir en un estado de sesión intermediaria y el formateo rápido + + + La unidad soporta el DCB de inhibición de escritura en medios DVD+RW + + + La unidad soporta escribir con encriptación del bus + + + La unidad soporta enlazado de pérdida cero + + + El tiempo de la unidad está sincronizado con una fuente NTP + + + El tiempo de la unidad está en UTC + + + La unidad usa una interfaz ATAPI + + + La unidad usa una interfaz IEEE-1394A + + + La unidad usa una interfaz IEEE-1394B + + + La unidad usa una interfaz IEEE-1394 + + + La unidad usa una interfaz desconocida con código {0} + + + La unidad usa una interfaz física no especificada + + + La unidad usa una interfaz USB + + + La unidad usa una interfaz Fibre Channel + + + La unidad usa una interfaz SCSI + + + La unidad usa una interfaz ATAPI serial + + + La unidad usa una bandeja + + + La unidad usa una interfaz propietaria del fabricante + + + La unidad utiliza la compresión por defecto + + + La unidad usa un carrito para el medio + + + La unidad usa la compresión desconocida {0} + + + La unidad usa el mecanismo de carga desconocido {0} + + + La unidad abortará al detectar un error de escritura + + + La unidad demorará {0} ms antes de que los datos del búfer sean escritor a la fuerza en el medio incluso antes de que el búfer se llene + + + La unidad no hará nada con un medio WORM manipulado + + + La unidad expulsará los cartuchos de limpieza ante un error + + + La unidad expulsará los cartuchos de datos ante un error + + + La unidad expulsará los cartuchos de firmware ante un error + + + La unidad empleará un máximo de {0} ms para recuperar datos + + + La unidad se liberará y posicionará por sí misma en un reinicio de LUN o destino + + + La unidad mantendrá la posición en un reinicio de LUN o destino + + + La unidad no aceptará bajar el firmware con una cinta FMR + + + La unidad no saldrá de la emulación automáticamente + + + La unidad sólo grabará un disco en formato OSSC + + + La unidad sólo responderá a los comandos si ha recibido una reserva + + + La unidad solicitará limpieza periódicamente + + + La unidad pre-leerá hasta llenar el búfer + + + La unidad pre-leerá hasta detectar una marca de fichero + + + La unidad pre-leerá hasta detectar tres marcas de fichero + + + La unidad pre-leerá hasta detectar dos marcaa de fichero + + + La unidad se mantendrá en el mismo estado 125 ms después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 250 ms después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 500 ms después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 1 segundo después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 2 segundos después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 4 segundos después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 8 segundos después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 16 segundos después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 32 segundos después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 1 minuto después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 2 minutos después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 4 minutos después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 8 minutos después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 16 minutos después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado 32 minutos después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el mismo estado durante un tiempo específico del fabricante después de una operación de posicionamiento, lectura o escritura + + + La unidad se mantendrá en el estado de mantener la pista 125 ms después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 250 ms después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 500 ms después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 1 segundo después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 2 segundos después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 4 segundos después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 8 segundos después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 16 segundos después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 32 segundos después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 1 minuto después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 2 minutos después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 4 minutos después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 8 minutos después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 16 minutos después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista 32 minutos después de un posicionamiento o lectura + + + La unidad se mantendrá en el estado de mantener la pista un tiempo específico del fabricante después de una operación de posicionamiento o lectura + + + La unidad repetirá las operaciones de lectura {0} veces + + + La unidad repetirá las operaciones de verificación {0} veces + + + La unidad repetirá las operaciones de escritura {0} veces + + + La unidad reportará los errores de auto-prueba en segundo plano + + + La unidad responderá al ID SCSI {0} en la activación del Puerto A + + + La unidad retornará CHECK CONDITION con un medio WORM manipulado + + + La unidad volverá del comando de reproducción inmediatamente + + + La unidad volverá del comando de reproducción cuando esta termine + + + La unidad establecerá CHECK CONDITION cuando sea necesaria una limpieza + + + La unidad establecerá CHECK CONDITION cuando se cumplan los criterios de medio muerto + + + La unidad detendrá la reproducción al finalizar la pista + + + La unidad sincronizará el búfer con el medio ante advertencias tempranas + + + La unidad transferirá la longitud solicitada completa sin demora al realizar recuperación de errores + + + La unidad usará primero los métodos más oportunos de recuperación de errores + + + El conjunto de funcionalidades DSN está soportado + + + El conjunto de funcionalidades DSN está soportado y activado + + + DT1825 está soportado + + + DT1825 está soportado y activado + + + El colorante es orgánico + + + El colorante es de cambio de fase + + + Cada canal puede silenciarse independientemente + + + El volumen de cada canal puede controlarse independientemente + + + Cada minuto tiene {0} segundos + + + Cada segundo tiene {0} fotogramas + + + Cada pulso de paso dura {0} ms + + + ECMA-46 & ANSI X3.56-1986: Cartucho de Cinta Magnética de 6,30 mm, Codificación por Fase, 63 bpmm + + + ECMA-62 & ANSI X3.22-1983: Cinta Magnética de 9 pistas y 12,7 mm, 32 tfpmm, NRZI, 32 cpmm + + + ECMA-62 & ANSI X3.54-1986: Cinta Magnética de 9 pistas y 12,7 mm, 356 tfpmm, NRZI, 245 cpmm GCR + + + ECMA-62 & ANSI X3.39-1986: Cinta Magnética de 9 pistas y 12,7 mm, 126 tfpmm, Codificación por Fase, 63 cpmm + + + ECMA-79 & ANSI X3.116-1986: Cartucho de Cinta Magnética de 6,30 mm, 252 tfpmm, MFM + + + ECMA-98: Cartucho de Cinta Magnética de 6.30 mm, NRZI, 394 tfpmm + + + ECMA TC17: Cartucho de Cinta Magnética de 8 mm, 1789 bpmm, RLL + + + Versión del formato de la EEPROM: {0}.{1} + + + Dispositivo de servicios de carcasa + + + Tiempo final del intervalo que debe ser esquivado: {0:D2}:{1:D2}:{2:D2} + + + Fin de fichero. + + + Encontrado fin de medio o partición + + + Fin de registro. + + + Epílogo {0:X2}{1:X2}{2:X2} + + + El rango de memoria borrado debería ser '{0}'. + + + Bloque de borrado: {0} bytes + + + El ratio de energía de borrado no está especificado + + + Error de clase {0} tipo {1} + + + Error de clase {0} tipo {1} occurido en el bloque {2} + + + La corrección de errores está desactivada + + + PAL (Europa) + + + EXB-8200 + + + EXB-8200 comprimida + + + EXB-8500 + + + EXB-8500 comprimida + + + Se esperaba un tamaño de CDFullTOC ({0} bytes) que no es el recibido ({1} bytes), no se descodificará + + + Se esperaba un tamaño de CDSessionInfo ({0} bytes) que no es el recibido ({1} bytes), no se descodificará + + + Se esperaba un tamaño de ATIP de CD (32 bytes) que no es el recibido ({0} bytes), no se descodificará + + + Se esperaba un tamaño de PMA de CD ({0} bytes) que no es el recibido ({1} bytes), no se descodificará + + + Se esperaba un tamaño de CD-Text ({0} bytes) que no es el recibido ({1} bytes), no se descodificará + + + Se esperaba un tamaño de CD TOC ({0} bytes) que no es el recibido ({1} bytes), no se descodificará + + + La Lealtad Contingente Extendida está activada + + + Las Condiciones Extendidas de Energía están soportadas + + + Las Condiciones Extendidas de Energía están soportadas y activada + + + El auto-text extendido toma {0} en completarse + + + El Reporte Extendido de Estado está soportado + + + El Reporte Extendido de Estado está soportado y activado + + + El extent comienza en el PSN {0:X6}h y termina en el PSN {1:X6}h + + + El código de prueba de fábrica 1 está desactivado + + + El código de prueba de fábrica 2 está desactivado + + + El código de prueba de fábrica está desactivado + + + La unidad puede expulsar el medio + + + La unidad puede cargar el medio + + + La unidad puede bloquear el medio + + + La unidad es un intercambiador que usa cartuchos + + + La unidad es un intercambiador de discos individuales + + + La unidad se abre desde arriba + + + La unidad enciende bloqueada + + + La unidad reporta eventos de Clase de Dispositivo Ocupado en la carga/descarga del medio + + + La unidad usa una bandeja + + + La unidad usa un carrito para el medio + + + La unidad usa un mecanismo de carga desconocido tipo {0} + + + Medio extraíble MMC: + + + La unidad puede leer DVD+R DL + + + La unidad es capaz de detectar y reportar medios escribibles defectuosos y comportarse adecuadamente + + + El comportamiento de la reja es normal + + + Fibre Channel + + + Encontrada marca de fichero o genérica + + + Número de fichero: {0} + + + Terminado el sector en {0} + + + Cartucho de firmware insertado + + + Personalidad del firmware: {0} + + + Sub-personalidad del firmware: {0} + + + Las actualizaciones del firmware están permanentemente desactivadas + + + Firmware versión: {0} + + + Firmware versión: {0}.{1} + + + Número de dirección de la primera zona de datos en esta capa: {0} + + + Número de la primera sesión completa: {0} + + + Primer PSN de la Lista de Defectos: 0x{0:X8} + + + Primer PSN del Área de la Unidad: 0x{0:X8} + + + Primer bloque de entrada + + + Primer bloque de salida + + + La primera pista de la última sesión es la pisa {0} + + + Número de la primera pista: {0} ( + + + Número de la primera pista en la primera sesión completa: {0} + + + Número de la primera pista en la último sesión completa: {0} + + + La primera pista del disco es la pista {0} + + + Número de la primera pista de video: {0} + + + FLUSH CACHE EXT está soportado + + + FLUSH CACHE EXT está soportado y activado + + + FLUSH CACHE está soportado + + + FLUSH CACHE está soportado y activado + + + Formateo en progreso. + + + El formateo sólo está usando la certificación parcial + + + Progreso del formateo {0:P} + + + Se requiere la tolerancia de separación de la velocidad del formateo + + + Forma 1. + + + Forma 2. + + + Encontrado tamaño de BCA de Blu-ray incorrecto ({0} bytes) + + + Encontrado tamaño de Estado del Cartucho de Blu-ray incorrecto ({0} bytes) + + + Encontrado tamaño de Información del Disco de Blu-ray incorrecto ({0} bytes) + + + Encontrada firma de DDS incorrecta (0x{0:X4}) + + + Encontrado identificador de tipo de disco desconocido "{0}" + + + Cuarto bloque de entrada + + + El conjunto de funcionalidades de control de caída libre están soportados + + + El conjunto de funcionalidades de control de caída libre están soportados y activados + + + La sensibilidad de caída libre está establecida en {0} + + + Página de Control de Verificación de Fujitsu: + + + El juego requiere el controlador analógico horizontal. + + + El juego requiere el gatillo L analógico. + + + El juego requiere el gatillo R analógico. + + + El juego requiere el controlador analógico vertical. + + + El juego requiere los botones A + B + Start y el D-Pad. + + + El juego requiere el botón C. + + + El juego requiere el botón D. + + + El juego requiere el controlador analógico horizontal extendido. + + + El juego requiere el controlador analógico vertical extendido. + + + El juego requiere los botones de dirección extendidos + + + El juego requiere el botón X. + + + El juego requiere el botón Y. + + + El juego requiere el botón Z. + + + El juego soporta el controlador analógico. + + + El juego soporta el controlador analógico de giro. + + + El juego soporta la pistola. + + + El juego soporta el JoyPad. + + + El juego soporta el teclado. + + + El juego soporta la pistola de luz. + + + El juego soporta el JoyPad de la Master System. + + + El juego soporta la tarjeta de memoria. + + + El juego soporta el micrófono. + + + El juego soporta el ratón. + + + El juego soporta el multitap. + + + El juego soporta otra expansión. + + + El juego soporta el controlador de paleta. + + + El juego soporta la interfaz de impresora. + + + El juego soporta el paquete Puru Puru. + + + El juego soporta la interfaz serie (RS-232C). + + + El juego soporta la interfaz de tableta. + + + El juego soporta la caja VGA. + + + El juego soporta el trackball. + + + El juego soporta la máscara de periféricos desconocida {0:X2} + + + El juego soporta el periférico desconocido {0}. + + + El juego soporta la región desconocida {0}. + + + El juego usa Windows CE. + + + Disco de propósito general para uso en unidades de propósito general + + + Las Anotaciones de Propósito General están soportadas + + + Las Anotaciones de Propósito General están soportadas y activadas + + + No generar sense en excepciones informativas + + + Generar atención de unidad en excepciones informativas + + + Geometría: + + + un óptico de sobreescritura directa + + + ECMA-100 y ANSI X3.137: Cartucho de Disco Flexible de 90 mm usando grabación MFM a 7859 tfprad en ambas caras; 5,3 pistas por mm + + + ECMA-54: Cartucho de Disco Flexible de 200 mm usando grabación de frecuencia dual a 13262 tfprad en una cara + + + ECMA-59 y ANSI X3.121-1984: Cartucho de Disco Flexible de 200 mm usando grabación de frecuencia dual a 13262 tfprad en ambas caras + + + ECMA-66: Cartucho de disco flexible de 130 mm usando grabación de frecuencia dual a 7958 tfprad en una cara + + + ECMA-69: Cartucho de disco flexible de 200 mm usando grabación MFM a 13262 tfprad en ambas caras + + + ECMA-70 y ANSI X3.125-1985: Cartucho de disco flexible de 130 mm usando grabación MFM a 7958 tfprad en ambas caras; 1,9 pistas por mm + + + ECMA-78 y ANSI X3.126-1986: Cartucho de disco flexible de 130 mm usando grabación MFM a 7958 tfprad en ambas caras; 3,8 pistas por mm + + + ECMA-99 y ISO 8630-1985: Cartucho de disco flexible de 130 mm usando grabación MFM a 13262 tfprad en ambas caras; 3,8 pistas por mm + + + un óptico borrable + + + 3,5-pulgadas, 135 ppp, 15916 bits/radián, MFM de doble capa (1,44Mb) + + + un disco Sony Hi-MD + + + un óptico de sólo lectura + + + un óptico combinación de sólo lectura y escritura única + + + 3,5-pulgadas, 135 ppp, 12362 bits/radián, MFM de doble capa (1,25Mb) + + + un óptico de escritura única y lecturas múltiples + + + ANSI X3.73-1980: 200 mm, 6631 tfprad, 1,9 pistas por mm, 1 cara + + + ANSI X3.73-1980: 200 mm, 6631 tfprad, 1,9 pistas por mm, 2 caras + + + ANSI X3.80-1980: 130 mm, 3979 tfprad, 1,9 pistas por mm, 1 cara + + + El objetivo global de anotación está desactivado + + + Obtenidos {0} bytes de separación + + + Dispositivo de artes gráficas pre-prensa (definido en ASC IT8) + + + El grupo {0} ha sido certificado por un usuario + + + El grupo {0} está siendo parcialmente certificado + + + El grupo {0} está siendo formateado + + + El control de funcionalidades de hardware está soportado + + + El control de funcionalidades de hardware está soportado y activado + + + ID del hardware: {0} + + + Cabezas: {0} + + + Cabezas: {0} máx., {1} actualmente + + + Las cabezas aparcan en el cilindro {0} + + + Las cabezas se estabilizan en {0} µs + + + El tiempo de cambio entre cabezas es superior a 15 µs. + + + La cabeza tarda {0} ms en cargarse + + + La cabeza tarda {0} ms en descargarse + + + HI-TC1: Cartucho de cinta magnética de 12,7mm y 24 pistas, 500 bpmm, GCR + + + HI-TC2: Cartucho de cinta magnética de 12,7mm y 24 pistas, 999 bpmm, GCR + + + Dispositivo Hi-MD. + + + Bytes 44 a 45, específicos de Hi-MD + + + Dispositivo de bloques por zonas gestionado por el anfitrión + + + El Área Protegida del Anfitrión está soportada + + + El Área Protegida del Anfitrión está soportada y activada + + + Como deben descargarse las cintas en un ciclo de corriente, incompatibilidad de cinta, descarga de firmware o final de limpieza: + + + Página de modo de recuperación de desastre / emulación de CD de HP: + + + Página de modo de tiempo del dispositivo HP: + + + Página de niveles de revisión ACI de la unidad HP: + + + Página de niveles de revisión del firmware de la unidad HP: + + + Página de niveles de revisión del hardware de la unidad HP: + + + Página de niveles de revisión del ensamblado del cabezal de la unidad HP: + + + Página de niveles de revisión del mecanismo de la unidad HP: + + + Página de niveles de revisión del PCA de la unidad HP: + + + Página de modo de la sustitución de número de series de HP: + + + Página de modo del reinicio extendido de HP: + + + Información específica del fabricante de HP: + + + Borrador ECMA y ANSI X3B5/87-099: Cartucho de cinta magnética de 12,7mm y 18 pistas, 1944 tfpmm, IFM, GCR (IBM 3480, 3490, 3490E) + + + IBM 3490E + + + IBM 3590 + + + IBM 3590E + + + IBM 3590E extendido + + + IBM 3590 extendido + + + IBM ALDC con búfer de 1024 bytes + + + IBM ALDC con búfer de 2048 bytes + + + IBM ALDC con búfer de 512 bytes + + + Página de modo de la configuración del comportamiento de IBM: + + + Página de niveles de revisión de los componentes de la unidad IBM: + + + Página de números de serie dela unidad IBM: + + + IBM IDRC + + + Página de modo LEOT de IBM: + + + Campo específico OEM de IBM: {0} + + + Página de modo de controles específicos del fabricante de IBM: + + + Página de información específica del fabricante de IBM: + + + El identificador pertenece a la unidad lógica direccionada + + + El identificador pertenece a un dispositivo destino que contiene la unidad lógica direccionada + + + El identificador pertenece al puerto de destino + + + El identificado tiene una asociación desconocida con código {0} + + + IDLE IMMEDIATE con UNLOAD FEATURE está soportado + + + IDLE IMMEDIATE con UNLOAD FEATURE está soportado y activado + + + IEEE 1394 + + + IEEE EUI-64: {0} + + + IEEE EUI-64: {0:X2} + + + Si ACA está establecido, el conjunto de comandos de tareas debería resumir al desestablecerse, si no deberían terminar con un CHECK CONDITION + + + Si está establecido, el destino debería reportar condiciones de excepción de anotación + + + Campo ilegal en el CDB + + + Campo ilegal en los parámetros de datos + + + El Acceso Asimétrico Implícito a la Unidad Lógica está activado + + + Respuesta de identificación incompleta + + + Paquete de CD-Text de tipo incorrecto {0}, no se descodificará + + + ECC P incorrecto. + + + ECC Q incorrecto. + + + EDC incorrect. + + + Indicador de longitud incorrecto + + + Contenido del sector incorrecto. + + + Relleno de ceros incorrecto. + + + Potencia Indicativa de Escritura Objetivo: 0x{0:X2} + + + Las excepciones informativas están desactivadas + + + Las excepciones informativas están activadas + + + El reporte de las excepciones informativas no debería afectar el rendimiento de la unidad + + + Las condiciones de excepción informativa se reportarán un máximo de {0} veces + + + La prioridad inicial es {0} + + + Dirección inicial del programa: 0x{0:X8} + + + Punto de entrada inicial del programa: 0x{0:X8} + + + Tamaño de carga inicial del programa: {0} bytes + + + RAM de trabajo inicial del programa: {0} bytes + + + La separación interior tiene {0} bytes + + + El descriptor de INQUIRY contiene: {0} + + + El descriptor de INQUIRY contiene los datos binarios (hexadecimal): {0} + + + El descriptor de INQUIRY contiene el tipo desconocido de datos {1} (hexadecimal): {0} + + + El descriptor de INQUIRY de tipo {2} contiene el tipo desconocido de datos {1} (hexadecimal): {0} + + + El cartucho insertado es LTO + + + Internet SCSI + + + La separación entre bloques es {0} veces el tamaño definido por el dispositivo + + + La separación entre bloques es suficientemente larga para soportar la actualización in-situ + + + La separación entre bloques tiene un valor desconocido {0} + + + Modo 3 inválido + + + Campo de propósito inválido con valor {0} + + + tamaño inválido + + + Valor inválido en el bit {0} del campo {1} del CDB + + + Valor inválido en el campo {0} del CDB + + + La entrega de datos por orden está soportada + + + La entrega de datos por orden está soportada y activada + + + IORDY está soportado + + + IORDY está soportado y puede ser desactivado + + + Tamaño ISA0: {0} + + + Tamaño ISA1: {0} + + + ISO/IEC 10090: Disco óptico de 86 mm de lectura/escritura y una cara con 12500 pistas + + + ISO/IEC 13614: Disco óptico de 300 mm y doble caras + + + NTSC (Japonés) + + + kilobytes + + + El multiplicador máximo de la unidad larga es {0}. + + + El tamaño de la unidad larga es {0} MiB + + + El último bloque lógico direccionable es {0} + + + Número de unidad de la última dirección de la zona de datos de esta capa: {0} + + + Número de la última sesión completa: {0} + + + Los últimos datos leídos estaban comprimidos con + + + Los últimos datos leídos estaban descomprimidos + + + El último error de seguridad extendida fue {0} + + + La última dirección posible para el Lead-Out es {0} (como LBA) o {1:X2}:{2:X2}:{3:X2} + + + La última sesión está completa + + + La última sesión está dañada + + + La última sesión está vacía + + + La última sesión está incompleta + + + La dirección del Lead-In de la última sesión es {0} (como LBA) o {1:X2}:{2:X2}:{3:X2} + + + La última pista en la última sesión es la pista {0} + + + Número de la última pista: {0} ( + + + Número de la última pista en la última sesión completa: {0} + + + LSN 0 del último área de datos de usuario: 0x{0:X8} + + + Último PSN de datos de usuari para el disco: {0} + + + Número de la última pista de video: {0} + + + Dirección del último bloque ECC escribible: 0x{0:X6} + + + El último comando WRITE MULTIPLE programó {0} sectores correctamente + + + Las capas están en el camino de pista opuesto + + + Las capas están en el camino de pista paralelo + + + La capa {0} es de tipo Blu-ray + + + La capa {0} es de tipo CD + + + La capa {0} es de tipo DVD + + + La capa {0} es de tipo HD DVD + + + La capa {0} es de tipo desconocido 0x{1:X4} + + + La capa 0 termina en el PSN {0:X}h + + + El extent de LBA {0} comienza en el LBA {1} y dura {2} sectores + + + El Lead-In está pre-grabado + + + El Lead-Out es de tipo audio + + + El Lead-Out es de tipo datos + + + El Lead-Out está pre-grabado + + + Posición de comienzo del Lead-Out: {0:D2}:{1:D2}:{2:D2} + + + Posición de comienzo del Lead-Out: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Valor antiguo: 0x{0:X2} + + + La interfaz de la librería emite un bit de parada por byte + + + La interfaz de la librería emite dos bits de parada por byte + + + La interfaz de la libreria operará a 115200 baudios en el siguiente reinicio + + + La interfaz de la libreria operará a 19200 baudios en el siguiente reinicio + + + La interfaz de la libreria operará a 38400 baudios en el siguiente reinicio + + + La interfaz de la libreria operará a 57600 baudios en el siguiente reinicio + + + La interfaz de la libreria operará a 9600 baudios en el siguiente reinicio + + + La librería está presente + + + La hora de la librería es {0} + + + Bloque vínculo + + + La ETIQUETA DE APLICACIÓN DEL BLOQUE LÓGICO no debe ser modificada + + + El reporte de errores de provisionado de bloques lógicos está activado + + + Tamaño del sector lógico: {0} bytes + + + El sector lógico comienza en la posición {0} del sector físico + + + Identificador del grupo de unidad lógica: {0} + + + La unidad lógica soporta protección de bloques lógicos + + + La unidad lógica soporta los tipos de protección 1, 2 y 3 + + + La unidad lógica soporta los tipos de protección 1 y 2 + + + La unidad lógica soporta los tipos de protección 1 y 3 + + + La unidad lógica soporta los tipos de protección 2 y 3 + + + La unidad lógica soporta el tipo de protección 1 + + + La unidad lógica soporta el tipo de protección 2 + + + La unidad lógica soporta el tipo de protección 3 + + + La unidad lógica soporta un tipo de protección desconocido definido por el código {0} + + + La configuración del alineamiento físico largo es {0} + + + La lectura adelantada está soportada + + + La lectura adelantada está soportada y activada + + + El LSN 0 está en el PSN {0:X}h + + + LTO Ultrium-2 en modo de emulación de CD + + + LTO Ultrium-3 en modo de emulación de CD + + + LTO Ultrium-4 en modo de emulación de CD + + + LTO Ultrium-5 en modo de emulación de CD + + + LTO en modo de emulación de CD-ROM + + + LTO Ultrium-2 o T9840 + + + LTO Ultrium-3 o T9940 + + + LTO Ultrium-4 o T9840D + + + LTO Ultrium o Super AIT-1 + + + Insertado cartucho LTO Ultrium 1 Tipo A + + + Insertado cartucho LTO Ultrium 1 Tipo B + + + Insertado cartucho LTO Ultrium 1 Tipo C + + + Insertado cartucho LTO Ultrium 1 Tipo D + + + Insertado cartucho LTO Ultrium 2 + + + Insertado cartucho de limpieza LTO Ultrium + + + La LUN debe desactivar la condición de atención de unidad reportada en el mismo nexo + + + La LUN no debe desactivar la condición de atención de unidad reportada en el mismo nexo + + + La LUN no debe desactivar la condición de atención de unidad reportada en el mismo nexo y debe establecer una condición de atención de unidad para el iniciador + + + Mammoth-2 + + + Fabricante: {0} + + + Tupa de Identificación del Fabricante PCMCIA: + + + ID del fabricante: {0} + + + Número de serie de fabricación: {0} + + + Código de revisión de la contraseña maestra: {0} + + + Tipo de material: 0x{0:X2} + + + Máximo {0} entradas de información de mezcla de extents + + + Revisión ATA soportada máxima: + + + El tamaño de datos de sense máximo sería de {0} bytes + + + Comienzo máximo del Lead-Out más externo del área grabable del disco: {0:D2}:{1:D2}:{2:D2} + + + Comienzo máximo del Lead-Out más externo del área grabable del disco: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + El tiempo de espera máximo para cambiar el comando cuando se establece un valor en el campo de códigos del modo de operación es {0:D2}ms + + + El tiempo de espera máximo para cambiar el comando cuando se establece un valor en el campo de códigos del modo de operación es {0:D2}s + + + El tiempo de espera máximo para cambiar el comando cuando se establece un valor en el campo de códigos del modo de operación es {0:D2}µs + + + La ID máxima de contexto es {0}. + + + MBit/s + + + MD5 del identificador de la unidad lógica: {0} + + + MD5 del identificador de la unidad lógica: {0:X2} + + + El atributo del medio es {0} + + + El formateo del medio en segundo plano ha terminado + + + El set de comandos de tarjetas de memoria está soportado + + + El set de comandos de tarjetas de memoria está soportado y activado + + + El medio ha sido extraído, o insertado en, el cartucho + + + El medio tiene el bit de salida marcado, no debería + + + El medio tiene el bit de protección contra escritura marcado, no debería + + + ID del medio: + + + El medio está siendo formateado actualmente en segundo plano + + + El medio está insertado en un cartucho + + + El medio no está en un cartucho + + + El medio está protegido contra escritura + + + Versión del firmware del cargador de medios: {0} + + + Versión del hardware del cargador de medios: {0} + + + El cargador de medios está presente + + + Versión de la mecánica del cargador de medios: {0} + + + El número de serie del medio está soportado + + + El número de serie del medio está soportado y es válido + + + La superficie del medio activa la protección contra escritura + + + El medio estaba siendo formateado en segundo plano pero ha sido parado y está incompleto + + + Compact Disc Digital Audio de 120 mm + + + Compact Disc Digital Audio de 80mm + + + CD-R de 120 mm con sólo datos + + + CD-R de 120 mm + + + CD-R de 80 mm + + + CD-RW de 120 mm con sólo datos + + + CD-RW de 80 mm con sólo datos + + + CD-RW de 120 mm con sólo audio + + + CD-RW de 80 mm con sólo audio + + + CD-RW de 120 mm con datos y audio + + + CD-RW de 80 mm con datos y audio + + + CD-R de 80 mm con sólo datos + + + CD-R de 120 mm con sólo audio + + + CD-R de 80 mm con sólo audio + + + CD-R de 120 mm con datos y audio + + + Disco HD de 120 mm + + + Disco HD de 80mm + + + Disco híbrido (Photo CD) de 120 mm + + + Disco CD-R híbrido (Photo CD) de 120 mm + + + Disco CD-RW híbrido (Photo CD) de 120 mm + + + Disco CD-RW híbrido (Photo CD) de 80 mm + + + Disco CD-R híbrido (Photo CD) cd 80 mm + + + Disco Compacto de 120 mm con datos y audio + + + Disco Compacto de 80 mm con datos y audio + + + CD-R de tamaño desconocido + + + CD-RW de tamaño desconocido + + + Disco HD de tamaño desconocido + + + CompactTape I, Exatape 28m, CompactTape II, VXA-2 o VXA-3 + + + DAT-72 + + + DC-2900SL + + + DC-9200 o DDS-4 + + + Cartucho de limpieza DDS + + + DLTtape S4 + + + Exatape 106m, DLTtape IV o Travan 5 + + + Exatape 160m XL o Super DLTtape I + + + Exatape 112m + + + Exatape 125m + + + Exatape 150m + + + Exatape 15m, IBM MagStar o VXA + + + Exatape 170m + + + Exatape 225m + + + Exatape 22m + + + Exatape 22m AME + + + Exatape 40m + + + Exatape 45m + + + Exatape 54m o DLTtape III + + + Exatape 75m + + + Exatape 76m + + + Exatape 80m o DLTtape IIIxt + + + LTO Ultrium + + + LTO Ultrium-2 + + + LTO Ultrium-3 + + + LTO Ultrium-3 WORM + + + LTO Ultrium-4 + + + LTO Ultrium-4 WORM + + + LTO Ultrium-5 + + + LTO Ultrium-5 WORM + + + LTO Ultrium-6 + + + LTO Ultrium-6 WORM + + + LTO Ultrium-7 + + + LTO Ultrium-7 WORM + + + LTO Ultrium WORM o cartucho de limpieza + + + MLR1-26GB o DDS-3 + + + Super DLTtape II + + + SLR-32 + + + SLR-32SL + + + SLR-40, SLR-60 o SLR-100 + + + SLR-5 + + + SLR-5SL + + + SLRtape-100 + + + SLRtape-140 + + + SLRtape-24 + + + SLRtape-24 SL + + + SLRtape-40 + + + SLRtape-50 + + + SLRtape-50 SL + + + SLRtape-60 o SLRtape-75 + + + SLRtape-7 + + + SLRtape-7 SL + + + Cinta de 6,3mm con 12 pistas a 394 tfpmm o DC-9250 + + + Cinta de 6,3mm con 24 pistas a 394 tfpmm o MLR1-26GBSL + + + Travan 7 + + + sin definir + + + VStape I + + + Dispositivo de intercambio de medios + + + Descripción del medio: {0} + + + El medio tiene una longitud nominal de {0} m en una cinta de {1} mm de ancho + + + El medio ha definido {0} particiones + + + El medio es + + + El medio es {0} + + + El medio está protegido contra escritura + + + El medio rota a {0} rpm + + + El medio soporta IDs de bloques + + + El medio soporta los siguientes códigos de densidad: + + + Tipo de medio "{0}" definido por "{1}". + + + Código de tipo de medio: {0:X2}h + + + megabytes + + + El tamaño mínimo de solicitud es {0} + + + Versión menor de ATA no especificada + + + MLR1-26GB + + + MLR1-26GBSL + + + MMC Lectura de Blu-ray + + + MMC Escritura de Blu-ray + + + MMC Lectura de CD + + + MMC Funcionalidad base: + + + MMC Lectura de DVD + + + MMC Intercambiador integrado: + + + MMC Función de reporte mejorado de defectos: + + + MMC Formateable: + + + MMC Gestión de defectos por hardware: + + + MMC Escribible por transmisión incremental: + + + MMC Grabación de salto de capa: + + + MMC Morfismo: + + + MMC Lectura aleatoria + + + MMC Escritura aleatoria: + + + MMC Transmisión en tiempo real: + + + MMC Sobreescritura rígidamente restringida + + + MMC perfiles soportados: + + + MMC Escritura única + + + MMC Protección contra escritura: + + + Modo 0. + + + Modo 1. + + + Modo 2. + + + Revisión del módulo: {0} + + + Momento de inercia: 0x{0:X2} + + + El MRW está corrupto + + + Registro de Identificación del Dispositivo MultiMediaCard: + + + Registro de Datos Específicos del Dispositivo MultiMediaCard: + + + Registro de Datos Específicos Extendidos del Dispositivo MultiMediaCard: + + + Registro de Condiciones de Operación MultiMediaCard: + + + Dispositivo multi-puerto + + + DMA multi-palabra: + + + silenciado + + + NAA: {0} + + + NAA: {0:X2} + + + El auto-sense de NCQ está soportado + + + NCQ está soportado + + + La prioridad NCQ está soportada + + + La gestión de cola NCQ está soportada + + + La transmisión NCQ está soportada + + + Nunca aplicar la operación de verificación + + + El primer sector del siguiente Border-In es el PSN {0:X}h + + + Caché no volátil: + + + La caché no volátil es de {0} bytes + + + La caché no volátil está desactivada + + + La compensación no-cero del búfer está soportada + + + La compensación no-cero del búfer está soportada y activada + + + NOP está soportado + + + NOP está soportado y activado + + + Comportamiento de reinicio normal + + + NTSC (Norteamérica). + + + No todos los comandos de 28-bits están soportados. + + + Sin información adicional. + + + No se reportará un error retrasado a un comando de rebobinado + + + No hay disco insertado, bandeja cerrada o carrito insertado + + + No hay configuración de región de la unidad. + + + No hay texto de información del fabricante. + + + No se realizará una pre-lectura. + + + No hay texto de nombre del producto. + + + No se reportará la condición de excepción informativa + + + no específico + + + No habrá atención de unidad en la liberación + + + El número y tamaño de las particiones se pueden definir manualmente + + + El número de las particiones puede ser definido pero su tamaño lo definirá el dispositivo + + + Número de punteros de intervalos de salto: {0} + + + Número de punteros de saltos de pista: {0} + + + Dispositivo de almacenamiento basado en objetos + + + Sólo se está formateando un grupo + + + Sólo se reportará la condición de excepción informativa bajo demanda + + + Sólo se usarán el CIRC y los reintentos. + + + Sólo se usarán los reintentos. + + + En el bloque lógico {0} + + + Al insertar un medio, se cargará sólo para acceso a la memoria auxiliar + + + Al insertar un medio, se cargará para acceso completo + + + Al insertar un medio, no se cargará + + + Al leer un bloque actualizado la unidad devolverá RECOVERED ERROR + + + En el segmento {0} + + + Valores de OPC para {0}Kbit/seg.: {1}, {2}, {3}, {4}, {5}, {6} + + + El soporte de sistemas operativos es el estándar LTO + + + El soporte de sistemas operativos es el código desconocido {0} + + + Dispositivo de tarjeta óptica de lectura/escritura + + + Dispositivo de memoria óptica + + + El tamaño óptimo de lectura es de {0} KiB + + + El tamaño óptimo de recorte es de {0} KiB + + + El tamaño óptimo de escritura es de {0} KiB + + + Potencia óptica de grabado: 0x{0:X2} + + + Tamaño OSA: {0} + + + El puerto de salida 0 tiene canales + + + El puerto de salida 1 tiene canales + + + El puerto de salida 2 tiene canales + + + El puerto de salida 3 tiene canales + + + Título extranjero: {0} + + + OVERWRITE EXT está soportado + + + PACKET está soportado + + + PACKET está soportado y activado + + + El comportamiento de reja de pánico está activado + + + Dispositivo ATA paralelo: + + + SCSI paralelo + + + Los parámetros se puede guardar + + + Las particiones se definen en bytes + + + Las particiones se definen en kilobytes + + + Las particiones se definen en megabytes + + + Las particiones se definen en unidades de {0} bytes + + + Las particiones están fijadas en las definiciones del dispositivo + + + La partición {0} mide {1} {2} + + + La partición {0} mide {1} unidades + + + La partición {0} continúa el resto del medio + + + Alineación de partición: {0} bytes + + + Los parámetros de partición no se aplicarán hasta que se reciba un comando FORMAT MEDIUM + + + Parte versión {0} + + + PCI Express + + + Tuplas de Geometría del Dispositivo PCMCIA: + + + Tupla de Información del Producto / Versión Nivel 1 PCMCIA: + + + El rendimiento está limitado usando el factor {0} + + + El rendimiento no está limitado + + + Periféricos: + + + La protección contra escritura permanente está desactivada. + + + La protección contra escritura permanente de las áreas de arranque está desactivada. + + + La protección contra escritura permanente se aplicará al grupo seleccionado. + + + La protección contra escritura permanente está activada. + + + La protección contra escritura persistente está activada. + + + El PFI de la zona borde extra comienza en el PSN {0:X}h + + + Tamaño del sector físico: {0} bytes + + + Los contadores de eventos PHY están soportados + + + El pin 1 indica reinicio de cambio de disco cuando está activo alto + + + El pin 1 indica reinicio de cambio de disco cuando está activo bajo + + + El pin 1 indica función desconocida {0} cuando está activo alto + + + El pin 1 indica función desconocida {0} cuando está activo bajo + + + El pin 1 está desconectado + + + El pin 2 indica función desconocida {0} cuando está activo alto + + + El pin 2 indica función desconocida {0} cuando está activo bajo + + + El pin 34 indica función desconocida {0} cuando está activo alto + + + El pin 1 indica función desconocida {0} cuando está activo alto + + + El pin 34 indica función desconocida {0} cuando está activo bajo + + + El pin 1 indica función desconocida {0} cuando está activo bajo + + + El pin 2 está desconectado + + + El pin 34 indica que el disco ha cambiado cuando está activo alto + + + El pin 34 indica que el disco ha cambiado cuando está activo bajo + + + El pin 34 indica que la unidad está lista cuando está activo alto + + + El pin 34 indica que la unidad está lista cuando está activo bajo + + + El pin 34 está desconectado + + + El pin 4 indica que la unidad está en uso cuando está activo alto + + + El pin 4 indica que la unidad está en uso cuando está activo bajo + + + El pin 4 indica expulsión cuando está activo alto + + + El pin 4 indica expulsión cuando está activo bajo + + + El pin 4 indica carga de la cabeza cuando está activo alto + + + El pin 4 indica carga de la cabeza cuando está activo bajo + + + El pin 4 está desconectado + + + Modo de reloj PIO: {0} + + + La pendiente de pista es 0,147 µm/bit + + + La pendiente de pista es 0,153 µm/bit + + + La pendiente de pista es 0,267 µm/bit + + + La pendiente de pista es 0,353 µm/bit + + + La pendiente de pista está entre 0,130 µm/bit y 0.140 µm/bit + + + La pendiente de pista está entre 0,140 µm/bit y 0.148 µm/bit + + + La pendiente de pista está entre 0,409 µm/bit y 0.435 µm/bit + + + Dispositivo POP + + + El enlace del puerto A está caído + + + El puerto A usa una interfaz SCSI paralela Ultra-160 + + + Posición {0:X2}:{1:X2}:{2:X2} (LBA {3}) + + + La protección contra escritura en el ciclo de energía está desactivada. + + + La protección contra escritura de las áreas de arranque en el ciclo de energía está desactivada. + + + La protección contra escritura se aplicará al grupo seleccionado en el ciclo de energía. + + + La gestión de energía está soportada + + + La gestión de energía está soportada y activada + + + El conjunto de funcionalidades del modo de energía está soportado + + + El conjunto de funcionalidades del modo de energía está soportado y activado + + + El auto-test en el encendido está desactivado + + + El auto-test en el encendido está activado + + + El encendido en esperá está soportado + + + El encendido en esperá está soportado y activado + + + La pre-lectura puede seguir a través de descontinuidades (como cilindros o pistas) + + + La pre-lectura deberá abortarse al recibir un nuevo comando + + + Los valores de pre-lectura indican un multiplicador de bloque + + + La pre-lectura se hará para los comandos READ de {0} bloques o menos + + + Código primaro: {0:X2}h + + + El área de reemplazo primaria comienza en el PSN {0:X}h y termina en el PSN {1:X}h, inclusivos + + + Dispositivo de impresión + + + Dispositivo procesador + + + Productor: {0} + + + Código de producto: {0} + + + CRC de producto: 0x{0:X8} + + + Familia de producto: {0} + + + La familia del producto es 10,0/20,0 GB + + + La familia del producto es 15,0/30,0 GB + + + La familia del producto es 20,0/40,0 GB + + + La familia del producto es 2,6 GB + + + La familia del producto es 6,0 GB + + + La familia del producto no está especificada + + + Nombre del producto: {0} + + + Revisión del producto: {0:X2}.{1:X2} + + + Número de serie del producto: {0} + + + Versión del producto: {0} + + + Perfil {0}: {1} + + + Prólogo encontrado en {0} + + + La comprobación de información del protector está desactivada + + + Descriptor específico del protocolo (ATA/ATAPI) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (Interfaz de Transporte de Automatización/Unidad) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (Fibre Channel) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (IEEE 1394) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (Internet SCSI) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (SCSI paralelo) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (PCI Express) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (SCSIe) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (Acceso Directo a Memoria Remota SCSI) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (SCSI de conexión en serie) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (SSA) con formato desconocido (hexadecimal): {0} + + + Descriptor específico del protocolo (UAS): Dirección USB {0} interfaz {1} + + + Descriptor específico del protocolo (código desconocido {0}) con formato desconocido (hexadecimal): {1} + + + Descriptor específico del protocolo (desconocido) con formato desconocido (hexadecimal): {0} + + + PSN del LSN 0 del área de datos de usuario: 0x{0:X8} + + + QIC-11 + + + QIC-120: Cartucho de cinta magnética de 6,3 mm y 15 pistas, 394 bpmm, GCR + + + QIC-1350: Cartucho de cinta magnética de 6,3 mm y 30 pistas, 2034 bmpp, RLL + + + QIC-150: Cartucho de cinta magnética de 6,3 mm y 18 pistas, 394 bpmm, GCR + + + QIC-320: Cartucho de cinta magnética de 6,3mm y 26 pistas, 630 bpmm, GCR + + + Pista de audio cuadrafónico con pre-énfasis de 50/15 µs + + + Pista de audio cuadrafónico sin pre-énfasis + + + Checksum de la EEPROM del firmware: 0x{0:X4} + + + Página de información de versión del firmware de Quantum: + + + Fecha de versión del firmware de lectura/escritura: {0} + + + Checksum del firmware de lectura/escritura: 0x{0:X8} + + + Checksum del firmware del servo: 0x{0:X4} + + + Información específica del fabricante de Quantum: + + + Subcanal Q modo {0} + + + Subcanal Q sin modo + + + El subcanal Q contiene la posición actual + + + El subcanal Q contiene el ISRC + + + El subcanal Q contiene el número de catálogo del medio + + + El subcanal Q contiene el puntero a pista + + + El subcanal Q contiene el puntero a pista de video + + + La lectura después de TRIM es determinista + + + La lectura después de TRIM devuelve datos vacíos + + + La lectura adelantada está desactivada + + + Bloque de lectura: {0} bytes + + + La logitud del bloque de lectura es {0} bytes + + + El tamaño del bloque de lectura está definido en el CSD extendido + + + READ BUFFER DMA está soportado + + + READ BUFFER está soportado + + + READ BUFFER está soportado y activado + + + El búfer de lectura debe tener un ratio de vacío de {0} antes de leer más datos del medio + + + La caché de lectura está activada + + + Los comandos de lectura puede cruzar los límites de los bloques físicos + + + READ DMA QUEUED y WRITE DMA QUEUED están soportados + + + READ DMA QUEUED y WRITE DMA QUEUED están soportados y activados + + + READ LOG DMA EXT está soportado + + + Dispositivo de bloques de sólo lectura + + + Dispositivo de bloques de lectura/escritura + + + READ/WRITE DMA EXT GPL está soportado + + + READ/WRITE DMA EXT GPL está soportado y activado + + + READ/WRITE LONG tiene {0} bytes extra + + + Bloque en tiempo real. + + + La recepción de solicitudes de gestión de energía iniciadas por el anfritrión están soportadas + + + RECEIVE FPDMA QUEUED y SEND FPDMA QUEUED están soportados + + + El ratio recomendado de energía de borrado es {0} ε + + + La energía de grabación recomendada es de {0} mW + + + Las marcas grabadas tienen una reflectividad superior que las no grabadas (disco LTH). + + + Las marcas grabadas tienen una reflectividad inferior que las no grabadas (disco HTL). + + + La potencia de grabación no está especificada + + + Los datos recuperados del búfer llegan en orden FIFO + + + Los datos recuperados del búfer llegan en orden LIFO + + + Se reportarán los errores corregidos. + + + Se reportarán los errores corregidos y se abortará con CHECK CONDITION. + + + No se reportarán los errores corregidos. + + + La velocidad de referencia es 2x + + + La velocidad de referencia es 4x + + + La velocidad de referencia es 8x + + + La velocidad de referencia establecida es desconocida: {0} + + + La velocidad de referencia es 3,49 m/s + + + Regiones soportadas: + + + Registro versión 1.0 + + + Registro versión 1.1 + + + Registro versión 1.2 + + + Registro versión 2.0 + + + La versión del registró está especificada en el Registro de Datos Extendidos Específicos del Dispositivo + + + Identificador relativo de puerto objetivo: {0} + + + Fecha de salida: {0} + + + Versión del firmware: {0} + + + La liberación está soportada + + + La liberación está soportada y activada + + + Dispositivo extraíble + + + El conjunto de funcionalidades de medios extraíbles está soportado + + + El conjunto de funcionalidades de medios extraíbles está soportado y activado + + + El conjunto de funcionalidades de notificación del estado del medio extraíble está soportado + + + La notificación del estado del medio extraíble está soportada + + + La notificación del estado del medio extraíble está soportada y activada + + + Número de serie reportado: {0} + + + La excepción reportada en la compresión es {0} + + + Reservado1 = 0x{0:X2} + + + Reservado2 = 0x{0:X2} + + + Reservado3 = 0x{0:X8} + + + Reservado4 = 0x{0:X8} + + + Reservado5 = 0x{0:X8} + + + Reservado6 = 0x{0:X8} + + + Reservado7 = 0x{0:X8} + + + Reservado4 = 0x{0:X16} + + + Reservado7 = 0x{0:X2} + + + Reservado8 = 0x{0:X2} + + + Reservado9 = 0x{0:X8} + + + Reservado3 = 0x{0:X2} + + + Reservado4 = 0x{0:X2} + + + Reservado5 = 0x{0:X2} + + + Reservado6 = 0x{0:X2} + + + El modo {0} reservado de auto-carga está establecido + + + Bytes reservados 74 a 95 + + + Byte reservado 56, bits 7 a 4 = 0x{0:X2} + + + Byte reservado 57 = 0x{0:X2} + + + Byte reservado 5, bits 2 a 1 = 0x{0:X2} + + + Valor reservado {0} de control de desconexión de la transferencia de datos + + + Reservado = 0x{0:X2} + + + Valores reservados 0x{0:X2} establecidos + + + El valor reservado 2 para QErr está establecido + + + El valor reservado 1 para UA_INTLCK_CTRL está establecido + + + El valor reservado 0x02 se ha encontrado en el campo de reloj de SPI + + + Valor reservado establecido en el calificador de periférico + + + Modificador de respuesta: {0} + + + Valor de respuesta: 0x{0:X8} + + + La tolerancia a la velocidad de rotación es superior al 0,5% + + + El fechado puede inicializerse por métodos externos a los estándares SCSI, pero SET TIMESTAMP deberá tener preferencia sobre ellos + + + Valor S4: 0x{0:X6} + + + SANITIZE ANTIFREEZE LOCK EXT está soportado + + + Los comandos de sanitización están especificados por ACS-2 + + + Los comandos de sanitización están especificados por ACS-3 o superior + + + El conjunto de funciones de sanitización están soportados + + + SATA 1,5Gb/s está soportado + + + SATA 3,0Gb/s está soportado + + + SATA 6,0Gb/s está soportado + + + Dispositivo SATA Express + + + Dispositivo escáner + + + Página SCSI de control en segundo plano: + + + Página SCSI de modo de caché: + + + Página SCSI de parámetros de control de audio del CD-ROM: + + + Página SCSI de capacidades de CD-ROM: + + + Página SCSI de parámetros de CD-ROM: + + + Página SCSI de extensión de control: + + + Página SCSI de modo de control: + + + Página SCSI de compresión de datos: + + + Página SCSI de configuración del dispositivo: + + + Página SCSI de identificación del dispositivo + + + Página SCSI del modo de Desconexión-Reconexión: + + + Pagína SCSI del modo de operación de la unidad: + + + Página SCSI de datos extendidos de INQUIRY: + + + Página SCSI de disco flexible: + + + Página SCSI de formato del dispositivo: + + + Pagína SCSI de definiciones de operación implementadas: + + + Página SCSI de control de excepciones informativas: + + + Página SCSI de direcciones de red de gestión: + + + Página SCSI del modo de configuración del medio: + + + Página SCSI de partición del medio: + + + Página SCSI de partición del medio (extra): + + + Página SCSI de tipos de medio soportados: + + + Cabecera del MODE SENSE SCSI: + + + Identificador de nombre SCSI: {0} + + + Identificador de nombre SCSI (hexadecimal): {0} + + + Memoria óptica SCSI: + + + SCSI sobre PCI Express + + + El puerto SCSI está desactivado + + + El puerto SCSI está activado + + + El puerto SCSI se desactivará en el siguiente encendido + + + El puerto SCSI se activará en el siguiente encendido + + + Página SCSI de consumo energético: + + + Página SCSI de recuperación de errores de lectura para dispositivos MultiMedia: + + + Página SCSI de recuperación de errores de lectura/escritura: + + + Acces Directo a Memoria Remota SCSI + + + Página SCSI de capacidades de acceso a bloques extraíbles + + + Página SCSI de geometría del disco rígido: + + + SCSI SENSE: {0} + + + Capacidades del dispositivo SCSI de acceso secuencial: + + + Identificadores de la interfaz software SCSI: + + + Página SCSI de temporizador y protección: + + + Datos de la capa de traducción SCSI a ATA: + + + El comando UNLOAD no expulsará el cartucho + + + Página SCSI de verificación de recuperación de errores: + + + Página SCSI de verificación de recuperación de errores para dispositivos MultiMedia: + + + Página SCSI del modo de control XOR: + + + Las tablas de datos SCT están soportadas + + + El control de recuperación de errores SCT está soportado + + + Las funciones de control SCT están soportadas + + + Las direcciones largas de sector SCT están soportadas + + + La misma escritura SCT está soportada + + + Super DLTtape I + + + Super DLTtape I comprimida + + + Super DLTtape 1 a 133000 bpp + + + Página de números del firmware de Seagate: + + + Página de información específica del fabricante de Seagate: + + + Código secundario: {0:X2}h + + + Segundo bloque de entrada + + + Segundo bloque de salida + + + Sectores direccionables en modo CHS: {0} + + + Sectores direccionables en modo CHS: {0} máx, {1} actualmente + + + Sectores por pista: {0} + + + Sectores por pista: {0} máx., {1} actualmente + + + Los sectores empiezan por 1 + + + Sector {0} + + + Las direcciones de sectores incrementan progresivamente en un cilindro antes de pasar al siguiente + + + Las direcciones de sectores incrementan progresivamente en una superficia antes de pasar a la siguiente + + + Registro de Configuración del Dispositivo SecureDigital: + + + Registro de Identificación del Dispositivo SecureDigital: + + + Registro de Datos Específicos del Dispositivo SecureDigital: + + + Registro de Condiciones de Operación de SecureDigital: + + + Seguridad: + + + El contador de seguridad ha expirado + + + El contador de seguridad no ha expirado + + + La seguridad está activada + + + La seguridad está congelada + + + La seguridad está bloqueada + + + La seguridad no está activada + + + La seguridad no está congelada + + + La seguridad no está bloqueada + + + El nivel de seguridad es alto + + + El nivel de seguridad es máximo + + + Dispositivo Gestor de Segurdad + + + El modo de seguridad está soportado + + + El modo de seguridad está soportado y activado + + + INFORMACIÓN DEL IP.BIN DE SEGA: + + + La funcionalidad segmentada en DOWNLOAD MICROCODE está soportada + + + La funcionalidad segmentada en DOWNLOAD MICROCODE está soportada y activada + + + La fuerza seleccionada del controlador es de tipo {0}. + + + En el bloque lógico {0} + + + Dispositivo de acceso secuencial + + + Dispositivo ATA en serie: + + + SCSI de Conexión en Serie + + + Número de serie: {0} + + + El número de serie no es el valor por defecto del fabricante + + + El número de serie es el valor por defecto del fabricante + + + La interrupción de SERVICE está soportada + + + La interrupción de SERVICE está soportada y activada + + + Versión del firmware del servo: {0} + + + Sesión {0} + + + SET FEATURES es requerido antes del inicio + + + La extensión de seguridad a SET MAX está soportada + + + La extensión de seguridad a SET MAX está soportada y activada + + + SET PASSWORD DMA y SET UNLOCK DMA están soportados + + + Dispositivo simplificado de acceso directo + + + DMA de palabra única: + + + La asignación {0} del intervalo de tiempo de omisión dice que desde {1:D2}:{2:D2}:{3:D2} hasta {4:D2}:{5:D2}:{6:D2} deben ser omitidos + + + La asignación {0} del intervalo de tiempo de omisión dice que desde {4}:{1:D2}:{2:D2}:{3:D2} hasta {8}:{5:D2}:{6:D2}:{7:D2} deben ser omitidos + + + Omitir pista {0} + + + La asignación de omisión de pista {0} dice que la pista {1} debe omitirse + + + SLR-32 SL + + + SLR40, SLR60 o SLR100 + + + SLR-5 SL + + + En transporte de comandos S.M.A.R.T. está soportado + + + Transporte de comandos S.M.A.R.T. (SCT): + + + El registro de errores de S.M.A.R.T. está soportado + + + El registro de errores de S.M.A.R.T. está soportado y activado + + + S.M.A.R.T. está soportado + + + S.M.A.R.T. está soportado y activado + + + La auto-prueba S.M.A.R.T. está soportada + + + La auto-prueba S.M.A.R.T. está soportada y activado + + + La conversación de los ajustes de software está soportada + + + La conversación de los ajustes de software está soportada y activada + + + La protección contra escritura está activada hasta el siguiente apagado + + + La protección contra escritura está activada + + + Valores completos del área de reserva: 0x{0:X2} + + + Encontrado tamaño incorrecto de la información sobre el área de reserva de Blu-ray ({0} bytes) + + + El control del motor giratorio está implementado + + + La sincronización del motor giratorio está desactivada o no está soportada + + + SSA + + + Los valores del tiempo de reposo son estándar + + + Comienzo del posible siguiente programa en el área grabable del disco: {0:D2}:{1:D2}:{2:D2} + + + Comienzo del posible siguiente programa en el área grabable del disco: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Posición de comienzo de la parte exterior del área del Lead-In: {0:D2}:{1:D2}:{2:D2} + + + Posición de comienzo de la parte exterior del área del Lead-In: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Tiempo de comienzo del intervalo que se debe omitir: {0:D2}:{1:D2}:{2:D2} + + + Tiempo de comienzo del primer área de Lead-In del disco: {0:D2}:{1:D2}:{2:D2} + + + Tiempo de comienzo del primer área de Lead-In del disco: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Pista de audio estéreo con un pre-énfasis de 50/15 µs + + + Pista de audio estéreo sin pre-énfasis + + + Posición de parada de la parte interna del área del Lead-Out: {0:D2}:{1:D2}:{2:D2} + + + Posición de parada de la parte interna del área del Lead-Out: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Transmisión: + + + La latencia de acceso en transmisión es de {0} + + + El conjunto de funciones de transmisión están soportados + + + El conjunto de funciones de transmisión están soportados y activados + + + La granularidad del rendimiento de la transmisión es {0} + + + El tiempo de transmisión en DMA es {0} + + + El tiempo de transmisión en PIO es {0} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q: {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} {13:X2} {14:X2} {15:X2} {16:X2} {17:X2} CRC 0x{18:X2}{19:X2} ({20}), R-W {21} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8}, {9} punteros de intervalo de omisión, {10} asignaciones de pistas omitidas, CRC 0x{11:X2}{12:X2} ({13}), R-W {14} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8}, valores de ATIP {9:X2}, {10:X2}, {11:X2}, el primer Lead-In del disco empieza en {12:X2}{13:X2}{14:X2} (LBA {15}), CRC 0x{16:X2}{17:X2} ({18}), R-W {19} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8} ISRC: {9} fotograma {10:X2} CRC 0x{11:X2}{12:X2} ({13}), R-W {14} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8} MCN: {9} fotograma {10:X2} CRC 0x{11:X2}{12:X2} ({13}), R-W {14} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8} el siguiente área de programa puede empezar en {9:X2}:{10:X2}:{11:X2} (LBA {12}), última sesión, {13} punteros de modo 5, CRC 0x{14:X2}{15:X2} ({16}), R-W {17} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8} el siguiente área de programa puede empezar en {9:X2}:{10:X2}:{11:X2} (LBA {12}), Lead-Out máximo en {13:X2}:{14:X2}:{15:X2} (LBA {16}), {17} punteros de modo 5, CRC 0x{18:X2}{19:X2} ({20}), R-W {21} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8} posición: {9:X2}:{10:X2}:{11:X2} (LBA {12}), pista {13:X} es la primera pista del área de programa en formato {14}, Q CRC 0x{15:X2}{16:X2} ({17}), R-W {18} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8} posición: {9:X2}:{10:X2}:{11:X2} (LBA {12}), pista {13:X} es la última pista del área de programa, Q CRC 0x{14:X2}{15:X2} ({16}), R-W {17} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8} posición: {9:X2}:{10:X2}:{11:X2} (LBA {12}), pista {13:X} comienza en {14:X2}:{15:X2}:{16:X2} (LBA {17}), Q CRC 0x{18:X2}{19:X2} ({20}), R-W {21} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8} tiempo de comienzo del intervalo de omisión {9:X2}{10:X2}{11:X2}, tiempo de parada del intervalo de omisión {12:X2}{13:X2}{14:X2}, CRC 0x{15:X2}{16:X2} ({17}), R-W {18} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8}, la pista {9} debe omitirse, CRC 0x{10:X2}{11:X2} ({12}), R-W {13} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: área de {4}, {5}, {6}, {7}, Q modo {8} posición: pista {9:X} índice {10:X} posición relativa {11:X2}:{12:X2}:{13:X2} (LBA {14}), posición absoluta {15:X2}:{16:X2}:{17:X2} (LBA {18}), Q CRC 0x{19:X2}{20:X2} ({21}), R-W {22} + + + INCORRECTO + + + CD-DA / CD-ROM + + + CD-i + + + CD-ROM XA + + + copia permitida + + + copia prohibida + + + pausa corrupta + + + vacío + + + datos incrementales + + + Lead-In + + + Lead-Out + + + no está vacío + + + no está en pausa + + + OK + + + pausa + + + programa + + + audio cuadrafónico sin pre-énfasis + + + audio cuadrafónico con pre-enfasis + + + valor de control {0} reservado + + + audio estéreo sin pre-énfasis + + + audio estéreo con pre-énfasis + + + datos ininterrumpidos + + + desconocido {0:X2} + + + Las copias de las subcabeceras son diferentes. + + + Versiones ATA soportadas: + + + Tipo de medio soportado cuatro: {0} + + + Tipo de medio soportado uno: {0} + + + Tipo de medio soportado tres: {0} + + + Tipo de medio soportado dos: {0} + + + Definiciones de operación soportadas: + + + Soporta información de protección y longitudes de bloques + + + Soporta transiciones automáticas de parcial a reposo por el dispositivo + + + Soporta borrado de seguridad mejorada + + + Soporta transiciones automáticas de parcial a reposo por el anfitrión + + + Nombre del sistema: {0} + + + Dirección del programa de sistema: 0x{0:X8} + + + Dirección de entrada del programa de sistema: 0x{0:X8} + + + Tamaño de carga del programa de sistema: {0} bytes + + + RAM de trabajo del programa de sistema: {0} bytes + + + T10000A + + + T10000B + + + T10000C + + + T10000D + + + T9840C + + + T9940 + + + El etiquedato del encolado está desactivado + + + Las etiquetas deben estar en unidades de {0} sectores. + + + El tamaño de los recursos de etiqueta es {0}. + + + Mammoth + + + Versión del directorio de formato de la cinta: {0} + + + La cinta se desenroscará + + + La cinta se desenroscará y descargará + + + La cinta permanecerá enroscada al comienzo + + + El valor del entrelazado dependiende del objetivo es {0} + + + Identificador del grupo objetivo: {0} + + + El objetivo tiene permitido re-ordenar la transferencia de datos + + + El objetivo puede lanzar una notificación de evento asíncrona en lugar de un error diferido + + + El objetivo puede lanzar una notificación de evento asíncrona en lugar de una condición de atención de unidad + + + El objetivo puede lanzar una notificación de evento asíncrona al completar su inicialización + + + El objetivo opera como un maestro sincronizado con la rotación + + + El objetivo opera como el control maestro sincronizado con la rotación + + + El objetivo opera como el contro esclavo sincronizado con la rotación + + + El objetivo no debe liberar la señal de encendido del motor + + + El objetivo no debe transferir datos para un comando durante la misma interconexión + + + El objetivo debe esperar {0} segundos desde que la unidad está lista antes de abortar intentos de acceso al medio + + + El objetivo debe esperar {0} segundos antes de intentar acceder al medio cuando se active la señal de encendido del motor + + + El objetivo debe esperar {0} segundos antes de librar la señal de encendido del motor después de entrar en reposo + + + Las operaciones abortadas por las acciones de otros iniciadores deben terminar con TASK ABORTES + + + La operación de escritura de prueba está restringida durante las operaciones de lectura o escritura. + + + Campo de texto: "{0}" + + + Hay {0} bloques por cada segundo de audio + + + Hay {0} por bloque + + + Hay comandos pendientes de re-envío + + + No hay direcciones + + + No hay identificadores + + + No hay definiciones soportadas + + + Hay acceso a la partición {0} de propósito general + + + Hay una señal de unidad lista + + + No hay acceso a la partición de arranque + + + No hay ningún cartucho introducido + + + No hay límite al tiempo máximo que se permite permanecer ocupado + + + Hay acceso de lectura/escritura a la partición de arranque 1 + + + Hay acceso de lectura/escritura a la partición de arranque 2 + + + Hay acceso de lectura/escritura al bloque de memoria protegido contra repetición + + + El tipo de dispositivo que se proveería en la respuesta a INQUIRY es {0} + + + La unidad lógica no hace cumplir los Controls de Región de Reproducción (RPC). + + + La unidad lógica mantiene un conjunto de tareas para todos los nexos + + + La unidad lógica mantiene conjuntos de tareas separados para cada nexo + + + La unidad lógica debe adherirse a la especificación y requisitos del acuerdo de licencia de CSS al respecto de RPC. + + + La unidad lógica usa un esquema de cumplimiento de regiones desconocido. + + + La señal del motor activo debe permanecer libre + + + Tercer bloque de entrada + + + Este descriptor está duplicado + + + El disco contiene una capa CD-ROM. + + + El disco contiene una capa CD-RW. + + + El disco contiene una capa CD-R. + + + El disco contiene una capa DVD-ROM. + + + El disco contiene una capa DVD-RW. + + + El disco contiene una capa DVD-R. + + + El disco no contiene una capa CD. + + + El disco no contiene una capa DVD. + + + El disco tiene {0} capas + + + Este DI continúa la unidad anterior + + + Este DI se refiere a la capa {0} + + + Este DI comienza una nueva unidad + + + Esta es la densidad por defecto de la unidad + + + Esta es la capa por defecto. + + + Esta es la capa actualmente en uso. + + + El intervalo del temporizador es de {0} ms. + + + El intervalo del temporizador es específico del fabricante. + + + Fechado: {0} + + + El fechado puede ser inicializado por métodos externos a los estándares SCSI + + + Número total de Media Key Blocks de CPRM disponibles para transferir: {0} + + + Número total de Media Key Blocks disponibles para transferir: {0} + + + pista {0} + + + Pista {0} (Datos, grabada incrementalmente) comienza en {1:D2}:{2:D2}:{3:D2} y termina en {4:D2}:{5:D2}:{6:D2} + + + Pista {0} (Datos, grabada ininterrumpidamente) comienza en {1:D2}:{2:D2}:{3:D2} y termina en {4:D2}:{5:D2}:{6:D2} + + + Pista {0} (Audio cuadrafónico con pre-énfasis de 50/15 µs) comienza en {1:D2}:{2:D2}:{3:D2} y termina en {4:D2}:{5:D2}:{6:D2} + + + Pista {0} (Audio estéreo con pre-énfasis de 50/15 µs) comienza en {4}:{1:D2}:{2:D2}:{3:D2} y termina en {8}:{5:D2}:{6:D2}:{7:D2} + + + Pista {0} (Audio cuadrafónico sin pre-énfasis) comienza en {1:D2}:{2:D2}:{3:D2} y termina en {4:D2}:{5:D2}:{6:D2} + + + Pista {0} (Audio estéreo sin pre-énfasis) comienza en {1:D2}:{2:D2}:{3:D2} y termina en {4:D2}:{5:D2}:{6:D2} + + + Pista {0} (Datos, grabada incrementalmente) comienza en {4}:{1:D2}:{2:D2}:{3:D2} y termina en {8}:{5:D2}:{6:D2}:{7:D2} + + + Pista {0} (Datos, grabada ininterrumpidamente) comienza en {4}:{1:D2}:{2:D2}:{3:D2} y termina en {8}:{5:D2}:{6:D2}:{7:D2} + + + Pista {0} (Audio cuadrafónico con pre-énfasis de 50/15 µs) comienza en {4}:{1:D2}:{2:D2}:{3:D2} y termina en {8}:{5:D2}:{6:D2}:{7:D2} + + + Pista {0} (Audio cuadrafónico sin pre-énfasis) comienza en {4}:{1:D2}:{2:D2}:{3:D2} y termina en {8}:{5:D2}:{6:D2}:{7:D2} + + + Pista {0} (Audio estéreo con pre-énfasis de 50/15 µs) comienza en {1:D2}:{2:D2}:{3:D2} y termina en {4:D2}:{5:D2}:{6:D2} + + + Pista {0} (Audio estéreo sin pre-énfasis) comienza en {4}:{1:D2}:{2:D2}:{3:D2} y termina en {8}:{5:D2}:{6:D2}:{7:D2} + + + Pista número: {0} + + + Pista número: Lead-Out + + + La opción de compensación de pista está disponible + + + El tamaño de la pista es 0,34 µm + + + El tamaño de la pista es 0,40 µm + + + El tamaño de la pista es 0,615 µm + + + El tamaño de la pista es 0,74 µm + + + El tamaño de la pista es 0,80 µm + + + La pista comienza en el LBA {0}, o el MSF {1:X2}:{2:X2}:{3:X2} + + + Velocidad de transferencia: {0} kbit/s + + + La transferencia se terminará al detectar un error + + + Nombre de la capa de traducción: {0} + + + Versión de la capa de traducción: {0} + + + Fabricante de la capa de traducción: {0} + + + Travan 5 + + + Bandeja cerrada o carrito insertado pero error del medio + + + Bandeja abierto o carrito no insertado + + + Bloque gatillo. + + + El conjunto de funciones de la Computación Confiable está soportado + + + Ultra DMA: + + + Generar errores recuperados incondicionalmente ante excepciones informativas + + + unidades + + + unidades de {0} bytes + + + La unidad está reservada por el iniciador con ID {0:X16} + + + MHz + + + ms + + + ns + + + desconocida + + + µs + + + Código de comportamiento ATAPI DRQ desconocido ({0}) + + + Código de tamaño del paquete ATAPI desconocido ({0}) + + + Revisión ATA desconocida (0x{0:X4}) + + + Código de modo {0} de auto-carga desconocido + + + Código de auto-descarga desconocido ({0}) + + + Dispositivo de bloques desconocido + + + Condición de arranque para el ancho del bus desconocida con código 3. + + + Código de modo del búfer desconocido (0x{0:X2}) + + + Código de formato del cartucho desconocido ({0}) + + + Código de tipo del cartucho desconocido ({0}) + + + Subtipo de disco CD-RW desconocido: {0} + + + Subtipo de disco CD-R desconocido: {0} + + + Código de comportamiento de limpieza desconocido ({0}) + + + con código {0} desconocido + + + Código de reenvío de comandos desconocido ({0}) + + + Código de control de compresión desconocido ({0}) + + + Insertado cartucho de datos desconocido + + + Valor {0} de prioridad de retención de demanda de lectura desconocido + + + Valor {0} de prioridad de retención de demanda de escritura desconocido + + + código de densidad 0x{0:X2} desconocido + + + Descriptor de tipo {1} desconocido contiene: {0} + + + Descriptor de tipo {1} desconocido contiene datos binarios (hexadecimal): {0} + + + Modo {0} desconocido de acceso al dispositivo + + + Configuración específica desconocida (0x{0:X4}) del dispositivo + + + Valor del campo de tipo de dispositivo desconocido (0x{0:X2}) + + + tipo de disco desconocido + + + Tipo de disco {0:X2}h desconocido + + + ID de tipo de disco desconocida ({0}) + + + Código de tipo de carcasa de DVD-RAM desconocido ({0}) + + + Código desconocido ({0}) de activación de la partición de arranque + + + Código desconocido ({0}) de contenido de la memoria borrada + + + Código de prueba de fábrica desconocido ({0}) + + + Código de comportamiento de la reja desconocido ({0}) + + + Código de baudios de la interfaz de la librería desconocido ({0}) + + + ID del fabricante desconocida: 0x{0:X2} + + + Código de reconocimiento del medio desconocido ({0}) + + + Tipo de medio desconocido + + + tipo de medio 0x{0:X2} desconocido + + + Método {0} de reporte desconocido + + + Tipo de dispositivo desconocido o ninguno + + + Código de unidad de tamaño de la partición desconocido ({0}) + + + Código de tamaño de pendiente de pista desconocido ({0}) + + + Código de tipo del transporte del puerto A desconocido ({0}) + + + Código del auto-test al encendido desconocido ({0}) + + + Código del algoritmo modificador de la cola desconocido ({0}) + + + Parámetro de recuperación 0x{0:X2} desconocida + + + Velocidad de referencia desconocida + + + Versión del registro {0} desconocida + + + Código de comportamiento de los datos sense desconocido ({0}) + + + identificador de tamaño desconocido ({0}) + + + Tipo de conjuntos de tareas desconocido ({0}) + + + Formato de entrada de la TOC desconocido, mostrando los valores tal cual + + + Pendiente pista desconocida + + + Código de tamaño de pista desconocido ({0}) + + + Tipo de transporte 0x{0:X1} desconocido + + + Valor 0x{0:X2} desconocido en el campo de reloj SPI + + + Valor 0x{0:X2} desconocido en el campo TPGS + + + ID de fabricante 0x{0:X4} desconocido + + + Longitud de onda desconocida + + + Código de emulación WORM desconocido ({0}) + + + Código de restricciones de etiqueta WORM desconocido ({0}) + + + Se puede descargar con comandos NCQ pendientes + + + Los errores CIRC no recuperables no abortarán la transferencia. + + + Los errores CIRC no recuperables devolverán CHECK CONDITION. + + + Los errores CIRC no recuperables devolverán CHECK CONDITION y los datos sin corregir. + + + Los errores ECC no recuperables no abortarán la transferencia. + + + Los errores ECC no recuperables devolverán CHECK CONDITION. + + + Los errores ECC no recuperables devolverán CHECK CONDITION y los datos sin corregir. + + + La asignación {0} de no-omitir intervarlos dice que desde {1:D2}:{2:D2}:{3:D2} hasta {4:D2}:{5:D2}:{6:D2} no deben omitirse + + + La asignación {0} de no-omitir intervarlos dice que desde {4}:{1:D2}:{2:D2}:{3:D2} hasta {8}:{5:D2}:{6:D2}:{7:D2} no deben omitirse + + + La asignación {0} de no-omitir pistas dice la que la pista {1} no debe ser omitida + + + Dirección no especificada: {0} + + + El bit URG está soportado en los comandos READ STREAM DMA EXT y READ STREAM EXT + + + El bit URG está soportado en los comandos WRITE STREAM DMA EXT y WRITE STREAM EXT + + + NTSC (EEUU). + + + SCSI conectado por USB + + + Bloque de datos de usuario + + + sólo datos de usuario + + + datos de usuario y auxiliares + + + Usa datos sense de 35 bytes + + + Usa datos sense de 96 bytes + + + El uso de las funciones de protección con contraseña está permanentemente desactivado. + + + El uso de la protección contra escritura permanente está desactivado. + + + El descriptor del fabricante contiene: {0} + + + El descriptor del fabricante contiene datos binarios (hexadecimal): {0} + + + El descriptor del fabricante contiene datos de tipo {1} desconocido (hexadecimal): {0} + + + Modificador del tipo de dispositivo específico del fabricante = 0x{0:X2} + + + ASC ESPECÍFICO DEL FABRICANTE {0:X2}h CON ASCQ {1:X2}h + + + ASC ESPECÍFICO DEL FABRICANTE {0:X2}h CON ASCQ ESPECÍFICO DEL FABRICANTE {1:X2}h + + + El bit 5 del byte 6, específico del fabricante, está establecido en la respuesta a INQUIRY + + + Bytes 36 a 55, específicos del fabricante + + + Bytes 47 a 55, específicos del fabricante + + + Bytes 96 a {0}, específicos del fabricante + + + Control de modo específico del fabricante: {0} + + + Configuración de velocidad específica del fabricante: {0} + + + Valor {0} específico del fabricante establecido en el campo del calificador de periférico + + + La verificación tras la escritura está desactivada + + + Versión {0} + + + Bloque de video. + + + La pista de video {3} comienza en: {0:D2}:{1:D2}:{2:D2} + + + Volumen {0} + + + VStape I comprimida + + + VXA-1 + + + VXA-2 + + + VXA-3 + + + El reporte de advertencias está activado + + + La longitud de onda es 650nm + + + Unidad lógica bien conocida + + + con el código de densidad desconocido 0x{0:X2} + + + Palabra 116: 0x{0:X4} + + + Palabra 174: 0x{0:X4} + + + Palabra 175: 0x{0:X4} + + + Palabra {1}: 0x{0:X4} + + + Palabra {1} (CE-ATA): 0x{0:X4} + + + Palabra {1} (CFA): 0x{0:X4} + + + Palabra 207 (CE-ATA): 0x{0:X4} + + + Palabra 208 (CE-ATA): 0x{0:X4} + + + Palabra 219 bits 15 a 8: 0x{0:X2} + + + Palabra 220 bits 15 a 8: 0x{0:X2} + + + Palabra 221: 0x{0:X4} + + + Palabra 47 bits 15 a 8: 0x{0:X2} + + + Palabra 51 bits 7 a 0: 0x{0:X2} + + + Palabra 52 bits 7 a 0: 0x{0:X2} + + + Palabra 64 bits 15 a 8: 0x{0:X2} + + + Palabra 70: 0x{0:X4} + + + Palabra 73: 0x{0:X4} + + + Palabra 74: 0x{0:X4} + + + Palabra 9: 0x{0:X4} + + + World Wide Name: {0:X16} + + + La emulación WORM está desactivada + + + La emulación WORM está activada + + + Bloque de escritura: {0} bytes + + + La longitud del bloque de escritura es de {0} bytes + + + La longitud del bloque de escritura está definida en el CSD extendido + + + WRITE BUFFER DMA está soportado + + + WRITE BUFFER está soportado + + + WRITE BUFFER está soportado y activado + + + El búfer de escritura debe tener un ratio de llenado de {0} antes de vaciarse en el medio + + + La caché de escritura está activada + + + La caché de escritura está soportada + + + La caché de escritura está soportada y activada + + + Los comandos de escritura pueden cruzar los límites de los bloques físicos + + + La reducción de la corriente en escritura comienza en el cilindro {0} + + + WRITE DMA FUA EXT y WRITE MULTIPLE FUA EXT están soportados + + + WRITE DMA FUA EXT y WRITE MULTIPLE FUA EXT están soportados y activado + + + WRITE DMA QUEUED FUA EXT está soportado + + + WRITE DMA QUEUED FUA EXT está soportado y activado + + + Dispositivo de escritura única + + + La pre-compensación de escritura es {0} + + + La pre-compensación de escritura comienza en el cilindro {0} + + + Escribir/Leer/Verificar está soportado + + + Escribir/Leer/Verificar está soportado y activado + + + WRITE UNCORRECTABLE está soportado + + + WRITE UNCORRECTABLE está soportado y activado + + + La escritura está inihibida por alguna razón específica del medio + + + La escritura es {0} veces más lenta que la lectura + + + ANSI X3B5/86-199: Cartucho de cinta magnética de 12,7 mm y 22 pistas, 262 bpmm, MFM + + + ANSI X3B5/97-174: Cartucho de cinta magnética de 12,7 mm y 48 pistas, 1673 bpmm, MFM + + + ANSI X3B5/88-185A: Casete de cinta magnética de 3,81 mm, 2400 bpmm, DDS + + + ANSI X3.157-1987: Cartucho de cinta magnética de 12,7 mm y 9 pistas, 126 bpmm, codificación por fase + + + ANSI X3.136-1986: Cartucho de cinta magnética de 6,3 mm y 4 ó 9 pistas, 315 bpmm, GCR (QIC-24) + + + ANSI X3.158-1987: Casete de cinta magnética de 3,81 mm y 4 pistas, 315 bpmm, GCR + + + ANSI X3.191: Disco óptico de 130 mm y escritura única con 30000 pistas + + + ANSI X3.193-1990: Cartucho de cinta magnética de 12,7 mm y 48 pistas, 394 bpmm, MFM + + + ANSI X3.200: Disco óptico de 356 mm y doble cara con 56350 pistas + + + ANSI X3.202-1991: Casete de cinta magnética de 8 mm, 1703 bpmm, RLL + + + ANSI X3.211: Disco óptico de 130 mm, doble cara y escritura única con 18750 pistas + + + ANSI X3.212: Disco óptico de 130 mm, doble cara y lectura/escritura con 18750 pistas + + + ANSI X3.214: Disco óptico de 130 mm, doble cara y escritura única con 20000 pistas + + + Disco de Xbox 360 + + + Disco de Xbox + + + Las operaciones XOR están desactivadas + + + La zona {0} comienza en el LSN {1} + + + {0} particiones adicionales definidas + + + {0} bloques de reserva asignados + + + {0} bloques suplementarios de reserva asignados + + + {0} pistas asignadas en el disco + + + {0} bloques son {1} y tienen {2} bytes cada uno + + + {0} bloques son {1} y tienen una longitud variable + + + {0} bloques son {1} bytes cada uno + + + {0} bloques tienen conformidad con {1} y tienen {2} bytes cada uno + + + {0} bloques tienen conformidad con {1} y tienen una longitud variable + + + {0} bloques tienen {1} y tienen {2} bytes cada uno + + + {0} bloques tienen una longitud variable + + + {0} bytes límite de cuenta para ATAPI + + + como máximo {0} bytes pueden ser transferidos antes de una desconexión + + + como máximo {0} bytes puede ser transferidos durante un comando junto al comando de desconexión + + + {0} bytes por bloque lógico + + + {0} bytes por sector físico + + + {0} bytes por sector + + + {0} bytes por sector sin formato + + + {0} bytes por pista sin formato + + + actualmente {0} pistas del disco se pueden anexar + + + {0} cilindros + + + profundidad máxima de {0} en la cola + + + {0} sectores del firmware se programaron correctamente + + + reconocidas {0} capas de formato + + + {0} bloques de reserva libres + + + {0} cabezas + + + {0} KiB de búfer multi sector de puerto dual + + + {0} KiB de búfer multi sector de puerto dual con caché de lectura + + + {0} KiB de búfer de sector y puerto únicos + + + {0} KiB de búfer de tipo {1} desconocido + + + {0} bloques lógicos por unidad legible del medio + + + {0} bloques lógicos por unidad escribible del medio + + + máximo de {0} particiones adicionales + + + máximo posible de {0} pistas anexables en el disco + + + máximo posible de {0} pistas en el disco + + + se requieren {0} bloques del medio para el nonce vinculante + + + {0} microsegundos de retraso interposicional para la comprobación acústica ISO-7779 + + + {0} minutos para completar el borrado de seguridad mejorada + + + {0} minutos para completar el borrado seguro + + + {0} ms antes de intentar notificaciones de eventos asíncronos tras la inicialización + + + {0} ns. típicos para limpiar el bit BSY al recibir SERVICE + + + {0} ns. típicos para liberar el bus al recibir PACKET + + + {0} sectores físicos por pista + + + {0} ratio del búfer que debe estar vacío antes de intentar una reselección + + + {0} ratio del búfer que debe estar lleno antes de intentar una reselección + + + {0} entradas restantes del mapa de relocalización POW + + + {0} reemplazos POW restantes + + + {0} actualizaciones POW restantes + + + {0} segundos para terminar el auto-test extendido + + + {0} sectores entre el último bloque de un cilindro y el primer bloque del siguiente + + + {0} sectores entre el último bloque de una pista y el primer bloque de la siguiente + + + {0} sectores para el modo 3 de Escritura/Lectura/Verificación + + + {0} sectores para el modo 2 de Escritura/Lectura/Verificación + + + {0} sectores en modo LBA de 28-bits + + + {0} sectores en modo LBA de 48-bits + + + {0} sectores en la tarjeta + + + {0} sectores por pista + + + {0} sectores por zona que se deben reservar para la gestión de defectos + + + {0} pistas por LUN que se deben reservar para la gestión de defectos + + + {0} pistas por zona que se deben reservar para la gestión de defectos + + + {0} pistas por zona a usar para dividir la capacidad con el propósito de asignar sectores alternativos + + + {0} bloques de reserva primarios sin usar + + + {0} bloques de reserve suplementarios sin usar + + + {0} envolturas + + + deben pasar {0} horas entre el comienzo de una operación de escaneo en segundo plano y la siguiente + + + se permite usar el bus durante {0} µs antes de la desconexión, si se obtiene el privilegio y no está restringido + + + se permite activar BSY durante un máximo de {0} µs sin realizar el intercambio REQ/ACK + + + se permite un tiempo de espera máximo de {0} µs después de liberar el bus antes de intentar la reselección + + + 120mm + + + 13262 transiciones de flujo por radián + + + 15916 transiciones de flujo por radián + + + 1997 ó 2013 + + + 1998 ó 2014 + + + 1999 ó 2015 + + + 2000 ó 2016 + + + 2001 ó 2017 + + + 2002 ó 2018 + + + 2003 ó 2019 + + + 2004 ó 2020 + + + 2005 ó 2021 + + + 2006 ó 2022 + + + 2007 ó 2023 + + + 2008 ó 2024 + + + 2009 ó 2025 + + + LBA de 28-bits está soportado + + + LBA de 48-bits está soportado + + + LBA de 48-bits está soportado y activado + + + etiqueta de 4 bytes, datos de usuario y auxiliares + + + 60mm + + + 7958 transiciones de flujo por radían + + + 80mm + + + (activo) + + \ No newline at end of file diff --git a/Aaru.Decoders/Localization/Localization.resx b/Aaru.Decoders/Localization/Localization.resx new file mode 100644 index 000000000..0bd5dd377 --- /dev/null +++ b/Aaru.Decoders/Localization/Localization.resx @@ -0,0 +1,9757 @@ + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + ATAPI device + + + CompactFlash device + + + ATA device + + + Additional product ID: {0} + + + World Wide Name: {0:X16} + + + Supported ATA versions: + + + Maximum ATA revision supported: + + + Minor ATA version not specified + + + ATA (ATA-1) X3T9.2 781D prior to revision 4 + + + ATA-1 published, ANSI X3.221-1994 + + + ATA (ATA-1) X3T9.2 781D revision 4 + + + ATA-2 published, ANSI X3.279-1996 + + + ATA-2 X3T10 948D prior to revision 2k + + + ATA-3 X3T10 2008D revision 1 + + + ATA-2 X3T10 948D revision 2k + + + ATA-3 X3T10 2008D revision 0 + + + ATA-2 X3T10 948D revision 3 + + + ATA-3 published, ANSI X3.298-1997 + + + ATA-3 X3T10 2008D revision 6 + + + ATA-3 X3T13 2008D revision 7 + + + ATA/ATAPI-4 X3T13 1153D revision 6 + + + ATA/ATAPI-4 T13 1153D revision 13 + + + ATA/ATAPI-4 X3T13 1153D revision 7 + + + ATA/ATAPI-4 T13 1153D revision 18 + + + ATA/ATAPI-4 T13 1153D revision 15 + + + ATA/ATAPI-4 published, ANSI INCITS 317-1998 + + + ATA/ATAPI-5 T13 1321D revision 3 + + + ATA/ATAPI-4 T13 1153D revision 14 + + + ATA/ATAPI-5 T13 1321D revision 1 + + + ATA/ATAPI-5 published, ANSI INCITS 340-2000 + + + ATA/ATAPI-4 T13 1153D revision 17 + + + ATA/ATAPI-6 T13 1410D revision 0 + + + ATA/ATAPI-6 T13 1410D revision 3a + + + ATA/ATAPI-7 T13 1532D revision 1 + + + ATA/ATAPI-6 T13 1410D revision 2 + + + ATA/ATAPI-6 T13 1410D revision 1 + + + ATA/ATAPI-7 published ANSI INCITS 397-2005 + + + ATA/ATAPI-7 T13 1532D revision 0 + + + ACS-3 Revision 3b + + + ATA/ATAPI-7 T13 1532D revision 4a + + + ATA/ATAPI-6 published, ANSI INCITS 361-2002 + + + ATA8-ACS Revision 3c + + + ATA8-ACS Revision 6 + + + ATA8-ACS Revision 4 + + + ACS-2 Revision 2 + + + ATA8-ACS Revision 3e + + + ATA8-ACS Revision 4c + + + ATA8-ACS Revision 3f + + + ATA8-ACS Revision 3b + + + ACS-3 Revision 5 + + + ACS-2 published, ANSI INCITS 482-2012 + + + ATA8-ACS Revision 2d + + + ACS-2 Revision 3 + + + ACS-3 Revision 4 + + + Unknown ATA revision 0x{0:X4} + + + Parallel ATA device: + + + Serial ATA device: + + + SATA Express device + + + Unknown transport type 0x{0:X1} + + + ATAPI Direct-access device + + + ATAPI Sequential-access device + + + ATAPI Printer device + + + ATAPI Processor device + + + ATAPI Write-once device + + + ATAPI CD-ROM/DVD/etc device + + + ATAPI Scanner device + + + ATAPI Optical memory device + + + ATAPI Medium change device + + + ATAPI Communications device + + + ATAPI Graphics arts pre-press device (defined in ASC IT8) + + + ATAPI Array controller device + + + ATAPI Enclosure services device + + + ATAPI Simplified direct-access device + + + ATAPI Optical card reader/writer device + + + ATAPI Bridging Expanders + + + ATAPI Object-based Storage Device + + + ATAPI Automation/Drive Interface + + + ATAPI Well known logical unit + + + ATAPI Unknown or no device type + + + ATAPI Unknown device type field value 0x{0:X2} + + + Device shall set DRQ within 3 ms of receiving PACKET + + + Device shall assert INTRQ when DRQ is set to one + + + Device shall set DRQ within 50 µs of receiving PACKET + + + Unknown ATAPI DRQ behaviour code {0} + + + ATAPI device uses 12 byte command packet + + + ATAPI device uses 16 byte command packet + + + Unknown ATAPI packet size code {0} + + + Incomplete identify response + + + Device uses non-magnetic media + + + Device is removable + + + Device is fixed + + + Device transfer rate is <= 5 Mb/s + + + Device transfer rate is > 5 Mb/s but <= 10 Mb/s + + + Device transfer rate is > 10 Mb/s + + + Device is soft sectored + + + Device is hard sectored + + + Device is not MFM encoded + + + Format speed tolerance gap is required + + + Track offset option is available + + + Data strobe offset option is available + + + Rotational speed tolerance is higher than 0.5% + + + Spindle motor control is implemented + + + Head switch time is bigger than 15 µs. + + + Device does not rotate. + + + Device rotates at {0} rpm. + + + Physical sector size: {0} bytes + + + Logical sector size: {0} bytes + + + Logical sector starts at offset {0} from physical sector + + + Cylinders: {0} max., {1} current + + + Heads: {0} max., {1} current + + + Sectors per track: {0} max., {1} current + + + Sectors addressable in CHS mode: {0} max., {1} current + + + Cylinders: {0} + + + Heads: {0} + + + Sectors per track: {0} + + + Sectors addressable in CHS mode: {0} + + + {0} sectors in 28-bit LBA mode + + + {0} sectors in 48-bit LBA mode + + + Device size in CHS mode: {0} bytes, {1} Mb, {2} MiB + + + Device size in 28-bit LBA mode: {0} bytes, {1} Tb, {2} TiB + + + Device size in 28-bit LBA mode: {0} bytes, {1} Gb, {2} GiB + + + Device size in 28-bit LBA mode: {0} bytes, {1} Mb, {2} MiB + + + Device size in 48-bit LBA mode: {0} bytes, {1} Tb, {2} TiB + + + Device size in 48-bit LBA mode: {0} bytes, {1} Gb, {2} GiB + + + Device size in 48-bit LBA mode: {0} bytes, {1} Mb, {2} MiB + + + {0} sectors in card + + + {0} bytes per unformatted track + + + {0} bytes per unformatted sector + + + Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete. + + + Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is complete. + + + Device does not require SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete. + + + Device does not require SET FEATURES to spin up and IDENTIFY DEVICE response is complete. + + + Unknown device specific configuration 0x{0:X4} + + + {0} KiB of single ported single sector buffer + + + {0} KiB of dual ported multi sector buffer + + + {0} KiB of dual ported multi sector buffer with read caching + + + {0} KiB of unknown type {1} buffer + + + READ/WRITE LONG has {0} extra bytes + + + Device capabilities: + + + Standby time values are standard + + + IORDY is supported and can be disabled + + + IORDY is supported + + + DMA is supported + + + Device indicates a specific minimum standby timer value + + + A maximum of {0} sectors can be transferred per interrupt on READ/WRITE MULTIPLE + + + Device supports setting a maximum of {0} sectors + + + Long Physical Alignment setting is {0} + + + Device supports doubleword I/O + + + ATAPI device supports interleaved DMA + + + ATAPI device supports command queueing + + + ATAPI device supports overlapped operations + + + ATAPI device requires ATA software reset + + + PIO timing mode: {0} + + + DMA timing mode: {0} + + + Advanced PIO: + + + Single-word DMA: + + + (active) + + + Multi-word DMA: + + + Ultra DMA: + + + At minimum {0} ns. transfer cycle time per word in MDMA, {1} ns. recommended + + + At minimum {0} ns. transfer cycle time per word in PIO, without flow control + + + At minimum {0} ns. transfer cycle time per word in PIO, with IORDY flow control + + + {0} depth of queue maximum + + + {0} ns. typical to release bus from receipt of PACKET + + + {0} ns. typical to clear BSY bit from receipt of SERVICE + + + SATA 1.5Gb/s is supported + + + SATA 3.0Gb/s is supported + + + SATA 6.0Gb/s is supported + + + Receipt of host initiated power management requests is supported + + + PHY Event counters are supported + + + Supports host automatic partial to slumber transitions is supported + + + Supports device automatic partial to slumber transitions is supported + + + NCQ is supported + + + NCQ priority is supported + + + Unload is supported with outstanding NCQ commands + + + NCQ queue management is supported + + + NCQ streaming is supported + + + ATAPI device supports host environment detection + + + ATAPI device supports attention on slimline connected devices + + + {0} microseconds of interseek delay for ISO-7779 acoustic testing + + + Device nominal size is 5.25" + + + Device nominal size is 3.5" + + + Device nominal size is 2.5" + + + Device nominal size is 1.8" + + + Device nominal size is smaller than 1.8" + + + Device nominal size field value {0} is unknown + + + {0} bytes count limit for ATAPI + + + CompactFlash device supports power mode 1 + + + CompactFlash power mode 1 required for one or more commands + + + CompactFlash power mode 1 is disabled + + + CompactFlash device uses a maximum of {0} mA + + + Command set and features: + + + NOP is supported and enabled + + + NOP is supported + + + READ BUFFER is supported and enabled + + + READ BUFFER is supported + + + WRITE BUFFER is supported and enabled + + + WRITE BUFFER is supported + + + Host Protected Area is supported and enabled + + + Host Protected Area is supported + + + DEVICE RESET is supported and enabled + + + DEVICE RESET is supported + + + SERVICE interrupt is supported and enabled + + + SERVICE interrupt is supported + + + Release is supported and enabled + + + Release is supported + + + Look-ahead read is supported and enabled + + + Look-ahead read is supported + + + Write cache is supported and enabled + + + Write cache is supported + + + PACKET is supported and enabled + + + PACKET is supported + + + Power management is supported and enabled + + + Power management is supported + + + Removable media feature set is supported and enabled + + + Removable media feature set is supported + + + Security mode is supported and enabled + + + Security mode is supported + + + 28-bit LBA is supported + + + 48-bit LBA is supported and enabled + + + 48-bit LBA is supported + + + FLUSH CACHE is supported and enabled + + + FLUSH CACHE is supported + + + FLUSH CACHE EXT is supported and enabled + + + FLUSH CACHE EXT is supported + + + Device Configuration Overlay feature set is supported and enabled + + + Device Configuration Overlay feature set is supported + + + Automatic Acoustic Management is supported and enabled with value {0} (vendor recommends {1} + + + Automatic Acoustic Management is supported + + + SET MAX security extension is supported and enabled + + + SET MAX security extension is supported + + + Address Offset Reserved Area Boot is supported and enabled + + + Address Offset Reserved Area Boot is supported + + + SET FEATURES is required before spin-up + + + Power-up in standby is supported and enabled + + + Power-up in standby is supported + + + Removable Media Status Notification is supported and enabled + + + Removable Media Status Notification is supported + + + Advanced Power Management is supported and enabled with value {0} + + + Advanced Power Management is supported + + + CompactFlash feature set is supported and enabled + + + CompactFlash feature set is supported + + + READ DMA QUEUED and WRITE DMA QUEUED are supported and enabled + + + READ DMA QUEUED and WRITE DMA QUEUED are supported + + + DOWNLOAD MICROCODE is supported and enabled + + + DOWNLOAD MICROCODE is supported + + + S.M.A.R.T. is supported and enabled + + + S.M.A.R.T. is supported + + + S.M.A.R.T. Command Transport is supported + + + S.M.A.R.T. self-testing is supported and enabled + + + S.M.A.R.T. self-testing is supported + + + S.M.A.R.T. error logging is supported and enabled + + + S.M.A.R.T. error logging is supported + + + IDLE IMMEDIATE with UNLOAD FEATURE is supported and enabled + + + IDLE IMMEDIATE with UNLOAD FEATURE is supported + + + URG bit is supported in WRITE STREAM DMA EXT and WRITE STREAM EXT + + + URG bit is supported in READ STREAM DMA EXT and READ STREAM EXT + + + Device has a World Wide Name + + + WRITE DMA QUEUED FUA EXT is supported and enabled + + + WRITE DMA QUEUED FUA EXT is supported + + + WRITE DMA FUA EXT and WRITE MULTIPLE FUA EXT are supported and enabled + + + WRITE DMA FUA EXT and WRITE MULTIPLE FUA EXT are supported + + + General Purpose Logging is supported and enabled + + + General Purpose Logging is supported + + + Streaming feature set is supported and enabled + + + Streaming feature set is supported + + + Media Card Pass Through command set is supported and enabled + + + Media Card Pass Through command set is supported + + + Media Serial is supported and valid + + + Media Serial is supported + + + DSN feature set is supported and enabled + + + DSN feature set is supported + + + Accessible Max Address Configuration is supported and enabled + + + Accessible Max Address Configuration is supported + + + Extended Power Conditions are supported and enabled + + + Extended Power Conditions are supported + + + Extended Status Reporting is supported and enabled + + + Extended Status Reporting is supported + + + Free-fall control feature set is supported and enabled + + + Free-fall control feature set is supported + + + Segmented feature in DOWNLOAD MICROCODE is supported and enabled + + + Segmented feature in DOWNLOAD MICROCODE is supported + + + READ/WRITE DMA EXT GPL are supported and enabled + + + READ/WRITE DMA EXT GPL are supported + + + WRITE UNCORRECTABLE is supported and enabled + + + WRITE UNCORRECTABLE is supported + + + Write/Read/Verify is supported and enabled + + + Write/Read/Verify is supported + + + {0} sectors for Write/Read/Verify mode 3 + + + {0} sectors for Write/Read/Verify mode 2 + + + Current Write/Read/Verify mode: {0} + + + DT1825 is supported and enabled + + + DT1825 is supported + + + BLOCK ERASE EXT is supported + + + OVERWRITE EXT is supported + + + CRYPTO SCRAMBLE EXT is supported + + + DEVICE CONFIGURATION IDENTIFY DMA and DEVICE CONFIGURATION SET DMA are supported + + + READ BUFFER DMA is supported + + + WRITE BUFFER DMA is supported + + + DOWNLOAD MICROCODE DMA is supported + + + SET PASSWORD DMA and SET UNLOCK DMA are supported + + + Not all 28-bit commands are supported + + + Device follows CFast specification + + + Device follows IEEE-1667 + + + Read after TRIM is deterministic + + + Read after TRIM returns empty data + + + Device supports Long Physical Sector Alignment Error Reporting Control + + + Device encrypts all user data + + + Device's write cache is non-volatile + + + Device is zoned + + + Sanitize feature set is supported + + + Sanitize commands are specified by ACS-3 or higher + + + Sanitize commands are specified by ACS-2 + + + SANITIZE ANTIFREEZE LOCK EXT is supported + + + Trusted Computing feature set is supported + + + READ LOG DMA EXT is supported + + + RECEIVE FPDMA QUEUED and SEND FPDMA QUEUED are supported + + + Non-zero buffer offsets are supported and enabled + + + Non-zero buffer offsets are supported + + + DMA Setup auto-activation is supported and enabled + + + DMA Setup auto-activation is supported + + + Device-initiated power management is supported and enabled + + + Device-initiated power management is supported + + + In-order data delivery is supported and enabled + + + In-order data delivery is supported + + + Hardware Feature Control is supported and enabled + + + Hardware Feature Control is supported + + + Asynchronous notification is supported and enabled + + + Asynchronous notification is supported + + + Software Settings Preservation is supported and enabled + + + Software Settings Preservation is supported + + + NCQ Autosense is supported + + + Automatic Partial to Slumber transitions are enabled + + + Removable Media Status Notification feature set is supported + + + Free-fall sensitivity set to {0} + + + DATA SET MANAGEMENT can receive a maximum of {0} blocks of 512 bytes + + + Security: + + + Security is enabled + + + Security is locked + + + Security is not locked + + + Security is frozen + + + Security is not frozen + + + Security count has expired + + + Security count has not expired + + + Security level is maximum + + + Security level is high + + + Security is not enabled + + + Supports enhanced security erase + + + {0} minutes to complete secure erase + + + {0} minutes to complete enhanced secure erase + + + Master password revision code: {0} + + + Streaming: + + + Minimum request size is {0} + + + Streaming transfer time in PIO is {0} + + + Streaming transfer time in DMA is {0} + + + Streaming access latency is {0} + + + Streaming performance granularity is {0} + + + S.M.A.R.T. Command Transport (SCT): + + + SCT Long Sector Address is supported + + + SCT Write Same is supported + + + SCT Error Recovery Control is supported + + + SCT Features Control is supported + + + SCT Data Tables are supported + + + Non-Volatile Cache: + + + Version {0} + + + Power mode feature set is supported and enabled + + + Power mode feature set is supported + + + Non-Volatile Cache is {0} bytes + + + Word 9: 0x{0:X4} + + + Word 47 bits 15 to 8: 0x{0:X2} + + + Word 51 bits 7 to 0: 0x{0:X2} + + + Word 52 bits 7 to 0: 0x{0:X2} + + + Word 64 bits 15 to 8: 0x{0:X2} + + + Word 70: 0x{0:X4} + + + Word 73: 0x{0:X4} + + + Word 74: 0x{0:X4} + + + Word 116: 0x{0:X4} + + + Word {1}: 0x{0:X4} + + + Word {1} (CFA): 0x{0:X4} + + + Word 174: 0x{0:X4} + + + Word 175: 0x{0:X4} + + + Word 207 (CE-ATA): 0x{0:X4} + + + Word 208 (CE-ATA): 0x{0:X4} + + + Word 219 bits 15 to 8: 0x{0:X2} + + + Word 220 bits 15 to 8: 0x{0:X2} + + + Word 221: 0x{0:X4} + + + Word {1} (CE-ATA): 0x{0:X4} + + + Found incorrect Blu-ray BCA size ({0} bytes) + + + Reserved1 = 0x{0:X2} + + + Reserved2 = 0x{0:X2} + + + Blu-ray Burst Cutting Area in hex follows: + + + Found incorrect Blu-ray Cartridge Status size ({0} bytes) + + + Reserved3 = 0x{0:X8} + + + Reserved4 = 0x{0:X8} + + + Reserved5 = 0x{0:X8} + + + Reserved6 = 0x{0:X8} + + + Reserved7 = 0x{0:X8} + + + Media is inserted in a cartridge + + + Media has been taken out, or inserted in, the cartridge + + + Media is write protected + + + Media is not in a cartridge + + + Media has out bit marked, shouldn't + + + Media has write protection bit marked, shouldn't + + + Found incorrect DDS signature (0x{0:X4}) + + + DDS Format: 0x{0:X2} + + + First PSN of Drive Area: 0x{0:X8} + + + First PSN of Defect List: 0x{0:X8} + + + PSN of User Data Area's LSN 0: 0x{0:X8} + + + Last User Data Area's LSN 0: 0x{0:X8} + + + ISA0 size: {0} + + + OSA size: {0} + + + ISA1 size: {0} + + + Spare Area Full Flags: 0x{0:X2} + + + Disc Type Specific Field 1: 0x{0:X2} + + + Disc Type Specific Field 2: 0x{0:X8} + + + Blu-ray DDS Status Bits in hex follows: + + + Blu-ray DDS Disc Type Specific Data in hex follows: + + + Reserved3 = 0x{0:X2} + + + Reserved4 = 0x{0:X16} + + + Reserved7 = 0x{0:X2} + + + Reserved8 = 0x{0:X2} + + + Reserved9 = 0x{0:X8} + + + Blu-ray DI Unit format dependent contents as hex follows: + + + Disc product revision number: {0} + + + Disc timestamp: 0x{0:X2} + + + Disc media type ID: "{0}" + + + Disc manufacturer ID: "{0}" + + + Last address unit number of data zone in this layer: {0} + + + First address unit number of data zone in this layer: {0} + + + Last user data PSN for disc: {0} + + + Disc does not specify a maximum transfer rate. + + + Disc has a maximum transfer rate of {0} Mbit/sec. + + + Disc uses unknown BCA code {0} + + + Disc has a BCA. + + + Disc doesn't have a BCA. + + + Disc uses unknown recorded reflectivity polarity with code {0} + + + Recorded marks have a higher reflectivity than unrecorded ones (LTH disc). + + + Recorded marks have a lower reflectivity than unrecorded ones (HTL disc). + + + Disc uses unknown polarity with code {0} + + + Disc uses negative polarity. + + + Disc uses positive polarity. + + + Disc uses unknown channel length with code {0} + + + Disc uses a 69.0nm channel giving 27 Gb per layer. + + + Disc uses a 74.5nm channel giving 25 Gb per layer. + + + This disc contains a CD-RW layer. + + + This disc contains a CD-R layer. + + + This disc contains a CD-ROM layer. + + + This disc does not contain a CD layer. + + + This disc contains a DVD-RW layer. + + + This disc contains a DVD-R layer. + + + This disc contains a DVD-ROM layer. + + + This disc does not contain a DVD layer. + + + This disc has {0} layers + + + Disc version: {0} + + + Disc class: {0} + + + Disc size: Unknown code {0} + + + Disc size: 80mm + + + Disc size: 120mm + + + Disc type identifier: "{0}" + + + DI Unit is {0} bytes + + + This DI starts a new unit + + + This DI continues previous unit + + + Legacy value: 0x{0:X2} + + + This DI refers to layer {0} + + + There are {0} per block + + + DI Unit Format: 0x{0:X2} + + + DI Unit Sequence: {0} + + + Found unknown disc type identifier "{0}" + + + Found incorrect Blu-ray Disc Information size ({0} bytes) + + + Found incorrect Blu-ray Spare Area Information size ({0} bytes) + + + {0} free spare blocks + + + {0} allocated spare blocks + + + Expected CD ATIP size (32 bytes) is not received size ({0} bytes), not decoding + + + Indicative Target Writing Power: 0x{0:X2} + + + Disc is DDCD-RW + + + Disc is DDCD-R + + + Reference speed is 4x + + + Reference speed is 8x + + + Reference speed set is unknown: {0} + + + ATIP Start time of Lead-in: 0x{0:X6} + + + ATIP Last possible start time of Lead-out: 0x{0:X6} + + + S4 value: 0x{0:X6} + + + Disc is CD-RW + + + Disc is High-Speed CD-RW + + + Disc is Ultra-Speed CD-RW + + + Disc is Ultra-Speed+ CD-RW + + + Disc is medium type B, low beta category (B-) CD-RW + + + Disc is medium type B, high beta category (B+) CD-RW + + + Disc is medium type C, low beta category (C-) CD-RW + + + Disc is medium type C, high beta category (C+) CD-RW + + + Unknown CD-RW disc subtype: {0} + + + Reference speed is 2x + + + Disc is CD-R + + + Disc is normal speed (CLV) CD-R + + + Disc is high speed (CAV) CD-R + + + Disc is medium type A, low beta category (A-) CD-R + + + Disc is medium type A, high beta category (A+) CD-R + + + Disc is medium type B, low beta category (B-) CD-R + + + Disc is medium type B, high beta category (B+) CD-R + + + Disc is medium type C, low beta category (C-) CD-R + + + Disc is medium type C, high beta category (C+) CD-R + + + Unknown CD-R disc subtype: {0} + + + ATIP Start time of Lead-in: {0}:{1:D2}:{2:D2} + + + ATIP Last possible start time of Lead-out: {0}:{1:D2}:{2:D2} + + + Disc use is unrestricted + + + Disc use is restricted + + + A1 value: 0x{0:X6} + + + A2 value: 0x{0:X6} + + + A3 value: 0x{0:X6} + + + Disc uses phase change + + + Disc uses long strategy type dye (Cyanine, AZO, etc...) + + + Disc uses short strategy type dye (Phthalocyanine, etc...) + + + Disc manufactured by: {0} + + + Expected CD-TEXT size ({0} bytes) is not received size ({1} bytes), not decoding + + + Incorrect CD-Text pack type {0}, not decoding + + + CD-Text pack contains title for album + + + CD-Text pack contains title for track {0} + + + CD-Text pack contains performer for album + + + CD-Text pack contains performer for track {0} + + + CD-Text pack contains songwriter for album + + + CD-Text pack contains songwriter for track {0} + + + album + + + track {0} + + + CD-Text pack contains arranger for album + + + CD-Text pack contains arranger for track {0} + + + CD-Text pack contains content provider's message for album + + + CD-Text pack contains content provider's message for track {0} + + + CD-Text pack contains disc identification information + + + CD-Text pack contains genre identification information + + + CD-Text pack contains table of contents information + + + CD-Text pack contains second table of contents information + + + CD-Text pack contains reserved data + + + CD-Text pack contains data reserved for content provider only + + + CD-Text pack contains UPC + + + CD-Text pack contains size block information + + + Double Byte Character Code is used + + + Block number {0} + + + Character position {0} + + + Text field: "{0}" + + + Binary contents: {0} + + + CRC: 0x{0:X4} + + + Expected CDFullTOC size ({0} bytes) is not received size ({1} bytes), not decoding + + + First complete session number: {0} + + + Last complete session number: {0} + + + Unknown TOC entry format, printing values as-is + + + Session {0} + + + First video track number: {0} + + + CD-V single in NTSC format with digital stereo sound + + + CD-V single in NTSC format with digital bilingual sound + + + CD-V disc in NTSC format with digital stereo sound + + + CD-V disc in NTSC format with digital bilingual sound + + + CD-V single in PAL format with digital stereo sound + + + CD-V single in PAL format with digital bilingual sound + + + CD-V disc in PAL format with digital stereo sound + + + CD-V disc in PAL format with digital bilingual sound + + + First track number: {0} ( + + + ) + + + Stereo audio track with no pre-emphasis + + + Stereo audio track with 50/15 μs pre-emphasis + + + Quadraphonic audio track with no pre-emphasis + + + Quadraphonic audio track with 50/15 μs pre-emphasis + + + Data track, recorded uninterrupted + + + Data track, recorded incrementally + + + Disc type: {0} + + + Last video track number: {0} + + + Last track number: {0} ( + + + Lead-Out start position: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Lead-Out start position: {0:D2}:{1:D2}:{2:D2} + + + Lead-Out is audio type + + + Lead-Out is data type + + + Book type: 0x{0:X2} + + + Material type: 0x{0:X2} + + + Moment of inertia: 0x{0:X2} + + + Data track {3} starts at: {4:D2}:{0:D2}:{1:D2}:{2:D2} ( + + + Audio track {3} starts at: {4:D2}:{0:D2}:{1:D2}:{2:D2} ( + + + Data track {3} starts at: {0:D2}:{1:D2}:{2:D2} ( + + + Audio track {3} starts at: {0:D2}:{1:D2}:{2:D2} ( + + + Absolute time: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Absolute time: {0:D2}:{1:D2}:{2:D2} + + + Video track {3} starts at: {0:D2}:{1:D2}:{2:D2} + + + Start of next possible program in the recordable area of the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Maximum start of outermost Lead-Out in the recordable area of the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Start of next possible program in the recordable area of the disc: {0:D2}:{1:D2}:{2:D2} + + + Maximum start of outermost Lead-Out in the recordable area of the disc: {0:D2}:{1:D2}:{2:D2} + + + Number of skip interval pointers: {0} + + + Number of skip track pointers: {0} + + + Skip track {0} + + + Optimum recording power: 0x{0:X2} + + + Start time of the first Lead-in area in the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Start time of the first Lead-in area in the disc: {0:D2}:{1:D2}:{2:D2} + + + Copy of information of A1 from ATIP found + + + Start position of outer part lead-in area: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Stop position of inner part lead-out area: {3:D2}:{0:D2}:{1:D2}:{2:D2} + + + Start position of outer part lead-in area: {0:D2}:{1:D2}:{2:D2} + + + Stop position of inner part lead-out area: {0:D2}:{1:D2}:{2:D2} + + + Start time for interval that should be skipped: {0:D2}:{1:D2}:{2:D2} + + + Ending time for interval that should be skipped: {0:D2}:{1:D2}:{2:D2} + + + Disc ID: {0:X6} + + + Expected CD PMA size ({0} bytes) is not received size ({1} bytes), not decoding + + + Track {0} (Stereo audio track with no pre-emphasis) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2} + + + Track {0} (Stereo audio track with no pre-emphasis) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2} + + + Track {0} (Stereo audio track with 50/15 μs pre-emphasis) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2} + + + Track {0} (Stereo audio track with 50/15 μs pre-emphasis) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2} + + + Track {0} (Quadraphonic audio track with no pre-emphasis) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2} + + + Track {0} (Quadraphonic audio track with no pre-emphasis) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2} + + + Track {0} (Quadraphonic audio track with 50/15 μs pre-emphasis) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2} + + + Track {0} (Quadraphonic audio track with 50/15 μs pre-emphasis) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2} + + + Track {0} (Data track, recorded uninterrupted) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2} + + + Track {0} (Data track, recorded uninterrupted) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2} + + + Track {0} (Data track, recorded incrementally) starts at {4}:{1:D2}:{2:D2}:{3:D2} and ends at {8}:{5:D2}:{6:D2}:{7:D2} + + + Track {0} (Data track, recorded incrementally) starts at {1:D2}:{2:D2}:{3:D2} and ends at {4:D2}:{5:D2}:{6:D2} + + + Reserved = 0x{0:X2} + + + Skip track assignment {0} says that tracks {1} should be skipped + + + Unskip track assignment {0} says that tracks {1} should not be skipped + + + Skip time interval assignment {0} says that from {4}:{1:D2}:{2:D2}:{3:D2} to {8}:{5:D2}:{6:D2}:{7:D2} should be skipped + + + Skip time interval assignment {0} says that from {1:D2}:{2:D2}:{3:D2} to {4:D2}:{5:D2}:{6:D2} should be skipped + + + Unskip time interval assignment {0} says that from {4}:{1:D2}:{2:D2}:{3:D2} to {8}:{5:D2}:{6:D2}:{7:D2} should not be skipped + + + Unskip time interval assignment {0} says that from {1:D2}:{2:D2}:{3:D2} to {4:D2}:{5:D2}:{6:D2} should not be skipped + + + CD sector. + + + CD-ROM sector. + + + Position {0:X2}:{1:X2}:{2:X2} (LBA {3}) + + + Mode 0. + + + Mode 1. + + + Mode 2. + + + Invalid mode 3. + + + User data block + + + Fourth run-in block + + + Third run-in block + + + Second run-in block + + + First run-in block + + + Link block + + + Second run-out block + + + First run-out block + + + Correct sector contents. + + + Incorrect sector contents. + + + Correct EDC. + + + Incorrect EDC. + + + Correct ECC P. + + + Incorrect ECC P. + + + Correct ECC Q. + + + Incorrect ECC Q. + + + Correct zero fill. + + + Incorrect zero fill. + + + Subheader copies differ. + + + File number: {0} + + + Channel number: {0} + + + Coding information number: {0} + + + End of file. + + + Real-time block. + + + Form 2. + + + Form 1. + + + Trigger block. + + + Data block. + + + Audio block. + + + Video block. + + + End of record. + + + Expected CDSessionInfo size ({0} bytes) is not received size ({1} bytes), not decoding + + + First track number in last complete session: {0} + + + Track starts at LBA {0}, or MSF {1:X2}:{2:X2}:{3:X2} + + + Q subchannel mode not given + + + Q subchannel stores current position + + + Q subchannel stores ISRC + + + Q subchannel stores media catalog number + + + Reserved flags 0x{0:X2} set + + + Digital copy of track is permitted + + + Digital copy of track is prohibited + + + stereo audio with pre-emphasis + + + stereo audio without pre-emphasis + + + incremental data + + + uninterrupted data + + + quadraphonic audio with pre-emphasis + + + quadraphonic audio without pre-emphasis + + + reserved control value {0} + + + copy permitted + + + copy prohibited + + + Lead-In + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} position: {9:X2}:{10:X2}:{11:X2} (LBA {12}), track {13:X} starts at {14:X2}:{15:X2}:{16:X2} (LBA {17}), Q CRC 0x{18:X2}{19:X2} ({20}), R-W {21} + + + corrupted pause + + + pause + + + not pause + + + OK + + + BAD + + + empty + + + not empty + + + CD-DA / CD-ROM + + + CD-i + + + CD-ROM XA + + + unknown {0:X2} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} position: {9:X2}:{10:X2}:{11:X2} (LBA {12}), track {13:X} is first program area track in {14} format, Q CRC 0x{15:X2}{16:X2} ({17}), R-W {18} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} position: {9:X2}:{10:X2}:{11:X2} (LBA {12}), track {13:X} is last program area track, Q CRC 0x{14:X2}{15:X2} ({16}), R-W {17} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} MCN: {9} frame {10:X2} CRC 0x{11:X2}{12:X2} ({13}), R-W {14} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q: {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} {13:X2} {14:X2} {15:X2} {16:X2} {17:X2} CRC 0x{18:X2}{19:X2} ({20}), R-W {21} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} skip interval start time {9:X2}{10:X2}{11:X2}, skip interval stop time {12:X2}{13:X2}{14:X2}, CRC 0x{15:X2}{16:X2} ({17}), R-W {18} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} next program area can start at {9:X2}:{10:X2}:{11:X2} (LBA {12}), last-session, {13} mode 5 pointers, CRC 0x{14:X2}{15:X2} ({16}), R-W {17} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} next program area can start at {9:X2}:{10:X2}:{11:X2} (LBA {12}), maximum Lead-out at {13:X2}:{14:X2}:{15:X2} (LBA {16}), {17} mode 5 pointers, CRC 0x{18:X2}{19:X2} ({20}), R-W {21} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8}, {9} skip interval pointers, {10} skip track assignments, CRC 0x{11:X2}{12:X2} ({13}), R-W {14} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8}, ATIP values {9:X2}, {10:X2}, {11:X2}, first disc Lead-in starts at {12:X2}{13:X2}{14:X2} (LBA {15}), CRC 0x{16:X2}{17:X2} ({18}), R-W {19} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8}, tracks {9} to be skipped, CRC 0x{10:X2}{11:X2} ({12}), R-W {13} + + + Lead-Out + + + Program + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} position: track {9:X} index {10:X} relative position {11:X2}:{12:X2}:{13:X2} (LBA {14}), absolute position {15:X2}:{16:X2}:{17:X2} (LBA {18}), Q CRC 0x{19:X2}{20:X2} ({21}), R-W {22} + + + {0:D2}:{1:D2}:{2:D2} - LBA {3,6}: {4} area, {5}, {6}, {7}, Q mode {8} ISRC: {9} frame {10:X2} CRC 0x{11:X2}{12:X2} ({13}), R-W {14} + + + Expected CD TOC size ({0} bytes) is not received size ({1} bytes), not decoding + + + First track number in first complete session: {0} + + + Last track number in last complete session: {0} + + + Track number: Lead-Out + + + Track number: {0} + + + Q subchannel stores track pointer + + + Q subchannel stores video track pointer + + + Q subchannel mode {0} + + + Disc surface is set to write protected status + + + Disc comes in a cartridge + + + Disc has been extracted from the cartridge + + + Cartridge is set to write protected + + + Disc shall not be written without a cartridge + + + Disc may be written without a cartridge + + + Unknown disc type id {0} + + + Disc is write inhibited because it has been extracted from the cartridge + + + Disc is write inhibited for an unspecified reason + + + Disc has unknown reason {0} for write inhibition + + + No drive region setting. + + + Drive region is set. + + + Drive region is set, with additional restrictions required to make a change. + + + Drive region has been set permanently, but may be reset by the vendor if necessary. + + + Drive has {0} vendor resets available. + + + Drive has {0} user controlled changes available. + + + Drive has no region set. + + + Drive is region free. + + + Drive has the following regions set: + + + The Logical Unit does not enforce Region Playback Controls (RPC). + + + The Logical Unit shall adhere to the specification and all requirements of the CSS license agreement concerning RPC. + + + The Logical Unit uses an unknown region enforcement scheme. + + + Disc has no encryption. + + + Disc is encrypted using CSS or CPPM. + + + Disc is encrypted using CPRM. + + + Disc is encrypted using AACS. + + + Disc is encrypted using unknown algorithm with ID {0}. + + + Disc cannot be played in any region at all. + + + Disc can be played in any region. + + + Disc can be played in the following regions: + + + Formatting in progress. + + + Formatting is only using partial certification + + + Only a group is being formatted + + + Disc has been certified by a user + + + Disc has been certified by a manufacturer + + + DDS has been updated {0} times + + + Group {0} is being formatted + + + Group {0} is being certified partially + + + Group {0} has been certified by an user + + + Disc has {0} zones + + + Primary Spare Area stats at PSN {0:X}h and ends at PSN {1:X}h, inclusively + + + LSN 0 is at PSN {0:X}h + + + Zone {0} starts at LSN {1} + + + unknown size identifier {0} + + + Disc is a {0} {1} version {2} + + + Disc claims conformation to ECMA-267 + + + Disc claims conformation to ECMA-268 + + + Disc claims conformation to ECMA-272 + + + Disc claims conformation to ECMA-330 + + + Disc claims conformation to ECMA-279 + + + Disc claims conformation to ECMA-359 + + + Disc claims conformation to ECMA-382 + + + Disc claims conformation to ECMA-338 + + + Disc claims conformation to ECMA-384 + + + 60mm + + + invalid size + + + Disc claims conformation to ECMA-365 + + + Disc claims conformation to ECMA-274 + + + Disc claims conformation to ECMA-337 + + + Disc claims conformation to ECMA-371 + + + Disc claims conformation to ECMA-349 + + + Disc claims conformation to ECMA-374 + + + Disc claims conformation to ECMA-364 + + + Disc is a Nintendo Gamecube Optical Disc (GOD) + + + Disc is a Nintendo Wii Optical Disc (WOD) + + + unknown disc type + + + 80mm + + + 120mm + + + Disc book type is {0} + + + Disc maximum transfer rate is 2.52 Mbit/sec. + + + Disc maximum transfer rate is 5.04 Mbit/sec. + + + Disc maximum transfer rate is 10.08 Mbit/sec. + + + Disc maximum transfer rate is 20.16 Mbit/sec. + + + Disc maximum transfer rate is 30.24 Mbit/sec. + + + Disc maximum transfer rate is unspecified. + + + Disc maximum transfer rate is specified by unknown key {0} + + + Disc has {0} layers + + + Layers are in parallel track path + + + Layers are in opposite track path + + + Pitch size is 0.267 μm/bit + + + Pitch size is 0.147 μm/bit + + + Pitch size is between 0.409 μm/bit and 0.435 μm/bit + + + Pitch size is between 0.140 μm/bit and 0.148 μm/bit + + + Pitch size is 0.153 μm/bit + + + Pitch size is between 0.130 μm/bit and 0.140 μm/bit + + + Pitch size is 0.353 μm/bit + + + Unknown pitch size key {0} + + + Track size is 0.74 μm + + + Track size is 0.80 μm + + + Track size is 0.615 μm + + + Track size is 0.40 μm + + + Track size is 0.34 μm + + + Unknown track size key {0} + + + Data area starts at PSN {0:X}h + + + Data area ends at PSN {0:X}h + + + Layer 0 ends at PSN {0:X}h + + + Disc is empty + + + Media attribute is {0} + + + Disc shall be recorded with a case + + + Disc can be recorded with or without a case + + + Unknown DVD-RAM case type key {0} + + + Disc manufacturer is {0} + + + Disc manufacturer supplementary information is {0} + + + Current Border-Out first sector is PSN {0:X}h + + + Next Border-In first sector is PSN {0:X}h + + + Disc contains extended information for VCPS + + + Disc media type is {0} + + + Disc product revision is {0} + + + Current RMD in extra Border zone starts at PSN {0:X}h + + + PFI in extra Border zone starts at PSN {0:X}h + + + Control Data Zone is pre-recorded + + + Lead-In is pre-recorded + + + Lead-Out is pre-recorded + + + Disc for unrestricted use. + + + Invalid purpose field with value {0} + + + Consumer purpose disc for use in consumer purpose drives + + + Disc for restricted use. + + + Disc for use in special drives according with purpose value {0} + + + General purpose disc for use in general purpose drives + + + Disc track pitch is 0.74 μm + + + Unknown track pitch + + + Reference velocity is 3.49 m/s + + + Unknown reference velocity + + + Disc has 80mm diameter + + + Disc has 120mm diameter + + + Disc reflectivity is between 18% and 30% + + + Disc reflectivity is between 45% and 85% + + + Dye is organic + + + Dye is phase change + + + Disc is RW (rewritable) + + + Disc is R (recordable) + + + Wavelength is 650nm + + + Unknown wavelength + + + Last writable ECC block address: 0x{0:X6} + + + Part version {0} + + + Recommended recording power is {0} mW + + + Recording power is not specified + + + Recommended erasing power ratio is {0} ε + + + Erasing power ratio is not specified + + + {0} unused primary spare blocks + + + {0} unused supplementary spare blocks + + + {0} allocated supplementary spare blocks + + + Prologue found at {0} + + + Volume {0} + + + Sector {0} + + + Checksum {0} + + + Epilogue {0:X2}{1:X2}{2:X2} + + + Inner gap has {0} bytes + + + Data has {0} bytes + + + Got {0} bytes of gap + + + Finished sector at {0} + + + Adding sector {0} of track {1} + + + MultiMediaCard Device Identification Register: + + + Manufacturer: {0} + + + Removable device + + + BGA device + + + POP device + + + Application ID: {0} + + + Product revision: {0:X2}.{1:X2} + + + Product serial number: {0} + + + 1997 or 2013 + + + 1998 or 2014 + + + 1999 or 2015 + + + 2000 or 2016 + + + 2001 or 2017 + + + 2002 or 2018 + + + 2003 or 2019 + + + 2004 or 2020 + + + 2005 or 2021 + + + 2006 or 2022 + + + 2007 or 2023 + + + 2008 or 2024 + + + 2009 or 2025 + + + Device manufactured month {0} of {1} + + + CID CRC: 0x{0:X2} + + + Register version 1.0 + + + Register version 1.1 + + + Register version 1.2 + + + MultiMediaCard Device Specific Data Register: + + + Register version is defined in Extended Device Specific Data Register + + + ns + + + μs + + + ms + + + MHz + + + unknown + + + Device's clock frequency: {0}{1} + + + Read block length size is defined in extended CSD + + + Device may be bigger than 2GiB and have its real size defined in the extended CSD + + + Device has {0} blocks + + + Device has {0} GiB + + + Device has {0} MiB + + + Device has {0} KiB + + + Device has {0} bytes + + + Device uses a maximum of 0.5mA for reading at minimum voltage + + + Device uses a maximum of 1mA for reading at minimum voltage + + + Device uses a maximum of 5mA for reading at minimum voltage + + + Device uses a maximum of 10mA for reading at minimum voltage + + + Device uses a maximum of 25mA for reading at minimum voltage + + + Device uses a maximum of 35mA for reading at minimum voltage + + + Device uses a maximum of 60mA for reading at minimum voltage + + + Device uses a maximum of 100mA for reading at minimum voltage + + + Device uses a maximum of 1mA for reading at maximum voltage + + + Device uses a maximum of 5mA for reading at maximum voltage + + + Device uses a maximum of 10mA for reading at maximum voltage + + + Device uses a maximum of 25mA for reading at maximum voltage + + + Device uses a maximum of 35mA for reading at maximum voltage + + + Device uses a maximum of 45mA for reading at maximum voltage + + + Device uses a maximum of 80mA for reading at maximum voltage + + + Device uses a maximum of 200mA for reading at maximum voltage + + + Device uses a maximum of 0.5mA for writing at minimum voltage + + + Device uses a maximum of 1mA for writing at minimum voltage + + + Device uses a maximum of 5mA for writing at minimum voltage + + + Device uses a maximum of 10mA for writing at minimum voltage + + + Device uses a maximum of 25mA for writing at minimum voltage + + + Device uses a maximum of 35mA for writing at minimum voltage + + + Device uses a maximum of 60mA for writing at minimum voltage + + + Device uses a maximum of 100mA for writing at minimum voltage + + + Device uses a maximum of 1mA for writing at maximum voltage + + + Device uses a maximum of 5mA for writing at maximum voltage + + + Device uses a maximum of 10mA for writing at maximum voltage + + + Device uses a maximum of 25mA for writing at maximum voltage + + + Device uses a maximum of 35mA for writing at maximum voltage + + + Device uses a maximum of 45mA for writing at maximum voltage + + + Device uses a maximum of 80mA for writing at maximum voltage + + + Device uses a maximum of 200mA for writing at maximum voltage + + + Device can erase a minimum of {0} blocks at a time + + + Device can write protect regions + + + Device can write protect a minimum of {0} blocks at a time + + + Device can't write protect regions + + + Device uses no ECC by default + + + Device uses BCH(542, 512) ECC by default + + + Device uses unknown ECC code {0} by default + + + Writing is {0} times slower than reading + + + Write block length size is defined in extended CSD + + + Write block length is {0} bytes + + + Device allows writing partial blocks + + + Device supports content protection + + + Device contents are original + + + Device is permanently write protected + + + Device is temporarily write protected + + + Device is formatted like a hard disk + + + Device is formatted like a floppy disk using Microsoft FAT + + + Device uses Universal File Format + + + Device uses unknown file format code {0} + + + Device uses unknown file format code {0} and file format group 1 + + + Device currently uses no ECC + + + Device currently uses BCH(542, 512) ECC + + + Device currently uses unknown ECC code {0} + + + CSD CRC: 0x{0:X2} + + + MultiMediaCard Extended Device Specific Data Register: + + + Last extended security error was {0} + + + Device supports standard MMC command set + + + Device supports unknown command sets 0x{0:X2} + + + Device implements HPI using CMD12 + + + Device implements HPI using CMD13 + + + Device supports background operations + + + Device supports a maximum of {0} packed reads and {1} packed writes + + + Device supports Data Tag + + + Tags must be in units of {0} sectors + + + Tag resources size is {0}. + + + Max context ID is {0}. + + + Large unit maximum multiplier is {0}. + + + Large unit size is {0} MiB + + + Device supports non-persistent extended partitions + + + Device supports system code extended partitions + + + Device supports FFU + + + Maximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}s + + + Maximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}ms + + + Maximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}µs + + + Device supports Vendor Specific Mode + + + Device supports the barrier command + + + Device supports command queuing with a depth of {0} + + + {0} firmware sectors correctly programmed + + + Device used between 0% and 10% of its estimated life time + + + Device used between 10% and 20% of its estimated life time + + + Device used between 20% and 30% of its estimated life time + + + Device used between 30% and 40% of its estimated life time + + + Device used between 40% and 50% of its estimated life time + + + Device used between 50% and 60% of its estimated life time + + + Device used between 60% and 70% of its estimated life time + + + Device used between 70% and 80% of its estimated life time + + + Device used between 80% and 90% of its estimated life time + + + Device used between 90% and 100% of its estimated life time + + + Device exceeded its maximum estimated life time + + + Device informs it's in good health + + + Device informs it should be replaced soon + + + Device informs it should be replace immediately + + + Device does not report an optimal read size + + + Optimal read size is {0} KiB + + + Device does not report an optimal write size + + + Optimal write size is {0} KiB + + + Device does not report an optimal trim size + + + Optimal trim size is {0} KiB + + + Device version: {0} + + + Firmware version: {0} + + + Device has no cache + + + Device has {0} KiB of cache + + + Device takes a maximum of {0} ms by default for a SWITCH command + + + Device takes a maximum of {0} by default to power off from a SWITCH command notification + + + Device has no pending background operations + + + Device has non critical operations outstanding + + + Device has performance impacted operations outstanding + + + Device has critical operations outstanding + + + Last WRITE MULTIPLE command correctly programmed {0} sectors + + + Device takes a maximum of {0} ms for initialization after partition + + + Device uses a FIFO policy for cache flushing + + + Device takes a maximum of {0} ms for trimming a single erase group + + + Device supports the sanitize operation + + + Device supports supports the secure and insecure trim operations + + + Device supports automatic erase on retired defective blocks + + + Device supports secure purge operations + + + Device takes a maximum of {0} ms for securely erasing a single erase group + + + Device takes a maximum of {0} ms for securely trimming a single erase group + + + Device supports high speed timing on boot + + + Device supports dual data rate on boot + + + Device supports alternative boot method + + + Device has a {0} KiB boot partition + + + Device has a page size of {0} KiB + + + Device erase groups are {0} KiB + + + Device takes a maximum of {0} ms for erasing a single erase group + + + Device smallest write protect group is made of {0} erase groups + + + Device uses {0} mA on Vcc when sleeping + + + Device uses {0} μA on Vcc when sleeping + + + Device uses {0} mA on Vccq when sleeping + + + Device uses {0} μA on Vccq when sleeping + + + Device takes a maximum of {0} s to switch production state awareness + + + Device takes a maximum of {0} ms to switch production state awareness + + + Device takes a maximum of {0} μs to switch production state awareness + + + Device takes a maximum of {0} ms to transition between sleep and standby states + + + Device takes a maximum of {0} μs to transition between sleep and standby states + + + Device takes a maximum of {0} ns to transition between sleep and standby states + + + Device takes a maximum of {0} s to move to sleep state + + + Device takes a maximum of {0} ms to move to sleep state + + + Device takes a maximum of {0} μs to move to sleep state + + + Device has {0} sectors + + + Device supports secure write protection + + + Device has secure write protection enabled + + + Device cannot achieve 2.4MB/s reading in SDR 26Mhz mode + + + Device can achieve a minimum of {0}MB/s reading in SDR 26Mhz mode + + + Device cannot achieve 2.4MB/s reading in SDR 26Mhz 4-bit mode + + + Device can achieve a minimum of {0}MB/s reading in SDR 26Mhz 4-bit mode + + + Device cannot achieve 2.4MB/s reading in SDR 52Mhz mode + + + Device can achieve a minimum of {0}MB/s reading in SDR 52Mhz mode + + + Device cannot achieve 4.8MB/s reading in DDR 52Mhz mode + + + Device can achieve a minimum of {0}MB/s reading in DDR 52Mhz mode + + + Device cannot achieve 2.4MB/s writing in SDR 26Mhz mode + + + Device can achieve a minimum of {0}MB/s writing in SDR 26Mhz mode + + + Device cannot achieve 2.4MB/s writing in SDR 26Mhz 4-bit mode + + + Device can achieve a minimum of {0}MB/s writing in SDR 26Mhz 4-bit mode + + + Device cannot achieve 2.4MB/s writing in SDR 52Mhz mode + + + Device can achieve a minimum of {0}MB/s writing in SDR 52Mhz mode + + + Device cannot achieve 4.8MB/s writing in DDR 52Mhz mode + + + Device can achieve a minimum of {0}MB/s writing in DDR 52Mhz mode + + + Device can take a maximum of {0} ms when switching partitions + + + Device can take a maximum of {0} ms when releasing from an interrupt + + + Device supports I/O driver strength type 0. + + + Device supports I/O driver strength type 1. + + + Device supports I/O driver strength type 2. + + + Device supports I/O driver strength type 3. + + + Device supports I/O driver strength type 4. + + + Device supports 26 Mhz mode + + + Device supports 52 Mhz mode + + + Device supports DDR 52 Mhz mode at 1.8V or 3V + + + Device supports DDR 52 Mhz mode 1.2V + + + Device supports HS-200 mode (SDR 200Mhz) at 1.8V + + + Device supports HS-200 mode (SDR 200Mhz) at 1.2V + + + Device supports HS-400 mode (DDR 200Mhz) at 1.8V + + + Device supports HS-400 mode (DDR 200Mhz) at 1.2V + + + CSD version 1.{0} revision 1.{1} + + + Device follows compatibility MMC command set. + + + Device follows standard MMC command set v4.0. + + + Device follows standard MMC command set with unknown version code {0}. + + + Device follows unknown MMC command set code {0} with revision code {1}. + + + Device is in High Speed mode. + + + Device is in HS-200 mode. + + + Device is in HS-400 mode. + + + Device has unknown timing mode {0}. + + + Selected driver strength is type {0}. + + + Device supports enhanced strobe mode + + + Device uses strobe during Data Out, CRC and CMD responses + + + Device uses strobe during Data Out and CRC responses + + + Device is using 1-bit data bus + + + Device is using 4-bit data bus + + + Device is using 8-bit data bus + + + Device is using 4-bit DDR data bus + + + Device is using 8-bit DDR data bus + + + Device is using unknown data bus code {0} + + + Erased memory range shall be '{0}'. + + + Unknown erased memory content code {0} + + + Device sends boot acknowledge + + + Device is not boot enabled + + + Device boot partition 1 is enabled + + + Device boot partition 2 is enabled + + + Device user area is enable for boot + + + Unknown enabled boot partition code {0} + + + There is no access to boot partition + + + There is read/write access to boot partition 1 + + + There is read/write access to boot partition 2 + + + There is read/write access to replay protected memory block + + + There is access to general purpose partition {0} + + + Change of the boot configuration register bits is permanently disabled. + + + Change of the boot configuration register bits is disabled until the next power cycle. + + + Device will boot up in x1 SDR or x4 DDR bus width. + + + Device will boot up in x4 SDR or DDR bus width. + + + Device will boot up in x8 SDR or DDR bus width. + + + Unknown boot condition for bus width with code 3. + + + Device will retain boot conditions after boot operation. + + + Device will reset boot conditions to compatibility mode after boot operation. + + + Device will use single data rate with compatible timings in boot operation. + + + Device will use single data rate with high speed timings in boot operation. + + + Device will use dual data rate in boot operation. + + + Device will use unknown boot mode with code 3. + + + Device will use high capacity erase unit size, timeout and write protect group size definitions. + + + Boot area 1 is not protected + + + Boot area 1 is power on protected + + + Boot area 1 is permanently protected + + + Boot area 2 is not protected + + + Boot area 2 is power on protected + + + Boot area 2 is permanently protected + + + Boot area 2 is permanently write protected. + + + Boot area 1 is permanently write protected. + + + Both boot areas are permanently write protected. + + + Boot area 2 is write protected until next power cycle. + + + Boot area 1 is write protected until next power cycle. + + + Both boot areas are write protected until next power cycle. + + + Permanent write protection of boot areas is disabled. + + + Power cycled write protection of boot areas is disabled. + + + Use of password protection features is permanently disabled. + + + Use of permanent write protection is disabled. + + + Permanent write protection is disabled. + + + Power cycled write protection is disabled. + + + Permanent write protection will be applied to selected group. + + + Power cycled write protection will be applied to selected group. + + + Firmware updates are permanently disabled + + + Device has a {0} KiB replay protected memory block + + + Device supports partitioning features + + + Device can have enhanced technological features in partitions and user data area + + + Device can have extended partitions attribute. + + + Device natively uses 512 byte sectors + + + Device natively uses 4096 byte sectors + + + Device natively uses unknown sector size indicated by code {0} + + + Device is emulating 512 byte sectors + + + Device is using natively sized sectors + + + Device emulates unknown sector size indicated by code {0} + + + Device currently addresses 512 byte sectors + + + Device currently addresses 4096 byte sectors + + + Device currently addresses unknown sector size indicated by code {0} + + + Device's cache is enabled + + + Device has enabled command queuing + + + MultiMediaCard Operation Conditions Register: + + + Device is powering up + + + Device is byte addressed + + + Device is sector addressed + + + Unknown device access mode {0} + + + Device can work with supply 3.5~3.6V + + + Device can work with supply 3.4~3.5V + + + Device can work with supply 3.3~3.4V + + + Device can work with supply 3.2~3.3V + + + Device can work with supply 3.1~3.2V + + + Device can work with supply 2.9~3.0V + + + Device can work with supply 2.8~2.9V + + + Device can work with supply 2.7~2.8V + + + Device can work with supply 2.6~2.7V + + + Device can work with supply 2.5~2.6V + + + Device can work with supply 2.4~2.5V + + + Device can work with supply 2.3~2.4V + + + Device can work with supply 2.2~2.3V + + + Device can work with supply 2.1~2.2V + + + Device can work with supply 2.0~2.1V + + + Device can work with supply 1.65~1.95V + + + Unknown manufacturer ID 0x{0:X2} + + + PCMCIA Device Geometry Tuples: + + + Geometry: + + + Device width: {0} bits + + + Erase block: {0} bytes + + + Read block: {0} bytes + + + Write block: {0} bytes + + + Partition alignment: {0} bytes + + + PCMCIA Manufacturer Identification Tuple: + + + Manufacturer ID: {0} + + + Card ID: 0x{0:X4} + + + PCMCIA Level 1 Version / Product Information Tuple: + + + Card indicates compliance with PC Card Standard Release {0}.{1} + + + No manufacturer information string. + + + No product name string. + + + No additional information. + + + Additional information: + + + Unknown vendor id 0x{0:X4} + + + AACS Volume Identifier in hex follows: + + + AACS Media Serial Number in hex follows: + + + AACS Media Identifier in hex follows: + + + Total number of media key blocks available to transfer {0} + + + AACS Media Key Blocks in hex follows: + + + AACS Data Keys in hex follows: + + + Drive can store 256 LBA Extents + + + Drive cannot store LBA Extents + + + Drive can store {0} LBA Extents + + + LBA Extent {0} starts at LBA {1} and goes for {2} sectors + + + Total number of CPRM Media Key Blocks available to transfer: {0} + + + CPRM Media Key Blocks in hex follows: + + + Disc type declared as CD-DA or CD-ROM + + + Disc type declared as CD-i + + + Disc type declared as CD-ROM XA + + + Disc type is undefined + + + Unknown disc type {0:X2}h + + + Disc is incomplete + + + Disc is finalized + + + Disc is erasable + + + Last session is empty + + + Last session is incomplete + + + Last session is damaged + + + Last session is complete + + + Media was being formatted in the background but it is stopped and incomplete + + + Media is currently being formatted in the background + + + Media background formatting has completed + + + MRW is dirty + + + First track on disc is track {0} + + + Disc has {0} sessions + + + First track in last session is track {0} + + + Last track in last session is track {0} + + + Last session Lead-In address is {0} (as LBA) or {1:X2}:{2:X2}:{3:X2} + + + Last possible Lead-Out address is {0} (as LBA) or {1:X2}:{2:X2}:{3:X2} + + + Disc is defined for unrestricted use + + + Disc is defined for restricted use + + + Disc barcode: {0:X16} + + + Disc application code: {0} + + + OPC values for {0}Kbit/sec.: {1}, {2}, {3}, {4}, {5}, {6} + + + {0} maximum possible tracks on the disc + + + {0} assigned tracks on the disc + + + {0} maximum possible appendable tracks on the disc + + + {0} current appendable tracks on the disc + + + {0} remaining POW replacements + + + {0} remaining POW reallocation map entries + + + {0} remaining POW updates + + + Drive reported a reserved profile number + + + MMC Supported Profiles: + + + Drive supports non-removable changeable media + + + Drive supports rewritable and removable media + + + Drive supports Magneto-Optical media + + + Drive supports optical write-once media + + + Drive supports Advanced Storage - Magneto-Optical + + + Drive supports CD-ROM + + + Drive supports CD-R + + + Drive supports CD-RW + + + Drive supports DVD-ROM + + + Drive supports DVD-R + + + Drive supports DVD-RAM + + + Drive supports restricted overwrite DVD-RW + + + Drive supports sequentially recorded DVD-RW + + + Drive supports sequentially recorded DVD-R DL + + + Drive supports layer jump recorded DVD-R DL + + + Drive supports DVD-RW DL + + + Drive supports DVD-Download + + + Drive supports DVD+RW + + + Drive supports DVD+R + + + Drive supports DDCD-ROM + + + Drive supports DDCD-R + + + Drive supports DDCD-RW + + + Drive supports DVD+RW DL + + + Drive supports DVD+R DL + + + Drive supports BD-ROM + + + Drive supports BD-R SRM + + + Drive supports BD-R RRM + + + Drive supports BD-RE + + + Drive supports HD DVD-ROM + + + Drive supports HD DVD-R + + + Drive supports HD DVD-RAM + + + Drive supports HD DVD-RW + + + Drive supports HD DVD-R DL + + + Drive supports HD DVD-RW DL + + + Drive supports HDBurn CD-ROM + + + Drive supports HDBurn CD-R + + + Drive supports HDBurn CD-RW + + + Drive is not conforming to any profile + + + Drive informs of unknown profile 0x{0:X4} + + + (current) + + + MMC Core Feature: + + + Drive uses an unspecified physical interface + + + Drive uses a SCSI interface + + + Drive uses an ATAPI interface + + + Drive uses an IEEE-1394 interface + + + Drive uses an IEEE-1394A interface + + + Drive uses a Fibre Channel interface + + + Drive uses an IEEE-1394B interface + + + Drive uses a Serial ATAPI interface + + + Drive uses an USB interface + + + Drive uses a vendor unique interface + + + Drive uses an unknown interface with code {0} + + + Drive supports Device Busy events + + + Drive supports EVPD, Page Code and 16-bit Allocation Length as described in SPC-3 + + + MMC Morphing: + + + Drive supports polling and asynchronous GET EVENT STATUS NOTIFICATION + + + Drive supports only polling GET EVENT STATUS NOTIFICATION + + + Drive supports operational change request / notification class events + + + MMC Removable Medium: + + + Drive uses media caddy + + + Drive uses a tray + + + Drive is pop-up + + + Drive is a changer with individually changeable discs + + + Drive is a changer using cartridges + + + Drive uses unknown loading mechanism type {0} + + + Drive can lock media + + + Drive power ups locked + + + Drive can eject media + + + Drive can load media + + + Drive reports Device Busy Class events during medium loading/unloading + + + MMC Write Protect: + + + Drive supports reading/writing the Disc Write Protect PAC on BD-R/-RE media + + + Drive supports writing the Write Inhibit DCB on DVD+RW media + + + Drive supports set/release of PWP status + + + Drive supports the SWPP bit of the Timeout and Protect mode page + + + MMC Random Readable + + + Drive shall report Read/Write Error Recovery mode page + + + {0} bytes per logical block + + + {0} logical blocks per media readable unit + + + Drive claims capability to read all CD formats according to OSTA Multi-Read Specification + + + + MMC CD Read + + + Drive supports the DAP bit in the READ CD and READ CD MSF commands + + + Drive supports C2 Error Pointers + + + Drive can return CD-Text from Lead-In + + + MMC DVD Read + + + Drive can read DVD media + + + Drive can read DVD-R DL from all recording modes + + + Drive can read DVD-RW DL from all recording modes + + + Drive conforms to DVD Multi Drive Read-only Specifications + + + MMC Random Writable: + + + {0} logical blocks per media writable unit + + + Last addressable logical block is {0} + + + MMC Incremental Streaming Writable: + + + Drive supports data block types: + + + Drive claims support to report Track Resources Information + + + Drive supports address mode reservation on the RESERVE TRACK command + + + Drive is capable of zero loss linking + + + Drive supports media that require erasing before writing + + + MMC Formattable: + + + Drive can format media into logical blocks + + + Drive can format BD-RE with no spares allocated + + + Drive can expand the spare area on a formatted BD-RE disc + + + Drive can format BD-RE discs with quick certification + + + Drive can format BD-RE discs with full certification + + + Drive can fast re-format BD-RE discs + + + Drive can format BD-R discs with RRM format + + + MMC Hardware Defect Management: + + + Drive shall be able to provide a defect-free contiguous address space + + + Drive can return Spare Area Information + + + MMC Write Once + + + Drive shall have the ability to overwrite logical blocks only in fixed sets at a time + + + Drive can write High-Speed CD-RW + + + Drive can read and write CD-MRW and DVD+MRW + + + Drive can read and write DVD+MRW + + + Drive and read DVD+MRW and read and write CD-MRW + + + Drive can read and write CD-MRW + + + Drive can read CD-MRW and DVD+MRW + + + Drive can read CD-MRW + + + MMC Enhanced Defect Reporting Feature: + + + Drive supports DRT-DM mode + + + Drive supports Persistent-DM mode + + + Drive has {0} DBI cache zones + + + Drive has {0} DBI entries + + + Drive can read and write DVD+RW + + + Drive supports only the read compatibility stop + + + Drive supports both forms of background format stopping + + + Drive can do a quick start formatting + + + Drive can read DVD+RW + + + Drive can read and write DVD+R + + + Drive can read DVD+R + + + MMC Rigid Restricted Overwrite + + + Drive supports the BLANK command + + + Drive supports writing on an intermediate state session and quick formatting + + + Drive can read Defect Status data recorded on the medium + + + Drive can generate Defect Status data during formatting + + + Drive can write CDs in Track at Once Mode: + + + Drive can write user provided data in the R-W subchannels + + + Drive accepts RAW R-W subchannel data + + + Drive accepts Packed R-W subchannel data + + + Drive can overwrite a TAO track with another in CD-RWs + + + Drive can do a test writing + + + Drive supports zero loss linking + + + Drive can write CDs in Session at Once Mode: + + + Drive can write CDs in raw Mode: + + + Drive can write CDs in Session at Once and in Raw Modes: + + + Drive can write multi-session CDs in raw mode + + + Drive supports a maximum of {0} bytes in a single cue sheet + + + Drive supports writing DVD-R, DVD-RW and DVD-R DL + + + Drive supports writing DVD-R and DVD-R DL + + + Drive supports writing DVD-R and DVD-RW + + + Drive supports writing DVD-R + + + Drive can read DDCDs + + + Drive supports writing DDCD-R + + + Drive supports writing DDCD-RW + + + Drive supports quick formatting + + + MMC Layer Jump Recording: + + + Current media has a {0} bytes link available + + + Drive can stop a long immediate operation + + + Drive can write CD-RW + + + Drive supports CD-RW subtypes + + + Drive can write BD-R on Pseudo-OVerwrite SRM mode + + + Drive can read and write DVD+RW DL + + + Drive can read DVD+RW DL + + + Drive can read and write DVD+R DL + + + Drive can read DVD+R DL + + + MMC BD Read + + + Drive can read BD-ROM pre-1.0 + + + Drive can read BD-ROM Ver.1 + + + Drive can read BD-R pre-1.0 + + + Drive can read BD-R Ver.1 + + + Drive can read BD-RE pre-1.0 + + + Drive can read BD-RE Ver.1 + + + Drive can read BD-RE Ver.2 + + + Drive can read BD's Burst Cutting Area + + + MMC BD Write + + + Drive can write BD-R pre-1.0 + + + Drive can write BD-R Ver.1 + + + Drive can write BD-RE pre-1.0 + + + Drive can write BD-RE Ver.1 + + + Drive can write BD-RE Ver.2 + + + Drive supports write without verify requirement + + + Drive is able to detect and report defective writable unit and behave accordingly + + + Drive can read HD DVD-ROM, HD DVD-RW, HD DVD-R and HD DVD-RAM + + + Drive can read HD DVD-ROM, HD DVD-RW and HD DVD-R + + + Drive can read HD DVD-ROM, HD DVD-RW and HD DVD-RAM + + + Drive can read HD DVD-ROM and HD DVD-RW + + + Drive can write HD DVD-RW, HD DVD-R and HD DVD-RAM + + + Drive can write HD DVD-RW and HD DVD-R + + + Drive can write HD DVD-RW and HD DVD-RAM + + + Drive can write HD DVD-RW + + + Drive is able to access Hybrid discs + + + Drive is able to maintain the online format layer through reset and power cycling + + + Drive is able to perform host and drive directed power management + + + Drive supports S.M.A.R.T. + + + Drive supports the Informational Exceptions Control mode page 1Ch + + + MMC Embedded Changer: + + + Drive can change disc side + + + Drive is able to report slots contents after a reset or change + + + Drive has {0} slots + + + Drive has an analogue audio output + + + Drive supports the SCAN command + + + Drive is able to mute channels separately + + + Drive supports separate volume per channel + + + Drive has {0} volume levels + + + Drive supports Microcode Upgrade + + + Drive supports validating the 5-bit Mode of the READ BUFFER and WRITE BUFFER commands + + + Drive supports Timeout & Protect mode page 1Dh + + + Drive supports the Group3 in Timeout & Protect mode page 1Dh + + + Drive has {0} increase of Group 3 time unit + + + Drive supports DVD CSS/CPPM version {0} and current disc is encrypted + + + Drive supports DVD CSS/CPPM version {0} + + + MMC Real Time Streaming: + + + Drive supports Set Minimum Performance with the SET STREAMING command + + + Drive supports the block bit in the READ BUFFER CAPACITY command + + + Drive supports the SET CD SPEED command + + + Drive supports the Write Speed Performance Descriptor Blocks in the MMC mode page 2Ah + + + Drive supports the Write Speed data of GET PERFORMANCE and the WRC field of SET STREAMING + + + Drive supports stream recording + + + Drive is able to read media serial number + + + Drive supports DCB {0:X8}h + + + Drive supports DVD CPRM version {0} and current disc is or can be encrypted + + + Drive supports DVD CPRM version {0} + + + Drive firmware is dated {0} + + + Drive supports AACS version {0} and current disc is encrypted + + + Drive supports AACS version {0} + + + Drive supports reading the Drive Certificate + + + Drive supports reading Media Key Block of CPRM + + + Drive supports writing with bus encryption + + + Drive supports bus encryption + + + Drive supports generating the binding nonce + + + {0} media blocks are required for the binding nonce + + + Drive supports {0} AGIDs concurrently + + + Maximum {0} scramble extent information entries + + + Drive and currently inserted media support VCPS + + + Drive supports VCPS + + + Drive and currently inserted media support SecurDisc + + + Drive supports SecurDisc + + + Drive supports the Trusted Computing Group Optical Security Subsystem Class + + + Current media is initialized with TCG OSSC + + + Drive supports PSA updates on write-once media + + + Drive supports linked OSPBs + + + Drive will only record on the OSSC Disc Format + + + Profile {0}: {1} + + + {0} format layers recognized + + + Layer {0} is of type Blu-ray + + + This is the default layer. + + + This is the layer actually in use. + + + Layer {0} is of type CD + + + Layer {0} is of type DVD + + + Layer {0} is of type HD DVD + + + Layer {0} is of unknown type 0x{1:X4} + + + Writing inhibited by media specific reason + + + Cartridge sets write protection + + + Media surface sets write protection + + + Software write protection is set until power down + + + Reserved4 = 0x{0:X2} + + + Reserved5 = 0x{0:X2} + + + Reserved6 = 0x{0:X2} + + + SCSI Control mode page: + + + Parameters can be saved + + + If set, target shall report log exception conditions + + + Tagged queuing is disabled + + + Extended Contingent Allegiance is enabled + + + Target may issue an asynchronous event notification upon completing its initialization + + + Target may issue an asynchronous event notification instead of a unit attention condition + + + Target may issue an asynchronous event notification instead of a deferred error + + + Global logging target save disabled + + + CHECK CONDITION should be reported rather than a long busy condition + + + Tasks aborted by other initiator's actions should be terminated with TASK ABORTED + + + All tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate + + + Device shall return descriptor format sense data when returning sense data in the same transactions as a CHECK CONDITION + + + LOGICAL BLOCK APPLICATION TAG should not be modified + + + Protector information checking is disabled + + + No unit attention on release + + + Application Tag mode page is enabled + + + Abort any write command without protection information + + + Supports block lengths and protection information + + + The logical unit maintains one task set for all nexuses + + + The logical unit maintains separate task sets for each nexus + + + Unknown Task set type {0} + + + Commands should be sent strictly ordered + + + Commands can be reordered in any manner + + + Unknown Queue Algorithm Modifier {0} + + + If ACA is established, the task set commands shall resume after it is cleared, otherwise they shall terminate with CHECK CONDITION + + + All the affected commands in the task set shall be aborted when CHECK CONDITION is returned + + + Affected commands in the task set belonging with the CHECK CONDITION nexus shall be aborted + + + Reserved QErr value 2 is set + + + LUN shall clear unit attention condition reported in the same nexus + + + LUN shall not clear unit attention condition reported in the same nexus + + + LUN shall not clear unit attention condition reported in the same nexus and shall establish a unit attention condition for the initiator + + + Reserved UA_INTLCK_CTRL value 1 is set + + + On medium insertion, it shall be loaded for full access + + + On medium insertion, it shall be loaded for auxiliary memory access only + + + On medium insertion, it shall not be loaded + + + Reserved autoload mode {0} set + + + {0} ms before attempting asynchronous event notifications after initialization + + + There is no limit on the maximum time that is allowed to remain busy + + + A maximum of {0} ms are allowed to remain busy + + + {0} seconds to complete extended self-test + + + SCSI Control extension page: + + + Timestamp can be initialized by methods outside of the SCSI standards + + + Timestamp can be initialized by methods outside of the SCSI standards, but SCSI's SET TIMESTAMP shall take precedence over them + + + Implicit Asymmetric Logical Unit Access is enabled + + + Initial priority is {0} + + + Device will not degrade performance to extend its life + + + Maximum sense data would be {0} bytes + + + SCSI Medium types supported page: + + + Supported medium type one: {0} + + + Supported medium type two: {0} + + + Supported medium type three: {0} + + + Supported medium type four: {0} + + + SCSI CD-ROM parameters page: + + + Drive will remain in track hold state a vendor-specified time after a seek or read + + + Drive will remain in track hold state 125 ms after a seek or read + + + Drive will remain in track hold state 250 ms after a seek or read + + + Drive will remain in track hold state 500 ms after a seek or read + + + Drive will remain in track hold state 1 second after a seek or read + + + Drive will remain in track hold state 2 seconds after a seek or read + + + Drive will remain in track hold state 4 seconds after a seek or read + + + Drive will remain in track hold state 8 seconds after a seek or read + + + Drive will remain in track hold state 16 seconds after a seek or read + + + Drive will remain in track hold state 32 seconds after a seek or read + + + Drive will remain in track hold state 1 minute after a seek or read + + + Drive will remain in track hold state 2 minutes after a seek or read + + + Drive will remain in track hold state 4 minutes after a seek or read + + + Drive will remain in track hold state 8 minutes after a seek or read + + + Drive will remain in track hold state 16 minutes after a seek or read + + + Drive will remain in track hold state 32 minutes after a seek or read + + + Each minute has {0} seconds + + + Each second has {0} frames + + + SCSI CD-ROM audio control parameters page: + + + Drive will return from playback command immediately + + + Drive will return from playback command when playback ends + + + Drive will stop playback on track end + + + There are {0} blocks per each second of audio + + + Output port 0 has channels + + + muted + + + at maximum volume + + + at volume {0} + + + Output port 1 has channels + + + Output port 2 has channels + + + Output port 3 has channels + + + SCSI Data compression page: + + + Drive supports data compression + + + Data compression is enabled with + + + IBM ALDC with 512 byte buffer + + + IBM ALDC with 1024 byte buffer + + + IBM ALDC with 2048 byte buffer + + + IBM IDRC + + + DCLZ + + + an unregistered compression algorithm + + + an unknown algorithm coded {0} + + + Data decompression is enabled + + + Last data read was uncompressed + + + Last data read was compressed with + + + Report exception on compression is set to {0} + + + Drive does not support data compression + + + SCSI Drive Operation Mode page: + + + Verifying after writing is disabled + + + Drive will abort when a writing error is detected + + + Drive has two LUNs with rewritable being + + + SCSI Power Consumption page: + + + Device power consumption is dictated by identifier {0} of Power Consumption VPD + + + Device is in highest relative power consumption level + + + Device is in intermediate relative power consumption level + + + Device is in lowest relative power consumption level + + + SCSI Removable Block Access Capabilities page: + + + Drive can be used as a system floppy device + + + Drive supports reporting progress of format + + + Drive is a Non-CD Optical Device + + + Device is a dual device supporting CD and Non-CD Optical + + + Drive supports {0} LUNs + + + SCSI Informational exceptions control page: + + + Informational exceptions are disabled + + + Informational exceptions are enabled + + + No reporting of informational exception condition + + + Asynchronous event reporting of informational exceptions + + + Generate unit attention on informational exceptions + + + Conditionally generate recovered error on informational exceptions + + + Unconditionally generate recovered error on informational exceptions + + + Generate no sense on informational exceptions + + + Only report informational exception condition on request + + + Unknown method of reporting {0} + + + Informational exceptions reporting should not affect drive performance + + + A test informational exception will raise on next timer + + + Drive shall log informational exception conditions + + + Timer interval is vendor-specific + + + Timer interval is {0} ms + + + Informational exception conditions will be reported a maximum of {0} times + + + Warning reporting is enabled + + + Background functions are enabled + + + Drive will report background self-test errors + + + SCSI Background Control page: + + + Background scans will be halted if log is full + + + Background scans will only be logged if they require intervention + + + Background medium scans are enabled + + + Background pre-scans are enabled + + + {0} hours shall be between the start of a background scan operation and the next + + + Background pre-scan operations can take a maximum of {0} hours + + + At least {0} ms must be idle before resuming a suspended background scan operation + + + At most {0} ms must be before suspending a background scan operation and processing received commands + + + SCSI Timer & Protect page: + + + Drive is disabled until power is cycled + + + Drive is software write-protected until powered down + + + Drive will remain in same status a vendor-specified time after a seek, read or write operation + + + Drive will remain in same status 125 ms after a seek, read or write operation + + + Drive will remain in same status 250 ms after a seek, read or write operation + + + Drive will remain in same status 500 ms after a seek, read or write operation + + + Drive will remain in same status 1 second after a seek, read or write operation + + + Drive will remain in same status 2 seconds after a seek, read or write operation + + + Drive will remain in same status 4 seconds after a seek, read or write operation + + + Drive will remain in same status 8 seconds after a seek, read or write operation + + + Drive will remain in same status 16 seconds after a seek, read or write operation + + + Drive will remain in same status 32 seconds after a seek, read or write operation + + + Drive will remain in same status 1 minute after a seek, read or write operation + + + Drive will remain in same status 2 minutes after a seek, read or write operation + + + Drive will remain in same status 4 minutes after a seek, read or write operation + + + Drive will remain in same status 8 minutes after a seek, read or write operation + + + Drive will remain in same status 16 minutes after a seek, read or write operation + + + Drive will remain in same status 32 minutes after a seek, read or write operation + + + SCSI Medium Configuration Mode Page: + + + Drive is operating in WORM mode + + + Drive does not allow any logical blocks to be overwritten + + + Drive allows a tape header to be overwritten + + + Drive allows all format labels to be overwritten + + + Unknown WORM mode label restrictions code {0} + + + SCSI Read-write error recovery page: + + + Automatic write reallocation is enabled + + + Automatic read reallocation is enabled + + + Data not recovered within limits shall be transferred back before a CHECK CONDITION + + + Drive will transfer the entire requested length without delaying to perform error recovery + + + Drive will use the most expedient form of error recovery first + + + Drive shall report recovered errors + + + Transfer will be terminated upon error detection + + + Error correction is disabled + + + Drive will repeat read operations {0} times + + + Drive will repeat write operations {0} times + + + Drive will employ a maximum of {0} ms to recover data + + + Logical block provisioning error reporting is enabled + + + SCSI Read error recovery page for MultiMedia Devices: + + + All available recovery procedures will be used. + + + Only retries and CIRC are used. + + + Only retries are used. + + + Recovered errors will not be reported. + + + Recovered errors will be reported. + + + Recovered errors will be reported and aborted with CHECK CONDITION. + + + Unrecovered ECC errors will return CHECK CONDITION. + + + Unrecovered CIRC errors will return CHECK CONDITION. + + + Unrecovered ECC errors will not abort the transfer. + + + Unrecovered CIRC errors will not abort the transfer. + + + Unrecovered ECC errors will return CHECK CONDITION and the uncorrected data. + + + Unrecovered CIRC errors will return CHECK CONDITION and the uncorrected data. + + + Unknown recovery parameter 0x{0:X2} + + + SCSI CD-ROM capabilities page: + + + Drive can play audio + + + Drive can read sectors in Mode 2 Form 1 format + + + Drive can read sectors in Mode 2 Form 2 format + + + Drive supports multi-session discs and/or Photo-CD + + + Drive can read digital audio + + + Drive can continue from streaming loss + + + Drive can read uncorrected and interleaved R-W subchannels + + + Drive can read, deinterleave and correct R-W subchannels + + + Drive supports C2 pointers + + + Drive can read Media Catalogue Number + + + Drive can read ISRC + + + Drive uses media caddy + + + Drive uses a tray + + + Drive is pop-up + + + Drive is a changer with individually changeable discs + + + Drive is a changer using cartridges + + + Drive uses unknown loading mechanism type {0} + + + Drive can lock media + + + Drive power ups locked + + + Drive is locked, media cannot be ejected or inserted + + + Drive is not locked, media can be ejected and inserted + + + Drive is locked, media cannot be ejected, but if empty, can be inserted + + + Drive can eject media + + + Each channel can be muted independently + + + Each channel's volume can be controlled independently + + + Drive supports {0} volume levels + + + Drive has {0} Kbyte of buffer + + + Drive's maximum reading speed is {0} Kbyte/sec. + + + Drive's current reading speed is {0} Kbyte/sec. + + + Drive can read and write CD-R + + + Drive can read CD-R + + + Drive supports reading CD-R packet media + + + Drive can read and write CD-RW + + + Drive can read CD-RW + + + Drive can read DVD-ROM + + + Drive can read and write DVD-R + + + Drive can read DVD-R + + + Drive can read and write DVD-RAM + + + Drive can read DVD-RAM + + + Drive can deliver a composite audio and video data stream + + + Drive supports IEC-958 digital output on port 1 + + + Drive supports IEC-958 digital output on port 2 + + + Drive contains a changer that can report the exact contents of the slots + + + Drive's current writing speed is {0} Kbyte/sec. in CLV mode + + + Drive's current writing speed is {0} Kbyte/sec. in pure CAV mode + + + Drive's maximum writing speed is {0} Kbyte/sec. + + + Drive's current writing speed is {0} Kbyte/sec. + + + Drive supports writing at {0} Kbyte/sec. in CLV mode + + + Drive supports writing at {0} Kbyte/sec. in pure CAV mode + + + Drive supports test writing + + + Drive can read barcode + + + Drive can read both sides of a disc + + + Drive can read raw R-W subchannel from the Lead-In + + + Drive supports DVD CSS and/or DVD CPPM + + + Drive supports buffer under-run free recording + + + IBM Behaviour Configuration Mode Page: + + + Fence behaviour is normal + + + Panic fence behaviour is enabled + + + Unknown fence behaviour code {0} + + + Cleaning behaviour is normal + + + Drive will periodically request cleaning + + + Unknown cleaning behaviour code {0} + + + WORM emulation is disabled + + + WORM emulation is enabled + + + Unknown WORM emulation code {0} + + + Uses 35-bytes sense data + + + Uses 96-bytes sense data + + + Unknown sense data behaviour code {0} + + + Drive will set CHECK CONDITION when cleaning is needed + + + No deferred error will be reported to a rewind command + + + Drive will set CHECK CONDITION when the criteria for Dead Media is met + + + Drive will not accept downlevel firmware via an FMR tape + + + Drive will eject cleaning cartridges on error + + + Drive will eject firmware cartridges on error + + + Drive will eject data cartridges on error + + + SCSI Disconnect-Reconnect mode page: + + + {0} ratio of buffer that shall be full prior to attempting a reselection + + + {0} ratio of buffer that shall be empty prior to attempting a reselection + + + {0} µs maximum permitted to assert BSY without a REQ/ACK handshake + + + {0} µs maximum permitted wait after releasing the bus before attempting reselection + + + {0} µs allowed to use the bus before disconnecting, if granted the privilege and not restricted + + + {0} bytes maximum can be transferred before disconnecting + + + {0} bytes maximum can be transferred for a command along with the disconnect command + + + Target shall not transfer data for a command during the same interconnect tenancy + + + Target is allowed to re-order the data transfer + + + Data transfer disconnect control is not used + + + All data for a command shall be transferred within a single interconnect tenancy + + + All data and the response for a command shall be transferred within a single interconnect tenancy + + + Reserved data transfer disconnect control value {0} + + + HP Serial Number Override Mode Page: + + + Serial number is the manufacturer's default value + + + Serial number is not the manufacturer's default value + + + Serial number: {0} + + + HP Device Time Mode Page: + + + Drive has been powered up {0} times + + + Drive has been powered up since {0} seconds ago this time + + + Drive has been powered up a total of {0} seconds + + + Drive's date/time is: {0} + + + Drive's time is UTC + + + Drive's time is synchronized with a NTP source + + + Library time is {0} + + + HP Extended Reset Mode Page: + + + Normal reset behaviour + + + Drive will flush and position itself on a LUN or target reset + + + Drive will maintain position on a LUN or target reset + + + IBM LEOT Mode Page: + + + {0} wraps + + + Fujitsu Verify Control Page: + + + Audio/Visual data support mode is applied + + + Test write operation is restricted during read or write operations. + + + Always apply the verify operation + + + Never apply the verify operation + + + Apply the verify operation depending on the condition + + + The device type that would be provided in the INQUIRY response is {0} + + + HP CD-ROM Emulation/Disaster Recovery Mode Page: + + + Drive is emulating a CD-ROM drive + + + Drive is not emulating a CD-ROM drive + + + Drive will not exit emulation automatically + + + SCSI Format device page: + + + {0} tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors + + + {0} sectors per zone that shall be reserved for defect handling + + + {0} tracks per zone that shall be reserved for defect handling + + + {0} tracks per LUN that shall be reserved for defect handling + + + {0} physical sectors per track + + + {0} Bytes per physical sector + + + Target-dependent interleave value is {0} + + + {0} sectors between last block of one track and first block of the next + + + {0} sectors between last block of a cylinder and first block of the next one + + + Drive supports soft-sectoring format + + + Drive supports hard-sectoring format + + + Drive media is removable + + + Sector addressing is progressively incremented in one surface before going to the next + + + Sector addressing is progressively incremented in one cylinder before going to the next + + + SCSI Rigid disk drive geometry page: + + + {0} heads + + + {0} cylinders + + + Write pre-compensation starts at cylinder {0} + + + Write current reduction starts at cylinder {0} + + + Drive steps in {0} ns + + + Heads park in cylinder {0} + + + Medium rotates at {0} rpm + + + Spindle synchronization is disabled or unsupported + + + Target operates as a synchronized-spindle slave + + + Target operates as a synchronized-spindle master + + + Target operates as a synchronized-spindle master control + + + SCSI Flexible disk page: + + + Transfer rate: {0} kbit/s + + + {0} sectors per track + + + {0} bytes per sector + + + Drive steps in {0} μs + + + Each step pulse is {0} ms + + + Heads settles in {0} μs + + + Target shall wait {0} seconds before attempting to access the medium after motor on is asserted + + + Target shall wait {0} seconds after drive is ready before aborting medium access attempts + + + Target shall wait {0} seconds before releasing the motor on signal after becoming idle + + + Target shall never release the motor on signal + + + There is a drive ready signal + + + Sectors start at 1 + + + The motor on signal shall remain released + + + Drive needs to do {0} step pulses per cylinder + + + Write pre-compensation is {0} + + + Head takes {0} ms to load + + + Head takes {0} ms to unload + + + Pin 34 is unconnected + + + Pin 34 indicates drive is ready when active high + + + Pin 34 indicates drive is ready when active low + + + Pin 34 indicates disk has changed when active high + + + Pin 34 indicates disk has changed when active low + + + Pin 34 indicates unknown function {0} when active high + + + Pin 34 indicates unknown function {0} when active low + + + Pin 4 is unconnected + + + Pin 4 indicates drive is in use when active high + + + Pin 4 indicates drive is in use when active low + + + Pin 4 indicates eject when active high + + + Pin 4 indicates eject when active low + + + Pin 4 indicates head load when active high + + + Pin 4 indicates head load when active low + + + Pin 4 indicates unknown function {0} when active high + + + Pin 4 indicates unknown function {0} when active low + + + Pin 2 is unconnected + + + Pin 2 indicates unknown function {0} when active high + + + Pin 2 indicates unknown function {0} when active low + + + Pin 1 is unconnected + + + Pin 1 indicates disk change reset when active high + + + Pin 1 indicates disk change reset when active low + + + Pin 1 indicates unknown function {0} when active high + + + Pin 1 indicates unknown function {0} when active low + + + SCSI optical memory: + + + On reading an updated block drive will return RECOVERED ERROR + + + SCSI Verify error recovery page: + + + Drive will repeat verify operations {0} times + + + SCSI Verify error recovery page for MultiMedia Devices: + + + SCSI Caching mode page: + + + Read-cache is enabled + + + Write-cache is enabled + + + Drive does not distinguish between cached read data + + + Data put by READ commands should be evicted from cache sooner than data put in read cache by other means + + + Data put by READ commands should not be evicted if there is data cached by other means that can be evicted + + + Unknown demand read retention priority value {0} + + + Drive does not distinguish between cached write data + + + Data put by WRITE commands should be evicted from cache sooner than data put in write cache by other means + + + Data put by WRITE commands should not be evicted if there is data cached by other means that can be evicted + + + Unknown demand write retention priority value {0} + + + Read-ahead is disabled + + + Pre-fetch values indicate a block multiplier + + + No pre-fetch will be done + + + Pre-fetch will be done for READ commands of {0} blocks or less + + + At least {0} blocks will be always pre-fetched + + + A maximum of {0} blocks will be pre-fetched + + + A maximum of {0} blocks will be pre-fetched even if it is commanded to pre-fetch more + + + Device should use number of cache segments or cache segment size for caching + + + Pre-fetch should be aborted upon receiving a new command + + + Caching analysis is permitted + + + Pre-fetch can continue across discontinuities (such as cylinders or tracks) + + + Drive should not reorder the sequence of write commands to be faster + + + Drive cache segments should be {0} blocks long + + + Drive cache segments should be {0} bytes long + + + Drive should have {0} cache segments + + + Drive shall allocate {0} bytes to buffer even when all cached data cannot be evicted + + + Non-Volatile cache is disabled + + + SCSI XOR control mode page: + + + XOR operations are disabled + + + Drive accepts a maximum of {0} blocks in a single XOR WRITE command + + + Drive accepts a maximum of {0} blocks in a REGENERATE command + + + Drive accepts a maximum of {0} blocks in a READ command during rebuild + + + Drive needs a minimum of {0} ms between READ commands during rebuild + + + SCSI Device configuration page: + + + Active format: {0} + + + Active partition: {0} + + + Write buffer shall have a full ratio of {0} before being flushed to medium + + + Read buffer shall have an empty ratio of {0} before more data is read from medium + + + Drive will delay {0} ms before buffered data is forcefully written to the medium even before buffer is full + + + Drive supports recovering data from buffer + + + Recovered buffer data comes in LIFO order + + + Recovered buffer data comes in FIFO order + + + Medium supports block IDs + + + Drive reports setmarks + + + Drive will pre-read until buffer is full + + + Drive will pre-read until one filemark is detected + + + Drive will pre-read until two filemark is detected + + + Drive will pre-read until three filemark is detected + + + Drive reports early warnings + + + Drive will synchronize buffer to medium on early warnings + + + Inter-block gap is long enough to support update in place + + + Inter-block gap is {0} times the device's defined gap size + + + Inter-block gap is unknown value {0} + + + Drive generates end-of-data + + + Drive does not use compression + + + Drive uses default compression + + + Drive uses unknown compression {0} + + + Software write protect is enabled + + + Associated write protect is enabled + + + Persistent write protect is enabled + + + Permanent write protect is enabled + + + Drive operates using explicit address mode + + + Drive operates using implicit address mode + + + Drive shall position to beginning of default data partition on reset + + + Drive shall maintain its position on reset + + + Drive will do nothing on WORM tampered medium + + + Drive will return CHECK CONDITION on WORM tampered medium + + + Drive will only respond to commands if it has received a reservation + + + SCSI medium partition page: + + + {0} maximum additional partitions + + + {0} additional partitions defined + + + Partitions are fixed under device definitions + + + Number of partitions can be defined but their size is defined by the device + + + Number and size of partitions can be manually defined + + + Partition parameters will not be applied until a FORMAT MEDIUM command is received + + + Device may erase any or all partitions on MODE SELECT for partitioning + + + Device shall erase all partitions on MODE SELECT for partitioning + + + Device shall not erase any partition on MODE SELECT for partitioning + + + Device shall erase all partitions differing on size on MODE SELECT for partitioning + + + Partitions are defined in bytes + + + bytes + + + Partitions are defined in kilobytes + + + kilobytes + + + Partitions are defined in megabytes + + + megabytes + + + Partitions are defined in units of {0} bytes + + + units of {0} bytes + + + Unknown partition size unit code {0} + + + units + + + Device is capable of recognizing both medium partitions and format + + + Device is capable of recognizing medium format + + + Device is capable of recognizing medium partitions + + + Device is not capable of recognizing neither medium partitions nor format + + + Unknown medium recognition code {0} + + + Medium has defined {0} partitions + + + Device recognizes one single partition spanning whole medium + + + Partition {0} runs for rest of medium + + + Partition {0} is {1} {2} long + + + SCSI medium partition page (extra): + + + Partition {0} is {1} units long + + + Certance Drive Capabilities Control Mode Page: + + + Operating systems support is standard LTO + + + Operating systems support is unknown code {0} + + + Factory test code is disabled + + + Factory test code 1 is disabled + + + Factory test code 2 is disabled + + + Unknown factory test code {0} + + + Power-On Self-Test is enabled + + + Power-On Self-Test is disabled + + + Unknown Power-On Self-Test code {0} + + + Compression is controlled using mode pages 0Fh and 10h + + + Compression is enabled and not controllable + + + Compression is disabled and not controllable + + + Unknown compression control code {0} + + + SCSI UNLOAD command will not eject the cartridge + + + How should tapes be unloaded in a power cycle, tape incompatibility, firmware download or cleaning end: + + + Tape will stay threaded at beginning + + + Tape will be unthreaded + + + Tape will be unthreaded and unloaded + + + Data tapes will be threaded at beginning, rest will be unloaded + + + Unknown auto unload code {0} + + + Certance Interface Control Mode Page: + + + Library interface will operate at 9600 baud on next reset + + + Library interface will operate at 19200 baud on next reset + + + Library interface will operate at 38400 baud on next reset + + + Library interface will operate at 57600 baud on next reset + + + Library interface will operate at 115200 baud on next reset + + + Unknown library interface baud rate code {0} + + + Library interface transmits 2 stop bits per byte + + + Library interface transmits 1 stop bits per byte + + + Port A uses Parallel SCSI Ultra-160 interface + + + Drive will respond to SCSI ID {0} on Port A enabling + + + Drive jumpers choose SCSI ID {0} + + + SCSI port is enabled + + + SCSI port is disabled + + + SCSI port will be enabled on next power up + + + SCSI port will be disabled on next power up + + + IBM Vendor-Specific Control Mode Page: + + + Vendor-specific mode control: {0} + + + Vendor-specific velocity setting: {0} + + + Drive supports encryption + + + Drive has encryption enabled + + + ECMA-54: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on One Side + + + ECMA-59 & ANSI X3.121-1984: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on Both Sides + + + ECMA-69: 200 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides + + + ECMA-66: 130 mm Flexible Disk Cartridge using Two-Frequency Recording at 7958 ftprad on One Side + + + ECMA-70 & ANSI X3.125-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 1.9 Tracks per mm + + + ECMA-78 & ANSI X3.126-1986: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 3.8 Tracks per mm + + + ECMA-99 & ISO 8630-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides; 3.8 Tracks per mm + + + ECMA-100 & ANSI X3.137: 90 mm Flexible Disk Cartridge using MFM Recording at 7859 ftprad on Both Sides; 5.3 Tracks per mm + + + ANSI X3.73-1980: 200 mm, 6631 ftprad, 1.9 Tracks per mm, 1 side + + + ANSI X3.73-1980: 200 mm, 6631 ftprad, 1.9 Tracks per mm, 2 sides + + + ANSI X3.80-1980: 130 mm, 3979 ftprad, 1.9 Tracks per mm, 1 side + + + 3.5-inch, 135 tpi, 12362 bits/radian, double-sided MFM (aka 1.25Mb) + + + 3.5-inch, 135 tpi, 15916 bits/radian, double-sided MFM (aka 1.44Mb) + + + a Read-only optical + + + a Write-once Read-many optical + + + a Erasable optical + + + a combination of read-only and write-once optical + + + a direct-overwrite optical + + + a Sony Hi-MD disc + + + SCSI Mode Sense Header: + + + Medium is {0} + + + Medium is write protected + + + Drive supports DPO and FUA bits + + + 7958 flux transitions per radian + + + 13262 flux transitions per radian + + + 15916 flux transitions per radian + + + with unknown density code 0x{0:X2} + + + All remaining blocks have {0} and are {1} bytes each + + + {0} blocks have {1} and are {2} bytes each + + + All remaining blocks are {0} bytes each + + + {0} blocks are {1} bytes each + + + Device writes directly to media + + + Device uses a write cache + + + Device uses a write cache but doesn't return until cache is flushed + + + Unknown buffered mode code 0x{0:X2} + + + Device uses default speed + + + Device uses speed {0} + + + undefined + + + 6.3 mm tape with 12 tracks at 394 ftpmm or DC-9250 + + + 6.3 mm tape with 24 tracks at 394 ftpmm or MLR1-26GBSL + + + LTO Ultrium WORM or cleaning cartridge + + + LTO Ultrium + + + LTO Ultrium-2 + + + DC-2900SL + + + MLR1-26GB or DDS-3 + + + DC-9200 or DDS-4 + + + DAT-72 + + + LTO Ultrium-3 + + + LTO Ultrium-3 WORM + + + DDS cleaning cartridge + + + SLR-32 + + + SLRtape-50 + + + LTO Ultrium-4 + + + LTO Ultrium-4 WORM + + + SLRtape-50 SL + + + SLR-32SL + + + SLR-5 + + + SLR-5SL + + + LTO Ultrium-5 + + + LTO Ultrium-5 WORM + + + SLRtape-7 + + + SLRtape-7 SL + + + SLRtape-24 + + + SLRtape-24 SL + + + LTO Ultrium-6 + + + LTO Ultrium-6 WORM + + + SLRtape-140 + + + SLRtape-40 + + + SLRtape-60 or SLRtape-75 + + + SLRtape-100 + + + SLR-40, SLR-60 or SLR-100 + + + LTO Ultrium-7 + + + LTO Ultrium-7 WORM + + + Exatape 15m, IBM MagStar or VXA + + + CompactTape I, Exatape 28m, CompactTape II, VXA-2 or VXA-3 + + + Exatape 54m or DLTtape III + + + Exatape 80m or DLTtape IIIxt + + + Exatape 106m, DLTtape IV or Travan 5 + + + Exatape 160m XL or Super DLTtape I + + + Super DLTtape II + + + VStape I + + + DLTtape S4 + + + Travan 7 + + + Exatape 22m + + + Exatape 40m + + + Exatape 76m + + + Exatape 112m + + + Exatape 22m AME + + + Exatape 170m + + + Exatape 125m + + + Exatape 45m + + + Exatape 225m + + + Exatape 150m + + + Exatape 75m + + + unknown medium type 0x{0:X2} + + + ECMA-62 & ANSI X3.22-1983: 12.7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZI, 32 cpmm + + + ECMA-62 & ANSI X3.39-1986: 12.7 mm 9-Track Magnetic Tape, 126 ftpmm, Phase Encoding, 63 cpmm + + + ECMA-62 & ANSI X3.54-1986: 12.7 mm 9-Track Magnetic Tape, 356 ftpmm, NRZI, 245 cpmm GCR + + + ECMA-79 & ANSI X3.116-1986: 6.30 mm Magnetic Tape Cartridge, 252 ftpmm, MFM + + + Draft ECMA & ANSI X3B5/87-099: 12.7 mm 18-Track Magnetic Tape Cartridge, 1944 ftpmm, IFM, GCR (IBM 3480, 3490, 3490E) + + + ECMA-46 & ANSI X3.56-1986: 6.30 mm Magnetic Tape Cartridge, Phase Encoding, 63 bpmm + + + ECMA-98: 6.30 mm Magnetic Tape Cartridge, NRZI, 394 ftpmm + + + ANSI X3.136-1986: 6.3 mm 4 or 9-Track Magnetic Tape Cartridge, 315 bpmm, GCR (QIC-24) + + + ANSI X3.157-1987: 12.7 mm 9-Track Magnetic Tape, 126 bpmm, Phase Encoding + + + ANSI X3.158-1987: 3.81 mm 4-Track Magnetic Tape Cassette, 315 bpmm, GCR + + + ANSI X3B5/86-199: 12.7 mm 22-Track Magnetic Tape Cartridge, 262 bpmm, MFM + + + HI-TC1: 12.7 mm 24-Track Magnetic Tape Cartridge, 500 bpmm, GCR + + + HI-TC2: 12.7 mm 24-Track Magnetic Tape Cartridge, 999 bpmm, GCR + + + QIC-120: 6.3 mm 15-Track Magnetic Tape Cartridge, 394 bpmm, GCR + + + QIC-150: 6.3 mm 18-Track Magnetic Tape Cartridge, 394 bpmm, GCR + + + QIC-320: 6.3 mm 26-Track Magnetic Tape Cartridge, 630 bpmm, GCR + + + QIC-1350: 6.3 mm 30-Track Magnetic Tape Cartridge, 2034 bpmm, RLL + + + ANSI X3B5/88-185A: 3.81 mm Magnetic Tape Cassette, 2400 bpmm, DDS + + + ANSI X3.202-1991: 8 mm Magnetic Tape Cassette, 1703 bpmm, RLL + + + ECMA TC17: 8 mm Magnetic Tape Cassette, 1789 bpmm, RLL + + + ANSI X3.193-1990: 12.7 mm 48-Track Magnetic Tape Cartridge, 394 bpmm, MFM + + + ANSI X3B5/97-174: 12.7 mm 48-Track Magnetic Tape Cartridge, 1673 bpmm, MFM + + + QIC-11 + + + IBM 3490E + + + LTO Ultrium or Super AIT-1 + + + LTO Ultrium-2 or T9840 + + + T9940 + + + LTO Ultrium-3 or T9940 + + + T9840C + + + LTO Ultrium-4 or T9840D + + + T10000A + + + T10000B + + + T10000C + + + T10000D + + + AIT-1 + + + AIT-2 + + + AIT-3 + + + DDS-2 + + + DDS-3 + + + DDS-4 + + + unknown density code 0x{0:X2} + + + LTO Ultrium cleaning cartridge + + + MLR1-26GB + + + DC-9200 + + + LTO Ultrium-2 in CD emulation mode + + + LTO Ultrium-3 in CD emulation mode + + + LTO Ultrium-4 in CD emulation mode + + + LTO Ultrium-5 in CD emulation mode + + + EXB-8200 + + + EXB-8200 compressed + + + EXB-8500 + + + EXB-8500 compressed + + + Mammoth + + + IBM 3590 + + + IBM 3590E + + + VXA-1 + + + CompactTape I + + + CompactTape II + + + IBM 3590 extended + + + IBM 3590E extended + + + VXA-2 + + + VXA-3 + + + DLTtape III at 42500 bpi + + + DLTtape III with 56 tracks + + + DLTtape III at 62500 bpi + + + DLTtape III compressed + + + DLTtape IIIxt + + + DLTtape IIIxt compressed + + + DLTtape IV + + + DLTtape IV at 123090 bpi + + + DLTtape IV at 98250 bpi + + + Travan 5 + + + DLTtape IV compressed + + + DLTtape IV at 85937 bpi + + + DLTtape IV at 85937 bpi compressed + + + DLTtape IV at 123090 bpi compressed + + + DLTtape IV at 98250 bpi compressed + + + Super DLTtape I at 133000 bpi + + + Super DLTtape I + + + Super DLTtape I compressed + + + VStape I compressed + + + Mammoth-2 + + + DC-9250 + + + MLR1-26GBSL + + + SLR-32 SL + + + SLR-5 SL + + + SLR40, SLR60 or SLR100 + + + All remaining blocks conform to {0} and have a variable length + + + All remaining blocks conform to {0} and are {1} bytes each + + + {0} blocks conform to {1} and have a variable length + + + {0} blocks conform to {1} and are {2} bytes each + + + All remaining blocks have a variable length + + + {0} blocks have a variable length + + + Device prints directly + + + Device uses a print cache + + + Medium is + + + a combination of read-only and erasable optical + + + a combination of write-once and erasable optical + + + an unknown medium type 0x{0:X2} + + + Blank checking during write is enabled + + + ISO/IEC 10090: 86 mm Read/Write single-sided optical disc with 12500 tracks + + + 89 mm Read/Write double-sided optical disc with 12500 tracks + + + ANSI X3.212: 130 mm Read/Write double-sided optical disc with 18750 tracks + + + ANSI X3.191: 130 mm Write-Once double-sided optical disc with 30000 tracks + + + ANSI X3.214: 130 mm Write-Once double-sided optical disc with 20000 tracks + + + ANSI X3.211: 130 mm Write-Once double-sided optical disc with 18750 tracks + + + 200 mm optical disc + + + ISO/IEC 13614: 300 mm double-sided optical disc + + + ANSI X3.200: 356 mm double-sided optical disc with 56350 tracks + + + All remaining blocks are {0} and have a variable length + + + All remaining blocks are {0} and are {1} bytes each + + + {0} blocks are {1} and have a variable length + + + {0} blocks are {1} and are {2} bytes each + + + 120 mm CD-ROM + + + 120 mm Compact Disc Digital Audio + + + 120 mm Compact Disc with data and audio + + + 80 mm CD-ROM + + + 80 mm Compact Disc Digital Audio + + + 80 mm Compact Disc with data and audio + + + Unknown medium type + + + 120 mm Hybrid disc (Photo CD) + + + Unknown size CD-R + + + 120 mm CD-R with data only + + + 120 mm CD-R with audio only + + + 120 mm CD-R with data and audio + + + 120 mm Hybrid CD-R (Photo CD) + + + 80 mm CD-R with data only + + + 80 mm CD-R with audio only + + + 80 mm Hybrid CD-R (Photo CD) + + + Unknown size CD-RW + + + 120 mm CD-RW with data only + + + 120 mm CD-RW with audio only + + + 120 mm CD-RW with data and audio + + + 120 mm Hybrid CD-RW (Photo CD) + + + 80 mm CD-RW with data only + + + 80 mm CD-RW with audio only + + + 80 mm CD-RW with data and audio + + + 80 mm Hybrid CD-RW (Photo CD) + + + Unknown size HD disc + + + 120 mm HD disc + + + 80 mm HD disc + + + No disc inserted, tray closed or caddy inserted + + + Tray open or no caddy inserted + + + Tray closed or caddy inserted but medium error + + + Read-only block device + + + Read/Write block device + + + Unknown block device + + + LTO in CD-ROM emulation mode + + + user data only + + + user data plus auxiliary data + + + 4-byte tag, user data plus auxiliary data + + + audio information only + + + Density "{0}" defined by "{1}". + + + Secondary code: {0:X2}h + + + Drive can write this density + + + This descriptor is duplicated + + + This is the default density on the drive + + + Density has {0} bits per mm, with {1} tracks in a {2} mm width tape + + + Density maximum capacity is {0} megabytes + + + Density description: {0} + + + Primary code: {0:X2}h + + + Medium supports following density codes: + + + Medium type "{0}" defined by "{1}". + + + Medium type code: {0:X2}h + + + Medium has a nominal length of {0} m in a {1} mm width tape + + + Medium description: {0} + + + SCSI Implemented operating definitions: + + + Default operating definition: {0} + + + Current operating definition: {0} + + + There are no supported definitions + + + Supported operating definitions: + + + SCSI Device identification: + + + There are no identifiers + + + Automation/Drive Interface Transport + + + AT Attachment Interface (ATA/ATAPI) + + + Fibre Channel + + + IEEE 1394 + + + Internet SCSI + + + no specific + + + PCI Express + + + SCSI Remote Direct Memory Access + + + Serial Attachment SCSI + + + Parallel SCSI + + + SCSI over PCI Express + + + SSA + + + USB Attached SCSI + + + unknown code {0} + + + Descriptor refers to {0} protocol + + + Vendor descriptor contains: {0} + + + Vendor descriptor contains binary data (hex): {0} + + + Vendor descriptor contains unknown kind {1} of data (hex): {0} + + + Inquiry descriptor contains: {0} + + + Inquiry descriptor contains binary data (hex): {0} + + + Inquiry descriptor contains unknown kind {1} of data (hex): {0} + + + IEEE EUI-64: {0} + + + IEEE EUI-64: {0:X2} + + + NAA: {0} + + + NAA: {0:X2} + + + Relative target port identifier: {0} + + + Target group identifier: {0} + + + Logical unit group identifier: {0} + + + MD5 logical unit identifier: {0} + + + MD5 logical unit identifier: {0:x2} + + + SCSI name string identifier: {0} + + + SCSI name string identifier (hex): {0} + + + Protocol (Automation/Drive Interface Transport) specific descriptor with unknown format (hex): {0} + + + Protocol (ATA/ATAPI) specific descriptor with unknown format (hex): {0} + + + Protocol (Fibre Channel) specific descriptor with unknown format (hex): {0} + + + Protocol (IEEE 1394) specific descriptor with unknown format (hex): {0} + + + Protocol (Internet SCSI) specific descriptor with unknown format (hex): {0} + + + Protocol (unknown) specific descriptor with unknown format (hex): {0} + + + Protocol (PCI Express) specific descriptor with unknown format (hex): {0} + + + Protocol (SCSI Remote Direct Memory Access) specific descriptor with unknown format (hex): {0} + + + Protocol (Serial Attachment SCSI) specific descriptor with unknown format (hex): {0} + + + Protocol (Parallel SCSI) specific descriptor with unknown format (hex): {0} + + + Protocol (SSA) specific descriptor with unknown format (hex): {0} + + + Protocol (SCSIe) specific descriptor: Routing ID is {0} + + + Protocol (UAS) specific descriptor: USB address {0} interface {1} + + + Protocol (unknown code {0}) specific descriptor with unknown format (hex): {1} + + + Unknown descriptor type {1} contains: {0} + + + Unknown descriptor type {1} contains binary data (hex): {0} + + + Inquiry descriptor type {2} contains unknown kind {1} of data (hex): {0} + + + SCSI Software Interface Identifiers: + + + SCSI Management Network Addresses: + + + There are no addresses + + + Identifier belongs to addressed logical unit + + + Identifier belongs to target port + + + Identifier belongs to target device that contains the addressed logical unit + + + Identifier has unknown association with code {0} + + + Address for code download: {0} + + + Address for diagnostics: {0} + + + Address for logging: {0} + + + Address for status: {0} + + + Address for storage configuration service: {0} + + + Unspecified address: {0} + + + Address for copy service: {0} + + + Address for administrative configuration service: {0} + + + Address of unknown type {1}: {0} + + + SCSI Extended INQUIRY Data: + + + Logical unit supports type 1 protection + + + Logical unit supports types 1 and 2 protection + + + Logical unit supports type 2 protection + + + Logical unit supports types 1 and 3 protection + + + Logical unit supports type 3 protection + + + Logical unit supports types 2 and 3 protection + + + Logical unit supports types 1, 2 and 3 protection + + + Logical unit supports unknown protection defined by code {0} + + + Logical unit supports logical block protection + + + Device checks the logical block guard + + + Device checks the logical block application tag + + + Device checks the logical block reference tag + + + Device supports unit attention condition sense key specific data + + + Device supports grouping + + + Device supports priority + + + Device supports head of queue + + + Device supports the ORDERED task attribute + + + Device supports the SIMPLE task attribute + + + Device supports marking a block as uncorrectable with WRITE LONG + + + Device supports disabling correction with WRITE LONG + + + Device has a non-volatile cache + + + Device has a volatile cache + + + Device has disabled protection information checks + + + Device supports protection information intervals + + + Device clears any unit attention condition in all LUNs after reporting for any LUN + + + Device supports referrals + + + Device implements alternate reset handling + + + Device supports capability-based command security + + + Device supports power-on activation for new microcode + + + Device supports hard reset activation for new microcode + + + Device supports vendor specific activation for new microcode + + + Extended self-test takes {0} to complete + + + Device supports a maximum of {0} bytes for sense data + + + SCSI to ATA Translation Layer Data: + + + Translation layer vendor: {0} + + + Translation layer name: {0} + + + Translation layer release level: {0} + + + Device responded to ATA IDENTIFY DEVICE command. + + + Device responded to ATA IDENTIFY PACKET DEVICE command. + + + Device responded to ATA command {0:X2}h + + + Device uses Parallel ATA. + + + Device uses Serial ATA. + + + Device uses unknown transport with code {0} + + + ATA IDENTIFY information follows: + + + Could not decode ATA IDENTIFY information + + + Quantum Firmware Build Information page: + + + Servo firmware checksum: 0x{0:X4} + + + EEPROM firmware checksum: 0x{0:X4} + + + Read/write firmware checksum: 0x{0:X8} + + + Read/write firmware build date: {0} + + + Certance Drive Component Revision Levels page: + + + Component: {0} + + + Version: {0} + + + Date: {0} + + + Variant: {0} + + + Certance Drive Component Serial Number page: + + + Head Assembly Serial Number: {0} + + + Reel Motor 1 Serial Number: {0} + + + Reel Motor 2 Serial Number: {0} + + + Board Serial Number: {0} + + + Base Mechanical Serial Number: {0} + + + Certance drive status page: + + + Command forwarding is disabled + + + Command forwarding is enabled + + + Unknown command forwarding code {0} + + + Alerts are enabled + + + Cartridge removable is prevented + + + Unit is reserved by initiator ID {0:X16} + + + Device needs cleaning cartridge + + + Cartridge tape is threaded + + + There are commands pending to be forwarded + + + Cartridge will be loaded and threaded on insertion + + + Cartridge will be loaded but not threaded on insertion + + + Cartridge will not be loaded + + + Unknown autoloading mode code {0} + + + Port A link is down + + + Unknown port A transport type code {0} + + + Drive responds to SCSI ID {0} + + + Drive has been operating {0} + + + Inserted cartridge is LTO + + + Unknown cartridge format code {0} + + + There is no cartridge inserted + + + Cleaning cartridge inserted + + + Unknown data cartridge inserted + + + Firmware cartridge inserted + + + LTO Ultrium 1 Type A cartridge inserted + + + LTO Ultrium 1 Type B cartridge inserted + + + LTO Ultrium 1 Type C cartridge inserted + + + LTO Ultrium 1 Type D cartridge inserted + + + LTO Ultrium 2 cartridge inserted + + + Unknown cartridge type code {0} + + + Cartridge has an uncompressed capability of {0} gigabytes + + + Cartridge serial number: {0} + + + IBM Drive Component Revision Levels page: + + + Code name: {0} + + + IBM Drive Serial Numbers page: + + + Manufacturing serial number: {0} + + + Reported serial number: {0} + + + SCSI Sequential-access Device Capabilities: + + + Device supports WORM media + + + Device supports Tape Stream Mirroring + + + HP Drive Firmware Revision Levels page: + + + HP Drive Hardware Revision Levels page: + + + HP Drive PCA Revision Levels page: + + + HP Drive Mechanism Revision Levels page: + + + HP Drive Head Assembly Revision Levels page: + + + HP Drive ACI Revision Levels page: + + + Copyright: {0} + + + Seagate Firmware Numbers page: + + + Controller firmware version: {0} + + + Boot firmware version: {0} + + + Servo firmware version: {0} + + + Error class {0} type {1} happened on block {2} + + + Error class {0} type {1} + + + SCSI SENSE: {0} + + + On segment {0} + + + Filemark or setmark found + + + End-of-medium/partition found + + + Incorrect length indicator + + + On logical block {0} + + + Illegal field in CDB + + + Illegal field in data parameters + + + Invalid value in bit {0} in field {1} of CDB + + + Invalid value in field {0} of CDB + + + Format progress {0:P} + + + Actual retry count is {0} + + + On logical block {0} + + + VENDOR-SPECIFIC ASC {0:X2}h WITH VENDOR-SPECIFIC ASCQ {1:X2}h + + + VENDOR-SPECIFIC ASC {0:X2}h WITH ASCQ {1:X2}h + + + ASC {0:X2}h WITH VENDOR-SPECIFIC ASCQ {1:X2}h + + + ASC {0:X2}h WITH ASCQ {1:X2}h + + + SecureDigital Device Identification Register: + + + SecureDigital Device Specific Data Register: + + + Register version 2.0 + + + Asynchronous data access time is {0}{1} + + + Clock dependent part of data access is {0} clock cycles + + + MBit/s + + + Device's transfer speed: {0}{1} + + + Device support command classes {0} + + + Read block length is {0} bytes + + + Device allows reading partial blocks + + + Write commands can cross physical block boundaries + + + Read commands can cross physical block boundaries + + + Device implements configurable driver stage + + + Device has {0} TiB + + + Device can erase multiple blocks + + + Device must erase a minimum of {0} blocks at a time + + + SecureDigital Operation Conditions Register: + + + Device is SDHC, SDXC or higher + + + Device is UHS-II or higher + + + Device can switch to work with 1.8V supply + + + Device is in low power mode + + + SecureDigital Device Configuration Register: + + + Unknown register version {0} + + + Device follows SecureDigital Physical Layer Specification version 1.0x + + + Device follows SecureDigital Physical Layer Specification version 1.10 + + + Device follows SecureDigital Physical Layer Specification version 2.00 + + + Device follows SecureDigital Physical Layer Specification version 3.0x + + + Device follows SecureDigital Physical Layer Specification version 4.xx + + + Device follows SecureDigital Physical Layer Specification version 5.xx + + + Device follows SecureDigital Physical Layer Specification version 6.xx + + + Device follows SecureDigital Physical Layer Specification version 7.xx + + + Device follows SecureDigital Physical Layer Specification version 8.xx + + + Device follows SecureDigital Physical Layer Specification with unknown version {0}.{1}.{2}.{3} + + + Device does not support CPRM + + + Device does not use CPRM + + + Device uses CPRM according to specification version 1.01 + + + Device uses CPRM according to specification version 2.00 + + + Device uses CPRM according to specification version 3.xx + + + Device uses unknown CPRM specification with code {0} + + + Device supports 1-bit data bus + + + Device supports 4-bit data bus + + + Device supports extended security + + + Device supports extension register multi-block commands + + + Device supports extension register single-block commands + + + Device supports set block count command + + + Device supports speed class control command + + + SEGA IP.BIN INFORMATION: + + + System name: {0} + + + Initial program address: 0x{0:X8} + + + Initial program load size: {0} bytes + + + Initial program entry address: 0x{0:X8} + + + Initial program work RAM: {0} bytes + + + System program address: 0x{0:X8} + + + System program load size: {0} bytes + + + System program entry address: 0x{0:X8} + + + System program work RAM: {0} bytes + + + Release date: {0} + + + Hardware ID: {0} + + + Developer code: {0} + + + Domestic title: {0} + + + Overseas title: {0} + + + Product code: {0} + + + Peripherals: + + + Game supports analog controller. + + + Game supports trackball. + + + Game supports light gun. + + + Game supports JoyPad. + + + Game supports Master System's JoyPad. + + + Game supports printer interface. + + + Game supports serial (RS-232C) interface. + + + Game supports tablet interface. + + + Game supports paddle controller. + + + Game supports unknown peripheral {0}. + + + Regions supported: + + + Japanese NTSC. + + + USA NTSC. + + + Europe PAL. + + + Game supports unknown region {0}. + + + Product name: {0} + + + Product version: {0} + + + Product CRC: 0x{0:X8} + + + Producer: {0} + + + Disc media: {0} + + + Disc number {0} of {1} + + + Disc boots natively. + + + Disc boots using Windows CE. + + + Disc boots using unknown loader: {0}. + + + North America NTSC. + + + Game uses Windows CE. + + + Game supports the VGA Box. + + + Game supports other expansion. + + + Game supports Puru Puru pack. + + + Game supports Mike Device. + + + Game supports Memory Card. + + + Game requires A + B + Start buttons and D-Pad. + + + Game requires C button. + + + Game requires D button. + + + Game requires X button. + + + Game requires Y button. + + + Game requires Z button. + + + Game requires expanded direction buttons. + + + Game requires analog R trigger. + + + Game requires analog L trigger. + + + Game requires analog horizontal controller. + + + Game requires analog vertical controller. + + + Game requires expanded analog horizontal controller. + + + Game requires expanded analog vertical controller. + + + Game supports Gun. + + + Game supports Keyboard. + + + Game supports Mouse. + + + Game supports unknown peripherals mask {0:X2} + + + Game supports analog steering controller. + + + Game supports multitap. + + + Asia NTSC. + + + Catalogue number: + + + Timestamp: {0} + + + Media ID: + + + Xbox Game Disc + + + Xbox 360 Game Disc + + + Challenge ID: {0} + + + Challenge level: {0} + + + Challenge value: 0x{0:X8} + + + Response modifier: {0} + + + Response value: 0x{0:X8} + + + Extent starts at PSN {0:X6}h and ends at PSN {1:X6}h + + + Device vendor: {0} + + + Device name: {0} + + + Device release level: {0} + + + Device is connected and supported. + + + Device is supported but not connected. + + + Reserved value set in Peripheral Qualifier field. + + + Device is connected but unsupported. + + + Vendor value {0} set in Peripheral Qualifier field. + + + Direct-access device + + + Sequential-access device + + + Printer device + + + Processor device + + + Write-once device + + + CD-ROM/DVD/etc device + + + Scanner device + + + Optical memory device + + + Medium change device + + + Communications device + + + Graphics arts pre-press device (defined in ASC IT8) + + + Array controller device + + + Enclosure services device + + + Simplified direct-access device + + + Optical card reader/writer device + + + Bridging Expanders + + + Object-based Storage Device + + + Automation/Drive Interface + + + Security Manager Device + + + Host managed zoned block device + + + Well known logical unit + + + Unknown or no device type + + + Unknown device type field value 0x{0:X2} + + + Device does not claim to comply with any SCSI ANSI standard + + + Device claims to comply with ANSI X3.131:1986 (SCSI-1) + + + Device claims to comply with ANSI X3.131:1994 (SCSI-2) + + + Device claims to comply with ANSI X3.301:1997 (SPC-1) + + + Device claims to comply with ANSI X3.351:2001 (SPC-2) + + + Device claims to comply with ANSI X3.408:2005 (SPC-3) + + + Device claims to comply with ANSI X3.408:2005 (SPC-4) + + + Device claims to comply with unknown SCSI ANSI standard value 0x{0:X2}) + + + Device does not claim to comply with any SCSI ECMA standard + + + Device claims to comply ECMA-111: Small Computer System Interface SCSI + + + Device claims to comply with unknown SCSI ECMA standard value 0x{0:X2}) + + + Device does not claim to comply with any SCSI ISO/IEC standard + + + Device claims to comply with ISO/IEC 9316:1995 + + + Device claims to comply with unknown SCSI ISO/IEC standard value 0x{0:X2}) + + + Device supports Asynchronous Event Reporting Capability + + + Device supports TERMINATE TASK command + + + Device supports setting Normal ACA + + + Device supports LUN hierarchical addressing + + + Device contains an embedded storage array controller + + + Device contains an Access Control Coordinator + + + Device supports third-party copy commands + + + Device supports protection information + + + Device supports basic queueing + + + Device contains an embedded enclosure services component + + + Multi-port device + + + Device contains or is attached to a medium changer + + + Device supports request and acknowledge handshakes + + + Device supports 32-bit wide SCSI addresses + + + Device supports 16-bit wide SCSI addresses + + + Device supports relative addressing + + + Device supports 32-bit wide data transfers + + + Device supports 16-bit wide data transfers + + + Device supports synchronous data transfer + + + Device supports linked commands + + + Device supports CONTINUE TASK and TARGET TRANSFER DISABLE commands + + + Device supports Quick Arbitration and Selection + + + Device supports TCQ queue + + + Device supports information unit transfers + + + Device implements RESET as a soft reset + + + Vendor specific bit 5 on byte 6 of INQUIRY response is set + + + Device does not support asymmetrical access + + + Device only supports implicit asymmetrical access + + + Device only supports explicit asymmetrical access + + + Device supports implicit and explicit asymmetrical access + + + Unknown value in TPGS field 0x{0:X2} + + + Device supports only ST clocking + + + Device supports only DT clocking + + + Reserved value 0x02 found in SPI clocking field + + + Device supports ST and DT clocking + + + Unknown value in SPI clocking field 0x{0:X2} + + + Device complies with SAM (no version claimed) + + + Device complies with SAM T10/0994-D revision 18 + + + Device complies with SAM ANSI INCITS 270-1996 + + + Device complies with SAM-2 (no version claimed) + + + Device complies with SAM-2 T10/1157-D revision 23 + + + Device complies with SAM-2 T10/1157-D revision 24 + + + Device complies with SAM-2 ANSI INCITS 366-2003 + + + Device complies with SAM-2 ISO/IEC 14776-412 + + + Device complies with SAM-3 (no version claimed) + + + Device complies with SAM-3 T10/1561-D revision 7 + + + Device complies with SAM-3 T10/1561-D revision 13 + + + Device complies with SAM-3 T10/1561-D revision 14 + + + Device complies with SAM-3 ANSI INCITS 402-2005 + + + Device complies with SAM-4 (no version claimed) + + + Device complies with SAM-4 T10/1683-D revision 13 + + + Device complies with SAM-4 T10/1683-D revision 14 + + + Device complies with SAM-4 ANSI INCITS 447-2008 + + + Device complies with SAM-4 ISO/IEC 14776-414 + + + Device complies with SAM-5 (no version claimed) + + + Device complies with SAM-5 T10/2104-D revision 4 + + + Device complies with SAM-5 T10/2104-D revision 20 + + + Device complies with SAM-5 T10/2104-D revision 21 + + + Device complies with SAM-6 (no version claimed) + + + Device complies with SPC (no version claimed) + + + Device complies with SPC T10/0995-D revision 11a + + + Device complies with SPC ANSI INCITS 301-1997 + + + Device complies with MMC (no version claimed) + + + Device complies with MMC T10/1048-D revision 10a + + + Device complies with MMC ANSI INCITS 304-1997 + + + Device complies with SCC (no version claimed) + + + Device complies with SCC T10/1047-D revision 06c + + + Device complies with SCC ANSI INCITS 276-1997 + + + Device complies with SBC (no version claimed) + + + Device complies with SBC T10/0996-D revision 08c + + + Device complies with SBC ANSI INCITS 306-1998 + + + Device complies with SMC (no version claimed) + + + Device complies with SMC T10/0999-D revision 10a + + + Device complies with SMC ANSI INCITS 314-1998 + + + Device complies with SMC ISO/IEC 14776-351 + + + Device complies with SES (no version claimed) + + + Device complies with SES T10/1212-D revision 08b + + + Device complies with SES ANSI INCITS 305-1998 + + + Device complies with SES T10/1212 revision 08b w/ Amendment ANSI INCITS.305/AM1-2000 + + + Device complies with SES ANSI INCITS 305-1998 w/ Amendment ANSI INCITS.305/AM1-2000 + + + Device complies with SCC-2 (no version claimed) + + + Device complies with SCC-2 T10/1125-D revision 04 + + + Device complies with SCC-2 ANSI INCITS 318-1998 + + + Device complies with SSC (no version claimed) + + + Device complies with SSC T10/0997-D revision 17 + + + Device complies with SSC T10/0997-D revision 22 + + + Device complies with SSC ANSI INCITS 335-2000 + + + Device complies with RBC (no version claimed) + + + Device complies with RBC T10/1240-D revision 10a + + + Device complies with RBC ANSI INCITS 330-2000 + + + Device complies with MMC-2 (no version claimed) + + + Device complies with MMC-2 T10/1228-D revision 11 + + + Device complies with MMC-2 T10/1228-D revision 11a + + + Device complies with MMC-2 ANSI INCITS 333-2000 + + + Device complies with SPC-2 (no version claimed) + + + Device complies with SPC-2 T10/1236-D revision 12 + + + Device complies with SPC-2 T10/1236-D revision 18 + + + Device complies with SPC-2 T10/1236-D revision 19 + + + Device complies with SPC-2 T10/1236-D revision 20 + + + Device complies with SPC-2 ANSI INCITS 351-2001 + + + Device complies with SPC-2 ISO/IEC 14776-452 + + + Device complies with OCRW (no version claimed) + + + Device complies with OCRW ISO/IEC 14776-381 + + + Device complies with MMC-3 (no version claimed) + + + Device complies with MMC-3 T10/1363-D revision 9 + + + Device complies with MMC-3 T10/1363-D revision 10g + + + Device complies with MMC-3 ANSI INCITS 360-2002 + + + Device complies with SMC-2 (no version claimed) + + + Device complies with SMC-2 T10/1383-D revision 5 + + + Device complies with SMC-2 T10/1383-D revision 6 + + + Device complies with SMC-2 T10/1383-D revision 7 + + + Device complies with SMC-2 ANSI INCITS 382-2004 + + + Device complies with SPC-3 (no version claimed) + + + Device complies with SPC-3 T10/1416-D revision 7 + + + Device complies with SPC-3 T10/1416-D revision 21 + + + Device complies with SPC-3 T10/1416-D revision 22 + + + Device complies with SPC-3 T10/1416-D revision 23 + + + Device complies with SPC-3 ANSI INCITS 408-2005 + + + Device complies with SPC-3 ISO/IEC 14776-453 + + + Device complies with SBC-2 (no version claimed) + + + Device complies with SBC-2 T10/1417-D revision 5a + + + Device complies with SBC-2 T10/1417-D revision 15 + + + Device complies with SBC-2 T10/1417-D revision 16 + + + Device complies with SBC-2 ANSI INCITS 405-2005 + + + Device complies with SBC-2 ISO/IEC 14776-322 + + + Device complies with OSD (no version claimed) + + + Device complies with OSD T10/1355-D revision 0 + + + Device complies with OSD T10/1355-D revision 7a + + + Device complies with OSD T10/1355-D revision 8 + + + Device complies with OSD T10/1355-D revision 9 + + + Device complies with OSD T10/1355-D revision 10 + + + Device complies with OSD ANSI INCITS 400-2004 + + + Device complies with SSC-2 (no version claimed) + + + Device complies with SSC-2 T10/1434-D revision 7 + + + Device complies with SSC-2 T10/1434-D revision 9 + + + Device complies with SSC-2 ANSI INCITS 380-2003 + + + Device complies with BCC (no version claimed) + + + Device complies with MMC-4 (no version claimed) + + + Device complies with MMC-4 T10/1545-D revision 5 + + + Device complies with MMC-4 T10/1545-D revision 5a + + + Device complies with MMC-4 T10/1545-D revision 3 + + + Device complies with MMC-4 T10/1545-D revision 3d + + + Device complies with MMC-4 ANSI INCITS 401-2005 + + + Device complies with ADC (no version claimed) + + + Device complies with ADC T10/1558-D revision 6 + + + Device complies with ADC T10/1558-D revision 7 + + + Device complies with ADC ANSI INCITS 403-2005 + + + Device complies with SES-2 (no version claimed) + + + Device complies with SES-2 T10/1559-D revision 16 + + + Device complies with SES-2 T10/1559-D revision 19 + + + Device complies with SES-2 T10/1559-D revision 20 + + + Device complies with SES-2 ANSI INCITS 448-2008 + + + Device complies with SES-2 ISO/IEC 14776-372 + + + Device complies with SSC-3 (no version claimed) + + + Device complies with SSC-3 T10/1611-D revision 04a + + + Device complies with SSC-3 T10/1611-D revision 05 + + + Device complies with SSC-3 ANSI INCITS 467-2011 + + + Device complies with SSC-3 ISO/IEC 14776-333:2013 + + + Device complies with MMC-5 (no version claimed) + + + Device complies with MMC-5 T10/1675-D revision 03 + + + Device complies with MMC-5 T10/1675-D revision 03b + + + Device complies with MMC-5 T10/1675-D revision 04 + + + Device complies with MMC-5 ANSI INCITS 430-2007 + + + Device complies with OSD-2 (no version claimed) + + + Device complies with OSD-2 T10/1729-D revision 4 + + + Device complies with OSD-2 T10/1729-D revision 5 + + + Device complies with OSD-2 ANSI INCITS 458-2011 + + + Device complies with SPC-4 (no version claimed) + + + Device complies with SPC-4 T10/BSR INCITS 513 revision 16 + + + Device complies with SPC-4 T10/BSR INCITS 513 revision 18 + + + Device complies with SPC-4 T10/BSR INCITS 513 revision 23 + + + Device complies with SPC-4 T10/BSR INCITS 513 revision 36 + + + Device complies with SPC-4 T10/BSR INCITS 513 revision 37 + + + Device complies with SPC-4 T10/BSR INCITS 513 revision 37a + + + Device complies with SPC-4 ANSI INCITS 513-2015 + + + Device complies with SMC-3 (no version claimed) + + + Device complies with SMC-3 T10/1730-D revision 15 + + + Device complies with SMC-3 T10/1730-D revision 16 + + + Device complies with SMC-3 ANSI INCITS 484-2012 + + + Device complies with ADC-2 (no version claimed) + + + Device complies with ADC-2 T10/1741-D revision 7 + + + Device complies with ADC-2 T10/1741-D revision 8 + + + Device complies with ADC-2 ANSI INCITS 441-2008 + + + Device complies with SBC-3 (no version claimed) + + + Device complies with SBC-3 T10/BSR INCITS 514 revision 35 + + + Device complies with SBC-3 T10/BSR INCITS 514 revision 36 + + + Device complies with SBC-3 ANSI INCITS 514-2014 + + + Device complies with MMC-6 (no version claimed) + + + Device complies with MMC-6 T10/1836-D revision 02b + + + Device complies with MMC-6 T10/1836-D revision 02g + + + Device complies with MMC-6 ANSI INCITS 468-2010 + + + Device complies with MMC-6 ANSI INCITS 468-2010 + MMC-6/AM1 ANSI INCITS 468-2010/AM 1 + + + Device complies with ADC-3 (no version claimed) + + + Device complies with ADC-3 T10/1895-D revision 04 + + + Device complies with ADC-3 T10/1895-D revision 05 + + + Device complies with ADC-3 T10/1895-D revision 05a + + + Device complies with ADC-3 ANSI INCITS 497-2012 + + + Device complies with SSC-4 (no version claimed) + + + Device complies with SSC-4 T10/BSR INCITS 516 revision 2 + + + Device complies with SSC-4 T10/BSR INCITS 516 revision 3 + + + Device complies with SSC-4 ANSI INCITS 516-2013 + + + Device complies with OSD-3 (no version claimed) + + + Device complies with SES-3 (no version claimed) + + + Device complies with SSC-5 (no version claimed) + + + Device complies with SPC-5 (no version claimed) + + + Device complies with SFSC (no version claimed) + + + Device complies with SFSC BSR INCITS 501 revision 01 + + + Device complies with SBC-4 (no version claimed) + + + Device complies with ZBC (no version claimed) + + + Device complies with ZBC BSR INCITS 536 revision 02 + + + Device complies with ADC-4 (no version claimed) + + + Device complies with SSA-TL2 (no version claimed) + + + Device complies with SSA-TL2 T10.1/1147-D revision 05b + + + Device complies with SSA-TL2 ANSI INCITS 308-1998 + + + Device complies with SSA-TL1 (no version claimed) + + + Device complies with SSA-TL1 T10.1/0989-D revision 10b + + + Device complies with SSA-TL1 ANSI INCITS 295-1996 + + + Device complies with SSA-S3P (no version claimed) + + + Device complies with SSA-S3P T10.1/1051-D revision 05b + + + Device complies with SSA-S3P ANSI INCITS 309-1998 + + + Device complies with SSA-S2P (no version claimed) + + + Device complies with SSA-S2P T10.1/1121-D revision 07b + + + Device complies with SSA-S2P ANSI INCITS 294-1996 + + + Device complies with SIP (no version claimed) + + + Device complies with SIP T10/0856-D revision 10 + + + Device complies with SIP ANSI INCITS 292-1997 + + + Device complies with FCP (no version claimed) + + + Device complies with FCP T10/0993-D revision 12 + + + Device complies with FCP ANSI INCITS 269-1996 + + + Device complies with SBP-2 (no version claimed) + + + Device complies with SBP-2 T10/1155-D revision 04 + + + Device complies with SBP-2 ANSI INCITS 325-1998 + + + Device complies with FCP-2 (no version claimed) + + + Device complies with FCP-2 T10/1144-D revision 4 + + + Device complies with FCP-2 T10/1144-D revision 7 + + + Device complies with FCP-2 T10/1144-D revision 7a + + + Device complies with FCP-2 ANSI INCITS 350-2003 + + + Device complies with FCP-2 T10/1144-D revision 8 + + + Device complies with SST (no version claimed) + + + Device complies with SST T10/1380-D revision 8b + + + Device complies with SRP (no version claimed) + + + Device complies with SRP T10/1415-D revision 10 + + + Device complies with SRP T10/1415-D revision 16a + + + Device complies with SRP ANSI INCITS 365-2002 + + + Device complies with iSCSI (no version claimed) + + + Device complies with iSCSI revision {0} + + + Device complies with SBP-3 (no version claimed) + + + Device complies with SBP-3 T10/1467-D revision 1f + + + Device complies with SBP-3 T10/1467-D revision 3 + + + Device complies with SBP-3 T10/1467-D revision 4 + + + Device complies with SBP-3 T10/1467-D revision 5 + + + Device complies with SBP-3 ANSI INCITS 375-2004 + + + Device complies with ADP (no version claimed) + + + Device complies with ADT (no version claimed) + + + Device complies with ADT T10/1557-D revision 11 + + + Device complies with ADT T10/1557-D revision 14 + + + Device complies with ADT ANSI INCITS 406-2005 + + + Device complies with FCP-3 (no version claimed) + + + Device complies with FCP-3 T10/1560-D revision 3f + + + Device complies with FCP-3 T10/1560-D revision 4 + + + Device complies with FCP-3 ANSI INCITS 416-2006 + + + Device complies with FCP-3 ISO/IEC 14776-223 + + + Device complies with ADT-2 (no version claimed) + + + Device complies with ADT-2 T10/1742-D revision 06 + + + Device complies with ADT-2 T10/1742-D revision 08 + + + Device complies with ADT-2 T10/1742-D revision 09 + + + Device complies with ADT-2 ANSI INCITS 472-2011 + + + Device complies with FCP-4 (no version claimed) + + + Device complies with FCP-4 T10/1828-D revision 01 + + + Device complies with FCP-4 T10/1828-D revision 02 + + + Device complies with FCP-4 T10/1828-D revision 02b + + + Device complies with FCP-4 ANSI INCITS 481-2012 + + + Device complies with ADT-3 (no version claimed) + + + Device complies with SPI (no version claimed) + + + Device complies with SPI T10/0855-D revision 15a + + + Device complies with SPI ANSI INCITS 253-1995 + + + Device complies with SPI T10/0855-D revision 15a with SPI Amnd revision 3a + + + Device complies with SPI ANSI INCITS 253-1995 with SPI Amnd ANSI INCITS 253/AM1-1998 + + + Device complies with Fast-20 (no version claimed) + + + Device complies with Fast-20 T10/1071 revision 06 + + + Device complies with Fast-20 ANSI INCITS 277-1996 + + + Device complies with SPI-2 (no version claimed) + + + Device complies with SPI-2 T10/1142-D revision 20b + + + Device complies with SPI-2 ANSI INCITS 302-1999 + + + Device complies with SPI-3 (no version claimed) + + + Device complies with SPI-3 T10/1302-D revision 10 + + + Device complies with SPI-3 T10/1302-D revision 13a + + + Device complies with SPI-3 T10/1302-D revision 14 + + + Device complies with SPI-3 ANSI INCITS 336-2000 + + + Device complies with EPI (no version claimed) + + + Device complies with EPI T10/1134 revision 16 + + + Device complies with EPI ANSI INCITS TR-23 1999 + + + Device complies with SPI-4 (no version claimed) + + + Device complies with SPI-4 T10/1365-D revision 7 + + + Device complies with SPI-4 T10/1365-D revision 9 + + + Device complies with SPI-4 ANSI INCITS 362-2002 + + + Device complies with SPI-4 T10/1365-D revision 10 + + + Device complies with SPI-5 (no version claimed) + + + Device complies with SPI-5 T10/1525-D revision 3 + + + Device complies with SPI-5 T10/1525-D revision 5 + + + Device complies with SPI-5 T10/1525-D revision 6 + + + Device complies with SPI-5 ANSI INCITS 367-2003 + + + Device complies with SAS (no version claimed) + + + Device complies with SAS T10/1562-D revision 01 + + + Device complies with SAS T10/1562-D revision 03 + + + Device complies with SAS T10/1562-D revision 04 + + + Device complies with SAS T10/1562-D revision 05 + + + Device complies with SAS ANSI INCITS 376-2003 + + + Device complies with SAS-1.1 (no version claimed) + + + Device complies with SAS-1.1 T10/1601-D revision 9 + + + Device complies with SAS-1.1 T10/1601-D revision 10 + + + Device complies with SAS-1.1 ANSI INCITS 417-2006 + + + Device complies with SAS-1.1 ISO/IEC 14776-151 + + + Device complies with SAS-2 (no version claimed) + + + Device complies with SAS-2 T10/1760-D revision 14 + + + Device complies with SAS-2 T10/1760-D revision 15 + + + Device complies with SAS-2 T10/1760-D revision 16 + + + Device complies with SAS-2 ANSI INCITS 457-2010 + + + Device complies with SAS-2.1 (no version claimed) + + + Device complies with SAS-2.1 T10/2125-D revision 04 + + + Device complies with SAS-2.1 T10/2125-D revision 06 + + + Device complies with SAS-2.1 T10/2125-D revision 07 + + + Device complies with SAS-2.1 ANSI INCITS 478-2011 + + + Device complies with SAS-2.1 ANSI INCITS 478-2011 w/ Amnd 1 ANSI INCITS 478/AM1-2014 + + + Device complies with SAS-2.1 ISO/IEC 14776-153 + + + Device complies with SAS-3 (no version claimed) + + + Device complies with SAS-3 T10/BSR INCITS 519 revision 05a + + + Device complies with SAS-3 T10/BSR INCITS 519 revision 06 + + + Device complies with SAS-3 ANSI INCITS 519-2014 + + + Device complies with SAS-4 (no version claimed) + + + Device complies with FC-PH (no version claimed) + + + Device complies with FC-PH ANSI INCITS 230-1994 + + + Device complies with FC-PH ANSI INCITS 230-1994 with Amnd 1 ANSI INCITS 230/AM1-1996 + + + Device complies with FC-AL (no version claimed) + + + Device complies with FC-AL ANSI INCITS 272-1996 + + + Device complies with FC-AL-2 (no version claimed) + + + Device complies with FC-AL-2 T11/1133-D revision 7.0 + + + Device complies with FC-AL-2 ANSI INCITS 332-1999 with AM1-2003 & AM2-2006 + + + Device complies with FC-AL-2 ANSI INCITS 332-1999 with Amnd 2 AM2-2006 + + + Device complies with FC-AL-2 ISO/IEC 14165-122 with AM1 & AM2 + + + Device complies with FC-AL-2 ANSI INCITS 332-1999 + + + Device complies with FC-AL-2 ANSI INCITS 332-1999 with Amnd 1 AM1-2003 + + + Device complies with FC-PH-3 (no version claimed) + + + Device complies with FC-PH-3 ANSI INCITS 303-1998 + + + Device complies with FC-FS (no version claimed) + + + Device complies with FC-FS T11/1331-D revision 1.2 + + + Device complies with FC-FS T11/1331-D revision 1.7 + + + Device complies with FC-FS ANSI INCITS 373-2003 + + + Device complies with FC-FS ISO/IEC 14165-251 + + + Device complies with FC-PI (no version claimed) + + + Device complies with FC-PI ANSI INCITS 352-2002 + + + Device complies with FC-PI-2 (no version claimed) + + + Device complies with FC-PI-2 T11/1506-D revision 5.0 + + + Device complies with FC-PI-2 ANSI INCITS 404-2006 + + + Device complies with FC-FS-2 (no version claimed) + + + Device complies with FC-FS-2 ANSI INCITS 242-2007 + + + Device complies with FC-FS-2 ANSI INCITS 242-2007 with AM1 ANSI INCITS 242/AM1-2007 + + + Device complies with FC-LS (no version claimed) + + + Device complies with FC-LS T11/1620-D revision 1.62 + + + Device complies with FC-LS ANSI INCITS 433-2007 + + + Device complies with FC-SP (no version claimed) + + + Device complies with FC-SP T11/1570-D revision 1.6 + + + Device complies with FC-SP ANSI INCITS 426-2007 + + + Device complies with FC-PI-3 (no version claimed) + + + Device complies with FC-PI-3 T11/1625-D revision 2.0 + + + Device complies with FC-PI-3 T11/1625-D revision 2.1 + + + Device complies with FC-PI-3 T11/1625-D revision 4.0 + + + Device complies with FC-PI-3 ANSI INCITS 460-2011 + + + Device complies with FC-PI-4 (no version claimed) + + + Device complies with FC-PI-4 T11/1647-D revision 8.0 + + + Device complies with FC-PI-4 ANSI INCITS 450-2009 + + + Device complies with FC 10GFC (no version claimed) + + + Device complies with FC 10GFC ANSI INCITS 364-2003 + + + Device complies with FC 10GFC ISO/IEC 14165-116 + + + Device complies with FC 10GFC ISO/IEC 14165-116 with AM1 + + + Device complies with FC 10GFC ANSI INCITS 364-2003 with AM1 ANSI INCITS 364/AM1-2007 + + + Device complies with FC-SP-2 (no version claimed) + + + Device complies with FC-FS-3 (no version claimed) + + + Device complies with FC-FS-3 T11/1861-D revision 0.9 + + + Device complies with FC-FS-3 T11/1861-D revision 1.0 + + + Device complies with FC-FS-3 T11/1861-D revision 1.10 + + + Device complies with FC-FS-3 ANSI INCITS 470-2011 + + + Device complies with FC-LS-2 (no version claimed) + + + Device complies with FC-LS-2 T11/2103-D revision 2.11 + + + Device complies with FC-LS-2 T11/2103-D revision 2.21 + + + Device complies with FC-LS-2 ANSI INCITS 477-2011 + + + Device complies with FC-PI-5 (no version claimed) + + + Device complies with FC-PI-5 T11/2118-D revision 2.00 + + + Device complies with FC-PI-5 T11/2118-D revision 3.00 + + + Device complies with FC-PI-5 T11/2118-D revision 6.00 + + + Device complies with FC-PI-5 T11/2118-D revision 6.10 + + + Device complies with FC-PI-5 ANSI INCITS 479-2011 + + + Device complies with FC-PI-6 (no version claimed) + + + Device complies with FC-FS-4 (no version claimed) + + + Device complies with FC-LS-3 (no version claimed) + + + Device complies with FC-SCM (no version claimed) + + + Device complies with FC-SCM T11/1824DT revision 1.0 + + + Device complies with FC-SCM T11/1824DT revision 1.1 + + + Device complies with FC-SCM T11/1824DT revision 1.4 + + + Device complies with FC-SCM INCITS TR-47 2012 + + + Device complies with FC-DA-2 (no version claimed) + + + Device complies with FC-DA-2 T11/1870DT revision 1.04 + + + Device complies with FC-DA-2 T11/1870DT revision 1.06 + + + Device complies with FC-DA-2 INCITS TR-49 2012 + + + Device complies with FC-DA (no version claimed) + + + Device complies with FC-DA T11/1513-DT revision 3.1 + + + Device complies with FC-DA ANSI INCITS TR-36 2004 + + + Device complies with FC-DA ISO/IEC 14165-341 + + + Device complies with FC-Tape (no version claimed) + + + Device complies with FC-Tape T11/1315 revision 1.16 + + + Device complies with FC-Tape T11/1315 revision 1.17 + + + Device complies with FC-Tape ANSI INCITS TR-24 1999 + + + Device complies with FC-FLA (no version claimed) + + + Device complies with FC-FLA T11/1235 revision 7 + + + Device complies with FC-FLA ANSI INCITS TR-20 1998 + + + Device complies with FC-PLDA (no version claimed) + + + Device complies with FC-PLDA T11/1162 revision 2.1 + + + Device complies with FC-PLDA ANSI INCITS TR-19 1998 + + + Device complies with SSA-PH2 (no version claimed) + + + Device complies with SSA-PH2 T10.1/1145-D revision 09c + + + Device complies with SSA-PH2 ANSI INCITS 293-1996 + + + Device complies with SSA-PH3 (no version claimed) + + + Device complies with SSA-PH3 T10.1/1146-D revision 05b + + + Device complies with SSA-PH3 ANSI INCITS 307-1998 + + + Device complies with IEEE 1394 (no version claimed) + + + Device complies with ANSI IEEE 1394-1995 + + + Device complies with IEEE 1394a (no version claimed) + + + Device complies with IEEE 1394b (no version claimed) + + + Device complies with ATA/ATAPI-6 (no version claimed) + + + Device complies with ATA/ATAPI-6 ANSI INCITS 361-2002 + + + Device complies with ATA/ATAPI-7 (no version claimed) + + + Device complies with ATA/ATAPI-7 T13/1532-D revision 3 + + + Device complies with ATA/ATAPI-7 ANSI INCITS 397-2005 + + + Device complies with ATA/ATAPI-7 ISO/IEC 24739 + + + Device complies with ATA/ATAPI-8 ATA8-AAM (no version claimed) + + + Device complies with ATA/ATAPI-8 ATA8-APT Parallel Transport (no version claimed) + + + Device complies with ATA/ATAPI-8 ATA8-AST Serial Transport (no version claimed) + + + Device complies with ATA/ATAPI-8 ATA8-ACS ATA/ATAPI Command Set (no version claimed) + + + Device complies with ATA/ATAPI-8 ATA8-AAM ANSI INCITS 451-2008 + + + Device complies with ATA/ATAPI-8 ATA8-ACS ANSI INCITS 452-2009 w/ Amendment 1 + + + Device complies with Universal Serial Bus Specification, Revision 1.1 + + + Device complies with Universal Serial Bus Specification, Revision 2.0 + + + Device complies with USB Mass Storage Class Bulk-Only Transport, Revision 1.0 + + + Device complies with UAS (no version claimed) + + + Device complies with UAS T10/2095-D revision 02 + + + Device complies with UAS T10/2095-D revision 04 + + + Device complies with UAS ANSI INCITS 471-2010 + + + Device complies with UAS ISO/IEC 14776-251:2014 + + + Device complies with ACS-2 (no version claimed) + + + Device complies with ACS-2 ANSI INCITS 482-2013 + + + Device complies with ACS-3 (no version claimed) + + + Device complies with UAS-2 (no version claimed) + + + Device complies with SAT (no version claimed) + + + Device complies with SAT T10/1711-D revision 8 + + + Device complies with SAT T10/1711-D revision 9 + + + Device complies with SAT ANSI INCITS 431-2007 + + + Device complies with SAT-2 (no version claimed) + + + Device complies with SAT-2 T10/1826-D revision 06 + + + Device complies with SAT-2 T10/1826-D revision 09 + + + Device complies with SAT-2 ANSI INCITS 465-2010 + + + Device complies with SAT-3 (no version claimed) + + + Device complies with SAT-3 T10/BSR INCITS 517 revision 4 + + + Device complies with SAT-3 T10/BSR INCITS 517 revision 7 + + + Device complies with SAT-3 ANSI INCITS 517-2015 + + + Device complies with SAT-4 (no version claimed) + + + Device complies with SPL (no version claimed) + + + Device complies with SPL T10/2124-D revision 6a + + + Device complies with SPL T10/2124-D revision 7 + + + Device complies with SPL ANSI INCITS 476-2011 + + + Device complies with SPL ANSI INCITS 476-2011 + SPL AM1 INCITS 476/AM1 2012 + + + Device complies with SPL ISO/IEC 14776-261:2012 + + + Device complies with SPL-2 (no version claimed) + + + Device complies with SPL-2 T10/BSR INCITS 505 revision 4 + + + Device complies with SPL-2 T10/BSR INCITS 505 revision 5 + + + Device complies with SPL-2 ANSI INCITS 505-2013 + + + Device complies with SPL-3 (no version claimed) + + + Device complies with SPL-3 T10/BSR INCITS 492 revision 6 + + + Device complies with SPL-3 T10/BSR INCITS 492 revision 7 + + + Device complies with SPL-3 ANSI INCITS 492-2015 + + + Device complies with SPL-4 (no version claimed) + + + Device complies with SOP (no version claimed) + + + Device complies with SOP T10/BSR INCITS 489 revision 4 + + + Device complies with SOP T10/BSR INCITS 489 revision 5 + + + Device complies with SOP ANSI INCITS 489-2014 + + + Device complies with PQI (no version claimed) + + + Device complies with PQI T10/BSR INCITS 490 revision 6 + + + Device complies with PQI T10/BSR INCITS 490 revision 7 + + + Device complies with PQI ANSI INCITS 490-2014 + + + Device complies with SOP-2 (no version claimed) + + + Device complies with PQI-2 (no version claimed) + + + Device complies with IEEE 1667 (no version claimed) + + + Device complies with IEEE 1667-2006 + + + Device complies with IEEE 1667-2009 + + + Device complies with unknown standard code 0x{0:X4} + + + Quantum vendor-specific information: + + + Product family is not specified + + + Product family is 2.6 GB + + + Product family is 6.0 GB + + + Product family is 10.0/20.0 GB + + + Product family is 20.0/40.0 GB + + + Product family is 15.0/30.0 GB + + + Product family: {0} + + + Release firmware: {0} + + + Firmware version: {0}.{1} + + + EEPROM format version: {0}.{1} + + + Firmware personality: {0} + + + Firmware sub-personality: {0} + + + Tape directory format version: {0} + + + Controller hardware version: {0} + + + Drive EEPROM version: {0} + + + Drive hardware version: {0} + + + Media loader firmware version: {0} + + + Media loader hardware version: {0} + + + Media loader mechanical version: {0} + + + Library is present + + + Media loader is present + + + Module revision: {0} + + + IBM vendor-specific information: + + + Performance is not limited + + + Performance is limited using factor {0} + + + Automation is disabled + + + IBM OEM Specific Field: {0} + + + HP vendor-specific information: + + + Device supports WORM version {0} + + + Device supports Tape Disaster Recovery + + + Seagate vendor-specific information: + + + Drive copyright: {0} + + + Drive servo part number: {0} + + + Drive is flashed with Kreon firmware {0}. + + + Vendor's device type modifier = 0x{0:X2} + + + Reserved byte 5, bits 2 to 1 = 0x{0:X2} + + + Reserved byte 56, bits 7 to 4 = 0x{0:X2} + + + Reserved byte 57 = 0x{0:X2} + + + Reserved bytes 74 to 95 + + + Vendor-specific bytes 47 to 55 + + + Vendor-specific bytes 36 to 55 + + + Hi-MD device. + + + Hi-MD specific bytes 44 to 55 + + + Vendor-specific bytes 96 to {0} + + \ No newline at end of file diff --git a/Aaru.Decoders/MMC/CID.cs b/Aaru.Decoders/MMC/CID.cs new file mode 100644 index 000000000..1884b2b7d --- /dev/null +++ b/Aaru.Decoders/MMC/CID.cs @@ -0,0 +1,168 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CID.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes MultiMediaCard CID. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.MMC; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnassignedField.Global")] +public class CID +{ + public byte ApplicationID; + public byte CRC; + public byte DeviceType; + public byte Manufacturer; + public byte ManufacturingDate; + public string ProductName; + public byte ProductRevision; + public uint ProductSerialNumber; +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static partial class Decoders +{ + public static CID DecodeCID(uint[] response) + { + if(response?.Length != 4) return null; + + var data = new byte[16]; + + byte[] tmp = BitConverter.GetBytes(response[0]); + Array.Copy(tmp, 0, data, 0, 4); + tmp = BitConverter.GetBytes(response[1]); + Array.Copy(tmp, 0, data, 4, 4); + tmp = BitConverter.GetBytes(response[2]); + Array.Copy(tmp, 0, data, 8, 4); + tmp = BitConverter.GetBytes(response[3]); + Array.Copy(tmp, 0, data, 12, 4); + + return DecodeCID(data); + } + + public static CID DecodeCID(byte[] response) + { + if(response?.Length != 16) return null; + + var cid = new CID + { + Manufacturer = response[0], + DeviceType = (byte)(response[1] & 0x03), + ProductRevision = response[9], + ProductSerialNumber = Swapping.Swap(BitConverter.ToUInt32(response, 10)), + ManufacturingDate = response[14], + CRC = (byte)((response[15] & 0xFE) >> 1) + }; + + var tmp = new byte[6]; + Array.Copy(response, 3, tmp, 0, 6); + cid.ProductName = StringHandlers.CToString(tmp); + + return cid; + } + + public static string PrettifyCID(CID cid) + { + if(cid == null) return null; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MultiMediaCard_Device_Identification_Register); + sb.AppendFormat("\t" + Localization.Manufacturer_0, VendorString.Prettify(cid.Manufacturer)).AppendLine(); + + switch(cid.DeviceType) + { + case 0: + sb.AppendLine("\t" + Localization.Removable_device); + + break; + case 1: + sb.AppendLine("\t" + Localization.BGA_device); + + break; + case 2: + sb.AppendLine("\t" + Localization.POP_device); + + break; + } + + sb.AppendFormat("\t" + Localization.Application_ID_0, cid.ApplicationID).AppendLine(); + sb.AppendFormat("\t" + Localization.Product_name_0, cid.ProductName).AppendLine(); + + sb.AppendFormat("\t" + Localization.Product_revision_0_1, + (cid.ProductRevision & 0xF0) >> 4, + cid.ProductRevision & 0x0F) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Product_serial_number_0, cid.ProductSerialNumber).AppendLine(); + + string year = (cid.ManufacturingDate & 0x0F) switch + { + 0 => Localization._1997_or_2013, + 1 => Localization._1998_or_2014, + 2 => Localization._1999_or_2015, + 3 => Localization._2000_or_2016, + 4 => Localization._2001_or_2017, + 5 => Localization._2002_or_2018, + 6 => Localization._2003_or_2019, + 7 => Localization._2004_or_2020, + 8 => Localization._2005_or_2021, + 9 => Localization._2006_or_2022, + 10 => Localization._2007_or_2023, + 11 => Localization._2008_or_2024, + 12 => Localization._2009_or_2025, + 13 => "2010", + 14 => "2011", + 15 => "2012", + _ => "" + }; + + sb.AppendFormat("\t" + Localization.Device_manufactured_month_0_of_1, (cid.ManufacturingDate & 0xF0) >> 4, year) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.CID_CRC_0, cid.CRC).AppendLine(); + + return sb.ToString(); + } + + public static string PrettifyCID(uint[] response) => PrettifyCID(DecodeCID(response)); + + public static string PrettifyCID(byte[] response) => PrettifyCID(DecodeCID(response)); +} \ No newline at end of file diff --git a/Aaru.Decoders/MMC/CSD.cs b/Aaru.Decoders/MMC/CSD.cs new file mode 100644 index 000000000..e9e9cfe56 --- /dev/null +++ b/Aaru.Decoders/MMC/CSD.cs @@ -0,0 +1,613 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CSD.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes MultiMediaCard CSD. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.MMC; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class CSD +{ + public ushort Classes; + public bool ContentProtection; + public bool Copy; + public byte CRC; + public byte DefaultECC; + public bool DSRImplemented; + public byte ECC; + public byte EraseGroupSize; + public byte EraseGroupSizeMultiplier; + public byte FileFormat; + public bool FileFormatGroup; + public byte NSAC; + public bool PermanentWriteProtect; + public byte ReadBlockLength; + public byte ReadCurrentAtVddMax; + public byte ReadCurrentAtVddMin; + public bool ReadMisalignment; + public bool ReadsPartialBlocks; + public ushort Size; + public byte SizeMultiplier; + public byte Speed; + public byte Structure; + public byte TAAC; + public bool TemporaryWriteProtect; + public byte Version; + public byte WriteBlockLength; + public byte WriteCurrentAtVddMax; + public byte WriteCurrentAtVddMin; + public bool WriteMisalignment; + public bool WriteProtectGroupEnable; + public byte WriteProtectGroupSize; + public bool WritesPartialBlocks; + public byte WriteSpeedFactor; +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static partial class Decoders +{ + public static CSD DecodeCSD(uint[] response) + { + if(response?.Length != 4) return null; + + var data = new byte[16]; + + byte[] tmp = BitConverter.GetBytes(response[0]); + Array.Copy(tmp, 0, data, 0, 4); + tmp = BitConverter.GetBytes(response[1]); + Array.Copy(tmp, 0, data, 4, 4); + tmp = BitConverter.GetBytes(response[2]); + Array.Copy(tmp, 0, data, 8, 4); + tmp = BitConverter.GetBytes(response[3]); + Array.Copy(tmp, 0, data, 12, 4); + + return DecodeCSD(data); + } + + public static CSD DecodeCSD(byte[] response) + { + if(response?.Length != 16) return null; + + return new CSD + { + Structure = (byte)((response[0] & 0xC0) >> 6), + Version = (byte)((response[0] & 0x3C) >> 2), + TAAC = response[1], + NSAC = response[2], + Speed = response[3], + Classes = (ushort)((response[4] << 4) + ((response[5] & 0xF0) >> 4)), + ReadBlockLength = (byte)(response[5] & 0x0F), + ReadsPartialBlocks = (response[6] & 0x80) == 0x80, + WriteMisalignment = (response[6] & 0x40) == 0x40, + ReadMisalignment = (response[6] & 0x20) == 0x20, + DSRImplemented = (response[6] & 0x10) == 0x10, + Size = (ushort)(((response[6] & 0x03) << 10) + (response[7] << 2) + ((response[8] & 0xC0) >> 6)), + ReadCurrentAtVddMin = (byte)((response[8] & 0x38) >> 3), + ReadCurrentAtVddMax = (byte)(response[8] & 0x07), + WriteCurrentAtVddMin = (byte)((response[9] & 0xE0) >> 5), + WriteCurrentAtVddMax = (byte)((response[9] & 0x1C) >> 2), + SizeMultiplier = (byte)(((response[9] & 0x03) << 1) + ((response[10] & 0x80) >> 7)), + EraseGroupSize = (byte)((response[10] & 0x7C) >> 2), + EraseGroupSizeMultiplier = (byte)(((response[10] & 0x03) << 3) + ((response[11] & 0xE0) >> 5)), + WriteProtectGroupSize = (byte)(response[11] & 0x1F), + WriteProtectGroupEnable = (response[12] & 0x80) == 0x80, + DefaultECC = (byte)((response[12] & 0x60) >> 5), + WriteSpeedFactor = (byte)((response[12] & 0x1C) >> 2), + WriteBlockLength = (byte)(((response[12] & 0x03) << 2) + ((response[13] & 0xC0) >> 6)), + WritesPartialBlocks = (response[13] & 0x20) == 0x20, + ContentProtection = (response[13] & 0x01) == 0x01, + FileFormatGroup = (response[14] & 0x80) == 0x80, + Copy = (response[14] & 0x40) == 0x40, + PermanentWriteProtect = (response[14] & 0x20) == 0x20, + TemporaryWriteProtect = (response[14] & 0x10) == 0x10, + FileFormat = (byte)((response[14] & 0x0C) >> 2), + ECC = (byte)(response[14] & 0x03), + CRC = (byte)((response[15] & 0xFE) >> 1) + }; + } + + public static string PrettifyCSD(CSD csd) + { + if(csd == null) return null; + + double unitFactor = 0; + double multiplier = 0; + var unit = ""; + + var sb = new StringBuilder(); + sb.AppendLine(Localization.MultiMediaCard_Device_Specific_Data_Register_); + + switch(csd.Structure) + { + case 0: + sb.AppendLine("\t" + Localization.Register_version_1_0); + + break; + case 1: + sb.AppendLine("\t" + Localization.Register_version_1_1); + + break; + case 2: + sb.AppendLine("\t" + Localization.Register_version_1_2); + + break; + case 3: + sb.AppendLine("\t" + + Localization.Register_version_is_defined_in_Extended_Device_Specific_Data_Register); + + break; + } + + switch(csd.TAAC & 0x07) + { + case 0: + unit = Localization.unit_ns; + unitFactor = 1; + + break; + case 1: + unit = Localization.unit_ns; + unitFactor = 10; + + break; + case 2: + unit = Localization.unit_ns; + unitFactor = 100; + + break; + case 3: + unit = Localization.unit_μs; + unitFactor = 1; + + break; + case 4: + unit = Localization.unit_μs; + unitFactor = 10; + + break; + case 5: + unit = Localization.unit_μs; + unitFactor = 100; + + break; + case 6: + unit = Localization.unit_ms; + unitFactor = 1; + + break; + case 7: + unit = Localization.unit_ms; + unitFactor = 10; + + break; + } + + multiplier = ((csd.TAAC & 0x78) >> 3) switch + { + 0 => 0, + 1 => 1, + 2 => 1.2, + 3 => 1.3, + 4 => 1.5, + 5 => 2, + 6 => 2.5, + 7 => 3, + 8 => 3.5, + 9 => 4, + 10 => 4.5, + 11 => 5, + 12 => 5.5, + 13 => 6, + 14 => 7, + 15 => 8, + _ => multiplier + }; + + double result = unitFactor * multiplier; + sb.AppendFormat("\t" + Localization.Asynchronous_data_access_time_is_0_1, result, unit).AppendLine(); + + sb.AppendFormat("\t" + Localization.Clock_dependent_part_of_data_access_is_0_clock_cycles, csd.NSAC * 100) + .AppendLine(); + + unit = Localization.unit_MHz; + + switch(csd.Speed & 0x07) + { + case 0: + unitFactor = 0.1; + + break; + case 1: + unitFactor = 1; + + break; + case 2: + unitFactor = 10; + + break; + case 3: + unitFactor = 100; + + break; + default: + unit = Localization.unit_unknown; + unitFactor = 0; + + break; + } + + multiplier = ((csd.Speed & 0x78) >> 3) switch + { + 0 => 0, + 1 => 1, + 2 => 1.2, + 3 => 1.3, + 4 => 1.5, + 5 => 2, + 6 => 2.6, + 7 => 3, + 8 => 3.5, + 9 => 4, + 10 => 4.5, + 11 => 5.2, + 12 => 5.5, + 13 => 6, + 14 => 7, + 15 => 8, + _ => multiplier + }; + + result = unitFactor * multiplier; + sb.AppendFormat("\t" + Localization.Device_s_clock_frequency_0_1, result, unit).AppendLine(); + + unit = ""; + + for(int cl = 0, mask = 1; cl <= 11; cl++, mask <<= 1) + if((csd.Classes & mask) == mask) + unit += $" {cl}"; + + sb.AppendFormat("\t" + Localization.Device_support_command_classes_0, unit).AppendLine(); + + if(csd.ReadBlockLength == 15) + sb.AppendLine("\t" + Localization.Read_block_length_size_is_defined_in_extended_CSD); + else + { + sb.AppendFormat("\t" + Localization.Read_block_length_is_0_bytes, Math.Pow(2, csd.ReadBlockLength)) + .AppendLine(); + } + + if(csd.ReadsPartialBlocks) sb.AppendLine("\t" + Localization.Device_allows_reading_partial_blocks); + + if(csd.WriteMisalignment) sb.AppendLine("\t" + Localization.Write_commands_can_cross_physical_block_boundaries); + + if(csd.ReadMisalignment) sb.AppendLine("\t" + Localization.Read_commands_can_cross_physical_block_boundaries); + + if(csd.DSRImplemented) sb.AppendLine("\t" + Localization.Device_implements_configurable_driver_stage); + + if(csd.Size == 0xFFF) + { + sb.AppendLine("\t" + + Localization + .Device_may_be_bigger_than_2GiB_and_have_its_real_size_defined_in_the_extended_CSD); + } + + result = (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2); + sb.AppendFormat("\t" + Localization.Device_has_0_blocks, (int)result).AppendLine(); + + result = (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2) * Math.Pow(2, csd.ReadBlockLength); + + switch(result) + { + case > 1073741824: + sb.AppendFormat("\t" + Localization.Device_has_0_GiB, result / 1073741824.0).AppendLine(); + + break; + case > 1048576: + sb.AppendFormat("\t" + Localization.Device_has_0_MiB, result / 1048576.0).AppendLine(); + + break; + case > 1024: + sb.AppendFormat("\t" + Localization.Device_has_0_KiB, result / 1024.0).AppendLine(); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_has_0_bytes, result).AppendLine(); + + break; + } + + switch(csd.ReadCurrentAtVddMin & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_0_5mA_for_reading_at_minimum_voltage); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_1mA_for_reading_at_minimum_voltage); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_5mA_for_reading_at_minimum_voltage); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_10mA_for_reading_at_minimum_voltage); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_25mA_for_reading_at_minimum_voltage); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_35mA_for_reading_at_minimum_voltage); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_60mA_for_reading_at_minimum_voltage); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_100mA_for_reading_at_minimum_voltage); + + break; + } + + switch(csd.ReadCurrentAtVddMax & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_1mA_for_reading_at_maximum_voltage); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_5mA_for_reading_at_maximum_voltage); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_10mA_for_reading_at_maximum_voltage); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_25mA_for_reading_at_maximum_voltage); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_35mA_for_reading_at_maximum_voltage); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_45mA_for_reading_at_maximum_voltage); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_80mA_for_reading_at_maximum_voltage); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_200mA_for_reading_at_maximum_voltage); + + break; + } + + switch(csd.WriteCurrentAtVddMin & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_0_5mA_for_writing_at_minimum_voltage); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_1mA_for_writing_at_minimum_voltage); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_5mA_for_writing_at_minimum_voltage); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_10mA_for_writing_at_minimum_voltage); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_25mA_for_writing_at_minimum_voltage); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_35mA_for_writing_at_minimum_voltage); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_60mA_for_writing_at_minimum_voltage); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_100mA_for_writing_at_minimum_voltage); + + break; + } + + switch(csd.WriteCurrentAtVddMax & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_1mA_for_writing_at_maximum_voltage); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_5mA_for_writing_at_maximum_voltage); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_10mA_for_writing_at_maximum_voltage); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_25mA_for_writing_at_maximum_voltage); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_35mA_for_writing_at_maximum_voltage); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_45mA_for_writing_at_maximum_voltage); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_80mA_for_writing_at_maximum_voltage); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_200mA_for_writing_at_maximum_voltage); + + break; + } + + // TODO: Check specification + unitFactor = Convert.ToDouble(csd.EraseGroupSize); + multiplier = Convert.ToDouble(csd.EraseGroupSizeMultiplier); + result = (unitFactor + 1) * (multiplier + 1); + sb.AppendFormat("\t" + Localization.Device_can_erase_a_minimum_of_0_blocks_at_a_time, (int)result).AppendLine(); + + if(csd.WriteProtectGroupEnable) + { + sb.AppendLine("\t" + Localization.Device_can_write_protect_regions); + + // TODO: Check specification + // unitFactor = Convert.ToDouble(csd.WriteProtectGroupSize); + + sb.AppendFormat("\t" + Localization.Device_can_write_protect_a_minimum_of_0_blocks_at_a_time, + (int)(result + 1)) + .AppendLine(); + } + else + sb.AppendLine("\t" + Localization.Device_cant_write_protect_regions); + + switch(csd.DefaultECC) + { + case 0: + sb.AppendLine("\t" + Localization.Device_uses_no_ECC_by_default); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_BCH_542_512_ECC_by_default); + + break; + case 2: + sb.AppendFormat("\t" + Localization.Device_uses_unknown_ECC_code_0_by_default, csd.DefaultECC) + .AppendLine(); + + break; + } + + sb.AppendFormat("\t" + Localization.Writing_is_0_times_slower_than_reading, Math.Pow(2, csd.WriteSpeedFactor)) + .AppendLine(); + + if(csd.WriteBlockLength == 15) + sb.AppendLine("\t" + Localization.Write_block_length_size_is_defined_in_extended_CSD); + else + { + sb.AppendFormat("\t" + Localization.Write_block_length_is_0_bytes, Math.Pow(2, csd.WriteBlockLength)) + .AppendLine(); + } + + if(csd.WritesPartialBlocks) sb.AppendLine("\t" + Localization.Device_allows_writing_partial_blocks); + + if(csd.ContentProtection) sb.AppendLine("\t" + Localization.Device_supports_content_protection); + + if(!csd.Copy) sb.AppendLine("\t" + Localization.Device_contents_are_original); + + if(csd.PermanentWriteProtect) sb.AppendLine("\t" + Localization.Device_is_permanently_write_protected); + + if(csd.TemporaryWriteProtect) sb.AppendLine("\t" + Localization.Device_is_temporarily_write_protected); + + if(!csd.FileFormatGroup) + { + switch(csd.FileFormat) + { + case 0: + sb.AppendLine("\t" + Localization.Device_is_formatted_like_a_hard_disk); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_is_formatted_like_a_floppy_disk_using_Microsoft_FAT); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_Universal_File_Format); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_uses_unknown_file_format_code_0, csd.FileFormat) + .AppendLine(); + + break; + } + } + else + { + sb.AppendFormat("\t" + Localization.Device_uses_unknown_file_format_code_0_and_file_format_group_1, + csd.FileFormat) + .AppendLine(); + } + + switch(csd.ECC) + { + case 0: + sb.AppendLine("\t" + Localization.Device_currently_uses_no_ECC); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_currently_uses_BCH_542_512_ECC); + + break; + case 2: + sb.AppendFormat("\t" + Localization.Device_currently_uses_unknown_ECC_code_0, csd.DefaultECC) + .AppendLine(); + + break; + } + + sb.AppendFormat("\t" + Localization.CSD_CRC_0, csd.CRC).AppendLine(); + + return sb.ToString(); + } + + public static string PrettifyCSD(uint[] response) => PrettifyCSD(DecodeCSD(response)); + + public static string PrettifyCSD(byte[] response) => PrettifyCSD(DecodeCSD(response)); +} \ No newline at end of file diff --git a/Aaru.Decoders/MMC/ExtendedCSD.cs b/Aaru.Decoders/MMC/ExtendedCSD.cs new file mode 100644 index 000000000..7cc814fb3 --- /dev/null +++ b/Aaru.Decoders/MMC/ExtendedCSD.cs @@ -0,0 +1,1430 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ExtendedCSD.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes MultiMediaCard extended CSD. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable InconsistentNaming + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text; + +namespace Aaru.Decoders.MMC; + +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnassignedField.Global")] +[StructLayout(LayoutKind.Sequential, Pack = 1)] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public class ExtendedCSD +{ + public byte AccessSize; + public byte BackgroundOperationsStatus; + public BackgroundOperationsSupport BackgroundOperationsSupport; + public byte BadBlockManagementMode; + public byte BarrierControl; + public byte BarrierSupport; + public BootAreaWriteProtectionRegister BootAreaWriteProtectionRegister; + public byte BootBusConditions; + public BootConfigProtection BootConfigProtection; + public BootInformation BootInformation; + public byte BootPartitionSize; + public byte BootWriteProtectionStatus; + public byte BusWidth; + public byte CacheControl; + public byte CacheFlushing; + public CacheFlushingPolicy CacheFlushingPolicy; + public uint CacheSize; + public byte Class6CommandsControl; + public byte CMDQueuingDepth; + public CMDQueuingSupport CMDQueuingSupport; + public byte CommandQueueModeEnable; + public byte CommandSet; + public byte CommandSetRevision; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] + public byte[] ContextConfiguration; + public byte ContextManagementCaps; + public uint CorrectlyProgrammedSectors; + public DataTagSupport DataTagSupport; + public byte DeviceLifeEstimationTypeA; + public byte DeviceLifeEstimationTypeB; + public DeviceType DeviceType; + public ushort DeviceVersion; + public DriverStrength DriverStrength; + public byte DyncapNeeded; + public byte EnableBackgroundOperationsHandshake; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] EnhancedUserDataAreaSize; + public uint EnhancedUserDataStartAddress; + public byte ErasedMemoryContent; + public ushort ExceptionEventsControl; + public ushort ExceptionEventsStatus; + public ushort ExtendedPartitionsAttribute; + public ExtendedPartitionsSupport ExtendedPartitionsSupport; + public byte ExtendedSecurityCommandsError; + public uint FFUArgument; + public FFUFeatures FFUFeatures; + public byte FFUStatus; + public byte FirmwareConfiguration; + public ulong FirmwareVersion; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] GeneralPurposePartitionSize; + public byte GenericCMD6Timeout; + public HighCapacityEraseGroupDefinition HighCapacityEraseGroupDefinition; + public byte HighCapacityEraseTimeout; + public byte HighCapacityEraseUnitSize; + public byte HighCapacityWriteProtectGroupSize; + public byte HighSpeedInterfaceTiming; + public HPIFeatures HPIFeatures; + public byte HPIManagement; + public byte HWResetFunction; + public byte InitializationTimeAfterPartition; + public byte InitializationTimeoutAfterEmulationChange; + public byte LargeUnitSize; + public byte ManuallyStartBackgroundOperations; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] MaxEnhancedAreaSize; + public byte MaxPackedReadCommands; + public byte MaxPackedWriteCommands; + public uint MaxPreLoadingDataSize; + public byte MinimumReadPerformance26; + public byte MinimumReadPerformance26_4; + public byte MinimumReadPerformance52; + public byte MinimumReadPerformanceDDR52; + public byte MinimumWritePerformance26; + public byte MinimumWritePerformance26_4; + public byte MinimumWritePerformance52; + public byte MinimumWritePerformanceDDR52; + public byte ModeConfig; + public byte ModeOperationCodes; + public byte NativeSectorSize; + public uint NumberOfFWSectorsCorrectlyProgrammed; + public byte OperationCodesTimeout; + public byte OptimalReadSize; + public byte OptimalTrimUnitSize; + public byte OptimalWriteSize; + public byte OutOfInterruptBusyTiming; + public byte PackageCaseTemperatureControl; + public byte PackedCommandFailureIndex; + public byte PackedCommandStatus; + public byte PartitionConfiguration; + public byte PartitioningSetting; + public PartitioningSupport PartitioningSupport; + public byte PartitionsAttribute; + public byte PartitionSwitchingTime; + public byte PeriodicWakeUp; + public byte PowerClass; + public byte PowerClass26; + public byte PowerClass26_195; + public byte PowerClass52; + public byte PowerClass52_195; + public byte PowerClassDDR200; + public byte PowerClassDDR200_130; + public byte PowerClassDDR200_195; + public byte PowerClassDDR52; + public byte PowerClassDDR52_195; + public byte PowerOffNotification; + public byte PowerOffNotificationTimeout; + public byte PreEOLInformation; + public uint PreLoadingDataSize; + public byte ProductionStateAwareness; + public byte ProductionStateAwarenessTimeout; + public byte ProductStateAwarenessEnablement; + public byte ReliableWriteSectorCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] + public byte[] Reserved0; + public ushort Reserved1; + public byte Reserved10; + public byte Reserved11; + public byte Reserved12; + public byte Reserved13; + public byte Reserved14; + public byte Reserved15; + public byte Reserved16; + public byte Reserved17; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 177)] + public byte[] Reserved18; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] Reserved19; + public ushort Reserved2; + public byte Reserved3; + public byte Reserved4; + public byte Reserved5; + public byte Reserved6; + public byte Reserved7; + public byte Reserved8; + public byte Reserved9; + public byte Revision; + public byte RPMBSize; + public uint SectorCount; + public byte SectorSize; + public byte SectorSizeEmulation; + public byte SecureEraseMultiplier; + public SecureFeatureSupport SecureFeatureSupport; + public byte SecureRemovalType; + public byte SecureTRIMMultiplier; + public SecureWriteProtectInformation SecureWriteProtectInformation; + public byte SleepAwakeTimeout; + public byte SleepCurrentVcc; + public byte SleepCurrentVccQ; + public byte SleepNotificationTimeout; + public byte StartSanitizeOperation; + public byte StrobeSupport; + public byte Structure; + public DeviceSupportedCommandSets SupportedCommandSets; + public SupportedModes SupportedModes; + public byte SupportsProgramCxDInDDR; + public byte TagResourcesSize; + public byte TagUnitSize; + public byte TRIMMultiplier; + public UserAreaWriteProtectionRegister UserAreaWriteProtectionRegister; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] VendorHealthReport; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public byte[] VendorSpecific; + public byte WriteReliabilityParameterRegister; + public byte WriteReliabilitySettingRegister; +} + +[Flags] +public enum DeviceSupportedCommandSets : byte +{ + Standard = 1 << 0 +} + +[Flags] +public enum HPIFeatures : byte +{ + Supported = 1 << 0, + CMD12 = 1 << 1 +} + +[Flags] +public enum BackgroundOperationsSupport : byte +{ + Supported = 1 << 0 +} + +[Flags] +public enum DataTagSupport : byte +{ + Supported = 1 << 0 +} + +[Flags] +public enum ExtendedPartitionsSupport : byte +{ + SystemCode = 1 << 0, + NonPersistent = 1 << 1 +} + +[Flags] +public enum SupportedModes : byte +{ + FFU = 1 << 0, + VendorSpecific = 1 << 1 +} + +[Flags] +public enum FFUFeatures : byte +{ + SupportedModeOperationCodes = 1 << 0 +} + +[Flags] +public enum CMDQueuingSupport : byte +{ + Supported = 1 << 0 +} + +[Flags] +public enum CacheFlushingPolicy : byte +{ + FIFO = 1 << 0 +} + +[Flags] +public enum SecureFeatureSupport : byte +{ + Purge = 1 << 0, + Defective = 1 << 2, + Trim = 1 << 4, + Sanitize = 1 << 6 +} + +[Flags] +public enum BootInformation : byte +{ + Alternative = 1 << 0, + DDR = 1 << 1, + HighSpeed = 1 << 2 +} + +[Flags] +public enum SecureWriteProtectInformation : byte +{ + Supported = 1 << 0, + Enabled = 1 << 1 +} + +[Flags] +public enum DriverStrength : byte +{ + Type0 = 1 << 0, + Type1 = 1 << 1, + Type2 = 1 << 2, + Type3 = 1 << 3, + Type4 = 1 << 4 +} + +[Flags] +public enum DeviceType : byte +{ + HS_26 = 1 << 0, + HS_52 = 1 << 1, + HS_DDR_52 = 1 << 2, + HS_DDR_52_LV = 1 << 3, + HS200_18 = 1 << 4, + HS200_12 = 1 << 5, + HS400_18 = 1 << 6, + HS400_12 = 1 << 7 +} + +[Flags] +public enum BootConfigProtection : byte +{ + PowerCycle = 1 << 0, + Permanent = 1 << 4 +} + +[Flags] +public enum HighCapacityEraseGroupDefinition : byte +{ + Enabled = 1 << 0 +} + +[Flags] +public enum BootAreaWriteProtectionRegister : byte +{ + PowerOn = 1 << 0, + PowerOnArea2 = 1 << 1, + Permanent = 1 << 2, + PermanentArea2 = 1 << 3, + PermanentDisable = 1 << 4, + PowerOnDisable = 1 << 6, + Selected = 1 << 7 +} + +[Flags] +public enum UserAreaWriteProtectionRegister : byte +{ + ApplyPowerOn = 1 << 0, + ApplyPermanent = 1 << 2, + DisablePowerOn = 1 << 3, + DisablePermanent = 1 << 4, + DisableWriteProtect = 1 << 6, + DisablePassword = 1 << 7 +} + +[Flags] +public enum PartitioningSupport : byte +{ + Supported = 1 << 0, + Enhanced = 1 << 1, + Extended = 1 << 2 +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Decoders +{ + public static ExtendedCSD DecodeExtendedCSD(byte[] response) + { + if(response?.Length != 512) return null; + + var handle = GCHandle.Alloc(response, GCHandleType.Pinned); + var csd = (ExtendedCSD)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedCSD)); + handle.Free(); + + return csd; + } + + public static string PrettifyExtendedCSD(ExtendedCSD csd) + { + if(csd == null) return null; + + var sb = new StringBuilder(); + sb.AppendLine(Localization.MultiMediaCard_Extended_Device_Specific_Data_Register); + + double unit; + + if(csd.ExtendedSecurityCommandsError != 0) + { + sb.AppendFormat("\t" + Localization.Last_extended_security_error_was_0, csd.ExtendedSecurityCommandsError) + .AppendLine(); + } + + if(csd.SupportedCommandSets.HasFlag(DeviceSupportedCommandSets.Standard)) + sb.AppendLine("\t" + Localization.Device_supports_standard_MMC_command_set); + + if(((int)csd.SupportedCommandSets & 0xFE) != 0) + sb.AppendFormat("\t" + Localization.Device_supports_unknown_command_sets_0, (int)csd.SupportedCommandSets); + + if(csd.HPIFeatures.HasFlag(HPIFeatures.Supported)) + { + sb.AppendLine(csd.HPIFeatures.HasFlag(HPIFeatures.CMD12) + ? "\t" + Localization.Device_implements_HPI_using_CMD12 + : "\t" + Localization.Device_implements_HPI_using_CMD13); + } + + if(csd.BackgroundOperationsSupport.HasFlag(BackgroundOperationsSupport.Supported)) + sb.AppendLine("\t" + Localization.Device_supports_background_operations); + + sb.AppendFormat("\t" + Localization.Device_supports_a_maximum_of_0_packed_reads_and_1_packed_writes, + csd.MaxPackedReadCommands, + csd.MaxPackedWriteCommands) + .AppendLine(); + + if(csd.DataTagSupport.HasFlag(DataTagSupport.Supported)) + { + sb.AppendLine("\t" + Localization.Device_supports_Data_Tag); + + sb.AppendFormat("\t" + Localization.Tags_must_be_in_units_of_0_sectors, Math.Pow(2, csd.TagUnitSize)) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Tag_resources_size_is_0, csd.TagResourcesSize).AppendLine(); + } + + if(csd.ContextManagementCaps != 0) + { + sb.AppendFormat("\t" + Localization.Max_context_ID_is_0, csd.ContextManagementCaps & 0xF).AppendLine(); + + sb.AppendFormat("\t" + Localization.Large_unit_maximum_multiplier_is_0, + ((csd.ContextManagementCaps & 0x70) >> 4) + 1) + .AppendLine(); + } + + sb.AppendFormat("\t" + Localization.Large_unit_size_is_0_MiB, csd.LargeUnitSize + 1).AppendLine(); + + if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.NonPersistent)) + sb.AppendLine("\t" + Localization.Device_supports_non_persistent_extended_partitions); + + if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.SystemCode)) + sb.AppendLine("\t" + Localization.Device_supports_system_code_extended_partitions); + + if(csd.SupportedModes.HasFlag(SupportedModes.FFU)) + { + sb.AppendLine("\t" + Localization.Device_supports_FFU); + + if(csd.FFUFeatures.HasFlag(FFUFeatures.SupportedModeOperationCodes)) + + // todo public byte ModeOperationCodes + + { + if(csd.OperationCodesTimeout > 0) + { + unit = Math.Pow(2, csd.OperationCodesTimeout) * 100; + + switch(unit) + { + case > 1000000: + sb.AppendFormat("\t" + + Localization + .Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_codes_field_is_0_s, + unit / 1000000) + .AppendLine(); + + break; + case > 1000: + sb.AppendFormat("\t" + + Localization + .Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_codes_field_is_0_ms, + unit / 1000) + .AppendLine(); + + break; + default: + sb.AppendFormat("\t" + + Localization + .Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_codes_field_is_0_µs, + unit) + .AppendLine(); + + break; + } + } + } + } + + if(csd.SupportedModes.HasFlag(SupportedModes.VendorSpecific)) + sb.AppendLine("\t" + Localization.Device_supports_Vendor_Specific_Mode); + + if(csd.BarrierSupport == 0x01) sb.AppendLine("\t" + Localization.Device_supports_the_barrier_command); + + if(csd.CMDQueuingSupport.HasFlag(CMDQueuingSupport.Supported)) + { + sb.AppendFormat("\t" + Localization.Device_supports_command_queuing_with_a_depth_of_0, + csd.CMDQueuingDepth + 1) + .AppendLine(); + } + + sb.AppendFormat("\t" + Localization._0_firmware_sectors_correctly_programmed, + csd.NumberOfFWSectorsCorrectlyProgrammed) + .AppendLine(); + + switch(csd.DeviceLifeEstimationTypeB) + { + case 1: + sb.AppendLine("\t" + Localization.Device_used_between_zero_and_10_of_its_estimated_life_time); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_used_between_10_and_20_of_its_estimated_life_time); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_used_between_20_and_30_of_its_estimated_life_time); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_used_between_30_and_40_of_its_estimated_life_time); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_used_between_40_and_50_of_its_estimated_life_time); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_used_between_50_and_60_of_its_estimated_life_time); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_used_between_60_and_70_of_its_estimated_life_time); + + break; + case 8: + sb.AppendLine("\t" + Localization.Device_used_between_70_and_80_of_its_estimated_life_time); + + break; + case 9: + sb.AppendLine("\t" + Localization.Device_used_between_80_and_90_of_its_estimated_life_time); + + break; + case 10: + sb.AppendLine("\t" + Localization.Device_used_between_90_and_100_of_its_estimated_life_time); + + break; + case 11: + sb.AppendLine("\t" + Localization.Device_exceeded_its_maximum_estimated_life_time); + + break; + } + + switch(csd.DeviceLifeEstimationTypeA) + { + case 1: + sb.AppendLine("\t" + Localization.Device_used_between_zero_and_10_of_its_estimated_life_time); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_used_between_10_and_20_of_its_estimated_life_time); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_used_between_20_and_30_of_its_estimated_life_time); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_used_between_30_and_40_of_its_estimated_life_time); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_used_between_40_and_50_of_its_estimated_life_time); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_used_between_50_and_60_of_its_estimated_life_time); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_used_between_60_and_70_of_its_estimated_life_time); + + break; + case 8: + sb.AppendLine("\t" + Localization.Device_used_between_70_and_80_of_its_estimated_life_time); + + break; + case 9: + sb.AppendLine("\t" + Localization.Device_used_between_80_and_90_of_its_estimated_life_time); + + break; + case 10: + sb.AppendLine("\t" + Localization.Device_used_between_90_and_100_of_its_estimated_life_time); + + break; + case 11: + sb.AppendLine("\t" + Localization.Device_exceeded_its_maximum_estimated_life_time); + + break; + } + + switch(csd.PreEOLInformation) + { + case 1: + sb.AppendLine("\t" + Localization.Device_informs_its_in_good_health); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_informs_it_should_be_replaced_soon); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_informs_it_should_be_replace_immediately); + + break; + } + + if(csd.OptimalReadSize == 0) + sb.AppendLine("\t" + Localization.Device_does_not_report_an_optimal_read_size); + else + sb.AppendFormat("\t" + Localization.Optimal_read_size_is_0_KiB, 4 * csd.OptimalReadSize).AppendLine(); + + if(csd.OptimalWriteSize == 0) + sb.AppendLine("\t" + Localization.Device_does_not_report_an_optimal_write_size); + else + sb.AppendFormat("\t" + Localization.Optimal_write_size_is_0_KiB, 4 * csd.OptimalWriteSize).AppendLine(); + + if(csd.OptimalTrimUnitSize == 0) + sb.AppendLine("\t" + Localization.Device_does_not_report_an_optimal_trim_size); + else + { + sb.AppendFormat("\t" + Localization.Optimal_trim_size_is_0_KiB, + 4 * Math.Pow(2, csd.OptimalTrimUnitSize - 1)) + .AppendLine(); + } + + sb.AppendFormat("\t" + Localization.Device_version_0, csd.DeviceVersion).AppendLine(); + sb.AppendFormat("\t" + Localization.Firmware_version_0, csd.FirmwareVersion).AppendLine(); + + if(csd.CacheSize == 0) + sb.AppendLine("\t" + Localization.Device_has_no_cache); + else + sb.AppendFormat("\t" + Localization.Device_has_0_KiB_of_cache, csd.CacheSize / 8).AppendLine(); + + if(csd.GenericCMD6Timeout > 0) + { + sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_by_default_for_a_SWITCH_command, + csd.GenericCMD6Timeout * 10) + .AppendLine(); + } + + if(csd.PowerOffNotificationTimeout > 0) + { + sb.AppendFormat("\t" + + Localization + .Device_takes_a_maximum_of_0_by_default_to_power_off_from_a_SWITCH_command_notification, + csd.PowerOffNotificationTimeout * 10) + .AppendLine(); + } + + switch(csd.BackgroundOperationsStatus & 0x03) + { + case 0: + sb.AppendLine("\t" + Localization.Device_has_no_pending_background_operations); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_has_non_critical_operations_outstanding); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_has_performance_impacted_operations_outstanding); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_has_critical_operations_outstanding); + + break; + } + + sb.AppendFormat("\t" + Localization.Last_WRITE_MULTIPLE_command_correctly_programmed_0_sectors, + csd.CorrectlyProgrammedSectors) + .AppendLine(); + + if(csd.InitializationTimeAfterPartition > 0) + { + sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_for_initialization_after_partition, + csd.InitializationTimeAfterPartition * 100) + .AppendLine(); + } + + if(csd.CacheFlushingPolicy.HasFlag(CacheFlushingPolicy.FIFO)) + sb.AppendLine("\t" + Localization.Device_uses_a_FIFO_policy_for_cache_flushing); + + if(csd.TRIMMultiplier > 0) + { + sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_for_trimming_a_single_erase_group, + csd.TRIMMultiplier * 300) + .AppendLine(); + } + + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Sanitize)) + sb.AppendLine("\t" + Localization.Device_supports_the_sanitize_operation); + + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Trim)) + sb.AppendLine("\t" + Localization.Device_supports_supports_the_secure_and_insecure_trim_operations); + + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Defective)) + sb.AppendLine("\t" + Localization.Device_supports_automatic_erase_on_retired_defective_blocks); + + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Purge)) + sb.AppendLine("\t" + Localization.Device_supports_secure_purge_operations); + + if(csd.SecureEraseMultiplier > 0) + { + sb.AppendFormat("\t" + + Localization.Device_takes_a_maximum_of_0_ms_for_securely_erasing_a_single_erase_group, + csd.SecureEraseMultiplier * 300) + .AppendLine(); + } + + if(csd.SecureTRIMMultiplier > 0) + { + sb.AppendFormat("\t" + + Localization.Device_takes_a_maximum_of_0_ms_for_securely_trimming_a_single_erase_group, + csd.SecureTRIMMultiplier * 300) + .AppendLine(); + } + + if(csd.BootInformation.HasFlag(BootInformation.HighSpeed)) + sb.AppendLine("\t" + Localization.Device_supports_high_speed_timing_on_boot); + + if(csd.BootInformation.HasFlag(BootInformation.DDR)) + sb.AppendLine("\t" + Localization.Device_supports_dual_data_rate_on_boot); + + if(csd.BootInformation.HasFlag(BootInformation.Alternative)) + sb.AppendLine("\t" + Localization.Device_supports_alternative_boot_method); + + if(csd.BootPartitionSize > 0) + { + sb.AppendFormat("\t" + Localization.Device_has_a_0_KiB_boot_partition, csd.BootPartitionSize * 128) + .AppendLine(); + } + + if((csd.AccessSize & 0x0F) > 0) + { + sb.AppendFormat("\t" + Localization.Device_has_a_page_size_of_0_KiB, + 512 * Math.Pow(2, (csd.AccessSize & 0x0F) - 1) / 1024.0) + .AppendLine(); + } + + if(csd.HighCapacityEraseUnitSize > 0) + { + sb.AppendFormat("\t" + Localization.Device_erase_groups_are_0_KiB, csd.HighCapacityEraseUnitSize * 512) + .AppendLine(); + } + + if(csd.HighCapacityEraseTimeout > 0) + { + sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_for_erasing_a_single_erase_group, + csd.HighCapacityEraseTimeout * 300) + .AppendLine(); + } + + if(csd.HighCapacityWriteProtectGroupSize > 0) + { + sb.AppendFormat("\t" + Localization.Device_smallest_write_protect_group_is_made_of_0_erase_groups, + csd.HighCapacityWriteProtectGroupSize) + .AppendLine(); + } + + if(csd.SleepCurrentVcc > 0) + { + unit = Math.Pow(2, csd.SleepCurrentVcc); + + if(unit > 1000) + sb.AppendFormat("\t" + Localization.Device_uses_0_mA_on_Vcc_when_sleeping, unit / 1000).AppendLine(); + else + sb.AppendFormat("\t" + Localization.Device_uses_0_μA_on_Vcc_when_sleeping, unit).AppendLine(); + } + + if(csd.SleepCurrentVccQ > 0) + { + unit = Math.Pow(2, csd.SleepCurrentVccQ); + + if(unit > 1000) + sb.AppendFormat("\t" + Localization.Device_uses_0_mA_on_Vccq_when_sleeping, unit / 1000).AppendLine(); + else + sb.AppendFormat("\t" + Localization.Device_uses_0_μA_on_Vccq_when_sleeping, unit).AppendLine(); + } + + if(csd.ProductionStateAwarenessTimeout > 0) + { + unit = Math.Pow(2, csd.ProductionStateAwareness) * 100; + + switch(unit) + { + case > 1000000: + sb.AppendFormat("\t" + + Localization.Device_takes_a_maximum_of_0_s_to_switch_production_state_awareness, + unit / 1000000) + .AppendLine(); + + break; + case > 1000: + sb.AppendFormat("\t" + + Localization.Device_takes_a_maximum_of_0_ms_to_switch_production_state_awareness, + unit / 1000) + .AppendLine(); + + break; + default: + sb.AppendFormat("\t" + + Localization.Device_takes_a_maximum_of_0_μs_to_switch_production_state_awareness, + unit) + .AppendLine(); + + break; + } + } + + if(csd.SleepAwakeTimeout > 0) + { + unit = Math.Pow(2, csd.SleepAwakeTimeout) * 100; + + switch(unit) + { + case > 1000000: + sb.AppendFormat("\t" + + Localization + .Device_takes_a_maximum_of_0_ms_to_transition_between_sleep_and_standby_states, + unit / 1000000) + .AppendLine(); + + break; + case > 1000: + sb.AppendFormat("\t" + + Localization + .Device_takes_a_maximum_of_0_μs_to_transition_between_sleep_and_standby_states, + unit / 1000) + .AppendLine(); + + break; + default: + sb.AppendFormat("\t" + + Localization + .Device_takes_a_maximum_of_0_ns_to_transition_between_sleep_and_standby_states, + unit) + .AppendLine(); + + break; + } + } + + if(csd.SleepNotificationTimeout > 0) + { + unit = Math.Pow(2, csd.SleepNotificationTimeout) * 10; + + switch(unit) + { + case > 1000000: + sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_s_to_move_to_sleep_state, + unit / 1000000) + .AppendLine(); + + break; + case > 1000: + sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_to_move_to_sleep_state, + unit / 1000) + .AppendLine(); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_μs_to_move_to_sleep_state, unit) + .AppendLine(); + + break; + } + } + + sb.AppendFormat("\t" + Localization.Device_has_0_sectors, csd.SectorCount).AppendLine(); + + if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Supported)) + { + sb.AppendLine("\t" + Localization.Device_supports_secure_write_protection); + + if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Enabled)) + sb.AppendLine("\t" + Localization.Device_has_secure_write_protection_enabled); + } + + unit = csd.MinimumReadPerformance26 * 300; + + if(csd.MinimumReadPerformance26 == 0) + sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_reading_in_SDR_26Mhz_mode); + else + { + sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_26Mhz_mode, + unit / 1000) + .AppendLine(); + } + + unit = csd.MinimumReadPerformance26_4 * 300; + + if(csd.MinimumReadPerformance26_4 == 0) + sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_reading_in_SDR_26Mhz_4_bit_mode); + else + { + sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_26Mhz_4_bit_mode, + unit / 1000) + .AppendLine(); + } + + unit = csd.MinimumReadPerformance52 * 300; + + if(csd.MinimumReadPerformance52 == 0) + sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_reading_in_SDR_52Mhz_mode); + else + { + sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_52Mhz_mode, + unit / 1000) + .AppendLine(); + } + + unit = csd.MinimumReadPerformanceDDR52 * 600; + + if(csd.MinimumReadPerformanceDDR52 == 0) + sb.AppendLine("\t" + Localization.Device_cannot_achieve_4_8MB_s_reading_in_DDR_52Mhz_mode); + else + { + sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_reading_in_DDR_52Mhz_mode, + unit / 1000) + .AppendLine(); + } + + unit = csd.MinimumWritePerformance26 * 300; + + if(csd.MinimumWritePerformance26 == 0) + sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_writing_in_SDR_26Mhz_mode); + else + { + sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_26Mhz_mode, + unit / 1000) + .AppendLine(); + } + + unit = csd.MinimumWritePerformance26_4 * 300; + + if(csd.MinimumWritePerformance26_4 == 0) + sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_writing_in_SDR_26Mhz_4_bit_mode); + else + { + sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_26Mhz_4_bit_mode, + unit / 1000) + .AppendLine(); + } + + unit = csd.MinimumWritePerformance52 * 300; + + if(csd.MinimumWritePerformance52 == 0) + sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_writing_in_SDR_52Mhz_mode); + else + { + sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_52Mhz_mode, + unit / 1000) + .AppendLine(); + } + + unit = csd.MinimumWritePerformanceDDR52 * 600; + + if(csd.MinimumWritePerformanceDDR52 == 0) + sb.AppendLine("\t" + Localization.Device_cannot_achieve_4_8MB_s_writing_in_DDR_52Mhz_mode); + else + { + sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_writing_in_DDR_52Mhz_mode, + unit / 1000) + .AppendLine(); + } + + if(csd.PartitionSwitchingTime > 0) + { + sb.AppendFormat("\t" + Localization.Device_can_take_a_maximum_of_0_ms_when_switching_partitions, + csd.PartitionSwitchingTime * 10) + .AppendLine(); + } + + if(csd.OutOfInterruptBusyTiming > 0) + { + sb.AppendFormat("\t" + Localization.Device_can_take_a_maximum_of_0_ms_when_releasing_from_an_interrupt, + csd.OutOfInterruptBusyTiming * 10) + .AppendLine(); + } + + if(csd.DriverStrength.HasFlag(DriverStrength.Type0)) + sb.AppendLine("\t" + Localization.Device_supports_IO_driver_strength_type_zero); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type1)) + sb.AppendLine("\t" + Localization.Device_supports_IO_driver_strength_type_one); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type2)) + sb.AppendLine("\t" + Localization.Device_supports_IO_driver_strength_type_two); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type3)) + sb.AppendLine("\t" + Localization.Device_supports_IO_driver_strength_type_three); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type4)) + sb.AppendLine("\t" + Localization.Device_supports_IO_driver_strength_type_four); + + if(csd.DeviceType.HasFlag(DeviceType.HS_26)) sb.AppendLine("\t" + Localization.Device_supports_26_Mhz_mode); + + if(csd.DeviceType.HasFlag(DeviceType.HS_52)) sb.AppendLine("\t" + Localization.Device_supports_52_Mhz_mode); + + if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52)) + sb.AppendLine("\t" + Localization.Device_supports_DDR_52_Mhz_mode_at_1_8V_or_3V); + + if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52_LV)) + sb.AppendLine("\t" + Localization.Device_supports_DDR_52_Mhz_mode_1_2V); + + if(csd.DeviceType.HasFlag(DeviceType.HS200_18)) + sb.AppendLine("\t" + Localization.Device_supports_HS_200_mode_SDR_200Mhz_at_1_8V); + + if(csd.DeviceType.HasFlag(DeviceType.HS200_12)) + sb.AppendLine("\t" + Localization.Device_supports_HS_200_mode_SDR_200Mhz_at_1_2V); + + if(csd.DeviceType.HasFlag(DeviceType.HS400_18)) + sb.AppendLine("\t" + Localization.Device_supports_HS_400_mode_DDR_200Mhz_at_1_8V); + + if(csd.DeviceType.HasFlag(DeviceType.HS400_12)) + sb.AppendLine("\t" + Localization.Device_supports_HS_400_mode_DDR_200Mhz_at_1_2V); + + sb.AppendFormat("\t" + Localization.CSD_version_one_0_revision_one_1, csd.Structure, csd.Revision).AppendLine(); + + switch(csd.CommandSet) + { + case 0: + sb.AppendLine("\t" + Localization.Device_follows_compatibility_MMC_command_set); + + break; + case 1: + switch(csd.CommandSetRevision) + { + case 0: + sb.AppendLine("\t" + Localization.Device_follows_standard_MMC_command_set_v4_0); + + break; + default: + sb.AppendFormat("\t" + + Localization + .Device_follows_standard_MMC_command_set_with_unknown_version_code_0, + csd.CommandSetRevision) + .AppendLine(); + + break; + } + + break; + default: + sb.AppendFormat("\t" + Localization.Device_follows_unknown_MMC_command_set_code_0_with_revision_code_1, + csd.CommandSet, + csd.CommandSetRevision) + .AppendLine(); + + break; + } + + switch(csd.HighSpeedInterfaceTiming & 0x0F) + { + case 0: + break; + case 1: + sb.AppendLine("\t" + Localization.Device_is_in_High_Speed_mode); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_is_in_HS200_mode); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_is_in_HS400_mode); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_has_unknown_timing_mode_0, + csd.HighSpeedInterfaceTiming & 0x0F) + .AppendLine(); + + break; + } + + sb.AppendFormat("\t" + Localization.Selected_driver_strength_is_type_0, + (csd.HighSpeedInterfaceTiming & 0xF0) >> 4) + .AppendLine(); + + if((csd.StrobeSupport & 0x01) == 0x01) + { + sb.AppendLine("\t" + Localization.Device_supports_enhanced_strobe_mode); + + sb.AppendLine((csd.BusWidth & 0x80) == 0x80 + ? "\t" + Localization.Device_uses_strobe_during_Data_Out_CRC_and_CMD_responses + : "\t" + Localization.Device_uses_strobe_during_Data_Out_and_CRC_responses); + } + + switch(csd.BusWidth & 0x0F) + { + case 0: + sb.AppendLine("\t" + Localization.Device_is_using_1bit_data_bus); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_is_using_4bit_data_bus); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_is_using_8bit_data_bus); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_is_using_4bit_DDR_data_bus); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_is_using_8bit_DDR_data_bus); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_is_using_unknown_data_bus_code_0, csd.BusWidth & 0x0F) + .AppendLine(); + + break; + } + + switch(csd.ErasedMemoryContent) + { + case 0: + case 1: + sb.AppendFormat("\t" + Localization.Erased_memory_range_shall_be_0, csd.ErasedMemoryContent) + .AppendLine(); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_erased_memory_content_code_0, csd.ErasedMemoryContent) + .AppendLine(); + + break; + } + + if((csd.PartitionConfiguration & 0x40) == 0x40) + sb.AppendLine("\t" + Localization.Device_sends_boot_acknowledge); + + switch((csd.PartitionConfiguration & 0x38) >> 3) + { + case 0: + sb.AppendLine("\t" + Localization.Device_is_not_boot_enabled); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_boot_partition_one_is_enabled); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_boot_partition_two_is_enabled); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_user_area_is_enable_for_boot); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_enabled_boot_partition_code_0, + (csd.PartitionConfiguration & 0x38) >> 3) + .AppendLine(); + + break; + } + + switch(csd.PartitionConfiguration & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.There_is_no_access_to_boot_partition); + + break; + case 1: + sb.AppendLine("\t" + Localization.There_is_read_write_access_to_boot_partition_one); + + break; + case 2: + sb.AppendLine("\t" + Localization.There_is_read_write_access_to_boot_partition_two); + + break; + case 3: + sb.AppendLine("\t" + Localization.There_is_read_write_access_to_replay_protected_memory_block); + + break; + default: + sb.AppendFormat("\t" + Localization.There_is_access_to_general_purpose_partition_0, + (csd.PartitionConfiguration & 0x07) - 3) + .AppendLine(); + + break; + } + + if(csd.BootConfigProtection.HasFlag(BootConfigProtection.Permanent)) + sb.AppendLine("\t" + Localization.Change_of_the_boot_configuration_register_bits_is_permanently_disabled); + else if(csd.BootConfigProtection.HasFlag(BootConfigProtection.PowerCycle)) + { + sb.AppendLine("\t" + + Localization + .Change_of_the_boot_configuration_register_bits_is_disabled_until_the_next_power_cycle); + } + + switch(csd.BootBusConditions & 0x03) + { + case 0: + sb.AppendLine("\t" + Localization.Device_will_boot_up_in_x1_SDR_or_x4_DDR_bus_width); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_will_boot_up_in_x4_SDR_or_DDR_bus_width); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_will_boot_up_in_x8_SDR_or_DDR_bus_width); + + break; + case 3: + sb.AppendLine("\t" + Localization.Unknown_boot_condition_for_bus_width_with_code_three); + + break; + } + + sb.AppendLine((csd.BootBusConditions & 4) == 4 + ? "\t" + Localization.Device_will_retain_boot_conditions_after_boot_operation + : "\t" + + Localization.Device_will_reset_boot_conditions_to_compatibility_mode_after_boot_operation); + + switch((csd.BootBusConditions & 0x24) >> 3) + { + case 0: + sb.AppendLine("\t" + + Localization.Device_will_use_single_data_rate_with_compatible_timings_in_boot_operation); + + break; + case 1: + sb.AppendLine("\t" + + Localization.Device_will_use_single_data_rate_with_high_speed_timings_in_boot_operation); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_will_use_dual_data_rate_in_boot_operation); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_will_use_unknown_boot_mode_with_code_three); + + break; + } + + if(csd.HighCapacityEraseGroupDefinition.HasFlag(HighCapacityEraseGroupDefinition.Enabled)) + { + sb.AppendLine("\t" + + Localization + .Device_will_use_high_capacity_erase_unit_size__timeout_and_write_protect_group_size_definitions); + } + + switch(csd.BootWriteProtectionStatus & 0x03) + { + case 0: + sb.AppendLine("\t" + Localization.Boot_area_one_is_not_protected); + + break; + case 1: + sb.AppendLine("\t" + Localization.Boot_area_one_is_power_on_protected); + + break; + case 2: + sb.AppendLine("\t" + Localization.Boot_area_one_is_permanently_protected); + + break; + } + + switch((csd.BootWriteProtectionStatus & 0x0C) >> 2) + { + case 0: + sb.AppendLine("\t" + Localization.Boot_area_two_is_not_protected); + + break; + case 1: + sb.AppendLine("\t" + Localization.Boot_area_two_is_power_on_protected); + + break; + case 2: + sb.AppendLine("\t" + Localization.Boot_area_two_is_permanently_protected); + + break; + } + + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Permanent)) + { + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Selected)) + { + sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister + .PermanentArea2) + ? "\t" + Localization.Boot_area_two_is_permanently_write_protected + : "\t" + Localization.Boot_area_one_is_permanently_write_protected); + } + else + sb.AppendLine("\t" + Localization.Both_boot_areas_are_permanently_write_protected); + } + else if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOn)) + { + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Selected)) + { + sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOnArea2) + ? "\t" + Localization.Boot_area_two_is_write_protected_until_next_power_cycle + : "\t" + Localization.Boot_area_one_is_write_protected_until_next_power_cycle); + } + else + sb.AppendLine("\t" + Localization.Both_boot_areas_are_write_protected_until_next_power_cycle); + } + + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PermanentDisable)) + sb.AppendLine("\t" + Localization.Permanent_write_protection_of_boot_areas_is_disabled); + + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOnDisable)) + sb.AppendLine("\t" + Localization.Power_cycled_write_protection_of_boot_areas_is_disabled); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePassword)) + sb.AppendLine("\t" + Localization.Use_of_password_protection_features_is_permanently_disabled); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisableWriteProtect)) + sb.AppendLine("\t" + Localization.Use_of_permanent_write_protection_is_disabled); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePermanent)) + sb.AppendLine("\t" + Localization.Permanent_write_protection_is_disabled); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePowerOn)) + sb.AppendLine("\t" + Localization.Power_cycled_write_protection_is_disabled); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPermanent)) + sb.AppendLine("\t" + Localization.Permanent_write_protection_will_be_applied_to_selected_group); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPowerOn)) + sb.AppendLine("\t" + Localization.Power_cycled_write_protection_will_be_applied_to_selected_group); + + if((csd.FirmwareConfiguration & 0x01) == 0x01) + sb.AppendLine("\t" + Localization.Firmware_updates_are_permanently_disabled); + + if(csd.RPMBSize > 0) + { + sb.AppendFormat("\t" + Localization.Device_has_a_0_KiB_replay_protected_memory_block, csd.RPMBSize * 128) + .AppendLine(); + } + + if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Supported)) + { + sb.AppendLine("\t" + Localization.Device_supports_partitioning_features); + + if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Enhanced)) + { + sb.AppendLine("\t" + + Localization + .Device_can_have_enhanced_technological_features_in_partitions_and_user_data_area); + } + + if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Extended)) + sb.AppendLine("\t" + Localization.Device_can_have_extended_partitions_attribute); + } + + switch(csd.NativeSectorSize) + { + case 0: + sb.AppendLine("\t" + Localization.Device_natively_uses_512_byte_sectors); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_natively_uses_4096_byte_sectors); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_natively_uses_unknown_sector_size_indicated_by_code_0, + csd.NativeSectorSize) + .AppendLine(); + + break; + } + + switch(csd.SectorSizeEmulation) + { + case 0: + sb.AppendLine("\t" + Localization.Device_is_emulating_512_byte_sectors); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_is_using_natively_sized_sectors); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_emulates_unknown_sector_size_indicated_by_code_0, + csd.NativeSectorSize) + .AppendLine(); + + break; + } + + switch(csd.SectorSize) + { + case 0: + sb.AppendLine("\t" + Localization.Device_currently_addresses_512_byte_sectors); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_currently_addresses_4096_byte_sectors); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_currently_addresses_unknown_sector_size_indicated_by_code_0, + csd.NativeSectorSize) + .AppendLine(); + + break; + } + + if((csd.CacheControl & 0x01) == 0x01) sb.AppendLine("\t" + Localization.Devices_cache_is_enabled); + + if((csd.CommandQueueModeEnable & 0x01) == 0x01) + sb.AppendLine("\t" + Localization.Device_has_enabled_command_queuing); + + return sb.ToString(); + } + + public static string PrettifyExtendedCSD(byte[] response) => PrettifyExtendedCSD(DecodeExtendedCSD(response)); +} \ No newline at end of file diff --git a/Aaru.Decoders/MMC/OCR.cs b/Aaru.Decoders/MMC/OCR.cs new file mode 100644 index 000000000..01fdbfc0c --- /dev/null +++ b/Aaru.Decoders/MMC/OCR.cs @@ -0,0 +1,167 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : OCR.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes MultiMediaCard OCR. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.MMC; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class OCR +{ + public byte AccessMode; + public bool OneSix; + public bool PowerUp; + public bool ThreeFive; + public bool ThreeFour; + public bool ThreeOne; + public bool ThreeThree; + public bool ThreeTwo; + public bool ThreeZero; + public bool TwoEight; + public bool TwoFive; + public bool TwoFour; + public bool TwoNine; + public bool TwoOne; + public bool TwoSeven; + public bool TwoSix; + public bool TwoThree; + public bool TwoTwo; + public bool TwoZero; +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static partial class Decoders +{ + public static OCR DecodeOCR(uint response) + { + response = Swapping.Swap(response); + + return new OCR + { + PowerUp = (response & 0x80000000) == 0x80000000, + AccessMode = (byte)((response & 0x60000000) >> 29), + ThreeFive = (response & 0x00800000) == 0x00800000, + ThreeFour = (response & 0x00400000) == 0x00400000, + ThreeThree = (response & 0x00200000) == 0x00200000, + ThreeTwo = (response & 0x00100000) == 0x00100000, + ThreeOne = (response & 0x00080000) == 0x00080000, + ThreeZero = (response & 0x00040000) == 0x00040000, + TwoNine = (response & 0x00020000) == 0x00020000, + TwoEight = (response & 0x00010000) == 0x00010000, + TwoSeven = (response & 0x00008000) == 0x00008000, + TwoSix = (response & 0x00004000) == 0x00004000, + TwoFive = (response & 0x00002000) == 0x00002000, + TwoFour = (response & 0x00001000) == 0x00001000, + TwoThree = (response & 0x00000800) == 0x00000800, + TwoTwo = (response & 0x00000400) == 0x00000400, + TwoOne = (response & 0x00000200) == 0x00000200, + TwoZero = (response & 0x00000100) == 0x00000100, + OneSix = (response & 0x00000080) == 0x00000080 + }; + } + + public static OCR DecodeOCR(byte[] response) => + response?.Length != 4 ? null : DecodeOCR(BitConverter.ToUInt32(response, 0)); + + public static string PrettifyOCR(OCR ocr) + { + if(ocr == null) return null; + + var sb = new StringBuilder(); + sb.AppendLine(Localization.MultiMediaCard_Operation_Conditions_Register); + + if(!ocr.PowerUp) sb.AppendLine("\t" + Localization.Device_is_powering_up); + + switch(ocr.AccessMode) + { + case 0: + sb.AppendLine("\t" + Localization.Device_is_byte_addressed); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_is_sector_addressed); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_device_access_mode_0, ocr.AccessMode).AppendLine(); + + break; + } + + if(ocr.ThreeFive) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_3_5_3_6V); + + if(ocr.ThreeFour) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_3_4_3_5V); + + if(ocr.ThreeThree) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_3_3_3_4V); + + if(ocr.ThreeTwo) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_3_2_3_3V); + + if(ocr.ThreeOne) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_3_1_3_2V); + + if(ocr.TwoNine) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_9_3_0V); + + if(ocr.TwoEight) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_8_2_9V); + + if(ocr.TwoSeven) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_7_2_8V); + + if(ocr.TwoSix) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_6_2_7V); + + if(ocr.TwoFive) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_5_2_6V); + + if(ocr.TwoFour) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_4_2_5V); + + if(ocr.TwoThree) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_3_2_4V); + + if(ocr.TwoTwo) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_2_2_3V); + + if(ocr.TwoOne) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_1_2_2V); + + if(ocr.TwoZero) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_0_2_1V); + + if(ocr.OneSix) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_1_65_1_95V); + + return sb.ToString(); + } + + public static string PrettifyOCR(byte[] response) => PrettifyOCR(DecodeOCR(response)); + + public static string PrettifyOCR(uint response) => PrettifyOCR(DecodeOCR(response)); +} \ No newline at end of file diff --git a/Aaru.Decoders/MMC/VendorString.cs b/Aaru.Decoders/MMC/VendorString.cs new file mode 100644 index 000000000..0b5dceea2 --- /dev/null +++ b/Aaru.Decoders/MMC/VendorString.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : VendorString.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes MultiMediaCard vendor code. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.MMC; + +/// Decodes MultiMediaCard vendors +public static class VendorString +{ + /// Converts the byte value of a MultiMediaCard vendor ID to the manufacturer's name string + /// MMC vendor ID + /// Manufacturer + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public static string Prettify(byte mmcVendorId) => mmcVendorId switch + { + 0x07 => "Nokia", + 0x15 => "Samsung", + 0x2C => "extreMEmory", + _ => string.Format(Localization.Unknown_manufacturer_ID_0, + mmcVendorId) + }; +} \ No newline at end of file diff --git a/Aaru.Decoders/PCMCIA/CIS.cs b/Aaru.Decoders/PCMCIA/CIS.cs new file mode 100644 index 000000000..663d51521 --- /dev/null +++ b/Aaru.Decoders/PCMCIA/CIS.cs @@ -0,0 +1,305 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CIS.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes PCMCIA Card Information Structure. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.PCMCIA; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static class CIS +{ + // TODO: Handle links? Or are they removed in lower layers of the operating system drivers? + public static Tuple[] GetTuples(byte[] data) + { + List tuples = []; + var position = 0; + + while(position < data.Length) + { + var tuple = new Tuple + { + Code = (TupleCodes)data[position] + }; + + if(tuple.Code == TupleCodes.CISTPL_NULL) continue; + + if(tuple.Code == TupleCodes.CISTPL_END) break; + + tuple.Link = data[position + 1]; + + if(position + 2 + tuple.Link > data.Length) break; + + tuple.Data = new byte[tuple.Link + 2]; + Array.Copy(data, position, tuple.Data, 0, tuple.Link + 2); + + tuples.Add(tuple); + position += tuple.Link + 2; + } + + return tuples.ToArray(); + } + + public static DeviceGeometryTuple DecodeDeviceGeometryTuple(Tuple tuple) + { + if(tuple == null) return null; + + if(tuple.Code != TupleCodes.CISTPL_DEVICEGEO && tuple.Code != TupleCodes.CISTPL_DEVICEGEO_A) return null; + + return tuple.Data == null ? null : DecodeDeviceGeometryTuple(tuple.Data); + } + + public static DeviceGeometryTuple DecodeDeviceGeometryTuple(byte[] data) + { + if((data?.Length - 2) % 6 != 0) return null; + + var tuple = new DeviceGeometryTuple(); + List geometries = []; + + for(var position = 2; position < data.Length; position += 6) + { + var geometry = new DeviceGeometry + { + CardInterface = data[position], + EraseBlockSize = data[position + 1], + ReadBlockSize = data[position + 2], + WriteBlockSize = data[position + 3], + Partitions = data[position + 4], + Interleaving = data[position + 5] + }; + + geometries.Add(geometry); + } + + tuple.Code = (TupleCodes)data[0]; + tuple.Link = data[1]; + tuple.Geometries = geometries.ToArray(); + + return tuple; + } + + public static string PrettifyDeviceGeometryTuple(DeviceGeometryTuple tuple) + { + if(tuple == null) return null; + + if(tuple.Code != TupleCodes.CISTPL_DEVICEGEO && tuple.Code != TupleCodes.CISTPL_DEVICEGEO_A) return null; + + var sb = new StringBuilder(); + sb.AppendLine(Localization.PCMCIA_Device_Geometry_Tuples); + + foreach(DeviceGeometry geometry in tuple.Geometries) + { + sb.AppendLine("\t" + Localization.Geometry); + + sb.AppendFormat("\t\t" + Localization.Device_width_0_bits, (1 << geometry.CardInterface - 1) * 8) + .AppendLine(); + + sb.AppendFormat("\t\t" + Localization.Erase_block_0_bytes, + (1 << geometry.EraseBlockSize - 1) * (1 << geometry.Interleaving - 1)) + .AppendLine(); + + sb.AppendFormat("\t\t" + Localization.Read_block_0_bytes, + (1 << geometry.ReadBlockSize - 1) * (1 << geometry.Interleaving - 1)) + .AppendLine(); + + sb.AppendFormat("\t\t" + Localization.Write_block_0_bytes, + (1 << geometry.WriteBlockSize - 1) * (1 << geometry.Interleaving - 1)) + .AppendLine(); + + sb.AppendFormat("\t\t" + Localization.Partition_alignment_0_bytes, + (1 << geometry.EraseBlockSize - 1) * + (1 << geometry.Interleaving - 1) * + (1 << geometry.Partitions - 1)) + .AppendLine(); + } + + return sb.ToString(); + } + + public static string PrettifyDeviceGeometryTuple(Tuple tuple) => + PrettifyDeviceGeometryTuple(DecodeDeviceGeometryTuple(tuple)); + + public static string PrettifyDeviceGeometryTuple(byte[] data) => + PrettifyDeviceGeometryTuple(DecodeDeviceGeometryTuple(data)); + + public static ManufacturerIdentificationTuple DecodeManufacturerIdentificationTuple(Tuple tuple) + { + if(tuple?.Code != TupleCodes.CISTPL_MANFID) return null; + + return tuple.Data == null ? null : DecodeManufacturerIdentificationTuple(tuple.Data); + } + + public static ManufacturerIdentificationTuple DecodeManufacturerIdentificationTuple(byte[] data) + { + if(data == null) return null; + + if(data.Length < 6) return null; + + return new ManufacturerIdentificationTuple + { + Code = (TupleCodes)data[0], + Link = data[1], + ManufacturerID = BitConverter.ToUInt16(data, 2), + CardID = BitConverter.ToUInt16(data, 4) + }; + } + + public static string PrettifyManufacturerIdentificationTuple(ManufacturerIdentificationTuple tuple) + { + if(tuple?.Code != TupleCodes.CISTPL_MANFID) return null; + + var sb = new StringBuilder(); + sb.AppendLine(Localization.Manufacturer_Identification_Tuple); + sb.AppendFormat("\t" + Localization.Manufacturer_ID_0, VendorCode.Prettify(tuple.ManufacturerID)).AppendLine(); + sb.AppendFormat("\t" + Localization.Card_ID_0, tuple.CardID).AppendLine(); + + return sb.ToString(); + } + + public static string PrettifyManufacturerIdentificationTuple(Tuple tuple) => + PrettifyManufacturerIdentificationTuple(DecodeManufacturerIdentificationTuple(tuple)); + + public static string PrettifyManufacturerIdentificationTuple(byte[] data) => + PrettifyManufacturerIdentificationTuple(DecodeManufacturerIdentificationTuple(data)); + + public static Level1VersionTuple DecodeLevel1VersionTuple(Tuple tuple) + { + if(tuple?.Code != TupleCodes.CISTPL_VERS_1) return null; + + return tuple.Data == null ? null : DecodeLevel1VersionTuple(tuple.Data); + } + + public static Level1VersionTuple DecodeLevel1VersionTuple(byte[] data) + { + if(data == null) return null; + + if(data.Length < 4) return null; + + List buffer = []; + List strings = null; + var firstString = false; + const bool secondString = false; + + var tuple = new Level1VersionTuple + { + Code = (TupleCodes)data[0], + Link = data[1], + MajorVersion = data[2], + MinorVersion = data[3] + }; + + for(var position = 4; position < data.Length; position++) + { + if(data[position] == 0xFF) break; + + buffer.Add(data[position]); + + if(data[position] != 0x00) continue; + + if(!firstString) + { + tuple.Manufacturer = StringHandlers.CToString(buffer.ToArray()); + buffer = []; + firstString = true; + + continue; + } + + // TODO: Check this + if(!secondString) + { + tuple.Product = StringHandlers.CToString(buffer.ToArray()); + buffer = []; + firstString = true; + + continue; + } + + strings ??= []; + + strings.Add(StringHandlers.CToString(buffer.ToArray())); + buffer = []; + } + + if(strings != null) tuple.AdditionalInformation = strings.ToArray(); + + return tuple; + } + + public static string PrettifyLevel1VersionTuple(Level1VersionTuple tuple) + { + if(tuple?.Code != TupleCodes.CISTPL_VERS_1) return null; + + var sb = new StringBuilder(); + sb.AppendLine(Localization.PCMCIA_Level_1_Version_Product_Information_Tuple); + + sb.AppendFormat("\t" + Localization.Card_indicates_compliance_with_PC_Card_Standard_Release_0_1, + tuple.MajorVersion, + tuple.MinorVersion) + .AppendLine(); + + if(string.IsNullOrEmpty(tuple.Manufacturer)) + sb.AppendLine("\t" + Localization.No_manufacturer_information_string); + else + sb.AppendFormat(Localization.Manufacturer_0, tuple.Manufacturer).AppendLine(); + + if(string.IsNullOrEmpty(tuple.Product)) + sb.AppendLine("\t" + Localization.No_product_name_string); + else + sb.AppendFormat(Localization.Product_name_0, tuple.Product).AppendLine(); + + if(tuple.AdditionalInformation == null || tuple.AdditionalInformation.Length == 0) + sb.AppendLine("\t" + Localization.No_additional_information); + else + { + sb.AppendLine("\t" + Localization.Additional_information); + + foreach(string info in tuple.AdditionalInformation.Where(info => !string.IsNullOrEmpty(info))) + sb.Append($"\t\t{info}").AppendLine(); + } + + return sb.ToString(); + } + + public static string PrettifyLevel1VersionTuple(Tuple tuple) => + PrettifyLevel1VersionTuple(DecodeLevel1VersionTuple(tuple)); + + public static string PrettifyLevel1VersionTuple(byte[] data) => + PrettifyLevel1VersionTuple(DecodeLevel1VersionTuple(data)); +} \ No newline at end of file diff --git a/Aaru.Decoders/PCMCIA/Enums.cs b/Aaru.Decoders/PCMCIA/Enums.cs new file mode 100644 index 000000000..62e4184a0 --- /dev/null +++ b/Aaru.Decoders/PCMCIA/Enums.cs @@ -0,0 +1,184 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains PCMCIA enumerations. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.PCMCIA; + +/// Tuple codes. +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum TupleCodes : byte +{ + /// Checksum control + CISTPL_CHECKSUM = 0x10, + /// End-of-chain + CISTPL_END = 0xFF, + /// Indirect access PC Card memory + CISTPL_INDIRECT = 0x03, + /// Link-target-control + CISTPL_LINKTARGET = 0x13, + /// Longlink to attribute memory + CISTPL_LONGLINK_A = 0x11, + /// Longlink to common memory + CISTPL_LONGLINK_C = 0x12, + /// Longlink to next chain on a Cardbus PC Card + CISTPL_LONGLINK_CB = 0x02, + /// Longlink to function specific chains + CISTPL_LONGLINK_MFC = 0x06, + /// No-link to common memory + CISTPL_NO_LINK = 0x14, + /// Null tuple + CISTPL_NULL = 0x00, + /// Alternate language string + CISTPL_ALTSTR = 0x16, + /// Common memory device information + CISTPL_DEVICE = 0x01, + /// Attribute memory device information + CISTPL_DEVICE_A = 0x17, + /// Other operating conditions information for attribute memory + CISTPL_DEVICE_OA = 0x1D, + /// Other operating conditions information for common memory + CISTPL_DEVICE_OC = 0x1C, + /// Device geometry information for common memory + CISTPL_DEVICEGEO = 0x1E, + /// Device geometry information for attribute memory + CISTPL_DEVICEGEO_A = 0x1F, + /// Extended common memory device information + CISTPL_EXTDEVIC = 0x09, + /// Function extensions + CISTPL_FUNCE = 0x22, + /// Function class identification + CISTPL_FUNCID = 0x21, + /// JEDEC programming information for attribute memory + CISTPL_JEDEC_A = 0x19, + /// JEDEC programming information for common memory + CISTPL_JEDEC_C = 0x18, + /// Manufacturer identification string + CISTPL_MANFID = 0x20, + /// Level 1 version/product information + CISTPL_VERS_1 = 0x15, + /// BAR for a CardBus PC Card + CISTPL_BAR = 0x07, + /// Configuration-table-entry + CISTPL_CFTABLE_ENTRY = 0x1B, + /// Configuration-table-entry for a CardBus PC Card + CISTPL_CFTABLE_ENTRY_CB = 0x05, + /// Configuration tuple for a 16-bit PC Card + CISTPL_CONFIG = 0x1A, + /// Configuration tuple for a CardBus PC Card + CISTPL_CONFIG_CB = 0x04, + /// Function state save/restore definition + CISTPL_PWR_MGMNT = 0x08, + /// Battery replacement date + CISTPL_BATTERY = 0x45, + /// Card initialization date + CISTPL_DATE = 0x44, + /// Level 2 version/product information + CISTPL_VERS_2 = 0x40, + /// Byte ordering for disk-like partitions + CISTPL_BYTEORDER = 0x43, + /// Data recording format for common memory + CISTPL_FORMAT = 0x41, + /// Data recording format for attribute memory + CISTPL_FORMAT_A = 0x47, + /// Partition geometry + CISTPL_GEOMETRY = 0x42, + /// Software interleaving + CISTPL_SWIL = 0x23, + /// Partition organization + CISTPL_ORG = 0x46, + /// Special purpose + CISTPL_SPCL = 0x90 +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum DeviceTypeCodes : byte +{ + /// No device, used to designate a hole + DTYPE_NULL = 0, + /// Masked ROM + DTYPE_ROM = 1, + /// One-type-programmable ROM + DTYPE_OTPROM = 2, + /// UV-Erasable Programmable ROM + DTYPE_EPROM = 3, + /// Electronically-Erasable Programmable ROM + DTYPE_EEPROM = 4, + /// Flash memory + DTYPE_FLASH = 5, + /// Static RAM + DTYPE_SRAM = 6, + /// Dynamic RAM + DTYPE_DRAM = 7, + /// Function-specific memory address range + DTYPE_FUNCSPEC = 13, + /// Extended type follows + DTYPE_EXTEND = 14 +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum DeviceSpeedCodes : byte +{ + /// No device + DSPEED_NULL = 0, + /// 250 ns + DSPEED_250NS = 1, + /// 200 ns + DSPEED_200NS = 2, + /// 150 ns + DSPEED_150NS = 3, + /// 100 ns + DSPEED_100NS = 4, + /// Extended speed follows + DSPEED_EXT = 7 +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum FunctionCodes : byte +{ + MultiFunction = 0x00, + Memory = 0x01, + Serial = 0x02, + Parallel = 0x03, + FixedDisk = 0x04, + Video = 0x05, + Network = 0x06, + AIMS = 0x07, + SCSI = 0x08, + Security = 0x09, + Instrument = 0x0A, + HighSpeedSerial = 0x0B, + VendorSpecific = 0xFE +} \ No newline at end of file diff --git a/Aaru.Decoders/PCMCIA/Types.cs b/Aaru.Decoders/PCMCIA/Types.cs new file mode 100644 index 000000000..664c92875 --- /dev/null +++ b/Aaru.Decoders/PCMCIA/Types.cs @@ -0,0 +1,347 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Types.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains PCMCIA tuple structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global +// ReSharper disable InconsistentNaming +// ReSharper disable ClassCanBeSealed.Global +// ReSharper disable MemberCanBeInternal + +namespace Aaru.Decoders.PCMCIA; + +/// Basic classure of a PCMCIA tuple +public class Tuple +{ + public TupleCodes Code; + public byte[] Data; + public byte Link; +} + +/// Checksum tuple +public class ChecksumTuple +{ + /// Modulo-256 sum of region + public byte Checksum; + /// + /// + /// + public TupleCodes Code; + /// Length of region to be checksummed + public ushort Length; + /// Link to next tuple + public byte Link; + /// Offset to region to be checksummed + public short Offset; +} + +/// Indirect Access PC Card Memory +public class IndirectTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; +} + +/// Link target tuple +public class LinkTargetTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; + /// 'C''I''S' in ASCII + public byte[] Tag; +} + +/// 16-bit PC Card Long Link Tuple +public class LongLinkTuple +{ + /// Target address + public uint Address; + /// + /// or or + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; +} + +[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] +public class ConfigurationAddress +{ + /// Target address + public uint Address; + /// Target address space, 0 = attribute, 1 = common + public byte TargetAddressSpace; +} + +/// Multiple function link tuple +public class MultipleFunctionLinkTuple +{ + /// Link to more configuration registers + public ConfigurationAddress[] Addresses; + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; + /// How many functions follow + public byte NumberFunctions; +} + +public class NoLinkTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; +} + +public class AlternateStringTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; + /// + /// Array of strings. On memory they're preceded by an ISO Escape Code indicating codepage. Here they're stored as + /// Unicode, so no need for it. + /// + public string[] Strings; +} + +[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] +public class ExtendedDeviceSpeed +{ + /// Speed exponent + public byte Exponent; + /// Another extended follows + public bool Extended; + /// Speed mantisa + public byte Mantissa; +} + +public struct DeviceInfo +{ + /// Device type code + public DeviceTypeCodes Type; + /// Write protected + public bool WPS; + /// Speed code + public DeviceSpeedCodes Speed; + /// Extended speeds + public ExtendedDeviceSpeed[] ExtendedSpeeds; + /// Extended types + public byte[] ExtendedTypes; + /// Size in units - 1 + public byte Units; + /// Code to define units unit + public byte SizeCode; +} + +public class DeviceTuple +{ + /// or + public TupleCodes Code; + /// Array of device information bytes + public DeviceInfo[] Infos; + /// Link to next tuple + public byte Link; +} + +public struct OtherConditionInfo +{ + /// True if another other condition info follows + public bool Extended; + /// Vcc used + public byte VccUsed; + /// Supports WAIT# signal + public bool MWAIT; +} + +public class OtherConditionTuple +{ + /// or + public TupleCodes Code; + /// Array of device information bytes + public DeviceInfo[] Infos; + /// Link to next tuple + public byte Link; + /// Array of other condition information bytes + public OtherConditionInfo[] OtherConditionInfos; +} + +public struct DeviceGeometry +{ + /// 1 << n-1 bytes, 2 = 16-bit PC Card, 3 = CardBus PC Card + public byte CardInterface; + /// + /// Erase block size in 1 << n-1 increments of wide accesses. If n == 4, and + /// == 16, erase block size = 32 * 4 = 128 bytes + /// + public byte EraseBlockSize; + /// + /// Read block size in 1 << n-1 increments of wide accesses. If n == 4, and + /// == 16, read block size = 32 * 4 = 128 bytes + /// + public byte ReadBlockSize; + /// + /// Write block size in 1 << n-1 increments of wide accesses. If n == 4, and + /// == 16, write block size = 32 * 4 = 128 bytes + /// + public byte WriteBlockSize; + /// + /// Device partitioning in granularity of 1 << n-1 erase blocks If n == 4, and erase block is 128 bytes, + /// partitions must be aligned to 32 erase block, or 4096 bytes + /// + public byte Partitions; + /// Card employs a multiple of 1 << n-1 times interleaving the entire memory arrays + public byte Interleaving; +} + +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class DeviceGeometryTuple +{ + /// or + public TupleCodes Code; + /// Array of device geometries + public DeviceGeometry[] Geometries; + /// Link to next tuple + public byte Link; +} + +public class FunctionIdentificationTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Function code + public FunctionCodes Function; + /// Link to next tuple + public byte Link; + /// Device wants to be part of power-on-self-test + public bool POST; + /// Device contains boot ROM + public bool ROM; +} + +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class ManufacturerIdentificationTuple +{ + /// Card ID + public ushort CardID; + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; + /// Manufacturer ID + public ushort ManufacturerID; +} + +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class Level1VersionTuple +{ + /// Additional information strings + public string[] AdditionalInformation; + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; + /// Major version of standard compliance + public byte MajorVersion; + /// Manufacturer string + public string Manufacturer; + /// Minor version of standard compliance + public byte MinorVersion; + /// Product string + public string Product; +} + +public class Level2VersionTuple +{ + /// Address of first data byte + public ushort Address; + /// Number of copies of CIS present + public byte CISCopies; + /// + /// + /// + public TupleCodes Code; + /// Level of compliance + public byte Compliance; + /// Informational message about the card + public string Information; + /// Link to next tuple + public byte Link; + /// Vendor of software that formatted the card + public string OEM; + /// Version of this classure + public byte StructureVersion; + /// Vendor-specific byte + public byte VendorSpecific1; + /// Vendor-specific byte + public byte VendorSpecific2; +} + +public class GeometryTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Cylinders + public ushort Cylinders; + /// Link to next tuple + public byte Link; + /// Sectors per track + public byte SectorsPerTrack; + /// Tracks per cylinder + public byte TracksPerCylinder; +} \ No newline at end of file diff --git a/Aaru.Decoders/PCMCIA/VendorCode.cs b/Aaru.Decoders/PCMCIA/VendorCode.cs new file mode 100644 index 000000000..450b1aa90 --- /dev/null +++ b/Aaru.Decoders/PCMCIA/VendorCode.cs @@ -0,0 +1,678 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : VendorCode.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes PCMCIA vendor code. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.PCMCIA; + +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +public static class VendorCode +{ + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public static string Prettify(ushort id) + { + switch(id) + { +#region JEDEC + + case 0x01: + return "AMD"; + case 0x02: + return "AMI"; + case 0x83: + return "Fairchild"; + case 0x04: + return "Fujitsu"; + case 0x85: + return "GTE"; + case 0x86: + return "Harris"; + case 0x07: + return "Hitachi"; + case 0x08: + return "Inmos"; + case 0x89: + return "Intel"; + case 0x8A: + return "I.T.T."; + case 0x0B: + return "Intersil"; + case 0x8C: + return "Monolithic Memories"; + case 0x0D: + return "Mostek"; + case 0x0E: + return "Freescale"; + case 0x8F: + return "National"; + case 0x10: + return "NEC"; + case 0x91: + return "RCA"; + case 0x92: + return "Raytheon"; + case 0x13: + return "Conexant"; + case 0x94: + return "Seeq"; + case 0x15: + return "NXP"; + case 0x16: + return "Synertek"; + case 0x97: + return "Texas Instruments"; + case 0x98: + return "Toshiba"; + case 0x19: + return "Xicor"; + case 0x1A: + return "Zilog"; + case 0x9B: + return "Eurotechnique"; + case 0x1C: + return "Mitsubishi2"; + case 0x9D: + return "Lucent"; + case 0x9E: + return "Exel"; + case 0x1F: + return "Atmel"; + case 0x20: + return "SGS/Thomson"; + case 0xA1: + return "Lattice Semiconductor"; + case 0xA2: + return "NCR"; + case 0x23: + return "Wafer Scale Integration"; + case 0xA4: + return "International Business Machines"; + case 0x25: + return "Tristar"; + case 0x26: + return "Visic"; + case 0xA7: + return "International CMOS Technology"; + case 0xA8: + return "SSSI"; + case 0x29: + return "Microchip Technology"; + case 0x2A: + return "Ricoh"; + case 0xAB: + return "VLSI"; + case 0x2C: + return "Micron Technology"; + case 0xAD: + return "Hynix Semiconductor"; + case 0xAE: + return "OKI Semiconductor"; + case 0x2F: + return "ACTEL"; + case 0xB0: + return "Sharp"; + case 0x31: + return "Catalyst"; + case 0x32: + return "Panasonic"; + case 0xB3: + return "IDT"; + case 0x34: + return "Cypress"; + case 0xB5: + return "Digital Equipment Corporation"; + case 0xB6: + return "LSI Logic"; + case 0x37: + return "Zarlink"; + case 0x38: + return "UTMC"; + case 0xB9: + return "Thinking Machine"; + case 0xBA: + return "Thomson CSF"; + case 0x3B: + return "Integrated CMOS"; + case 0xBC: + return "Honeywell"; + case 0x3D: + return "Tektronix"; + case 0x3E: + return "Oracle Corporation"; + case 0xBF: + return "Silicon Storage Technology"; + case 0x40: + return "ProMos"; + case 0xC1: + return "Infineon"; + case 0xC2: + return "Macronix"; + case 0x43: + return "Xerox"; + case 0xC4: + return "Plus Logic"; + case 0x45: + return "SanDisk Corporation"; + case 0x46: + return "Elan Circuit Technology"; + case 0xC7: + return "European Silicon"; + case 0xC8: + return "Apple"; + case 0x49: + return "Xilinx"; + case 0x4A: + return "Compaq"; + case 0xCB: + return "Protocol Engines"; + case 0x4C: + return "SCI"; + case 0xCD: + return "Seiko Instruments"; + case 0xCE: + return "Samsung"; + case 0x4F: + return "I3 Design System"; + case 0xD0: + return "Klic"; + case 0x51: + return "Crosspoint Solutions"; + case 0x52: + return "Alliance Semiconductor"; + case 0xD3: + return "Tandem"; + case 0x54: + return "Hewlett-Packard"; + case 0xD5: + return "Integrated Silicon Solutions"; + case 0xD6: + return "Brooktree"; + case 0x57: + return "New Media"; + case 0x58: + return "MHS Electronic"; + case 0xD9: + return "Performance Semiconductors"; + case 0xDA: + return "Winbond Electronic"; + case 0x5B: + return "Kawasaki Steel"; + case 0x5D: + return "TECMAR"; + case 0x5E: + return "Exar"; + case 0xDF: + return "PCMCIA"; + case 0xE0: + return "LG Semiconductor"; + case 0x61: + return "Northern Telecom"; + case 0x62: + return "Sanyo2"; + case 0xE3: + return "Array Microsystems"; + case 0x64: + return "Crystal Semiconductor"; + case 0xE5: + return "Analog Devices"; + case 0xE6: + return "PMC-Sierra"; + case 0x67: + return "Asparix"; + case 0x68: + return "Convex Computer"; + case 0xE9: + return "Nimbus Technology"; + case 0x6B: + return "Transwitch"; + case 0xEC: + return "Micronas"; + case 0x6D: + return "Canon"; + case 0x6E: + return "Altera"; + case 0xEF: + return "NEXCOM"; + case 0x70: + return "Qualcomm"; + case 0xF1: + return "Sony"; + case 0xF2: + return "Cray Research"; + case 0x73: + return "AMS"; + case 0xF4: + return "Vitesse"; + case 0x75: + return "Aster Electronics"; + case 0x76: + return "Bay Networks"; + case 0xF7: + return "Zentrum"; + case 0xF8: + return "TRW"; + case 0x79: + return "Thesys"; + case 0x7A: + return "Solbourne Computer"; + case 0xFB: + return "Allied-Signal"; + case 0x7C: + return "Dialog Semiconductor"; + case 0xFD: + return "Media Vision"; + case 0xFE: + return "Numonyx Corporation"; + case 0x7F01: + return "Cirrus Logic"; + case 0x7F02: + return "National Instruments"; + case 0x7F04: + return "Alcatel Mietec"; + case 0x7F07: + return "JTAG Technologies"; + case 0x7F08: + return "Loral"; + case 0x7F0B: + return "Bestlink Systems"; + case 0x7F0D: + return "GENNUM"; + case 0x7F0E: + return "VideoLogic"; + case 0x7F10: + return "Chip Express"; + case 0x7F13: + return "TCSI"; + case 0x7F15: + return "Hughes Aircraft"; + case 0x7F16: + return "Lanstar Semiconductor"; + case 0x7F19: + return "Music Semi"; + case 0x7F1A: + return "Ericsson Components"; + case 0x7F1C: + return "Eon Silicon Devices"; + case 0x7F1F: + return "Integ.Memories Tech."; + case 0x7F20: + return "Corollary Inc."; + case 0x7F23: + return "EIV(Switzerland)"; + case 0x7F25: + return "Zarlink(formerly Mitel)"; + case 0x7F26: + return "Clearpoint"; + case 0x7F29: + return "Vanguard"; + case 0x7F2A: + return "Hagiwara Sys-Com"; + case 0x7F2C: + return "Celestica"; + case 0x7F2F: + return "Rohm Company Ltd."; + case 0x7F31: + return "Libit Signal Processing"; + case 0x7F32: + return "Enhanced Memories Inc."; + case 0x7F34: + return "Adaptec Inc."; + case 0x7F37: + return "AMIC Technology"; + case 0x7F38: + return "Adobe Systems"; + case 0x7F3B: + return "Newport Digital"; + case 0x7F3D: + return "T Square"; + case 0x7F3E: + return "Seiko Epson"; + case 0x7F40: + return "Viking Components"; + case 0x7F43: + return "Suwa Electronics"; + case 0x7F45: + return "Micron CMS"; + case 0x7F46: + return "American Computer &Digital Components Inc"; + case 0x7F49: + return "CPU Design"; + case 0x7F4A: + return "Price Point"; + case 0x7F4C: + return "Tellabs"; + case 0x7F4F: + return "Transcend Information"; + case 0x7F51: + return "CKD Corporation Ltd."; + case 0x7F52: + return "Capital Instruments, Inc."; + case 0x7F54: + return "Linvex Technology"; + case 0x7F57: + return "Dynamem, Inc."; + case 0x7F58: + return "NERA ASA"; + case 0x7F5B: + return "Acorn Computers"; + case 0x7F5D: + return "Oak Technology, Inc."; + case 0x7F5E: + return "Itec Memory"; + case 0x7F61: + return "Wintec Industries"; + case 0x7F62: + return "Super PC Memory"; + case 0x7F64: + return "Galvantech"; + case 0x7F67: + return "GateField"; + case 0x7F68: + return "Integrated Memory System"; + case 0x7F6B: + return "Goldenram"; + case 0x7F6D: + return "Cimaron Communications"; + case 0x7F6E: + return "Nippon Steel Semi.Corp."; + case 0x7F70: + return "AMCC"; + case 0x7F73: + return "Digital Microwave"; + case 0x7F75: + return "MIMOS Semiconductor"; + case 0x7F76: + return "Advanced Fibre"; + case 0x7F79: + return "Acbel Polytech Inc."; + case 0x7F7A: + return "Apacer Technology"; + case 0x7F7C: + return "FOXCONN"; + case 0x7F83: + return "ILC Data Device"; + case 0x7F85: + return "Micro Linear"; + case 0x7F86: + return "Univ.Of NC"; + case 0x7F89: + return "Nchip"; + case 0x7F8A: + return "Galileo Tech"; + case 0x7F8C: + return "Graychip"; + case 0x7F8F: + return "Robert Bosch"; + case 0x7F91: + return "DATARAM"; + case 0x7F92: + return "United Microelec Corp."; + case 0x7F94: + return "Smart Modular"; + case 0x7F97: + return "Qlogic"; + case 0x7F98: + return "Kingston"; + case 0x7F9B: + return "SpaSE"; + case 0x7F9D: + return "Programmable Micro Corp"; + case 0x7F9E: + return "DoD"; + case 0x7FA1: + return "Dallas Semiconductor"; + case 0x7FA2: + return "Omnivision"; + case 0x7FA4: + return "Novatel Wireless"; + case 0x7FA7: + return "Cabletron"; + case 0x7FA8: + return "Silicon Technology"; + case 0x7FAB: + return "Vantis"; + case 0x7FAD: + return "Century"; + case 0x7FAE: + return "Hal Computers"; + case 0x7FB0: + return "Juniper Networks"; + case 0x7FB3: + return "Tundra Semiconductor"; + case 0x7FB5: + return "LightSpeed Semi."; + case 0x7FB6: + return "ZSP Corp."; + case 0x7FB9: + return "Dynachip"; + case 0x7FBA: + return "PNY Electronics"; + case 0x7FBC: + return "MMC Networks"; + case 0x7FBF: + return "Broadcom"; + case 0x7FC1: + return "V3 Semiconductor"; + case 0x7FC2: + return "Flextronics(formerly Orbit)"; + case 0x7FC4: + return "Transmeta"; + case 0x7FC7: + return "Enhance 3000 Inc"; + case 0x7FC8: + return "Tower Semiconductor"; + case 0x7FCB: + return "Maxim Integrated Product"; + case 0x7FCD: + return "Centaur Technology"; + case 0x7FCE: + return "Unigen Corporation"; + case 0x7FD0: + return "Memory Card Technology"; + case 0x7FD3: + return "Aica Kogyo, Ltd."; + case 0x7FD5: + return "MSC Vertriebs GmbH"; + case 0x7FD6: + return "AKM Company, Ltd."; + case 0x7FD9: + return "GSI Technology"; + case 0x7FDA: + return "Dane-Elec (C Memory)"; + case 0x7FDC: + return "Lara Technology"; + case 0x7FDF: + return "Tanisys Technology"; + case 0x7FE0: + return "Truevision"; + case 0x7FE3: + return "MGV Memory"; + case 0x7FE5: + return "Gadzoox Networks"; + case 0x7FE6: + return "Multi Dimensional Cons."; + case 0x7FE9: + return "Triscend"; + case 0x7FEA: + return "XaQti"; + case 0x7FEC: + return "Clear Logic"; + case 0x7FEF: + return "Advantage Memory"; + case 0x7FF1: + return "LeCroy"; + case 0x7FF2: + return "Yamaha Corporation"; + case 0x7FF4: + return "NetLogic Microsystems"; + case 0x7FF7: + return "BF Goodrich Data."; + case 0x7FF8: + return "Epigram"; + case 0x7FFB: + return "Admor Memory"; + case 0x7FFD: + return "Quadratics Superconductor"; + case 0x7FFE: + return "3COM"; + +#endregion JEDEC + + case 0x0100: + return "Digital Equipment Corporation"; + case 0x0101: + return "3Com Corporation"; + case 0x0102: + return "Megahertz Corporation"; + case 0x0104: + return "Socket Communications"; + case 0x0105: + return "TDK Corporation"; + case 0x0108: + return "Standard Microsystems Corporation"; + case 0x0109: + return "Motorola Corporation"; + case 0x010b: + return "National Instruments"; + case 0x0115: + return "US Robotics Corporation"; + case 0x0121: + return "Olicom"; + case 0x0126: + return "Proxim"; + case 0x0128: + return "Megahertz Corporation"; + case 0x012F: + return "Adaptec Corporation"; + case 0x0137: + return "Quatech"; + case 0x0138: + return "Compaq"; + case 0x0140: + return "Ositech"; + case 0x0143: + return "D-Link"; + case 0x0149: + return "Netgear"; + case 0x014D: + return "Simple Technology"; + case 0x0156: + return "Lucent Technologies"; + case 0x015F: + return "Aironet Wireless Communications"; + case 0x016B: + return "Ericsson"; + case 0x016C: + return "Psion"; + case 0x0183: + return "Compaq"; + case 0x0186: + return "Kingston"; + case 0x0192: + return "Sierra Wireless"; + case 0x0194: + return "Dayna Corporation"; + case 0x01a6: + return "Raytheon"; + case 0x01BF: + return "Belkin"; + case 0x01EB: + return "Bay Networks"; + case 0x0200: + return "Farallon Communications"; + case 0x021B: + return "Telecom Device"; + case 0x023D: + return "Nokia Communications"; + case 0x0250: + return "Samsung"; + case 0x0264: + return "Anycom"; + case 0x0268: + return "Alvarion Ltd."; + case 0x026C: + return "Symbol"; + case 0x026F: + return "BUFFALO"; + case 0x0274: + return "The Linksys Group"; + case 0x0288: + return "NEC Infrontia"; + case 0x028A: + return "I-O DATA"; + case 0x02AA: + return "Asustek Computer"; + case 0x02AC: + return "Siemens"; + case 0x02D2: + return "Microsoft Corporation"; + case 0x02DF: + return "AmbiCom Inc"; + case 0x0a02: + return "BreezeCOM"; + case 0x10CD: + return "NewMedia"; + case 0x1668: + return "ACTIONTEC"; + case 0x3401: + return "Lasat Communications A/S"; + case 0x4E01: + return "Lexar Media"; + case 0x5241: + return "Archos"; + case 0x890F: + return "Dual"; + case 0x8A01: + return "Compex Corporation"; + case 0xC001: + return "Contec"; + case 0xC00B: + return "MACNICA"; + case 0xC00C: + return "Roland"; + case 0xC00F: + return "Corega K.K."; + case 0xC012: + return "Hagiwara SYS-COM"; + case 0xC015: + return "RATOC System Inc."; + case 0xC020: + return "NextCom K.K."; + case 0xC250: + return "EMTAC Technology Corporation"; + case 0xD601: + return "Elsa"; + default: + return string.Format(Localization.Unknown_vendor_id_0, id); + } + } +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/DiscStructureCapabilities.cs b/Aaru.Decoders/SCSI/DiscStructureCapabilities.cs new file mode 100644 index 000000000..f4e3dcd98 --- /dev/null +++ b/Aaru.Decoders/SCSI/DiscStructureCapabilities.cs @@ -0,0 +1,85 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DiscStructureCapabilities.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI DISC STRUCTURE structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class DiscStructureCapabilities +{ + public static Capability[] Decode(byte[] response) + { + var len = (ushort)((response[0] << 8) + response[1]); + + if(len + 2 != response.Length) return null; + + List caps = []; + + uint offset = 4; + + while(offset < response.Length) + { + var cap = new Capability + { + FormatCode = response[offset], + SDS = (response[offset + 1] & 0x80) == 0x80, + RDS = (response[offset + 1] & 0x40) == 0x40 + }; + + caps.Add(cap); + offset += 4; + } + + return caps.ToArray(); + } + +#region Nested type: Capability + + public struct Capability + { + /// READ/SEND DISC STRUCTURE format code + public byte FormatCode; + /// Supported in SEND DISC STRUCTURE + public bool SDS; + /// Supported in READ DISC STRUCTURE + public bool RDS; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/EVPD.cs b/Aaru.Decoders/SCSI/EVPD.cs new file mode 100644 index 000000000..231467d47 --- /dev/null +++ b/Aaru.Decoders/SCSI/EVPD.cs @@ -0,0 +1,2354 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : EVPD.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI EVPDs. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Aaru.CommonTypes.Structs.Devices.ATA; +using Aaru.CommonTypes.Structs.Devices.SCSI; +using Aaru.Helpers; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnassignedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static class EVPD +{ + /// Decodes VPD page 0x00: Supported VPD pages + /// A byte array containing all supported VPD pages. + /// Page 0x00. + public static byte[] DecodePage00(byte[] page) + { + if(page?[1] != 0) return null; + + if(page.Length != page[3] + 4) return null; + + var decoded = new byte[page.Length - 4]; + + Array.Copy(page, 4, decoded, 0, page.Length - 4); + + return decoded; + } + + /// Decides VPD pages 0x01 to 0x7F: ASCII Information + /// An ASCII string with the contents of the page. + /// Page 0x01-0x7F. + public static string DecodeASCIIPage(byte[] page) + { + if(page == null) return null; + + if(page[1] == 0 || page[1] > 0x7F) return null; + + if(page.Length != page[3] + 4) return null; + + var ascii = new byte[page[4]]; + + Array.Copy(page, 5, ascii, 0, page[4]); + + return StringHandlers.CToString(ascii); + } + + /// Decodes VPD page 0x80: Unit Serial Number + /// The unit serial number. + /// Page 0x80. + public static string DecodePage80(byte[] page) + { + if(page?[1] != 0x80) return null; + + if(page.Length != page[3] + 4) return null; + + var ascii = new byte[page.Length - 4]; + + Array.Copy(page, 4, ascii, 0, page.Length - 4); + + for(var i = 0; i < ascii.Length - 1; i++) + if(ascii[i] < 0x20) + return null; + + return StringHandlers.CToString(ascii); + } + + /// Decodes VPD page 0x82: ASCII implemented operating definition + /// ASCII implemented operating definition. + /// Page 0x82. + public static string DecodePage82(byte[] page) + { + if(page?[1] != 0x82) return null; + + if(page.Length != page[3] + 4) return null; + + var ascii = new byte[page.Length - 4]; + + Array.Copy(page, 4, ascii, 0, page.Length - 4); + + return StringHandlers.CToString(ascii); + } + +#region EVPD Page 0xB1: Manufacturer-assigned Serial Number page + + public static string DecodePageB1(byte[] page) + { + if(page?[1] != 0xB1) return null; + + if(page.Length != page[3] + 4) return null; + + var ascii = new byte[page.Length - 4]; + + Array.Copy(page, 4, ascii, 0, page.Length - 4); + + return StringHandlers.CToString(ascii).Trim(); + } + +#endregion EVPD Page 0xB1: Manufacturer-assigned Serial Number page + +#region EVPD Page 0xB2: TapeAlert Supported Flags page + + public static ulong DecodePageB2(byte[] page) + { + if(page?[1] != 0xB2) return 0; + + if(page.Length != 12) return 0; + + var bitmap = new byte[8]; + + Array.Copy(page, 4, bitmap, 0, 8); + + return BitConverter.ToUInt64(bitmap.Reverse().ToArray(), 0); + } + +#endregion EVPD Page 0xB2: TapeAlert Supported Flags page + +#region EVPD Page 0xB3: Automation Device Serial Number page + + public static string DecodePageB3(byte[] page) + { + if(page?[1] != 0xB3) return null; + + if(page.Length != page[3] + 4) return null; + + var ascii = new byte[page.Length - 4]; + + Array.Copy(page, 4, ascii, 0, page.Length - 4); + + return StringHandlers.CToString(ascii).Trim(); + } + +#endregion EVPD Page 0xB3: Automation Device Serial Number page + +#region EVPD Page 0xB4: Data Transfer Device Element Address page + + public static string DecodePageB4(byte[] page) + { + if(page?[1] != 0xB3) return null; + + if(page.Length != page[3] + 4) return null; + + var element = new byte[page.Length - 4]; + var sb = new StringBuilder(); + + foreach(byte b in element) sb.Append($"{b:X2}"); + + return sb.ToString(); + } + +#endregion EVPD Page 0xB4: Data Transfer Device Element Address page + +#region EVPD Page 0x81: Implemented operating definition page + + /// Implemented operating definition page Page code 0x81 + public struct Page_81 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// Current operating definition + public ScsiDefinitions Current; + /// Default operating definition + public ScsiDefinitions Default; + /// Support operating definition list + public ScsiDefinitions[] Supported; + } + + public static Page_81? DecodePage_81(byte[] pageResponse) + { + if(pageResponse?[1] != 0x81) return null; + + if(pageResponse[3] + 4 != pageResponse.Length) return null; + + if(pageResponse.Length < 6) return null; + + var decoded = new Page_81 + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + Current = (ScsiDefinitions)(pageResponse[4] & 0x7F), + Default = (ScsiDefinitions)(pageResponse[5] & 0x7F) + }; + + var position = 6; + List definitions = []; + + while(position < pageResponse.Length) + { + var definition = (ScsiDefinitions)(pageResponse[position] & 0x7F); + position++; + definitions.Add(definition); + } + + decoded.Supported = definitions.ToArray(); + + return decoded; + } + + public static string PrettifyPage_81(byte[] pageResponse) => PrettifyPage_81(DecodePage_81(pageResponse)); + + public static string DefinitionToString(ScsiDefinitions definition) => definition switch + { + ScsiDefinitions.Current => "", + ScsiDefinitions.CCS => "CCS", + ScsiDefinitions.SCSI1 => "SCSI-1", + ScsiDefinitions.SCSI2 => "SCSI-2", + ScsiDefinitions.SCSI3 => "SCSI-3", + _ => + $"Unknown definition code {(byte)definition}" + }; + + public static string PrettifyPage_81(Page_81? modePage) + { + if(!modePage.HasValue) return null; + + Page_81 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Implemented_operating_definitions); + + sb.AppendFormat("\t" + Localization.Default_operating_definition_0, DefinitionToString(page.Current)) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Current_operating_definition_0, DefinitionToString(page.Current)) + .AppendLine(); + + if(page.Supported.Length == 0) + { + sb.AppendLine("\t" + Localization.There_are_no_supported_definitions); + + return sb.ToString(); + } + + sb.AppendLine("\t" + Localization.Supported_operating_definitions); + + foreach(ScsiDefinitions definition in page.Supported) + sb.AppendFormat("\t" + "\t{0}", DefinitionToString(definition)).AppendLine(); + + return sb.ToString(); + } + +#endregion EVPD Page 0x81: Implemented operating definition page + +#region EVPD Page 0x83: Device identification page + + public enum IdentificationAssociation : byte + { + /// Identifier field is associated with the addressed logical unit + LogicalUnit = 0, + /// Identifier field is associated with the target port + TargetPort = 1, + /// Identifier field is associated with the target device that contains the LUN + TargetDevice = 2 + } + + public enum IdentificationCodeSet : byte + { + /// Identifier is binary + Binary = 1, + /// Identifier is pure ASCII + ASCII = 2, + /// Identifier is in UTF-8 + UTF8 = 3 + } + + public enum IdentificationTypes : byte + { + /// No assignment authority was used and there is no guarantee the identifier is unique + NoAuthority = 0, + /// Concatenates vendor and product identifier from INQUIRY plus unit serial number from page 80h + Inquiry = 1, + /// Identifier is a 64-bit IEEE EUI-64, or extended + EUI = 2, + /// Identifier is compatible with 64-bit FC-PH Name_Identifier + NAA = 3, + /// Identifier to relative port in device + Relative = 4, + /// Identifier to group of target ports in device + TargetPortGroup = 5, + /// Identifier to group of target LUNs in device + LogicalUnitGroup = 6, + /// MD5 of device identification values + MD5 = 7, + /// SCSI name string + SCSI = 8, + /// Protocol specific port identifier + ProtocolSpecific = 9 + } + + public struct IdentificatonDescriptor + { + /// Protocol identifier + public ProtocolIdentifiers ProtocolIdentifier; + /// Defines how the identifier is stored + public IdentificationCodeSet CodeSet; + /// Set if protocol identifier is valid + public bool PIV; + /// Identifies which decide the identifier associates with + public IdentificationAssociation Association; + /// Defines the type of the identifier + public IdentificationTypes Type; + /// Length of the identifier + public byte Length; + /// Identifier as a string if applicable + public string ASCII; + /// Binary identifier + public byte[] Binary; + } + + /// Device identification page Page code 0x83 + public struct Page_83 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// The descriptors. + public IdentificatonDescriptor[] Descriptors; + } + + public static Page_83? DecodePage_83(byte[] pageResponse) + { + if(pageResponse?[1] != 0x83) return null; + + if(pageResponse[3] + 4 != pageResponse.Length) return null; + + if(pageResponse.Length < 6) return null; + + var decoded = new Page_83 + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4) + }; + + var position = 4; + List descriptors = []; + + while(position < pageResponse.Length) + { + var descriptor = new IdentificatonDescriptor + { + ProtocolIdentifier = (ProtocolIdentifiers)((pageResponse[position] & 0xF0) >> 4), + CodeSet = (IdentificationCodeSet)(pageResponse[position] & 0x0F), + PIV = (pageResponse[position + 1] & 0x80) == 0x80, + Association = (IdentificationAssociation)((pageResponse[position + 1] & 0x30) >> 4), + Type = (IdentificationTypes)(pageResponse[position + 1] & 0x0F), + Length = pageResponse[position + 3] + }; + + descriptor.Binary = new byte[descriptor.Length]; + + if(descriptor.Length + position + 4 >= pageResponse.Length) + descriptor.Length = (byte)(pageResponse.Length - position - 4); + + Array.Copy(pageResponse, position + 4, descriptor.Binary, 0, descriptor.Length); + + descriptor.ASCII = descriptor.CodeSet switch + { + IdentificationCodeSet.ASCII => StringHandlers.CToString(descriptor.Binary), + IdentificationCodeSet.UTF8 => Encoding.UTF8.GetString(descriptor.Binary), + _ => "" + }; + + position += 4 + descriptor.Length; + descriptors.Add(descriptor); + } + + decoded.Descriptors = descriptors.ToArray(); + + return decoded; + } + + public static string PrettifyPage_83(byte[] pageResponse) => PrettifyPage_83(DecodePage_83(pageResponse)); + + public static string PrettifyPage_83(Page_83? modePage) + { + if(!modePage.HasValue) return null; + + Page_83 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Device_identification); + + if(page.Descriptors.Length == 0) + { + sb.AppendLine("\t" + Localization.There_are_no_identifiers); + + return sb.ToString(); + } + + foreach(IdentificatonDescriptor descriptor in page.Descriptors) + { + switch(descriptor.Association) + { + case IdentificationAssociation.LogicalUnit: + sb.AppendLine("\t" + Localization.Identifier_belongs_to_addressed_logical_unit); + + break; + case IdentificationAssociation.TargetPort: + sb.AppendLine("\t" + Localization.Identifier_belongs_to_target_port); + + break; + case IdentificationAssociation.TargetDevice: + sb.AppendLine("\t" + + Localization + .Identifier_belongs_to_target_device_that_contains_the_addressed_logical_unit); + + break; + default: + sb.AppendFormat("\t" + Localization.Identifier_has_unknown_association_with_code_0, + (byte)descriptor.Association) + .AppendLine(); + + break; + } + + if(descriptor.PIV) + { + string protocol = descriptor.ProtocolIdentifier switch + { + ProtocolIdentifiers.ADT => Localization.Automation_Drive_Interface_Transport, + ProtocolIdentifiers.ATA => Localization.AT_Attachment_Interface__ATA_ATAPI_, + ProtocolIdentifiers.FibreChannel => Localization.Fibre_Channel, + ProtocolIdentifiers.Firewire => Localization.IEEE_1394, + ProtocolIdentifiers.iSCSI => Localization.Internet_SCSI, + ProtocolIdentifiers.NoProtocol => Localization.no_specific_protocol, + ProtocolIdentifiers.PCIe => Localization.PCI_Express, + ProtocolIdentifiers.RDMAP => Localization.SCSI_Remote_Direct_Memory_Access, + ProtocolIdentifiers.SAS => Localization.Serial_Attachment_SCSI, + ProtocolIdentifiers.SCSI => Localization.Parallel_SCSI, + ProtocolIdentifiers.SCSIe => Localization.SCSI_over_PCI_Express, + ProtocolIdentifiers.SSA => Localization.SSA, + ProtocolIdentifiers.UAS => Localization.USB_Attached_SCSI, + _ => string.Format(Localization.unknown_code_protocol_0, + (byte)descriptor.ProtocolIdentifier) + }; + + sb.AppendFormat("\t" + Localization.Descriptor_refers_to_0_protocol, protocol).AppendLine(); + } + + switch(descriptor.Type) + { + case IdentificationTypes.NoAuthority: + switch(descriptor.CodeSet) + { + case IdentificationCodeSet.ASCII: + case IdentificationCodeSet.UTF8: + sb.AppendFormat("\t" + Localization.Vendor_descriptor_contains_0, descriptor.ASCII) + .AppendLine(); + + break; + case IdentificationCodeSet.Binary: + sb.AppendFormat("\t" + Localization.Vendor_descriptor_contains_binary_data_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + default: + sb.AppendFormat("\t" + Localization.Vendor_descriptor_contains_unknown_kind_1_of_data_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), + (byte)descriptor.CodeSet) + .AppendLine(); + + break; + } + + break; + case IdentificationTypes.Inquiry: + switch(descriptor.CodeSet) + { + case IdentificationCodeSet.ASCII: + case IdentificationCodeSet.UTF8: + sb.AppendFormat("\t" + Localization.Inquiry_descriptor_contains_0, descriptor.ASCII) + .AppendLine(); + + break; + case IdentificationCodeSet.Binary: + sb.AppendFormat("\t" + Localization.Inquiry_descriptor_contains_binary_data_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + default: + sb.AppendFormat("\t" + + Localization.Inquiry_descriptor_contains_unknown_kind_1_of_data_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), + (byte)descriptor.CodeSet) + .AppendLine(); + + break; + } + + break; + case IdentificationTypes.EUI: + if(descriptor.CodeSet is IdentificationCodeSet.ASCII or IdentificationCodeSet.UTF8) + sb.AppendFormat("\t" + Localization.IEEE_EUI_64_0, descriptor.ASCII).AppendLine(); + else + { + sb.AppendFormat("\t" + Localization.IEEE_EUI_64_0_X2, descriptor.Binary[0]); + + for(var i = 1; i < descriptor.Binary.Length; i++) sb.Append($":{descriptor.Binary[i]:X2}"); + + sb.AppendLine(); + } + + break; + case IdentificationTypes.NAA: + if(descriptor.CodeSet is IdentificationCodeSet.ASCII or IdentificationCodeSet.UTF8) + sb.AppendFormat("\t" + Localization.NAA_0, descriptor.ASCII).AppendLine(); + else + { + sb.AppendFormat("\t" + Localization.NAA_0_X2, descriptor.Binary[0]); + + for(var i = 1; i < descriptor.Binary.Length; i++) sb.Append($":{descriptor.Binary[i]:X2}"); + + sb.AppendLine(); + } + + break; + case IdentificationTypes.Relative: + if(descriptor.CodeSet is IdentificationCodeSet.ASCII or IdentificationCodeSet.UTF8) + { + sb.AppendFormat("\t" + Localization.Relative_target_port_identifier_0, descriptor.ASCII) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization.Relative_target_port_identifier_0, + (descriptor.Binary[2] << 8) + descriptor.Binary[3]) + .AppendLine(); + } + + break; + case IdentificationTypes.TargetPortGroup: + if(descriptor.CodeSet is IdentificationCodeSet.ASCII or IdentificationCodeSet.UTF8) + sb.AppendFormat("\t" + Localization.Target_group_identifier_0, descriptor.ASCII).AppendLine(); + else + { + sb.AppendFormat("\t" + Localization.Target_group_identifier_0, + (descriptor.Binary[2] << 8) + descriptor.Binary[3]) + .AppendLine(); + } + + break; + case IdentificationTypes.LogicalUnitGroup: + if(descriptor.CodeSet is IdentificationCodeSet.ASCII or IdentificationCodeSet.UTF8) + { + sb.AppendFormat("\t" + Localization.Logical_unit_group_identifier_0, descriptor.ASCII) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization.Logical_unit_group_identifier_0, + (descriptor.Binary[2] << 8) + descriptor.Binary[3]) + .AppendLine(); + } + + break; + case IdentificationTypes.MD5: + if(descriptor.CodeSet is IdentificationCodeSet.ASCII or IdentificationCodeSet.UTF8) + { + sb.AppendFormat("\t" + Localization.MD5_logical_unit_identifier_0, descriptor.ASCII) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization.MD5_logical_unit_identifier_0_x2, descriptor.Binary[0]); + + for(var i = 1; i < descriptor.Binary.Length; i++) sb.Append($"{descriptor.Binary[i]:x2}"); + + sb.AppendLine(); + } + + break; + case IdentificationTypes.SCSI: + if(descriptor.CodeSet is IdentificationCodeSet.ASCII or IdentificationCodeSet.UTF8) + { + sb.AppendFormat("\t" + Localization.SCSI_name_string_identifier_0, descriptor.ASCII) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization.SCSI_name_string_identifier_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + } + + break; + case IdentificationTypes.ProtocolSpecific: + { + if(descriptor.PIV) + { + switch(descriptor.ProtocolIdentifier) + { + case ProtocolIdentifiers.ADT: + sb.AppendFormat("\t" + + Localization + .Protocol_Automation_Drive_Interface_Transport_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.ATA: + sb.AppendFormat("\t" + + Localization + .Protocol_ATA_ATAPI_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.FibreChannel: + sb.AppendFormat("\t" + + Localization + .Protocol_Fibre_Channel_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.Firewire: + sb.AppendFormat("\t" + + Localization + .Protocol_IEEE_1394_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.iSCSI: + sb.AppendFormat("\t" + + Localization + .Protocol_Internet_SCSI_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.NoProtocol: + sb.AppendFormat("\t" + + Localization + .Protocol_unknown_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.PCIe: + sb.AppendFormat("\t" + + Localization + .Protocol_PCI_Express_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.RDMAP: + sb.AppendFormat("\t" + + Localization + .Protocol_SCSI_Remote_Direct_Memory_Access_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.SAS: + sb.AppendFormat("\t" + + Localization + .Protocol_Serial_Attachment_SCSI_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.SCSI: + sb.AppendFormat("\t" + + Localization + .Protocol_Parallel_SCSI_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.SSA: + sb.AppendFormat("\t" + + Localization.Protocol_SSA_specific_descriptor_with_unknown_format_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + case ProtocolIdentifiers.SCSIe: + sb.AppendFormat("\t" + Localization.Protocol_SCSIe_specific_descriptor_Routing_ID_is_0, + (descriptor.Binary[0] << 8) + descriptor.Binary[1]) + .AppendLine(); + + break; + case ProtocolIdentifiers.UAS: + sb.AppendFormat("\t" + + Localization.Protocol_UAS_specific_descriptor_USB_address_0_interface_1, + descriptor.Binary[0] & 0x7F, + descriptor.Binary[2]) + .AppendLine(); + + break; + default: + sb.AppendFormat("\t" + + Localization + .Protocol_unknown_code_0_specific_descriptor_with_unknown_format_hex_1, + (byte)descriptor.ProtocolIdentifier, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)) + .AppendLine(); + + break; + } + } + } + + break; + default: + switch(descriptor.CodeSet) + { + case IdentificationCodeSet.ASCII: + case IdentificationCodeSet.UTF8: + sb.AppendFormat("\t" + Localization.Unknown_descriptor_type_1_contains_0, + descriptor.ASCII, + (byte)descriptor.Type) + .AppendLine(); + + break; + case IdentificationCodeSet.Binary: + sb.AppendFormat("\t" + Localization.Unknown_descriptor_type_1_contains_binary_data_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), + (byte)descriptor.Type) + .AppendLine(); + + break; + default: + sb.AppendFormat(Localization + .Inquiry_descriptor_type_2_contains_unknown_kind_1_of_data_hex_0, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), + (byte)descriptor.CodeSet, + (byte)descriptor.Type) + .AppendLine(); + + break; + } + + break; + } + } + + return sb.ToString(); + } + +#endregion EVPD Page 0x83: Device identification page + +#region EVPD Page 0x84: Software Interface Identification page + + public struct SoftwareIdentifier + { + /// EUI-48 identifier + public byte[] Identifier; + } + + /// Software Interface Identification page Page code 0x84 + public struct Page_84 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// The descriptors. + public SoftwareIdentifier[] Identifiers; + } + + public static Page_84? DecodePage_84(byte[] pageResponse) + { + if(pageResponse?[1] != 0x84) return null; + + if(pageResponse[3] + 4 != pageResponse.Length) return null; + + if(pageResponse.Length < 10) return null; + + var decoded = new Page_84 + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4) + }; + + var position = 4; + List identifiers = []; + + while(position < pageResponse.Length) + { + var identifier = new SoftwareIdentifier + { + Identifier = new byte[6] + }; + + Array.Copy(pageResponse, position, identifier.Identifier, 0, 6); + identifiers.Add(identifier); + position += 6; + } + + decoded.Identifiers = identifiers.ToArray(); + + return decoded; + } + + public static string PrettifyPage_84(byte[] pageResponse) => PrettifyPage_84(DecodePage_84(pageResponse)); + + public static string PrettifyPage_84(Page_84? modePage) + { + if(!modePage.HasValue) return null; + + Page_84 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Software_Interface_Identifiers); + + if(page.Identifiers.Length == 0) + { + sb.AppendLine("\t" + Localization.There_are_no_identifiers); + + return sb.ToString(); + } + + foreach(SoftwareIdentifier identifier in page.Identifiers) + { + sb.AppendFormat("\t" + "{0:X2}", identifier.Identifier[0]); + + for(var i = 1; i < identifier.Identifier.Length; i++) sb.Append($":{identifier.Identifier[i]:X2}"); + + sb.AppendLine(); + } + + return sb.ToString(); + } + +#endregion EVPD Page 0x84: Software Interface Identification page + +#region EVPD Page 0x85: Management Network Addresses page + + public enum NetworkServiceTypes : byte + { + Unspecified = 0, + StorageConf = 1, + Diagnostics = 2, + Status = 3, + Logging = 4, + CodeDownload = 5, + CopyService = 6, + Administrative = 7 + } + + public struct NetworkDescriptor + { + /// Identifies which device the identifier associates with + public IdentificationAssociation Association; + /// Defines the type of the identifier + public NetworkServiceTypes Type; + /// Length of the identifier + public ushort Length; + /// Binary identifier + public byte[] Address; + } + + /// Device identification page Page code 0x85 + public struct Page_85 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public ushort PageLength; + /// The descriptors. + public NetworkDescriptor[] Descriptors; + } + + public static Page_85? DecodePage_85(byte[] pageResponse) + { + if(pageResponse?[1] != 0x85) return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) return null; + + if(pageResponse.Length < 4) return null; + + var decoded = new Page_85 + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (ushort)((pageResponse[2] << 8) + pageResponse[3] + 4) + }; + + var position = 4; + List descriptors = []; + + while(position < pageResponse.Length) + { + var descriptor = new NetworkDescriptor + { + Association = (IdentificationAssociation)((pageResponse[position] & 0x60) >> 5), + Type = (NetworkServiceTypes)(pageResponse[position] & 0x1F), + Length = (ushort)((pageResponse[position + 2] << 8) + pageResponse[position + 3]) + }; + + descriptor.Address = new byte[descriptor.Length]; + Array.Copy(pageResponse, position + 4, descriptor.Address, 0, descriptor.Length); + + position += 4 + descriptor.Length; + descriptors.Add(descriptor); + } + + decoded.Descriptors = descriptors.ToArray(); + + return decoded; + } + + public static string PrettifyPage_85(byte[] pageResponse) => PrettifyPage_85(DecodePage_85(pageResponse)); + + public static string PrettifyPage_85(Page_85? modePage) + { + if(!modePage.HasValue) return null; + + Page_85 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Management_Network_Addresses); + + if(page.Descriptors.Length == 0) + { + sb.AppendLine("\t" + Localization.There_are_no_addresses); + + return sb.ToString(); + } + + foreach(NetworkDescriptor descriptor in page.Descriptors) + { + switch(descriptor.Association) + { + case IdentificationAssociation.LogicalUnit: + sb.AppendLine("\t" + Localization.Identifier_belongs_to_addressed_logical_unit); + + break; + case IdentificationAssociation.TargetPort: + sb.AppendLine("\t" + Localization.Identifier_belongs_to_target_port); + + break; + case IdentificationAssociation.TargetDevice: + sb.AppendLine("\t" + + Localization + .Identifier_belongs_to_target_device_that_contains_the_addressed_logical_unit); + + break; + default: + sb.AppendFormat("\t" + Localization.Identifier_has_unknown_association_with_code_0, + (byte)descriptor.Association) + .AppendLine(); + + break; + } + + switch(descriptor.Type) + { + case NetworkServiceTypes.CodeDownload: + sb.AppendFormat(Localization.Address_for_code_download_0, + StringHandlers.CToString(descriptor.Address)) + .AppendLine(); + + break; + case NetworkServiceTypes.Diagnostics: + sb.AppendFormat(Localization.Address_for_diagnostics_0, + StringHandlers.CToString(descriptor.Address)) + .AppendLine(); + + break; + case NetworkServiceTypes.Logging: + sb.AppendFormat(Localization.Address_for_logging_0, StringHandlers.CToString(descriptor.Address)) + .AppendLine(); + + break; + case NetworkServiceTypes.Status: + sb.AppendFormat(Localization.Address_for_status_0, StringHandlers.CToString(descriptor.Address)) + .AppendLine(); + + break; + case NetworkServiceTypes.StorageConf: + sb.AppendFormat(Localization.Address_for_storage_configuration_service_0, + StringHandlers.CToString(descriptor.Address)) + .AppendLine(); + + break; + case NetworkServiceTypes.Unspecified: + sb.AppendFormat(Localization.Unspecified_address_0, StringHandlers.CToString(descriptor.Address)) + .AppendLine(); + + break; + case NetworkServiceTypes.CopyService: + sb.AppendFormat(Localization.Address_for_copy_service_0, + StringHandlers.CToString(descriptor.Address)) + .AppendLine(); + + break; + case NetworkServiceTypes.Administrative: + sb.AppendFormat(Localization.Address_for_administrative_configuration_service_0, + StringHandlers.CToString(descriptor.Address)) + .AppendLine(); + + break; + default: + sb.AppendFormat(Localization.Address_of_unknown_type_1_0, + StringHandlers.CToString(descriptor.Address), + (byte)descriptor.Type) + .AppendLine(); + + break; + } + } + + return sb.ToString(); + } + +#endregion EVPD Page 0x85: Management Network Addresses page + +#region EVPD Page 0x86: Extended INQUIRY data page + + /// Device identification page Page code 0x86 + public struct Page_86 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// Indicates how a device server activates microcode + public byte ActivateMicrocode; + /// Protection types supported by device + public byte SPT; + /// Checks logical block guard field + public bool GRD_CHK; + /// Checks logical block application tag + public bool APP_CHK; + /// Checks logical block reference + public bool REF_CHK; + /// Supports unit attention condition sense key specific data + public bool UASK_SUP; + /// Supports grouping + public bool GROUP_SUP; + /// Supports priority + public bool PRIOR_SUP; + /// Supports head of queue + public bool HEADSUP; + /// Supports ordered + public bool ORDSUP; + /// Supports simple + public bool SIMPSUP; + /// Supports marking a block as uncorrectable + public bool WU_SUP; + /// Supports disabling correction on WRITE LONG + public bool CRD_SUP; + /// Supports a non-volatile cache + public bool NV_SUP; + /// Supports a volatile cache + public bool V_SUP; + /// Disable protection information checks + public bool NO_PI_CHK; + /// Protection information interval supported + public bool P_I_I_SUP; + /// Clears all LUNs unit attention when clearing one + public bool LUICLR; + /// Referrals support + public bool R_SUP; + /// History snapshots release effects + public bool HSSRELEF; + /// Capability based command security + public bool CBCS; + /// Indicates how it handles microcode updating with multiple nexuxes + public byte Nexus; + /// Time to complete extended self-test + public ushort ExtendedTestMinutes; + /// Power on activation support + public bool POA_SUP; + /// Hard reset actication + public bool HRA_SUP; + /// Vendor specific activation + public bool VSA_SUP; + /// Maximum length in bytes of sense data + public byte MaximumSenseLength; + } + + public static Page_86? DecodePage_86(byte[] pageResponse) + { + if(pageResponse?[1] != 0x86) return null; + + if(pageResponse[3] + 4 != pageResponse.Length) return null; + + if(pageResponse.Length < 64) return null; + + return new Page_86 + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + ActivateMicrocode = (byte)((pageResponse[4] & 0xC0) >> 6), + SPT = (byte)((pageResponse[4] & 0x38) >> 3), + GRD_CHK = (pageResponse[4] & 0x04) == 0x04, + APP_CHK = (pageResponse[4] & 0x02) == 0x02, + REF_CHK = (pageResponse[4] & 0x01) == 0x01, + UASK_SUP = (pageResponse[5] & 0x20) == 0x20, + GROUP_SUP = (pageResponse[5] & 0x10) == 0x10, + PRIOR_SUP = (pageResponse[5] & 0x08) == 0x08, + HEADSUP = (pageResponse[5] & 0x04) == 0x04, + ORDSUP = (pageResponse[5] & 0x02) == 0x02, + SIMPSUP = (pageResponse[5] & 0x01) == 0x01, + WU_SUP = (pageResponse[6] & 0x08) == 0x08, + CRD_SUP = (pageResponse[6] & 0x04) == 0x04, + NV_SUP = (pageResponse[6] & 0x02) == 0x02, + V_SUP = (pageResponse[6] & 0x01) == 0x01, + NO_PI_CHK = (pageResponse[7] & 0x20) == 0x20, + P_I_I_SUP = (pageResponse[7] & 0x10) == 0x10, + LUICLR = (pageResponse[7] & 0x01) == 0x01, + R_SUP = (pageResponse[8] & 0x10) == 0x10, + HSSRELEF = (pageResponse[8] & 0x02) == 0x02, + CBCS = (pageResponse[8] & 0x01) == 0x01, + Nexus = (byte)(pageResponse[9] & 0x0F), + ExtendedTestMinutes = (ushort)((pageResponse[10] << 8) + pageResponse[11]), + POA_SUP = (pageResponse[12] & 0x80) == 0x80, + HRA_SUP = (pageResponse[12] & 0x40) == 0x40, + VSA_SUP = (pageResponse[12] & 0x20) == 0x20, + MaximumSenseLength = pageResponse[13] + }; + } + + public static string PrettifyPage_86(byte[] pageResponse) => PrettifyPage_86(DecodePage_86(pageResponse)); + + public static string PrettifyPage_86(Page_86? modePage) + { + if(!modePage.HasValue) return null; + + Page_86 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Extended_INQUIRY_Data); + + switch(page.PeripheralDeviceType) + { + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.SCSIZonedBlockDevice: + switch(page.SPT) + { + case 0: + sb.AppendLine(Localization.Logical_unit_supports_type_1_protection); + + break; + case 1: + sb.AppendLine(Localization.Logical_unit_supports_types_1_and_2_protection); + + break; + case 2: + sb.AppendLine(Localization.Logical_unit_supports_type_2_protection); + + break; + case 3: + sb.AppendLine(Localization.Logical_unit_supports_types_1_and_3_protection); + + break; + case 4: + sb.AppendLine(Localization.Logical_unit_supports_type_3_protection); + + break; + case 5: + sb.AppendLine(Localization.Logical_unit_supports_types_2_and_3_protection); + + break; + case 7: + sb.AppendLine(Localization.Logical_unit_supports_types_1_2_and_3_protection); + + break; + default: + sb.AppendFormat(Localization.Logical_unit_supports_unknown_protection_defined_by_code_0, + page.SPT) + .AppendLine(); + + break; + } + + break; + case PeripheralDeviceTypes.SequentialAccess when page.SPT == 1: + sb.AppendLine(Localization.Logical_unit_supports_logical_block_protection); + + break; + } + + if(page.GRD_CHK) sb.AppendLine(Localization.Device_checks_the_logical_block_guard); + + if(page.APP_CHK) sb.AppendLine(Localization.Device_checks_the_logical_block_application_tag); + + if(page.REF_CHK) sb.AppendLine(Localization.Device_checks_the_logical_block_reference_tag); + + if(page.UASK_SUP) sb.AppendLine(Localization.Device_supports_unit_attention_condition_sense_key_specific_data); + + if(page.GROUP_SUP) sb.AppendLine(Localization.Device_supports_grouping); + + if(page.PRIOR_SUP) sb.AppendLine(Localization.Device_supports_priority); + + if(page.HEADSUP) sb.AppendLine(Localization.Device_supports_head_of_queue); + + if(page.ORDSUP) sb.AppendLine(Localization.Device_supports_the_ORDERED_task_attribute); + + if(page.SIMPSUP) sb.AppendLine(Localization.Device_supports_the_SIMPLE_task_attribute); + + if(page.WU_SUP) sb.AppendLine(Localization.Device_supports_marking_a_block_as_uncorrectable_with_WRITE_LONG); + + if(page.CRD_SUP) sb.AppendLine(Localization.Device_supports_disabling_correction_with_WRITE_LONG); + + if(page.NV_SUP) sb.AppendLine(Localization.Device_has_a_non_volatile_cache); + + if(page.V_SUP) sb.AppendLine(Localization.Device_has_a_volatile_cache); + + if(page.NO_PI_CHK) sb.AppendLine(Localization.Device_has_disabled_protection_information_checks); + + if(page.P_I_I_SUP) sb.AppendLine(Localization.Device_supports_protection_information_intervals); + + if(page.LUICLR) + { + sb.AppendLine(Localization + .Device_clears_any_unit_attention_condition_in_all_LUNs_after_reporting_for_any_LUN); + } + + if(page.R_SUP) sb.AppendLine(Localization.Device_supports_referrals); + + if(page.HSSRELEF) sb.AppendLine(Localization.Device_implements_alternate_reset_handling); + + if(page.CBCS) sb.AppendLine(Localization.Device_supports_capability_based_command_security); + + if(page.POA_SUP) sb.AppendLine(Localization.Device_supports_power_on_activation_for_new_microcode); + + if(page.HRA_SUP) sb.AppendLine(Localization.Device_supports_hard_reset_activation_for_new_microcode); + + if(page.VSA_SUP) sb.AppendLine(Localization.Device_supports_vendor_specific_activation_for_new_microcode); + + if(page.ExtendedTestMinutes > 0) + { + sb.AppendFormat(Localization.Extended_self_test_takes_0_to_complete, + TimeSpan.FromMinutes(page.ExtendedTestMinutes)) + .AppendLine(); + } + + if(page.MaximumSenseLength > 0) + { + sb.AppendFormat(Localization.Device_supports_a_maximum_of_0_bytes_for_sense_data, page.MaximumSenseLength) + .AppendLine(); + } + + return sb.ToString(); + } + +#endregion EVPD Page 0x86: Extended INQUIRY data page + +#region EVPD Page 0x89: ATA Information page + + /// ATA Information page Page code 0x89 + public struct Page_89 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public ushort PageLength; + /// Contains the SAT vendor identification + public byte[] VendorIdentification; + /// Contains the SAT product identification + public byte[] ProductIdentification; + /// Contains the SAT revision level + public byte[] ProductRevisionLevel; + /// Contains the ATA device signature + public byte[] Signature; + /// Contains the command code used to identify the device + public byte CommandCode; + /// Contains the response to ATA IDENTIFY (PACKET) DEVICE + public byte[] IdentifyData; + } + + public static Page_89? DecodePage_89(byte[] pageResponse) + { + if(pageResponse?[1] != 0x89) return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) return null; + + if(pageResponse.Length < 572) return null; + + var decoded = new Page_89 + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (ushort)((pageResponse[2] << 8) + pageResponse[3] + 4), + VendorIdentification = new byte[8], + ProductIdentification = new byte[16], + ProductRevisionLevel = new byte[4], + Signature = new byte[20], + IdentifyData = new byte[512] + }; + + Array.Copy(pageResponse, 8, decoded.VendorIdentification, 0, 8); + Array.Copy(pageResponse, 16, decoded.ProductIdentification, 0, 16); + Array.Copy(pageResponse, 32, decoded.ProductRevisionLevel, 0, 4); + Array.Copy(pageResponse, 36, decoded.Signature, 0, 20); + decoded.CommandCode = pageResponse[56]; + Array.Copy(pageResponse, 60, decoded.IdentifyData, 0, 512); + + return decoded; + } + + public static string PrettifyPage_89(byte[] pageResponse) => PrettifyPage_89(DecodePage_89(pageResponse)); + + // TODO: Decode ATA signature? + public static string PrettifyPage_89(Page_89? modePage) + { + if(!modePage.HasValue) return null; + + Page_89 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_to_ATA_Translation_Layer_Data); + + sb.AppendFormat("\t" + Localization.Translation_layer_vendor_0, + VendorString.Prettify(StringHandlers.CToString(page.VendorIdentification).Trim())) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Translation_layer_name_0, + StringHandlers.CToString(page.ProductIdentification).Trim()) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Translation_layer_release_level_0, + StringHandlers.CToString(page.ProductRevisionLevel).Trim()) + .AppendLine(); + + switch(page.CommandCode) + { + case 0xEC: + sb.AppendLine("\t" + Localization.Device_responded_to_ATA_IDENTIFY_DEVICE_command); + + break; + case 0xA1: + sb.AppendLine("\t" + Localization.Device_responded_to_ATA_IDENTIFY_PACKET_DEVICE_command); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_responded_to_ATA_command_0, page.CommandCode).AppendLine(); + + break; + } + + switch(page.Signature[0]) + { + case 0x00: + sb.AppendLine("\t" + Localization.Device_uses_Parallel_ATA); + + break; + case 0x34: + sb.AppendLine("\t" + Localization.Device_uses_Serial_ATA); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_uses_unknown_transport_with_code_0, page.Signature[0]) + .AppendLine(); + + break; + } + + Identify.IdentifyDevice? id = Identify.Decode(page.IdentifyData); + + if(id != null) + { + sb.AppendLine("\t" + Localization.ATA_IDENTIFY_information_follows); + sb.Append($"{ATA.Identify.Prettify(id)}").AppendLine(); + } + else + sb.AppendLine("\t" + Localization.Could_not_decode_ATA_IDENTIFY_information); + + return sb.ToString(); + } + +#endregion EVPD Page 0x89: ATA Information page + +#region EVPD Page 0xC0 (Quantum): Firmware Build Information page + + /// Firmware Build Information page Page code 0xC0 (Quantum) + public struct Page_C0_Quantum + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// Servo firmware checksum + public ushort ServoFirmwareChecksum; + /// Servo EEPROM checksum + public ushort ServoEEPROMChecksum; + /// Read/Write firmware checksum + public uint ReadWriteFirmwareChecksum; + /// Read/Write firmware build data + public byte[] ReadWriteFirmwareBuildData; + } + + public static Page_C0_Quantum? DecodePage_C0_Quantum(byte[] pageResponse) + { + if(pageResponse?[1] != 0xC0) return null; + + if(pageResponse[3] != 20) return null; + + if(pageResponse.Length != 36) return null; + + var decoded = new Page_C0_Quantum + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + ServoFirmwareChecksum = (ushort)((pageResponse[4] << 8) + pageResponse[5]), + ServoEEPROMChecksum = (ushort)((pageResponse[6] << 8) + pageResponse[7]), + ReadWriteFirmwareChecksum = (uint)((pageResponse[8] << 24) + + (pageResponse[9] << 16) + + (pageResponse[10] << 8) + + pageResponse[11]), + ReadWriteFirmwareBuildData = new byte[24] + }; + + Array.Copy(pageResponse, 12, decoded.ReadWriteFirmwareBuildData, 0, 24); + + return decoded; + } + + public static string PrettifyPage_C0_Quantum(byte[] pageResponse) => + PrettifyPage_C0_Quantum(DecodePage_C0_Quantum(pageResponse)); + + public static string PrettifyPage_C0_Quantum(Page_C0_Quantum? modePage) + { + if(!modePage.HasValue) return null; + + Page_C0_Quantum page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Quantum_Quantum_Firmware_Build_Information_page); + + sb.AppendFormat("\t" + Localization.Quantum_Servo_firmware_checksum_0, page.ServoFirmwareChecksum).AppendLine(); + sb.AppendFormat("\t" + Localization.Quantum_EEPROM_firmware_checksum_0, page.ServoEEPROMChecksum).AppendLine(); + + sb.AppendFormat("\t" + Localization.Quantum_Read_write_firmware_checksum_0, page.ReadWriteFirmwareChecksum) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Quantum_Read_write_firmware_build_date_0, + StringHandlers.CToString(page.ReadWriteFirmwareBuildData)) + .AppendLine(); + + return sb.ToString(); + } + +#endregion EVPD Page 0xC0 (Quantum): Firmware Build Information page + +#region EVPD Pages 0xC0, 0xC1 (Certance): Drive component revision level pages + + /// Drive component revision level pages Page codes 0xC0, 0xC1 (Certance) + public struct Page_C0_C1_Certance + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] Component; + public byte[] Version; + public byte[] Date; + public byte[] Variant; + } + + public static Page_C0_C1_Certance? DecodePage_C0_C1_Certance(byte[] pageResponse) + { + if(pageResponse == null) return null; + + if(pageResponse[1] != 0xC0 && pageResponse[1] != 0xC1) return null; + + if(pageResponse[3] != 92) return null; + + if(pageResponse.Length != 96) return null; + + var decoded = new Page_C0_C1_Certance + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + Component = new byte[26], + Version = new byte[19], + Date = new byte[24], + Variant = new byte[23] + }; + + Array.Copy(pageResponse, 4, decoded.Component, 0, 26); + Array.Copy(pageResponse, 30, decoded.Version, 0, 19); + Array.Copy(pageResponse, 49, decoded.Date, 0, 24); + Array.Copy(pageResponse, 73, decoded.Variant, 0, 23); + + return decoded; + } + + public static string PrettifyPage_C0_C1_Certance(byte[] pageResponse) => + PrettifyPage_C0_C1_Certance(DecodePage_C0_C1_Certance(pageResponse)); + + public static string PrettifyPage_C0_C1_Certance(Page_C0_C1_Certance? modePage) + { + if(!modePage.HasValue) return null; + + Page_C0_C1_Certance page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Certance_Certance_Drive_Component_Revision_Levels_page); + + sb.AppendFormat("\t" + Localization.Certance_Component_0, StringHandlers.CToString(page.Component)) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Certance_Version_0, StringHandlers.CToString(page.Version)).AppendLine(); + sb.AppendFormat("\t" + Localization.Certance_Date_0, StringHandlers.CToString(page.Date)).AppendLine(); + sb.AppendFormat("\t" + Localization.Certance_Variant_0, StringHandlers.CToString(page.Variant)).AppendLine(); + + return sb.ToString(); + } + +#endregion EVPD Pages 0xC0, 0xC1 (Certance): Drive component revision level pages + +#region EVPD Pages 0xC2, 0xC3, 0xC4, 0xC5, 0xC6 (Certance): Drive component serial number pages + + /// Drive component serial number pages Page codes 0xC2, 0xC3, 0xC4, 0xC5, 0xC6 (Certance) + public struct Page_C2_C3_C4_C5_C6_Certance + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] SerialNumber; + } + + public static Page_C2_C3_C4_C5_C6_Certance? DecodePage_C2_C3_C4_C5_C6_Certance(byte[] pageResponse) + { + if(pageResponse == null) return null; + + if(pageResponse[1] != 0xC2 && + pageResponse[1] != 0xC3 && + pageResponse[1] != 0xC4 && + pageResponse[1] != 0xC5 && + pageResponse[1] != 0xC6) + return null; + + if(pageResponse[3] != 12) return null; + + if(pageResponse.Length != 16) return null; + + var decoded = new Page_C2_C3_C4_C5_C6_Certance + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + SerialNumber = new byte[12] + }; + + Array.Copy(pageResponse, 4, decoded.SerialNumber, 0, 12); + + return decoded; + } + + public static string PrettifyPage_C2_C3_C4_C5_C6_Certance(byte[] pageResponse) => + PrettifyPage_C2_C3_C4_C5_C6_Certance(DecodePage_C2_C3_C4_C5_C6_Certance(pageResponse)); + + public static string PrettifyPage_C2_C3_C4_C5_C6_Certance(Page_C2_C3_C4_C5_C6_Certance? modePage) + { + if(!modePage.HasValue) return null; + + Page_C2_C3_C4_C5_C6_Certance page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Certance_Certance_Drive_Component_Serial_Number_page); + + switch(page.PageCode) + { + case 0xC2: + sb.AppendFormat("\t" + Localization.Certance_Head_Assembly_Serial_Number_0, + StringHandlers.CToString(page.SerialNumber)) + .AppendLine(); + + break; + case 0xC3: + sb.AppendFormat("\t" + Localization.Certance_Reel_Motor_1_Serial_Number_0, + StringHandlers.CToString(page.SerialNumber)) + .AppendLine(); + + break; + case 0xC4: + sb.AppendFormat("\t" + Localization.Certance_Reel_Motor_2_Serial_Number_0, + StringHandlers.CToString(page.SerialNumber)) + .AppendLine(); + + break; + case 0xC5: + sb.AppendFormat("\t" + Localization.Certance_Board_Serial_Number_0, + StringHandlers.CToString(page.SerialNumber)) + .AppendLine(); + + break; + case 0xC6: + sb.AppendFormat("\t" + Localization.Certance_Base_Mechanical_Serial_Number_0, + StringHandlers.CToString(page.SerialNumber)) + .AppendLine(); + + break; + } + + return sb.ToString(); + } + +#endregion EVPD Pages 0xC0, 0xC1 (Certance): Drive component revision level pages + +#region EVPD Page 0xDF (Certance): Drive status pages + + /// Drive status pages Page codes 0xDF (Certance) + public struct Page_DF_Certance + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// Command forwarding + public byte CmdFwd; + /// Alerts + public bool Alerts; + /// Removable prevention + public bool NoRemov; + /// Unit reservation + public bool UnitRsvd; + /// Needs cleaning + public bool Clean; + /// Tape threaded + public bool Threaded; + /// Commands await forwarding + public bool Lun1Cmd; + /// Autoload mode + public byte AutoloadMode; + /// Cartridge type + public byte CartridgeType; + /// Cartridge format + public byte CartridgeFormat; + /// Cartridge capacity in 10e9 bytes + public ushort CartridgeCapacity; + /// Port A transport type + public byte PortATransportType; + /// Port A SCSI ID + public byte PortASelectionID; + /// Total number of head-tape contact time + public uint OperatingHours; + /// ID that reserved the device + public ulong InitiatorID; + /// Cartridge serial number + public byte[] CartridgeSerialNumber; + } + + public static Page_DF_Certance? DecodePage_DF_Certance(byte[] pageResponse) + { + if(pageResponse?[1] != 0xDF) return null; + + if(pageResponse[3] != 60) return null; + + if(pageResponse.Length != 64) return null; + + var decoded = new Page_DF_Certance + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + CmdFwd = (byte)((pageResponse[5] & 0xC0) >> 5), + Alerts = (pageResponse[5] & 0x20) == 0x20, + NoRemov = (pageResponse[5] & 0x08) == 0x08, + UnitRsvd = (pageResponse[5] & 0x04) == 0x04, + Clean = (pageResponse[5] & 0x01) == 0x01, + Threaded = (pageResponse[6] & 0x10) == 0x10, + Lun1Cmd = (pageResponse[6] & 0x08) == 0x08, + AutoloadMode = (byte)(pageResponse[6] & 0x07), + CartridgeType = pageResponse[8], + CartridgeFormat = pageResponse[9], + CartridgeCapacity = (ushort)((pageResponse[10] << 8) + pageResponse[11] + 4), + PortATransportType = pageResponse[12], + PortASelectionID = pageResponse[15], + OperatingHours = (uint)((pageResponse[20] << 24) + + (pageResponse[21] << 16) + + (pageResponse[22] << 8) + + pageResponse[23]), + CartridgeSerialNumber = new byte[32] + }; + + var buf = new byte[8]; + Array.Copy(pageResponse, 24, buf, 0, 8); + decoded.InitiatorID = BitConverter.ToUInt64(buf.Reverse().ToArray(), 0); + Array.Copy(pageResponse, 32, decoded.CartridgeSerialNumber, 0, 32); + + return decoded; + } + + public static string PrettifyPage_DF_Certance(byte[] pageResponse) => + PrettifyPage_DF_Certance(DecodePage_DF_Certance(pageResponse)); + + public static string PrettifyPage_DF_Certance(Page_DF_Certance? modePage) + { + if(!modePage.HasValue) return null; + + Page_DF_Certance page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Certance_drive_status_page); + + switch(page.CmdFwd) + { + case 0: + sb.AppendLine("\t" + Localization.Command_forwarding_is_disabled); + + break; + case 1: + sb.AppendLine("\t" + Localization.Command_forwarding_is_enabled); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_command_forwarding_code_0, page.CmdFwd).AppendLine(); + + break; + } + + if(page.Alerts) sb.AppendLine("\t" + Localization.Alerts_are_enabled); + + if(page.NoRemov) sb.AppendLine("\t" + Localization.Cartridge_removable_is_prevented); + + if(page.UnitRsvd) + sb.AppendFormat("\t" + Localization.Unit_is_reserved_by_initiator_ID_0, page.InitiatorID).AppendLine(); + + if(page.Clean) sb.AppendLine("\t" + Localization.Device_needs_cleaning_cartridge); + + if(page.Threaded) sb.AppendLine("\t" + Localization.Cartridge_tape_is_threaded); + + if(page.Lun1Cmd) sb.AppendLine("\t" + Localization.There_are_commands_pending_to_be_forwarded); + + switch(page.AutoloadMode) + { + case 0: + sb.AppendLine("\t" + Localization.Cartridge_will_be_loaded_and_threaded_on_insertion); + + break; + case 1: + sb.AppendLine("\t" + Localization.Cartridge_will_be_loaded_but_not_threaded_on_insertion); + + break; + case 2: + sb.AppendLine("\t" + Localization.Cartridge_will_not_be_loaded); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_autoloading_mode_code_0, page.AutoloadMode).AppendLine(); + + break; + } + + switch(page.PortATransportType) + { + case 0: + sb.AppendLine("\t" + Localization.Port_A_link_is_down); + + break; + case 3: + sb.AppendLine("\t" + Localization.Port_A_uses_Parallel_SCSI_Ultra_160_interface); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_port_A_transport_type_code_0, page.PortATransportType) + .AppendLine(); + + break; + } + + if(page.PortATransportType > 0) + sb.AppendFormat("\t" + Localization.Drive_responds_to_SCSI_ID_0, page.PortASelectionID).AppendLine(); + + sb.AppendFormat("\t" + Localization.Drive_has_been_operating_0, TimeSpan.FromHours(page.OperatingHours)) + .AppendLine(); + + if(page.CartridgeType > 0) + { + switch(page.CartridgeFormat) + { + case 0: + sb.AppendLine("\t" + Localization.Inserted_cartridge_is_LTO); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_cartridge_format_code_0, page.CartridgeType) + .AppendLine(); + + break; + } + + switch(page.CartridgeType) + { + case 0: + sb.AppendLine("\t" + Localization.There_is_no_cartridge_inserted); + + break; + case 1: + sb.AppendLine("\t" + Localization.Cleaning_cartridge_inserted); + + break; + case 2: + sb.AppendLine("\t" + Localization.Unknown_data_cartridge_inserted); + + break; + case 3: + sb.AppendLine("\t" + Localization.Firmware_cartridge_inserted); + + break; + case 4: + sb.AppendLine("\t" + Localization.LTO_Ultrium_1_Type_A_cartridge_inserted); + + break; + case 5: + sb.AppendLine("\t" + Localization.LTO_Ultrium_1_Type_B_cartridge_inserted); + + break; + case 6: + sb.AppendLine("\t" + Localization.LTO_Ultrium_1_Type_C_cartridge_inserted); + + break; + case 7: + sb.AppendLine("\t" + Localization.LTO_Ultrium_1_Type_D_cartridge_inserted); + + break; + case 8: + sb.AppendLine("\t" + Localization.LTO_Ultrium_2_cartridge_inserted); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_cartridge_type_code_0, page.CartridgeType).AppendLine(); + + break; + } + + sb.AppendFormat("\t" + Localization.Cartridge_has_an_uncompressed_capability_of_0_gigabytes, + page.CartridgeCapacity) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Cartridge_serial_number_0, + StringHandlers.SpacePaddedToString(page.CartridgeSerialNumber)) + .AppendLine(); + } + else + sb.AppendLine("\t" + Localization.There_is_no_cartridge_inserted); + + return sb.ToString(); + } + +#endregion EVPD Page 0xDF (Certance): Drive status pages + +#region EVPD Page 0xC0 (IBM): Drive Component Revision Levels page + + /// Drive Component Revision Levels page Page code 0xC0 (IBM) + public struct Page_C0_IBM + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] CodeName; + public byte[] Date; + } + + public static Page_C0_IBM? DecodePage_C0_IBM(byte[] pageResponse) + { + if(pageResponse?[1] != 0xC0) return null; + + if(pageResponse[3] != 39) return null; + + if(pageResponse.Length != 43) return null; + + var decoded = new Page_C0_IBM + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + CodeName = new byte[12], + Date = new byte[8] + }; + + Array.Copy(pageResponse, 4, decoded.CodeName, 0, 12); + Array.Copy(pageResponse, 23, decoded.Date, 0, 8); + + return decoded; + } + + public static string PrettifyPage_C0_IBM(byte[] pageResponse) => + PrettifyPage_C0_IBM(DecodePage_C0_IBM(pageResponse)); + + public static string PrettifyPage_C0_IBM(Page_C0_IBM? modePage) + { + if(!modePage.HasValue) return null; + + Page_C0_IBM page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.IBM_Drive_Component_Revision_Levels_page); + + sb.AppendFormat("\t" + Localization.Code_name_0, StringHandlers.CToString(page.CodeName)).AppendLine(); + sb.AppendFormat("\t" + Localization.Certance_Date_0, StringHandlers.CToString(page.Date)).AppendLine(); + + return sb.ToString(); + } + +#endregion EVPD Page 0xC0 (IBM): Drive Component Revision Levels page + +#region EVPD Page 0xC1 (IBM): Drive Serial Numbers page + + /// Drive Serial Numbers page Page code 0xC1 (IBM) + public struct Page_C1_IBM + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] ManufacturingSerial; + public byte[] ReportedSerial; + } + + public static Page_C1_IBM? DecodePage_C1_IBM(byte[] pageResponse) + { + if(pageResponse?[1] != 0xC1) return null; + + if(pageResponse[3] != 24) return null; + + if(pageResponse.Length != 28) return null; + + var decoded = new Page_C1_IBM + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + ManufacturingSerial = new byte[12], + ReportedSerial = new byte[12] + }; + + Array.Copy(pageResponse, 4, decoded.ManufacturingSerial, 0, 12); + Array.Copy(pageResponse, 16, decoded.ReportedSerial, 0, 12); + + return decoded; + } + + public static string PrettifyPage_C1_IBM(byte[] pageResponse) => + PrettifyPage_C1_IBM(DecodePage_C1_IBM(pageResponse)); + + public static string PrettifyPage_C1_IBM(Page_C1_IBM? modePage) + { + if(!modePage.HasValue) return null; + + Page_C1_IBM page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.IBM_Drive_Serial_Numbers_page); + + sb.AppendFormat("\t" + Localization.Manufacturing_serial_number_0, + StringHandlers.CToString(page.ManufacturingSerial)) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Reported_serial_number_0, StringHandlers.CToString(page.ReportedSerial)) + .AppendLine(); + + return sb.ToString(); + } + +#endregion EVPD Page 0xC1 (IBM): Drive Serial Numbers page + +#region EVPD Page 0xB0: Sequential-access device capabilities page + + /// Sequential-access device capabilities page Page code 0xB0 + public struct Page_B0 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public ushort PageLength; + public bool TSMC; + public bool WORM; + } + + public static Page_B0? DecodePage_B0(byte[] pageResponse) + { + if(pageResponse?[1] != 0xB0) return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) return null; + + if(pageResponse.Length < 5) return null; + + var decoded = new Page_B0 + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (ushort)((pageResponse[2] << 8) + pageResponse[3] + 4), + TSMC = (pageResponse[4] & 0x02) == 0x02, + WORM = (pageResponse[4] & 0x01) == 0x01 + }; + + return decoded; + } + + public static string PrettifyPage_B0(byte[] pageResponse) => PrettifyPage_B0(DecodePage_B0(pageResponse)); + + public static string PrettifyPage_B0(Page_B0? modePage) + { + if(!modePage.HasValue) return null; + + Page_B0 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Sequential_access_Device_Capabilities); + + if(page.WORM) sb.AppendLine("\t" + Localization.Device_supports_WORM_media); + + if(page.TSMC) sb.AppendLine("\t" + Localization.Device_supports_Tape_Stream_Mirroring); + + return sb.ToString(); + } + +#endregion EVPD Page 0xB0: Sequential-access device capabilities page + +#region EVPD Pages 0xC0 to 0xC5 (HP): Drive component revision level pages + + /// Drive component revision level pages Page codes 0xC0 to 0xC5 (HP) + public struct Page_C0_to_C5_HP + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] Component; + public byte[] Version; + public byte[] Date; + public byte[] Variant; + public byte[] Copyright; + } + + public static Page_C0_to_C5_HP? DecodePage_C0_to_C5_HP(byte[] pageResponse) + { + if(pageResponse == null) return null; + + if(pageResponse[1] != 0xC0 && + pageResponse[1] != 0xC1 && + pageResponse[1] != 0xC2 && + pageResponse[1] != 0xC3 && + pageResponse[1] != 0xC4 && + pageResponse[1] != 0xC5) + return null; + + if(pageResponse.Length < 4) return null; + + var decoded = new Page_C0_to_C5_HP + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + PageCode = pageResponse[1] + }; + + if(pageResponse[3] == 92 && pageResponse.Length >= 96) + { + decoded.Component = new byte[26]; + decoded.Version = new byte[19]; + decoded.Date = new byte[24]; + decoded.Variant = new byte[23]; + + Array.Copy(pageResponse, 4, decoded.Component, 0, 26); + Array.Copy(pageResponse, 30, decoded.Version, 0, 19); + Array.Copy(pageResponse, 49, decoded.Date, 0, 24); + Array.Copy(pageResponse, 73, decoded.Variant, 0, 23); + + return decoded; + } + + if(pageResponse[4] != pageResponse[3] - 1) return null; + + List array = []; + + const string fwRegExStr = @"Firmware Rev\s+=\s+(?\d+\.\d+)\s+Build date\s+=\s+(?(\w|\d|\s*.)*)\s*$"; + + const string fwcRegExStr = @"FW_CONF\s+=\s+(?0x[0-9A-Fa-f]{8})\s*$"; + const string servoRegExStr = @"Servo\s+Rev\s+=\s+(?\d+\.\d+)\s*$"; + var fwRegEx = new Regex(fwRegExStr); + var fwcRegEx = new Regex(fwcRegExStr); + var servoRegEx = new Regex(servoRegExStr); + + for(var pos = 5; pos < pageResponse.Length; pos++) + { + if(pageResponse[pos] == 0x00) + { + string str = StringHandlers.CToString(array.ToArray()); + Match fwMatch = fwRegEx.Match(str); + Match fwcMatch = fwcRegEx.Match(str); + Match servoMatch = servoRegEx.Match(str); + + if(str.ToLowerInvariant().StartsWith("copyright", StringComparison.Ordinal)) + decoded.Copyright = Encoding.ASCII.GetBytes(str); + else if(fwMatch.Success) + { + decoded.Component = "Firmware"u8.ToArray(); + decoded.Version = Encoding.ASCII.GetBytes(fwMatch.Groups["fw"].Value); + decoded.Date = Encoding.ASCII.GetBytes(fwMatch.Groups["date"].Value); + } + else if(fwcMatch.Success) + decoded.Variant = Encoding.ASCII.GetBytes(fwMatch.Groups["value"].Value); + else if(servoMatch.Success) + { + decoded.Component = "Servo"u8.ToArray(); + decoded.Version = Encoding.ASCII.GetBytes(servoMatch.Groups["version"].Value); + } + + array = []; + } + else + array.Add(pageResponse[pos]); + } + + return decoded; + } + + public static string PrettifyPage_C0_to_C5_HP(byte[] pageResponse) => + PrettifyPage_C0_to_C5_HP(DecodePage_C0_to_C5_HP(pageResponse)); + + public static string PrettifyPage_C0_to_C5_HP(Page_C0_to_C5_HP? modePage) + { + if(!modePage.HasValue) return null; + + Page_C0_to_C5_HP page = modePage.Value; + var sb = new StringBuilder(); + + switch(page.PageCode) + { + case 0xC0: + sb.AppendLine(Localization.HP_Drive_Firmware_Revision_Levels_page); + + break; + case 0xC1: + sb.AppendLine(Localization.HP_Drive_Hardware_Revision_Levels_page); + + break; + case 0xC2: + sb.AppendLine(Localization.HP_Drive_PCA_Revision_Levels_page); + + break; + case 0xC3: + sb.AppendLine(Localization.HP_Drive_Mechanism_Revision_Levels_page); + + break; + case 0xC4: + sb.AppendLine(Localization.HP_Drive_Head_Assembly_Revision_Levels_page); + + break; + case 0xC5: + sb.AppendLine(Localization.HP_Drive_ACI_Revision_Levels_page); + + break; + } + + if(page.Component is { Length: > 0 }) + { + sb.AppendFormat("\t" + Localization.Certance_Component_0, StringHandlers.CToString(page.Component)) + .AppendLine(); + } + + if(page.Version is { Length: > 0 }) + { + sb.AppendFormat("\t" + Localization.Certance_Version_0, StringHandlers.CToString(page.Version)) + .AppendLine(); + } + + if(page.Date is { Length: > 0 }) + sb.AppendFormat("\t" + Localization.Certance_Date_0, StringHandlers.CToString(page.Date)).AppendLine(); + + if(page.Variant is { Length: > 0 }) + { + sb.AppendFormat("\t" + Localization.Certance_Variant_0, StringHandlers.CToString(page.Variant)) + .AppendLine(); + } + + if(page.Copyright is { Length: > 0 }) + sb.AppendFormat("\t" + Localization.Copyright_0, StringHandlers.CToString(page.Copyright)).AppendLine(); + + return sb.ToString(); + } + +#endregion EVPD Pages 0xC0 to 0xC5 (HP): Drive component revision level pages + +#region EVPD Page 0xC0 (Seagate): Firmware numbers page + + /// Firmware numbers page Page code 0xC0 (Seagate) + public struct Page_C0_Seagate + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] ControllerFirmware; + public byte[] BootFirmware; + public byte[] ServoFirmware; + } + + public static Page_C0_Seagate? DecodePage_C0_Seagate(byte[] pageResponse) + { + if(pageResponse?[1] != 0xC0) return null; + + if(pageResponse[3] != 12) return null; + + if(pageResponse.Length != 16) return null; + + var decoded = new Page_C0_Seagate + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + PageCode = pageResponse[1], + ControllerFirmware = new byte[4], + BootFirmware = new byte[4], + ServoFirmware = new byte[4] + }; + + Array.Copy(pageResponse, 4, decoded.ControllerFirmware, 0, 4); + Array.Copy(pageResponse, 8, decoded.BootFirmware, 0, 4); + Array.Copy(pageResponse, 12, decoded.ServoFirmware, 0, 4); + + return decoded; + } + + public static string PrettifyPage_C0_Seagate(byte[] pageResponse) => + PrettifyPage_C0_Seagate(DecodePage_C0_Seagate(pageResponse)); + + public static string PrettifyPage_C0_Seagate(Page_C0_Seagate? modePage) + { + if(!modePage.HasValue) return null; + + Page_C0_Seagate page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Seagate_Firmware_Numbers_page); + + sb.AppendFormat("\t" + Localization.Controller_firmware_version_0, + StringHandlers.CToString(page.ControllerFirmware)) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Boot_firmware_version_0, StringHandlers.CToString(page.BootFirmware)) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Servo_firmware_version_0, StringHandlers.CToString(page.ServoFirmware)) + .AppendLine(); + + return sb.ToString(); + } + +#endregion EVPD Page 0xC0 (Seagate): Firmware numbers page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Inquiry.cs b/Aaru.Decoders/SCSI/Inquiry.cs new file mode 100644 index 000000000..c3f58c7db --- /dev/null +++ b/Aaru.Decoders/SCSI/Inquiry.cs @@ -0,0 +1,2513 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Inquiry.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI INQUIRY responses. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.Structs.Devices.SCSI; +using Aaru.Helpers; +using Aaru.Localization; + +namespace Aaru.Decoders.SCSI; + +// Information from the following standards: +// T9/375-D revision 10l +// T10/995-D revision 10 +// T10/1236-D revision 20 +// T10/1416-D revision 23 +// T10/1731-D revision 16 +// T10/502 revision 05 +// RFC 7144 +// ECMA-111 +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Inquiry +{ + public static string Prettify(CommonTypes.Structs.Devices.SCSI.Inquiry? SCSIInquiryResponse) + { + if(SCSIInquiryResponse == null) return null; + + CommonTypes.Structs.Devices.SCSI.Inquiry response = SCSIInquiryResponse.Value; + + var sb = new StringBuilder(); + + sb.AppendFormat(Localization.Device_vendor_0, + VendorString.Prettify(StringHandlers.CToString(response.VendorIdentification).Trim())) + .AppendLine(); + + sb.AppendFormat(Localization.Device_name_0, StringHandlers.CToString(response.ProductIdentification).Trim()) + .AppendLine(); + + sb.AppendFormat(Localization.Device_release_level_0, + StringHandlers.CToString(response.ProductRevisionLevel).Trim()) + .AppendLine(); + + switch((PeripheralQualifiers)response.PeripheralQualifier) + { + case PeripheralQualifiers.Supported: + sb.AppendLine(Localization.Device_is_connected_and_supported); + + break; + case PeripheralQualifiers.Unconnected: + sb.AppendLine(Localization.Device_is_supported_but_not_connected); + + break; + case PeripheralQualifiers.Reserved: + sb.AppendLine(Localization.Reserved_value_set_in_Peripheral_Qualifier_field); + + break; + case PeripheralQualifiers.Unsupported: + sb.AppendLine(Localization.Device_is_connected_but_unsupported); + + break; + default: + sb.AppendFormat(Localization.Vendor_value_0_set_in_Peripheral_Qualifier_field, + response.PeripheralQualifier) + .AppendLine(); + + break; + } + + switch((PeripheralDeviceTypes)response.PeripheralDeviceType) + { + case PeripheralDeviceTypes.DirectAccess: //0x00, + sb.AppendLine(Localization.Direct_access_device); + + break; + case PeripheralDeviceTypes.SequentialAccess: //0x01, + sb.AppendLine(Localization.Sequential_access_device); + + break; + case PeripheralDeviceTypes.PrinterDevice: //0x02, + sb.AppendLine(Localization.Printer_device); + + break; + case PeripheralDeviceTypes.ProcessorDevice: //0x03, + sb.AppendLine(Localization.Processor_device); + + break; + case PeripheralDeviceTypes.WriteOnceDevice: //0x04, + sb.AppendLine(Localization.Write_once_device); + + break; + case PeripheralDeviceTypes.MultiMediaDevice: //0x05, + sb.AppendLine(Localization.CD_ROM_DVD_etc_device); + + break; + case PeripheralDeviceTypes.ScannerDevice: //0x06, + sb.AppendLine(Localization.Scanner_device); + + break; + case PeripheralDeviceTypes.OpticalDevice: //0x07, + sb.AppendLine(Localization.Optical_memory_device); + + break; + case PeripheralDeviceTypes.MediumChangerDevice: //0x08, + sb.AppendLine(Localization.Medium_change_device); + + break; + case PeripheralDeviceTypes.CommsDevice: //0x09, + sb.AppendLine(Localization.Communications_device); + + break; + case PeripheralDeviceTypes.PrePressDevice1: //0x0A, + sb.AppendLine(Localization.Graphics_arts_pre_press_device_defined_in_ASC_IT8); + + break; + case PeripheralDeviceTypes.PrePressDevice2: //0x0B, + sb.AppendLine(Localization.Graphics_arts_pre_press_device_defined_in_ASC_IT8); + + break; + case PeripheralDeviceTypes.ArrayControllerDevice: //0x0C, + sb.AppendLine(Localization.Array_controller_device); + + break; + case PeripheralDeviceTypes.EnclosureServiceDevice: //0x0D, + sb.AppendLine(Localization.Enclosure_services_device); + + break; + case PeripheralDeviceTypes.SimplifiedDevice: //0x0E, + sb.AppendLine(Localization.Simplified_direct_access_device); + + break; + case PeripheralDeviceTypes.OCRWDevice: //0x0F, + sb.AppendLine(Localization.Optical_card_reader_writer_device); + + break; + case PeripheralDeviceTypes.BridgingExpander: //0x10, + sb.AppendLine(Localization.Bridging_Expanders); + + break; + case PeripheralDeviceTypes.ObjectDevice: //0x11, + sb.AppendLine(Localization.Object_based_Storage_Device); + + break; + case PeripheralDeviceTypes.ADCDevice: //0x12, + sb.AppendLine(Localization.Automation_Drive_Interface); + + break; + case PeripheralDeviceTypes.SCSISecurityManagerDevice: //0x13, + sb.AppendLine(Localization.Security_Manager_Device); + + break; + case PeripheralDeviceTypes.SCSIZonedBlockDevice: //0x14 + sb.AppendLine(Localization.Host_managed_zoned_block_device); + + break; + case PeripheralDeviceTypes.WellKnownDevice: //0x1E, + sb.AppendLine(Localization.Well_known_logical_unit); + + break; + case PeripheralDeviceTypes.UnknownDevice: //0x1F + sb.AppendLine(Localization.Unknown_or_no_device_type); + + break; + default: + sb.AppendFormat(Localization.Unknown_device_type_field_value_0, response.PeripheralDeviceType) + .AppendLine(); + + break; + } + + switch((ANSIVersions)response.ANSIVersion) + { + case ANSIVersions.ANSINoVersion: + sb.AppendLine(Localization.Device_does_not_claim_to_comply_with_any_SCSI_ANSI_standard); + + break; + case ANSIVersions.ANSI1986Version: + sb.AppendLine(Localization.Device_claims_to_comply_with_ANSI_X3_131_1986_SCSI_1); + + break; + case ANSIVersions.ANSI1994Version: + sb.AppendLine(Localization.Device_claims_to_comply_with_ANSI_X3_131_1994_SCSI_2); + + break; + case ANSIVersions.ANSI1997Version: + sb.AppendLine(Localization.Device_claims_to_comply_with_ANSI_X3_301_1997_SPC_1); + + break; + case ANSIVersions.ANSI2001Version: + sb.AppendLine(Localization.Device_claims_to_comply_with_ANSI_X3_351_2001_SPC_2); + + break; + case ANSIVersions.ANSI2005Version: + sb.AppendLine(Localization.Device_claims_to_comply_with_ANSI_X3_408_2005_SPC_3); + + break; + case ANSIVersions.ANSI2008Version: + sb.AppendLine(Localization.Device_claims_to_comply_with_ANSI_X3_408_2005_SPC_4); + + break; + default: + sb.AppendFormat(Localization.Device_claims_to_comply_with_unknown_SCSI_ANSI_standard_value_0, + response.ANSIVersion) + .AppendLine(); + + break; + } + + switch((ECMAVersions)response.ECMAVersion) + { + case ECMAVersions.ECMANoVersion: + sb.AppendLine(Localization.Device_does_not_claim_to_comply_with_any_SCSI_ECMA_standard); + + break; + case ECMAVersions.ECMA111: + sb.AppendLine(Localization.Device_claims_to_comply_ECMA_111_Small_Computer_System_Interface_SCSI); + + break; + default: + sb.AppendFormat(Localization.Device_claims_to_comply_with_unknown_SCSI_ECMA_standard_value_0, + response.ECMAVersion) + .AppendLine(); + + break; + } + + switch((ISOVersions)response.ISOVersion) + { + case ISOVersions.ISONoVersion: + sb.AppendLine(Localization.Device_does_not_claim_to_comply_with_any_SCSI_ISO_IEC_standard); + + break; + case ISOVersions.ISO1995Version: + sb.AppendLine(Localization.Device_claims_to_comply_with_ISO_IEC_9316_1995); + + break; + default: + sb.AppendFormat(Localization.Device_claims_to_comply_with_unknown_SCSI_ISO_IEC_standard_value_0, + response.ISOVersion) + .AppendLine(); + + break; + } + + if(response.RMB) sb.AppendLine(Localization.Device_is_removable); + + if(response.AERC) sb.AppendLine(Localization.Device_supports_Asynchronous_Event_Reporting_Capability); + + if(response.TrmTsk) sb.AppendLine(Localization.Device_supports_TERMINATE_TASK_command); + + if(response.NormACA) sb.AppendLine(Localization.Device_supports_setting_Normal_ACA); + + if(response.HiSup) sb.AppendLine(Localization.Device_supports_LUN_hierarchical_addressing); + + if(response.SCCS) sb.AppendLine(Localization.Device_contains_an_embedded_storage_array_controller); + + if(response.ACC) sb.AppendLine(Localization.Device_contains_an_Access_Control_Coordinator); + + if(response.ThreePC) sb.AppendLine(Localization.Device_supports_third_party_copy_commands); + + if(response.Protect) sb.AppendLine(Localization.Device_supports_protection_information); + + if(response.BQue) sb.AppendLine(Localization.Device_supports_basic_queueing); + + if(response.EncServ) sb.AppendLine(Localization.Device_contains_an_embedded_enclosure_services_component); + + if(response.MultiP) sb.AppendLine(Localization.Multi_port_device); + + if(response.MChngr) sb.AppendLine(Localization.Device_contains_or_is_attached_to_a_medium_changer); + + if(response.ACKREQQ) sb.AppendLine(Localization.Device_supports_request_and_acknowledge_handshakes); + + if(response.Addr32) sb.AppendLine(Localization.Device_supports_32_bit_wide_SCSI_addresses); + + if(response.Addr16) sb.AppendLine(Localization.Device_supports_16_bit_wide_SCSI_addresses); + + if(response.RelAddr) sb.AppendLine(Localization.Device_supports_relative_addressing); + + if(response.WBus32) sb.AppendLine(Localization.Device_supports_32_bit_wide_data_transfers); + + if(response.WBus16) sb.AppendLine(Localization.Device_supports_16_bit_wide_data_transfers); + + if(response.Sync) sb.AppendLine(Localization.Device_supports_synchronous_data_transfer); + + if(response.Linked) sb.AppendLine(Localization.Device_supports_linked_commands); + + if(response.TranDis) + sb.AppendLine(Localization.Device_supports_CONTINUE_TASK_and_TARGET_TRANSFER_DISABLE_commands); + + if(response.QAS) sb.AppendLine(Localization.Device_supports_Quick_Arbitration_and_Selection); + + if(response.CmdQue) sb.AppendLine(Localization.Device_supports_TCQ_queue); + + if(response.IUS) sb.AppendLine(Localization.Device_supports_information_unit_transfers); + + if(response.SftRe) sb.AppendLine(Localization.Device_implements_RESET_as_a_soft_reset); +#if DEBUG + if(response.VS1) sb.AppendLine(Localization.Vendor_specific_bit_5_on_byte_6_of_INQUIRY_response_is_set); +#endif + + switch((TGPSValues)response.TPGS) + { + case TGPSValues.NotSupported: + sb.AppendLine(Localization.Device_does_not_support_asymmetrical_access); + + break; + case TGPSValues.OnlyImplicit: + sb.AppendLine(Localization.Device_only_supports_implicit_asymmetrical_access); + + break; + case TGPSValues.OnlyExplicit: + sb.AppendLine(Localization.Device_only_supports_explicit_asymmetrical_access); + + break; + case TGPSValues.Both: + sb.AppendLine(Localization.Device_supports_implicit_and_explicit_asymmetrical_access); + + break; + default: + sb.AppendFormat(Localization.Unknown_value_in_TPGS_field_0, response.TPGS).AppendLine(); + + break; + } + + switch((SPIClocking)response.Clocking) + { + case SPIClocking.ST: + sb.AppendLine(Localization.Device_supports_only_ST_clocking); + + break; + case SPIClocking.DT: + sb.AppendLine(Localization.Device_supports_only_DT_clocking); + + break; + case SPIClocking.Reserved: + sb.AppendLine(Localization.Reserved_value_0x02_found_in_SPI_clocking_field); + + break; + case SPIClocking.STandDT: + sb.AppendLine(Localization.Device_supports_ST_and_DT_clocking); + + break; + default: + sb.AppendFormat(Localization.Unknown_value_in_SPI_clocking_field_0, response.Clocking).AppendLine(); + + break; + } + + if(response.VersionDescriptors != null) + { + foreach(ushort VersionDescriptor in response.VersionDescriptors) + { + switch(VersionDescriptor) + { + case 0xFFFF: + case 0x0000: + break; + case 0x0020: + sb.AppendLine(Localization.Device_complies_with_SAM_no_version_claimed); + + break; + case 0x003B: + sb.AppendLine(Localization.Device_complies_with_SAM_T10_0994_D_revision_18); + + break; + case 0x003C: + sb.AppendLine(Localization.Device_complies_with_SAM_ANSI_INCITS_270_1996); + + break; + case 0x0040: + sb.AppendLine(Localization.Device_complies_with_SAM_2_no_version_claimed); + + break; + case 0x0054: + sb.AppendLine(Localization.Device_complies_with_SAM_2_T10_1157_D_revision_23); + + break; + case 0x0055: + sb.AppendLine(Localization.Device_complies_with_SAM_2_T10_1157_D_revision_24); + + break; + case 0x005C: + sb.AppendLine(Localization.Device_complies_with_SAM_2_ANSI_INCITS_366_2003); + + break; + case 0x005E: + sb.AppendLine(Localization.Device_complies_with_SAM_2_ISO_IEC_14776_412); + + break; + case 0x0060: + sb.AppendLine(Localization.Device_complies_with_SAM_3_no_version_claimed); + + break; + case 0x0062: + sb.AppendLine(Localization.Device_complies_with_SAM_3_T10_1561_D_revision_7); + + break; + case 0x0075: + sb.AppendLine(Localization.Device_complies_with_SAM_3_T10_1561_D_revision_13); + + break; + case 0x0076: + sb.AppendLine(Localization.Device_complies_with_SAM_3_T10_1561_D_revision_14); + + break; + case 0x0077: + sb.AppendLine(Localization.Device_complies_with_SAM_3_ANSI_INCITS_402_2005); + + break; + case 0x0080: + sb.AppendLine(Localization.Device_complies_with_SAM_4_no_version_claimed); + + break; + case 0x0087: + sb.AppendLine(Localization.Device_complies_with_SAM_4_T10_1683_D_revision_13); + + break; + case 0x008B: + sb.AppendLine(Localization.Device_complies_with_SAM_4_T10_1683_D_revision_14); + + break; + case 0x0090: + sb.AppendLine(Localization.Device_complies_with_SAM_4_ANSI_INCITS_447_2008); + + break; + case 0x0092: + sb.AppendLine(Localization.Device_complies_with_SAM_4_ISO_IEC_14776_414); + + break; + case 0x00A0: + sb.AppendLine(Localization.Device_complies_with_SAM_5_no_version_claimed); + + break; + case 0x00A2: + sb.AppendLine(Localization.Device_complies_with_SAM_5_T10_2104_D_revision_4); + + break; + case 0x00A4: + sb.AppendLine(Localization.Device_complies_with_SAM_5_T10_2104_D_revision_20); + + break; + case 0x00A6: + sb.AppendLine(Localization.Device_complies_with_SAM_5_T10_2104_D_revision_21); + + break; + case 0x00C0: + sb.AppendLine(Localization.Device_complies_with_SAM_6_no_version_claimed); + + break; + case 0x0120: + sb.AppendLine(Localization.Device_complies_with_SPC_no_version_claimed); + + break; + case 0x013B: + sb.AppendLine(Localization.Device_complies_with_SPC_T10_0995_D_revision_11a); + + break; + case 0x013C: + sb.AppendLine(Localization.Device_complies_with_SPC_ANSI_INCITS_301_1997); + + break; + case 0x0140: + sb.AppendLine(Localization.Device_complies_with_MMC_no_version_claimed); + + break; + case 0x015B: + sb.AppendLine(Localization.Device_complies_with_MMC_T10_1048_D_revision_10a); + + break; + case 0x015C: + sb.AppendLine(Localization.Device_complies_with_MMC_ANSI_INCITS_304_1997); + + break; + case 0x0160: + sb.AppendLine(Localization.Device_complies_with_SCC_no_version_claimed); + + break; + case 0x017B: + sb.AppendLine(Localization.Device_complies_with_SCC_T10_1047_D_revision_06c); + + break; + case 0x017C: + sb.AppendLine(Localization.Device_complies_with_SCC_ANSI_INCITS_276_1997); + + break; + case 0x0180: + sb.AppendLine(Localization.Device_complies_with_SBC_no_version_claimed); + + break; + case 0x019B: + sb.AppendLine(Localization.Device_complies_with_SBC_T10_0996_D_revision_08c); + + break; + case 0x019C: + sb.AppendLine(Localization.Device_complies_with_SBC_ANSI_INCITS_306_1998); + + break; + case 0x01A0: + sb.AppendLine(Localization.Device_complies_with_SMC_no_version_claimed); + + break; + case 0x01BB: + sb.AppendLine(Localization.Device_complies_with_SMC_T10_0999_D_revision_10a); + + break; + case 0x01BC: + sb.AppendLine(Localization.Device_complies_with_SMC_ANSI_INCITS_314_1998); + + break; + case 0x01BE: + sb.AppendLine(Localization.Device_complies_with_SMC_ISO_IEC_14776_351); + + break; + case 0x01C0: + sb.AppendLine(Localization.Device_complies_with_SES_no_version_claimed); + + break; + case 0x01DB: + sb.AppendLine(Localization.Device_complies_with_SES_T10_1212_D_revision_08b); + + break; + case 0x01DC: + sb.AppendLine(Localization.Device_complies_with_SES_ANSI_INCITS_305_1998); + + break; + case 0x01DD: + sb.AppendLine(Localization + .Device_complies_with_SES_T10_1212_revision_08b_Amendment_ANSI_INCITS_305_AM1_2000); + + break; + case 0x01DE: + sb.AppendLine(Localization + .Device_complies_with_SES_ANSI_INCITS_305_1998_Amendment_ANSI_INCITS_305_AM1_2000); + + break; + case 0x01E0: + sb.AppendLine(Localization.Device_complies_with_SCC_2_no_version_claimed); + + break; + case 0x01FB: + sb.AppendLine(Localization.Device_complies_with_SCC_2_T10_1125_D_revision_04); + + break; + case 0x01FC: + sb.AppendLine(Localization.Device_complies_with_SCC_2_ANSI_INCITS_318_1998); + + break; + case 0x0200: + sb.AppendLine(Localization.Device_complies_with_SSC_no_version_claimed); + + break; + case 0x0201: + sb.AppendLine(Localization.Device_complies_with_SSC_T10_0997_D_revision_17); + + break; + case 0x0207: + sb.AppendLine(Localization.Device_complies_with_SSC_T10_0997_D_revision_22); + + break; + case 0x021C: + sb.AppendLine(Localization.Device_complies_with_SSC_ANSI_INCITS_335_2000); + + break; + case 0x0220: + sb.AppendLine(Localization.Device_complies_with_RBC_no_version_claimed); + + break; + case 0x0238: + sb.AppendLine(Localization.Device_complies_with_RBC_T10_1240_D_revision_10a); + + break; + case 0x023C: + sb.AppendLine(Localization.Device_complies_with_RBC_ANSI_INCITS_330_2000); + + break; + case 0x0240: + sb.AppendLine(Localization.Device_complies_with_MMC_2_no_version_claimed); + + break; + case 0x0255: + sb.AppendLine(Localization.Device_complies_with_MMC_2_T10_1228_D_revision_11); + + break; + case 0x025B: + sb.AppendLine(Localization.Device_complies_with_MMC_2_T10_1228_D_revision_11a); + + break; + case 0x025C: + sb.AppendLine(Localization.Device_complies_with_MMC_2_ANSI_INCITS_333_2000); + + break; + case 0x0260: + sb.AppendLine(Localization.Device_complies_with_SPC_2_no_version_claimed); + + break; + case 0x0267: + sb.AppendLine(Localization.Device_complies_with_SPC_2_T10_1236_D_revision_12); + + break; + case 0x0269: + sb.AppendLine(Localization.Device_complies_with_SPC_2_T10_1236_D_revision_18); + + break; + case 0x0275: + sb.AppendLine(Localization.Device_complies_with_SPC_2_T10_1236_D_revision_19); + + break; + case 0x0276: + sb.AppendLine(Localization.Device_complies_with_SPC_2_T10_1236_D_revision_20); + + break; + case 0x0277: + sb.AppendLine(Localization.Device_complies_with_SPC_2_ANSI_INCITS_351_2001); + + break; + case 0x0278: + sb.AppendLine(Localization.Device_complies_with_SPC_2_ISO_IEC_14776_452); + + break; + case 0x0280: + sb.AppendLine(Localization.Device_complies_with_OCRW_no_version_claimed); + + break; + case 0x029E: + sb.AppendLine(Localization.Device_complies_with_OCRW_ISO_IEC_14776_381); + + break; + case 0x02A0: + sb.AppendLine(Localization.Device_complies_with_MMC_3_no_version_claimed); + + break; + case 0x02B5: + sb.AppendLine(Localization.Device_complies_with_MMC_3_T10_1363_D_revision_9); + + break; + case 0x02B6: + sb.AppendLine(Localization.Device_complies_with_MMC_3_T10_1363_D_revision_10g); + + break; + case 0x02B8: + sb.AppendLine(Localization.Device_complies_with_MMC_3_ANSI_INCITS_360_2002); + + break; + case 0x02E0: + sb.AppendLine(Localization.Device_complies_with_SMC_2_no_version_claimed); + + break; + case 0x02F5: + sb.AppendLine(Localization.Device_complies_with_SMC_2_T10_1383_D_revision_5); + + break; + case 0x02FC: + sb.AppendLine(Localization.Device_complies_with_SMC_2_T10_1383_D_revision_6); + + break; + case 0x02FD: + sb.AppendLine(Localization.Device_complies_with_SMC_2_T10_1383_D_revision_7); + + break; + case 0x02FE: + sb.AppendLine(Localization.Device_complies_with_SMC_2_ANSI_INCITS_382_2004); + + break; + case 0x0300: + sb.AppendLine(Localization.Device_complies_with_SPC_3_no_version_claimed); + + break; + case 0x0301: + sb.AppendLine(Localization.Device_complies_with_SPC_3_T10_1416_D_revision_7); + + break; + case 0x0307: + sb.AppendLine(Localization.Device_complies_with_SPC_3_T10_1416_D_revision_21); + + break; + case 0x030F: + sb.AppendLine(Localization.Device_complies_with_SPC_3_T10_1416_D_revision_22); + + break; + case 0x0312: + sb.AppendLine(Localization.Device_complies_with_SPC_3_T10_1416_D_revision_23); + + break; + case 0x0314: + sb.AppendLine(Localization.Device_complies_with_SPC_3_ANSI_INCITS_408_2005); + + break; + case 0x0316: + sb.AppendLine(Localization.Device_complies_with_SPC_3_ISO_IEC_14776_453); + + break; + case 0x0320: + sb.AppendLine(Localization.Device_complies_with_SBC_2_no_version_claimed); + + break; + case 0x0322: + sb.AppendLine(Localization.Device_complies_with_SBC_2_T10_1417_D_revision_5a); + + break; + case 0x0324: + sb.AppendLine(Localization.Device_complies_with_SBC_2_T10_1417_D_revision_15); + + break; + case 0x033B: + sb.AppendLine(Localization.Device_complies_with_SBC_2_T10_1417_D_revision_16); + + break; + case 0x033D: + sb.AppendLine(Localization.Device_complies_with_SBC_2_ANSI_INCITS_405_2005); + + break; + case 0x033E: + sb.AppendLine(Localization.Device_complies_with_SBC_2_ISO_IEC_14776_322); + + break; + case 0x0340: + sb.AppendLine(Localization.Device_complies_with_OSD_no_version_claimed); + + break; + case 0x0341: + sb.AppendLine(Localization.Device_complies_with_OSD_T10_1355_D_revision_0); + + break; + case 0x0342: + sb.AppendLine(Localization.Device_complies_with_OSD_T10_1355_D_revision_7a); + + break; + case 0x0343: + sb.AppendLine(Localization.Device_complies_with_OSD_T10_1355_D_revision_8); + + break; + case 0x0344: + sb.AppendLine(Localization.Device_complies_with_OSD_T10_1355_D_revision_9); + + break; + case 0x0355: + sb.AppendLine(Localization.Device_complies_with_OSD_T10_1355_D_revision_10); + + break; + case 0x0356: + sb.AppendLine(Localization.Device_complies_with_OSD_ANSI_INCITS_400_2004); + + break; + case 0x0360: + sb.AppendLine(Localization.Device_complies_with_SSC_2_no_version_claimed); + + break; + case 0x0374: + sb.AppendLine(Localization.Device_complies_with_SSC_2_T10_1434_D_revision_7); + + break; + case 0x0375: + sb.AppendLine(Localization.Device_complies_with_SSC_2_T10_1434_D_revision_9); + + break; + case 0x037D: + sb.AppendLine(Localization.Device_complies_with_SSC_2_ANSI_INCITS_380_2003); + + break; + case 0x0380: + sb.AppendLine(Localization.Device_complies_with_BCC_no_version_claimed); + + break; + case 0x03A0: + sb.AppendLine(Localization.Device_complies_with_MMC_4_no_version_claimed); + + break; + case 0x03B0: + sb.AppendLine(Localization.Device_complies_with_MMC_4_T10_1545_D_revision_5); + + break; + case 0x03B1: + sb.AppendLine(Localization.Device_complies_with_MMC_4_T10_1545_D_revision_5a); + + break; + case 0x03BD: + sb.AppendLine(Localization.Device_complies_with_MMC_4_T10_1545_D_revision_3); + + break; + case 0x03BE: + sb.AppendLine(Localization.Device_complies_with_MMC_4_T10_1545_D_revision_3d); + + break; + case 0x03BF: + sb.AppendLine(Localization.Device_complies_with_MMC_4_ANSI_INCITS_401_2005); + + break; + case 0x03C0: + sb.AppendLine(Localization.Device_complies_with_ADC_no_version_claimed); + + break; + case 0x03D5: + sb.AppendLine(Localization.Device_complies_with_ADC_T10_1558_D_revision_6); + + break; + case 0x03D6: + sb.AppendLine(Localization.Device_complies_with_ADC_T10_1558_D_revision_7); + + break; + case 0x03D7: + sb.AppendLine(Localization.Device_complies_with_ADC_ANSI_INCITS_403_2005); + + break; + case 0x03E0: + sb.AppendLine(Localization.Device_complies_with_SES_2_no_version_claimed); + + break; + case 0x03E1: + sb.AppendLine(Localization.Device_complies_with_SES_2_T10_1559_D_revision_16); + + break; + case 0x03E7: + sb.AppendLine(Localization.Device_complies_with_SES_2_T10_1559_D_revision_19); + + break; + case 0x03EB: + sb.AppendLine(Localization.Device_complies_with_SES_2_T10_1559_D_revision_20); + + break; + case 0x03F0: + sb.AppendLine(Localization.Device_complies_with_SES_2_ANSI_INCITS_448_2008); + + break; + case 0x03F2: + sb.AppendLine(Localization.Device_complies_with_SES_2_ISO_IEC_14776_372); + + break; + case 0x0400: + sb.AppendLine(Localization.Device_complies_with_SSC_3_no_version_claimed); + + break; + case 0x0403: + sb.AppendLine(Localization.Device_complies_with_SSC_3_T10_1611_D_revision_04a); + + break; + case 0x0407: + sb.AppendLine(Localization.Device_complies_with_SSC_3_T10_1611_D_revision_05); + + break; + case 0x0409: + sb.AppendLine(Localization.Device_complies_with_SSC_3_ANSI_INCITS_467_2011); + + break; + case 0x040B: + sb.AppendLine(Localization.Device_complies_with_SSC_3_ISO_IEC_14776_333_2013); + + break; + case 0x0420: + sb.AppendLine(Localization.Device_complies_with_MMC_5_no_version_claimed); + + break; + case 0x042F: + sb.AppendLine(Localization.Device_complies_with_MMC_5_T10_1675_D_revision_03); + + break; + case 0x0431: + sb.AppendLine(Localization.Device_complies_with_MMC_5_T10_1675_D_revision_03b); + + break; + case 0x0432: + sb.AppendLine(Localization.Device_complies_with_MMC_5_T10_1675_D_revision_04); + + break; + case 0x0434: + sb.AppendLine(Localization.Device_complies_with_MMC_5_ANSI_INCITS_430_2007); + + break; + case 0x0440: + sb.AppendLine(Localization.Device_complies_with_OSD_2_no_version_claimed); + + break; + case 0x0444: + sb.AppendLine(Localization.Device_complies_with_OSD_2_T10_1729_D_revision_4); + + break; + case 0x0446: + sb.AppendLine(Localization.Device_complies_with_OSD_2_T10_1729_D_revision_5); + + break; + case 0x0448: + sb.AppendLine(Localization.Device_complies_with_OSD_2_ANSI_INCITS_458_2011); + + break; + case 0x0460: + sb.AppendLine(Localization.Device_complies_with_SPC_4_no_version_claimed); + + break; + case 0x0461: + sb.AppendLine(Localization.Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_16); + + break; + case 0x0462: + sb.AppendLine(Localization.Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_18); + + break; + case 0x0463: + sb.AppendLine(Localization.Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_23); + + break; + case 0x0466: + sb.AppendLine(Localization.Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_36); + + break; + case 0x0468: + sb.AppendLine(Localization.Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_37); + + break; + case 0x0469: + sb.AppendLine(Localization.Device_complies_with_SPC_4_T10_BSR_INCITS_513_revision_37a); + + break; + case 0x046C: + sb.AppendLine(Localization.Device_complies_with_SPC_4_ANSI_INCITS_513_2015); + + break; + case 0x0480: + sb.AppendLine(Localization.Device_complies_with_SMC_3_no_version_claimed); + + break; + case 0x0482: + sb.AppendLine(Localization.Device_complies_with_SMC_3_T10_1730_D_revision_15); + + break; + case 0x0484: + sb.AppendLine(Localization.Device_complies_with_SMC_3_T10_1730_D_revision_16); + + break; + case 0x0486: + sb.AppendLine(Localization.Device_complies_with_SMC_3_ANSI_INCITS_484_2012); + + break; + case 0x04A0: + sb.AppendLine(Localization.Device_complies_with_ADC_2_no_version_claimed); + + break; + case 0x04A7: + sb.AppendLine(Localization.Device_complies_with_ADC_2_T10_1741_D_revision_7); + + break; + case 0x04AA: + sb.AppendLine(Localization.Device_complies_with_ADC_2_T10_1741_D_revision_8); + + break; + case 0x04AC: + sb.AppendLine(Localization.Device_complies_with_ADC_2_ANSI_INCITS_441_2008); + + break; + case 0x04C0: + sb.AppendLine(Localization.Device_complies_with_SBC_3_no_version_claimed); + + break; + case 0x04C3: + sb.AppendLine(Localization.Device_complies_with_SBC_3_T10_BSR_INCITS_514_revision_35); + + break; + case 0x04C5: + sb.AppendLine(Localization.Device_complies_with_SBC_3_T10_BSR_INCITS_514_revision_36); + + break; + case 0x04C8: + sb.AppendLine(Localization.Device_complies_with_SBC_3_ANSI_INCITS_514_2014); + + break; + case 0x04E0: + sb.AppendLine(Localization.Device_complies_with_MMC_6_no_version_claimed); + + break; + case 0x04E3: + sb.AppendLine(Localization.Device_complies_with_MMC_6_T10_1836_D_revision_02b); + + break; + case 0x04E5: + sb.AppendLine(Localization.Device_complies_with_MMC_6_T10_1836_D_revision_02g); + + break; + case 0x04E6: + sb.AppendLine(Localization.Device_complies_with_MMC_6_ANSI_INCITS_468_2010); + + break; + case 0x04E7: + sb.AppendLine(Localization + .Device_complies_with_MMC_6_ANSI_INCITS_468_2010_MMC_6_AM1_ANSI_INCITS_468_2010_AM_1); + + break; + case 0x0500: + sb.AppendLine(Localization.Device_complies_with_ADC_3_no_version_claimed); + + break; + case 0x0502: + sb.AppendLine(Localization.Device_complies_with_ADC_3_T10_1895_D_revision_04); + + break; + case 0x0504: + sb.AppendLine(Localization.Device_complies_with_ADC_3_T10_1895_D_revision_05); + + break; + case 0x0506: + sb.AppendLine(Localization.Device_complies_with_ADC_3_T10_1895_D_revision_05a); + + break; + case 0x050A: + sb.AppendLine(Localization.Device_complies_with_ADC_3_ANSI_INCITS_497_2012); + + break; + case 0x0520: + sb.AppendLine(Localization.Device_complies_with_SSC_4_no_version_claimed); + + break; + case 0x0523: + sb.AppendLine(Localization.Device_complies_with_SSC_4_T10_BSR_INCITS_516_revision_2); + + break; + case 0x0525: + sb.AppendLine(Localization.Device_complies_with_SSC_4_T10_BSR_INCITS_516_revision_3); + + break; + case 0x0527: + sb.AppendLine(Localization.Device_complies_with_SSC_4_ANSI_INCITS_516_2013); + + break; + case 0x0560: + sb.AppendLine(Localization.Device_complies_with_OSD_3_no_version_claimed); + + break; + case 0x0580: + sb.AppendLine(Localization.Device_complies_with_SES_3_no_version_claimed); + + break; + case 0x05A0: + sb.AppendLine(Localization.Device_complies_with_SSC_5_no_version_claimed); + + break; + case 0x05C0: + sb.AppendLine(Localization.Device_complies_with_SPC_5_no_version_claimed); + + break; + case 0x05E0: + sb.AppendLine(Localization.Device_complies_with_SFSC_no_version_claimed); + + break; + case 0x05E3: + sb.AppendLine(Localization.Device_complies_with_SFSC_BSR_INCITS_501_revision_01); + + break; + case 0x0600: + sb.AppendLine(Localization.Device_complies_with_SBC_4_no_version_claimed); + + break; + case 0x0620: + sb.AppendLine(Localization.Device_complies_with_ZBC_no_version_claimed); + + break; + case 0x0622: + sb.AppendLine(Localization.Device_complies_with_ZBC_BSR_INCITS_536_revision_02); + + break; + case 0x0640: + sb.AppendLine(Localization.Device_complies_with_ADC_4_no_version_claimed); + + break; + case 0x0820: + sb.AppendLine(Localization.Device_complies_with_SSA_TL2_no_version_claimed); + + break; + case 0x083B: + sb.AppendLine(Localization.Device_complies_with_SSA_TL2_T10_1_1147_D_revision_05b); + + break; + case 0x083C: + sb.AppendLine(Localization.Device_complies_with_SSA_TL2_ANSI_INCITS_308_1998); + + break; + case 0x0840: + sb.AppendLine(Localization.Device_complies_with_SSA_TL1_no_version_claimed); + + break; + case 0x085B: + sb.AppendLine(Localization.Device_complies_with_SSA_TL1_T10_1_0989_D_revision_10b); + + break; + case 0x085C: + sb.AppendLine(Localization.Device_complies_with_SSA_TL1_ANSI_INCITS_295_1996); + + break; + case 0x0860: + sb.AppendLine(Localization.Device_complies_with_SSA_S3P_no_version_claimed); + + break; + case 0x087B: + sb.AppendLine(Localization.Device_complies_with_SSA_S3P_T10_1_1051_D_revision_05b); + + break; + case 0x087C: + sb.AppendLine(Localization.Device_complies_with_SSA_S3P_ANSI_INCITS_309_1998); + + break; + case 0x0880: + sb.AppendLine(Localization.Device_complies_with_SSA_S2P_no_version_claimed); + + break; + case 0x089B: + sb.AppendLine(Localization.Device_complies_with_SSA_S2P_T10_1_1121_D_revision_07b); + + break; + case 0x089C: + sb.AppendLine(Localization.Device_complies_with_SSA_S2P_ANSI_INCITS_294_1996); + + break; + case 0x08A0: + sb.AppendLine(Localization.Device_complies_with_SIP_no_version_claimed); + + break; + case 0x08BB: + sb.AppendLine(Localization.Device_complies_with_SIP_T10_0856_D_revision_10); + + break; + case 0x08BC: + sb.AppendLine(Localization.Device_complies_with_SIP_ANSI_INCITS_292_1997); + + break; + case 0x08C0: + sb.AppendLine(Localization.Device_complies_with_FCP_no_version_claimed); + + break; + case 0x08DB: + sb.AppendLine(Localization.Device_complies_with_FCP_T10_0993_D_revision_12); + + break; + case 0x08DC: + sb.AppendLine(Localization.Device_complies_with_FCP_ANSI_INCITS_269_1996); + + break; + case 0x08E0: + sb.AppendLine(Localization.Device_complies_with_SBP_2_no_version_claimed); + + break; + case 0x08FB: + sb.AppendLine(Localization.Device_complies_with_SBP_2_T10_1155_D_revision_04); + + break; + case 0x08FC: + sb.AppendLine(Localization.Device_complies_with_SBP_2_ANSI_INCITS_325_1998); + + break; + case 0x0900: + sb.AppendLine(Localization.Device_complies_with_FCP_2_no_version_claimed); + + break; + case 0x0901: + sb.AppendLine(Localization.Device_complies_with_FCP_2_T10_1144_D_revision_4); + + break; + case 0x0915: + sb.AppendLine(Localization.Device_complies_with_FCP_2_T10_1144_D_revision_7); + + break; + case 0x0916: + sb.AppendLine(Localization.Device_complies_with_FCP_2_T10_1144_D_revision_7a); + + break; + case 0x0917: + sb.AppendLine(Localization.Device_complies_with_FCP_2_ANSI_INCITS_350_2003); + + break; + case 0x0918: + sb.AppendLine(Localization.Device_complies_with_FCP_2_T10_1144_D_revision_8); + + break; + case 0x0920: + sb.AppendLine(Localization.Device_complies_with_SST_no_version_claimed); + + break; + case 0x0935: + sb.AppendLine(Localization.Device_complies_with_SST_T10_1380_D_revision_8b); + + break; + case 0x0940: + sb.AppendLine(Localization.Device_complies_with_SRP_no_version_claimed); + + break; + case 0x0954: + sb.AppendLine(Localization.Device_complies_with_SRP_T10_1415_D_revision_10); + + break; + case 0x0955: + sb.AppendLine(Localization.Device_complies_with_SRP_T10_1415_D_revision_16a); + + break; + case 0x095C: + sb.AppendLine(Localization.Device_complies_with_SRP_ANSI_INCITS_365_2002); + + break; + case 0x0960: + sb.AppendLine(Localization.Device_complies_with_iSCSI_no_version_claimed); + + break; + case 0x0961: + case 0x0962: + case 0x0963: + case 0x0964: + case 0x0965: + case 0x0966: + case 0x0967: + case 0x0968: + case 0x0969: + case 0x096A: + case 0x096B: + case 0x096C: + case 0x096D: + case 0x096E: + case 0x096F: + case 0x0970: + case 0x0971: + case 0x0972: + case 0x0973: + case 0x0974: + case 0x0975: + case 0x0976: + case 0x0977: + case 0x0978: + case 0x0979: + case 0x097A: + case 0x097B: + case 0x097C: + case 0x097D: + case 0x097E: + case 0x097F: + sb.AppendFormat(Localization.Device_complies_with_iSCSI_revision_0, VersionDescriptor & 0x1F) + .AppendLine(); + + break; + case 0x0980: + sb.AppendLine(Localization.Device_complies_with_SBP_3_no_version_claimed); + + break; + case 0x0982: + sb.AppendLine(Localization.Device_complies_with_SBP_3_T10_1467_D_revision_1f); + + break; + case 0x0994: + sb.AppendLine(Localization.Device_complies_with_SBP_3_T10_1467_D_revision_3); + + break; + case 0x099A: + sb.AppendLine(Localization.Device_complies_with_SBP_3_T10_1467_D_revision_4); + + break; + case 0x099B: + sb.AppendLine(Localization.Device_complies_with_SBP_3_T10_1467_D_revision_5); + + break; + case 0x099C: + sb.AppendLine(Localization.Device_complies_with_SBP_3_ANSI_INCITS_375_2004); + + break; + case 0x09C0: + sb.AppendLine(Localization.Device_complies_with_ADP_no_version_claimed); + + break; + case 0x09E0: + sb.AppendLine(Localization.Device_complies_with_ADT_no_version_claimed); + + break; + case 0x09F9: + sb.AppendLine(Localization.Device_complies_with_ADT_T10_1557_D_revision_11); + + break; + case 0x09FA: + sb.AppendLine(Localization.Device_complies_with_ADT_T10_1557_D_revision_14); + + break; + case 0x09FD: + sb.AppendLine(Localization.Device_complies_with_ADT_ANSI_INCITS_406_2005); + + break; + case 0x0A00: + sb.AppendLine(Localization.Device_complies_with_FCP_3_no_version_claimed); + + break; + case 0x0A07: + sb.AppendLine(Localization.Device_complies_with_FCP_3_T10_1560_D_revision_3f); + + break; + case 0x0A0F: + sb.AppendLine(Localization.Device_complies_with_FCP_3_T10_1560_D_revision_4); + + break; + case 0x0A11: + sb.AppendLine(Localization.Device_complies_with_FCP_3_ANSI_INCITS_416_2006); + + break; + case 0x0A1C: + sb.AppendLine(Localization.Device_complies_with_FCP_3_ISO_IEC_14776_223); + + break; + case 0x0A20: + sb.AppendLine(Localization.Device_complies_with_ADT_2_no_version_claimed); + + break; + case 0x0A22: + sb.AppendLine(Localization.Device_complies_with_ADT_2_T10_1742_D_revision_06); + + break; + case 0x0A27: + sb.AppendLine(Localization.Device_complies_with_ADT_2_T10_1742_D_revision_08); + + break; + case 0x0A28: + sb.AppendLine(Localization.Device_complies_with_ADT_2_T10_1742_D_revision_09); + + break; + case 0x0A2B: + sb.AppendLine(Localization.Device_complies_with_ADT_2_ANSI_INCITS_472_2011); + + break; + case 0x0A40: + sb.AppendLine(Localization.Device_complies_with_FCP_4_no_version_claimed); + + break; + case 0x0A42: + sb.AppendLine(Localization.Device_complies_with_FCP_4_T10_1828_D_revision_01); + + break; + case 0x0A44: + sb.AppendLine(Localization.Device_complies_with_FCP_4_T10_1828_D_revision_02); + + break; + case 0x0A45: + sb.AppendLine(Localization.Device_complies_with_FCP_4_T10_1828_D_revision_02b); + + break; + case 0x0A46: + sb.AppendLine(Localization.Device_complies_with_FCP_4_ANSI_INCITS_481_2012); + + break; + case 0x0A60: + sb.AppendLine(Localization.Device_complies_with_ADT_3_no_version_claimed); + + break; + case 0x0AA0: + sb.AppendLine(Localization.Device_complies_with_SPI_no_version_claimed); + + break; + case 0x0AB9: + sb.AppendLine(Localization.Device_complies_with_SPI_T10_0855_D_revision_15a); + + break; + case 0x0ABA: + sb.AppendLine(Localization.Device_complies_with_SPI_ANSI_INCITS_253_1995); + + break; + case 0x0ABB: + sb.AppendLine(Localization + .Device_complies_with_SPI_T10_0855_D_revision_15a_with_SPI_Amnd_revision_3a); + + break; + case 0x0ABC: + sb.AppendLine(Localization + .Device_complies_with_SPI_ANSI_INCITS_253_1995_with_SPI_Amnd_ANSI_INCITS_253_AM1_1998); + + break; + case 0x0AC0: + sb.AppendLine(Localization.Device_complies_with_Fast_20_no_version_claimed); + + break; + case 0x0ADB: + sb.AppendLine(Localization.Device_complies_with_Fast_20_T10_1071_revision_06); + + break; + case 0x0ADC: + sb.AppendLine(Localization.Device_complies_with_Fast_20_ANSI_INCITS_277_1996); + + break; + case 0x0AE0: + sb.AppendLine(Localization.Device_complies_with_SPI_2_no_version_claimed); + + break; + case 0x0AFB: + sb.AppendLine(Localization.Device_complies_with_SPI_2_T10_1142_D_revision_20b); + + break; + case 0x0AFC: + sb.AppendLine(Localization.Device_complies_with_SPI_2_ANSI_INCITS_302_1999); + + break; + case 0x0B00: + sb.AppendLine(Localization.Device_complies_with_SPI_3_no_version_claimed); + + break; + case 0x0B18: + sb.AppendLine(Localization.Device_complies_with_SPI_3_T10_1302_D_revision_10); + + break; + case 0x0B19: + sb.AppendLine(Localization.Device_complies_with_SPI_3_T10_1302_D_revision_13a); + + break; + case 0x0B1A: + sb.AppendLine(Localization.Device_complies_with_SPI_3_T10_1302_D_revision_14); + + break; + case 0x0B1C: + sb.AppendLine(Localization.Device_complies_with_SPI_3_ANSI_INCITS_336_2000); + + break; + case 0x0B20: + sb.AppendLine(Localization.Device_complies_with_EPI_no_version_claimed); + + break; + case 0x0B3B: + sb.AppendLine(Localization.Device_complies_with_EPI_T10_1134_revision_16); + + break; + case 0x0B3C: + sb.AppendLine(Localization.Device_complies_with_EPI_ANSI_INCITS_TR_23_1999); + + break; + case 0x0B40: + sb.AppendLine(Localization.Device_complies_with_SPI_4_no_version_claimed); + + break; + case 0x0B54: + sb.AppendLine(Localization.Device_complies_with_SPI_4_T10_1365_D_revision_7); + + break; + case 0x0B55: + sb.AppendLine(Localization.Device_complies_with_SPI_4_T10_1365_D_revision_9); + + break; + case 0x0B56: + sb.AppendLine(Localization.Device_complies_with_SPI_4_ANSI_INCITS_362_2002); + + break; + case 0x0B59: + sb.AppendLine(Localization.Device_complies_with_SPI_4_T10_1365_D_revision_10); + + break; + case 0x0B60: + sb.AppendLine(Localization.Device_complies_with_SPI_5_no_version_claimed); + + break; + case 0x0B79: + sb.AppendLine(Localization.Device_complies_with_SPI_5_T10_1525_D_revision_3); + + break; + case 0x0B7A: + sb.AppendLine(Localization.Device_complies_with_SPI_5_T10_1525_D_revision_5); + + break; + case 0x0B7B: + sb.AppendLine(Localization.Device_complies_with_SPI_5_T10_1525_D_revision_6); + + break; + case 0x0B7C: + sb.AppendLine(Localization.Device_complies_with_SPI_5_ANSI_INCITS_367_2003); + + break; + case 0x0BE0: + sb.AppendLine(Localization.Device_complies_with_SAS_no_version_claimed); + + break; + case 0x0BE1: + sb.AppendLine(Localization.Device_complies_with_SAS_T10_1562_D_revision_01); + + break; + case 0x0BF5: + sb.AppendLine(Localization.Device_complies_with_SAS_T10_1562_D_revision_03); + + break; + case 0x0BFA: + sb.AppendLine(Localization.Device_complies_with_SAS_T10_1562_D_revision_04); + + break; + case 0x0BFB: + sb.AppendLine(Localization.Device_complies_with_SAS_T10_1562_D_revision_04); + + break; + case 0x0BFC: + sb.AppendLine(Localization.Device_complies_with_SAS_T10_1562_D_revision_05); + + break; + case 0x0BFD: + sb.AppendLine(Localization.Device_complies_with_SAS_ANSI_INCITS_376_2003); + + break; + case 0x0C00: + sb.AppendLine(Localization.Device_complies_with_SAS_1_1_no_version_claimed); + + break; + case 0x0C07: + sb.AppendLine(Localization.Device_complies_with_SAS_1_1_T10_1601_D_revision_9); + + break; + case 0x0C0F: + sb.AppendLine(Localization.Device_complies_with_SAS_1_1_T10_1601_D_revision_10); + + break; + case 0x0C11: + sb.AppendLine(Localization.Device_complies_with_SAS_1_1_ANSI_INCITS_417_2006); + + break; + case 0x0C12: + sb.AppendLine(Localization.Device_complies_with_SAS_1_1_ISO_IEC_14776_151); + + break; + case 0x0C20: + sb.AppendLine(Localization.Device_complies_with_SAS_2_no_version_claimed); + + break; + case 0x0C23: + sb.AppendLine(Localization.Device_complies_with_SAS_2_T10_1760_D_revision_14); + + break; + case 0x0C27: + sb.AppendLine(Localization.Device_complies_with_SAS_2_T10_1760_D_revision_15); + + break; + case 0x0C28: + sb.AppendLine(Localization.Device_complies_with_SAS_2_T10_1760_D_revision_16); + + break; + case 0x0C2A: + sb.AppendLine(Localization.Device_complies_with_SAS_2_ANSI_INCITS_457_2010); + + break; + case 0x0C40: + sb.AppendLine(Localization.Device_complies_with_SAS_2_1_no_version_claimed); + + break; + case 0x0C48: + sb.AppendLine(Localization.Device_complies_with_SAS_2_1_T10_2125_D_revision_04); + + break; + case 0x0C4A: + sb.AppendLine(Localization.Device_complies_with_SAS_2_1_T10_2125_D_revision_06); + + break; + case 0x0C4B: + sb.AppendLine(Localization.Device_complies_with_SAS_2_1_T10_2125_D_revision_07); + + break; + case 0x0C4E: + sb.AppendLine(Localization.Device_complies_with_SAS_2_1_ANSI_INCITS_478_2011); + + break; + case 0x0C4F: + sb.AppendLine(Localization + .Device_complies_with_SAS_2_1_ANSI_INCITS_478_2011_w__Amnd_1_ANSI_INCITS_478_AM1_2014); + + break; + case 0x0C52: + sb.AppendLine(Localization.Device_complies_with_SAS_2_1_ISO_IEC_14776_153); + + break; + case 0x0C60: + sb.AppendLine(Localization.Device_complies_with_SAS_3_no_version_claimed); + + break; + case 0x0C63: + sb.AppendLine(Localization.Device_complies_with_SAS_3_T10_BSR_INCITS_519_revision_05a); + + break; + case 0x0C65: + sb.AppendLine(Localization.Device_complies_with_SAS_3_T10_BSR_INCITS_519_revision_06); + + break; + case 0x0C68: + sb.AppendLine(Localization.Device_complies_with_SAS_3_ANSI_INCITS_519_2014); + + break; + case 0x0C80: + sb.AppendLine(Localization.Device_complies_with_SAS_4_no_version_claimed); + + break; + case 0x0D20: + sb.AppendLine(Localization.Device_complies_with_FC_PH_no_version_claimed); + + break; + case 0x0D3B: + sb.AppendLine(Localization.Device_complies_with_FC_PH_ANSI_INCITS_230_1994); + + break; + case 0x0D3C: + sb.AppendLine(Localization + .Device_complies_with_FC_PH_ANSI_INCITS_230_1994_with_Amnd_1_ANSI_INCITS_230_AM1_1996); + + break; + case 0x0D40: + sb.AppendLine(Localization.Device_complies_with_FC_AL_no_version_claimed); + + break; + case 0x0D5C: + sb.AppendLine(Localization.Device_complies_with_FC_AL_ANSI_INCITS_272_1996); + + break; + case 0x0D60: + sb.AppendLine(Localization.Device_complies_with_FC_AL_2_no_version_claimed); + + break; + case 0x0D61: + sb.AppendLine(Localization.Device_complies_with_FC_AL_2_T11_1133_D_revision_7_0); + + break; + case 0x0D63: + sb.AppendLine(Localization + .Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999_with_AM1_2003___AM2_2006); + + break; + case 0x0D64: + sb.AppendLine(Localization + .Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999_with_Amnd_2_AM2_2006); + + break; + case 0x0D65: + sb.AppendLine(Localization.Device_complies_with_FC_AL_2_ISO_IEC_14165_122_with_AM1___AM2); + + break; + case 0x0D7C: + sb.AppendLine(Localization.Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999); + + break; + case 0x0D7D: + sb.AppendLine(Localization + .Device_complies_with_FC_AL_2_ANSI_INCITS_332_1999_with_Amnd_1_AM1_2003); + + break; + case 0x0D80: + sb.AppendLine(Localization.Device_complies_with_FC_PH_3_no_version_claimed); + + break; + case 0x0D9C: + sb.AppendLine(Localization.Device_complies_with_FC_PH_3_ANSI_INCITS_303_1998); + + break; + case 0x0DA0: + sb.AppendLine(Localization.Device_complies_with_FC_FS_no_version_claimed); + + break; + case 0x0DB7: + sb.AppendLine(Localization.Device_complies_with_FC_FS_T11_1331_D_revision_1_2); + + break; + case 0x0DB8: + sb.AppendLine(Localization.Device_complies_with_FC_FS_T11_1331_D_revision_1_7); + + break; + case 0x0DBC: + sb.AppendLine(Localization.Device_complies_with_FC_FS_ANSI_INCITS_373_2003); + + break; + case 0x0DBD: + sb.AppendLine(Localization.Device_complies_with_FC_FS_ISO_IEC_14165_251); + + break; + case 0x0DC0: + sb.AppendLine(Localization.Device_complies_with_FC_PI_no_version_claimed); + + break; + case 0x0DDC: + sb.AppendLine(Localization.Device_complies_with_FC_PI_ANSI_INCITS_352_2002); + + break; + case 0x0DE0: + sb.AppendLine(Localization.Device_complies_with_FC_PI_2_no_version_claimed); + + break; + case 0x0DE2: + sb.AppendLine(Localization.Device_complies_with_FC_PI_2_T11_1506_D_revision_5_0); + + break; + case 0x0DE4: + sb.AppendLine(Localization.Device_complies_with_FC_PI_2_ANSI_INCITS_404_2006); + + break; + case 0x0E00: + sb.AppendLine(Localization.Device_complies_with_FC_FS_2_no_version_claimed); + + break; + case 0x0E02: + sb.AppendLine(Localization.Device_complies_with_FC_FS_2_ANSI_INCITS_242_2007); + + break; + case 0x0E03: + sb.AppendLine(Localization + .Device_complies_with_FC_FS_2_ANSI_INCITS_242_2007_with_AM1_ANSI_INCITS_242_AM1_2007); + + break; + case 0x0E20: + sb.AppendLine(Localization.Device_complies_with_FC_LS_no_version_claimed); + + break; + case 0x0E21: + sb.AppendLine(Localization.Device_complies_with_FC_LS_T11_1620_D_revision_1_62); + + break; + case 0x0E29: + sb.AppendLine(Localization.Device_complies_with_FC_LS_ANSI_INCITS_433_2007); + + break; + case 0x0E40: + sb.AppendLine(Localization.Device_complies_with_FC_SP_no_version_claimed); + + break; + case 0x0E42: + sb.AppendLine(Localization.Device_complies_with_FC_SP_T11_1570_D_revision_1_6); + + break; + case 0x0E45: + sb.AppendLine(Localization.Device_complies_with_FC_SP_ANSI_INCITS_426_2007); + + break; + case 0x0E60: + sb.AppendLine(Localization.Device_complies_with_FC_PI_3_no_version_claimed); + + break; + case 0x0E62: + sb.AppendLine(Localization.Device_complies_with_FC_PI_3_T11_1625_D_revision_2_0); + + break; + case 0x0E68: + sb.AppendLine(Localization.Device_complies_with_FC_PI_3_T11_1625_D_revision_2_1); + + break; + case 0x0E6A: + sb.AppendLine(Localization.Device_complies_with_FC_PI_3_T11_1625_D_revision_4_0); + + break; + case 0x0E6E: + sb.AppendLine(Localization.Device_complies_with_FC_PI_3_ANSI_INCITS_460_2011); + + break; + case 0x0E80: + sb.AppendLine(Localization.Device_complies_with_FC_PI_4_no_version_claimed); + + break; + case 0x0E82: + sb.AppendLine(Localization.Device_complies_with_FC_PI_4_T11_1647_D_revision_8_0); + + break; + case 0x0E88: + sb.AppendLine(Localization.Device_complies_with_FC_PI_4_ANSI_INCITS_450_2009); + + break; + case 0x0EA0: + sb.AppendLine(Localization.Device_complies_with_FC_10GFC_no_version_claimed); + + break; + case 0x0EA2: + sb.AppendLine(Localization.Device_complies_with_FC_10GFC_ANSI_INCITS_364_2003); + + break; + case 0x0EA3: + sb.AppendLine(Localization.Device_complies_with_FC_10GFC_ISO_IEC_14165_116); + + break; + case 0x0EA5: + sb.AppendLine(Localization.Device_complies_with_FC_10GFC_ISO_IEC_14165_116_with_AM1); + + break; + case 0x0EA6: + sb.AppendLine(Localization + .Device_complies_with_FC_10GFC_ANSI_INCITS_364_2003_with_AM1_ANSI_INCITS_364_AM1_2007); + + break; + case 0x0EC0: + sb.AppendLine(Localization.Device_complies_with_FC_SP_2_no_version_claimed); + + break; + case 0x0EE0: + sb.AppendLine(Localization.Device_complies_with_FC_FS_3_no_version_claimed); + + break; + case 0x0EE2: + sb.AppendLine(Localization.Device_complies_with_FC_FS_3_T11_1861_D_revision_0_9); + + break; + case 0x0EE7: + sb.AppendLine(Localization.Device_complies_with_FC_FS_3_T11_1861_D_revision_1_0); + + break; + case 0x0EE9: + sb.AppendLine(Localization.Device_complies_with_FC_FS_3_T11_1861_D_revision_1_10); + + break; + case 0x0EEB: + sb.AppendLine(Localization.Device_complies_with_FC_FS_3_ANSI_INCITS_470_2011); + + break; + case 0x0F00: + sb.AppendLine(Localization.Device_complies_with_FC_LS_2_no_version_claimed); + + break; + case 0x0F03: + sb.AppendLine(Localization.Device_complies_with_FC_LS_2_T11_2103_D_revision_2_11); + + break; + case 0x0F05: + sb.AppendLine(Localization.Device_complies_with_FC_LS_2_T11_2103_D_revision_2_21); + + break; + case 0x0F07: + sb.AppendLine(Localization.Device_complies_with_FC_LS_2_ANSI_INCITS_477_2011); + + break; + case 0x0F20: + sb.AppendLine(Localization.Device_complies_with_FC_PI_5_no_version_claimed); + + break; + case 0x0F27: + sb.AppendLine(Localization.Device_complies_with_FC_PI_5_T11_2118_D_revision_2_00); + + break; + case 0x0F28: + sb.AppendLine(Localization.Device_complies_with_FC_PI_5_T11_2118_D_revision_3_00); + + break; + case 0x0F2A: + sb.AppendLine(Localization.Device_complies_with_FC_PI_5_T11_2118_D_revision_6_00); + + break; + case 0x0F2B: + sb.AppendLine(Localization.Device_complies_with_FC_PI_5_T11_2118_D_revision_6_10); + + break; + case 0x0F2E: + sb.AppendLine(Localization.Device_complies_with_FC_PI_5_ANSI_INCITS_479_2011); + + break; + case 0x0F40: + sb.AppendLine(Localization.Device_complies_with_FC_PI_6_no_version_claimed); + + break; + case 0x0F60: + sb.AppendLine(Localization.Device_complies_with_FC_FS_4_no_version_claimed); + + break; + case 0x0F80: + sb.AppendLine(Localization.Device_complies_with_FC_LS_3_no_version_claimed); + + break; + case 0x12A0: + sb.AppendLine(Localization.Device_complies_with_FC_SCM_no_version_claimed); + + break; + case 0x12A3: + sb.AppendLine(Localization.Device_complies_with_FC_SCM_T11_1824DT_revision_1_0); + + break; + case 0x12A5: + sb.AppendLine(Localization.Device_complies_with_FC_SCM_T11_1824DT_revision_1_1); + + break; + case 0x12A7: + sb.AppendLine(Localization.Device_complies_with_FC_SCM_T11_1824DT_revision_1_4); + + break; + case 0x12AA: + sb.AppendLine(Localization.Device_complies_with_FC_SCM_INCITS_TR_47_2012); + + break; + case 0x12C0: + sb.AppendLine(Localization.Device_complies_with_FC_DA_2_no_version_claimed); + + break; + case 0x12C3: + sb.AppendLine(Localization.Device_complies_with_FC_DA_2_T11_1870DT_revision_1_04); + + break; + case 0x12C5: + sb.AppendLine(Localization.Device_complies_with_FC_DA_2_T11_1870DT_revision_1_06); + + break; + case 0x12C9: + sb.AppendLine(Localization.Device_complies_with_FC_DA_2_INCITS_TR_49_2012); + + break; + case 0x12E0: + sb.AppendLine(Localization.Device_complies_with_FC_DA_no_version_claimed); + + break; + case 0x12E2: + sb.AppendLine(Localization.Device_complies_with_FC_DA_T11_1513_DT_revision_3_1); + + break; + case 0x12E8: + sb.AppendLine(Localization.Device_complies_with_FC_DA_ANSI_INCITS_TR_36_2004); + + break; + case 0x12E9: + sb.AppendLine(Localization.Device_complies_with_FC_DA_ISO_IEC_14165_341); + + break; + case 0x1300: + sb.AppendLine(Localization.Device_complies_with_FC_Tape_no_version_claimed); + + break; + case 0x1301: + sb.AppendLine(Localization.Device_complies_with_FC_Tape_T11_1315_revision_1_16); + + break; + case 0x131B: + sb.AppendLine(Localization.Device_complies_with_FC_Tape_T11_1315_revision_1_17); + + break; + case 0x131C: + sb.AppendLine(Localization.Device_complies_with_FC_Tape_ANSI_INCITS_TR_24_1999); + + break; + case 0x1320: + sb.AppendLine(Localization.Device_complies_with_FC_FLA_no_version_claimed); + + break; + case 0x133B: + sb.AppendLine(Localization.Device_complies_with_FC_FLA_T11_1235_revision_7); + + break; + case 0x133C: + sb.AppendLine(Localization.Device_complies_with_FC_FLA_ANSI_INCITS_TR_20_1998); + + break; + case 0x1340: + sb.AppendLine(Localization.Device_complies_with_FC_PLDA_no_version_claimed); + + break; + case 0x135B: + sb.AppendLine(Localization.Device_complies_with_FC_PLDA_T11_1162_revision_2_1); + + break; + case 0x135C: + sb.AppendLine(Localization.Device_complies_with_FC_PLDA_ANSI_INCITS_TR_19_1998); + + break; + case 0x1360: + sb.AppendLine(Localization.Device_complies_with_SSA_PH2_no_version_claimed); + + break; + case 0x137B: + sb.AppendLine(Localization.Device_complies_with_SSA_PH2_T10_1_1145_D_revision_09c); + + break; + case 0x137C: + sb.AppendLine(Localization.Device_complies_with_SSA_PH2_ANSI_INCITS_293_1996); + + break; + case 0x1380: + sb.AppendLine(Localization.Device_complies_with_SSA_PH3_no_version_claimed); + + break; + case 0x139B: + sb.AppendLine(Localization.Device_complies_with_SSA_PH3_T10_1_1146_D_revision_05b); + + break; + case 0x139C: + sb.AppendLine(Localization.Device_complies_with_SSA_PH3_ANSI_INCITS_307_1998); + + break; + case 0x14A0: + sb.AppendLine(Localization.Device_complies_with_IEEE_1394_no_version_claimed); + + break; + case 0x14BD: + sb.AppendLine(Localization.Device_complies_with_ANSI_IEEE_1394_1995); + + break; + case 0x14C0: + sb.AppendLine(Localization.Device_complies_with_IEEE_1394a_no_version_claimed); + + break; + case 0x14E0: + sb.AppendLine(Localization.Device_complies_with_IEEE_1394b_no_version_claimed); + + break; + case 0x15E0: + sb.AppendLine(Localization.Device_complies_with_ATA_ATAPI_6_no_version_claimed); + + break; + case 0x15FD: + sb.AppendLine(Localization.Device_complies_with_ATA_ATAPI_6_ANSI_INCITS_361_2002); + + break; + case 0x1600: + sb.AppendLine(Localization.Device_complies_with_ATA_ATAPI_7_no_version_claimed); + + break; + case 0x1602: + sb.AppendLine(Localization.Device_complies_with_ATA_ATAPI_7_T13_1532_D_revision_3); + + break; + case 0x161C: + sb.AppendLine(Localization.Device_complies_with_ATA_ATAPI_7_ANSI_INCITS_397_2005); + + break; + case 0x161E: + sb.AppendLine(Localization.Device_complies_with_ATA_ATAPI_7_ISO_IEC_24739); + + break; + case 0x1620: + sb.AppendLine(Localization.Device_complies_with_ATA_ATAPI_8_ATA8_AAM_no_version_claimed); + + break; + case 0x1621: + sb.AppendLine(Localization + .Device_complies_with_ATA_ATAPI_8_ATA8_APT_Parallel_Transport_no_version_claimed); + + break; + case 0x1622: + sb.AppendLine(Localization + .Device_complies_with_ATA_ATAPI_8_ATA8_AST_Serial_Transport_no_version_claimed); + + break; + case 0x1623: + sb.AppendLine(Localization + .Device_complies_with_ATA_ATAPI_8_ATA8_ACS_ATA_ATAPI_Command_Set_no_version_claimed); + + break; + case 0x1628: + sb.AppendLine(Localization.Device_complies_with_ATA_ATAPI_8_ATA8_AAM_ANSI_INCITS_451_2008); + + break; + case 0x162A: + sb.AppendLine(Localization + .Device_complies_with_ATA_ATAPI_8_ATA8_ACS_ANSI_INCITS_452_2009_w__Amendment_1); + + break; + case 0x1728: + sb.AppendLine(Localization + .Device_complies_with_Universal_Serial_Bus_Specification__Revision_1_1); + + break; + case 0x1729: + sb.AppendLine(Localization + .Device_complies_with_Universal_Serial_Bus_Specification__Revision_2_0); + + break; + case 0x1730: + sb.AppendLine(Localization + .Device_complies_with_USB_Mass_Storage_Class_Bulk_Only_Transport__Revision_1_0); + + break; + case 0x1740: + sb.AppendLine(Localization.Device_complies_with_UAS_no_version_claimed); + + break; + case 0x1743: + sb.AppendLine(Localization.Device_complies_with_UAS_T10_2095_D_revision_02); + + break; + case 0x1747: + sb.AppendLine(Localization.Device_complies_with_UAS_T10_2095_D_revision_04); + + break; + case 0x1748: + sb.AppendLine(Localization.Device_complies_with_UAS_ANSI_INCITS_471_2010); + + break; + case 0x1749: + sb.AppendLine(Localization.Device_complies_with_UAS_ISO_IEC_14776_251_2014); + + break; + case 0x1761: + sb.AppendLine(Localization.Device_complies_with_ACS_2_no_version_claimed); + + break; + case 0x1762: + sb.AppendLine(Localization.Device_complies_with_ACS_2_ANSI_INCITS_482_2013); + + break; + case 0x1765: + sb.AppendLine(Localization.Device_complies_with_ACS_3_no_version_claimed); + + break; + case 0x1780: + sb.AppendLine(Localization.Device_complies_with_UAS_2_no_version_claimed); + + break; + case 0x1EA0: + sb.AppendLine(Localization.Device_complies_with_SAT_no_version_claimed); + + break; + case 0x1EA7: + sb.AppendLine(Localization.Device_complies_with_SAT_T10_1711_D_revision_8); + + break; + case 0x1EAB: + sb.AppendLine(Localization.Device_complies_with_SAT_T10_1711_D_revision_9); + + break; + case 0x1EAD: + sb.AppendLine(Localization.Device_complies_with_SAT_ANSI_INCITS_431_2007); + + break; + case 0x1EC0: + sb.AppendLine(Localization.Device_complies_with_SAT_2_no_version_claimed); + + break; + case 0x1EC4: + sb.AppendLine(Localization.Device_complies_with_SAT_2_T10_1826_D_revision_06); + + break; + case 0x1EC8: + sb.AppendLine(Localization.Device_complies_with_SAT_2_T10_1826_D_revision_09); + + break; + case 0x1ECA: + sb.AppendLine(Localization.Device_complies_with_SAT_2_ANSI_INCITS_465_2010); + + break; + case 0x1EE0: + sb.AppendLine(Localization.Device_complies_with_SAT_3_no_version_claimed); + + break; + case 0x1EE2: + sb.AppendLine(Localization.Device_complies_with_SAT_3_T10_BSR_INCITS_517_revision_4); + + break; + case 0x1EE4: + sb.AppendLine(Localization.Device_complies_with_SAT_3_T10_BSR_INCITS_517_revision_7); + + break; + case 0x1EE8: + sb.AppendLine(Localization.Device_complies_with_SAT_3_ANSI_INCITS_517_2015); + + break; + case 0x1F00: + sb.AppendLine(Localization.Device_complies_with_SAT_4_no_version_claimed); + + break; + case 0x20A0: + sb.AppendLine(Localization.Device_complies_with_SPL_no_version_claimed); + + break; + case 0x20A3: + sb.AppendLine(Localization.Device_complies_with_SPL_T10_2124_D_revision_6a); + + break; + case 0x20A5: + sb.AppendLine(Localization.Device_complies_with_SPL_T10_2124_D_revision_7); + + break; + case 0x20A7: + sb.AppendLine(Localization.Device_complies_with_SPL_ANSI_INCITS_476_2011); + + break; + case 0x20A8: + sb.AppendLine(Localization + .Device_complies_with_SPL_ANSI_INCITS_476_2011_SPL_AM1_INCITS_476_AM1_2012); + + break; + case 0x20AA: + sb.AppendLine(Localization.Device_complies_with_SPL_ISO_IEC_14776_261_2012); + + break; + case 0x20C0: + sb.AppendLine(Localization.Device_complies_with_SPL_2_no_version_claimed); + + break; + case 0x20C2: + sb.AppendLine(Localization.Device_complies_with_SPL_2_T10_BSR_INCITS_505_revision_4); + + break; + case 0x20C4: + sb.AppendLine(Localization.Device_complies_with_SPL_2_T10_BSR_INCITS_505_revision_5); + + break; + case 0x20C8: + sb.AppendLine(Localization.Device_complies_with_SPL_2_ANSI_INCITS_505_2013); + + break; + case 0x20E0: + sb.AppendLine(Localization.Device_complies_with_SPL_3_no_version_claimed); + + break; + case 0x20E4: + sb.AppendLine(Localization.Device_complies_with_SPL_3_T10_BSR_INCITS_492_revision_6); + + break; + case 0x20E6: + sb.AppendLine(Localization.Device_complies_with_SPL_3_T10_BSR_INCITS_492_revision_7); + + break; + case 0x20E8: + sb.AppendLine(Localization.Device_complies_with_SPL_3_ANSI_INCITS_492_2015); + + break; + case 0x2100: + sb.AppendLine(Localization.Device_complies_with_SPL_4_no_version_claimed); + + break; + case 0x21E0: + sb.AppendLine(Localization.Device_complies_with_SOP_no_version_claimed); + + break; + case 0x21E4: + sb.AppendLine(Localization.Device_complies_with_SOP_T10_BSR_INCITS_489_revision_4); + + break; + case 0x21E6: + sb.AppendLine(Localization.Device_complies_with_SOP_T10_BSR_INCITS_489_revision_5); + + break; + case 0x21E8: + sb.AppendLine(Localization.Device_complies_with_SOP_ANSI_INCITS_489_2014); + + break; + case 0x2200: + sb.AppendLine(Localization.Device_complies_with_PQI_no_version_claimed); + + break; + case 0x2204: + sb.AppendLine(Localization.Device_complies_with_PQI_T10_BSR_INCITS_490_revision_6); + + break; + case 0x2206: + sb.AppendLine(Localization.Device_complies_with_PQI_T10_BSR_INCITS_490_revision_7); + + break; + case 0x2208: + sb.AppendLine(Localization.Device_complies_with_PQI_ANSI_INCITS_490_2014); + + break; + case 0x2220: + sb.AppendLine(Localization.Device_complies_with_SOP_2_no_version_claimed); + + break; + case 0x2240: + sb.AppendLine(Localization.Device_complies_with_PQI_2_no_version_claimed); + + break; + case 0xFFC0: + sb.AppendLine(Localization.Device_complies_with_IEEE_1667_no_version_claimed); + + break; + case 0xFFC1: + sb.AppendLine(Localization.Device_complies_with_IEEE_1667_2006); + + break; + case 0xFFC2: + sb.AppendLine(Localization.Device_complies_with_IEEE_1667_2009); + + break; + default: + sb.AppendFormat(Localization.Device_complies_with_unknown_standard_code_0, VersionDescriptor) + .AppendLine(); + + break; + } + } + } + +#region Quantum vendor prettifying + + if(response.QuantumPresent && + StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "quantum") + { + sb.AppendLine(Localization.Quantum_vendor_specific_information); + + switch(response.Qt_ProductFamily) + { + case 0: + sb.AppendLine(Localization.Product_family_is_not_specified); + + break; + case 1: + sb.AppendLine(Localization.Product_family_is_2_6_GB); + + break; + case 2: + sb.AppendLine(Localization.Product_family_is_6_0_GB); + + break; + case 3: + sb.AppendLine(Localization.Product_family_is_10_0_20_0_GB); + + break; + case 5: + sb.AppendLine(Localization.Product_family_is_20_0_40_0_GB); + + break; + case 6: + sb.AppendLine(Localization.Product_family_is_15_0_30_0_GB); + + break; + default: + sb.AppendFormat(Localization.Product_family_0, response.Qt_ProductFamily).AppendLine(); + + break; + } + + sb.AppendFormat(Localization.Release_firmware_0, response.Qt_ReleasedFirmware).AppendLine(); + + sb.AppendFormat(Localization.Firmware_version_0_1, + response.Qt_FirmwareMajorVersion, + response.Qt_FirmwareMinorVersion) + .AppendLine(); + + sb.AppendFormat(Localization.EEPROM_format_version_0_1, + response.Qt_EEPROMFormatMajorVersion, + response.Qt_EEPROMFormatMinorVersion) + .AppendLine(); + + sb.AppendFormat(Localization.Firmware_personality_0, response.Qt_FirmwarePersonality).AppendLine(); + sb.AppendFormat(Localization.Firmware_sub_personality_0, response.Qt_FirmwareSubPersonality).AppendLine(); + + sb.AppendFormat(Localization.Tape_directory_format_version_0, response.Qt_TapeDirectoryFormatVersion) + .AppendLine(); + + sb.AppendFormat(Localization.Controller_hardware_version_0, response.Qt_ControllerHardwareVersion) + .AppendLine(); + + sb.AppendFormat(Localization.Drive_EEPROM_version_0, response.Qt_DriveEEPROMVersion).AppendLine(); + sb.AppendFormat(Localization.Drive_hardware_version_0, response.Qt_DriveHardwareVersion).AppendLine(); + + sb.AppendFormat(Localization.Media_loader_firmware_version_0, response.Qt_MediaLoaderFirmwareVersion) + .AppendLine(); + + sb.AppendFormat(Localization.Media_loader_hardware_version_0, response.Qt_MediaLoaderHardwareVersion) + .AppendLine(); + + sb.AppendFormat(Localization.Media_loader_mechanical_version_0, response.Qt_MediaLoaderMechanicalVersion) + .AppendLine(); + + if(response.Qt_LibraryPresent) sb.AppendLine(Localization.Library_is_present); + + if(response.Qt_MediaLoaderPresent) sb.AppendLine(Localization.Media_loader_is_present); + + sb.AppendFormat(Localization.Module_revision_0, StringHandlers.CToString(response.Qt_ModuleRevision)) + .AppendLine(); + } + +#endregion Quantum vendor prettifying + +#region IBM vendor prettifying + + if(response.IBMPresent && + StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "ibm") + { + sb.AppendLine(Localization.IBM_vendor_specific_information); + + if(response.IBM_PerformanceLimit == 0) + sb.AppendLine(Localization.Performance_is_not_limited); + else + sb.AppendFormat(Localization.Performance_is_limited_using_factor_0, response.IBM_PerformanceLimit); + + if(response.IBM_AutDis) sb.AppendLine(Localization.Automation_is_disabled); + + sb.AppendFormat(Localization.IBM_OEM_Specific_Field_0, response.IBM_OEMSpecific).AppendLine(); + } + +#endregion IBM vendor prettifying + +#region HP vendor prettifying + + if(response.HPPresent && + StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "hp") + { + sb.AppendLine(Localization.HP_vendor_specific_information); + + if(response.HP_WORM) + sb.AppendFormat(Localization.Device_supports_WORM_version_0, response.HP_WORMVersion).AppendLine(); + + byte[] OBDRSign = "$DR-10"u8.ToArray(); + + if(OBDRSign.SequenceEqual(response.HP_OBDR)) + sb.AppendLine(Localization.Device_supports_Tape_Disaster_Recovery); + } + +#endregion HP vendor prettifying + +#region Seagate vendor prettifying + + if((response.SeagatePresent || response.Seagate2Present || response.Seagate3Present) && + StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "seagate") + { + sb.AppendLine(Localization.Seagate_vendor_specific_information); + + if(response.SeagatePresent) + { + sb.AppendFormat(Core.Drive_serial_number_0, + StringHandlers.CToString(response.Seagate_DriveSerialNumber)) + .AppendLine(); + } + + if(response.Seagate2Present) + { + sb.AppendFormat(Localization.Drive_copyright_0, StringHandlers.CToString(response.Seagate_Copyright)) + .AppendLine(); + } + + if(response.Seagate3Present) + { + sb.AppendFormat(Localization.Drive_servo_part_number_0, + PrintHex.ByteArrayToHexArrayString(response.Seagate_ServoPROMPartNo, 40)) + .AppendLine(); + } + } + +#endregion Seagate vendor prettifying + +#region Kreon vendor prettifying + + if(response.KreonPresent) + { + sb.AppendFormat(Localization.Drive_is_flashed_with_Kreon_firmware_0, + StringHandlers.CToString(response.KreonVersion)) + .AppendLine(); + } + +#endregion Kreon vendor prettifying + +#if DEBUG + if(response.DeviceTypeModifier != 0) + sb.AppendFormat(Localization.Vendor_device_type_modifier_0, response.DeviceTypeModifier).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved_byte_five_bits_two_to_one_0, response.Reserved2).AppendLine(); + + if(response.Reserved3 != 0) + sb.AppendFormat(Localization.Reserved_byte_56_bits_seven_to_four_0, response.Reserved3).AppendLine(); + + if(response.Reserved4 != 0) sb.AppendFormat(Localization.Reserved_byte_57, response.Reserved4).AppendLine(); + + if(response.Reserved5 != null) + { + sb.AppendLine(Localization.Reserved_bytes_74_to_95); + sb.AppendLine("============================================================"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.Reserved5, 60)); + sb.AppendLine("============================================================"); + } + + if(response is { VendorSpecific: not null, IsHiMD: true }) + { + if(response.KreonPresent) + { + var vendor = new byte[7]; + Array.Copy(response.VendorSpecific, 11, vendor, 0, 7); + sb.AppendLine(Localization.Vendor_specific_bytes_47_to_55); + sb.AppendLine("============================================================"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(vendor, 60)); + sb.AppendLine("============================================================"); + } + else + { + sb.AppendLine(Localization.Vendor_specific_bytes_36_to_55); + sb.AppendLine("============================================================"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.VendorSpecific, 60)); + sb.AppendLine("============================================================"); + } + } + + if(response.IsHiMD) + { + sb.AppendLine(Localization.Hi_MD_device_); + + if(response.HiMDSpecific != null) + { + sb.AppendLine(Localization.Hi_MD_specific_bytes_44_to_55); + sb.AppendLine("============================================================"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.HiMDSpecific, 60)); + sb.AppendLine("============================================================"); + } + } + + if(response.VendorSpecific2 == null) return sb.ToString(); + + sb.AppendFormat(Localization.Vendor_specific_bytes_96_to_0, response.AdditionalLength + 4).AppendLine(); + sb.AppendLine("============================================================"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.VendorSpecific2, 60)); + sb.AppendLine("============================================================"); +#endif + + return sb.ToString(); + } + + public static string Prettify(byte[] SCSIInquiryResponse) + { + CommonTypes.Structs.Devices.SCSI.Inquiry? decoded = + CommonTypes.Structs.Devices.SCSI.Inquiry.Decode(SCSIInquiryResponse); + + return Prettify(decoded); + } +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/MMC/AACS.cs b/Aaru.Decoders/SCSI/MMC/AACS.cs new file mode 100644 index 000000000..b44c2d4e4 --- /dev/null +++ b/Aaru.Decoders/SCSI/MMC/AACS.cs @@ -0,0 +1,458 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : AACS.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes AACS structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.SCSI.MMC; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class AACS +{ + public static AACSVolumeIdentifier? DecodeAACSVolumeIdentifier(byte[] AACSVIResponse) + { + if(AACSVIResponse == null) return null; + + var decoded = new AACSVolumeIdentifier + { + VolumeIdentifier = new byte[AACSVIResponse.Length - 4], + DataLength = BigEndianBitConverter.ToUInt16(AACSVIResponse, 0), + Reserved1 = AACSVIResponse[2], + Reserved2 = AACSVIResponse[3] + }; + + Array.Copy(AACSVIResponse, 4, decoded.VolumeIdentifier, 0, AACSVIResponse.Length - 4); + + return decoded; + } + + public static string PrettifyAACSVolumeIdentifier(AACSVolumeIdentifier? AACSVIResponse) + { + if(AACSVIResponse == null) return null; + + AACSVolumeIdentifier response = AACSVIResponse.Value; + + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); +#endif + sb.AppendFormat(Localization.AACS_Volume_Identifier_in_hex_follows); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.VolumeIdentifier, 80)); + + return sb.ToString(); + } + + public static string PrettifyAACSVolumeIdentifier(byte[] AACSVIResponse) + { + AACSVolumeIdentifier? decoded = DecodeAACSVolumeIdentifier(AACSVIResponse); + + return PrettifyAACSVolumeIdentifier(decoded); + } + + public static AACSMediaSerialNumber? DecodeAACSMediaSerialNumber(byte[] AACSMSNResponse) + { + if(AACSMSNResponse == null) return null; + + var decoded = new AACSMediaSerialNumber + { + MediaSerialNumber = new byte[AACSMSNResponse.Length - 4], + DataLength = BigEndianBitConverter.ToUInt16(AACSMSNResponse, 0), + Reserved1 = AACSMSNResponse[2], + Reserved2 = AACSMSNResponse[3] + }; + + Array.Copy(AACSMSNResponse, 4, decoded.MediaSerialNumber, 0, AACSMSNResponse.Length - 4); + + return decoded; + } + + public static string PrettifyAACSMediaSerialNumber(AACSMediaSerialNumber? AACSMSNResponse) + { + if(AACSMSNResponse == null) return null; + + AACSMediaSerialNumber response = AACSMSNResponse.Value; + + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); +#endif + sb.AppendFormat(Localization.AACS_Media_Serial_Number_in_hex_follows); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaSerialNumber, 80)); + + return sb.ToString(); + } + + public static string PrettifyAACSMediaSerialNumber(byte[] AACSMSNResponse) + { + AACSMediaSerialNumber? decoded = DecodeAACSMediaSerialNumber(AACSMSNResponse); + + return PrettifyAACSMediaSerialNumber(decoded); + } + + public static AACSMediaIdentifier? DecodeAACSMediaIdentifier(byte[] AACSMIResponse) + { + if(AACSMIResponse == null) return null; + + var decoded = new AACSMediaIdentifier + { + MediaIdentifier = new byte[AACSMIResponse.Length - 4], + DataLength = BigEndianBitConverter.ToUInt16(AACSMIResponse, 0), + Reserved1 = AACSMIResponse[2], + Reserved2 = AACSMIResponse[3] + }; + + Array.Copy(AACSMIResponse, 4, decoded.MediaIdentifier, 0, AACSMIResponse.Length - 4); + + return decoded; + } + + public static string PrettifyAACSMediaIdentifier(AACSMediaIdentifier? AACSMIResponse) + { + if(AACSMIResponse == null) return null; + + AACSMediaIdentifier response = AACSMIResponse.Value; + + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); +#endif + sb.AppendFormat(Localization.AACS_Media_Identifier_in_hex_follows); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaIdentifier, 80)); + + return sb.ToString(); + } + + public static string PrettifyAACSMediaIdentifier(byte[] AACSMIResponse) + { + AACSMediaIdentifier? decoded = DecodeAACSMediaIdentifier(AACSMIResponse); + + return PrettifyAACSMediaIdentifier(decoded); + } + + public static AACSMediaKeyBlock? DecodeAACSMediaKeyBlock(byte[] AACSMKBResponse) + { + if(AACSMKBResponse == null) return null; + + var decoded = new AACSMediaKeyBlock + { + MediaKeyBlockPacks = new byte[AACSMKBResponse.Length - 4], + DataLength = BigEndianBitConverter.ToUInt16(AACSMKBResponse, 0), + Reserved = AACSMKBResponse[2], + TotalPacks = AACSMKBResponse[3] + }; + + Array.Copy(AACSMKBResponse, 4, decoded.MediaKeyBlockPacks, 0, AACSMKBResponse.Length - 4); + + return decoded; + } + + public static string PrettifyAACSMediaKeyBlock(AACSMediaKeyBlock? AACSMKBResponse) + { + if(AACSMKBResponse == null) return null; + + AACSMediaKeyBlock response = AACSMKBResponse.Value; + + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved != 0) sb.AppendFormat(Localization.Reserved_equals_0_X2, response.Reserved).AppendLine(); +#endif + sb.AppendFormat(Localization.Total_number_of_media_key_blocks_available_to_transfer_0, response.TotalPacks) + .AppendLine(); + + sb.AppendFormat(Localization.AACS_Media_Key_Blocks_in_hex_follows); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaKeyBlockPacks, 80)); + + return sb.ToString(); + } + + public static string PrettifyAACSMediaKeyBlock(byte[] AACSMKBResponse) + { + AACSMediaKeyBlock? decoded = DecodeAACSMediaKeyBlock(AACSMKBResponse); + + return PrettifyAACSMediaKeyBlock(decoded); + } + + public static AACSDataKeys? DecodeAACSDataKeys(byte[] AACSDKResponse) + { + if(AACSDKResponse == null) return null; + + var decoded = new AACSDataKeys + { + DataKeys = new byte[AACSDKResponse.Length - 4], + DataLength = BigEndianBitConverter.ToUInt16(AACSDKResponse, 0), + Reserved1 = AACSDKResponse[2], + Reserved2 = AACSDKResponse[3] + }; + + Array.Copy(AACSDKResponse, 4, decoded.DataKeys, 0, AACSDKResponse.Length - 4); + + return decoded; + } + + public static string PrettifyAACSDataKeys(AACSDataKeys? AACSDKResponse) + { + if(AACSDKResponse == null) return null; + + AACSDataKeys response = AACSDKResponse.Value; + + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); +#endif + sb.AppendFormat(Localization.AACS_Data_Keys_in_hex_follows); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.DataKeys, 80)); + + return sb.ToString(); + } + + public static string PrettifyAACSDataKeys(byte[] AACSDKResponse) + { + AACSDataKeys? decoded = DecodeAACSDataKeys(AACSDKResponse); + + return PrettifyAACSDataKeys(decoded); + } + + public static AACSLBAExtentsResponse? DecodeAACSLBAExtents(byte[] AACSLBAExtsResponse) + { + if(AACSLBAExtsResponse == null) return null; + + var decoded = new AACSLBAExtentsResponse + { + DataLength = BigEndianBitConverter.ToUInt16(AACSLBAExtsResponse, 0), + Reserved = AACSLBAExtsResponse[2], + MaxLBAExtents = AACSLBAExtsResponse[3] + }; + + if((AACSLBAExtsResponse.Length - 4) % 16 != 0) return decoded; + + decoded.Extents = new AACSLBAExtent[(AACSLBAExtsResponse.Length - 4) / 16]; + + for(var i = 0; i < (AACSLBAExtsResponse.Length - 4) / 16; i++) + { + decoded.Extents[i].Reserved = new byte[8]; + Array.Copy(AACSLBAExtsResponse, 0 + i * 16 + 4, decoded.Extents[i].Reserved, 0, 8); + decoded.Extents[i].StartLBA = BigEndianBitConverter.ToUInt32(AACSLBAExtsResponse, 8 + i * 16 + 4); + decoded.Extents[i].LBACount = BigEndianBitConverter.ToUInt32(AACSLBAExtsResponse, 12 + i * 16 + 4); + } + + return decoded; + } + + public static string PrettifyAACSLBAExtents(AACSLBAExtentsResponse? AACSLBAExtsResponse) + { + if(AACSLBAExtsResponse == null) return null; + + AACSLBAExtentsResponse response = AACSLBAExtsResponse.Value; + + var sb = new StringBuilder(); + + if(response.MaxLBAExtents == 0) + { + sb.AppendLine(response.DataLength > 2 + ? Localization.Drive_can_store_256_LBA_Extents + : Localization.Drive_cannot_store_LBA_Extents); + } + else + sb.AppendFormat(Localization.Drive_can_store_0_LBA_Extents, response.MaxLBAExtents).AppendLine(); + + for(var i = 0; i < response.Extents.Length; i++) + { + sb.AppendFormat(Localization.LBA_Extent_0_starts_at_LBA_1_and_goes_for_2_sectors, + i, + response.Extents[i].StartLBA, + response.Extents[i].LBACount); + } + + return sb.ToString(); + } + + public static string PrettifyAACSLBAExtents(byte[] AACSLBAExtsResponse) + { + AACSLBAExtentsResponse? decoded = DecodeAACSLBAExtents(AACSLBAExtsResponse); + + return PrettifyAACSLBAExtents(decoded); + } + +#region Nested type: AACSDataKeys + + public struct AACSDataKeys + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end AACS data keys + public byte[] DataKeys; + } + +#endregion + +#region Nested type: AACSLBAExtent + + public struct AACSLBAExtent + { + /// Bytes 0 to 7 Reserved + public byte[] Reserved; + /// Bytes 8 to 11 Start LBA of extent + public uint StartLBA; + /// Bytes 12 to 15 Extent length + public uint LBACount; + } + +#endregion + +#region Nested type: AACSLBAExtentsResponse + + public struct AACSLBAExtentsResponse + { + /// Bytes 0 to 1 Data Length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved; + /// + /// Byte 3 Number of LBA extents the drive can store. if(MaxLBAExtents == 0 && DataLength > 2), 256 + /// extents can be stored + /// + public byte MaxLBAExtents; + /// Bytes 4 to end LBA Extents + public AACSLBAExtent[] Extents; + } + +#endregion + +#region Nested type: AACSMediaIdentifier + + public struct AACSMediaIdentifier + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end AACS media identifier data + public byte[] MediaIdentifier; + } + +#endregion + +#region Nested type: AACSMediaKeyBlock + + public struct AACSMediaKeyBlock + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved; + /// Byte 3 Number of MKB packs available to transfer + public byte TotalPacks; + /// Bytes 4 to end AACS media key block packs + public byte[] MediaKeyBlockPacks; + } + +#endregion + +#region Nested type: AACSMediaSerialNumber + + public struct AACSMediaSerialNumber + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end AACS media serial number + public byte[] MediaSerialNumber; + } + +#endregion + +#region Nested type: AACSVolumeIdentifier + + public struct AACSVolumeIdentifier + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end AACS volume identifier data + public byte[] VolumeIdentifier; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/MMC/CPRM.cs b/Aaru.Decoders/SCSI/MMC/CPRM.cs new file mode 100644 index 000000000..7765c4d73 --- /dev/null +++ b/Aaru.Decoders/SCSI/MMC/CPRM.cs @@ -0,0 +1,120 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CPRM.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes CPRM structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.SCSI.MMC; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class CPRM +{ + public static CPRMMediaKeyBlock? DecodeCPRMMediaKeyBlock(byte[] CPRMMKBResponse) + { + if(CPRMMKBResponse == null) return null; + + var decoded = new CPRMMediaKeyBlock + { + MKBPackData = new byte[CPRMMKBResponse.Length - 4], + DataLength = BigEndianBitConverter.ToUInt16(CPRMMKBResponse, 0), + Reserved = CPRMMKBResponse[2], + TotalPacks = CPRMMKBResponse[3] + }; + + Array.Copy(CPRMMKBResponse, 4, decoded.MKBPackData, 0, CPRMMKBResponse.Length - 4); + + return decoded; + } + + public static string PrettifyCPRMMediaKeyBlock(CPRMMediaKeyBlock? CPRMMKBResponse) + { + if(CPRMMKBResponse == null) return null; + + CPRMMediaKeyBlock response = CPRMMKBResponse.Value; + + var sb = new StringBuilder(); + +#if DEBUG + if(response.Reserved != 0) sb.AppendFormat(Localization.Reserved_equals_0_X2, response.Reserved).AppendLine(); +#endif + sb.AppendFormat(Localization.Total_number_of_CPRM_Media_Key_Blocks_available_to_transfer_0, response.TotalPacks) + .AppendLine(); + + sb.AppendFormat(Localization.CPRM_Media_Key_Blocks_in_hex_follows); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MKBPackData, 80)); + + return sb.ToString(); + } + + public static string PrettifyCPRMMediaKeyBlock(byte[] CPRMMKBResponse) + { + CPRMMediaKeyBlock? decoded = DecodeCPRMMediaKeyBlock(CPRMMKBResponse); + + return PrettifyCPRMMediaKeyBlock(decoded); + } + +#region Nested type: CPRMMediaKeyBlock + + public struct CPRMMediaKeyBlock + { + /// Bytes 0 to 1 Data Length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved; + /// Byte 3 Number of MKB packs available to transfer + public byte TotalPacks; + /// Byte 4 MKB Packs + public byte[] MKBPackData; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/MMC/DiscInformation.cs b/Aaru.Decoders/SCSI/MMC/DiscInformation.cs new file mode 100644 index 000000000..f105499d2 --- /dev/null +++ b/Aaru.Decoders/SCSI/MMC/DiscInformation.cs @@ -0,0 +1,479 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DiscInformation.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes MMC GET DISC INFORMATION structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI.MMC; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DiscInformation +{ + public static StandardDiscInformation? Decode000b(byte[] response) + { + if(response.Length < 32) return null; + + if((response[2] & 0xE0) != 0) return null; + + var decoded = new StandardDiscInformation + { + DataLength = (ushort)((response[0] << 8) + response[1]) + }; + + if(decoded.DataLength + 2 != response.Length) return null; + + decoded.DataType = (byte)((response[2] & 0xE0) >> 5); + decoded.Erasable |= (response[2] & 0x10) == 0x10; + decoded.LastSessionStatus = (byte)((response[2] & 0x0C) >> 2); + decoded.DiscStatus = (byte)(response[2] & 0x03); + decoded.FirstTrackNumber = response[3]; + decoded.Sessions = (ushort)((response[9] << 8) + response[4]); + decoded.FirstTrackLastSession = (ushort)((response[10] << 8) + response[5]); + decoded.LastTrackLastSession = (ushort)((response[11] << 8) + response[6]); + + decoded.DID_V |= (response[7] & 0x80) == 0x80; + decoded.DBC_V |= (response[7] & 0x40) == 0x40; + decoded.URU |= (response[7] & 0x20) == 0x20; + decoded.DAC_V |= (response[7] & 0x10) == 0x10; + decoded.Reserved |= (response[7] & 0x08) == 0x08; + decoded.Dbit |= (response[7] & 0x04) == 0x04; + decoded.BGFormatStatus = (byte)(response[7] & 0x03); + + decoded.DiscIdentification = + (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]); + + decoded.LastSessionLeadInStartLBA = + (uint)((response[16] << 24) + (response[17] << 16) + (response[18] << 8) + response[19]); + + decoded.LastPossibleLeadOutStartLBA = + (uint)((response[20] << 24) + (response[21] << 16) + (response[22] << 8) + response[23]); + + var temp = new byte[8]; + Array.Copy(response, 24, temp, 0, 8); + Array.Reverse(temp); + decoded.DiscBarcode = BitConverter.ToUInt64(temp, 0); + + if(response.Length < 34) return null; + + decoded.DiscApplicationCode = response[32]; + decoded.OPCTablesNumber = response[33]; + + if(decoded.OPCTablesNumber <= 0 || response.Length != decoded.OPCTablesNumber * 8 + 34) return decoded; + + decoded.OPCTables = new OPCTable[decoded.OPCTablesNumber]; + + for(var i = 0; i < decoded.OPCTablesNumber; i++) + { + decoded.OPCTables[i].Speed = (ushort)((response[34 + i * 8 + 0] << 16) + response[34 + i * 8 + 1]); + + decoded.OPCTables[i].OPCValues = new byte[6]; + Array.Copy(response, 34 + i * 8 + 2, decoded.OPCTables[i].OPCValues, 0, 6); + } + + return decoded; + } + + public static string Prettify000b(StandardDiscInformation? information) + { + if(information?.DataType != 0) return null; + + var sb = new StringBuilder(); + + switch(information.Value.DiscType) + { + case 0x00: + sb.AppendLine(Localization.Disc_type_declared_as_CD_DA_or_CD_ROM); + + break; + case 0x10: + sb.AppendLine(Localization.Disc_type_declared_as_CD_i); + + break; + case 0x20: + sb.AppendLine(Localization.Disc_type_declared_as_CD_ROM_XA); + + break; + case 0xFF: + sb.AppendLine(Localization.Disc_type_is_undefined); + + break; + default: + sb.AppendFormat(Localization.Unknown_disc_type_0, information.Value.DiscType).AppendLine(); + + break; + } + + switch(information.Value.DiscStatus) + { + case 0: + sb.AppendLine(Localization.Disc_is_empty); + + break; + case 1: + sb.AppendLine(Localization.Disc_is_incomplete); + + break; + case 2: + sb.AppendLine(Localization.Disc_is_finalized); + + break; + } + + if(information.Value.Erasable) sb.AppendLine(Localization.Disc_is_erasable); + + switch(information.Value.LastSessionStatus) + { + case 0: + sb.AppendLine(Localization.Last_session_is_empty); + + break; + case 1: + sb.AppendLine(Localization.Last_session_is_incomplete); + + break; + case 2: + sb.AppendLine(Localization.Last_session_is_damaged); + + break; + case 3: + sb.AppendLine(Localization.Last_session_is_complete); + + break; + } + + switch(information.Value.BGFormatStatus) + { + case 1: + sb.AppendLine(Localization + .Media_was_being_formatted_in_the_background_but_it_is_stopped_and_incomplete); + + break; + case 2: + sb.AppendLine(Localization.Media_is_currently_being_formatted_in_the_background); + + break; + case 3: + sb.AppendLine(Localization.Media_background_formatting_has_completed); + + break; + } + + if(information.Value.Dbit) sb.AppendLine(Localization.MRW_is_dirty); + + sb.AppendFormat(Localization.First_track_on_disc_is_track_0, information.Value.FirstTrackNumber).AppendLine(); + sb.AppendFormat(Localization.Disc_has_0_sessions, information.Value.Sessions).AppendLine(); + + sb.AppendFormat(Localization.First_track_in_last_session_is_track_0, information.Value.FirstTrackLastSession) + .AppendLine(); + + sb.AppendFormat(Localization.Last_track_in_last_session_is_track_0, information.Value.LastTrackLastSession) + .AppendLine(); + + sb.AppendFormat(Localization.Last_session_Lead_In_address_is_0_as_LBA_or_1_2_3, + information.Value.LastSessionLeadInStartLBA, + (information.Value.LastSessionLeadInStartLBA & 0xFF0000) >> 16, + (information.Value.LastSessionLeadInStartLBA & 0xFF00) >> 8, + information.Value.LastSessionLeadInStartLBA & 0xFF) + .AppendLine(); + + sb.AppendFormat(Localization.Last_possible_Lead_Out_address_is_0_as_LBA_or_1_2_3, + information.Value.LastPossibleLeadOutStartLBA, + (information.Value.LastPossibleLeadOutStartLBA & 0xFF0000) >> 16, + (information.Value.LastPossibleLeadOutStartLBA & 0xFF00) >> 8, + information.Value.LastPossibleLeadOutStartLBA & 0xFF) + .AppendLine(); + + sb.AppendLine(information.Value.URU + ? Localization.Disc_is_defined_for_unrestricted_use + : Localization.Disc_is_defined_for_restricted_use); + + if(information.Value.DID_V) + sb.AppendFormat(Localization.Disc_ID_0_X6, information.Value.DiscIdentification & 0x00FFFFFF).AppendLine(); + + if(information.Value.DBC_V) + sb.AppendFormat(Localization.Disc_barcode_0, information.Value.DiscBarcode).AppendLine(); + + if(information.Value.DAC_V) + sb.AppendFormat(Localization.Disc_application_code_0, information.Value.DiscApplicationCode).AppendLine(); + + if(information.Value.OPCTables == null) return sb.ToString(); + + foreach(OPCTable table in information.Value.OPCTables) + { + sb.AppendFormat(Localization.OPC_values_for_0_Kbit_sec_1_2_3_4_5_6, + table.Speed, + table.OPCValues[0], + table.OPCValues[1], + table.OPCValues[2], + table.OPCValues[3], + table.OPCValues[4], + table.OPCValues[5]) + .AppendLine(); + } + + return sb.ToString(); + } + + public static TrackResourcesInformation? Decode001b(byte[] response) + { + if(response.Length != 12) return null; + + if((response[2] & 0xE0) != 0x20) return null; + + var decoded = new TrackResourcesInformation + { + DataLength = (ushort)((response[0] << 8) + response[1]) + }; + + if(decoded.DataLength + 2 != response.Length) return null; + + decoded.DataType = (byte)((response[2] & 0xE0) >> 5); + decoded.MaxTracks = (ushort)((response[4] << 8) + response[5]); + decoded.AssignedTracks = (ushort)((response[6] << 8) + response[7]); + decoded.MaxAppendableTracks = (ushort)((response[8] << 8) + response[9]); + decoded.AppendableTracks = (ushort)((response[10] << 8) + response[11]); + + return decoded; + } + + public static string Prettify001b(TrackResourcesInformation? information) + { + if(information?.DataType != 1) return null; + + var sb = new StringBuilder(); + + sb.AppendFormat(Localization._0_maximum_possible_tracks_on_the_disc, information.Value.MaxTracks).AppendLine(); + sb.AppendFormat(Localization._0_assigned_tracks_on_the_disc, information.Value.AssignedTracks).AppendLine(); + + sb.AppendFormat(Localization._0_maximum_possible_appendable_tracks_on_the_disc, + information.Value.AppendableTracks) + .AppendLine(); + + sb.AppendFormat(Localization._0_current_appendable_tracks_on_the_disc, information.Value.MaxAppendableTracks) + .AppendLine(); + + return sb.ToString(); + } + + public static POWResourcesInformation? Decode010b(byte[] response) + { + if(response.Length != 16) return null; + + if((response[2] & 0xE0) != 0x40) return null; + + var decoded = new POWResourcesInformation + { + DataLength = (ushort)((response[0] << 8) + response[1]) + }; + + if(decoded.DataLength + 2 != response.Length) return null; + + decoded.DataType = (byte)((response[2] & 0xE0) >> 5); + + decoded.RemainingPOWReplacements = + (ushort)((response[4] << 24) + (response[5] << 16) + (response[6] << 8) + response[7]); + + decoded.RemainingPOWReallocation = + (ushort)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]); + + decoded.RemainingPOWUpdates = + (ushort)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]); + + return decoded; + } + + public static string Prettify010b(POWResourcesInformation? information) + { + if(information?.DataType != 1) return null; + + var sb = new StringBuilder(); + + sb.AppendFormat(Localization._0_remaining_POW_replacements, information.Value.RemainingPOWReplacements) + .AppendLine(); + + sb.AppendFormat(Localization._0_remaining_POW_reallocation_map_entries, + information.Value.RemainingPOWReallocation) + .AppendLine(); + + sb.AppendFormat(Localization._0_remaining_POW_updates, information.Value.RemainingPOWUpdates).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify(byte[] response) + { + if(response == null) return null; + + if(response.Length < 12) return null; + + return (response[2] & 0xE0) switch + { + 0x00 => Prettify000b(Decode000b(response)), + 0x20 => Prettify001b(Decode001b(response)), + 0x40 => Prettify010b(Decode010b(response)), + _ => null + }; + } + +#region Nested type: OPCTable + + public struct OPCTable + { + /// Bytes 0 to 1 kilobytes/sec this OPC table applies to + public ushort Speed; + /// Bytes 2 to 7 OPC values + public byte[] OPCValues; + } + +#endregion + +#region Nested type: POWResourcesInformation + + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public struct POWResourcesInformation + { + /// Bytes 0 to 1 14 + public ushort DataLength; + /// Byte 2, bits 7 to 5 010b + public byte DataType; + /// Byte 2, bits 4 to 0 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 7 Remaining POW replacements + public uint RemainingPOWReplacements; + /// Bytes 8 to 11 Remaining POW reallocation map entries + public uint RemainingPOWReallocation; + /// Bytes 12 to 15 Number of remaining POW updates + public uint RemainingPOWUpdates; + } + +#endregion + +#region Nested type: StandardDiscInformation + + public struct StandardDiscInformation + { + /// Bytes 0 to 1 32 + OPCTablesNumber*8 + public ushort DataLength; + /// Byte 2, bits 7 to 5 000b + public byte DataType; + /// Byte 2, bit 4 If set, disc is erasable + public bool Erasable; + /// Byte 2, bits 3 to 2 Status of last session + public byte LastSessionStatus; + /// Byte 2, bits 1 to 0 Status of disc + public byte DiscStatus; + /// Byte 3 Number of logical track that contains LBA 0 + public byte FirstTrackNumber; + /// Byte 9 (MSB) and byte 4 (LSB) Number of sessions + public ushort Sessions; + /// Byte 10 (MSB) and byte 5 (LSB) Number of first track in last session + public ushort FirstTrackLastSession; + /// Byte 11 (MSB) and byte 6 (LSB) Number of last track in last session + public ushort LastTrackLastSession; + /// Byte 7, bit 7 If set, DiscIdentification is valid + public bool DID_V; + /// Byte 7, bit 6 If set, DiscBarcode is valid + public bool DBC_V; + /// Byte 7, bit 5 If set, disc is unrestricted + public bool URU; + /// Byte 7, bit 4 If set DiscApplicationCode is valid + public bool DAC_V; + /// Byte 7, bit 3 Reserved + public bool Reserved; + /// Byte 7, bit 2 Copy of dirty bit from MRW status + public bool Dbit; + /// Byte 7, bits 1 to 0 Background format status + public byte BGFormatStatus; + /// Byte 8 Disc type code + public byte DiscType; + /// Bytes 12 to 15 Disc identification number from PMA + public uint DiscIdentification; + /// Bytes 16 to 19 Last Session Lead-in Start Address (MSF for CD, LBA for others) + public uint LastSessionLeadInStartLBA; + /// Bytes 20 to 23 Last Possible Lead-out Start Address (MSF for CD, LBA for others) + public uint LastPossibleLeadOutStartLBA; + /// Bytes 24 to 31 Disc barcode + public ulong DiscBarcode; + /// Byte 32 Disc application code + public byte DiscApplicationCode; + /// Byte 33 How many OPC tables are + public byte OPCTablesNumber; + /// Bytes 34 to end OPC tables (8 bytes each) + public OPCTable[] OPCTables; + } + +#endregion + +#region Nested type: TrackResourcesInformation + + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public struct TrackResourcesInformation + { + /// Bytes 0 to 1 10 + public ushort DataLength; + /// Byte 2, bits 7 to 5 001b + public byte DataType; + /// Byte 2, bits 4 to 0 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 5 Maximum possible number of the tracks on the disc + public ushort MaxTracks; + /// Bytes 6 to 7 Number of the assigned tracks on the disc + public ushort AssignedTracks; + /// Bytes 8 to 9 Maximum possible number of appendable tracks on the disc + public ushort MaxAppendableTracks; + /// Bytes 10 to 11 Current number of appendable tracks on the disc + public ushort AppendableTracks; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/MMC/Enums.cs b/Aaru.Decoders/SCSI/MMC/Enums.cs new file mode 100644 index 000000000..a686849b9 --- /dev/null +++ b/Aaru.Decoders/SCSI/MMC/Enums.cs @@ -0,0 +1,87 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains various SCSI MMC enumerations. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + + +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +namespace Aaru.Decoders.SCSI.MMC; + +public enum FormatLayerTypeCodes : ushort +{ + CDLayer = 0x0008, + DVDLayer = 0x0010, + BDLayer = 0x0040, + HDDVDLayer = 0x0050 +} + +public enum SessionStatusCodes : byte +{ + Empty = 0x00, + Incomplete = 0x01, + ReservedOrDamaged = 0x02, + Complete = 0x03 +} + +public enum DiscStatusCodes : byte +{ + Empty = 0x00, + Incomplete = 0x01, + Finalized = 0x02, + Others = 0x03 +} + +public enum BGFormatStatusCodes : byte +{ + NoFormattable = 0x00, + IncompleteBackgroundFormat = 0x01, + BackgroundFormatInProgress = 0x02, + FormatComplete = 0x03 +} + +public enum DiscTypeCodes : byte +{ + /// Also valid for CD-DA, DVD and BD + CDROM = 0x00, + CDi = 0x10, + CDROMXA = 0x20, + Undefined = 0xFF +} + +public enum LayerJumpRecordingStatus : byte +{ + Incremental = 0, + Unspecified = 1, + Manual = 2, + RegularInterval = 3 +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/MMC/Features.cs b/Aaru.Decoders/SCSI/MMC/Features.cs new file mode 100644 index 000000000..70fd4be09 --- /dev/null +++ b/Aaru.Decoders/SCSI/MMC/Features.cs @@ -0,0 +1,4440 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Features.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MMC feature structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Text; +using Aaru.CommonTypes.Structs.Devices.SCSI; +using Aaru.Helpers; +using Aaru.Localization; + +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedType.Global +// ReSharper disable NotAccessedField.Global +// ReSharper disable InconsistentNaming +// ReSharper disable MemberCanBeInternal +// ReSharper disable UnusedMember.Global + +namespace Aaru.Decoders.SCSI.MMC; + +/// MMC Feature enumeration +public enum FeatureNumber : ushort +{ + /// Lists all profiles + ProfileList = 0x0000, + /// Mandatory behaviour + Core = 0x0001, + /// Operational changes + Morphing = 0x0002, + /// Removable medium + Removable = 0x0003, + /// Ability to control write protection status + WriteProtect = 0x0004, + /// Ability to read sectors with random addressing + RandomRead = 0x0010, + /// Reads on OSTA Multi-Read + MultiRead = 0x001D, + /// Able to read CD structures + CDRead = 0x001E, + /// Able to read DVD structures + DVDRead = 0x001F, + /// Ability to write sectors with random addressing + RandomWrite = 0x0020, + /// Ability to sequentially write + IncrementalWrite = 0x0021, + /// Support for media that requires erase before write + SectorErasable = 0x0022, + /// Supports formatting media + Formattable = 0x0023, + /// Ability to provide defect-free space + HardwareDefectMgmt = 0x0024, + /// Supports for write-once media in random order + WriteOnce = 0x0025, + /// Supports for media that shall be written from blocking boundaries + RestrictedOverwrite = 0x0026, + /// Supports high speed CD-RW + CDRWCAV = 0x0027, + /// Read and optionally write MRW + MRW = 0x0028, + /// Ability to control RECOVERED ERROR reporting + EnDefectReport = 0x0029, + /// Ability to recognize, read and optionally write DVD+RW + DVDRWPlus = 0x002A, + /// Ability to read DVD+R + DVDRPlus = 0x002B, + RigidOverWrite = 0x002C, + /// Ability to write CD in Track-at-Once + CDTAO = 0x002D, + /// Ability to write CD in Session-at-Once or RAW + CDMastering = 0x002E, + /// Ability to write DVD structures + DVDRWrite = 0x002F, + /// Ability to read DDCD + DDCD = 0x0030, + /// Ability to write DDCD-R + DDCDR = 0x0031, + /// Ability to write DDCD-RW + DDCDRW = 0x0032, + /// Ability to record in layer jump mode + LayerJump = 0x0033, + /// Ability to perform Layer Jump recording on Rigid Restricted Overwrite + LJRigid = 0x0034, + /// Ability to stop the long immediate operation + StopLong = 0x0035, + /// Ability to report CD-RW media sub-types supported for write + CDRWMediaWrite = 0x0037, + /// Logical block overwrite service on BD-R formatted as SRM+POW + BDRPOW = 0x0038, + /// Ability to read DVD+RW DL + DVDRWDLPlus = 0x003A, + /// Ability to read DVD+R DL + DVDRDLPlus = 0x003B, + /// Ability to read BD discs + BDRead = 0x0040, + /// Ability to write BD discs + BDWrite = 0x0041, + /// Timely, Safe Recording + TSR = 0x0042, + /// Ability to read HD DVD + HDDVDRead = 0x0050, + /// Ability to write HD DVD + HDDVDWrite = 0x0051, + /// Ability to write HD DVD-RW fragmented + HDDVDRWFragment = 0x0052, + /// Supports some Hybrid Discs + Hybrid = 0x0080, + /// Host and device directed power management + PowerMgmt = 0x0100, + /// Supports S.M.A.R.T. + SMART = 0x0101, + /// Single machanism multiple disc changer + Changer = 0x0102, + /// Ability to play CD audio to an analogue output + CDAudioExt = 0x0103, + /// Ability to accept new microcode + MicrocodeUpgrade = 0x0104, + /// Ability to respond to all commands within a specific time + Timeout = 0x0105, + /// Supports DVD CSS/CPPM + CSS = 0x0106, + /// Ability to read and write using host requested performance parameters + RTS = 0x0107, + /// Drive has a unique identifier + DriveSerial = 0x0108, + /// Ability to return unique Media Serial Number + MediaSerial = 0x0109, + /// Ability to read and/or write DCBs + DCBs = 0x010A, + /// Supports DVD CPRM + CPRM = 0x010B, + /// Firmware creation date report + FirmwareInfo = 0x010C, + /// Ability to decode and optionally encode AACS + AACS = 0x010D, + /// Ability to perform DVD CSS managed recording + CSSManagedRec = 0x010E, + /// Ability to decode and optionally encode VCPS + VCPS = 0x0110, + /// Supports SecurDisc + SecurDisc = 0x0113, + /// TCG Optical Security Subsystem Class + OSSC = 0x0142 +} + +/// MMC Profile enumeration +public enum ProfileNumber : ushort +{ + /// Not to use + Reserved = 0x0000, + /// Non-removable disk profile + NonRemovable = 0x0001, + /// Rewritable with removable media + Removable = 0x0002, + /// Magneto-Optical with sector erase + MOErasable = 0x0003, + /// Optical write once + OpticalWORM = 0x0004, + /// Advance Storage - Magneto-Optical + ASMO = 0x0005, + /// Read-only Compact Disc + CDROM = 0x0008, + /// Write-once Compact Disc + CDR = 0x0009, + /// Re-writable Compact Disc + CDRW = 0x000A, + /// Read-only DVD + DVDROM = 0x0010, + /// Write-once sequentially recorded DVD-R + DVDRSeq = 0x0011, + /// DVD-RAM + DVDRAM = 0x0012, + /// Restricted overwrite DVD-RW + DVDRWRes = 0x0013, + /// Sequential recording DVD-RW + DVDRWSeq = 0x0014, + /// Sequential recording DVD-R DL + DVDRDLSeq = 0x0015, + /// Layer jump recording DVD-R DL + DVDRDLJump = 0x0016, + /// DVD-RW DL + DVDRWDL = 0x0017, + /// DVD-Download + DVDDownload = 0x0018, + /// DVD+RW + DVDRWPlus = 0x001A, + /// DVD+R + DVDRPlus = 0x001B, + /// DDCD-ROM + DDCDROM = 0x0020, + /// DDCD-R + DDCDR = 0x0021, + /// DDCD-RW + DDCDRW = 0x0022, + /// DVD+RW DL + DVDRWDLPlus = 0x002A, + /// DVD+R DL + DVDRDLPlus = 0x002B, + /// BD-ROM + BDROM = 0x0040, + /// BD-R SRM + BDRSeq = 0x0041, + /// BD-R RRM + BDRRdm = 0x0042, + /// BD-RE + BDRE = 0x0043, + /// HD DVD-ROM + HDDVDROM = 0x0050, + /// HD DVD-R + HDDVDR = 0x0051, + /// HD DVD-RAM + HDDVDRAM = 0x0052, + /// HD DVD-RW + HDDVDRW = 0x0053, + /// HD DVD-R DL + HDDVDRDL = 0x0058, + /// HD DVD-RW DL + HDDVDRWDL = 0x005A, + /// HDBurn CD-ROM + HDBURNROM = 0x0080, + /// HDBurn CD-R + HDBURNR = 0x0081, + /// HDBurn CD-RW + HDBURNRW = 0x0082, + /// Drive does not conform to any profiles + Unconforming = 0xFFFF +} + +public struct Profile +{ + public ProfileNumber Number; + public bool Current; +} + +/// Profile List Feature (0000h) +public struct Feature_0000 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// All supported profiles + public Profile[] Profiles; +} + +/// Core Feature (0001h) +public struct Feature_0001 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Currently in-use physical interface standard + public PhysicalInterfaces PhysicalInterfaceStandard; + /// Supports EVPD, Page Code and 16-bit Allocation Length as defined in SPC-3 + public bool INQ2; + /// Supports Device Busy Event + public bool DBE; +} + +/// Morphing Feature (0002h) +public struct Feature_0002 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports Operational Change Request/Nofitication Class Events of GET EVENT/STATUS NOTIFICATION + public bool OCEvent; + /// Supports asynchronous GET EVENT/STATUS NOTIFICATION + public bool Async; +} + +/// Removable Medium Feature (0003h) +public struct Feature_0003 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Mechanism type + public byte LoadingMechanismType; + /// Drive is able to load the medium + public bool Load; + /// Device can eject medium + public bool Eject; + /// Device starts in medium ejection/insertion allow + public bool PreventJumper; + /// Reports Device Busy Class events during medium loading/unloading + public bool DBML; + /// Medium is currently locked + public bool Lock; +} + +/// Write Protect Feature (0004h) +public struct Feature_0004 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Drive can read/write Disc Write Protect PAC on BD-R/-RE media + public bool DWP; + /// Supports reading/writing Write Inhibit DCB on DVD+RW media. + public bool WDCB; + /// Supports PWP status + public bool SPWP; + /// Supports SWPP bit of mode page 1Dh + public bool SSWPP; +} + +/// Random Readable Feature (0010h) +public struct Feature_0010 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Bytes per logical block + public uint LogicalBlockSize; + /// Number of logical blocks per device readable unit + public ushort Blocking; + /// Read/Write Error Recovery page is present + public bool PP; +} + +/// Multi-Read Feature (001Dh) +public struct Feature_001D +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// CD Read Feature (001Eh) +public struct Feature_001E +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports DAP bit in READ CD and READ CD MSF + public bool DAP; + /// Supports C2 Error Pointers + public bool C2; + /// Can read CD-Text with READ TOC/PMA/ATIP + public bool CDText; +} + +/// DVD Read Feature (001Fh) +public struct Feature_001F +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Compliant with DVD Multi Drive Read-only specifications + public bool MULTI110; + /// Supports reading all DVD-RW DL + public bool DualRW; + /// Supports reading all DVD-R DL including remapping + public bool DualR; +} + +/// Random Writable Feature (0020h) +public struct Feature_0020 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Last logical block address + public uint LastLBA; + /// Bytes per logical block + public uint LogicalBlockSize; + /// Number of logical blocks per device readable unit + public ushort Blocking; + /// Read/Write Error Recovery page is present + public bool PP; +} + +/// Incremental Streaming Writable Feature (0021h) +public struct Feature_0021 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Bitmask of supported data types + public ushort DataTypeSupported; + /// Can report Track Resources Information of READ DISC INFORMATION + public bool TRIO; + /// Supports Address Mode in RESERVE TRACK + public bool ARSV; + /// Zero loss linking + public bool BUF; + /// Logical blocks per link + public byte[] LinkSizes; +} + +/// Sector Erasable Feature (0022h) +public struct Feature_0022 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// Formattable Feature (0023h) +public struct Feature_0023 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports formatting BD-RE without spare area + public bool RENoSA; + /// Supports expansion of the spare area on BD-RE + public bool Expand; + /// Supports FORMAT type 30h sub-type 11b + public bool QCert; + /// Supports FORMAT type 30h sub-type 10b + public bool Cert; + /// Supports FORMAT type 18h + public bool FRF; + /// Supports FORMAT type 00h/32h sub-type 10b on BD-R + public bool RRM; +} + +/// Hardware Defect Management Feature (0024h) +public struct Feature_0024 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports READ DISC STRUCTURE with Format Code 0Ah (Spare Area Information) + public bool SSA; +} + +/// Write Once Feature (0025h) +public struct Feature_0025 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Bytes per logical block + public uint LogicalBlockSize; + /// Number of logical blocks per device readable unit + public ushort Blocking; + /// Read/Write Error Recovery page is present + public bool PP; +} + +/// Restricted Overwrite Feature (0026h) +public struct Feature_0026 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// CD-RW CAV Write Feature (0027h) +public struct Feature_0027 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// MRW Feature (0028h) +public struct Feature_0028 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can read DVD+MRW discs + public bool DVDPRead; + /// Can write DVD+MRW discs + public bool DVDPWrite; + /// Can format and write to CD-MRW discs + public bool Write; +} + +/// Enhanced Defect Reporting Feature (0029h) +public struct Feature_0029 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports DRT-DM + public bool DRTDM; + /// Maximum number of DBI cache zones device can handle separately + public byte DBICacheZones; + /// Number of entries in worst case to case DBI overflow + public ushort Entries; +} + +/// DVD+RW Feature (002Ah) +public struct Feature_002A +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can format DVD+RW discs + public bool Write; + /// FORMAT UNIT supports quick start formatting + public bool QuickStart; + /// Drive only supports read compatibility stop + public bool CloseOnly; +} + +/// DVD+R Feature (002Bh) +public struct Feature_002B +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can write DVD+R + public bool Write; +} + +/// Rigid Restricted Overwrite Feature (002Ch) +public struct Feature_002C +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can generate Defect Status Data during formatting + public bool DSDG; + /// Can read Defect Status Data recorded on medium + public bool DSDR; + /// Supports writing on an intermediate state Session and quick formatting + public bool Intermediate; + /// Supports BLANK command types 00h and 01h + public bool Blank; +} + +/// CD Track at Once Feature (002Dh) +public struct Feature_002D +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports zero loss linking + public bool BUF; + /// Supports writing R-W subchannels in raw mode + public bool RWRaw; + /// Supports writing R-W subchannels in packed mode + public bool RWPack; + /// Can perform test writes + public bool TestWrite; + /// Supports overwriting a TAO track with another + public bool CDRW; + /// Can write R-W subchannels with user provided data + public bool RWSubchannel; + /// Bitmask of supported data types + public ushort DataTypeSupported; +} + +/// CD Mastering (Session at Once) Feature (002Eh) +public struct Feature_002E +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports zero loss linking + public bool BUF; + /// Can write in Session at Once + public bool SAO; + /// Can write multi-session in RAW + public bool RAWMS; + /// Can write in RAW + public bool RAW; + /// Can perform test writes + public bool TestWrite; + /// Can overwrite previously recorded data + public bool CDRW; + /// Can write R-W subchannels with user provided data + public bool RW; + /// Maximum length of a Cue Sheet for Session at Once + public uint MaxCueSheet; +} + +/// DVD-R/-RW Write Feature (002Fh) +public struct Feature_002F +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Buffer Under-run protection + public bool BUF; + /// Supports writing DVD-R DL + public bool RDL; + /// Test write + public bool TestWrite; + /// Can write and erase DVD-RW + public bool DVDRW; +} + +/// Double Density CD Read Feature (0030h) +public struct Feature_0030 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// Double Density CD-R Write Feature (0031h) +public struct Feature_0031 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Test write + public bool TestWrite; +} + +/// Double Density CD-RW Write Feature (0032h) +public struct Feature_0032 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports quick formatting + public bool Intermediate; + /// Supports BLANK command + public bool Blank; +} + +/// Layer Jump Recording Feature (0033h) +public struct Feature_0033 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + public byte[] LinkSizes; +} + +/// Stop Long Operation Feature (0035h) +public struct Feature_0035 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// CD-RW Media Write Support Feature (0037h) +public struct Feature_0037 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Bitmask of supported CD-RW media sub-types + public byte SubtypeSupport; +} + +/// BD-R Pseudo-Overwrite (POW) Feature (0038h) +public struct Feature_0038 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// DVD+RW Dual Layer Feature (003Ah) +public struct Feature_003A +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can format DVD+RW DL discs + public bool Write; + /// FORMAT UNIT supports quick start formatting + public bool QuickStart; + /// Drive only supports read compatibility stop + public bool CloseOnly; +} + +/// DVD+R Dual Layer Feature (003Bh) +public struct Feature_003B +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can format DVD+R DL discs + public bool Write; + /// FORMAT UNIT supports quick start formatting + public bool QuickStart; + /// Drive only supports read compatibility stop + public bool CloseOnly; +} + +/// BD Read Feature (0040h) +public struct Feature_0040 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can read BCA + public bool BCA; + /// Supports reading BD-RE Ver.2 + public bool RE2; + /// Supports reading BD-RE Ver.1 + public bool RE1; + /// Obsolete + public bool OldRE; + /// Supports reading BD-R Ver.1 + public bool R; + /// Obsolete + public bool OldR; + /// Supports reading BD-ROM Ver.1 + public bool ROM; + /// Obsolete + public bool OldROM; +} + +/// BD Write Feature (0041h) +public struct Feature_0041 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports verify not required + public bool SVNR; + /// Supports writing BD-RE Ver.2 + public bool RE2; + /// Supports writing BD-RE Ver.1 + public bool RE1; + /// Obsolete + public bool OldRE; + /// Supports writing BD-R Ver.1 + public bool R; + /// Obsolete + public bool OldR; +} + +/// TSR Feature (0042h) +public struct Feature_0042 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// HD DVD Read Feature (0050h) +public struct Feature_0050 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can read HD DVD-R + public bool HDDVDR; + /// Can read HD DVD-RAM + public bool HDDVDRAM; +} + +/// HD DVD Write Feature (0051h) +public struct Feature_0051 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can write HD DVD-R + public bool HDDVDR; + /// Can write HD DVD-RAM + public bool HDDVDRAM; +} + +/// Hybrid Disc Feature (0080h) +public struct Feature_0080 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Reset immunity + public bool RI; +} + +/// Power Management Feature (0100h) +public struct Feature_0100 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// S.M.A.R.T. Feature (0101h) +public struct Feature_0101 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Mode Page 1Ch is present + public bool PP; +} + +/// Embedded Changer Feature (0102h) +public struct Feature_0102 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Side change capable + public bool SCC; + /// Supports Disc Present + public bool SDP; + /// Number of slots - 1 + public byte HighestSlotNumber; +} + +/// CD Audio External Play Feature (0103h) +public struct Feature_0103 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports SCAN command + public bool Scan; + /// Separate Channel Mute + public bool SCM; + /// Separate Volume + public bool SV; + /// Number of volume levels + public ushort VolumeLevels; +} + +/// Microcode Upgrade Feature (0104h) +public struct Feature_0104 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports validating 5-bit mode field of READ BUFFER and WRITE BUFFER commands. + public bool M5; +} + +/// Time-Out Feature (0105h) +public struct Feature_0105 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports G3Enable bit and Group3 Timeout field in Mode Page 1Dh + public bool Group3; + /// Indicates a unit of block length, in sectors, corresponding to increase a unit of Group 3 time unit + public ushort UnitLength; +} + +/// DVD-CSS Feature (0106h) +public struct Feature_0106 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// CSS version + public byte CSSVersion; +} + +/// Real Time Streaming Feature (0107h) +public struct Feature_0107 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports Set Minimum Performance bit in SET STREAMING + public bool SMP; + /// Supports READ BUFFER CAPACITY with block bit set + public bool RBCB; + /// Supports SET CD SPEED + public bool SCS; + /// Has Mode Page 2Ah with Speed Performance Descriptors + public bool MP2A; + /// Supports type 03h of GET PERFORMANCE + public bool WSPD; + /// Supports stream recording + public bool SW; +} + +/// Drive serial number (0108h) +public struct Feature_0108 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Drive serial number + public string Serial; +} + +/// Media Serial Number Feature (0109h) +public struct Feature_0109 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// Disc Control Blocks Feature (010Ah) +public struct Feature_010A +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + public uint[] DCBs; +} + +/// DVD CPRM Feature (010Bh) +public struct Feature_010B +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// CPRM version + public byte CPRMVersion; +} + +/// Firmware Information Feature (010Ch) +public struct Feature_010C +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + public ushort Century; + public ushort Year; + public ushort Month; + public ushort Day; + public ushort Hour; + public ushort Minute; + public ushort Second; +} + +/// AACS Feature (010Dh) +public struct Feature_010D +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Drive supports reading drive certificate + public bool RDC; + /// Drive can read media key block of CPRM + public bool RMC; + /// Drive can write bus encrypted blocks + public bool WBE; + /// Drive supports bus encryption + public bool BEC; + /// Drive supports generating the binding nonce + public bool BNG; + /// Blocks required to store the binding nonce for the media + public byte BindNonceBlocks; + /// Maximum number of AGIDs supported concurrently + public byte AGIDs; + /// AACS version + public byte AACSVersion; +} + +/// DVD CSS Managed Recording Feature (010Eh) +public struct Feature_010E +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Maximum number of Scramble Extent information entries in a single SEND DISC STRUCTURE + public byte MaxScrambleExtent; +} + +/// SecurDisc Feature (0113h) +public struct Feature_0113 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +/// OSSC Feature (0142h) +public struct Feature_0142 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports PSA updates on write-once media + public bool PSAU; + /// Supports linked OSPBs + public bool LOSPB; + /// Restricted to recording only OSSC disc format + public bool ME; + public ushort[] Profiles; +} + +/// VCPS Feature (0110h) +public struct Feature_0110 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} + +public static class Features +{ + public static Feature_0000? Decode_0000(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0000) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0000(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + var offset = 4; + List listProfiles = []; + + while(offset < feature.Length) + { + var prof = new Profile + { + Number = (ProfileNumber)((feature[offset] << 8) + feature[offset + 1]) + }; + + prof.Current |= (feature[offset + 2] & 0x01) == 0x01; + listProfiles.Add(prof); + offset += 4; + } + + decoded.Profiles = listProfiles.ToArray(); + + return decoded; + } + + public static Feature_0001? Decode_0001(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0001) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0001(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.PhysicalInterfaceStandard = + (PhysicalInterfaces)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); + + if(decoded.Version >= 1 && feature.Length >= 12) decoded.DBE |= (feature[8] & 0x01) == 0x01; + + if(decoded.Version >= 2 && feature.Length >= 12) decoded.INQ2 |= (feature[8] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0002? Decode_0002(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0002) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0002(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Async |= (feature[4] & 0x01) == 0x01; + + if(decoded.Version >= 1) decoded.OCEvent |= (feature[4] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0003? Decode_0003(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0003) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0003(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.LoadingMechanismType = (byte)((feature[4] & 0xE0) >> 5); + decoded.Eject |= (feature[4] & 0x08) == 0x08; + decoded.PreventJumper |= (feature[4] & 0x04) == 0x04; + decoded.Lock |= (feature[4] & 0x01) == 0x01; + + if(decoded.Version < 2) return decoded; + + decoded.Load |= (feature[4] & 0x10) == 0x10; + decoded.DBML |= (feature[4] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0004? Decode_0004(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0004) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0004(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.SPWP |= (feature[4] & 0x02) == 0x02; + decoded.SSWPP |= (feature[4] & 0x01) == 0x01; + + if(decoded.Version >= 1) decoded.WDCB |= (feature[4] & 0x04) == 0x04; + + if(decoded.Version >= 2) decoded.DWP |= (feature[4] & 0x08) == 0x08; + + return decoded; + } + + public static Feature_0010? Decode_0010(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 12) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0010) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0010(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.LogicalBlockSize = (uint)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); + + decoded.Blocking = (ushort)((feature[8] << 8) + feature[9]); + + decoded.PP |= (feature[10] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_001D? Decode_001D(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x001D) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_001D(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_001E? Decode_001E(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x001E) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_001E(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 1) + { + decoded.C2 |= (feature[4] & 0x02) == 0x02; + decoded.CDText |= (feature[4] & 0x01) == 0x01; + } + + if(decoded.Version >= 2) decoded.DAP |= (feature[4] & 0x80) == 0x80; + + return decoded; + } + + public static Feature_001F? Decode_001F(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x001F) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_001F(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 2 && feature.Length >= 8) + { + decoded.MULTI110 |= (feature[4] & 0x01) == 0x01; + decoded.DualR |= (feature[6] & 0x01) == 0x01; + } + + // TODO: Check this + if(decoded.Version >= 2 && feature.Length >= 8) decoded.DualRW |= (feature[6] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0020? Decode_0020(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 16) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0020) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0020(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version < 1) return decoded; + + decoded.LastLBA = (uint)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); + + decoded.LogicalBlockSize = (uint)((feature[8] << 24) + (feature[9] << 16) + (feature[10] << 8) + feature[11]); + + decoded.Blocking = (ushort)((feature[12] << 8) + feature[13]); + decoded.PP |= (feature[14] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0021? Decode_0021(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0021) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0021(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 1) + { + decoded.DataTypeSupported = (ushort)((feature[4] << 8) + feature[5]); + decoded.BUF |= (feature[6] & 0x01) == 0x01; + decoded.LinkSizes = new byte[feature[7]]; + + if(feature.Length > feature[7] + 8) Array.Copy(feature, 8, decoded.LinkSizes, 0, feature[7]); + } + + if(decoded.Version < 3) return decoded; + + decoded.TRIO |= (feature[6] & 0x04) == 0x04; + decoded.ARSV |= (feature[6] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0022? Decode_0022(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0022) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0022(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0023? Decode_0023(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0023) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0023(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 1 && feature.Length >= 12) + { + decoded.RENoSA |= (feature[4] & 0x08) == 0x08; + decoded.Expand |= (feature[4] & 0x04) == 0x04; + decoded.QCert |= (feature[4] & 0x02) == 0x02; + decoded.Cert |= (feature[4] & 0x01) == 0x01; + decoded.RRM |= (feature[8] & 0x01) == 0x01; + } + + if(decoded.Version >= 2 && feature.Length >= 12) decoded.FRF |= (feature[4] & 0x80) == 0x80; + + return decoded; + } + + public static Feature_0024? Decode_0024(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0024) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0024(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 1 && feature.Length >= 8) decoded.SSA |= (feature[4] & 0x80) == 0x80; + + return decoded; + } + + public static Feature_0025? Decode_0025(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 12) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0025) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0025(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.LogicalBlockSize = (uint)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); + + decoded.Blocking = (ushort)((feature[8] << 8) + feature[9]); + + decoded.PP |= (feature[10] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0026? Decode_0026(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0026) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0026(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0027? Decode_0027(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0027) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0027(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0028? Decode_0028(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0028) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0028(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Write |= (feature[4] & 0x01) == 0x01; + + if(decoded.Version < 1) return decoded; + + decoded.DVDPWrite |= (feature[4] & 0x04) == 0x04; + decoded.DVDPRead |= (feature[4] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0029? Decode_0029(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0029) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0029(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.DRTDM |= (feature[4] & 0x01) == 0x01; + decoded.DBICacheZones = feature[5]; + decoded.Entries = (ushort)((feature[6] << 8) + feature[7]); + + return decoded; + } + + public static Feature_002A? Decode_002A(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x002A) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_002A(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Write |= (feature[4] & 0x01) == 0x01; + decoded.CloseOnly |= (feature[5] & 0x01) == 0x01; + + if(decoded.Version >= 1) decoded.QuickStart |= (feature[5] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_002B? Decode_002B(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x002B) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_002B(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Write |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_002C? Decode_002C(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x002C) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_002C(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.DSDG |= (feature[4] & 0x08) == 0x08; + decoded.DSDR |= (feature[4] & 0x04) == 0x04; + decoded.Intermediate |= (feature[4] & 0x02) == 0x02; + decoded.Blank |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_002D? Decode_002D(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x002D) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_002D(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.TestWrite |= (feature[4] & 0x04) == 0x04; + decoded.CDRW |= (feature[4] & 0x02) == 0x02; + decoded.RWSubchannel |= (feature[4] & 0x01) == 0x01; + decoded.DataTypeSupported = (ushort)((feature[6] << 8) + feature[7]); + + if(decoded.Version < 2) return decoded; + + decoded.BUF |= (feature[4] & 0x40) == 0x40; + decoded.RWRaw |= (feature[4] & 0x10) == 0x10; + decoded.RWPack |= (feature[4] & 0x08) == 0x08; + + return decoded; + } + + public static Feature_002E? Decode_002E(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x002E) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_002E(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.SAO |= (feature[4] & 0x20) == 0x20; + decoded.RAWMS |= (feature[4] & 0x10) == 0x10; + decoded.RAW |= (feature[4] & 0x08) == 0x08; + decoded.TestWrite |= (feature[4] & 0x04) == 0x04; + decoded.CDRW |= (feature[4] & 0x02) == 0x02; + decoded.RW |= (feature[4] & 0x01) == 0x01; + decoded.MaxCueSheet = (uint)((feature[5] << 16) + (feature[6] << 8) + feature[7]); + + if(decoded.Version >= 1) decoded.BUF |= (feature[4] & 0x40) == 0x40; + + return decoded; + } + + public static Feature_002F? Decode_002F(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x002F) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_002F(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.BUF |= (feature[4] & 0x40) == 0x40; + decoded.TestWrite |= (feature[4] & 0x04) == 0x04; + + if(decoded.Version >= 1) decoded.DVDRW |= (feature[4] & 0x02) == 0x02; + + if(decoded.Version >= 2) decoded.RDL |= (feature[4] & 0x08) == 0x08; + + return decoded; + } + + public static Feature_0030? Decode_0030(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0030) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0030(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0031? Decode_0031(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0031) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0031(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.TestWrite |= (feature[4] & 0x04) == 0x04; + + return decoded; + } + + public static Feature_0032? Decode_0032(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0032) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0032(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Intermediate |= (feature[4] & 0x02) == 0x02; + decoded.Blank |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0033? Decode_0033(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0033) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0033(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(feature[7] <= 0 || feature.Length <= feature[7] + 8) return decoded; + + decoded.LinkSizes = new byte[feature[7]]; + Array.Copy(feature, 8, decoded.LinkSizes, 0, feature[7]); + + return decoded; + } + + public static Feature_0035? Decode_0035(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0035) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0035(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0037? Decode_0037(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0037) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0037(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.SubtypeSupport = feature[5]; + + return decoded; + } + + public static Feature_0038? Decode_0038(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0038) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0038(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_003A? Decode_003A(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x003A) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_003A(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Write |= (feature[4] & 0x01) == 0x01; + decoded.QuickStart |= (feature[5] & 0x02) == 0x02; + decoded.CloseOnly |= (feature[5] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_003B? Decode_003B(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x003B) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_003B(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Write |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0040? Decode_0040(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 32) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0040) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0040(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.OldRE |= (feature[9] & 0x01) == 0x01; + decoded.OldR |= (feature[17] & 0x01) == 0x01; + decoded.OldROM |= (feature[25] & 0x01) == 0x01; + + if(decoded.Version < 1) return decoded; + + decoded.BCA |= (feature[4] & 0x01) == 0x01; + decoded.RE2 |= (feature[9] & 0x04) == 0x04; + decoded.RE1 |= (feature[9] & 0x02) == 0x02; + decoded.R |= (feature[17] & 0x02) == 0x02; + decoded.ROM |= (feature[25] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0041? Decode_0041(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 24) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0041) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0041(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.SVNR |= (feature[4] & 0x01) == 0x01; + decoded.OldRE |= (feature[9] & 0x01) == 0x01; + decoded.OldR |= (feature[17] & 0x01) == 0x01; + + if(decoded.Version < 1) return decoded; + + decoded.RE2 |= (feature[9] & 0x04) == 0x04; + decoded.RE1 |= (feature[9] & 0x02) == 0x02; + decoded.R |= (feature[17] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0042? Decode_0042(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0042) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0042(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0050? Decode_0050(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0050) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0050(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.HDDVDR |= (feature[4] & 0x01) == 0x01; + decoded.HDDVDRAM |= (feature[6] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0051? Decode_0051(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0051) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0051(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.HDDVDR |= (feature[4] & 0x01) == 0x01; + decoded.HDDVDRAM |= (feature[6] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0080? Decode_0080(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0080) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0080(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.RI |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0100? Decode_0100(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0100) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0100(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0101? Decode_0101(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0101) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0101(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.PP |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0102? Decode_0102(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0102) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0102(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.SCC |= (feature[4] & 0x10) == 0x10; + decoded.SDP |= (feature[4] & 0x04) == 0x04; + decoded.HighestSlotNumber = (byte)(feature[7] & 0x1F); + + return decoded; + } + + public static Feature_0103? Decode_0103(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0103) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0103(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Scan |= (feature[4] & 0x04) == 0x04; + decoded.SCM |= (feature[4] & 0x02) == 0x02; + decoded.SV |= (feature[4] & 0x01) == 0x01; + decoded.VolumeLevels = (ushort)((feature[6] << 8) + feature[7]); + + return decoded; + } + + public static Feature_0104? Decode_0104(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0104) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0104(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 1 && feature.Length >= 8) decoded.M5 |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0105? Decode_0105(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0105) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0105(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version < 1 || feature.Length < 8) return decoded; + + decoded.Group3 |= (feature[4] & 0x01) == 0x01; + decoded.UnitLength = (ushort)((feature[6] << 8) + feature[7]); + + return decoded; + } + + public static Feature_0106? Decode_0106(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0106) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0106(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.CSSVersion = feature[7]; + + return decoded; + } + + public static Feature_0107? Decode_0107(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0107) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0107(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 3 && feature.Length >= 8) + { + decoded.RBCB |= (feature[4] & 0x10) == 0x10; + decoded.SCS |= (feature[4] & 0x08) == 0x08; + decoded.MP2A |= (feature[4] & 0x04) == 0x04; + decoded.WSPD |= (feature[4] & 0x02) == 0x02; + decoded.SW |= (feature[4] & 0x01) == 0x01; + } + + if(decoded.Version < 5 || feature.Length < 8) return decoded; + + decoded.SMP |= (feature[4] & 0x20) == 0x20; + decoded.RBCB |= (feature[4] & 0x10) == 0x10; + + return decoded; + } + + public static Feature_0108? Decode_0108(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0108) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0108(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + var serial = new byte[feature.Length]; + Array.Copy(feature, 4, serial, 0, feature.Length - 4); + decoded.Serial = StringHandlers.CToString(serial).Trim(); + + return decoded; + } + + public static Feature_0109? Decode_0109(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0109) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0109(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_010A? Decode_010A(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x010A) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_010A(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.DCBs = new uint[feature[3] / 4]; + + for(var i = 0; i < decoded.DCBs.Length; i++) + { + decoded.DCBs[i] = (uint)((feature[0 + 4 + i * 4] << 24) + + (feature[1 + 4 + i * 4] << 16) + + (feature[2 + 4 + i * 4] << 8) + + feature[3 + 4 + i * 4]); + } + + return decoded; + } + + public static Feature_010B? Decode_010B(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x010B) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_010B(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.CPRMVersion = feature[7]; + + return decoded; + } + + public static Feature_010C? Decode_010C(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 20) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x010C) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_010C(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Century = (ushort)((feature[4] << 8) + feature[5]); + decoded.Year = (ushort)((feature[6] << 8) + feature[7]); + decoded.Month = (ushort)((feature[8] << 8) + feature[9]); + decoded.Day = (ushort)((feature[10] << 8) + feature[11]); + decoded.Hour = (ushort)((feature[12] << 8) + feature[13]); + decoded.Minute = (ushort)((feature[14] << 8) + feature[15]); + decoded.Second = (ushort)((feature[16] << 8) + feature[17]); + + return decoded; + } + + public static Feature_010D? Decode_010D(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x010D) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_010D(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.BNG |= (feature[4] & 0x01) == 0x01; + decoded.BindNonceBlocks = feature[5]; + decoded.AGIDs = (byte)(feature[6] & 0x0F); + decoded.AACSVersion = feature[7]; + + if(decoded.Version < 2) return decoded; + + decoded.RDC |= (feature[4] & 0x10) == 0x10; + decoded.RMC |= (feature[4] & 0x08) == 0x08; + decoded.WBE |= (feature[4] & 0x04) == 0x04; + decoded.BEC |= (feature[4] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_010E? Decode_010E(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x010E) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_010E(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.MaxScrambleExtent = feature[4]; + + return decoded; + } + + public static Feature_0110? Decode_0110(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 8) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0110) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0110(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0113? Decode_0113(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 4) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0113) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0113(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0142? Decode_0142(byte[] feature) + { + if(feature == null) return null; + + if(feature.Length < 6) return null; + + var number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0142) return null; + + if(feature[3] + 4 != feature.Length) return null; + + var decoded = new Feature_0142(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.PSAU |= (feature[4] & 0x80) == 0x80; + decoded.LOSPB |= (feature[4] & 0x40) == 0x40; + decoded.ME |= (feature[4] & 0x01) == 0x01; + decoded.Profiles = new ushort[feature[5]]; + + if(feature[5] * 2 + 6 != feature.Length) return decoded; + + for(var i = 0; i < feature[5]; i++) + decoded.Profiles[i] = (ushort)((feature[0 + 6 + 2 * i] << 8) + feature[1 + 6 + 2 * i]); + + return decoded; + } + + public static string Prettify_0000(Feature_0000? feature) + { + if(!feature.HasValue) return null; + + Feature_0000 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Supported_Profiles); + + if(ftr.Profiles == null) return sb.ToString(); + + foreach(Profile prof in ftr.Profiles) + { + switch(prof.Number) + { + case ProfileNumber.Reserved: + sb.Append("\t" + Localization.Drive_reported_a_reserved_profile_number); + + break; + case ProfileNumber.NonRemovable: + sb.Append("\t" + Localization.Drive_supports_non_removable_changeable_media); + + break; + case ProfileNumber.Removable: + sb.Append("\t" + Localization.Drive_supports_rewritable_and_removable_media); + + break; + case ProfileNumber.MOErasable: + sb.Append("\t" + Localization.Drive_supports_Magneto_Optical_media); + + break; + case ProfileNumber.OpticalWORM: + sb.Append("\t" + Localization.Drive_supports_optical_write_once_media); + + break; + case ProfileNumber.ASMO: + sb.Append("\t" + Localization.Drive_supports_Advanced_Storage_Magneto_Optical); + + break; + case ProfileNumber.CDROM: + sb.Append("\t" + Localization.Drive_supports_CD_ROM); + + break; + case ProfileNumber.CDR: + sb.Append("\t" + Localization.Drive_supports_CD_R); + + break; + case ProfileNumber.CDRW: + sb.Append("\t" + Localization.Drive_supports_CD_RW); + + break; + case ProfileNumber.DVDROM: + sb.Append("\t" + Localization.Drive_supports_DVD_ROM); + + break; + case ProfileNumber.DVDRSeq: + sb.Append("\t" + Localization.Drive_supports_DVD_R); + + break; + case ProfileNumber.DVDRAM: + sb.Append("\t" + Localization.Drive_supports_DVD_RAM); + + break; + case ProfileNumber.DVDRWRes: + sb.Append("\t" + Localization.Drive_supports_restricted_overwrite_DVD_RW); + + break; + case ProfileNumber.DVDRWSeq: + sb.Append("\t" + Localization.Drive_supports_sequentially_recorded_DVD_RW); + + break; + case ProfileNumber.DVDRDLSeq: + sb.Append("\t" + Localization.Drive_supports_sequentially_recorded_DVD_R_DL); + + break; + case ProfileNumber.DVDRDLJump: + sb.Append("\t" + Localization.Drive_supports_layer_jump_recorded_DVD_R_DL); + + break; + case ProfileNumber.DVDRWDL: + sb.Append("\t" + Localization.Drive_supports_DVD_RW_DL); + + break; + case ProfileNumber.DVDDownload: + sb.Append("\t" + Localization.Drive_supports_DVD_Download); + + break; + case ProfileNumber.DVDRWPlus: + sb.Append("\t" + Localization.Drive_supports_DVD_Plus_RW); + + break; + case ProfileNumber.DVDRPlus: + sb.Append("\t" + Localization.Drive_supports_DVD_Plus_R); + + break; + case ProfileNumber.DDCDROM: + sb.Append("\t" + Localization.Drive_supports_DDCD_ROM); + + break; + case ProfileNumber.DDCDR: + sb.Append("\t" + Localization.Drive_supports_DDCD_R); + + break; + case ProfileNumber.DDCDRW: + sb.Append("\t" + Localization.Drive_supports_DDCD_RW); + + break; + case ProfileNumber.DVDRWDLPlus: + sb.Append("\t" + Localization.Drive_supports_DVD_Plus_RW_DL); + + break; + case ProfileNumber.DVDRDLPlus: + sb.Append("\t" + Localization.Drive_supports_DVD_Plus_R_DL); + + break; + case ProfileNumber.BDROM: + sb.Append("\t" + Localization.Drive_supports_BD_ROM); + + break; + case ProfileNumber.BDRSeq: + sb.Append("\t" + Localization.Drive_supports_BD_R_SRM); + + break; + case ProfileNumber.BDRRdm: + sb.Append("\t" + Localization.Drive_supports_BD_R_RRM); + + break; + case ProfileNumber.BDRE: + sb.Append("\t" + Localization.Drive_supports_BD_RE); + + break; + case ProfileNumber.HDDVDROM: + sb.Append("\t" + Localization.Drive_supports_HD_DVD_ROM); + + break; + case ProfileNumber.HDDVDR: + sb.Append("\t" + Localization.Drive_supports_HD_DVD_R); + + break; + case ProfileNumber.HDDVDRAM: + sb.Append("\t" + Localization.Drive_supports_HD_DVD_RAM); + + break; + case ProfileNumber.HDDVDRW: + sb.Append("\t" + Localization.Drive_supports_HD_DVD_RW); + + break; + case ProfileNumber.HDDVDRDL: + sb.Append("\t" + Localization.Drive_supports_HD_DVD_R_DL); + + break; + case ProfileNumber.HDDVDRWDL: + sb.Append("\t" + Localization.Drive_supports_HD_DVD_RW_DL); + + break; + case ProfileNumber.HDBURNROM: + sb.Append("\t" + Localization.Drive_supports_HDBurn_CD_ROM); + + break; + case ProfileNumber.HDBURNR: + sb.Append("\t" + Localization.Drive_supports_HDBurn_CD_R); + + break; + case ProfileNumber.HDBURNRW: + sb.Append("\t" + Localization.Drive_supports_HDBurn_CD_RW); + + break; + case ProfileNumber.Unconforming: + sb.Append("\t" + Localization.Drive_is_not_conforming_to_any_profile); + + break; + default: + sb.AppendFormat("\t" + Localization.Drive_informs_of_unknown_profile_0, (ushort)prof.Number); + + break; + } + + if(prof.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify_0001(Feature_0001? feature) + { + if(!feature.HasValue) return null; + + Feature_0001 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Core_Feature); + sb.Append("\t"); + + switch(ftr.PhysicalInterfaceStandard) + { + case PhysicalInterfaces.Unspecified: + sb.AppendLine(Localization.Drive_uses_an_unspecified_physical_interface); + + break; + case PhysicalInterfaces.SCSI: + sb.AppendLine(Localization.Drive_uses_a_SCSI_interface); + + break; + case PhysicalInterfaces.ATAPI: + sb.AppendLine(Localization.Drive_uses_an_ATAPI_interface); + + break; + case PhysicalInterfaces.IEEE1394: + sb.AppendLine(Localization.Drive_uses_an_IEEE_1394_interface); + + break; + case PhysicalInterfaces.IEEE1394A: + sb.AppendLine(Localization.Drive_uses_an_IEEE_1394A_interface); + + break; + case PhysicalInterfaces.FC: + sb.AppendLine(Localization.Drive_uses_a_Fibre_Channel_interface); + + break; + case PhysicalInterfaces.IEEE1394B: + sb.AppendLine(Localization.Drive_uses_an_IEEE_1394B_interface); + + break; + case PhysicalInterfaces.SerialATAPI: + sb.AppendLine(Localization.Drive_uses_a_Serial_ATAPI_interface); + + break; + case PhysicalInterfaces.USB: + sb.AppendLine(Localization.Drive_uses_an_USB_interface); + + break; + case PhysicalInterfaces.Vendor: + sb.AppendLine(Localization.Drive_uses_a_vendor_unique_interface); + + break; + default: + sb.AppendFormat(Localization.Drive_uses_an_unknown_interface_with_code_0, + (uint)ftr.PhysicalInterfaceStandard) + .AppendLine(); + + break; + } + + if(ftr.DBE) sb.AppendLine("\t" + Localization.Drive_supports_Device_Busy_events); + + if(ftr.INQ2) + { + sb.AppendLine("\t" + + Localization + .Drive_supports_EVPD_Page_Code_and_16_bit_Allocation_Length_as_described_in_SPC_3); + } + + return sb.ToString(); + } + + public static string Prettify_0002(Feature_0002? feature) + { + if(!feature.HasValue) return null; + + Feature_0002 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Morphing); + + sb.AppendLine(ftr.Async + ? "\t" + Localization.Drive_supports_polling_and_asynchronous_GET_EVENT_STATUS_NOTIFICATION + : "\t" + Localization.Drive_supports_only_polling_GET_EVENT_STATUS_NOTIFICATION); + + if(ftr.OCEvent) + sb.AppendLine("\t" + Localization.Drive_supports_operational_change_request_notification_class_events); + + return sb.ToString(); + } + + public static string Prettify_0003(Feature_0003? feature) + { + if(!feature.HasValue) return null; + + Feature_0003 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Features_Prettify_0003_MMC_Removable_Medium); + + switch(ftr.LoadingMechanismType) + { + case 0: + sb.AppendLine("\t" + Localization.Features_Prettify_0003_Drive_uses_media_caddy); + + break; + case 1: + sb.AppendLine("\t" + Localization.Features_Prettify_0003_Drive_uses_a_tray); + + break; + case 2: + sb.AppendLine("\t" + Localization.Features_Prettify_0003_Drive_is_pop_up); + + break; + case 4: + sb.AppendLine("\t" + + Localization + .Features_Prettify_0003_Drive_is_a_changer_with_individually_changeable_discs); + + break; + case 5: + sb.AppendLine("\t" + Localization.Features_Prettify_0003_Drive_is_a_changer_using_cartridges); + + break; + default: + sb.AppendFormat("\t" + Localization.Features_Prettify_0003_Drive_uses_unknown_loading_mechanism_type_0, + ftr.LoadingMechanismType) + .AppendLine(); + + break; + } + + if(ftr.Lock) sb.AppendLine("\t" + Localization.Features_Prettify_0003_Drive_can_lock_media); + + if(ftr.PreventJumper) sb.AppendLine("\t" + Localization.Features_Prettify_0003_Drive_power_ups_locked); + + if(ftr.Eject) sb.AppendLine("\t" + Localization.Features_Prettify_0003_Drive_can_eject_media); + + if(ftr.Load) sb.AppendLine("\t" + Localization.Features_Prettify_0003_Drive_can_load_media); + + if(ftr.DBML) + { + sb.AppendLine("\t" + + Localization + .Features_Prettify_0003_Drive_reports_Device_Busy_Class_events_during_medium_loading_unloading); + } + + return sb.ToString(); + } + + public static string Prettify_0004(Feature_0004? feature) + { + if(!feature.HasValue) return null; + + Feature_0004 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Write_Protect); + + if(ftr.DWP) + { + sb.AppendLine("\t" + + Localization.Drive_supports_reading_writing_the_Disc_Write_Protect_PAC_on_BD_R_RE_media); + } + + if(ftr.WDCB) sb.AppendLine("\t" + Localization.Drive_supports_writing_the_Write_Inhibit_DCB_on_DVD_RW_media); + + if(ftr.SPWP) sb.AppendLine("\t" + Localization.Drive_supports_set_release_of_PWP_status); + + if(ftr.SSWPP) + sb.AppendLine("\t" + Localization.Drive_supports_the_SWPP_bit_of_the_Timeout_and_Protect_mode_page); + + return sb.ToString(); + } + + public static string Prettify_0010(Feature_0010? feature) + { + if(!feature.HasValue) return null; + + Feature_0010 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.MMC_Random_Readable); + + if(ftr.Current) sb.Append(Localization.current); + + sb.AppendLine(":"); + + if(ftr.PP) sb.AppendLine("\t" + Localization.Drive_shall_report_Read_Write_Error_Recovery_mode_page); + + if(ftr.LogicalBlockSize > 0) + sb.AppendFormat("\t" + Localization._0_bytes_per_logical_block, ftr.LogicalBlockSize).AppendLine(); + + if(ftr.Blocking > 1) + sb.AppendFormat("\t" + Localization._0_logical_blocks_per_media_readable_unit, ftr.Blocking).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_001D(Feature_001D? feature) => + !feature.HasValue + ? null + : Localization.Drive_claims_capability_to_read_all_CD_formats_according_to_OSTA_Multi_Read_Specification + + "\n"; + + public static string Prettify_001E(Feature_001E? feature) + { + if(!feature.HasValue) return null; + + Feature_001E ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.MMC_CD_Read); + + if(ftr.Current) sb.Append(Localization.current); + + sb.AppendLine(":"); + + if(ftr.DAP) + sb.AppendLine("\t" + Localization.Drive_supports_the_DAP_bit_in_the_READ_CD_and_READ_CD_MSF_commands); + + if(ftr.C2) sb.AppendLine("\t" + Localization.Drive_supports_C2_Error_Pointers); + + if(ftr.CDText) sb.AppendLine("\t" + Localization.Drive_can_return_CD_Text_from_Lead_In); + + return sb.ToString(); + } + + public static string Prettify_001F(Feature_001F? feature) + { + if(!feature.HasValue) return null; + + Feature_001F ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.MMC_DVD_Read); + + if(ftr.Current) sb.Append(Localization.current); + + sb.AppendLine(":"); + sb.AppendLine("\t" + Localization.Drive_can_read_DVD_media); + + if(ftr.DualR) sb.AppendLine("\t" + Localization.Drive_can_read_DVD_R_DL_from_all_recording_modes); + + if(ftr.DualRW) sb.AppendLine("\t" + Localization.Drive_can_read_DVD_RW_DL_from_all_recording_modes); + + if(ftr.MULTI110) sb.AppendLine("\t" + Localization.Drive_conforms_to_DVD_Multi_Drive_Read_only_Specifications); + + return sb.ToString(); + } + + public static string Prettify_0020(Feature_0020? feature) + { + if(!feature.HasValue) return null; + + Feature_0020 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.MMC_Random_Writable); + + if(ftr.Current) sb.Append(Localization.current); + + sb.AppendLine(":"); + + if(ftr.PP) sb.AppendLine("\t" + Localization.Drive_shall_report_Read_Write_Error_Recovery_mode_page); + + if(ftr.LogicalBlockSize > 0) + sb.AppendFormat("\t" + Localization._0_bytes_per_logical_block, ftr.LogicalBlockSize).AppendLine(); + + if(ftr.Blocking > 1) + sb.AppendFormat("\t" + Localization._0_logical_blocks_per_media_writable_unit, ftr.Blocking).AppendLine(); + + if(ftr.LastLBA > 0) + sb.AppendFormat("\t" + Localization.Last_addressable_logical_block_is_0, ftr.LastLBA).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0021(Feature_0021? feature) + { + if(!feature.HasValue) return null; + + Feature_0021 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Incremental_Streaming_Writable); + + if(ftr.DataTypeSupported > 0) + { + sb.Append("\t" + Localization.Drive_supports_data_block_types); + + if((ftr.DataTypeSupported & 0x0001) == 0x0001) sb.Append(" 0"); + + if((ftr.DataTypeSupported & 0x0002) == 0x0002) sb.Append(" 1"); + + if((ftr.DataTypeSupported & 0x0004) == 0x0004) sb.Append(" 2"); + + if((ftr.DataTypeSupported & 0x0008) == 0x0008) sb.Append(" 3"); + + if((ftr.DataTypeSupported & 0x0010) == 0x0010) sb.Append(" 4"); + + if((ftr.DataTypeSupported & 0x0020) == 0x0020) sb.Append(" 5"); + + if((ftr.DataTypeSupported & 0x0040) == 0x0040) sb.Append(" 6"); + + if((ftr.DataTypeSupported & 0x0080) == 0x0080) sb.Append(" 7"); + + if((ftr.DataTypeSupported & 0x0100) == 0x0100) sb.Append(" 8"); + + if((ftr.DataTypeSupported & 0x0200) == 0x0200) sb.Append(" 9"); + + if((ftr.DataTypeSupported & 0x0400) == 0x0400) sb.Append(" 10"); + + if((ftr.DataTypeSupported & 0x0800) == 0x0800) sb.Append(" 11"); + + if((ftr.DataTypeSupported & 0x1000) == 0x1000) sb.Append(" 12"); + + if((ftr.DataTypeSupported & 0x2000) == 0x2000) sb.Append(" 13"); + + if((ftr.DataTypeSupported & 0x4000) == 0x4000) sb.Append(" 14"); + + if((ftr.DataTypeSupported & 0x8000) == 0x8000) sb.Append(" 15"); + + sb.AppendLine(); + } + + if(ftr.TRIO) sb.AppendLine("\t" + Localization.Drive_claims_support_to_report_Track_Resources_Information); + + if(ftr.ARSV) + sb.AppendLine("\t" + Localization.Drive_supports_address_mode_reservation_on_the_RESERVE_TRACK_command); + + if(ftr.BUF) sb.AppendLine("\t" + Localization.Drive_is_capable_of_zero_loss_linking); + + return sb.ToString(); + } + + public static string Prettify_0022(Feature_0022? feature) => + !feature.HasValue ? null : Localization.Drive_supports_media_that_require_erasing_before_writing + "\n"; + + public static string Prettify_0023(Feature_0023? feature) + { + if(!feature.HasValue) return null; + + Feature_0023 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Formattable); + sb.AppendLine("\t" + Localization.Drive_can_format_media_into_logical_blocks); + + if(ftr.RENoSA) sb.AppendLine("\t" + Localization.Drive_can_format_BD_RE_with_no_spares_allocated); + + if(ftr.Expand) sb.AppendLine("\t" + Localization.Drive_can_expand_the_spare_area_on_a_formatted_BD_RE_disc); + + if(ftr.QCert) sb.AppendLine("\t" + Localization.Drive_can_format_BD_RE_discs_with_quick_certification); + + if(ftr.Cert) sb.AppendLine("\t" + Localization.Drive_can_format_BD_RE_discs_with_full_certification); + + if(ftr.FRF) sb.AppendLine("\t" + Localization.Drive_can_fast_re_format_BD_RE_discs); + + if(ftr.RRM) sb.AppendLine("\t" + Localization.Drive_can_format_BD_R_discs_with_RRM_format); + + return sb.ToString(); + } + + public static string Prettify_0024(Feature_0024? feature) + { + if(!feature.HasValue) return null; + + Feature_0024 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Hardware_Defect_Management); + sb.AppendLine("\t" + Localization.Drive_shall_be_able_to_provide_a_defect_free_contiguous_address_space); + + if(ftr.SSA) sb.AppendLine("\t" + Localization.Drive_can_return_Spare_Area_Information); + + return sb.ToString(); + } + + public static string Prettify_0025(Feature_0025? feature) + { + if(!feature.HasValue) return null; + + Feature_0025 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.MMC_Write_Once); + + if(ftr.Current) sb.Append(Localization.current); + + sb.AppendLine(":"); + + if(ftr.PP) sb.AppendLine("\t" + Localization.Drive_shall_report_Read_Write_Error_Recovery_mode_page); + + if(ftr.LogicalBlockSize > 0) + sb.AppendFormat("\t" + Localization._0_bytes_per_logical_block, ftr.LogicalBlockSize).AppendLine(); + + if(ftr.Blocking > 1) + sb.AppendFormat("\t" + Localization._0_logical_blocks_per_media_writable_unit, ftr.Blocking).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0026(Feature_0026? feature) => + !feature.HasValue + ? null + : Localization.Drive_shall_have_the_ability_to_overwrite_logical_blocks_only_in_fixed_sets_at_a_time + "\n"; + + public static string Prettify_0027(Feature_0027? feature) + { + if(!feature.HasValue) return null; + + Feature_0027 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.Drive_can_write_High_Speed_CD_RW); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0028(Feature_0028? feature) + { + if(!feature.HasValue) return null; + + Feature_0028 ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Write && ftr is { DVDPRead: true, DVDPWrite: true }) + sb.Append(Localization.Drive_can_read_and_write_CD_MRW_and_DVD_MRW); + else if(ftr is { DVDPRead: true, DVDPWrite: true }) + sb.Append(Localization.Drive_can_read_and_write_DVD_MRW); + else + { + switch(ftr.Write) + { + case true when ftr.DVDPRead: + sb.Append(Localization.Drive_and_read_DVD_MRW_and_read_and_write_CD_MRW); + + break; + case true: + sb.Append(Localization.Drive_can_read_and_write_CD_MRW); + + break; + default: + { + sb.Append(ftr.DVDPRead + ? Localization.Drive_can_read_CD_MRW_and_DVD_MRW + : Localization.Drive_can_read_CD_MRW); + + break; + } + } + } + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0029(Feature_0029? feature) + { + if(!feature.HasValue) return null; + + Feature_0029 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Enhanced_Defect_Reporting_Feature); + + sb.AppendLine(ftr.DRTDM + ? "\t" + Localization.Drive_supports_DRT_DM_mode + : "\t" + Localization.Drive_supports_Persistent_DM_mode); + + if(ftr.DBICacheZones > 0) + sb.AppendFormat("\t" + Localization.Drive_has_0_DBI_cache_zones, ftr.DBICacheZones).AppendLine(); + + if(ftr.Entries > 0) sb.AppendFormat("\t" + Localization.Drive_has_0_DBI_entries, ftr.Entries).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_002A(Feature_002A? feature) + { + if(!feature.HasValue) return null; + + Feature_002A ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Write) + { + sb.Append(Localization.Drive_can_read_and_write_DVD_RW); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + + sb.AppendLine(ftr.CloseOnly + ? "\t" + Localization.Drive_supports_only_the_read_compatibility_stop + : "\t" + Localization.Drive_supports_both_forms_of_background_format_stopping); + + if(ftr.QuickStart) sb.AppendLine("\t" + Localization.Drive_can_do_a_quick_start_formatting); + } + else + { + sb.Append(Localization.Drive_can_read_DVD_Plus_RW); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify_002B(Feature_002B? feature) + { + if(!feature.HasValue) return null; + + Feature_002B ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Write) + { + sb.Append(Localization.Drive_can_read_and_write_DVD_Plus_R); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + } + else + { + sb.Append(Localization.Drive_can_read_DVD_Plus_R); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify_002C(Feature_002C? feature) + { + if(!feature.HasValue) return null; + + Feature_002C ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.MMC_Rigid_Restricted_Overwrite); + sb.AppendLine(ftr.Current ? $"{Localization.current}:" : ":"); + + if(ftr.Blank) sb.AppendLine("\t" + Localization.Drive_supports_the_BLANK_command); + + if(ftr.Intermediate) + { + sb.AppendLine("\t" + + Localization.Drive_supports_writing_on_an_intermediate_state_session_and_quick_formatting); + } + + if(ftr.DSDR) sb.AppendLine("\t" + Localization.Drive_can_read_Defect_Status_data_recorded_on_the_medium); + + if(ftr.DSDG) sb.AppendLine("\t" + Localization.Drive_can_generate_Defect_Status_data_during_formatting); + + return sb.ToString(); + } + + public static string Prettify_002D(Feature_002D? feature) + { + if(!feature.HasValue) return null; + + Feature_002D ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Drive_can_write_CDs_in_Track_at_Once_Mode); + + if(ftr.RWSubchannel) + { + sb.AppendLine("\t" + Localization.Drive_can_write_user_provided_data_in_the_R_W_subchannels); + + if(ftr.RWRaw) sb.AppendLine("\t" + Localization.Drive_accepts_RAW_R_W_subchannel_data); + + if(ftr.RWPack) sb.AppendLine("\t" + Localization.Drive_accepts_Packed_R_W_subchannel_data); + } + + if(ftr.CDRW) sb.AppendLine("\t" + Localization.Drive_can_overwrite_a_TAO_track_with_another_in_CD_RWs); + + if(ftr.TestWrite) sb.AppendLine("\t" + Localization.Drive_can_do_a_test_writing); + + if(ftr.BUF) sb.AppendLine("\t" + Localization.Drive_supports_zero_loss_linking); + + if(ftr.DataTypeSupported <= 0) return sb.ToString(); + + sb.Append("\t" + Localization.Drive_supports_data_block_types); + + if((ftr.DataTypeSupported & 0x0001) == 0x0001) sb.Append(" 0"); + + if((ftr.DataTypeSupported & 0x0002) == 0x0002) sb.Append(" 1"); + + if((ftr.DataTypeSupported & 0x0004) == 0x0004) sb.Append(" 2"); + + if((ftr.DataTypeSupported & 0x0008) == 0x0008) sb.Append(" 3"); + + if((ftr.DataTypeSupported & 0x0010) == 0x0010) sb.Append(" 4"); + + if((ftr.DataTypeSupported & 0x0020) == 0x0020) sb.Append(" 5"); + + if((ftr.DataTypeSupported & 0x0040) == 0x0040) sb.Append(" 6"); + + if((ftr.DataTypeSupported & 0x0080) == 0x0080) sb.Append(" 7"); + + if((ftr.DataTypeSupported & 0x0100) == 0x0100) sb.Append(" 8"); + + if((ftr.DataTypeSupported & 0x0200) == 0x0200) sb.Append(" 9"); + + if((ftr.DataTypeSupported & 0x0400) == 0x0400) sb.Append(" 10"); + + if((ftr.DataTypeSupported & 0x0800) == 0x0800) sb.Append(" 11"); + + if((ftr.DataTypeSupported & 0x1000) == 0x1000) sb.Append(" 12"); + + if((ftr.DataTypeSupported & 0x2000) == 0x2000) sb.Append(" 13"); + + if((ftr.DataTypeSupported & 0x4000) == 0x4000) sb.Append(" 14"); + + if((ftr.DataTypeSupported & 0x8000) == 0x8000) sb.Append(" 15"); + + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_002E(Feature_002E? feature) + { + if(!feature.HasValue) return null; + + Feature_002E ftr = feature.Value; + var sb = new StringBuilder(); + + switch(ftr.SAO) + { + case true when !ftr.RAW: + sb.AppendLine(Localization.Drive_can_write_CDs_in_Session_at_Once_Mode); + + break; + case false when ftr.RAW: + sb.AppendLine(Localization.Drive_can_write_CDs_in_raw_Mode); + + break; + default: + sb.AppendLine(Localization.Drive_can_write_CDs_in_Session_at_Once_and_in_Raw_Modes); + + break; + } + + if(ftr is { RAW: true, RAWMS: true }) + sb.AppendLine("\t" + Localization.Drive_can_write_multi_session_CDs_in_raw_mode); + + if(ftr.RW) sb.AppendLine("\t" + Localization.Drive_can_write_user_provided_data_in_the_R_W_subchannels); + + if(ftr.CDRW) sb.AppendLine("\t" + Localization.Drive_can_write_CD_RW); + + if(ftr.TestWrite) sb.AppendLine("\t" + Localization.Drive_can_do_a_test_writing); + + if(ftr.BUF) sb.AppendLine("\t" + Localization.Drive_supports_zero_loss_linking); + + if(ftr.MaxCueSheet > 0) + { + sb.AppendFormat("\t" + Localization.Drive_supports_a_maximum_of_0_bytes_in_a_single_cue_sheet, + ftr.MaxCueSheet) + .AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify_002F(Feature_002F? feature) + { + if(!feature.HasValue) return null; + + Feature_002F ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr is { DVDRW: true, RDL: true }) + sb.AppendLine(Localization.Drive_supports_writing_DVD_R_DVD_RW_and_DVD_R_DL); + else if(ftr.RDL) + sb.AppendLine(Localization.Drive_supports_writing_DVD_R_and_DVD_R_DL); + else if(ftr.DVDRW) + sb.AppendLine(Localization.Drive_supports_writing_DVD_R_and_DVD_RW); + else + sb.AppendLine(Localization.Drive_supports_writing_DVD_R); + + if(ftr.TestWrite) sb.AppendLine("\t" + Localization.Drive_can_do_a_test_writing); + + if(ftr.BUF) sb.AppendLine("\t" + Localization.Drive_supports_zero_loss_linking); + + return sb.ToString(); + } + + public static string Prettify_0030(Feature_0030? feature) => + !feature.HasValue ? null : Localization.Drive_can_read_DDCDs + "\n"; + + public static string Prettify_0031(Feature_0031? feature) + { + if(!feature.HasValue) return null; + + Feature_0031 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Drive_supports_writing_DDCD_R); + + if(ftr.TestWrite) sb.AppendLine("\t" + Localization.Drive_can_do_a_test_writing); + + return sb.ToString(); + } + + public static string Prettify_0032(Feature_0032? feature) + { + if(!feature.HasValue) return null; + + Feature_0032 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Drive_supports_writing_DDCD_RW); + + if(ftr.Blank) sb.AppendLine("\t" + Localization.Drive_supports_the_BLANK_command); + + if(ftr.Intermediate) sb.AppendLine("\t" + Localization.Drive_supports_quick_formatting); + + return sb.ToString(); + } + + public static string Prettify_0033(Feature_0033? feature) + { + if(!feature.HasValue) return null; + + Feature_0033 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Layer_Jump_Recording); + + if(ftr.LinkSizes == null) return sb.ToString(); + + foreach(byte link in ftr.LinkSizes) + sb.AppendFormat("\t" + Localization.Current_media_has_a_0_bytes_link_available, link).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0035(Feature_0035? feature) => + !feature.HasValue ? null : Localization.Drive_can_stop_a_long_immediate_operation + "\n"; + + public static string Prettify_0037(Feature_0037? feature) + { + if(!feature.HasValue) return null; + + Feature_0037 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Drive_can_write_CD_RW); + + if(ftr.SubtypeSupport <= 0) return sb.ToString(); + + sb.Append("\t" + Localization.Drive_supports_CD_RW_subtypes); + + if((ftr.SubtypeSupport & 0x01) == 0x01) sb.Append(" 0"); + + if((ftr.SubtypeSupport & 0x02) == 0x02) sb.Append(" 1"); + + if((ftr.SubtypeSupport & 0x04) == 0x04) sb.Append(" 2"); + + if((ftr.SubtypeSupport & 0x08) == 0x08) sb.Append(" 3"); + + if((ftr.SubtypeSupport & 0x10) == 0x10) sb.Append(" 4"); + + if((ftr.SubtypeSupport & 0x20) == 0x20) sb.Append(" 5"); + + if((ftr.SubtypeSupport & 0x40) == 0x40) sb.Append(" 6"); + + if((ftr.SubtypeSupport & 0x80) == 0x80) sb.Append(" 7"); + + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0038(Feature_0038? feature) => + !feature.HasValue ? null : Localization.Drive_can_write_BD_R_on_Pseudo_OVerwrite_SRM_mode + "\n"; + + public static string Prettify_003A(Feature_003A? feature) + { + if(!feature.HasValue) return null; + + Feature_003A ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Write) + { + sb.Append(Localization.Drive_can_read_and_write_DVD_Plus_RW_DL); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + + sb.AppendLine(ftr.CloseOnly + ? "\t" + Localization.Drive_supports_only_the_read_compatibility_stop + : "\t" + Localization.Drive_supports_both_forms_of_background_format_stopping); + + if(ftr.QuickStart) sb.AppendLine("\t" + Localization.Drive_can_do_a_quick_start_formatting); + } + else + { + sb.Append(Localization.Drive_can_read_DVD_Plus_RW_DL); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify_003B(Feature_003B? feature) + { + if(!feature.HasValue) return null; + + Feature_003B ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Write) + { + sb.Append(Localization.Drive_can_read_and_write_DVD_Plus_R_DL); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + } + else + { + sb.Append(Localization.Features_Prettify_003B_Drive_can_read_DVD_Plus_R_DL); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify_0040(Feature_0040? feature) + { + if(!feature.HasValue) return null; + + Feature_0040 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.MMC_BD_Read); + sb.AppendLine(ftr.Current ? $"{Localization.current}:" : ":"); + + if(ftr.OldROM) sb.AppendLine("\t" + Localization.Drive_can_read_BD_ROM_pre_1_0); + + if(ftr.ROM) sb.AppendLine("\t" + Localization.Drive_can_read_BD_ROM_Ver_1); + + if(ftr.OldR) sb.AppendLine("\t" + Localization.Drive_can_read_BD_R_pre_1_0); + + if(ftr.R) sb.AppendLine("\t" + Localization.Drive_can_read_BD_R_Ver_1); + + if(ftr.OldRE) sb.AppendLine("\t" + Localization.Drive_can_read_BD_RE_pre_1_0); + + if(ftr.RE1) sb.AppendLine("\t" + Localization.Drive_can_read_BD_RE_Ver_1); + + if(ftr.RE2) sb.AppendLine("\t" + Localization.Drive_can_read_BD_RE_Ver_2); + + if(ftr.BCA) sb.AppendLine("\t" + Localization.Drive_can_read_BDs_Burst_Cutting_Area); + + return sb.ToString(); + } + + public static string Prettify_0041(Feature_0041? feature) + { + if(!feature.HasValue) return null; + + Feature_0041 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.MMC_BD_Write); + sb.AppendLine(ftr.Current ? $"{Localization.current}:" : ":"); + + if(ftr.OldR) sb.AppendLine("\t" + Localization.Drive_can_write_BD_R_pre_1_0); + + if(ftr.R) sb.AppendLine("\t" + Localization.Drive_can_write_BD_R_Ver_1); + + if(ftr.OldRE) sb.AppendLine("\t" + Localization.Drive_can_write_BD_RE_pre_1_0); + + if(ftr.RE1) sb.AppendLine("\t" + Localization.Drive_can_write_BD_RE_Ver_1); + + if(ftr.RE2) sb.AppendLine("\t" + Localization.Drive_can_write_BD_RE_Ver_2); + + if(ftr.SVNR) sb.AppendLine("\t" + Localization.Drive_supports_write_without_verify_requirement); + + return sb.ToString(); + } + + public static string Prettify_0042(Feature_0042? feature) => + !feature.HasValue + ? null + : Localization + .Features_Prettify_0042_Drive_is_able_to_detect_and_report_defective_writable_unit_and_behave_accordingly + + "\n"; + + public static string Prettify_0050(Feature_0050? feature) + { + if(!feature.HasValue) return null; + + Feature_0050 ftr = feature.Value; + var sb = new StringBuilder(); + + switch(ftr.HDDVDR) + { + case true when ftr.HDDVDRAM: + sb.Append(Localization.Drive_can_read_HD_DVD_ROM_HD_DVD_RW_HD_DVD_R_and_HD_DVD_RAM); + + break; + case true: + sb.Append(Localization.Drive_can_read_HD_DVD_ROM_HD_DVD_RW_and_HD_DVD_R); + + break; + default: + { + sb.Append(ftr.HDDVDRAM + ? Localization.Drive_can_read_HD_DVD_ROM_HD_DVD_RW_and_HD_DVD_RAM + : Localization.Drive_can_read_HD_DVD_ROM_and_HD_DVD_RW); + + break; + } + } + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0051(Feature_0051? feature) + { + if(!feature.HasValue) return null; + + Feature_0051 ftr = feature.Value; + var sb = new StringBuilder(); + + switch(ftr.HDDVDR) + { + case true when ftr.HDDVDRAM: + sb.Append(Localization.Drive_can_write_HD_DVD_RW_HD_DVD_R_and_HD_DVD_RAM); + + break; + case true: + sb.Append(Localization.Drive_can_write_HD_DVD_RW_and_HD_DVD_R); + + break; + default: + { + sb.Append(ftr.HDDVDRAM + ? Localization.Drive_can_write_HD_DVD_RW_and_HD_DVD_RAM + : Localization.Drive_can_write_HD_DVD_RW); + + break; + } + } + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0080(Feature_0080? feature) + { + if(!feature.HasValue) return null; + + Feature_0080 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.Drive_is_able_to_access_Hybrid_discs); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + + if(ftr.RI) + { + sb.AppendLine("\t" + + Localization + .Drive_is_able_to_maintain_the_online_format_layer_through_reset_and_power_cycling); + } + + return sb.ToString(); + } + + public static string Prettify_0100(Feature_0100? feature) => + !feature.HasValue + ? null + : Localization.Drive_is_able_to_perform_host_and_drive_directed_power_management + "\n"; + + public static string Prettify_0101(Feature_0101? feature) + { + if(!feature.HasValue) return null; + + Feature_0101 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Drive_supports_SMART); + + if(ftr.PP) sb.AppendLine("\t" + Localization.Drive_supports_the_Informational_Exceptions_Control_mode_page_1Ch); + + return sb.ToString(); + } + + public static string Prettify_0102(Feature_0102? feature) + { + if(!feature.HasValue) return null; + + Feature_0102 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Embedded_Changer); + + if(ftr.SCC) sb.AppendLine("\t" + Localization.Drive_can_change_disc_side); + + if(ftr.SDP) sb.AppendLine("\t" + Localization.Drive_is_able_to_report_slots_contents_after_a_reset_or_change); + + sb.AppendFormat("\t" + Localization.Drive_has_0_slots, ftr.HighestSlotNumber + 1).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0103(Feature_0103? feature) + { + if(!feature.HasValue) return null; + + Feature_0103 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Drive_has_an_analogue_audio_output); + + if(ftr.Scan) sb.AppendLine("\t" + Localization.Drive_supports_the_SCAN_command); + + if(ftr.SCM) sb.AppendLine("\t" + Localization.Drive_is_able_to_mute_channels_separately); + + if(ftr.SV) sb.AppendLine("\t" + Localization.Drive_supports_separate_volume_per_channel); + + sb.AppendFormat("\t" + Localization.Drive_has_0_volume_levels, ftr.VolumeLevels + 1).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0104(Feature_0104? feature) + { + if(!feature.HasValue) return null; + + Feature_0104 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Drive_supports_Microcode_Upgrade); + + if(ftr.M5) + { + sb.AppendLine(Localization + .Drive_supports_validating_the_5_bit_Mode_of_the_READ_BUFFER_and_WRITE_BUFFER_commands); + } + + return sb.ToString(); + } + + public static string Prettify_0105(Feature_0105? feature) + { + if(!feature.HasValue) return null; + + Feature_0105 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Drive_supports_Timeout_Protect_mode_page_1Dh); + + if(!ftr.Group3) return sb.ToString(); + + sb.AppendLine("\t" + Localization.Drive_supports_the_Group3_in_Timeout_Protect_mode_page_1Dh); + + if(ftr.UnitLength > 0) + sb.AppendFormat("\t" + Localization.Drive_has_0_increase_of_Group_3_time_unit, ftr.UnitLength).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0106(Feature_0106? feature) + { + if(!feature.HasValue) return null; + + Feature_0106 ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Current) + { + sb.AppendFormat(Localization.Drive_supports_DVD_CSS_CPPM_version_0_and_current_disc_is_encrypted, + ftr.CSSVersion) + .AppendLine(); + } + else + sb.AppendFormat(Localization.Drive_supports_DVD_CSS_CPPM_version_0, ftr.CSSVersion).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0107(Feature_0107? feature) + { + if(!feature.HasValue) return null; + + Feature_0107 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.MMC_Real_Time_Streaming_); + + if(ftr.SMP) + sb.AppendLine("\t" + Localization.Drive_supports_Set_Minimum_Performance_with_the_SET_STREAMING_command); + + if(ftr.RBCB) + sb.AppendLine("\t" + Localization.Drive_supports_the_block_bit_in_the_READ_BUFFER_CAPACITY_command); + + if(ftr.SCS) sb.AppendLine("\t" + Localization.Drive_supports_the_SET_CD_SPEED_command); + + if(ftr.MP2A) + { + sb.AppendLine("\t" + + Localization + .Drive_supports_the_Write_Speed_Performance_Descriptor_Blocks_in_the_MMC_mode_page_2Ah); + } + + if(ftr.WSPD) + { + sb.AppendLine("\t" + + Localization + .Drive_supports_the_Write_Speed_data_of_GET_PERFORMANCE_and_the_WRC_field_of_SET_STREAMING); + } + + if(ftr.SW) sb.AppendLine("\t" + Localization.Drive_supports_stream_recording); + + return sb.ToString(); + } + + public static string Prettify_0108(Feature_0108? feature) + { + if(!feature.HasValue) return null; + + Feature_0108 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendFormat(Core.Drive_serial_number_0, ftr.Serial).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0109(Feature_0109? feature) => + !feature.HasValue ? null : Localization.Drive_is_able_to_read_media_serial_number + "\n"; + + public static string Prettify_010A(Feature_010A? feature) + { + if(!feature.HasValue) return null; + + Feature_010A ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.DCBs == null) return sb.ToString(); + + foreach(uint dcb in ftr.DCBs) sb.AppendFormat(Localization.Drive_supports_DCB_0, dcb).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_010B(Feature_010B? feature) + { + if(!feature.HasValue) return null; + + Feature_010B ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Current) + { + sb.AppendFormat(Localization.Drive_supports_DVD_CPRM_version_0_and_current_disc_is_or_can_be_encrypted, + ftr.CPRMVersion) + .AppendLine(); + } + else + sb.AppendFormat(Localization.Drive_supports_DVD_CPRM_version_0, ftr.CPRMVersion).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_010C(Feature_010C? feature) + { + if(!feature.HasValue) return null; + + Feature_010C ftr = feature.Value; + var sb = new StringBuilder(); + + var temp = new byte[4]; + temp[0] = (byte)((ftr.Century & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Century & 0xFF); + temp[2] = (byte)((ftr.Year & 0xFF00) >> 8); + temp[3] = (byte)(ftr.Year & 0xFF); + string syear = Encoding.ASCII.GetString(temp); + temp = new byte[2]; + temp[0] = (byte)((ftr.Month & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Month & 0xFF); + string smonth = Encoding.ASCII.GetString(temp); + temp = new byte[2]; + temp[0] = (byte)((ftr.Day & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Day & 0xFF); + string sday = Encoding.ASCII.GetString(temp); + temp = new byte[2]; + temp[0] = (byte)((ftr.Hour & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Hour & 0xFF); + string shour = Encoding.ASCII.GetString(temp); + temp = new byte[2]; + temp[0] = (byte)((ftr.Minute & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Minute & 0xFF); + string sminute = Encoding.ASCII.GetString(temp); + temp = new byte[2]; + temp[0] = (byte)((ftr.Second & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Second & 0xFF); + string ssecond = Encoding.ASCII.GetString(temp); + + try + { + var fwDate = new DateTime(int.Parse(syear), + int.Parse(smonth), + int.Parse(sday), + int.Parse(shour), + int.Parse(sminute), + int.Parse(ssecond), + DateTimeKind.Utc); + + sb.AppendFormat(Localization.Drive_firmware_is_dated_0, fwDate).AppendLine(); + } +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body + catch + { + // ignored + } +#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body + + return sb.ToString(); + } + + public static string Prettify_010D(Feature_010D? feature) + { + if(!feature.HasValue) return null; + + Feature_010D ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Current) + { + sb.AppendFormat(Localization.Drive_supports_AACS_version_0_and_current_disc_is_encrypted, ftr.AACSVersion) + .AppendLine(); + } + else + sb.AppendFormat(Localization.Drive_supports_AACS_version_0, ftr.AACSVersion).AppendLine(); + + if(ftr.RDC) sb.AppendLine("\t" + Localization.Drive_supports_reading_the_Drive_Certificate); + + if(ftr.RMC) sb.AppendLine("\t" + Localization.Drive_supports_reading_Media_Key_Block_of_CPRM); + + if(ftr.WBE) sb.AppendLine("\t" + Localization.Drive_supports_writing_with_bus_encryption); + + if(ftr.BEC) sb.AppendLine("\t" + Localization.Drive_supports_bus_encryption); + + if(ftr.BNG) + { + sb.AppendLine("\t" + Localization.Drive_supports_generating_the_binding_nonce); + + if(ftr.BindNonceBlocks > 0) + { + sb.AppendFormat("\t" + Localization._0_media_blocks_are_required_for_the_binding_nonce, + ftr.BindNonceBlocks) + .AppendLine(); + } + } + + if(ftr.AGIDs > 0) + sb.AppendFormat("\t" + Localization.Drive_supports_0_AGIDs_concurrently, ftr.AGIDs).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_010E(Feature_010E? feature) + { + if(!feature.HasValue) return null; + + Feature_010E ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.Drive_supports_DVD_Download); + + if(ftr.Current) + sb.AppendLine(Localization.current); + else + sb.AppendLine(); + + if(ftr.MaxScrambleExtent > 0) + { + sb.AppendFormat("\t" + Localization.Maximum_0_scramble_extent_information_entries, ftr.MaxScrambleExtent) + .AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify_0110(Feature_0110? feature) + { + if(!feature.HasValue) return null; + + Feature_0110 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(ftr.Current + ? Localization.Drive_and_currently_inserted_media_support_VCPS + : Localization.Drive_supports_VCPS); + + return sb.ToString(); + } + + public static string Prettify_0113(Feature_0113? feature) + { + if(!feature.HasValue) return null; + + Feature_0113 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(ftr.Current + ? Localization.Drive_and_currently_inserted_media_support_SecurDisc + : Localization.Drive_supports_SecurDisc); + + return sb.ToString(); + } + + public static string Prettify_0142(Feature_0142? feature) + { + if(!feature.HasValue) return null; + + Feature_0142 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Drive_supports_the_Trusted_Computing_Group_Optical_Security_Subsystem_Class); + + if(ftr.Current) sb.AppendLine("\t" + Localization.Current_media_is_initialized_with_TCG_OSSC); + + if(ftr.PSAU) sb.AppendLine("\t" + Localization.Drive_supports_PSA_updates_on_write_once_media); + + if(ftr.LOSPB) sb.AppendLine("\t" + Localization.Drive_supports_linked_OSPBs); + + if(ftr.ME) sb.AppendLine("\t" + Localization.Drive_will_only_record_on_the_OSSC_Disc_Format); + + if(ftr.Profiles == null) return sb.ToString(); + + for(var i = 0; i < ftr.Profiles.Length; i++) + sb.AppendFormat("\t" + Localization.Profile_0_1, i, ftr.Profiles[i]).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0000(byte[] feature) => Prettify_0000(Decode_0000(feature)); + + public static string Prettify_0001(byte[] feature) => Prettify_0001(Decode_0001(feature)); + + public static string Prettify_0002(byte[] feature) => Prettify_0002(Decode_0002(feature)); + + public static string Prettify_0003(byte[] feature) => Prettify_0003(Decode_0003(feature)); + + public static string Prettify_0004(byte[] feature) => Prettify_0004(Decode_0004(feature)); + + public static string Prettify_0010(byte[] feature) => Prettify_0010(Decode_0010(feature)); + + public static string Prettify_001D(byte[] feature) => Prettify_001D(Decode_001D(feature)); + + public static string Prettify_001E(byte[] feature) => Prettify_001E(Decode_001E(feature)); + + public static string Prettify_001F(byte[] feature) => Prettify_001F(Decode_001F(feature)); + + public static string Prettify_0020(byte[] feature) => Prettify_0020(Decode_0020(feature)); + + public static string Prettify_0021(byte[] feature) => Prettify_0021(Decode_0021(feature)); + + public static string Prettify_0022(byte[] feature) => Prettify_0022(Decode_0022(feature)); + + public static string Prettify_0023(byte[] feature) => Prettify_0023(Decode_0023(feature)); + + public static string Prettify_0024(byte[] feature) => Prettify_0024(Decode_0024(feature)); + + public static string Prettify_0025(byte[] feature) => Prettify_0025(Decode_0025(feature)); + + public static string Prettify_0026(byte[] feature) => Prettify_0026(Decode_0026(feature)); + + public static string Prettify_0027(byte[] feature) => Prettify_0027(Decode_0027(feature)); + + public static string Prettify_0028(byte[] feature) => Prettify_0028(Decode_0028(feature)); + + public static string Prettify_0029(byte[] feature) => Prettify_0029(Decode_0029(feature)); + + public static string Prettify_002A(byte[] feature) => Prettify_002A(Decode_002A(feature)); + + public static string Prettify_002B(byte[] feature) => Prettify_002B(Decode_002B(feature)); + + public static string Prettify_002C(byte[] feature) => Prettify_002C(Decode_002C(feature)); + + public static string Prettify_002D(byte[] feature) => Prettify_002D(Decode_002D(feature)); + + public static string Prettify_002E(byte[] feature) => Prettify_002E(Decode_002E(feature)); + + public static string Prettify_002F(byte[] feature) => Prettify_002F(Decode_002F(feature)); + + public static string Prettify_0030(byte[] feature) => Prettify_0030(Decode_0030(feature)); + + public static string Prettify_0031(byte[] feature) => Prettify_0031(Decode_0031(feature)); + + public static string Prettify_0032(byte[] feature) => Prettify_0032(Decode_0032(feature)); + + public static string Prettify_0033(byte[] feature) => Prettify_0033(Decode_0033(feature)); + + public static string Prettify_0035(byte[] feature) => Prettify_0035(Decode_0035(feature)); + + public static string Prettify_0037(byte[] feature) => Prettify_0037(Decode_0037(feature)); + + public static string Prettify_0038(byte[] feature) => Prettify_0038(Decode_0038(feature)); + + public static string Prettify_003A(byte[] feature) => Prettify_003A(Decode_003A(feature)); + + public static string Prettify_003B(byte[] feature) => Prettify_003B(Decode_003B(feature)); + + public static string Prettify_0040(byte[] feature) => Prettify_0040(Decode_0040(feature)); + + public static string Prettify_0041(byte[] feature) => Prettify_0041(Decode_0041(feature)); + + public static string Prettify_0042(byte[] feature) => Prettify_0042(Decode_0042(feature)); + + public static string Prettify_0050(byte[] feature) => Prettify_0050(Decode_0050(feature)); + + public static string Prettify_0051(byte[] feature) => Prettify_0051(Decode_0051(feature)); + + public static string Prettify_0080(byte[] feature) => Prettify_0080(Decode_0080(feature)); + + public static string Prettify_0100(byte[] feature) => Prettify_0100(Decode_0100(feature)); + + public static string Prettify_0101(byte[] feature) => Prettify_0101(Decode_0101(feature)); + + public static string Prettify_0102(byte[] feature) => Prettify_0102(Decode_0102(feature)); + + public static string Prettify_0103(byte[] feature) => Prettify_0103(Decode_0103(feature)); + + public static string Prettify_0104(byte[] feature) => Prettify_0104(Decode_0104(feature)); + + public static string Prettify_0105(byte[] feature) => Prettify_0105(Decode_0105(feature)); + + public static string Prettify_0106(byte[] feature) => Prettify_0106(Decode_0106(feature)); + + public static string Prettify_0107(byte[] feature) => Prettify_0107(Decode_0107(feature)); + + public static string Prettify_0108(byte[] feature) => Prettify_0108(Decode_0108(feature)); + + public static string Prettify_0109(byte[] feature) => Prettify_0109(Decode_0109(feature)); + + public static string Prettify_010A(byte[] feature) => Prettify_010A(Decode_010A(feature)); + + public static string Prettify_010B(byte[] feature) => Prettify_010B(Decode_010B(feature)); + + public static string Prettify_010C(byte[] feature) => Prettify_010C(Decode_010C(feature)); + + public static string Prettify_010D(byte[] feature) => Prettify_010D(Decode_010D(feature)); + + public static string Prettify_010E(byte[] feature) => Prettify_010E(Decode_010E(feature)); + + public static string Prettify_0110(byte[] feature) => Prettify_0110(Decode_0110(feature)); + + public static string Prettify_0113(byte[] feature) => Prettify_0113(Decode_0113(feature)); + + public static string Prettify_0142(byte[] feature) => Prettify_0142(Decode_0142(feature)); + + public static SeparatedFeatures Separate(byte[] response) + { + var dec = new SeparatedFeatures + { + DataLength = (uint)((response[0] << 24) + (response[1] << 16) + (response[2] << 8) + response[4]), + CurrentProfile = (ushort)((response[6] << 8) + response[7]) + }; + + uint offset = 8; + List descLst = []; + + while(offset + 4 < response.Length) + { + var desc = new FeatureDescriptor + { + Code = (ushort)((response[offset + 0] << 8) + response[offset + 1]), + Data = new byte[response[offset + 3] + 4] + }; + + if(desc.Data.Length + offset > response.Length) desc.Data = new byte[response.Length - offset]; + + Array.Copy(response, offset, desc.Data, 0, desc.Data.Length); + offset += (uint)desc.Data.Length; + + descLst.Add(desc); + } + + dec.Descriptors = descLst.ToArray(); + + return dec; + } + +#region Nested type: FeatureDescriptor + + public struct FeatureDescriptor + { + public ushort Code; + public byte[] Data; + } + +#endregion + +#region Nested type: SeparatedFeatures + + public struct SeparatedFeatures + { + public uint DataLength; + public ushort CurrentProfile; + public FeatureDescriptor[] Descriptors; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/MMC/Hybrid.cs b/Aaru.Decoders/SCSI/MMC/Hybrid.cs new file mode 100644 index 000000000..0df2a105e --- /dev/null +++ b/Aaru.Decoders/SCSI/MMC/Hybrid.cs @@ -0,0 +1,192 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Hybrid.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MMC hybrid structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.SCSI.MMC; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] +public static class Hybrid +{ + public static RecognizedFormatLayers? DecodeFormatLayers(byte[] FormatLayersResponse) + { + if(FormatLayersResponse == null) return null; + + if(FormatLayersResponse.Length < 8) return null; + + var decoded = new RecognizedFormatLayers + { + DataLength = BigEndianBitConverter.ToUInt16(FormatLayersResponse, 0), + Reserved1 = FormatLayersResponse[2], + Reserved2 = FormatLayersResponse[3], + NumberOfLayers = FormatLayersResponse[4], + Reserved3 = (byte)((FormatLayersResponse[5] & 0xC0) >> 6), + DefaultFormatLayer = (byte)((FormatLayersResponse[5] & 0x30) >> 4), + Reserved4 = (byte)((FormatLayersResponse[5] & 0x0C) >> 2), + OnlineFormatLayer = (byte)(FormatLayersResponse[5] & 0x03), + FormatLayers = new ushort[(FormatLayersResponse.Length - 6) / 2] + }; + + for(var i = 0; i < (FormatLayersResponse.Length - 6) / 2; i++) + decoded.FormatLayers[i] = BigEndianBitConverter.ToUInt16(FormatLayersResponse, i * 2 + 6); + + return decoded; + } + + public static string PrettifyFormatLayers(RecognizedFormatLayers? FormatLayersResponse) + { + if(FormatLayersResponse == null) return null; + + RecognizedFormatLayers response = FormatLayersResponse.Value; + + var sb = new StringBuilder(); + + sb.AppendFormat(Localization._0_format_layers_recognized, response.NumberOfLayers); + + for(var i = 0; i < response.FormatLayers.Length; i++) + { + switch(response.FormatLayers[i]) + { + case (ushort)FormatLayerTypeCodes.BDLayer: + { + sb.AppendFormat(Localization.Layer_0_is_of_type_Blu_ray, i).AppendLine(); + + if(response.DefaultFormatLayer == i) sb.AppendLine(Localization.This_is_the_default_layer); + + if(response.OnlineFormatLayer == i) sb.AppendLine(Localization.This_is_the_layer_actually_in_use); + + break; + } + + case (ushort)FormatLayerTypeCodes.CDLayer: + { + sb.AppendFormat(Localization.Layer_0_is_of_type_CD, i).AppendLine(); + + if(response.DefaultFormatLayer == i) sb.AppendLine(Localization.This_is_the_default_layer); + + if(response.OnlineFormatLayer == i) sb.AppendLine(Localization.This_is_the_layer_actually_in_use); + + break; + } + + case (ushort)FormatLayerTypeCodes.DVDLayer: + { + sb.AppendFormat(Localization.Layer_0_is_of_type_DVD, i).AppendLine(); + + if(response.DefaultFormatLayer == i) sb.AppendLine(Localization.This_is_the_default_layer); + + if(response.OnlineFormatLayer == i) sb.AppendLine(Localization.This_is_the_layer_actually_in_use); + + break; + } + + case (ushort)FormatLayerTypeCodes.HDDVDLayer: + { + sb.AppendFormat(Localization.Layer_0_is_of_type_HD_DVD, i).AppendLine(); + + if(response.DefaultFormatLayer == i) sb.AppendLine(Localization.This_is_the_default_layer); + + if(response.OnlineFormatLayer == i) sb.AppendLine(Localization.This_is_the_layer_actually_in_use); + + break; + } + + default: + { + sb.AppendFormat(Localization.Layer_0_is_of_unknown_type_1, i, response.FormatLayers[i]) + .AppendLine(); + + if(response.DefaultFormatLayer == i) sb.AppendLine(Localization.This_is_the_default_layer); + + if(response.OnlineFormatLayer == i) sb.AppendLine(Localization.This_is_the_layer_actually_in_use); + + break; + } + } + } + + return sb.ToString(); + } + + public static string PrettifyFormatLayers(byte[] FormatLayersResponse) + { + RecognizedFormatLayers? decoded = DecodeFormatLayers(FormatLayersResponse); + + return PrettifyFormatLayers(decoded); + } + +#region Nested type: RecognizedFormatLayers + + public struct RecognizedFormatLayers + { + /// Bytes 0 to 1 Data Length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Number of format layers in hybrid disc identified by drive + public byte NumberOfLayers; + /// Byte 5, bits 7 to 6 Reserved + public byte Reserved3; + /// Byte 5, bits 5 to 4 Layer no. used when disc is inserted + public byte DefaultFormatLayer; + /// Byte 5, bits 3 to 2 Reserved + public byte Reserved4; + /// Byte 5, bits 1 to 0 Layer no. currently in use + public byte OnlineFormatLayer; + /// Bytes 6 to end Recognized format layers + public ushort[] FormatLayers; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/MMC/TrackInformation.cs b/Aaru.Decoders/SCSI/MMC/TrackInformation.cs new file mode 100644 index 000000000..9be9e94da --- /dev/null +++ b/Aaru.Decoders/SCSI/MMC/TrackInformation.cs @@ -0,0 +1,108 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : TrackInformation.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.SCSI.MMC; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +public class TrackInformation +{ + public bool Blank; + public bool Copy; + public bool Damage; + public ushort DataLength; + public byte DataMode; + public uint FixedPacketSize; + public bool FP; + public uint FreeBlocks; + public uint LastLayerJumpAddress; + public uint LastRecordedAddress; + public LayerJumpRecordingStatus LayerJumpRecordingStatus; + public ushort LogicalTrackNumber; + public uint LogicalTrackSize; + public uint LogicalTrackStartAddress; + public bool LraV; + public uint NextLayerJumpAddress; + public uint NextWritableAddress; + public bool NwaV; + public bool Packet; + public uint ReadCompatibilityLba; + public bool RT; + public ushort SessionNumber; + public byte TrackMode; + + public static TrackInformation Decode(byte[] response) + { + if(response.Length < 32) return null; + + var decoded = new TrackInformation + { + DataLength = (ushort)((response[0] << 8) + response[1]), + LogicalTrackNumber = response[2], + SessionNumber = response[3], + LayerJumpRecordingStatus = (LayerJumpRecordingStatus)(response[5] >> 6), + Damage = (response[5] & 0x20) == 0x20, + Copy = (response[5] & 0x10) == 0x10, + TrackMode = (byte)(response[5] & 0xF), + RT = (response[6] & 0x80) == 0x80, + Blank = (response[6] & 0x40) == 0x40, + Packet = (response[6] & 0x20) == 0x20, + FP = (response[6] & 0x10) == 0x10, + DataMode = (byte)(response[6] & 0xF), + LraV = (response[7] & 0x02) == 0x02, + NwaV = (response[7] & 0x01) == 0x01, + LogicalTrackStartAddress = + (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]), + NextWritableAddress = + (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]), + FreeBlocks = (uint)((response[16] << 24) + (response[17] << 16) + (response[18] << 8) + response[19]), + FixedPacketSize = (uint)((response[20] << 24) + (response[21] << 16) + (response[22] << 8) + response[23]), + LogicalTrackSize = (uint)((response[24] << 24) + (response[25] << 16) + (response[26] << 8) + response[27]), + LastRecordedAddress = + (uint)((response[28] << 24) + (response[29] << 16) + (response[30] << 8) + response[31]) + }; + + if(response.Length < 48) return decoded; + + decoded.LogicalTrackNumber += (ushort)(response[32] << 8); + + decoded.SessionNumber += (ushort)(response[33] << 8); + + decoded.ReadCompatibilityLba = + (uint)((response[36] << 24) + (response[37] << 16) + (response[38] << 8) + response[39]); + + decoded.NextLayerJumpAddress = + (uint)((response[40] << 24) + (response[41] << 16) + (response[42] << 8) + response[43]); + + decoded.LastLayerJumpAddress = + (uint)((response[44] << 24) + (response[45] << 16) + (response[46] << 8) + response[47]); + + return decoded; + } +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/MMC/WriteProtect.cs b/Aaru.Decoders/SCSI/MMC/WriteProtect.cs new file mode 100644 index 000000000..b49707206 --- /dev/null +++ b/Aaru.Decoders/SCSI/MMC/WriteProtect.cs @@ -0,0 +1,156 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : WriteProtect.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MMC write protection structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.SCSI.MMC; + +// Information from the following standards: +// ANSI X3.304-1997 +// T10/1048-D revision 9.0 +// T10/1048-D revision 10a +// T10/1228-D revision 7.0c +// T10/1228-D revision 11a +// T10/1363-D revision 10g +// T10/1545-D revision 1d +// T10/1545-D revision 5 +// T10/1545-D revision 5a +// T10/1675-D revision 2c +// T10/1675-D revision 4 +// T10/1836-D revision 2g +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class WriteProtect +{ + public static WriteProtectionStatus? DecodeWriteProtectionStatus(byte[] WPSResponse) + { + if(WPSResponse == null) return null; + + var decoded = new WriteProtectionStatus + { + DataLength = BigEndianBitConverter.ToUInt16(WPSResponse, 0), + Reserved1 = WPSResponse[2], + Reserved2 = WPSResponse[3], + Reserved3 = (byte)((WPSResponse[4] & 0xF0) >> 4), + MSWI = Convert.ToBoolean(WPSResponse[4] & 0x08), + CWP = Convert.ToBoolean(WPSResponse[4] & 0x04), + PWP = Convert.ToBoolean(WPSResponse[4] & 0x02), + SWPP = Convert.ToBoolean(WPSResponse[4] & 0x01), + Reserved4 = WPSResponse[5], + Reserved5 = WPSResponse[6], + Reserved6 = WPSResponse[7] + }; + + return decoded; + } + + public static string PrettifyWriteProtectionStatus(WriteProtectionStatus? WPSResponse) + { + if(WPSResponse == null) return null; + + WriteProtectionStatus response = WPSResponse.Value; + + var sb = new StringBuilder(); + + if(response.MSWI) sb.AppendLine(Localization.Writing_inhibited_by_media_specific_reason); + + if(response.CWP) sb.AppendLine(Localization.Cartridge_sets_write_protection); + + if(response.PWP) sb.AppendLine(Localization.Media_surface_sets_write_protection); + + if(response.SWPP) sb.AppendLine(Localization.Software_write_protection_is_set_until_power_down); + +#if DEBUG + if(response.Reserved1 != 0) + sb.AppendFormat(Localization.Reserved1_equals_0_X8, response.Reserved1).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat(Localization.Reserved2_equals_0_X8, response.Reserved2).AppendLine(); + + if(response.Reserved3 != 0) + sb.AppendFormat(Localization.Reserved_3_equals_0_X2, response.Reserved3).AppendLine(); + + if(response.Reserved4 != 0) + sb.AppendFormat(Localization.Reserved_4_equals_0_X2, response.Reserved4).AppendLine(); + + if(response.Reserved5 != 0) + sb.AppendFormat(Localization.Reserved_5_equals_0_X2, response.Reserved5).AppendLine(); + + if(response.Reserved6 != 0) + sb.AppendFormat(Localization.Reserved_6_equals_0_X2, response.Reserved6).AppendLine(); +#endif + + return sb.ToString(); + } + + public static string PrettifyWriteProtectionStatus(byte[] WPSResponse) + { + WriteProtectionStatus? decoded = DecodeWriteProtectionStatus(WPSResponse); + + return PrettifyWriteProtectionStatus(decoded); + } + +#region Nested type: WriteProtectionStatus + + public struct WriteProtectionStatus + { + /// Bytes 0 to 1 Data Length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bits 7 to 4 Reserved + public byte Reserved3; + /// Byte 4, bit 3 Writing inhibited by media specific reason + public bool MSWI; + /// Byte 4, bit 2 Cartridge sets write protection + public bool CWP; + /// Byte 4, bit 1 Media surface sets write protection + public bool PWP; + /// Byte 4, bit 0 Software write protection until power down + public bool SWPP; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved + public byte Reserved6; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/00_SFF.cs b/Aaru.Decoders/SCSI/Modes/00_SFF.cs new file mode 100644 index 000000000..8fef4f95d --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/00_SFF.cs @@ -0,0 +1,110 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 00_SFF.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 00h: Drive Operation Mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x00: Drive Operation Mode page + + /// Drive Operation Mode page Page code 0x00 4 bytes in INF-8070 + public struct ModePage_00_SFF + { + /// Parameters can be saved + public bool PS; + /// Select LUN Mode + public bool SLM; + /// Select LUN for rewritable + public bool SLR; + /// Disable verify for WRITE + public bool DVW; + /// Disable deferred error + public bool DDE; + } + + public static ModePage_00_SFF? DecodeModePage_00_SFF(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x00) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 4) return null; + + var decoded = new ModePage_00_SFF(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.SLM |= (pageResponse[2] & 0x80) == 0x80; + decoded.SLR |= (pageResponse[2] & 0x40) == 0x40; + decoded.DVW |= (pageResponse[2] & 0x20) == 0x20; + + decoded.DDE |= (pageResponse[3] & 0x10) == 0x10; + + return decoded; + } + + public static string PrettifyModePage_00_SFF(byte[] pageResponse) => + PrettifyModePage_00_SFF(DecodeModePage_00_SFF(pageResponse)); + + public static string PrettifyModePage_00_SFF(ModePage_00_SFF? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_00_SFF page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Drive_Operation_Mode_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.DVW) sb.AppendLine("\t" + Localization.Verifying_after_writing_is_disabled); + + if(page.DDE) sb.AppendLine("\t" + Localization.Drive_will_abort_when_a_writing_error_is_detected); + + if(!page.SLM) return sb.ToString(); + + sb.Append("\t" + Localization.Drive_has_two_LUNs_with_rewritable_being); + sb.AppendLine(page.SLR ? "LUN 1" : "LUN 0"); + + return sb.ToString(); + } + +#endregion Mode Page 0x00: Drive Operation Mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/01.cs b/Aaru.Decoders/SCSI/Modes/01.cs new file mode 100644 index 000000000..7a5f33178 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/01.cs @@ -0,0 +1,225 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 01.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes and encodes SCSI MODE PAGE 01h: Read-write error recovery page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ + public static byte[] EncodeModePage_01(ModePage_01 page) + { + var pg = new byte[8]; + + pg[0] = 0x01; + pg[1] = 6; + + if(page.PS) pg[0] += 0x80; + + if(page.AWRE) pg[2] += 0x80; + + if(page.ARRE) pg[2] += 0x40; + + if(page.TB) pg[2] += 0x20; + + if(page.RC) pg[2] += 0x10; + + if(page.EER) pg[2] += 0x08; + + if(page.PER) pg[2] += 0x04; + + if(page.DTE) pg[2] += 0x02; + + if(page.DCR) pg[2] += 0x01; + + pg[3] = page.ReadRetryCount; + pg[4] = page.CorrectionSpan; + pg[5] = (byte)page.HeadOffsetCount; + pg[6] = (byte)page.DataStrobeOffsetCount; + + // This is from a newer version of SCSI unknown what happen for drives expecting an 8 byte page + /* + pg[8] = page.WriteRetryCount; + if (page.LBPERE) + pg[7] += 0x80; + pg[10] = (byte)((page.RecoveryTimeLimit & 0xFF00) << 8); + pg[11] = (byte)(page.RecoveryTimeLimit & 0xFF);*/ + + return pg; + } + +#region Mode Page 0x01: Read-write error recovery page + + /// Disconnect-reconnect page Page code 0x01 12 bytes in SCSI-2, SBC-1, SBC-2 + public struct ModePage_01 + { + /// Parameters can be saved + public bool PS; + /// Automatic Write Reallocation Enabled + public bool AWRE; + /// Automatic Read Reallocation Enabled + public bool ARRE; + /// Transfer block + public bool TB; + /// Read continuous + public bool RC; + /// Enable early recovery + public bool EER; + /// Post error reporting + public bool PER; + /// Disable transfer on error + public bool DTE; + /// Disable correction + public bool DCR; + /// How many times to retry a read operation + public byte ReadRetryCount; + /// How many bits of largest data burst error is maximum to apply error correction on it + public byte CorrectionSpan; + /// Offset to move the heads + public sbyte HeadOffsetCount; + /// Incremental position to which the recovered data strobe shall be adjusted + public sbyte DataStrobeOffsetCount; + /// How many times to retry a write operation + public byte WriteRetryCount; + /// Maximum time in ms to use in data error recovery procedures + public ushort RecoveryTimeLimit; + + /// Logical block provisioning error reporting is enabled + public bool LBPERE; + } + + public static ModePage_01? DecodeModePage_01(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x01) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 8) return null; + + var decoded = new ModePage_01(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.AWRE |= (pageResponse[2] & 0x80) == 0x80; + decoded.ARRE |= (pageResponse[2] & 0x40) == 0x40; + decoded.TB |= (pageResponse[2] & 0x20) == 0x20; + decoded.RC |= (pageResponse[2] & 0x10) == 0x10; + decoded.EER |= (pageResponse[2] & 0x08) == 0x08; + decoded.PER |= (pageResponse[2] & 0x04) == 0x04; + decoded.DTE |= (pageResponse[2] & 0x02) == 0x02; + decoded.DCR |= (pageResponse[2] & 0x01) == 0x01; + + decoded.ReadRetryCount = pageResponse[3]; + decoded.CorrectionSpan = pageResponse[4]; + decoded.HeadOffsetCount = (sbyte)pageResponse[5]; + decoded.DataStrobeOffsetCount = (sbyte)pageResponse[6]; + + if(pageResponse.Length < 12) return decoded; + + decoded.WriteRetryCount = pageResponse[8]; + decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.LBPERE |= (pageResponse[7] & 0x80) == 0x80; + + return decoded; + } + + public static string PrettifyModePage_01(byte[] pageResponse) => + PrettifyModePage_01(DecodeModePage_01(pageResponse)); + + public static string PrettifyModePage_01(ModePage_01? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_01 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Read_write_error_recovery_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.AWRE) sb.AppendLine("\t" + Localization.Automatic_write_reallocation_is_enabled); + + if(page.ARRE) sb.AppendLine("\t" + Localization.Automatic_read_reallocation_is_enabled); + + if(page.TB) + { + sb.AppendLine("\t" + + Localization + .Data_not_recovered_within_limits_shall_be_transferred_back_before_a_CHECK_CONDITION); + } + + if(page.RC) + { + sb.AppendLine("\t" + + Localization + .Drive_will_transfer_the_entire_requested_length_without_delaying_to_perform_error_recovery); + } + + if(page.EER) sb.AppendLine("\t" + Localization.Drive_will_use_the_most_expedient_form_of_error_recovery_first); + + if(page.PER) sb.AppendLine("\t" + Localization.Drive_shall_report_recovered_errors); + + if(page.DTE) sb.AppendLine("\t" + Localization.Transfer_will_be_terminated_upon_error_detection); + + if(page.DCR) sb.AppendLine("\t" + Localization.Error_correction_is_disabled); + + if(page.ReadRetryCount > 0) + { + sb.AppendFormat("\t" + Localization.Drive_will_repeat_read_operations_0_times, page.ReadRetryCount) + .AppendLine(); + } + + if(page.WriteRetryCount > 0) + { + sb.AppendFormat("\t" + Localization.Drive_will_repeat_write_operations_0_times, page.WriteRetryCount) + .AppendLine(); + } + + if(page.RecoveryTimeLimit > 0) + { + sb.AppendFormat("\t" + Localization.Drive_will_employ_a_maximum_of_0_ms_to_recover_data, + page.RecoveryTimeLimit) + .AppendLine(); + } + + if(page.LBPERE) sb.AppendLine(Localization.Logical_block_provisioning_error_reporting_is_enabled); + + return sb.ToString(); + } + +#endregion Mode Page 0x01: Read-write error recovery page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/01_MMC.cs b/Aaru.Decoders/SCSI/Modes/01_MMC.cs new file mode 100644 index 000000000..eb95abb4b --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/01_MMC.cs @@ -0,0 +1,245 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 01_MMC.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 01h: Read error recovery page for MultiMedia Devices. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ + public static byte[] EncodeModePage_01_MMC(ModePage_01_MMC page) + { + var pg = new byte[12]; + + pg[0] = 0x01; + pg[1] = 10; + + if(page.PS) pg[0] += 0x80; + + pg[2] = page.Parameter; + pg[3] = page.ReadRetryCount; + + // This is from a newer version of SCSI unknown what happen for drives expecting an 8 byte page + + pg[8] = page.WriteRetryCount; + pg[10] = (byte)((page.RecoveryTimeLimit & 0xFF00) << 8); + pg[11] = (byte)(page.RecoveryTimeLimit & 0xFF); + + return pg; + } + +#region Mode Page 0x01: Read error recovery page for MultiMedia Devices + + /// + /// Read error recovery page for MultiMedia Devices Page code 0x01 8 bytes in SCSI-2, MMC-1 12 bytes in MMC-2, + /// MMC-3 + /// + public struct ModePage_01_MMC + { + /// Parameters can be saved + public bool PS; + /// Error recovery parameter + public byte Parameter; + /// How many times to retry a read operation + public byte ReadRetryCount; + /// How many times to retry a write operation + public byte WriteRetryCount; + /// Maximum time in ms to use in data error recovery procedures + public ushort RecoveryTimeLimit; + } + + public static ModePage_01_MMC? DecodeModePage_01_MMC(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x01) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 8) return null; + + var decoded = new ModePage_01_MMC(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.Parameter = pageResponse[2]; + decoded.ReadRetryCount = pageResponse[3]; + + if(pageResponse.Length < 12) return decoded; + + decoded.WriteRetryCount = pageResponse[8]; + decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + + return decoded; + } + + public static string PrettifyModePage_01_MMC(byte[] pageResponse) => + PrettifyModePage_01_MMC(DecodeModePage_01_MMC(pageResponse)); + + public static string PrettifyModePage_01_MMC(ModePage_01_MMC? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_01_MMC page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Read_error_recovery_page_for_MultiMedia_Devices); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.ReadRetryCount > 0) + { + sb.AppendFormat("\t" + Localization.Drive_will_repeat_read_operations_0_times, page.ReadRetryCount) + .AppendLine(); + } + + string AllUsed = "\t" + Localization.All_available_recovery_procedures_will_be_used + "\n"; + string CIRCRetriesUsed = "\t" + Localization.Only_retries_and_CIRC_are_used + "\n"; + string RetriesUsed = "\t" + Localization.Only_retries_are_used + "\n"; + string RecoveredNotReported = "\t" + Localization.Recovered_errors_will_not_be_reported + "\n"; + string RecoveredReported = "\t" + Localization.Recovered_errors_will_be_reported + "\n"; + + string RecoveredAbort = + "\t" + Localization.Recovered_errors_will_be_reported_and_aborted_with_CHECK_CONDITION + "\n"; + + string UnrecECCAbort = "\t" + Localization.Unrecovered_ECC_errors_will_return_CHECK_CONDITION; + string UnrecCIRCAbort = "\t" + Localization.Unrecovered_CIRC_errors_will_return_CHECK_CONDITION; + string UnrecECCNotAbort = "\t" + Localization.Unrecovered_ECC_errors_will_not_abort_the_transfer; + string UnrecCIRCNotAbort = "\t" + Localization.Unrecovered_CIRC_errors_will_not_abort_the_transfer; + + string UnrecECCAbortData = + "\t" + Localization.Unrecovered_ECC_errors_will_return_CHECK_CONDITION_and_the_uncorrected_data; + + string UnrecCIRCAbortData = + "\t" + Localization.Unrecovered_CIRC_errors_will_return_CHECK_CONDITION_and_the_uncorrected_data; + + switch(page.Parameter) + { + case 0x00: + sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbort); + + break; + case 0x01: + sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbort); + + break; + case 0x04: + sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbort); + + break; + case 0x05: + sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbort); + + break; + case 0x06: + sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbort); + + break; + case 0x07: + sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbort); + + break; + case 0x10: + sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCNotAbort); + + break; + case 0x11: + sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCNotAbort); + + break; + case 0x14: + sb.AppendLine(AllUsed + RecoveredReported + UnrecECCNotAbort); + + break; + case 0x15: + sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCNotAbort); + + break; + case 0x20: + sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbortData); + + break; + case 0x21: + sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbortData); + + break; + case 0x24: + sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbortData); + + break; + case 0x25: + sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbortData); + + break; + case 0x26: + sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbortData); + + break; + case 0x27: + sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbortData); + + break; + case 0x30: + goto case 0x10; + case 0x31: + goto case 0x11; + case 0x34: + goto case 0x14; + case 0x35: + goto case 0x15; + default: + sb.AppendFormat(Localization.Unknown_recovery_parameter_0, page.Parameter).AppendLine(); + + break; + } + + if(page.WriteRetryCount > 0) + { + sb.AppendFormat("\t" + Localization.Drive_will_repeat_write_operations_0_times, page.WriteRetryCount) + .AppendLine(); + } + + if(page.RecoveryTimeLimit > 0) + { + sb.AppendFormat("\t" + Localization.Drive_will_employ_a_maximum_of_0_ms_to_recover_data, + page.RecoveryTimeLimit) + .AppendLine(); + } + + return sb.ToString(); + } + +#endregion Mode Page 0x01: Read error recovery page for MultiMedia Devices +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/02.cs b/Aaru.Decoders/SCSI/Modes/02.cs new file mode 100644 index 000000000..6dd74fb67 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/02.cs @@ -0,0 +1,219 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 02.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 02h: Disconnect-reconnect page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x02: Disconnect-reconnect page + + /// Disconnect-reconnect page Page code 0x02 16 bytes in SCSI-2, SPC-1, SPC-2, SPC-3, SPC-4, SPC-5 + public struct ModePage_02 + { + /// Parameters can be saved + public bool PS; + /// How full should be the buffer prior to attempting a reselection + public byte BufferFullRatio; + /// How empty should be the buffer prior to attempting a reselection + public byte BufferEmptyRatio; + /// Max. time in 100 µs increments that the target is permitted to assert BSY without a REQ/ACK + public ushort BusInactivityLimit; + /// Min. time in 100 µs increments to wait after releasing the bus before attempting reselection + public ushort DisconnectTimeLimit; + /// + /// Max. time in 100 µs increments allowed to use the bus before disconnecting, if granted the privilege and not + /// restricted by + /// + public ushort ConnectTimeLimit; + /// Maximum amount of data before disconnecting in 512 bytes increments + public ushort MaxBurstSize; + /// Data transfer disconnect control + public byte DTDC; + + /// Target shall not transfer data for a command during the same interconnect tenancy + public bool DIMM; + /// Wether to use fair or unfair arbitration when requesting an interconnect tenancy + public byte FairArbitration; + /// Max. ammount of data in 512 bytes increments that may be transferred for a command along with the command + public ushort FirstBurstSize; + /// Target is allowed to re-order the data transfer + public bool EMDP; + } + + public static ModePage_02? DecodeModePage_02(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x02) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 12) return null; + + var decoded = new ModePage_02(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.BufferFullRatio = pageResponse[2]; + decoded.BufferEmptyRatio = pageResponse[3]; + decoded.BusInactivityLimit = (ushort)((pageResponse[4] << 8) + pageResponse[5]); + decoded.DisconnectTimeLimit = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.ConnectTimeLimit = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.MaxBurstSize = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + + if(pageResponse.Length >= 13) + { + decoded.EMDP |= (pageResponse[12] & 0x80) == 0x80; + decoded.DIMM |= (pageResponse[12] & 0x08) == 0x08; + decoded.FairArbitration = (byte)((pageResponse[12] & 0x70) >> 4); + decoded.DTDC = (byte)(pageResponse[12] & 0x07); + } + + if(pageResponse.Length >= 16) decoded.FirstBurstSize = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + + return decoded; + } + + public static string PrettifyModePage_02(byte[] pageResponse) => + PrettifyModePage_02(DecodeModePage_02(pageResponse)); + + public static string PrettifyModePage_02(ModePage_02? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_02 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Disconnect_Reconnect_mode_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.BufferFullRatio > 0) + { + sb.AppendFormat("\t" + Localization._0_ratio_of_buffer_that_shall_be_full_prior_to_attempting_a_reselection, + page.BufferFullRatio) + .AppendLine(); + } + + if(page.BufferEmptyRatio > 0) + { + sb.AppendFormat("\t" + + Localization._0_ratio_of_buffer_that_shall_be_empty_prior_to_attempting_a_reselection, + page.BufferEmptyRatio) + .AppendLine(); + } + + if(page.BusInactivityLimit > 0) + { + sb.AppendFormat("\t" + Localization._0_µs_maximum_permitted_to_assert_BSY_without_a_REQ_ACK_handshake, + page.BusInactivityLimit * 100) + .AppendLine(); + } + + if(page.DisconnectTimeLimit > 0) + { + sb.AppendFormat("\t" + + Localization + ._0_µs_maximum_permitted_wait_after_releasing_the_bus_before_attempting_reselection, + page.DisconnectTimeLimit * 100) + .AppendLine(); + } + + if(page.ConnectTimeLimit > 0) + { + sb.AppendFormat("\t" + + Localization + ._0_µs_allowed_to_use_the_bus_before_disconnecting_if_granted_the_privilege_and_not_restricted, + page.ConnectTimeLimit * 100) + .AppendLine(); + } + + if(page.MaxBurstSize > 0) + { + sb.AppendFormat("\t" + Localization._0_bytes_maximum_can_be_transferred_before_disconnecting, + page.MaxBurstSize * 512) + .AppendLine(); + } + + if(page.FirstBurstSize > 0) + { + sb.AppendFormat("\t" + + Localization + ._0_bytes_maximum_can_be_transferred_for_a_command_along_with_the_disconnect_command, + page.FirstBurstSize * 512) + .AppendLine(); + } + + if(page.DIMM) + { + sb.AppendLine("\t" + + Localization + .Target_shall_not_transfer_data_for_a_command_during_the_same_interconnect_tenancy); + } + + if(page.EMDP) sb.AppendLine("\t" + Localization.Target_is_allowed_to_reorder_the_data_transfer); + + switch(page.DTDC) + { + case 0: + sb.AppendLine("\t" + Localization.Data_transfer_disconnect_control_is_not_used); + + break; + case 1: + sb.AppendLine("\t" + + Localization + .All_data_for_a_command_shall_be_transferred_within_a_single_interconnect_tenancy); + + break; + case 3: + sb.AppendLine("\t" + + Localization + .All_data_and_the_response_for_a_command_shall_be_transferred_within_a_single_interconnect_tenancy); + + break; + default: + sb.AppendFormat("\t" + Localization.Reserved_data_transfer_disconnect_control_value_0, page.DTDC) + .AppendLine(); + + break; + } + + return sb.ToString(); + } + +#endregion Mode Page 0x02: Disconnect-reconnect page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/03.cs b/Aaru.Decoders/SCSI/Modes/03.cs new file mode 100644 index 000000000..665abd68e --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/03.cs @@ -0,0 +1,173 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 03.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 03h: Format device page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x03: Format device page + + /// Disconnect-reconnect page Page code 0x03 24 bytes in SCSI-2, SBC-1 + public struct ModePage_03 + { + /// Parameters can be saved + public bool PS; + /// Tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors + public ushort TracksPerZone; + /// Number of sectors per zone that shall be reserved for defect handling + public ushort AltSectorsPerZone; + /// Number of tracks per zone that shall be reserved for defect handling + public ushort AltTracksPerZone; + /// Number of tracks per LUN that shall be reserved for defect handling + public ushort AltTracksPerLun; + /// Number of physical sectors per track + public ushort SectorsPerTrack; + /// Bytes per physical sector + public ushort BytesPerSector; + /// Interleave value, target dependent + public ushort Interleave; + /// Sectors between last block of one track and first block of the next + public ushort TrackSkew; + /// Sectors between last block of a cylinder and first block of the next one + public ushort CylinderSkew; + /// Soft-sectored + public bool SSEC; + /// Hard-sectored + public bool HSEC; + /// Removable + public bool RMB; + /// + /// If set, address are allocated progressively in a surface before going to the next. Otherwise, it goes by + /// cylinders + /// + public bool SURF; + } + + public static ModePage_03? DecodeModePage_03(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x03) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 24) return null; + + var decoded = new ModePage_03(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.TracksPerZone = (ushort)((pageResponse[2] << 8) + pageResponse[3]); + decoded.AltSectorsPerZone = (ushort)((pageResponse[4] << 8) + pageResponse[5]); + decoded.AltTracksPerZone = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.AltTracksPerLun = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.SectorsPerTrack = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.BytesPerSector = (ushort)((pageResponse[12] << 8) + pageResponse[13]); + decoded.Interleave = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + decoded.TrackSkew = (ushort)((pageResponse[16] << 8) + pageResponse[17]); + decoded.CylinderSkew = (ushort)((pageResponse[18] << 8) + pageResponse[19]); + decoded.SSEC |= (pageResponse[20] & 0x80) == 0x80; + decoded.HSEC |= (pageResponse[20] & 0x40) == 0x40; + decoded.RMB |= (pageResponse[20] & 0x20) == 0x20; + decoded.SURF |= (pageResponse[20] & 0x10) == 0x10; + + return decoded; + } + + public static string PrettifyModePage_03(byte[] pageResponse) => + PrettifyModePage_03(DecodeModePage_03(pageResponse)); + + public static string PrettifyModePage_03(ModePage_03? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_03 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Format_device_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + sb.AppendFormat("\t" + + Localization + ._0_tracks_per_zone_to_use_in_dividing_the_capacity_for_the_purpose_of_allocating_alternate_sectors, + page.TracksPerZone) + .AppendLine(); + + sb.AppendFormat("\t" + Localization._0_sectors_per_zone_that_shall_be_reserved_for_defect_handling, + page.AltSectorsPerZone) + .AppendLine(); + + sb.AppendFormat("\t" + Localization._0_tracks_per_zone_that_shall_be_reserved_for_defect_handling, + page.AltTracksPerZone) + .AppendLine(); + + sb.AppendFormat("\t" + Localization._0_tracks_per_LUN_that_shall_be_reserved_for_defect_handling, + page.AltTracksPerLun) + .AppendLine(); + + sb.AppendFormat("\t" + Localization._0_physical_sectors_per_track, page.SectorsPerTrack).AppendLine(); + sb.AppendFormat("\t" + Localization._0_Bytes_per_physical_sector, page.BytesPerSector).AppendLine(); + sb.AppendFormat("\t" + Localization.Target_dependent_interleave_value_is_0, page.Interleave).AppendLine(); + + sb.AppendFormat("\t" + Localization._0_sectors_between_last_block_of_one_track_and_first_block_of_the_next, + page.TrackSkew) + .AppendLine(); + + sb.AppendFormat("\t" + Localization._0_sectors_between_last_block_of_a_cylinder_and_first_block_of_the_next_one, + page.CylinderSkew) + .AppendLine(); + + if(page.SSEC) sb.AppendLine("\t" + Localization.Drive_supports_soft_sectoring_format); + + if(page.HSEC) sb.AppendLine("\t" + Localization.Drive_supports_hard_sectoring_format); + + if(page.RMB) sb.AppendLine("\t" + Localization.Drive_media_is_removable); + + sb.AppendLine(page.SURF + ? "\t" + + Localization + .Sector_addressing_is_progressively_incremented_in_one_surface_before_going_to_the_next + : "\t" + + Localization + .Sector_addressing_is_progressively_incremented_in_one_cylinder_before_going_to_the_next); + + return sb.ToString(); + } + +#endregion Mode Page 0x03: Format device page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/04.cs b/Aaru.Decoders/SCSI/Modes/04.cs new file mode 100644 index 000000000..04a3549fa --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/04.cs @@ -0,0 +1,161 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 04.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 04h: Rigid disk drive geometry page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x04: Rigid disk drive geometry page + + /// Disconnect-reconnect page Page code 0x04 24 bytes in SCSI-2, SBC-1 + public struct ModePage_04 + { + /// Parameters can be saved + public bool PS; + /// Cylinders used for data storage + public uint Cylinders; + /// Heads for reading and/or writing + public byte Heads; + /// Cylinder where write precompensation starts + public uint WritePrecompCylinder; + /// Cylinder where write current reduction starts + public uint WriteReduceCylinder; + /// Step rate in 100 ns units + public ushort DriveStepRate; + /// Cylinder where the heads park + public int LandingCylinder; + /// Rotational position locking + public byte RPL; + /// Rotational skew to apply when synchronized + public byte RotationalOffset; + /// Medium speed in rpm + public ushort MediumRotationRate; + } + + public static ModePage_04? DecodeModePage_04(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x04) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 20) return null; + + var decoded = new ModePage_04(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.Cylinders = (uint)((pageResponse[2] << 16) + (pageResponse[3] << 8) + pageResponse[4]); + decoded.Heads = pageResponse[5]; + decoded.WritePrecompCylinder = (uint)((pageResponse[6] << 16) + (pageResponse[7] << 8) + pageResponse[8]); + + decoded.WriteReduceCylinder = (uint)((pageResponse[9] << 16) + (pageResponse[10] << 8) + pageResponse[11]); + + decoded.DriveStepRate = (ushort)((pageResponse[12] << 8) + pageResponse[13]); + + decoded.LandingCylinder = (pageResponse[14] << 16) + (pageResponse[15] << 8) + pageResponse[16]; + decoded.RPL = (byte)(pageResponse[17] & 0x03); + decoded.RotationalOffset = pageResponse[18]; + + if(pageResponse.Length >= 22) decoded.MediumRotationRate = (ushort)((pageResponse[20] << 8) + pageResponse[21]); + + return decoded; + } + + public static string PrettifyModePage_04(byte[] pageResponse) => + PrettifyModePage_04(DecodeModePage_04(pageResponse)); + + public static string PrettifyModePage_04(ModePage_04? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_04 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Rigid_disk_drive_geometry_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + sb.AppendFormat("\t" + Localization._0_heads, page.Heads).AppendLine(); + sb.AppendFormat("\t" + Localization._0_cylinders, page.Cylinders).AppendLine(); + + if(page.WritePrecompCylinder < page.Cylinders) + { + sb.AppendFormat("\t" + Localization.Write_pre_compensation_starts_at_cylinder_0, page.WritePrecompCylinder) + .AppendLine(); + } + + if(page.WriteReduceCylinder < page.Cylinders) + { + sb.AppendFormat("\t" + Localization.Write_current_reduction_starts_at_cylinder_0, page.WriteReduceCylinder) + .AppendLine(); + } + + if(page.DriveStepRate > 0) + sb.AppendFormat("\t" + Localization.Drive_steps_in_0_ns, (uint)page.DriveStepRate * 100).AppendLine(); + + sb.AppendFormat("\t" + Localization.Heads_park_in_cylinder_0, page.LandingCylinder).AppendLine(); + + if(page.MediumRotationRate > 0) + sb.AppendFormat("\t" + Localization.Medium_rotates_at_0_rpm, page.MediumRotationRate).AppendLine(); + + switch(page.RPL) + { + case 0: + sb.AppendLine("\t" + Localization.Spindle_synchronization_is_disabled_or_unsupported); + + break; + case 1: + sb.AppendLine("\t" + Localization.Target_operates_as_a_synchronized_spindle_slave); + + break; + case 2: + sb.AppendLine("\t" + Localization.Target_operates_as_a_synchronized_spindle_master); + + break; + case 3: + sb.AppendLine("\t" + Localization.Target_operates_as_a_synchronized_spindle_master_control); + + break; + } + + return sb.ToString(); + } + +#endregion Mode Page 0x04: Rigid disk drive geometry page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/05.cs b/Aaru.Decoders/SCSI/Modes/05.cs new file mode 100644 index 000000000..31fb36116 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/05.cs @@ -0,0 +1,346 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 05.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 05h: Flexible disk page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x05: Flexible disk page + + /// Disconnect-reconnect page Page code 0x05 32 bytes in SCSI-2, SBC-1 + public struct ModePage_05 + { + /// Parameters can be saved + public bool PS; + /// Data rate of peripheral device on kbit/s + public ushort TransferRate; + /// Heads for reading and/or writing + public byte Heads; + /// Sectors per revolution per head + public byte SectorsPerTrack; + /// Bytes of data per sector + public ushort BytesPerSector; + /// Cylinders used for data storage + public ushort Cylinders; + /// Cylinder where write precompensation starts + public ushort WritePrecompCylinder; + /// Cylinder where write current reduction starts + public ushort WriteReduceCylinder; + /// Step rate in 100 μs units + public ushort DriveStepRate; + /// Width of step pulse in μs + public byte DriveStepPulse; + /// Head settle time in 100 μs units + public ushort HeadSettleDelay; + /// + /// If is true, specified in 1/10s of a second the time waiting for read status before + /// aborting medium access. Otherwise, indicates time to way before medimum access after motor on signal is asserted. + /// + public byte MotorOnDelay; + /// + /// Time in 1/10s of a second to wait before releasing the motor on signal after an idle condition. 0xFF means to + /// never release the signal + /// + public byte MotorOffDelay; + /// Specifies if a signal indicates that the medium is ready to be accessed + public bool TRDY; + /// If true sectors start with one. Otherwise, they start with zero. + public bool SSN; + /// If true specifies that motor on shall remain released. + public bool MO; + /// Number of additional step pulses per cylinder. + public byte SPC; + /// Write compensation value + public byte WriteCompensation; + /// Head loading time in ms. + public byte HeadLoadDelay; + /// Head unloading time in ms. + public byte HeadUnloadDelay; + /// Description of shugart's bus pin 34 usage + public byte Pin34; + /// Description of shugart's bus pin 2 usage + public byte Pin2; + /// Description of shugart's bus pin 4 usage + public byte Pin4; + /// Description of shugart's bus pin 1 usage + public byte Pin1; + /// Medium speed in rpm + public ushort MediumRotationRate; + } + + public static ModePage_05? DecodeModePage_05(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x05) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 32) return null; + + var decoded = new ModePage_05(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.TransferRate = (ushort)((pageResponse[2] << 8) + pageResponse[3]); + decoded.Heads = pageResponse[4]; + decoded.SectorsPerTrack = pageResponse[5]; + decoded.BytesPerSector = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.Cylinders = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.WritePrecompCylinder = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.WriteReduceCylinder = (ushort)((pageResponse[12] << 8) + pageResponse[13]); + decoded.DriveStepRate = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + decoded.DriveStepPulse = pageResponse[16]; + decoded.HeadSettleDelay = (ushort)((pageResponse[17] << 8) + pageResponse[18]); + decoded.MotorOnDelay = pageResponse[19]; + decoded.MotorOffDelay = pageResponse[20]; + decoded.TRDY |= (pageResponse[21] & 0x80) == 0x80; + decoded.SSN |= (pageResponse[21] & 0x40) == 0x40; + decoded.MO |= (pageResponse[21] & 0x20) == 0x20; + decoded.SPC = (byte)(pageResponse[22] & 0x0F); + decoded.WriteCompensation = pageResponse[23]; + decoded.HeadLoadDelay = pageResponse[24]; + decoded.HeadUnloadDelay = pageResponse[25]; + decoded.Pin34 = (byte)((pageResponse[26] & 0xF0) >> 4); + decoded.Pin2 = (byte)(pageResponse[26] & 0x0F); + decoded.Pin4 = (byte)((pageResponse[27] & 0xF0) >> 4); + decoded.Pin1 = (byte)(pageResponse[27] & 0x0F); + decoded.MediumRotationRate = (ushort)((pageResponse[28] << 8) + pageResponse[29]); + + return decoded; + } + + public static string PrettifyModePage_05(byte[] pageResponse) => + PrettifyModePage_05(DecodeModePage_05(pageResponse)); + + public static string PrettifyModePage_05(ModePage_05? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_05 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Flexible_disk_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + sb.AppendFormat("\t" + Localization.Transfer_rate_0_kbits, page.TransferRate).AppendLine(); + sb.AppendFormat("\t" + Localization._0_heads, page.Heads).AppendLine(); + sb.AppendFormat("\t" + Localization._0_cylinders, page.Cylinders).AppendLine(); + sb.AppendFormat("\t" + Localization._0_sectors_per_track, page.SectorsPerTrack).AppendLine(); + sb.AppendFormat("\t" + Localization._0_bytes_per_sector, page.BytesPerSector).AppendLine(); + + if(page.WritePrecompCylinder < page.Cylinders) + { + sb.AppendFormat("\t" + Localization.Write_pre_compensation_starts_at_cylinder_0, page.WritePrecompCylinder) + .AppendLine(); + } + + if(page.WriteReduceCylinder < page.Cylinders) + { + sb.AppendFormat("\t" + Localization.Write_current_reduction_starts_at_cylinder_0, page.WriteReduceCylinder) + .AppendLine(); + } + + if(page.DriveStepRate > 0) + sb.AppendFormat("\t" + Localization.Drive_steps_in_0_μs, (uint)page.DriveStepRate * 100).AppendLine(); + + if(page.DriveStepPulse > 0) + sb.AppendFormat("\t" + Localization.Each_step_pulse_is_0_ms, page.DriveStepPulse).AppendLine(); + + if(page.HeadSettleDelay > 0) + sb.AppendFormat("\t" + Localization.Heads_settles_in_0_μs, (uint)page.HeadSettleDelay * 100).AppendLine(); + + if(!page.TRDY) + { + sb.AppendFormat("\t" + + Localization + .Target_shall_wait_0_seconds_before_attempting_to_access_the_medium_after_motor_on_is_asserted, + (double)page.MotorOnDelay * 10) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + + Localization + .Target_shall_wait_0_seconds_after_drive_is_ready_before_aborting_medium_access_attempts, + (double)page.MotorOnDelay * 10) + .AppendLine(); + } + + if(page.MotorOffDelay != 0xFF) + { + sb.AppendFormat("\t" + + Localization + .Target_shall_wait_0_seconds_before_releasing_the_motor_on_signal_after_becoming_idle, + (double)page.MotorOffDelay * 10) + .AppendLine(); + } + else + sb.AppendLine("\t" + Localization.Target_shall_never_release_the_motor_on_signal); + + if(page.TRDY) sb.AppendLine("\t" + Localization.There_is_a_drive_ready_signal); + + if(page.SSN) sb.AppendLine("\t" + Localization.Sectors_start_at_1); + + if(page.MO) sb.AppendLine("\t" + Localization.The_motor_on_signal_shall_remain_released); + + sb.AppendFormat("\t" + Localization.Drive_needs_to_do_0_step_pulses_per_cylinder, page.SPC + 1).AppendLine(); + + if(page.WriteCompensation > 0) + sb.AppendFormat("\t" + Localization.Write_pre_compensation_is_0, page.WriteCompensation).AppendLine(); + + if(page.HeadLoadDelay > 0) + sb.AppendFormat("\t" + Localization.Head_takes_0_ms_to_load, page.HeadLoadDelay).AppendLine(); + + if(page.HeadUnloadDelay > 0) + sb.AppendFormat("\t" + Localization.Head_takes_0_ms_to_unload, page.HeadUnloadDelay).AppendLine(); + + if(page.MediumRotationRate > 0) + sb.AppendFormat("\t" + Localization.Medium_rotates_at_0_rpm, page.MediumRotationRate).AppendLine(); + + switch(page.Pin34 & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Pin_34_is_unconnected); + + break; + case 1: + sb.Append("\t" + + ((page.Pin34 & 0x08) == 0x08 + ? Localization.Pin_34_indicates_drive_is_ready_when_active_high + : Localization.Pin_34_indicates_drive_is_ready_when_active_low)); + + break; + case 2: + sb.Append("\t" + + ((page.Pin34 & 0x08) == 0x08 + ? Localization.Pin_34_indicates_disk_has_changed_when_active_high + : Localization.Pin_34_indicates_disk_has_changed_when_active_low)); + + break; + default: + sb.AppendFormat("\t" + + ((page.Pin34 & 0x08) == 0x08 + ? Localization.Pin_34_indicates_unknown_function_0_when_active_high + : Localization.Pin_34_indicates_unknown_function_0_when_active_low), + page.Pin34 & 0x07); + + break; + } + + switch(page.Pin4 & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Pin_4_is_unconnected); + + break; + case 1: + sb.Append("\t" + + ((page.Pin4 & 0x08) == 0x08 + ? Localization.Pin_4_indicates_drive_is_in_use_when_active_high + : Localization.Pin_4_indicates_drive_is_in_use_when_active_low)); + + break; + case 2: + sb.Append("\t" + + ((page.Pin4 & 0x08) == 0x08 + ? Localization.Pin_4_indicates_eject_when_active_high + : Localization.Pin_4_indicates_eject_when_active_low)); + + break; + case 3: + sb.Append("\t" + + ((page.Pin4 & 0x08) == 0x08 + ? Localization.Pin_4_indicates_head_load_when_active_high + : Localization.Pin_4_indicates_head_load_when_active_low)); + + break; + default: + sb.AppendFormat("\t" + + ((page.Pin4 & 0x08) == 0x08 + ? Localization.Pin_4_indicates_unknown_function_0_when_active_high + : Localization.Pin_4_indicates_unknown_function_0_when_active_low), + page.Pin4 & 0x07); + + break; + } + + switch(page.Pin2 & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Pin_2_is_unconnected); + + break; + default: + sb.AppendFormat("\t" + + ((page.Pin2 & 0x08) == 0x08 + ? Localization.Pin_2_indicates_unknown_function_0_when_active_high + : Localization.Pin_2_indicates_unknown_function_0_when_active_low), + page.Pin2 & 0x07); + + break; + } + + switch(page.Pin1 & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Pin_1_is_unconnected); + + break; + case 1: + sb.Append("\t" + + ((page.Pin1 & 0x08) == 0x08 + ? Localization.Pin_1_indicates_disk_change_reset_when_active_high + : Localization.Pin_1_indicates_disk_change_reset_when_active_low)); + + break; + default: + sb.AppendFormat("\t" + + ((page.Pin1 & 0x08) == 0x08 + ? Localization.Pin_1_indicates_unknown_function_0_when_active_high + : Localization.Pin_1_indicates_unknown_function_0_when_active_low), + page.Pin1 & 0x07); + + break; + } + + return sb.ToString(); + } + +#endregion Mode Page 0x05: Flexible disk page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/06.cs b/Aaru.Decoders/SCSI/Modes/06.cs new file mode 100644 index 000000000..0f129a463 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/06.cs @@ -0,0 +1,92 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 06.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 06h: Optical memory page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x06: Optical memory page + + /// Optical memory page Page code 0x06 4 bytes in SCSI-2 + public struct ModePage_06 + { + /// Parameters can be saved + public bool PS; + /// Report updated block read + public bool RUBR; + } + + public static ModePage_06? DecodeModePage_06(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x06) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 4) return null; + + var decoded = new ModePage_06(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.RUBR |= (pageResponse[2] & 0x01) == 0x01; + + return decoded; + } + + public static string PrettifyModePage_06(byte[] pageResponse) => + PrettifyModePage_06(DecodeModePage_06(pageResponse)); + + public static string PrettifyModePage_06(ModePage_06? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_06 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_optical_memory); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.RUBR) sb.AppendLine("\t" + Localization.On_reading_an_updated_block_drive_will_return_RECOVERED_ERROR); + + return sb.ToString(); + } + +#endregion Mode Page 0x06: Optical memory page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/07.cs b/Aaru.Decoders/SCSI/Modes/07.cs new file mode 100644 index 000000000..665536619 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/07.cs @@ -0,0 +1,131 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 07.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 07h: Verify error recovery page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static partial class Modes +{ +#region Mode Page 0x07: Verify error recovery page + + /// Disconnect-reconnect page Page code 0x07 12 bytes in SCSI-2, SBC-1, SBC-2 + public struct ModePage_07 + { + /// Parameters can be saved + public bool PS; + /// Enable early recovery + public bool EER; + /// Post error reporting + public bool PER; + /// Disable transfer on error + public bool DTE; + /// Disable correction + public bool DCR; + /// How many times to retry a verify operation + public byte VerifyRetryCount; + /// How many bits of largest data burst error is maximum to apply error correction on it + public byte CorrectionSpan; + /// Maximum time in ms to use in data error recovery procedures + public ushort RecoveryTimeLimit; + } + + public static ModePage_07? DecodeModePage_07(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x07) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 12) return null; + + var decoded = new ModePage_07(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.EER |= (pageResponse[2] & 0x08) == 0x08; + decoded.PER |= (pageResponse[2] & 0x04) == 0x04; + decoded.DTE |= (pageResponse[2] & 0x02) == 0x02; + decoded.DCR |= (pageResponse[2] & 0x01) == 0x01; + + decoded.VerifyRetryCount = pageResponse[3]; + decoded.CorrectionSpan = pageResponse[4]; + decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + + return decoded; + } + + public static string PrettifyModePage_07(byte[] pageResponse) => + PrettifyModePage_07(DecodeModePage_07(pageResponse)); + + public static string PrettifyModePage_07(ModePage_07? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_07 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Verify_error_recovery_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.EER) sb.AppendLine("\t" + Localization.Drive_will_use_the_most_expedient_form_of_error_recovery_first); + + if(page.PER) sb.AppendLine("\t" + Localization.Drive_shall_report_recovered_errors); + + if(page.DTE) sb.AppendLine("\t" + Localization.Transfer_will_be_terminated_upon_error_detection); + + if(page.DCR) sb.AppendLine("\t" + Localization.Error_correction_is_disabled); + + if(page.VerifyRetryCount > 0) + { + sb.AppendFormat("\t" + Localization.Drive_will_repeat_verify_operations_0_times, page.VerifyRetryCount) + .AppendLine(); + } + + if(page.RecoveryTimeLimit > 0) + { + sb.AppendFormat("\t" + Localization.Drive_will_employ_a_maximum_of_0_ms_to_recover_data, + page.RecoveryTimeLimit) + .AppendLine(); + } + + return sb.ToString(); + } + +#endregion Mode Page 0x07: Verify error recovery page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/07_MMC.cs b/Aaru.Decoders/SCSI/Modes/07_MMC.cs new file mode 100644 index 000000000..1328c3e75 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/07_MMC.cs @@ -0,0 +1,199 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 07_MMC.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 07h: Verify error recovery page for MultiMedia Devices. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x07: Verify error recovery page for MultiMedia Devices + + /// Verify error recovery page for MultiMedia Devices Page code 0x07 8 bytes in SCSI-2, MMC-1 + public struct ModePage_07_MMC + { + /// Parameters can be saved + public bool PS; + /// Error recovery parameter + public byte Parameter; + /// How many times to retry a verify operation + public byte VerifyRetryCount; + } + + public static ModePage_07_MMC? DecodeModePage_07_MMC(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x07) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 8) return null; + + var decoded = new ModePage_07_MMC(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.Parameter = pageResponse[2]; + decoded.VerifyRetryCount = pageResponse[3]; + + return decoded; + } + + public static string PrettifyModePage_07_MMC(byte[] pageResponse) => + PrettifyModePage_07_MMC(DecodeModePage_07_MMC(pageResponse)); + + public static string PrettifyModePage_07_MMC(ModePage_07_MMC? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_07_MMC page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Verify_error_recovery_page_for_MultiMedia_Devices); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.VerifyRetryCount > 0) + { + sb.AppendFormat("\t" + Localization.Drive_will_repeat_verify_operations_0_times, page.VerifyRetryCount) + .AppendLine(); + } + + string AllUsed = "\t" + Localization.All_available_recovery_procedures_will_be_used + "\n"; + string CIRCRetriesUsed = "\t" + Localization.Only_retries_and_CIRC_are_used + "\n"; + string RetriesUsed = "\t" + Localization.Only_retries_are_used + "\n"; + string RecoveredNotReported = "\t" + Localization.Recovered_errors_will_not_be_reported + "\n"; + string RecoveredReported = "\t" + Localization.Recovered_errors_will_be_reported + "\n"; + + string RecoveredAbort = + "\t" + Localization.Recovered_errors_will_be_reported_and_aborted_with_CHECK_CONDITION + "\n"; + + string UnrecECCAbort = "\t" + Localization.Unrecovered_ECC_errors_will_return_CHECK_CONDITION; + string UnrecCIRCAbort = "\t" + Localization.Unrecovered_CIRC_errors_will_return_CHECK_CONDITION; + string UnrecECCNotAbort = "\t" + Localization.Unrecovered_ECC_errors_will_not_abort_the_transfer; + string UnrecCIRCNotAbort = "\t" + Localization.Unrecovered_CIRC_errors_will_not_abort_the_transfer; + + string UnrecECCAbortData = + "\t" + Localization.Unrecovered_ECC_errors_will_return_CHECK_CONDITION_and_the_uncorrected_data; + + string UnrecCIRCAbortData = + "\t" + Localization.Unrecovered_CIRC_errors_will_return_CHECK_CONDITION_and_the_uncorrected_data; + + switch(page.Parameter) + { + case 0x00: + sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbort); + + break; + case 0x01: + sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbort); + + break; + case 0x04: + sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbort); + + break; + case 0x05: + sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbort); + + break; + case 0x06: + sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbort); + + break; + case 0x07: + sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbort); + + break; + case 0x10: + sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCNotAbort); + + break; + case 0x11: + sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCNotAbort); + + break; + case 0x14: + sb.AppendLine(AllUsed + RecoveredReported + UnrecECCNotAbort); + + break; + case 0x15: + sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCNotAbort); + + break; + case 0x20: + sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbortData); + + break; + case 0x21: + sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbortData); + + break; + case 0x24: + sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbortData); + + break; + case 0x25: + sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbortData); + + break; + case 0x26: + sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbortData); + + break; + case 0x27: + sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbortData); + + break; + case 0x30: + goto case 0x10; + case 0x31: + goto case 0x11; + case 0x34: + goto case 0x14; + case 0x35: + goto case 0x15; + default: + sb.AppendFormat(Localization.Unknown_recovery_parameter_0, page.Parameter).AppendLine(); + + break; + } + + return sb.ToString(); + } + +#endregion Mode Page 0x07: Verify error recovery page for MultiMedia Devices +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/08.cs b/Aaru.Decoders/SCSI/Modes/08.cs new file mode 100644 index 000000000..205c9e100 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/08.cs @@ -0,0 +1,311 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 08.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 08h: Caching page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x08: Caching page + + /// Disconnect-reconnect page Page code 0x08 12 bytes in SCSI-2 20 bytes in SBC-1, SBC-2, SBC-3 + public struct ModePage_08 + { + /// Parameters can be saved + public bool PS; + /// true if write cache is enabled + public bool WCE; + /// Multiplication factor + public bool MF; + /// true if read cache is enabled + public bool RCD; + /// Advices on reading-cache retention priority + public byte DemandReadRetentionPrio; + /// Advices on writing-cache retention priority + public byte WriteRetentionPriority; + /// If requested read blocks are more than this, no pre-fetch is done + public ushort DisablePreFetch; + /// Minimum pre-fetch + public ushort MinimumPreFetch; + /// Maximum pre-fetch + public ushort MaximumPreFetch; + /// Upper limit on maximum pre-fetch value + public ushort MaximumPreFetchCeiling; + + /// Manual cache controlling + public bool IC; + /// Abort pre-fetch + public bool ABPF; + /// Caching analysis permitted + public bool CAP; + /// Pre-fetch over discontinuities + public bool Disc; + /// is to be used to control caching segmentation + public bool Size; + /// Force sequential write + public bool FSW; + /// Logical block cache segment size + public bool LBCSS; + /// Disable read-ahead + public bool DRA; + /// How many segments should the cache be divided upon + public byte CacheSegments; + /// How many bytes should the cache be divided upon + public ushort CacheSegmentSize; + /// How many bytes should be used as a buffer when all other cached data cannot be evicted + public uint NonCacheSegmentSize; + + public bool NV_DIS; + } + + public static ModePage_08? DecodeModePage_08(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x08) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 12) return null; + + var decoded = new ModePage_08(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.WCE |= (pageResponse[2] & 0x04) == 0x04; + decoded.MF |= (pageResponse[2] & 0x02) == 0x02; + decoded.RCD |= (pageResponse[2] & 0x01) == 0x01; + + decoded.DemandReadRetentionPrio = (byte)((pageResponse[3] & 0xF0) >> 4); + decoded.WriteRetentionPriority = (byte)(pageResponse[3] & 0x0F); + decoded.DisablePreFetch = (ushort)((pageResponse[4] << 8) + pageResponse[5]); + decoded.MinimumPreFetch = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.MaximumPreFetch = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.MaximumPreFetchCeiling = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + + if(pageResponse.Length < 20) return decoded; + + decoded.IC |= (pageResponse[2] & 0x80) == 0x80; + decoded.ABPF |= (pageResponse[2] & 0x40) == 0x40; + decoded.CAP |= (pageResponse[2] & 0x20) == 0x20; + decoded.Disc |= (pageResponse[2] & 0x10) == 0x10; + decoded.Size |= (pageResponse[2] & 0x08) == 0x08; + + decoded.FSW |= (pageResponse[12] & 0x80) == 0x80; + decoded.LBCSS |= (pageResponse[12] & 0x40) == 0x40; + decoded.DRA |= (pageResponse[12] & 0x20) == 0x20; + + decoded.CacheSegments = pageResponse[13]; + decoded.CacheSegmentSize = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + decoded.NonCacheSegmentSize = (uint)((pageResponse[17] << 16) + (pageResponse[18] << 8) + pageResponse[19]); + + decoded.NV_DIS |= (pageResponse[12] & 0x01) == 0x01; + + return decoded; + } + + public static string PrettifyModePage_08(byte[] pageResponse) => + PrettifyModePage_08(DecodeModePage_08(pageResponse)); + + public static string PrettifyModePage_08(ModePage_08? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_08 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Caching_mode_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.RCD) sb.AppendLine("\t" + Localization.Read_cache_is_enabled); + + if(page.WCE) sb.AppendLine("\t" + Localization.Write_cache_is_enabled); + + switch(page.DemandReadRetentionPrio) + { + case 0: + sb.AppendLine("\t" + Localization.Drive_does_not_distinguish_between_cached_read_data); + + break; + case 1: + sb.AppendLine("\t" + + Localization + .Data_put_by_READ_commands_should_be_evicted_from_cache_sooner_than_data_put_in_read_cache_by_other_means); + + break; + case 0xF: + sb.AppendLine("\t" + + Localization + .Data_put_by_READ_commands_should_not_be_evicted_if_there_is_data_cached_by_other_means_that_can_be_evicted); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_demand_read_retention_priority_value_0, + page.DemandReadRetentionPrio) + .AppendLine(); + + break; + } + + switch(page.WriteRetentionPriority) + { + case 0: + sb.AppendLine("\t" + Localization.Drive_does_not_distinguish_between_cached_write_data); + + break; + case 1: + sb.AppendLine("\t" + + Localization + .Data_put_by_WRITE_commands_should_be_evicted_from_cache_sooner_than_data_put_in_write_cache_by_other_means); + + break; + case 0xF: + sb.AppendLine("\t" + + Localization + .Data_put_by_WRITE_commands_should_not_be_evicted_if_there_is_data_cached_by_other_means_that_can_be_evicted); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_demand_write_retention_priority_value_0, + page.DemandReadRetentionPrio) + .AppendLine(); + + break; + } + + if(page.DRA) + sb.AppendLine("\t" + Localization.Read_ahead_is_disabled); + else + { + if(page.MF) sb.AppendLine("\t" + Localization.Pre_fetch_values_indicate_a_block_multiplier); + + if(page.DisablePreFetch == 0) + sb.AppendLine("\t" + Localization.No_pre_fetch_will_be_done); + else + { + sb.AppendFormat("\t" + Localization.Pre_fetch_will_be_done_for_READ_commands_of_0_blocks_or_less, + page.DisablePreFetch) + .AppendLine(); + + if(page.MinimumPreFetch > 0) + { + sb.AppendFormat(Localization.At_least_0_blocks_will_be_always_pre_fetched, page.MinimumPreFetch) + .AppendLine(); + } + + if(page.MaximumPreFetch > 0) + { + sb.AppendFormat("\t" + Localization.A_maximum_of_0_blocks_will_be_pre_fetched, page.MaximumPreFetch) + .AppendLine(); + } + + if(page.MaximumPreFetchCeiling > 0) + { + sb.AppendFormat("\t" + + Localization + .A_maximum_of_0_blocks_will_be_pre_fetched_even_if_it_is_commanded_to_pre_fetch_more, + page.MaximumPreFetchCeiling) + .AppendLine(); + } + + if(page.IC) + { + sb.AppendLine("\t" + + Localization + .Device_should_use_number_of_cache_segments_or_cache_segment_size_for_caching); + } + + if(page.ABPF) + sb.AppendLine("\t" + Localization.Pre_fetch_should_be_aborted_upon_receiving_a_new_command); + + if(page.CAP) sb.AppendLine("\t" + Localization.Caching_analysis_is_permitted); + + if(page.Disc) + { + sb.AppendLine("\t" + + Localization + .Pre_fetch_can_continue_across_discontinuities_such_as_cylinders_or_tracks); + } + } + } + + if(page.FSW) + sb.AppendLine("\t" + Localization.Drive_should_not_reorder_the_sequence_of_write_commands_to_be_faster); + + if(page.Size) + { + if(page.CacheSegmentSize > 0) + { + if(page.LBCSS) + { + sb.AppendFormat("\t" + Localization.Drive_cache_segments_should_be_0_blocks_long, + page.CacheSegmentSize) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization.Drive_cache_segments_should_be_0_bytes_long, + page.CacheSegmentSize) + .AppendLine(); + } + } + } + else + { + if(page.CacheSegments > 0) + { + sb.AppendFormat("\t" + Localization.Drive_should_have_0_cache_segments, page.CacheSegments) + .AppendLine(); + } + } + + if(page.NonCacheSegmentSize > 0) + { + sb.AppendFormat("\t" + + Localization + .Drive_shall_allocate_0_bytes_to_buffer_even_when_all_cached_data_cannot_be_evicted, + page.NonCacheSegmentSize) + .AppendLine(); + } + + if(page.NV_DIS) sb.AppendLine("\t" + Localization.Non_Volatile_cache_is_disabled); + + return sb.ToString(); + } + +#endregion Mode Page 0x08: Caching page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/0A.cs b/Aaru.Decoders/SCSI/Modes/0A.cs new file mode 100644 index 000000000..c6ed84489 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/0A.cs @@ -0,0 +1,478 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 0A.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 0Ah: Control mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x0A: Control mode page + + /// Control mode page Page code 0x0A 8 bytes in SCSI-2 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4, SPC-5 + public struct ModePage_0A + { + /// Parameters can be saved + public bool PS; + /// If set, target shall report log exception conditions + public bool RLEC; + /// Queue algorithm modifier + public byte QueueAlgorithm; + /// + /// If set all remaining suspended I/O processes shall be aborted after the contingent allegiance condition or + /// extended contingent allegiance condition + /// + public byte QErr; + /// Tagged queuing is disabled + public bool DQue; + /// Extended Contingent Allegiance is enabled + public bool EECA; + /// Target may issue an asynchronous event notification upon completing its initialization + public bool RAENP; + /// Target may issue an asynchronous event notification instead of a unit attention condition + public bool UAAENP; + /// Target may issue an asynchronous event notification instead of a deferred error + public bool EAENP; + /// Minimum time in ms after initialization before attempting asynchronous event notifications + public ushort ReadyAENHoldOffPeriod; + + /// Global logging target save disabled + public bool GLTSD; + /// CHECK CONDITION should be reported rather than a long busy condition + public bool RAC; + /// Software write protect is active + public bool SWP; + /// Maximum time in 100 ms units allowed to remain busy. 0xFFFF == unlimited. + public ushort BusyTimeoutPeriod; + + /// Task set type + public byte TST; + /// Tasks aborted by other initiator's actions should be terminated with TASK ABORTED + public bool TAS; + /// Action to be taken when a medium is inserted + public byte AutoloadMode; + /// Time in seconds to complete an extended self-test + public byte ExtendedSelfTestCompletionTime; + + /// All tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate + public bool TMF_ONLY; + /// + /// Device shall return descriptor format sense data when returning sense data in the same transactions as a CHECK + /// CONDITION + /// + public bool D_SENSE; + /// Unit attention interlocks control + public byte UA_INTLCK_CTRL; + /// LOGICAL BLOCK APPLICATION TAG should not be modified + public bool ATO; + + /// Protector information checking is disabled + public bool DPICZ; + /// No unit attention on release + public bool NUAR; + /// Application Tag mode page is enabled + public bool ATMPE; + /// Abort any write command without protection information + public bool RWWP; + /// Supportes block lengths and protection information + public bool SBLP; + } + + public static ModePage_0A? DecodeModePage_0A(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x0A) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 8) return null; + + var decoded = new ModePage_0A(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.RLEC |= (pageResponse[2] & 0x01) == 0x01; + + decoded.QueueAlgorithm = (byte)((pageResponse[3] & 0xF0) >> 4); + decoded.QErr = (byte)((pageResponse[3] & 0x06) >> 1); + + decoded.DQue |= (pageResponse[3] & 0x01) == 0x01; + decoded.EECA |= (pageResponse[4] & 0x80) == 0x80; + decoded.RAENP |= (pageResponse[4] & 0x04) == 0x04; + decoded.UAAENP |= (pageResponse[4] & 0x02) == 0x02; + decoded.EAENP |= (pageResponse[4] & 0x01) == 0x01; + + decoded.ReadyAENHoldOffPeriod = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + + if(pageResponse.Length < 10) return decoded; + + // SPC-1 + decoded.GLTSD |= (pageResponse[2] & 0x02) == 0x02; + decoded.RAC |= (pageResponse[4] & 0x40) == 0x40; + decoded.SWP |= (pageResponse[4] & 0x08) == 0x08; + + decoded.BusyTimeoutPeriod = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + + // SPC-2 + decoded.TST = (byte)((pageResponse[2] & 0xE0) >> 5); + decoded.TAS |= (pageResponse[4] & 0x80) == 0x80; + decoded.AutoloadMode = (byte)(pageResponse[5] & 0x07); + decoded.BusyTimeoutPeriod = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + + // SPC-3 + decoded.TMF_ONLY |= (pageResponse[2] & 0x10) == 0x10; + decoded.D_SENSE |= (pageResponse[2] & 0x04) == 0x04; + decoded.UA_INTLCK_CTRL = (byte)((pageResponse[4] & 0x30) >> 4); + decoded.TAS |= (pageResponse[5] & 0x40) == 0x40; + decoded.ATO |= (pageResponse[5] & 0x80) == 0x80; + + // SPC-5 + decoded.DPICZ |= (pageResponse[2] & 0x08) == 0x08; + decoded.NUAR |= (pageResponse[3] & 0x08) == 0x08; + decoded.ATMPE |= (pageResponse[5] & 0x20) == 0x20; + decoded.RWWP |= (pageResponse[5] & 0x10) == 0x10; + decoded.SBLP |= (pageResponse[5] & 0x08) == 0x08; + + return decoded; + } + + public static string PrettifyModePage_0A(byte[] pageResponse) => + PrettifyModePage_0A(DecodeModePage_0A(pageResponse)); + + public static string PrettifyModePage_0A(ModePage_0A? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_0A page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Control_mode_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.RLEC) sb.AppendLine("\t" + Localization.If_set_target_shall_report_log_exception_conditions); + + if(page.DQue) sb.AppendLine("\t" + Localization.Tagged_queuing_is_disabled); + + if(page.EECA) sb.AppendLine("\t" + Localization.Extended_Contingent_Allegiance_is_enabled); + + if(page.RAENP) + { + sb.AppendLine("\t" + + Localization + .Target_may_issue_an_asynchronous_event_notification_upon_completing_its_initialization); + } + + if(page.UAAENP) + { + sb.AppendLine("\t" + + Localization + .Target_may_issue_an_asynchronous_event_notification_instead_of_a_unit_attention_condition); + } + + if(page.EAENP) + { + sb.AppendLine("\t" + + Localization.Target_may_issue_an_asynchronous_event_notification_instead_of_a_deferred_error); + } + + if(page.GLTSD) sb.AppendLine("\t" + Localization.Global_logging_target_save_disabled); + + if(page.RAC) + sb.AppendLine("\t" + Localization.CHECK_CONDITION_should_be_reported_rather_than_a_long_busy_condition); + + if(page.SWP) sb.AppendLine("\t" + Localization.Software_write_protect_is_enabled); + + if(page.TAS) + { + sb.AppendLine("\t" + + Localization + .Tasks_aborted_by_other_initiator_s_actions_should_be_terminated_with_TASK_ABORTED); + } + + if(page.TMF_ONLY) + { + sb.AppendLine("\t" + + Localization + .All_tasks_received_in_nexus_with_ACA_ACTIVE_is_set_and_an_ACA_condition_is_established_shall_terminate); + } + + if(page.D_SENSE) + { + sb.AppendLine("\t" + + Localization + .Device_shall_return_descriptor_format_sense_data_when_returning_sense_data_in_the_same_transactions_as_a_CHECK_CONDITION); + } + + if(page.ATO) sb.AppendLine("\t" + Localization.LOGICAL_BLOCK_APPLICATION_TAG_should_not_be_modified); + + if(page.DPICZ) sb.AppendLine("\t" + Localization.Protector_information_checking_is_disabled); + + if(page.NUAR) sb.AppendLine("\t" + Localization.No_unit_attention_on_release); + + if(page.ATMPE) sb.AppendLine("\t" + Localization.Application_Tag_mode_page_is_enabled); + + if(page.RWWP) sb.AppendLine("\t" + Localization.Abort_any_write_command_without_protection_information); + + if(page.SBLP) sb.AppendLine("\t" + Localization.Supports_block_lengths_and_protection_information); + + switch(page.TST) + { + case 0: + sb.AppendLine("\t" + Localization.The_logical_unit_maintains_one_task_set_for_all_nexuses); + + break; + case 1: + sb.AppendLine("\t" + Localization.The_logical_unit_maintains_separate_task_sets_for_each_nexus); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_Task_set_type_0, page.TST).AppendLine(); + + break; + } + + switch(page.QueueAlgorithm) + { + case 0: + sb.AppendLine("\t" + Localization.Commands_should_be_sent_strictly_ordered); + + break; + case 1: + sb.AppendLine("\t" + Localization.Commands_can_be_reordered_in_any_manner); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_Queue_Algorithm_Modifier_0, page.QueueAlgorithm) + .AppendLine(); + + break; + } + + switch(page.QErr) + { + case 0: + sb.AppendLine("\t" + + Localization + .If_ACA_is_established_the_task_set_commands_shall_resume_after_it_is_cleared_otherwise_they_shall_terminate_with_CHECK_CONDITION); + + break; + case 1: + sb.AppendLine("\t" + + Localization + .All_the_affected_commands_in_the_task_set_shall_be_aborted_when_CHECK_CONDITION_is_returned); + + break; + case 3: + sb.AppendLine("\t" + + Localization + .Affected_commands_in_the_task_set_belonging_with_the_CHECK_CONDITION_nexus_shall_be_aborted); + + break; + default: + sb.AppendLine("\t" + Localization.Reserved_QErr_value_2_is_set); + + break; + } + + switch(page.UA_INTLCK_CTRL) + { + case 0: + sb.AppendLine("\t" + Localization.LUN_shall_clear_unit_attention_condition_reported_in_the_same_nexus); + + break; + case 2: + sb.AppendLine("\t" + + Localization.LUN_shall_not_clear_unit_attention_condition_reported_in_the_same_nexus); + + break; + case 3: + sb.AppendLine("\t" + + Localization + .LUN_shall_not_clear_unit_attention_condition_reported_in_the_same_nexus_and_shall_establish_a_unit_attention_condition_for_the_initiator); + + break; + default: + sb.AppendLine("\t" + Localization.Reserved_UA_INTLCK_CTRL_value_1_is_set); + + break; + } + + switch(page.AutoloadMode) + { + case 0: + sb.AppendLine("\t" + Localization.On_medium_insertion_it_shall_be_loaded_for_full_access); + + break; + case 1: + sb.AppendLine("\t" + + Localization.On_medium_insertion_it_shall_be_loaded_for_auxiliary_memory_access_only); + + break; + case 2: + sb.AppendLine("\t" + Localization.On_medium_insertion_it_shall_not_be_loaded); + + break; + default: + sb.AppendFormat("\t" + Localization.Reserved_autoload_mode_0_set, page.AutoloadMode).AppendLine(); + + break; + } + + if(page.ReadyAENHoldOffPeriod > 0) + { + sb.AppendFormat("\t" + + Localization._0_ms_before_attempting_asynchronous_event_notifications_after_initialization, + page.ReadyAENHoldOffPeriod) + .AppendLine(); + } + + if(page.BusyTimeoutPeriod > 0) + { + if(page.BusyTimeoutPeriod == 0xFFFF) + sb.AppendLine("\t" + Localization.There_is_no_limit_on_the_maximum_time_that_is_allowed_to_remain_busy); + else + { + sb.AppendFormat("\t" + Localization.A_maximum_of_0_ms_are_allowed_to_remain_busy, + page.BusyTimeoutPeriod * 100) + .AppendLine(); + } + } + + if(page.ExtendedSelfTestCompletionTime > 0) + { + sb.AppendFormat("\t" + Localization._0_seconds_to_complete_extended_self_test, + page.ExtendedSelfTestCompletionTime); + } + + return sb.ToString(); + } + +#endregion Mode Page 0x0A: Control mode page + +#region Mode Page 0x0A subpage 0x01: Control Extension mode page + + /// Control Extension mode page Page code 0x0A Subpage code 0x01 32 bytes in SPC-3, SPC-4, SPC-5 + public struct ModePage_0A_S01 + { + /// Parameters can be saved + public bool PS; + /// Timestamp outside this standard + public bool TCMOS; + /// SCSI precedence + public bool SCSIP; + /// Implicit Asymmetric Logical Unit Access Enabled + public bool IALUAE; + /// Initial task priority + public byte InitialPriority; + + /// Device life control disabled + public bool DLC; + /// Maximum size of SENSE data in bytes + public byte MaximumSenseLength; + } + + public static ModePage_0A_S01? DecodeModePage_0A_S01(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) != 0x40) return null; + + if((pageResponse[0] & 0x3F) != 0x0A) return null; + + if(pageResponse[1] != 0x01) return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) return null; + + if(pageResponse.Length < 32) return null; + + var decoded = new ModePage_0A_S01(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.IALUAE |= (pageResponse[4] & 0x01) == 0x01; + decoded.SCSIP |= (pageResponse[4] & 0x02) == 0x02; + decoded.TCMOS |= (pageResponse[4] & 0x04) == 0x04; + + decoded.InitialPriority = (byte)(pageResponse[5] & 0x0F); + + return decoded; + } + + public static string PrettifyModePage_0A_S01(byte[] pageResponse) => + PrettifyModePage_0A_S01(DecodeModePage_0A_S01(pageResponse)); + + public static string PrettifyModePage_0A_S01(ModePage_0A_S01? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_0A_S01 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Control_extension_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.TCMOS) + { + if(page.SCSIP) + { + sb.AppendLine("\t" + + Localization + .S01_Timestamp_can_be_initialized_by_methods_outside_of_the_SCSI_standards_but_SCSI_SET_TIMESTAMP_shall_take_precedence_over_them); + } + else + { + sb.AppendLine("\t" + + Localization.Timestamp_can_be_initialized_by_methods_outside_of_the_SCSI_standards); + } + } + + if(page.IALUAE) sb.AppendLine("\t" + Localization.Implicit_Asymmetric_Logical_Unit_Access_is_enabled); + + sb.AppendFormat("\t" + Localization.Initial_priority_is_0, page.InitialPriority).AppendLine(); + + if(page.DLC) sb.AppendLine("\t" + Localization.Device_will_not_degrade_performance_to_extend_its_life); + + if(page.MaximumSenseLength > 0) + { + sb.AppendFormat("\t" + Localization.Maximum_sense_data_would_be_0_bytes, page.MaximumSenseLength) + .AppendLine(); + } + + return sb.ToString(); + } + +#endregion Mode Page 0x0A subpage 0x01: Control Extension mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/0B.cs b/Aaru.Decoders/SCSI/Modes/0B.cs new file mode 100644 index 000000000..bae9c7827 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/0B.cs @@ -0,0 +1,119 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 0B.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 0Bh: Medium types supported page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x0B: Medium types supported page + + /// Disconnect-reconnect page Page code 0x0B 8 bytes in SCSI-2 + public struct ModePage_0B + { + /// Parameters can be saved + public bool PS; + public MediumTypes MediumType1; + public MediumTypes MediumType2; + public MediumTypes MediumType3; + public MediumTypes MediumType4; + } + + public static ModePage_0B? DecodeModePage_0B(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x0B) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 8) return null; + + var decoded = new ModePage_0B(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.MediumType1 = (MediumTypes)pageResponse[4]; + decoded.MediumType2 = (MediumTypes)pageResponse[5]; + decoded.MediumType3 = (MediumTypes)pageResponse[6]; + decoded.MediumType4 = (MediumTypes)pageResponse[7]; + + return decoded; + } + + public static string PrettifyModePage_0B(byte[] pageResponse) => + PrettifyModePage_0B(DecodeModePage_0B(pageResponse)); + + public static string PrettifyModePage_0B(ModePage_0B? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_0B page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Medium_types_supported_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.MediumType1 != MediumTypes.Default) + { + sb.AppendFormat(Localization.Supported_medium_type_one_0, GetMediumTypeDescription(page.MediumType1)) + .AppendLine(); + } + + if(page.MediumType2 != MediumTypes.Default) + { + sb.AppendFormat(Localization.Supported_medium_type_two_0, GetMediumTypeDescription(page.MediumType2)) + .AppendLine(); + } + + if(page.MediumType3 != MediumTypes.Default) + { + sb.AppendFormat(Localization.Supported_medium_type_three_0, GetMediumTypeDescription(page.MediumType3)) + .AppendLine(); + } + + if(page.MediumType4 != MediumTypes.Default) + { + sb.AppendFormat(Localization.Supported_medium_type_four_0, GetMediumTypeDescription(page.MediumType4)) + .AppendLine(); + } + + return sb.ToString(); + } + +#endregion Mode Page 0x0B: Medium types supported page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/0C.cs b/Aaru.Decoders/SCSI/Modes/0C.cs new file mode 100644 index 000000000..e8bee8a70 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/0C.cs @@ -0,0 +1,42 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 0C.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 0Ch: Notch page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Decoders.SCSI; + +public static partial class Modes +{ +#region Mode Page 0x0C: Notch page + + // TODO: Implement this page + +#endregion Mode Page 0x0C: Notch page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/0D.cs b/Aaru.Decoders/SCSI/Modes/0D.cs new file mode 100644 index 000000000..f025660bf --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/0D.cs @@ -0,0 +1,176 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 0D.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 0Dh: CD-ROM parameteres page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x0D: CD-ROM parameteres page + + /// CD-ROM parameteres page Page code 0x0D 8 bytes in SCSI-2, MMC-1, MMC-2, MMC-3 + public struct ModePage_0D + { + /// Parameters can be saved + public bool PS; + /// Time the drive shall remain in hold track state after seek or read + public byte InactivityTimerMultiplier; + /// Seconds per Minute + public ushort SecondsPerMinute; + /// Frames per Second + public ushort FramesPerSecond; + } + + public static ModePage_0D? DecodeModePage_0D(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x0D) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 8) return null; + + var decoded = new ModePage_0D(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.InactivityTimerMultiplier = (byte)(pageResponse[3] & 0xF); + decoded.SecondsPerMinute = (ushort)((pageResponse[4] << 8) + pageResponse[5]); + decoded.FramesPerSecond = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + + return decoded; + } + + public static string PrettifyModePage_0D(byte[] pageResponse) => + PrettifyModePage_0D(DecodeModePage_0D(pageResponse)); + + public static string PrettifyModePage_0D(ModePage_0D? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_0D page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_CD_ROM_parameters_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + switch(page.InactivityTimerMultiplier) + { + case 0: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_track_hold_state_a_vendor_specified_time_after_a_seek_or_read); + + break; + case 1: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_125_ms_after_a_seek_or_read); + + break; + case 2: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_250_ms_after_a_seek_or_read); + + break; + case 3: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_500_ms_after_a_seek_or_read); + + break; + case 4: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_1_second_after_a_seek_or_read); + + break; + case 5: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_2_seconds_after_a_seek_or_read); + + break; + case 6: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_4_seconds_after_a_seek_or_read); + + break; + case 7: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_8_seconds_after_a_seek_or_read); + + break; + case 8: + sb.AppendLine("\t" + + Localization.Drive_will_remain_in_track_hold_state_16_seconds_after_a_seek_or_read); + + break; + case 9: + sb.AppendLine("\t" + + Localization.Drive_will_remain_in_track_hold_state_32_seconds_after_a_seek_or_read); + + break; + case 10: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_1_minute_after_a_seek_or_read); + + break; + case 11: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_2_minutes_after_a_seek_or_read); + + break; + case 12: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_4_minutes_after_a_seek_or_read); + + break; + case 13: + sb.AppendLine("\t" + Localization.Drive_will_remain_in_track_hold_state_8_minutes_after_a_seek_or_read); + + break; + case 14: + sb.AppendLine("\t" + + Localization.Drive_will_remain_in_track_hold_state_16_minutes_after_a_seek_or_read); + + break; + case 15: + sb.AppendLine("\t" + + Localization.Drive_will_remain_in_track_hold_state_32_minutes_after_a_seek_or_read); + + break; + } + + if(page.SecondsPerMinute > 0) + sb.AppendFormat("\t" + Localization.Each_minute_has_0_seconds, page.SecondsPerMinute).AppendLine(); + + if(page.FramesPerSecond > 0) + sb.AppendFormat("\t" + Localization.Each_second_has_0_frames, page.FramesPerSecond).AppendLine(); + + return sb.ToString(); + } + +#endregion Mode Page 0x0D: CD-ROM parameteres page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/0E.cs b/Aaru.Decoders/SCSI/Modes/0E.cs new file mode 100644 index 000000000..4c0a8267b --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/0E.cs @@ -0,0 +1,259 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 0E.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 0Eh: CD-ROM audio control parameters page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x0E: CD-ROM audio control parameters page + + /// CD-ROM audio control parameters Page code 0x0E 16 bytes in SCSI-2, MMC-1, MMC-2, MMC-3 + public struct ModePage_0E + { + /// Parameters can be saved + public bool PS; + /// Return status as soon as playback operation starts + public bool Immed; + /// Stop on track crossing + public bool SOTC; + /// Indicates is valid + public bool APRVal; + /// Multiplier for + public byte LBAFormat; + /// LBAs per second of audio + public ushort BlocksPerSecondOfAudio; + /// Channels output on this port + public byte OutputPort0ChannelSelection; + /// Volume level for this port + public byte OutputPort0Volume; + /// Channels output on this port + public byte OutputPort1ChannelSelection; + /// Volume level for this port + public byte OutputPort1Volume; + /// Channels output on this port + public byte OutputPort2ChannelSelection; + /// Volume level for this port + public byte OutputPort2Volume; + /// Channels output on this port + public byte OutputPort3ChannelSelection; + /// Volume level for this port + public byte OutputPort3Volume; + } + + public static ModePage_0E? DecodeModePage_0E(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x0E) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 16) return null; + + var decoded = new ModePage_0E(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.Immed |= (pageResponse[2] & 0x04) == 0x04; + decoded.SOTC |= (pageResponse[2] & 0x02) == 0x02; + decoded.APRVal |= (pageResponse[5] & 0x80) == 0x80; + decoded.LBAFormat = (byte)(pageResponse[5] & 0x0F); + decoded.BlocksPerSecondOfAudio = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.OutputPort0ChannelSelection = (byte)(pageResponse[8] & 0x0F); + decoded.OutputPort0Volume = pageResponse[9]; + decoded.OutputPort1ChannelSelection = (byte)(pageResponse[10] & 0x0F); + decoded.OutputPort1Volume = pageResponse[11]; + decoded.OutputPort2ChannelSelection = (byte)(pageResponse[12] & 0x0F); + decoded.OutputPort2Volume = pageResponse[13]; + decoded.OutputPort3ChannelSelection = (byte)(pageResponse[14] & 0x0F); + decoded.OutputPort3Volume = pageResponse[15]; + + return decoded; + } + + public static string PrettifyModePage_0E(byte[] pageResponse) => + PrettifyModePage_0E(DecodeModePage_0E(pageResponse)); + + public static string PrettifyModePage_0E(ModePage_0E? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_0E page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_CD_ROM_audio_control_parameters_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + sb.AppendLine(page.Immed + ? "\t" + Localization.Drive_will_return_from_playback_command_immediately + : "\t" + Localization.Drive_will_return_from_playback_command_when_playback_ends); + + if(page.SOTC) sb.AppendLine("\t" + Localization.Drive_will_stop_playback_on_track_end); + + if(page.APRVal) + { + double blocks; + + if(page.LBAFormat == 8) + blocks = page.BlocksPerSecondOfAudio * (1 / 256f); + else + blocks = page.BlocksPerSecondOfAudio; + + sb.AppendFormat("\t" + Localization.There_are_0_blocks_per_each_second_of_audio, blocks).AppendLine(); + } + + if(page.OutputPort0ChannelSelection > 0) + { + sb.Append("\t" + Localization.Output_port_0_has_channels); + + if((page.OutputPort0ChannelSelection & 0x01) == 0x01) sb.Append("0 "); + + if((page.OutputPort0ChannelSelection & 0x02) == 0x02) sb.Append("1 "); + + if((page.OutputPort0ChannelSelection & 0x04) == 0x04) sb.Append("2 "); + + if((page.OutputPort0ChannelSelection & 0x08) == 0x08) sb.Append("3 "); + + switch(page.OutputPort0Volume) + { + case 0: + sb.AppendLine(Localization.muted); + + break; + case 0xFF: + sb.AppendLine(Localization.at_maximum_volume); + + break; + default: + sb.AppendFormat(Localization.at_volume_0, page.OutputPort0Volume).AppendLine(); + + break; + } + } + + if(page.OutputPort1ChannelSelection > 0) + { + sb.Append("\t" + Localization.Output_port_1_has_channels); + + if((page.OutputPort1ChannelSelection & 0x01) == 0x01) sb.Append("0 "); + + if((page.OutputPort1ChannelSelection & 0x02) == 0x02) sb.Append("1 "); + + if((page.OutputPort1ChannelSelection & 0x04) == 0x04) sb.Append("2 "); + + if((page.OutputPort1ChannelSelection & 0x08) == 0x08) sb.Append("3 "); + + switch(page.OutputPort1Volume) + { + case 0: + sb.AppendLine(Localization.muted); + + break; + case 0xFF: + sb.AppendLine(Localization.at_maximum_volume); + + break; + default: + sb.AppendFormat(Localization.at_volume_0, page.OutputPort1Volume).AppendLine(); + + break; + } + } + + if(page.OutputPort2ChannelSelection > 0) + { + sb.Append("\t" + Localization.Output_port_2_has_channels); + + if((page.OutputPort2ChannelSelection & 0x01) == 0x01) sb.Append("0 "); + + if((page.OutputPort2ChannelSelection & 0x02) == 0x02) sb.Append("1 "); + + if((page.OutputPort2ChannelSelection & 0x04) == 0x04) sb.Append("2 "); + + if((page.OutputPort2ChannelSelection & 0x08) == 0x08) sb.Append("3 "); + + switch(page.OutputPort2Volume) + { + case 0: + sb.AppendLine(Localization.muted); + + break; + case 0xFF: + sb.AppendLine(Localization.at_maximum_volume); + + break; + default: + sb.AppendFormat(Localization.at_volume_0, page.OutputPort2Volume).AppendLine(); + + break; + } + } + + if(page.OutputPort3ChannelSelection <= 0) return sb.ToString(); + + sb.Append("\t" + Localization.Output_port_3_has_channels); + + if((page.OutputPort3ChannelSelection & 0x01) == 0x01) sb.Append("0 "); + + if((page.OutputPort3ChannelSelection & 0x02) == 0x02) sb.Append("1 "); + + if((page.OutputPort3ChannelSelection & 0x04) == 0x04) sb.Append("2 "); + + if((page.OutputPort3ChannelSelection & 0x08) == 0x08) sb.Append("3 "); + + switch(page.OutputPort3Volume) + { + case 0: + sb.AppendLine(Localization.muted); + + break; + case 0xFF: + sb.AppendLine(Localization.at_maximum_volume); + + break; + default: + sb.AppendFormat(Localization.at_volume_0, page.OutputPort3Volume).AppendLine(); + + break; + } + + return sb.ToString(); + } + +#endregion Mode Page 0x0E: CD-ROM audio control parameters page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/0F.cs b/Aaru.Decoders/SCSI/Modes/0F.cs new file mode 100644 index 000000000..9d95f12d6 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/0F.cs @@ -0,0 +1,203 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 0F.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 0Fh: Data compression page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x0F: Data compression page + + /// Data compression page Page code 0x0F 16 bytes in SSC-1, SSC-2, SSC-3 + public struct ModePage_0F + { + /// Parameters can be saved + public bool PS; + /// Data compression enabled + public bool DCE; + /// Data compression capable + public bool DCC; + /// Data decompression enabled + public bool DDE; + /// Report exception on decompression + public byte RED; + /// Compression algorithm + public uint CompressionAlgo; + /// Decompression algorithm + public uint DecompressionAlgo; + } + + public static ModePage_0F? DecodeModePage_0F(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x0F) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 16) return null; + + var decoded = new ModePage_0F(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.DCE |= (pageResponse[2] & 0x80) == 0x80; + decoded.DCC |= (pageResponse[2] & 0x40) == 0x40; + decoded.DDE |= (pageResponse[3] & 0x80) == 0x80; + decoded.RED = (byte)((pageResponse[3] & 0x60) >> 5); + + decoded.CompressionAlgo = + (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) + pageResponse[7]); + + decoded.DecompressionAlgo = (uint)((pageResponse[8] << 24) + + (pageResponse[9] << 16) + + (pageResponse[10] << 8) + + pageResponse[11]); + + return decoded; + } + + public static string PrettifyModePage_0F(byte[] pageResponse) => + PrettifyModePage_0F(DecodeModePage_0F(pageResponse)); + + public static string PrettifyModePage_0F(ModePage_0F? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_0F page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Data_compression_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.DCC) + { + sb.AppendLine("\t" + Localization.Drive_supports_data_compression); + + if(page.DCE) + { + sb.Append("\t" + Localization.Data_compression_is_enabled_with); + + switch(page.CompressionAlgo) + { + case 3: + sb.AppendLine(Localization.IBM_ALDC_with_512_byte_buffer); + + break; + case 4: + sb.AppendLine(Localization.IBM_ALDC_with_1024_byte_buffer); + + break; + case 5: + sb.AppendLine(Localization.IBM_ALDC_with_2048_byte_buffer); + + break; + case 0x10: + sb.AppendLine(Localization.IBM_IDRC); + + break; + case 0x20: + sb.AppendLine(Localization.DCLZ); + + break; + case 0xFF: + sb.AppendLine(Localization.an_unregistered_compression_algorithm); + + break; + default: + sb.AppendFormat(Localization.an_unknown_algorithm_coded_0, page.CompressionAlgo).AppendLine(); + + break; + } + } + + if(page.DDE) + { + sb.AppendLine("\t" + Localization.Data_decompression_is_enabled); + + if(page.DecompressionAlgo == 0) + sb.AppendLine("\t" + Localization.Last_data_read_was_uncompressed); + else + { + sb.Append("\t" + Localization.Last_data_read_was_compressed_with_); + + switch(page.CompressionAlgo) + { + case 3: + sb.AppendLine(Localization.IBM_ALDC_with_512_byte_buffer); + + break; + case 4: + sb.AppendLine(Localization.IBM_ALDC_with_1024_byte_buffer); + + break; + case 5: + sb.AppendLine(Localization.IBM_ALDC_with_2048_byte_buffer); + + break; + case 0x10: + sb.AppendLine(Localization.IBM_IDRC); + + break; + case 0x20: + sb.AppendLine(Localization.DCLZ); + + break; + case 0xFF: + sb.AppendLine(Localization.an_unregistered_compression_algorithm); + + break; + default: + sb.AppendFormat(Localization.an_unknown_algorithm_coded_0, page.CompressionAlgo) + .AppendLine(); + + break; + } + } + } + + sb.AppendFormat("\t" + Localization.Report_exception_on_compression_is_set_to_0, page.RED).AppendLine(); + } + else + sb.AppendLine("\t" + Localization.Drive_does_not_support_data_compression); + + return sb.ToString(); + } + +#endregion Mode Page 0x0F: Data compression page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/10.cs b/Aaru.Decoders/SCSI/Modes/10.cs new file mode 100644 index 000000000..33ed836e8 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/10.cs @@ -0,0 +1,148 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 10.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 10h: XOR control mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x10: XOR control mode page + + /// XOR control mode page Page code 0x10 24 bytes in SBC-1, SBC-2 + public struct ModePage_10 + { + /// Parameters can be saved + public bool PS; + /// Disables XOR operations + public bool XORDIS; + /// Maximum transfer length in blocks for a XOR command + public uint MaxXorWrite; + /// Maximum regenerate length in blocks + public uint MaxRegenSize; + /// Maximum transfer length in blocks for READ during a rebuild + public uint MaxRebuildRead; + /// Minimum time in ms between READs during a rebuild + public ushort RebuildDelay; + } + + public static ModePage_10? DecodeModePage_10(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x10) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 24) return null; + + var decoded = new ModePage_10(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.XORDIS |= (pageResponse[2] & 0x02) == 0x02; + + decoded.MaxXorWrite = + (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) + pageResponse[7]); + + decoded.MaxRegenSize = (uint)((pageResponse[12] << 24) + + (pageResponse[13] << 16) + + (pageResponse[14] << 8) + + pageResponse[15]); + + decoded.MaxRebuildRead = (uint)((pageResponse[16] << 24) + + (pageResponse[17] << 16) + + (pageResponse[18] << 8) + + pageResponse[19]); + + decoded.RebuildDelay = (ushort)((pageResponse[22] << 8) + pageResponse[23]); + + return decoded; + } + + public static string PrettifyModePage_10(byte[] pageResponse) => + PrettifyModePage_10(DecodeModePage_10(pageResponse)); + + public static string PrettifyModePage_10(ModePage_10? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_10 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_XOR_control_mode_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.XORDIS) + sb.AppendLine("\t" + Localization.XOR_operations_are_disabled); + else + { + if(page.MaxXorWrite > 0) + { + sb.AppendFormat("\t" + Localization.Drive_accepts_a_maximum_of_0_blocks_in_a_single_XOR_WRITE_command, + page.MaxXorWrite) + .AppendLine(); + } + + if(page.MaxRegenSize > 0) + { + sb.AppendFormat("\t" + Localization.Drive_accepts_a_maximum_of_0_blocks_in_a_REGENERATE_command, + page.MaxRegenSize) + .AppendLine(); + } + + if(page.MaxRebuildRead > 0) + { + sb.AppendFormat("\t" + + Localization.Drive_accepts_a_maximum_of_0_blocks_in_a_READ_command_during_rebuild, + page.MaxRebuildRead) + .AppendLine(); + } + + if(page.RebuildDelay > 0) + { + sb.AppendFormat("\t" + Localization.Drive_needs_a_minimum_of_0_ms_between_READ_commands_during_rebuild, + page.RebuildDelay) + .AppendLine(); + } + } + + return sb.ToString(); + } + +#endregion Mode Page 0x10: XOR control mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/10_SSC.cs b/Aaru.Decoders/SCSI/Modes/10_SSC.cs new file mode 100644 index 000000000..122648a00 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/10_SSC.cs @@ -0,0 +1,331 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 10_SSC.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 10h: Device configuration page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x10: Device configuration page + + /// Device configuration page Page code 0x10 16 bytes in SCSI-2, SSC-1, SSC-2, SSC-3 + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public struct ModePage_10_SSC + { + /// Parameters can be saved + public bool PS; + /// Used in mode select to change partition to one specified in + public bool CAP; + /// Used in mode select to change format to one specified in + public bool CAF; + /// Active format, vendor-specific + public byte ActiveFormat; + /// Current logical partition + public byte ActivePartition; + /// How full the buffer shall be before writing to medium + public byte WriteBufferFullRatio; + /// How empty the buffer shall be before reading more data from the medium + public byte ReadBufferEmptyRatio; + /// Delay in 100 ms before buffered data is forcefully written to the medium even before buffer is full + public ushort WriteDelayTime; + /// Drive supports recovering data from buffer + public bool DBR; + /// Medium has block IDs + public bool BIS; + /// Drive recognizes and reports setmarks + public bool RSmk; + /// Drive selects best speed + public bool AVC; + /// If drive should stop pre-reading on filemarks + public byte SOCF; + /// If set, recovered buffer data is LIFO, otherwise, FIFO + public bool RBO; + /// Report early warnings + public bool REW; + /// Inter-block gap + public byte GapSize; + /// End-of-Data format + public byte EODDefined; + /// EOD generation enabled + public bool EEG; + /// Synchronize data to medium on early warning + public bool SEW; + /// Bytes to reduce buffer size on early warning + public uint BufferSizeEarlyWarning; + /// Selected data compression algorithm + public byte SelectedCompression; + + /// Soft write protect + public bool SWP; + /// Associated write protect + public bool ASOCWP; + /// Persistent write protect + public bool PERSWP; + /// Permanent write protect + public bool PRMWP; + + public bool BAML; + public bool BAM; + public byte RewindOnReset; + + /// How drive shall respond to detection of compromised WORM medium integrity + public byte WTRE; + /// Respond to commands only if a reservation exists + public bool OIR; + } + + public static ModePage_10_SSC? DecodeModePage_10_SSC(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x10) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 16) return null; + + var decoded = new ModePage_10_SSC(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.CAP |= (pageResponse[2] & 0x40) == 0x40; + decoded.CAF |= (pageResponse[2] & 0x20) == 0x20; + decoded.ActiveFormat = (byte)(pageResponse[2] & 0x1F); + decoded.ActivePartition = pageResponse[3]; + decoded.WriteBufferFullRatio = pageResponse[4]; + decoded.ReadBufferEmptyRatio = pageResponse[5]; + decoded.WriteDelayTime = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.DBR |= (pageResponse[8] & 0x80) == 0x80; + decoded.BIS |= (pageResponse[8] & 0x40) == 0x40; + decoded.RSmk |= (pageResponse[8] & 0x20) == 0x20; + decoded.AVC |= (pageResponse[8] & 0x10) == 0x10; + decoded.RBO |= (pageResponse[8] & 0x02) == 0x02; + decoded.REW |= (pageResponse[8] & 0x01) == 0x01; + decoded.EEG |= (pageResponse[10] & 0x10) == 0x10; + decoded.SEW |= (pageResponse[10] & 0x08) == 0x08; + decoded.SOCF = (byte)((pageResponse[8] & 0x0C) >> 2); + + decoded.BufferSizeEarlyWarning = (uint)((pageResponse[11] << 16) + (pageResponse[12] << 8) + pageResponse[13]); + + decoded.SelectedCompression = pageResponse[14]; + + decoded.SWP |= (pageResponse[10] & 0x04) == 0x04; + decoded.ASOCWP |= (pageResponse[15] & 0x04) == 0x04; + decoded.PERSWP |= (pageResponse[15] & 0x02) == 0x02; + decoded.PRMWP |= (pageResponse[15] & 0x01) == 0x01; + + decoded.BAML |= (pageResponse[10] & 0x02) == 0x02; + decoded.BAM |= (pageResponse[10] & 0x01) == 0x01; + + decoded.RewindOnReset = (byte)((pageResponse[15] & 0x18) >> 3); + + decoded.OIR |= (pageResponse[15] & 0x20) == 0x20; + decoded.WTRE = (byte)((pageResponse[15] & 0xC0) >> 6); + + return decoded; + } + + public static string PrettifyModePage_10_SSC(byte[] pageResponse) => + PrettifyModePage_10_SSC(DecodeModePage_10_SSC(pageResponse)); + + public static string PrettifyModePage_10_SSC(ModePage_10_SSC? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_10_SSC page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Device_configuration_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + sb.AppendFormat("\t" + Localization.Active_format_0, page.ActiveFormat).AppendLine(); + sb.AppendFormat("\t" + Localization.Active_partition_0, page.ActivePartition).AppendLine(); + + sb.AppendFormat("\t" + Localization.Write_buffer_shall_have_a_full_ratio_of_0_before_being_flushed_to_medium, + page.WriteBufferFullRatio) + .AppendLine(); + + sb.AppendFormat("\t" + + Localization.Read_buffer_shall_have_an_empty_ratio_of_0_before_more_data_is_read_from_medium, + page.ReadBufferEmptyRatio) + .AppendLine(); + + sb.AppendFormat("\t" + + Localization + .Drive_will_delay_0_ms_before_buffered_data_is_forcefully_written_to_the_medium_even_before_buffer_is_full, + page.WriteDelayTime * 100) + .AppendLine(); + + if(page.DBR) + { + sb.AppendLine("\t" + Localization.Drive_supports_recovering_data_from_buffer); + + sb.AppendLine(page.RBO + ? "\t" + Localization.Recovered_buffer_data_comes_in_LIFO_order + : "\t" + Localization.Recovered_buffer_data_comes_in_FIFO_order); + } + + if(page.BIS) sb.AppendLine("\t" + Localization.Medium_supports_block_IDs); + + if(page.RSmk) sb.AppendLine("\t" + Localization.Drive_reports_setmarks); + + switch(page.SOCF) + { + case 0: + sb.AppendLine("\t" + Localization.Drive_will_pre_read_until_buffer_is_full); + + break; + case 1: + sb.AppendLine("\t" + Localization.Drive_will_pre_read_until_one_filemark_is_detected); + + break; + case 2: + sb.AppendLine("\t" + Localization.Drive_will_pre_read_until_two_filemark_is_detected); + + break; + case 3: + sb.AppendLine("\t" + Localization.Drive_will_pre_read_until_three_filemark_is_detected); + + break; + } + + if(page.REW) + { + sb.AppendLine("\t" + Localization.Drive_reports_early_warnings); + + if(page.SEW) sb.AppendLine("\t" + Localization.Drive_will_synchronize_buffer_to_medium_on_early_warnings); + } + + switch(page.GapSize) + { + case 0: + break; + case 1: + sb.AppendLine("\t" + Localization.Inter_block_gap_is_long_enough_to_support_update_in_place); + + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + sb.AppendFormat("\t" + Localization.Inter_block_gap_is_0_times_the_device_defined_gap_size, + page.GapSize) + .AppendLine(); + + break; + default: + sb.AppendFormat("\t" + Localization.Inter_block_gap_is_unknown_value_0, page.GapSize).AppendLine(); + + break; + } + + if(page.EEG) sb.AppendLine("\t" + Localization.Drive_generates_end_of_data); + + switch(page.SelectedCompression) + { + case 0: + sb.AppendLine("\t" + Localization.Drive_does_not_use_compression); + + break; + case 1: + sb.AppendLine("\t" + Localization.Drive_uses_default_compression); + + break; + default: + sb.AppendFormat("\t" + Localization.Drive_uses_unknown_compression_0, page.SelectedCompression) + .AppendLine(); + + break; + } + + if(page.SWP) sb.AppendLine("\t" + Localization.Software_write_protect_is_enabled); + + if(page.ASOCWP) sb.AppendLine("\t" + Localization.Associated_write_protect_is_enabled); + + if(page.PERSWP) sb.AppendLine("\t" + Localization.Persistent_write_protect_is_enabled); + + if(page.PRMWP) sb.AppendLine("\t" + Localization.Permanent_write_protect_is_enabled); + + if(page.BAML) + { + sb.AppendLine(page.BAM + ? "\t" + Localization.Drive_operates_using_explicit_address_mode + : "\t" + Localization.Drive_operates_using_implicit_address_mode); + } + + switch(page.RewindOnReset) + { + case 1: + sb.AppendLine("\t" + Localization.Drive_shall_position_to_beginning_of_default_data_partition_on_reset); + + break; + case 2: + sb.AppendLine("\t" + Localization.Drive_shall_maintain_its_position_on_reset); + + break; + } + + switch(page.WTRE) + { + case 1: + sb.AppendLine("\t" + Localization.Drive_will_do_nothing_on_WORM_tampered_medium); + + break; + case 2: + sb.AppendLine("\t" + Localization.Drive_will_return_CHECK_CONDITION_on_WORM_tampered_medium); + + break; + } + + if(page.OIR) + sb.AppendLine("\t" + Localization.Drive_will_only_respond_to_commands_if_it_has_received_a_reservation); + + return sb.ToString(); + } + +#endregion Mode Page 0x10: Device configuration page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/11.cs b/Aaru.Decoders/SCSI/Modes/11.cs new file mode 100644 index 000000000..6f590397f --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/11.cs @@ -0,0 +1,276 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 11.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 11h: Medium partition page (1). +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x11: Medium partition page (1) + + public enum PartitionSizeUnitOfMeasures : byte + { + /// Partition size is measures in bytes + Bytes = 0, + /// Partition size is measures in Kilobytes + Kilobytes = 1, + /// Partition size is measures in Megabytes + Megabytes = 2, + /// Partition size is 10eUNITS bytes + Exponential = 3 + } + + public enum MediumFormatRecognitionValues : byte + { + /// Logical unit is incapable of format or partition recognition + Incapable = 0, + /// Logical unit is capable of format recognition only + FormatCapable = 1, + /// Logical unit is capable of partition recognition only + PartitionCapable = 2, + /// Logical unit is capable of both format and partition recognition + Capable = 3 + } + + /// Medium partition page(1) Page code 0x11 + public struct ModePage_11 + { + /// Parameters can be saved + public bool PS; + /// Maximum number of additional partitions supported + public byte MaxAdditionalPartitions; + /// Number of additional partitions to be defined for a volume + public byte AdditionalPartitionsDefined; + /// Device defines partitions based on its fixed definition + public bool FDP; + /// Device should divide medium according to the additional partitions defined field using sizes defined by device + public bool SDP; + /// Initiator defines number and size of partitions + public bool IDP; + /// Defines the unit on which the partition sizes are defined + public PartitionSizeUnitOfMeasures PSUM; + public bool POFM; + public bool CLEAR; + public bool ADDP; + /// Defines the capabilities for the unit to recognize media partitions and format + public MediumFormatRecognitionValues MediumFormatRecognition; + public byte PartitionUnits; + /// Array of partition sizes in units defined above + public ushort[] PartitionSizes; + } + + public static ModePage_11? DecodeModePage_11(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x11) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 8) return null; + + var decoded = new ModePage_11(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.MaxAdditionalPartitions = pageResponse[2]; + decoded.AdditionalPartitionsDefined = pageResponse[3]; + decoded.FDP |= (pageResponse[4] & 0x80) == 0x80; + decoded.SDP |= (pageResponse[4] & 0x40) == 0x40; + decoded.IDP |= (pageResponse[4] & 0x20) == 0x20; + decoded.PSUM = (PartitionSizeUnitOfMeasures)((pageResponse[4] & 0x18) >> 3); + decoded.POFM |= (pageResponse[4] & 0x04) == 0x04; + decoded.CLEAR |= (pageResponse[4] & 0x02) == 0x02; + decoded.ADDP |= (pageResponse[4] & 0x01) == 0x01; + decoded.PartitionUnits = (byte)(pageResponse[6] & 0x0F); + decoded.MediumFormatRecognition = (MediumFormatRecognitionValues)pageResponse[5]; + decoded.PartitionSizes = new ushort[(pageResponse.Length - 8) / 2]; + + for(var i = 8; i < pageResponse.Length; i += 2) + { + decoded.PartitionSizes[(i - 8) / 2] = (ushort)(pageResponse[i] << 8); + decoded.PartitionSizes[(i - 8) / 2] += pageResponse[i + 1]; + } + + return decoded; + } + + public static string PrettifyModePage_11(byte[] pageResponse) => + PrettifyModePage_11(DecodeModePage_11(pageResponse)); + + public static string PrettifyModePage_11(ModePage_11? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_11 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_medium_partition_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + sb.AppendFormat("\t" + Localization._0_maximum_additional_partitions, page.MaxAdditionalPartitions) + .AppendLine(); + + sb.AppendFormat("\t" + Localization._0_additional_partitions_defined, page.AdditionalPartitionsDefined) + .AppendLine(); + + if(page.FDP) sb.AppendLine("\t" + Localization.Partitions_are_fixed_under_device_definitions); + + if(page.SDP) + { + sb.AppendLine("\t" + + Localization.Number_of_partitions_can_be_defined_but_their_size_is_defined_by_the_device); + } + + if(page.IDP) sb.AppendLine("\t" + Localization.Number_and_size_of_partitions_can_be_manually_defined); + + if(page.POFM) + { + sb.AppendLine("\t" + + Localization + .Partition_parameters_will_not_be_applied_until_a_FORMAT_MEDIUM_command_is_received); + } + + switch(page.CLEAR) + { + case false when !page.ADDP: + sb.AppendLine("\t" + + Localization.Device_may_erase_any_or_all_partitions_on_MODE_SELECT_for_partitioning); + + break; + case true when !page.ADDP: + sb.AppendLine("\t" + Localization.Device_shall_erase_all_partitions_on_MODE_SELECT_for_partitioning); + + break; + case false: + sb.AppendLine("\t" + Localization.Device_shall_not_erase_any_partition_on_MODE_SELECT_for_partitioning); + + break; + default: + sb.AppendLine("\t" + + Localization + .Device_shall_erase_all_partitions_differing_on_size_on_MODE_SELECT_for_partitioning); + + break; + } + + string measure; + + switch(page.PSUM) + { + case PartitionSizeUnitOfMeasures.Bytes: + sb.AppendLine("\t" + Localization.Partitions_are_defined_in_bytes); + measure = Localization.bytes; + + break; + case PartitionSizeUnitOfMeasures.Kilobytes: + sb.AppendLine("\t" + Localization.Partitions_are_defined_in_kilobytes); + measure = Localization.kilobytes; + + break; + case PartitionSizeUnitOfMeasures.Megabytes: + sb.AppendLine("\t" + Localization.Partitions_are_defined_in_megabytes); + measure = Localization.megabytes; + + break; + case PartitionSizeUnitOfMeasures.Exponential: + sb.AppendFormat("\t" + Localization.Partitions_are_defined_in_units_of_0_bytes, + Math.Pow(10, page.PartitionUnits)) + .AppendLine(); + + measure = string.Format(Localization.units_of_0_bytes, Math.Pow(10, page.PartitionUnits)); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_partition_size_unit_code_0, (byte)page.PSUM).AppendLine(); + measure = Localization.units; + + break; + } + + switch(page.MediumFormatRecognition) + { + case MediumFormatRecognitionValues.Capable: + sb.AppendLine("\t" + Localization.Device_is_capable_of_recognizing_both_medium_partitions_and_format); + + break; + case MediumFormatRecognitionValues.FormatCapable: + sb.AppendLine("\t" + Localization.Device_is_capable_of_recognizing_medium_format); + + break; + case MediumFormatRecognitionValues.PartitionCapable: + sb.AppendLine("\t" + Localization.Device_is_capable_of_recognizing_medium_partitions); + + break; + case MediumFormatRecognitionValues.Incapable: + sb.AppendLine("\t" + + Localization.Device_is_not_capable_of_recognizing_neither_medium_partitions_nor_format); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_medium_recognition_code_0, + (byte)page.MediumFormatRecognition) + .AppendLine(); + + break; + } + + sb.AppendFormat("\t" + Localization.Medium_has_defined_0_partitions, page.PartitionSizes.Length).AppendLine(); + + for(var i = 0; i < page.PartitionSizes.Length; i++) + { + if(page.PartitionSizes[i] == 0) + { + if(page.PartitionSizes.Length == 1) + sb.AppendLine("\t" + Localization.Device_recognizes_one_single_partition_spanning_whole_medium); + else + sb.AppendFormat("\t" + Localization.Partition_0_runs_for_rest_of_medium, i).AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization.Partition_0_is_1_2_long, i, page.PartitionSizes[i], measure) + .AppendLine(); + } + } + + return sb.ToString(); + } + +#endregion Mode Page 0x11: Medium partition page (1) +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/12_13_14.cs b/Aaru.Decoders/SCSI/Modes/12_13_14.cs new file mode 100644 index 000000000..d254cfd69 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/12_13_14.cs @@ -0,0 +1,105 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 12_13_14.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGEs 12h, 13h, 14h: Medium partition page (2-4). +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Pages 0x12, 0x13, 0x14: Medium partition page (2-4) + + /// Medium partition page (2-4) Page codes 0x12, 0x13 and 0x14 + public struct ModePage_12_13_14 + { + /// Parameters can be saved + public bool PS; + /// Array of partition sizes in units defined in mode page 11 + public ushort[] PartitionSizes; + } + + public static ModePage_12_13_14? DecodeModePage_12_13_14(byte[] pageResponse) + { + if(pageResponse == null) return null; + + if((pageResponse[0] & 0x40) == 0x40) return null; + + if((pageResponse[0] & 0x3F) != 0x12 && (pageResponse[0] & 0x3F) != 0x13 && (pageResponse[0] & 0x3F) != 0x14) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 2) return null; + + var decoded = new ModePage_12_13_14(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.PartitionSizes = new ushort[(pageResponse.Length - 2) / 2]; + + for(var i = 2; i < pageResponse.Length; i += 2) + { + decoded.PartitionSizes[(i - 2) / 2] = (ushort)(pageResponse[i] << 8); + decoded.PartitionSizes[(i - 2) / 2] += pageResponse[i + 1]; + } + + return decoded; + } + + public static string PrettifyModePage_12_13_14(byte[] pageResponse) => + PrettifyModePage_12_13_14(DecodeModePage_12_13_14(pageResponse)); + + public static string PrettifyModePage_12_13_14(ModePage_12_13_14? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_12_13_14 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_medium_partition_page_extra); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + sb.AppendFormat("\t" + Localization.Medium_has_defined_0_partitions, page.PartitionSizes.Length).AppendLine(); + + for(var i = 0; i < page.PartitionSizes.Length; i++) + sb.AppendFormat("\t" + Localization.Partition_0_is_1_units_long, i, page.PartitionSizes[i]).AppendLine(); + + return sb.ToString(); + } + +#endregion Mode Pages 0x12, 0x13, 0x14: Medium partition page (2-4) +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/1A.cs b/Aaru.Decoders/SCSI/Modes/1A.cs new file mode 100644 index 000000000..331e2608f --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/1A.cs @@ -0,0 +1,272 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 1A.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 1Ah: Power condition page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x1A: Power condition page + + /// Power condition page Page code 0x1A 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4 40 bytes in SPC-5 + public struct ModePage_1A + { + /// Parameters can be saved + public bool PS; + /// Idle timer activated + public bool Idle; + /// Standby timer activated + public bool Standby; + /// Idle timer + public uint IdleTimer; + /// Standby timer + public uint StandbyTimer; + + /// Interactions between background functions and power management + public byte PM_BG_Precedence; + /// Standby timer Y activated + public bool Standby_Y; + /// Idle timer B activated + public bool Idle_B; + /// Idle timer C activated + public bool Idle_C; + /// Idle timer B + public uint IdleTimer_B; + /// Idle timer C + public uint IdleTimer_C; + /// Standby timer Y + public uint StandbyTimer_Y; + public byte CCF_Idle; + public byte CCF_Standby; + public byte CCF_Stopped; + } + + public static ModePage_1A? DecodeModePage_1A(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x1A) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 12) return null; + + var decoded = new ModePage_1A(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.Standby |= (pageResponse[3] & 0x01) == 0x01; + decoded.Idle |= (pageResponse[3] & 0x02) == 0x02; + + decoded.IdleTimer = (uint)((pageResponse[4] << 24) + + (pageResponse[5] << 16) + + (pageResponse[6] << 8) + + pageResponse[7]); + + decoded.StandbyTimer = (uint)((pageResponse[8] << 24) + + (pageResponse[9] << 16) + + (pageResponse[10] << 8) + + pageResponse[11]); + + if(pageResponse.Length < 40) return decoded; + + decoded.PM_BG_Precedence = (byte)((pageResponse[2] & 0xC0) >> 6); + decoded.Standby_Y |= (pageResponse[2] & 0x01) == 0x01; + decoded.Idle_B |= (pageResponse[3] & 0x04) == 0x04; + decoded.Idle_C |= (pageResponse[3] & 0x08) == 0x08; + + decoded.IdleTimer_B = (uint)((pageResponse[12] << 24) + + (pageResponse[13] << 16) + + (pageResponse[14] << 8) + + pageResponse[15]); + + decoded.IdleTimer_C = (uint)((pageResponse[16] << 24) + + (pageResponse[17] << 16) + + (pageResponse[18] << 8) + + pageResponse[19]); + + decoded.StandbyTimer_Y = (uint)((pageResponse[20] << 24) + + (pageResponse[21] << 16) + + (pageResponse[22] << 8) + + pageResponse[23]); + + decoded.CCF_Idle = (byte)((pageResponse[39] & 0xC0) >> 6); + decoded.CCF_Standby = (byte)((pageResponse[39] & 0x30) >> 4); + decoded.CCF_Stopped = (byte)((pageResponse[39] & 0x0C) >> 2); + + return decoded; + } + + public static string PrettifyModePage_1A(byte[] pageResponse) => + PrettifyModePage_1A(DecodeModePage_1A(pageResponse)); + + public static string PrettifyModePage_1A(ModePage_1A? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_1A page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Power condition page:"); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page is { Standby: true, StandbyTimer: > 0 } or { Standby_Y: true, StandbyTimer_Y: > 0 }) + { + if(page is { Standby: true, StandbyTimer: > 0 }) + sb.AppendFormat("\t" + "Standby timer Z is set to {0} ms", page.StandbyTimer * 100).AppendLine(); + + if(page is { Standby_Y: true, StandbyTimer_Y: > 0 }) + sb.AppendFormat("\t" + "Standby timer Y is set to {0} ms", page.StandbyTimer_Y * 100).AppendLine(); + } + else + sb.AppendLine("\t" + "Drive will not enter standby mode"); + + if(page is { Idle : true, IdleTimer : > 0 } + or { Idle_B: true, IdleTimer_B: > 0 } + or { Idle_C: true, IdleTimer_C: > 0 }) + { + if(page is { Idle: true, IdleTimer: > 0 }) + sb.AppendFormat("\t" + "Idle timer A is set to {0} ms", page.IdleTimer * 100).AppendLine(); + + if(page is { Idle_B: true, IdleTimer_B: > 0 }) + sb.AppendFormat("\t" + "Idle timer B is set to {0} ms", page.IdleTimer_B * 100).AppendLine(); + + if(page is { Idle_C: true, IdleTimer_C: > 0 }) + sb.AppendFormat("\t" + "Idle timer C is set to {0} ms", page.IdleTimer_C * 100).AppendLine(); + } + else + sb.AppendLine("\t" + "Drive will not enter idle mode"); + + switch(page.PM_BG_Precedence) + { + case 0: + break; + case 1: + sb.AppendLine("\t" + + "Performing background functions take precedence over maintaining low power conditions"); + + break; + case 2: + sb.AppendLine("\t" + + "Maintaining low power conditions take precedence over performing background functions"); + + break; + } + + return sb.ToString(); + } + +#endregion Mode Page 0x1A: Power condition page + +#region Mode Page 0x1A subpage 0x01: Power Consumption mode page + + /// Power Consumption mode page Page code 0x1A Subpage code 0x01 16 bytes in SPC-5 + public struct ModePage_1A_S01 + { + /// Parameters can be saved + public bool PS; + /// Active power level + public byte ActiveLevel; + /// Power Consumption VPD identifier in use + public byte PowerConsumptionIdentifier; + } + + public static ModePage_1A_S01? DecodeModePage_1A_S01(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) != 0x40) return null; + + if((pageResponse[0] & 0x3F) != 0x1A) return null; + + if(pageResponse[1] != 0x01) return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) return null; + + if(pageResponse.Length < 16) return null; + + var decoded = new ModePage_1A_S01(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.ActiveLevel = (byte)(pageResponse[6] & 0x03); + decoded.PowerConsumptionIdentifier = pageResponse[7]; + + return decoded; + } + + public static string PrettifyModePage_1A_S01(byte[] pageResponse) => + PrettifyModePage_1A_S01(DecodeModePage_1A_S01(pageResponse)); + + public static string PrettifyModePage_1A_S01(ModePage_1A_S01? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_1A_S01 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Power_Consumption_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + switch(page.ActiveLevel) + { + case 0: + sb.AppendFormat("\t" + + Localization + .Device_power_consumption_is_dictated_by_identifier_0_of_Power_Consumption_VPD, + page.PowerConsumptionIdentifier) + .AppendLine(); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_is_in_highest_relative_power_consumption_level); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_is_in_intermediate_relative_power_consumption_level); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_is_in_lowest_relative_power_consumption_level); + + break; + } + + return sb.ToString(); + } + +#endregion Mode Page 0x1A subpage 0x01: Power Consumption mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/1B.cs b/Aaru.Decoders/SCSI/Modes/1B.cs new file mode 100644 index 000000000..27b27810d --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/1B.cs @@ -0,0 +1,113 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 1B.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 1Bh: Removable Block Access Capabilities page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x1B: Removable Block Access Capabilities page + + /// Removable Block Access Capabilities page Page code 0x1B 12 bytes in INF-8070 + public struct ModePage_1B + { + /// Parameters can be saved + public bool PS; + /// Supports reporting progress of format + public bool SRFP; + /// Non-CD Optical Device + public bool NCD; + /// Phase change dual device supporting a CD and a Non-CD Optical devices + public bool SML; + /// Total number of LUNs + public byte TLUN; + /// System Floppy Type device + public bool SFLP; + } + + public static ModePage_1B? DecodeModePage_1B(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x1B) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 12) return null; + + var decoded = new ModePage_1B(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.SFLP |= (pageResponse[2] & 0x80) == 0x80; + decoded.SRFP |= (pageResponse[2] & 0x40) == 0x40; + decoded.NCD |= (pageResponse[3] & 0x80) == 0x80; + decoded.SML |= (pageResponse[3] & 0x40) == 0x40; + + decoded.TLUN = (byte)(pageResponse[3] & 0x07); + + return decoded; + } + + public static string PrettifyModePage_1B(byte[] pageResponse) => + PrettifyModePage_1B(DecodeModePage_1B(pageResponse)); + + public static string PrettifyModePage_1B(ModePage_1B? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_1B page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Removable_Block_Access_Capabilities_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.SFLP) sb.AppendLine("\t" + Localization.Drive_can_be_used_as_a_system_floppy_device); + + if(page.SRFP) sb.AppendLine("\t" + Localization.Drive_supports_reporting_progress_of_format); + + if(page.NCD) sb.AppendLine("\t" + Localization.Drive_is_a_Non_CD_Optical_Device); + + if(page.SML) sb.AppendLine("\t" + Localization.Device_is_a_dual_device_supporting_CD_and_Non_CD_Optical); + + if(page.TLUN > 0) sb.AppendFormat("\t" + Localization.Drive_supports_0_LUNs, page.TLUN).AppendLine(); + + return sb.ToString(); + } + +#endregion Mode Page 0x1B: Removable Block Access Capabilities page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/1C.cs b/Aaru.Decoders/SCSI/Modes/1C.cs new file mode 100644 index 000000000..3c95700f7 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/1C.cs @@ -0,0 +1,324 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 1C.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 1Ch: Informational exceptions control page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x1C: Informational exceptions control page + + /// Informational exceptions control page Page code 0x1C 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4 + public struct ModePage_1C + { + /// Parameters can be saved + public bool PS; + /// Informational exception operations should not affect performance + public bool Perf; + /// Disable informational exception operations + public bool DExcpt; + /// Create a test device failure at next interval time + public bool Test; + /// Log informational exception conditions + public bool LogErr; + /// Method of reporting informational exceptions + public byte MRIE; + /// 100 ms period to report an informational exception condition + public uint IntervalTimer; + /// How many times to report informational exceptions + public uint ReportCount; + + /// Enable background functions + public bool EBF; + /// Warning reporting enabled + public bool EWasc; + + /// Enable reporting of background self-test errors + public bool EBACKERR; + } + + public static ModePage_1C? DecodeModePage_1C(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x1C) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 8) return null; + + var decoded = new ModePage_1C(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.Perf |= (pageResponse[2] & 0x80) == 0x80; + decoded.DExcpt |= (pageResponse[2] & 0x08) == 0x08; + decoded.Test |= (pageResponse[2] & 0x04) == 0x04; + decoded.LogErr |= (pageResponse[2] & 0x01) == 0x01; + + decoded.MRIE = (byte)(pageResponse[3] & 0x0F); + + decoded.IntervalTimer = + (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) + pageResponse[7]); + + decoded.EBF |= (pageResponse[2] & 0x20) == 0x20; + decoded.EWasc |= (pageResponse[2] & 0x10) == 0x10; + + decoded.EBACKERR |= (pageResponse[2] & 0x02) == 0x02; + + if(pageResponse.Length >= 12) + { + decoded.ReportCount = (uint)((pageResponse[8] << 24) + + (pageResponse[9] << 16) + + (pageResponse[10] << 8) + + pageResponse[11]); + } + + return decoded; + } + + public static string PrettifyModePage_1C(byte[] pageResponse) => + PrettifyModePage_1C(DecodeModePage_1C(pageResponse)); + + public static string PrettifyModePage_1C(ModePage_1C? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_1C page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Informational_exceptions_control_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.DExcpt) + sb.AppendLine("\t" + Localization.Informational_exceptions_are_disabled); + else + { + sb.AppendLine("\t" + Localization.Informational_exceptions_are_enabled); + + switch(page.MRIE) + { + case 0: + sb.AppendLine("\t" + Localization.No_reporting_of_informational_exception_condition); + + break; + case 1: + sb.AppendLine("\t" + Localization.Asynchronous_event_reporting_of_informational_exceptions); + + break; + case 2: + sb.AppendLine("\t" + Localization.Generate_unit_attention_on_informational_exceptions); + + break; + case 3: + sb.AppendLine("\t" + + Localization.Conditionally_generate_recovered_error_on_informational_exceptions); + + break; + case 4: + sb.AppendLine("\t" + + Localization.Unconditionally_generate_recovered_error_on_informational_exceptions); + + break; + case 5: + sb.AppendLine("\t" + Localization.Generate_no_sense_on_informational_exceptions); + + break; + case 6: + sb.AppendLine("\t" + Localization.Only_report_informational_exception_condition_on_request); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_method_of_reporting_0, page.MRIE).AppendLine(); + + break; + } + + if(page.Perf) + { + sb.AppendLine("\t" + + Localization.Informational_exceptions_reporting_should_not_affect_drive_performance); + } + + if(page.Test) sb.AppendLine("\t" + Localization.A_test_informational_exception_will_raise_on_next_timer); + + if(page.LogErr) sb.AppendLine("\t" + Localization.Drive_shall_log_informational_exception_conditions); + + if(page.IntervalTimer > 0) + { + if(page.IntervalTimer == 0xFFFFFFFF) + sb.AppendLine("\t" + Localization.Timer_interval_is_vendor_specific); + else + sb.AppendFormat("\t" + Localization.Timer_interval_is_0_ms, page.IntervalTimer * 100).AppendLine(); + } + + if(page.ReportCount > 0) + { + sb.AppendFormat("\t" + + Localization.Informational_exception_conditions_will_be_reported_a_maximum_of_0_times, + page.ReportCount); + } + } + + if(page.EWasc) sb.AppendLine("\t" + Localization.Warning_reporting_is_enabled); + + if(page.EBF) sb.AppendLine("\t" + Localization.Background_functions_are_enabled); + + if(page.EBACKERR) sb.AppendLine("\t" + Localization.Drive_will_report_background_self_test_errors); + + return sb.ToString(); + } + +#endregion Mode Page 0x1C: Informational exceptions control page + +#region Mode Page 0x1C subpage 0x01: Background Control mode page + + /// Background Control mode page Page code 0x1A Subpage code 0x01 16 bytes in SPC-5 + public struct ModePage_1C_S01 + { + /// Parameters can be saved + public bool PS; + /// Suspend on log full + public bool S_L_Full; + /// Log only when intervention required + public bool LOWIR; + /// Enable background medium scan + public bool En_Bms; + /// Enable background pre-scan + public bool En_Ps; + /// Time in hours between background medium scans + public ushort BackgroundScanInterval; + /// Maximum time in hours for a background pre-scan to complete + public ushort BackgroundPrescanTimeLimit; + /// Minimum time in ms being idle before resuming a background scan + public ushort MinIdleBeforeBgScan; + /// Maximum time in ms to start processing commands while performing a background scan + public ushort MaxTimeSuspendBgScan; + } + + public static ModePage_1C_S01? DecodeModePage_1C_S01(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) != 0x40) return null; + + if((pageResponse[0] & 0x3F) != 0x1C) return null; + + if(pageResponse[1] != 0x01) return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) return null; + + if(pageResponse.Length < 16) return null; + + var decoded = new ModePage_1C_S01(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.S_L_Full |= (pageResponse[4] & 0x04) == 0x04; + decoded.LOWIR |= (pageResponse[4] & 0x02) == 0x02; + decoded.En_Bms |= (pageResponse[4] & 0x01) == 0x01; + decoded.En_Ps |= (pageResponse[5] & 0x01) == 0x01; + + decoded.BackgroundScanInterval = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.BackgroundPrescanTimeLimit = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.MinIdleBeforeBgScan = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.MaxTimeSuspendBgScan = (ushort)((pageResponse[12] << 8) + pageResponse[13]); + + return decoded; + } + + public static string PrettifyModePage_1C_S01(byte[] pageResponse) => + PrettifyModePage_1C_S01(DecodeModePage_1C_S01(pageResponse)); + + public static string PrettifyModePage_1C_S01(ModePage_1C_S01? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_1C_S01 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Background_Control_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.S_L_Full) sb.AppendLine("\t" + Localization.Background_scans_will_be_halted_if_log_is_full); + + if(page.LOWIR) + sb.AppendLine("\t" + Localization.Background_scans_will_only_be_logged_if_they_require_intervention); + + if(page.En_Bms) sb.AppendLine("\t" + Localization.Background_medium_scans_are_enabled); + + if(page.En_Ps) sb.AppendLine("\t" + Localization.Background_pre_scans_are_enabled); + + if(page.BackgroundScanInterval > 0) + { + sb.AppendFormat("\t" + + Localization + ._0__hours_shall_be_between_the_start_of_a_background_scan_operation_and_the_next, + page.BackgroundScanInterval) + .AppendLine(); + } + + if(page.BackgroundPrescanTimeLimit > 0) + { + sb.AppendFormat("\t" + Localization.Background_pre_scan_operations_can_take_a_maximum_of_0_hours, + page.BackgroundPrescanTimeLimit) + .AppendLine(); + } + + if(page.MinIdleBeforeBgScan > 0) + { + sb.AppendFormat("\t" + + Localization + .At_least_0_ms_must_be_idle_before_resuming_a_suspended_background_scan_operation, + page.MinIdleBeforeBgScan) + .AppendLine(); + } + + if(page.MaxTimeSuspendBgScan > 0) + { + sb.AppendFormat("\t" + + Localization + .At_most_0_ms_must_be_before_suspending_a_background_scan_operation_and_processing_received_commands, + page.MaxTimeSuspendBgScan) + .AppendLine(); + } + + return sb.ToString(); + } + +#endregion Mode Page 0x1C subpage 0x01: Background Control mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/1C_SFF.cs b/Aaru.Decoders/SCSI/Modes/1C_SFF.cs new file mode 100644 index 000000000..a1a8d03cc --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/1C_SFF.cs @@ -0,0 +1,201 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 1C_SFF.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 1Ch: Timer & Protect page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x1C: Timer & Protect page + + /// Timer & Protect page Page code 0x1C 8 bytes in INF-8070 + public struct ModePage_1C_SFF + { + /// Parameters can be saved + public bool PS; + /// Time the device shall remain in the current state after seek, read or write operation + public byte InactivityTimeMultiplier; + /// Disabled until power cycle + public bool DISP; + /// Software Write Protect until Power-down + public bool SWPP; + } + + public static ModePage_1C_SFF? DecodeModePage_1C_SFF(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x1C) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 8) return null; + + var decoded = new ModePage_1C_SFF(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.DISP |= (pageResponse[2] & 0x02) == 0x02; + decoded.SWPP |= (pageResponse[3] & 0x01) == 0x01; + + decoded.InactivityTimeMultiplier = (byte)(pageResponse[3] & 0x0F); + + return decoded; + } + + public static string PrettifyModePage_1C_SFF(byte[] pageResponse) => + PrettifyModePage_1C_SFF(DecodeModePage_1C_SFF(pageResponse)); + + public static string PrettifyModePage_1C_SFF(ModePage_1C_SFF? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_1C_SFF page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Timer_Protect_page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.DISP) sb.AppendLine("\t" + Localization.Drive_is_disabled_until_power_is_cycled); + + if(page.SWPP) sb.AppendLine("\t" + Localization.Drive_is_software_write_protected_until_powered_down); + + switch(page.InactivityTimeMultiplier) + { + case 0: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_a_vendor_specified_time_after_a_seek_read_or_write_operation); + + break; + case 1: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_125_ms_after_a_seek_read_or_write_operation); + + break; + case 2: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_250_ms_after_a_seek_read_or_write_operation); + + break; + case 3: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_500_ms_after_a_seek_read_or_write_operation); + + break; + case 4: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_1_second_after_a_seek_read_or_write_operation); + + break; + case 5: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_2_seconds_after_a_seek_read_or_write_operation); + + break; + case 6: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_4_seconds_after_a_seek_read_or_write_operation); + + break; + case 7: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_8_seconds_after_a_seek_read_or_write_operation); + + break; + case 8: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_16_seconds_after_a_seek_read_or_write_operation); + + break; + case 9: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_32_seconds_after_a_seek_read_or_write_operation); + + break; + case 10: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_1_minute_after_a_seek_read_or_write_operation); + + break; + case 11: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_2_minutes_after_a_seek_read_or_write_operation); + + break; + case 12: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_4_minutes_after_a_seek_read_or_write_operation); + + break; + case 13: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_8_minutes_after_a_seek_read_or_write_operation); + + break; + case 14: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_16_minutes_after_a_seek_read_or_write_operation); + + break; + case 15: + sb.AppendLine("\t" + + Localization + .Drive_will_remain_in_same_status_32_minutes_after_a_seek_read_or_write_operation); + + break; + } + + return sb.ToString(); + } + +#endregion Mode Page 0x1C: Timer & Protect page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/1D.cs b/Aaru.Decoders/SCSI/Modes/1D.cs new file mode 100644 index 000000000..af6beb8aa --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/1D.cs @@ -0,0 +1,136 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 1D.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 1Dh: Medium Configuration Mode Page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Mode Page 0x1D: Medium Configuration Mode Page + + public struct ModePage_1D + { + /// Parameters can be saved + public bool PS; + public bool WORMM; + public byte WormModeLabelRestrictions; + public byte WormModeFilemarkRestrictions; + } + + public static ModePage_1D? DecodeModePage_1D(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x1D) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 32) return null; + + var decoded = new ModePage_1D(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.WORMM |= (pageResponse[2] & 0x01) == 0x01; + decoded.WormModeLabelRestrictions = pageResponse[4]; + decoded.WormModeFilemarkRestrictions = pageResponse[5]; + + return decoded; + } + + public static string PrettifyModePage_1D(byte[] pageResponse) => + PrettifyModePage_1D(DecodeModePage_1D(pageResponse)); + + public static string PrettifyModePage_1D(ModePage_1D? modePage) + { + if(!modePage.HasValue) return null; + + ModePage_1D page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Medium_Configuration_Mode_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.WORMM) sb.AppendLine("\t" + Localization.Drive_is_operating_in_WORM_mode); + + switch(page.WormModeLabelRestrictions) + { + case 0: + sb.AppendLine("\t" + Localization.Drive_does_not_allow_any_logical_blocks_to_be_overwritten); + + break; + case 1: + sb.AppendLine("\t" + Localization.Drive_allows_a_tape_header_to_be_overwritten); + + break; + case 2: + sb.AppendLine("\t" + Localization.Drive_allows_all_format_labels_to_be_overwritten); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_WORM_mode_label_restrictions_code_0, + page.WormModeLabelRestrictions) + .AppendLine(); + + break; + } + + switch(page.WormModeFilemarkRestrictions) + { + case 2: + sb.AppendLine("\t" + + "Drive allows any number of filemarks immediately preceding EOD to be overwritten except filemark closes to BOP"); + + break; + case 3: + sb.AppendLine("\t" + + "Drive allows any number of filemarks immediately preceding EOD to be overwritten"); + + break; + default: + sb.AppendFormat("\t" + "Unknown WORM mode filemark restrictions code {0}", + page.WormModeLabelRestrictions) + .AppendLine(); + + break; + } + + return sb.ToString(); + } + +#endregion Mode Page 0x1D: Medium Configuration Mode Page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/21_Certance.cs b/Aaru.Decoders/SCSI/Modes/21_Certance.cs new file mode 100644 index 000000000..8740e8fde --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/21_Certance.cs @@ -0,0 +1,208 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 21_Certance.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Certance MODE PAGE 21h: Drive Capabilities Control Mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Certance Mode Page 0x21: Drive Capabilities Control Mode page + + public struct Certance_ModePage_21 + { + /// Parameters can be saved + public bool PS; + public byte OperatingSystemsSupport; + public byte FirmwareTestControl2; + public byte ExtendedPOSTMode; + public byte InquiryStringControl; + public byte FirmwareTestControl; + public byte DataCompressionControl; + public bool HostUnloadOverride; + public byte AutoUnloadMode; + } + + public static Certance_ModePage_21? DecodeCertanceModePage_21(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x21) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length != 9) return null; + + var decoded = new Certance_ModePage_21(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.OperatingSystemsSupport = pageResponse[2]; + decoded.FirmwareTestControl2 = pageResponse[3]; + decoded.ExtendedPOSTMode = pageResponse[4]; + decoded.InquiryStringControl = pageResponse[5]; + decoded.FirmwareTestControl = pageResponse[6]; + decoded.DataCompressionControl = pageResponse[7]; + decoded.HostUnloadOverride |= (pageResponse[8] & 0x80) == 0x80; + decoded.AutoUnloadMode = (byte)(pageResponse[8] & 0x7F); + + return decoded; + } + + public static string PrettifyCertanceModePage_21(byte[] pageResponse) => + PrettifyCertanceModePage_21(DecodeCertanceModePage_21(pageResponse)); + + public static string PrettifyCertanceModePage_21(Certance_ModePage_21? modePage) + { + if(!modePage.HasValue) return null; + + Certance_ModePage_21 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Certance_Drive_Capabilities_Control_Mode_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + switch(page.OperatingSystemsSupport) + { + case 0: + sb.AppendLine("\t" + Localization.Operating_systems_support_is_standard_LTO); + + break; + default: + sb.AppendFormat("\t" + Localization.Operating_systems_support_is_unknown_code_0, + page.OperatingSystemsSupport) + .AppendLine(); + + break; + } + + if(page.FirmwareTestControl == page.FirmwareTestControl2) + { + switch(page.FirmwareTestControl) + { + case 0: + sb.AppendLine("\t" + Localization.Factory_test_code_is_disabled); + + break; + case 1: + sb.AppendLine("\t" + Localization.Factory_test_code_1_is_disabled); + + break; + case 2: + sb.AppendLine("\t" + Localization.Factory_test_code_2_is_disabled); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_factory_test_code_0, page.FirmwareTestControl) + .AppendLine(); + + break; + } + } + + switch(page.ExtendedPOSTMode) + { + case 0: + sb.AppendLine("\t" + Localization.Power_On_Self_Test_is_enabled); + + break; + case 1: + sb.AppendLine("\t" + Localization.Power_On_Self_Test_is_disabled); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_Power_On_Self_Test_code_0, page.ExtendedPOSTMode) + .AppendLine(); + + break; + } + + switch(page.DataCompressionControl) + { + case 0: + sb.AppendLine("\t" + Localization.Compression_is_controlled_using_mode_pages_0Fh_and_10h); + + break; + case 1: + sb.AppendLine("\t" + Localization.Compression_is_enabled_and_not_controllable); + + break; + case 2: + sb.AppendLine("\t" + Localization.Compression_is_disabled_and_not_controllable); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_compression_control_code_0, page.DataCompressionControl) + .AppendLine(); + + break; + } + + if(page.HostUnloadOverride) sb.AppendLine("\t" + Localization.SCSI_UNLOAD_command_will_not_eject_the_cartridge); + + sb.Append("\t" + + Localization + .How_should_tapes_be_unloaded_in_a_power_cycle_tape_incompatibility_firmware_download_or_cleaning_end); + + switch(page.AutoUnloadMode) + { + case 0: + sb.AppendLine("\t" + Localization.Tape_will_stay_threaded_at_beginning); + + break; + case 1: + sb.AppendLine("\t" + Localization.Tape_will_be_unthreaded); + + break; + case 2: + sb.AppendLine("\t" + Localization.Tape_will_be_unthreaded_and_unloaded); + + break; + case 3: + sb.AppendLine("\t" + Localization.Data_tapes_will_be_threaded_at_beginning_rest_will_be_unloaded); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_auto_unload_code_0, page.AutoUnloadMode).AppendLine(); + + break; + } + + return sb.ToString(); + } + +#endregion Certance Mode Page 0x21: Drive Capabilities Control Mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/22_Certance.cs b/Aaru.Decoders/SCSI/Modes/22_Certance.cs new file mode 100644 index 000000000..f8892c9eb --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/22_Certance.cs @@ -0,0 +1,194 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 22_Certance.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Certance MODE PAGE 22h: Interface Control Mode Page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static partial class Modes +{ +#region Certance Mode Page 0x22: Interface Control Mode Page + + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public struct Certance_ModePage_22 + { + /// Parameters can be saved + public bool PS; + public byte BaudRate; + public byte CmdFwd; + public bool StopBits; + public byte Alerts; + public byte PortATransportType; + public byte PortAPresentSelectionID; + public byte NextSelectionID; + public byte JumperedSelectionID; + public byte TargetInitiatedBusControl; + public bool PortAEnabled; + public bool PortAEnabledOnPower; + } + + public static Certance_ModePage_22? DecodeCertanceModePage_22(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x22) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length != 16) return null; + + var decoded = new Certance_ModePage_22(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.BaudRate = pageResponse[2]; + decoded.CmdFwd = (byte)((pageResponse[3] & 0x18) >> 3); + decoded.StopBits |= (pageResponse[3] & 0x04) == 0x04; + decoded.CmdFwd = (byte)(pageResponse[3] & 0x03); + decoded.PortATransportType = pageResponse[4]; + decoded.PortAPresentSelectionID = pageResponse[7]; + decoded.NextSelectionID = pageResponse[12]; + decoded.JumperedSelectionID = pageResponse[13]; + decoded.TargetInitiatedBusControl = pageResponse[14]; + decoded.PortAEnabled |= (pageResponse[15] & 0x10) == 0x10; + decoded.PortAEnabledOnPower |= (pageResponse[15] & 0x04) == 0x04; + + return decoded; + } + + public static string PrettifyCertanceModePage_22(byte[] pageResponse) => + PrettifyCertanceModePage_22(DecodeCertanceModePage_22(pageResponse)); + + public static string PrettifyCertanceModePage_22(Certance_ModePage_22? modePage) + { + if(!modePage.HasValue) return null; + + Certance_ModePage_22 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Certance_Interface_Control_Mode_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + switch(page.BaudRate) + { + case 0: + case 1: + case 2: + sb.AppendLine("\t" + Localization.Library_interface_will_operate_at_9600_baud_on_next_reset); + + break; + case 3: + sb.AppendLine("\t" + Localization.Library_interface_will_operate_at_19200_baud_on_next_reset); + + break; + case 4: + sb.AppendLine("\t" + Localization.Library_interface_will_operate_at_38400_baud_on_next_reset); + + break; + case 5: + sb.AppendLine("\t" + Localization.Library_interface_will_operate_at_57600_baud_on_next_reset); + + break; + case 6: + sb.AppendLine("\t" + Localization.Library_interface_will_operate_at_115200_baud_on_next_reset); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_library_interface_baud_rate_code_0, page.BaudRate) + .AppendLine(); + + break; + } + + sb.AppendLine(page.StopBits + ? Localization.Library_interface_transmits_2_stop_bits_per_byte + : Localization.Library_interface_transmits_1_stop_bits_per_byte); + + switch(page.CmdFwd) + { + case 0: + sb.AppendLine("\t" + Localization.Command_forwarding_is_disabled); + + break; + case 1: + sb.AppendLine("\t" + Localization.Command_forwarding_is_enabled); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_command_forwarding_code_0, page.CmdFwd).AppendLine(); + + break; + } + + switch(page.PortATransportType) + { + case 0: + sb.AppendLine("\t" + Localization.Port_A_link_is_down); + + break; + case 3: + sb.AppendLine("\t" + Localization.Port_A_uses_Parallel_SCSI_Ultra_160_interface); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_port_A_transport_type_code_0, page.PortATransportType) + .AppendLine(); + + break; + } + + if(page.PortATransportType > 0) + sb.AppendFormat("\t" + Localization.Drive_responds_to_SCSI_ID_0, page.PortAPresentSelectionID).AppendLine(); + + sb.AppendFormat("\t" + Localization.Drive_will_respond_to_SCSI_ID_0_on_Port_A_enabling, page.NextSelectionID) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Drive_jumpers_choose_SCSI_ID_0, page.JumperedSelectionID).AppendLine(); + + sb.AppendLine(page.PortAEnabled + ? "\t" + Localization.SCSI_port_is_enabled + : "\t" + Localization.SCSI_port_is_disabled); + + sb.AppendLine(page.PortAEnabledOnPower + ? "\t" + Localization.SCSI_port_will_be_enabled_on_next_power_up + : "\t" + Localization.SCSI_port_will_be_disabled_on_next_power_up); + + return sb.ToString(); + } + +#endregion Certance Mode Page 0x22: Interface Control Mode Page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/24_IBM.cs b/Aaru.Decoders/SCSI/Modes/24_IBM.cs new file mode 100644 index 000000000..c196ca290 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/24_IBM.cs @@ -0,0 +1,103 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 24_IBM.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes IBM MODE PAGE 24h: Drive Capabilities Control Mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region IBM Mode Page 0x24: Drive Capabilities Control Mode page + + public struct IBM_ModePage_24 + { + /// Parameters can be saved + public bool PS; + public byte ModeControl; + public byte VelocitySetting; + public bool EncryptionEnabled; + public bool EncryptionCapable; + } + + public static IBM_ModePage_24? DecodeIBMModePage_24(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x24) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length != 8) return null; + + var decoded = new IBM_ModePage_24(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.ModeControl = pageResponse[2]; + decoded.VelocitySetting = pageResponse[3]; + decoded.EncryptionEnabled |= (pageResponse[7] & 0x08) == 0x08; + decoded.EncryptionCapable |= (pageResponse[7] & 0x01) == 0x01; + + return decoded; + } + + public static string PrettifyIBMModePage_24(byte[] pageResponse) => + PrettifyIBMModePage_24(DecodeIBMModePage_24(pageResponse)); + + public static string PrettifyIBMModePage_24(IBM_ModePage_24? modePage) + { + if(!modePage.HasValue) return null; + + IBM_ModePage_24 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.IBM_Vendor_Specific_Control_Mode_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + sb.AppendFormat("\t" + Localization.Vendor_specific_mode_control_0, page.ModeControl); + sb.AppendFormat("\t" + Localization.Vendor_specific_velocity_setting_0, page.VelocitySetting); + + if(!page.EncryptionCapable) return sb.ToString(); + + sb.AppendLine("\t" + Localization.Drive_supports_encryption); + + if(page.EncryptionEnabled) sb.AppendLine("\t" + Localization.Drive_has_encryption_enabled); + + return sb.ToString(); + } + +#endregion IBM Mode Page 0x24: Drive Capabilities Control Mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/2A.cs b/Aaru.Decoders/SCSI/Modes/2A.cs new file mode 100644 index 000000000..702dbd26e --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/2A.cs @@ -0,0 +1,276 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 2A.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI MODE PAGE 2Ah: CD-ROM capabilities page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.Structs.Devices.SCSI.Modes; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static partial class Modes +{ +#region Mode Page 0x2A: CD-ROM capabilities page + + public static string PrettifyModePage_2A(byte[] pageResponse) => + PrettifyModePage_2A(ModePage_2A.Decode(pageResponse)); + + public static string PrettifyModePage_2A(ModePage_2A modePage) + { + if(modePage is null) return null; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_CD_ROM_capabilities_page); + + if(modePage.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(modePage.AudioPlay) sb.AppendLine("\t" + Localization.Drive_can_play_audio); + + if(modePage.Mode2Form1) sb.AppendLine("\t" + Localization.Drive_can_read_sectors_in_Mode_2_Form_1_format); + + if(modePage.Mode2Form2) sb.AppendLine("\t" + Localization.Drive_can_read_sectors_in_Mode_2_Form_2_format); + + if(modePage.MultiSession) sb.AppendLine("\t" + Localization.Drive_supports_multi_session_discs_and_or_Photo_CD); + + if(modePage.CDDACommand) sb.AppendLine("\t" + Localization.Drive_can_read_digital_audio); + + if(modePage.AccurateCDDA) sb.AppendLine("\t" + Localization.Drive_can_continue_from_streaming_loss); + + if(modePage.Subchannel) + sb.AppendLine("\t" + Localization.Drive_can_read_uncorrected_and_interleaved_R_W_subchannels); + + if(modePage.DeinterlaveSubchannel) + sb.AppendLine("\t" + Localization.Drive_can_read__deinterleave_and_correct_R_W_subchannels); + + if(modePage.C2Pointer) sb.AppendLine("\t" + Localization.Drive_supports_C2_pointers); + + if(modePage.UPC) sb.AppendLine("\t" + Localization.Drive_can_read_Media_Catalogue_Number); + + if(modePage.ISRC) sb.AppendLine("\t" + Localization.Drive_can_read_ISRC); + + switch(modePage.LoadingMechanism) + { + case 0: + sb.AppendLine("\t" + Localization.Drive_uses_media_caddy); + + break; + case 1: + sb.AppendLine("\t" + Localization.Drive_uses_a_tray); + + break; + case 2: + sb.AppendLine("\t" + Localization.Drive_is_pop_up); + + break; + case 4: + sb.AppendLine("\t" + Localization.Drive_is_a_changer_with_individually_changeable_discs); + + break; + case 5: + sb.AppendLine("\t" + Localization.Drive_is_a_changer_using_cartridges); + + break; + default: + sb.AppendFormat("\t" + Localization.Drive_uses_unknown_loading_mechanism_type__0_, + modePage.LoadingMechanism) + .AppendLine(); + + break; + } + + if(modePage.Lock) sb.AppendLine("\t" + Localization.Drive_can_lock_media); + + if(modePage.PreventJumper) + { + sb.AppendLine("\t" + Localization.Drive_power_ups_locked); + + sb.AppendLine(modePage.LockState + ? "\t" + Localization.Drive_is_locked__media_cannot_be_ejected_or_inserted + : "\t" + Localization.Drive_is_not_locked__media_can_be_ejected_and_inserted); + } + else + { + sb.AppendLine(modePage.LockState + ? "\t" + + Localization.Drive_is_locked__media_cannot_be_ejected__but_if_empty__can_be_inserted + : "\t" + Localization.Drive_is_not_locked__media_can_be_ejected_and_inserted); + } + + if(modePage.Eject) sb.AppendLine("\t" + Localization.Drive_can_eject_media); + + if(modePage.SeparateChannelMute) sb.AppendLine("\t" + Localization.Each_channel_can_be_muted_independently); + + if(modePage.SeparateChannelVolume) + sb.AppendLine("\t" + Localization.Each_channel_s_volume_can_be_controlled_independently); + + if(modePage.SupportedVolumeLevels > 0) + { + sb.AppendFormat("\t" + Localization.Drive_supports_0_volume_levels, modePage.SupportedVolumeLevels) + .AppendLine(); + } + + if(modePage.BufferSize > 0) + sb.AppendFormat("\t" + Localization.Drive_has_0_Kbyte_of_buffer, modePage.BufferSize).AppendLine(); + + if(modePage.MaximumSpeed > 0) + { + sb.AppendFormat("\t" + Localization.Drive_maximum_reading_speed_is_0_Kbyte_sec, modePage.MaximumSpeed) + .AppendLine(); + } + + if(modePage.CurrentSpeed > 0) + { + sb.AppendFormat("\t" + Localization.Drive_current_reading_speed_is_0_Kbyte_sec, modePage.CurrentSpeed) + .AppendLine(); + } + + if(modePage.ReadCDR) + { + sb.AppendLine(modePage.WriteCDR + ? "\t" + Localization.Drive_can_read_and_write_CD_R + : "\t" + Localization.Drive_can_read_CD_R); + + if(modePage.Method2) sb.AppendLine("\t" + Localization.Drive_supports_reading_CD_R_packet_media); + } + + if(modePage.ReadCDRW) + { + sb.AppendLine(modePage.WriteCDRW + ? "\t" + Localization.Drive_can_read_and_write_CD_RW + : "\t" + Localization.Drive_can_read_CD_RW); + } + + if(modePage.ReadDVDROM) sb.AppendLine("\t" + Localization.Drive_can_read_DVD_ROM); + + if(modePage.ReadDVDR) + { + sb.AppendLine(modePage.WriteDVDR + ? "\t" + Localization.Drive_can_read_and_write_DVD_R + : "\t" + Localization.Drive_can_read_DVD_R); + } + + if(modePage.ReadDVDRAM) + { + sb.AppendLine(modePage.WriteDVDRAM + ? "\t" + Localization.Drive_can_read_and_write_DVD_RAM + : "\t" + Localization.Drive_can_read_DVD_RAM); + } + + if(modePage.Composite) + sb.AppendLine("\t" + Localization.Drive_can_deliver_a_composite_audio_and_video_data_stream); + + if(modePage.DigitalPort1) sb.AppendLine("\t" + Localization.Drive_supports_IEC_958_digital_output_on_port_1); + + if(modePage.DigitalPort2) sb.AppendLine("\t" + Localization.Drive_supports_IEC_958_digital_output_on_port_2); + + if(modePage.SDP) + sb.AppendLine("\t" + Localization.Drive_contains_a_changer_that_can_report_the_exact_contents_of_the_slots); + + if(modePage.CurrentWriteSpeedSelected > 0) + { + switch(modePage.RotationControlSelected) + { + case 0: + sb.AppendFormat("\t" + Localization.Drive_current_writing_speed_is_0_Kbyte_sec_in_CLV_mode, + modePage.CurrentWriteSpeedSelected) + .AppendLine(); + + break; + case 1: + sb.AppendFormat("\t" + Localization.Drive_current_writing_speed_is_0_Kbyte_sec_in_pure_CAV_mode, + modePage.CurrentWriteSpeedSelected) + .AppendLine(); + + break; + } + } + else + { + if(modePage.MaxWriteSpeed > 0) + { + sb.AppendFormat("\t" + Localization.Drive_maximum_writing_speed_is_0_Kbyte_sec, modePage.MaxWriteSpeed) + .AppendLine(); + } + + if(modePage.CurrentWriteSpeed > 0) + { + sb.AppendFormat("\t" + Localization.Drive_current_writing_speed_is_0_Kbyte_sec, + modePage.CurrentWriteSpeed) + .AppendLine(); + } + } + + if(modePage.WriteSpeedPerformanceDescriptors != null) + { + foreach(ModePage_2A_WriteDescriptor descriptor in + modePage.WriteSpeedPerformanceDescriptors.Where(descriptor => descriptor.WriteSpeed > 0)) + { + switch(descriptor.RotationControl) + { + case 0: + sb.AppendFormat("\t" + Localization.Drive_supports_writing_at_0_Kbyte_sec_in_CLV_mode, + descriptor.WriteSpeed) + .AppendLine(); + + break; + case 1: + sb.AppendFormat("\t" + Localization.Drive_supports_writing_at_is_0_Kbyte_sec_in_pure_CAV_mode, + descriptor.WriteSpeed) + .AppendLine(); + + break; + } + } + } + + if(modePage.TestWrite) sb.AppendLine("\t" + Localization.Drive_supports_test_writing); + + if(modePage.ReadBarcode) sb.AppendLine("\t" + Localization.Drive_can_read_barcode); + + if(modePage.SCC) sb.AppendLine("\t" + Localization.Drive_can_read_both_sides_of_a_disc); + + if(modePage.LeadInPW) sb.AppendLine("\t" + Localization.Drive_an_read_raw_R_W_subchannel_from_the_Lead_In); + + if(modePage.CMRSupported == 1) sb.AppendLine("\t" + Localization.Drive_supports_DVD_CSS_and_or_DVD_CPPM); + + if(modePage.BUF) sb.AppendLine("\t" + Localization.Drive_supports_buffer_under_run_free_recording); + + return sb.ToString(); + } + +#endregion Mode Page 0x2A: CD-ROM capabilities page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/2F_IBM.cs b/Aaru.Decoders/SCSI/Modes/2F_IBM.cs new file mode 100644 index 000000000..ebe42d03f --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/2F_IBM.cs @@ -0,0 +1,189 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 2F_IBM.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes IBM MODE PAGE 2Fh: Behaviour Configuration Mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnassignedField.Global")] +public static partial class Modes +{ +#region IBM Mode Page 0x2F: Behaviour Configuration Mode page + + public struct IBM_ModePage_2F + { + /// Parameters can be saved + public bool PS; + public byte FenceBehaviour; + public byte CleanBehaviour; + public byte WORMEmulation; + public byte SenseDataBehaviour; + public bool CCDM; + public bool DDEOR; + public bool CLNCHK; + public byte FirmwareUpdateBehaviour; + public byte UOE_D; + public byte UOE_F; + public byte UOE_C; + } + + public static IBM_ModePage_2F? DecodeIBMModePage_2F(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x2F) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length < 8) return null; + + return new IBM_ModePage_2F + { + PS = (pageResponse[0] & 0x80) == 0x80, + FenceBehaviour = pageResponse[2], + CleanBehaviour = pageResponse[3], + WORMEmulation = pageResponse[4], + SenseDataBehaviour = pageResponse[5], + CCDM = (pageResponse[6] & 0x04) == 0x04, + DDEOR = (pageResponse[6] & 0x02) == 0x02, + CLNCHK = (pageResponse[6] & 0x01) == 0x01, + FirmwareUpdateBehaviour = pageResponse[7], + UOE_C = (byte)((pageResponse[8] & 0x30) >> 4), + UOE_F = (byte)((pageResponse[8] & 0x0C) >> 2) + }; + } + + public static string PrettifyIBMModePage_2F(byte[] pageResponse) => + PrettifyIBMModePage_2F(DecodeIBMModePage_2F(pageResponse)); + + public static string PrettifyIBMModePage_2F(IBM_ModePage_2F? modePage) + { + if(!modePage.HasValue) return null; + + IBM_ModePage_2F page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.IBM_Behaviour_Configuration_Mode_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + switch(page.FenceBehaviour) + { + case 0: + sb.AppendLine("\t" + Localization.Fence_behaviour_is_normal); + + break; + case 1: + sb.AppendLine("\t" + Localization.Panic_fence_behaviour_is_enabled); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_fence_behaviour_code_0, page.FenceBehaviour).AppendLine(); + + break; + } + + switch(page.CleanBehaviour) + { + case 0: + sb.AppendLine("\t" + Localization.Cleaning_behaviour_is_normal); + + break; + case 1: + sb.AppendLine("\t" + Localization.Drive_will_periodically_request_cleaning); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_cleaning_behaviour_code_0, page.CleanBehaviour) + .AppendLine(); + + break; + } + + switch(page.WORMEmulation) + { + case 0: + sb.AppendLine("\t" + Localization.WORM_emulation_is_disabled); + + break; + case 1: + sb.AppendLine("\t" + Localization.WORM_emulation_is_enabled); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_WORM_emulation_code_0, page.WORMEmulation).AppendLine(); + + break; + } + + switch(page.SenseDataBehaviour) + { + case 0: + sb.AppendLine("\t" + Localization.Uses_35_bytes_sense_data); + + break; + case 1: + sb.AppendLine("\t" + Localization.Uses_96_bytes_sense_data); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_sense_data_behaviour_code_0, page.WORMEmulation) + .AppendLine(); + + break; + } + + if(page.CLNCHK) sb.AppendLine("\t" + Localization.Drive_will_set_Check_Condition_when_cleaning_is_needed); + + if(page.DDEOR) sb.AppendLine("\t" + Localization.No_deferred_error_will_be_reported_to_a_rewind_command); + + if(page.CCDM) + sb.AppendLine("\t" + Localization.Drive_will_set_Check_Condition_when_the_criteria_for_Dead_Media_is_met); + + if(page.FirmwareUpdateBehaviour > 0) + sb.AppendLine("\t" + Localization.Drive_will_not_accept_downlevel_firmware_via_an_FMR_tape); + + if(page.UOE_C == 1) sb.AppendLine("\t" + Localization.Drive_will_eject_cleaning_cartridges_on_error); + + if(page.UOE_F == 1) sb.AppendLine("\t" + Localization.Drive_will_eject_firmware_cartridges_on_error); + + if(page.UOE_D == 1) sb.AppendLine("\t" + Localization.Drive_will_eject_data_cartridges_on_error); + + return sb.ToString(); + } + +#endregion IBM Mode Page 0x2F: Behaviour Configuration Mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/30_Apple.cs b/Aaru.Decoders/SCSI/Modes/30_Apple.cs new file mode 100644 index 000000000..ab9b430ca --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/30_Apple.cs @@ -0,0 +1,65 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 30_Apple.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Apple MODE PAGE 30h: Apple OEM String. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Apple Mode Page 0x30: Apple OEM String + + static readonly byte[] AppleOEMString = "APPLE COMPUTER, INC."u8.ToArray(); + + public static bool IsAppleModePage_30(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return false; + + if((pageResponse?[0] & 0x3F) != 0x30) return false; + + if(pageResponse[1] + 2 != pageResponse.Length) return false; + + if(pageResponse.Length != 30) return false; + + var str = new byte[20]; + Array.Copy(pageResponse, 10, str, 0, 20); + + return AppleOEMString.SequenceEqual(str); + } + +#endregion Apple Mode Page 0x30: Apple OEM String +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/3B_HP.cs b/Aaru.Decoders/SCSI/Modes/3B_HP.cs new file mode 100644 index 000000000..f7e224498 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/3B_HP.cs @@ -0,0 +1,107 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 3B_HP.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes HP MODE PAGE 3Bh: Serial Number Override Mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region HP Mode Page 0x3B: Serial Number Override Mode page + + public struct HP_ModePage_3B + { + /// Parameters can be saved + public bool PS; + public byte MSN; + public byte[] SerialNumber; + } + + public static HP_ModePage_3B? DecodeHPModePage_3B(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x3B) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length != 16) return null; + + var decoded = new HP_ModePage_3B(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.MSN = (byte)(pageResponse[2] & 0x03); + decoded.SerialNumber = new byte[10]; + Array.Copy(pageResponse, 6, decoded.SerialNumber, 0, 10); + + return decoded; + } + + public static string PrettifyHPModePage_3B(byte[] pageResponse) => + PrettifyHPModePage_3B(DecodeHPModePage_3B(pageResponse)); + + public static string PrettifyHPModePage_3B(HP_ModePage_3B? modePage) + { + if(!modePage.HasValue) return null; + + HP_ModePage_3B page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.HP_Serial_Number_Override_Mode_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + switch(page.MSN) + { + case 1: + sb.AppendLine("\t" + Localization.Serial_number_is_the_manufacturer_default_value); + + break; + case 3: + sb.AppendLine("\t" + Localization.Serial_number_is_not_the_manufacturer_default_value); + + break; + } + + sb.AppendFormat("\t" + Localization.Serial_number_0, StringHandlers.CToString(page.SerialNumber)).AppendLine(); + + return sb.ToString(); + } + +#endregion HP Mode Page 0x3B: Serial Number Override Mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/3C_HP.cs b/Aaru.Decoders/SCSI/Modes/3C_HP.cs new file mode 100644 index 000000000..5d819d75c --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/3C_HP.cs @@ -0,0 +1,162 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 3C_HP.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes HP MODE PAGE 3Ch: Device Time Mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region HP Mode Page 0x3C: Device Time Mode page + + public struct HP_ModePage_3C + { + /// Parameters can be saved + public bool PS; + public bool LT; + public bool WT; + public bool PT; + public ushort CurrentPowerOn; + public uint PowerOnTime; + public bool UTC; + public bool NTP; + public uint WorldTime; + public byte LibraryHours; + public byte LibraryMinutes; + public byte LibrarySeconds; + public uint CumulativePowerOn; + } + + public static HP_ModePage_3C? DecodeHPModePage_3C(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x3C) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length != 36) return null; + + var decoded = new HP_ModePage_3C(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.LT |= (pageResponse[2] & 0x04) == 0x04; + decoded.WT |= (pageResponse[2] & 0x02) == 0x02; + decoded.PT |= (pageResponse[2] & 0x01) == 0x01; + decoded.CurrentPowerOn = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + + decoded.PowerOnTime = (uint)((pageResponse[8] << 24) + + (pageResponse[9] << 16) + + (pageResponse[10] << 8) + + pageResponse[11]); + + decoded.UTC |= (pageResponse[14] & 0x02) == 0x02; + decoded.NTP |= (pageResponse[14] & 0x01) == 0x01; + + decoded.WorldTime = (uint)((pageResponse[16] << 24) + + (pageResponse[17] << 16) + + (pageResponse[18] << 8) + + pageResponse[19]); + + decoded.LibraryHours = pageResponse[23]; + decoded.LibraryMinutes = pageResponse[24]; + decoded.LibrarySeconds = pageResponse[25]; + + decoded.CumulativePowerOn = (uint)((pageResponse[32] << 24) + + (pageResponse[33] << 16) + + (pageResponse[34] << 8) + + pageResponse[35]); + + return decoded; + } + + public static string PrettifyHPModePage_3C(byte[] pageResponse) => + PrettifyHPModePage_3C(DecodeHPModePage_3C(pageResponse)); + + public static string PrettifyHPModePage_3C(HP_ModePage_3C? modePage) + { + if(!modePage.HasValue) return null; + + HP_ModePage_3C page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.HP_Device_Time_Mode_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.PT) + { + sb.AppendFormat("\t" + Localization.Drive_has_been_powered_up_0_times, page.CurrentPowerOn); + + sb.AppendFormat("\t" + Localization.Drive_has_been_powered_up_since_0_seconds_ago_this_time, + TimeSpan.FromSeconds(page.PowerOnTime)) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Drive_has_been_powered_up_a_total_of_0_seconds, + TimeSpan.FromSeconds(page.CumulativePowerOn)) + .AppendLine(); + } + + if(page.WT) + { + sb.AppendFormat("\t" + Localization.Drive_date_time_is_0, + DateHandlers.UnixUnsignedToDateTime(page.WorldTime)) + .AppendLine(); + + if(page.UTC) sb.AppendLine("\t" + Localization.Drive_time_is_UTC); + + if(page.NTP) sb.AppendLine("\t" + Localization.Drive_time_is_synchronized_with_a_NTP_source); + } + + if(page.LT) + { + sb.AppendFormat("\t" + Localization.Library_time_is_0, + new DateTime(DateTime.Now.Year, + DateTime.Now.Month, + DateTime.Now.Day, + page.LibraryHours, + page.LibraryMinutes, + page.LibrarySeconds)) + .AppendLine(); + } + + return sb.ToString(); + } + +#endregion HP Mode Page 0x3C: Device Time Mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/3D_HP.cs b/Aaru.Decoders/SCSI/Modes/3D_HP.cs new file mode 100644 index 000000000..ebf9a1c53 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/3D_HP.cs @@ -0,0 +1,104 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 3D_HP.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes HP MODE PAGE 3Dh: Extended Reset Mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region HP Mode Page 0x3D: Extended Reset Mode page + + public struct HP_ModePage_3D + { + /// Parameters can be saved + public bool PS; + public byte ResetBehaviour; + } + + public static HP_ModePage_3D? DecodeHPModePage_3D(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x3D) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length != 4) return null; + + var decoded = new HP_ModePage_3D(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.ResetBehaviour = (byte)(pageResponse[2] & 0x03); + + return decoded; + } + + public static string PrettifyHPModePage_3D(byte[] pageResponse) => + PrettifyHPModePage_3D(DecodeHPModePage_3D(pageResponse)); + + public static string PrettifyHPModePage_3D(HP_ModePage_3D? modePage) + { + if(!modePage.HasValue) return null; + + HP_ModePage_3D page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.HP_Extended_Reset_Mode_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + switch(page.ResetBehaviour) + { + case 0: + sb.AppendLine("\t" + Localization.Normal_reset_behaviour); + + break; + case 1: + sb.AppendLine("\t" + Localization.Drive_will_flush_and_position_itself_on_a_LUN_or_target_reset); + + break; + case 2: + sb.AppendLine("\t" + Localization.Drive_will_maintain_position_on_a_LUN_or_target_reset); + + break; + } + + return sb.ToString(); + } + +#endregion HP Mode Page 0x3D: Extended Reset Mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/3D_IBM.cs b/Aaru.Decoders/SCSI/Modes/3D_IBM.cs new file mode 100644 index 000000000..14ec3f7d2 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/3D_IBM.cs @@ -0,0 +1,90 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 3D_IBM.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes IBM MODE PAGE 3D: Behaviour Configuration Mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region IBM Mode Page 0x3D: Behaviour Configuration Mode page + + public struct IBM_ModePage_3D + { + /// Parameters can be saved + public bool PS; + public ushort NumberOfWraps; + } + + public static IBM_ModePage_3D? DecodeIBMModePage_3D(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x3D) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length != 5) return null; + + var decoded = new IBM_ModePage_3D(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.NumberOfWraps = (ushort)((pageResponse[3] << 8) + pageResponse[4]); + + return decoded; + } + + public static string PrettifyIBMModePage_3D(byte[] pageResponse) => + PrettifyIBMModePage_3D(DecodeIBMModePage_3D(pageResponse)); + + public static string PrettifyIBMModePage_3D(IBM_ModePage_3D? modePage) + { + if(!modePage.HasValue) return null; + + IBM_ModePage_3D page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.IBM_LEOT_Mode_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + sb.AppendFormat("\t" + Localization._0_wraps, page.NumberOfWraps).AppendLine(); + + return sb.ToString(); + } + +#endregion IBM Mode Page 0x3D: Behaviour Configuration Mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/3E_Fujitsu.cs b/Aaru.Decoders/SCSI/Modes/3E_Fujitsu.cs new file mode 100644 index 000000000..eaeb6ef1b --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/3E_Fujitsu.cs @@ -0,0 +1,148 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 3E_Fujitsu.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Fujitsu MODE PAGE 3Eh: Verify Control page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.Structs.Devices.SCSI; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static partial class Modes +{ +#region Fujitsu Mode Page 0x3E: Verify Control page + + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public enum Fujitsu_VerifyModes : byte + { + /// Always verify after writing + Always = 0, + /// Never verify after writing + Never = 1, + /// Verify after writing depending on condition + Depends = 2, + Reserved = 4 + } + + public struct Fujitsu_ModePage_3E + { + /// Parameters can be saved + public bool PS; + /// If set, AV data support mode is applied + public bool audioVisualMode; + /// If set the test write operation is restricted + public bool streamingMode; + public byte Reserved1; + /// Verify mode for WRITE commands + public Fujitsu_VerifyModes verifyMode; + public byte Reserved2; + /// Device type provided in response to INQUIRY + public PeripheralDeviceTypes devType; + public byte[] Reserved3; + } + + public static Fujitsu_ModePage_3E? DecodeFujitsuModePage_3E(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x3E) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length != 8) return null; + + var decoded = new Fujitsu_ModePage_3E(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.audioVisualMode |= (pageResponse[2] & 0x80) == 0x80; + decoded.streamingMode |= (pageResponse[2] & 0x40) == 0x40; + decoded.Reserved1 = (byte)((pageResponse[2] & 0x3C) >> 2); + decoded.verifyMode = (Fujitsu_VerifyModes)(pageResponse[2] & 0x03); + + decoded.Reserved2 = (byte)((pageResponse[3] & 0xE0) >> 5); + decoded.devType = (PeripheralDeviceTypes)(pageResponse[3] & 0x1F); + + decoded.Reserved3 = new byte[4]; + Array.Copy(pageResponse, 4, decoded.Reserved3, 0, 4); + + return decoded; + } + + public static string PrettifyFujitsuModePage_3E(byte[] pageResponse) => + PrettifyFujitsuModePage_3E(DecodeFujitsuModePage_3E(pageResponse)); + + public static string PrettifyFujitsuModePage_3E(Fujitsu_ModePage_3E? modePage) + { + if(!modePage.HasValue) return null; + + Fujitsu_ModePage_3E page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Fujitsu_Verify_Control_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + if(page.audioVisualMode) sb.AppendLine("\t" + Localization.Audio_Visual_data_support_mode_is_applied); + + if(page.streamingMode) + sb.AppendLine("\t" + Localization.Test_write_operation_is_restricted_during_read_or_write_operations); + + switch(page.verifyMode) + { + case Fujitsu_VerifyModes.Always: + sb.AppendLine("\t" + Localization.Always_apply_the_verify_operation); + + break; + case Fujitsu_VerifyModes.Never: + sb.AppendLine("\t" + Localization.Never_apply_the_verify_operation); + + break; + case Fujitsu_VerifyModes.Depends: + sb.AppendLine("\t" + Localization.Apply_the_verify_operation_depending_on_the_condition); + + break; + } + + sb.AppendFormat("\t" + Localization.The_device_type_that_would_be_provided_in_the_INQUIRY_response_is_0, + page.devType) + .AppendLine(); + + return sb.ToString(); + } + +#endregion Fujitsu Mode Page 0x3E: Verify Control page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/3E_HP.cs b/Aaru.Decoders/SCSI/Modes/3E_HP.cs new file mode 100644 index 000000000..b6c5cda4f --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/3E_HP.cs @@ -0,0 +1,96 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : 3E_HP.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes HP MODE PAGE 3Eh: CD-ROM Emulation/Disaster Recovery Mode page. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region HP Mode Page 0x3E: CD-ROM Emulation/Disaster Recovery Mode page + + public struct HP_ModePage_3E + { + /// Parameters can be saved + public bool PS; + public bool NonAuto; + public bool CDmode; + } + + public static HP_ModePage_3E? DecodeHPModePage_3E(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) return null; + + if((pageResponse?[0] & 0x3F) != 0x3E) return null; + + if(pageResponse[1] + 2 != pageResponse.Length) return null; + + if(pageResponse.Length != 4) return null; + + var decoded = new HP_ModePage_3E(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.NonAuto |= (pageResponse[2] & 0x02) == 0x02; + decoded.CDmode |= (pageResponse[2] & 0x01) == 0x01; + + return decoded; + } + + public static string PrettifyHPModePage_3E(byte[] pageResponse) => + PrettifyHPModePage_3E(DecodeHPModePage_3E(pageResponse)); + + public static string PrettifyHPModePage_3E(HP_ModePage_3E? modePage) + { + if(!modePage.HasValue) return null; + + HP_ModePage_3E page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine(Localization.HP_CD_ROM_Emulation_Disaster_Recovery_Mode_Page); + + if(page.PS) sb.AppendLine("\t" + Localization.Parameters_can_be_saved); + + sb.AppendLine(page.CDmode + ? "\t" + Localization.Drive_is_emulating_a_CD_ROM_drive + : "\t" + Localization.Drive_is_not_emulating_a_CD_ROM_drive); + + if(page.NonAuto) sb.AppendLine("\t" + Localization.Drive_will_not_exit_emulation_automatically); + + return sb.ToString(); + } + +#endregion HP Mode Page 0x3E: CD-ROM Emulation/Disaster Recovery Mode page +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/Headers.cs b/Aaru.Decoders/SCSI/Modes/Headers.cs new file mode 100644 index 000000000..08866d197 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/Headers.cs @@ -0,0 +1,1605 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Headers.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Prettifies SCSI MODE headers. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.Structs.Devices.SCSI; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ + public static string GetMediumTypeDescription(MediumTypes type) => type switch + { + MediumTypes.ECMA54 => Localization + .GetMediumTypeDescription_ECMA_54, + MediumTypes.ECMA59 => Localization + .GetMediumTypeDescription_ECMA_59, + MediumTypes.ECMA69 => Localization + .GetMediumTypeDescription_ECMA_69, + MediumTypes.ECMA66 => Localization + .GetMediumTypeDescription_ECMA_66, + MediumTypes.ECMA70 => Localization + .GetMediumTypeDescription_ECMA_70, + MediumTypes.ECMA78 => Localization + .GetMediumTypeDescription_ECMA_78, + MediumTypes.ECMA99 => Localization + .GetMediumTypeDescription_ECMA_99, + MediumTypes.ECMA100 => Localization + .GetMediumTypeDescription_ECMA_100, + + // Most probably they will never appear, but magneto-opticals use these codes + /* + case MediumTypes.Unspecified_SS: + return "Unspecified single sided flexible disk"; + case MediumTypes.Unspecified_DS: + return "Unspecified double sided flexible disk"; + */ + MediumTypes.X3_73 => Localization + .GetMediumTypeDescription_X3_73, + MediumTypes.X3_73_DS => Localization + .GetMediumTypeDescription_X3_73_DS, + MediumTypes.X3_82 => Localization + .GetMediumTypeDescription_X3_82, + MediumTypes.Type3Floppy => Localization + .GetMediumTypeDescription_Type3Floppy, + MediumTypes.HDFloppy => Localization + .GetMediumTypeDescription_HDFloppy, + MediumTypes.ReadOnly => Localization + .GetMediumTypeDescription_ReadOnly, + MediumTypes.WORM => Localization + .GetMediumTypeDescription_WORM, + MediumTypes.Erasable => Localization + .GetMediumTypeDescription_Erasable, + MediumTypes.RO_WORM => Localization + .GetMediumTypeDescription_RO_WORM, + + // These magneto-opticals were never manufactured + /* + case MediumTypes.RO_RW: + return "a combination of read-only and erasable optical"; + break; + case MediumTypes.WORM_RW: + return "a combination of write-once and erasable optical"; + */ + MediumTypes.DOW => Localization + .GetMediumTypeDescription_DOW, + MediumTypes.HiMD => Localization + .GetMediumTypeDescription_HiMD, + _ => string.Format(Localization + .Unknown_medium_type_0, + (byte)type) + }; + + public static string PrettifyModeHeader(ModeHeader? header, PeripheralDeviceTypes deviceType) + { + if(!header.HasValue) return null; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SCSI_Mode_Sense_Header); + + switch(deviceType) + { +#region Direct access device mode header + + case PeripheralDeviceTypes.DirectAccess: + { + if(header.Value.MediumType != MediumTypes.Default) + { + sb.AppendFormat("\t" + Localization.Medium_is_0, GetMediumTypeDescription(header.Value.MediumType)) + .AppendLine(); + } + + if(header.Value.WriteProtected) sb.AppendLine("\t" + Localization.Medium_is_write_protected); + + if(header.Value.DPOFUA) sb.AppendLine("\t" + Localization.Drive_supports_DPO_and_FUA_bits); + + if(header.Value.BlockDescriptors != null) + { + foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + { + var density = ""; + + switch(descriptor.Density) + { + case DensityType.Default: + break; + case DensityType.Flux7958: + density = Localization._7958_ftprad; + + break; + case DensityType.Flux13262: + density = Localization._13262_ftprad; + + break; + case DensityType.Flux15916: + density = Localization._15916_ftprad; + + break; + default: + density = string.Format(Localization.with_unknown_density_code_0, + (byte)descriptor.Density); + + break; + } + + if(density != "") + { + if(descriptor.Blocks == 0) + { + sb.AppendFormat("\t" + Localization.All_remaining_blocks_have_0_and_are_1_bytes_each, + density, + descriptor.BlockLength) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization._0_blocks_have_1_and_are_2_bytes_each, + descriptor.Blocks, + density, + descriptor.BlockLength) + .AppendLine(); + } + } + else if(descriptor.Blocks == 0) + { + sb.AppendFormat("\t" + Localization.All_remaining_blocks_are_0_bytes_each, + descriptor.BlockLength) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization._0_blocks_are_1_bytes_each, + descriptor.Blocks, + descriptor.BlockLength) + .AppendLine(); + } + } + } + + break; + } + +#endregion Direct access device mode header + +#region Sequential access device mode header + + case PeripheralDeviceTypes.SequentialAccess: + { + switch(header.Value.BufferedMode) + { + case 0: + sb.AppendLine("\t" + Localization.Device_writes_directly_to_media); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_a_write_cache); + + break; + case 2: + sb.AppendLine("\t" + + Localization.Device_uses_a_write_cache_but_doesn_t_return_until_cache_is_flushed); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_buffered_mode_code_0, header.Value.BufferedMode) + .AppendLine(); + + break; + } + + if(header.Value.Speed == 0) + sb.AppendLine("\t" + Localization.Device_uses_default_speed); + else + sb.AppendFormat("\t" + Localization.Device_uses_speed_0, header.Value.Speed).AppendLine(); + + if(header.Value.WriteProtected) sb.AppendLine("\t" + Localization.Medium_is_write_protected); + + string medium = header.Value.MediumType switch + { + MediumTypes.Default => Localization.MediumType_undefined, + MediumTypes.Tape12 => Localization.MediumType_Tape12, + MediumTypes.Tape24 => Localization.MediumType_Tape24, + MediumTypes.LTOWORM => Localization.MediumType_LTOWORM, + MediumTypes.LTO => Localization.MediumType_LTO, + MediumTypes.LTO2 => Localization.MediumType_LTO2, + MediumTypes.DC2900SL => Localization.MediumType_DC2900SL, + MediumTypes.MLR1 => Localization.MediumType_MLR1, + MediumTypes.DC9200 => Localization.MediumType_DC9200, + MediumTypes.DAT72 => Localization.MediumType_DAT72, + MediumTypes.LTO3 => Localization.MediumType_LTO3, + MediumTypes.LTO3WORM => Localization.MediumType_LTO3WORM, + MediumTypes.DDSCleaning => Localization.MediumType_DDSCleaning, + MediumTypes.SLR32 => Localization.MediumType_SLR32, + MediumTypes.SLRtape50 => Localization.MediumType_SLRtape50, + MediumTypes.LTO4 => Localization.MediumType_LTO4, + MediumTypes.LTO4WORM => Localization.MediumType_LTO4WORM, + MediumTypes.SLRtape50SL => Localization.MediumType_SLRtape50SL, + MediumTypes.SLR32SL => Localization.MediumType_SLR32SL, + MediumTypes.SLR5 => Localization.MediumType_SLR5, + MediumTypes.SLR5SL => Localization.MediumType_SLR5SL, + MediumTypes.LTO5 => Localization.MediumType_LTO5, + MediumTypes.LTO5WORM => Localization.MediumType_LTO5WORM, + MediumTypes.SLRtape7 => Localization.MediumType_SLRtape7, + MediumTypes.SLRtape7SL => Localization.MediumType_SLRtape7SL, + MediumTypes.SLRtape24 => Localization.MediumType_SLRtape24, + MediumTypes.SLRtape24SL => Localization.MediumType_SLRtape24SL, + MediumTypes.LTO6 => Localization.MediumType_LTO6, + MediumTypes.LTO6WORM => Localization.MediumType_LTO6WORM, + MediumTypes.SLRtape140 => Localization.MediumType_SLRtape140, + MediumTypes.SLRtape40 => Localization.MediumType_SLRtape40, + MediumTypes.SLRtape60 => Localization.MediumType_SLRtape60, + MediumTypes.SLRtape100 => Localization.MediumType_SLRtape100, + MediumTypes.SLR40_60_100 => Localization.MediumType_SLR40_60_100, + MediumTypes.LTO7 => Localization.MediumType_LTO7, + MediumTypes.LTO7WORM => Localization.MediumType_LTO7WORM, + MediumTypes.LTOCD => Localization.MediumType_LTO, + MediumTypes.Exatape15m => Localization.MediumType_Exatape15m, + MediumTypes.CT1 => Localization.MediumType_CT1, + MediumTypes.Exatape54m => Localization.MediumType_Exatape54m, + MediumTypes.Exatape80m => Localization.MediumType_Exatape80m, + MediumTypes.Exatape106m => Localization.MediumType_Exatape106m, + MediumTypes.Exatape106mXL => Localization.MediumType_Exatape106mXL, + MediumTypes.SDLT2 => Localization.MediumType_SDLT2, + MediumTypes.VStapeI => Localization.MediumType_VStapeI, + MediumTypes.DLTtapeS4 => Localization.MediumType_DLTtapeS4, + MediumTypes.Travan7 => Localization.MediumType_Travan7, + MediumTypes.Exatape22m => Localization.MediumType_Exatape22m, + MediumTypes.Exatape40m => Localization.MediumType_Exatape40m, + MediumTypes.Exatape76m => Localization.MediumType_Exatape76m, + MediumTypes.Exatape112m => Localization.MediumType_Exatape112m, + MediumTypes.Exatape22mAME => Localization.MediumType_Exatape22mAME, + MediumTypes.Exatape170m => Localization.MediumType_Exatape170m, + MediumTypes.Exatape125m => Localization.MediumType_Exatape125m, + MediumTypes.Exatape45m => Localization.MediumType_Exatape45m, + MediumTypes.Exatape225m => Localization.MediumType_Exatape225m, + MediumTypes.Exatape150m => Localization.MediumType_Exatape150m, + MediumTypes.Exatape75m => Localization.MediumType_Exatape75m, + _ => string.Format(Localization.Unknown_medium_type_0, + (byte)header.Value.MediumType) + }; + + sb.AppendFormat("\t" + Localization.Medium_is_0, medium).AppendLine(); + + if(header.Value.BlockDescriptors != null) + { + foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + { + var density = ""; + + switch(header.Value.MediumType) + { + case MediumTypes.Default: + { + switch(descriptor.Density) + { + case DensityType.Default: + break; + case DensityType.ECMA62: + density = Localization.ECMA62; + + break; + case DensityType.ECMA62_Phase: + density = Localization.ECMA62_Phase; + + break; + case DensityType.ECMA62_GCR: + density = Localization.ECMA62_GCR; + + break; + case DensityType.ECMA79: + density = Localization.ECMA79; + + break; + case DensityType.IBM3480: + density = Localization.IBM3480; + + break; + case DensityType.ECMA46: + density = Localization.ECMA46; + + break; + case DensityType.ECMA98: + density = Localization.ECMA98; + + break; + case DensityType.X3_136: + density = Localization.X3_136; + + break; + case DensityType.X3_157: + density = Localization.X3_157; + + break; + case DensityType.X3_158: + density = Localization.X3_158; + + break; + case DensityType.X3B5_86: + density = Localization.X3B5_86; + + break; + case DensityType.HiTC1: + density = Localization.HiTC1; + + break; + case DensityType.HiTC2: + density = Localization.HiTC2; + + break; + case DensityType.QIC120: + density = Localization.QIC120; + + break; + case DensityType.QIC150: + density = Localization.QIC150; + + break; + case DensityType.QIC320: + density = Localization.QIC320; + + break; + case DensityType.QIC1350: + density = Localization.QIC1350; + + break; + case DensityType.X3B5_88: + density = Localization.X3B5_88; + + break; + case DensityType.X3_202: + density = Localization.X3_202; + + break; + case DensityType.ECMA_TC17: + density = Localization.ECMA_TC17; + + break; + case DensityType.X3_193: + density = Localization.X3_193; + + break; + case DensityType.X3B5_91: + density = Localization.X3B5_91; + + break; + case DensityType.QIC11: + density = Localization.QIC11; + + break; + case DensityType.IBM3490E: + density = Localization.IBM3490E; + + break; + case DensityType.LTO1: + //case DensityType.SAIT1: + density = Localization.LTO_or_SAIT1; + + break; + case DensityType.LTO2Old: + density = Localization.MediumType_LTO2; + + break; + case DensityType.LTO2: + //case DensityType.T9840: + density = Localization.LTO2_or_T9840; + + break; + case DensityType.T9940: + density = Localization.T9940; + + break; + case DensityType.LTO3: + //case DensityType.T9940: + density = Localization.LTO3_or_T9940; + + break; + case DensityType.T9840C: + density = Localization.T9840C; + + break; + case DensityType.LTO4: + //case DensityType.T9840D: + density = Localization.LTO4_or_T9840D; + + break; + case DensityType.T10000A: + density = Localization.T10000A; + + break; + case DensityType.T10000B: + density = Localization.T10000B; + + break; + case DensityType.T10000C: + density = Localization.T10000C; + + break; + case DensityType.T10000D: + density = Localization.T10000D; + + break; + case DensityType.AIT1: + density = Localization.AIT1; + + break; + case DensityType.AIT2: + density = Localization.AIT2; + + break; + case DensityType.AIT3: + density = Localization.AIT3; + + break; + case DensityType.DDS2: + density = Localization.DDS2; + + break; + case DensityType.DDS3: + density = Localization.DDS3; + + break; + case DensityType.DDS4: + density = Localization.DDS4; + + break; + default: + density = string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density); + + break; + } + } + + break; + case MediumTypes.LTOWORM: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.LTO_Ultrium_cleaning_cartridge, + DensityType.LTO3 => Localization.MediumType_LTO3WORM, + DensityType.LTO4 => Localization.MediumType_LTO4WORM, + DensityType.LTO5 => Localization.MediumType_LTO5WORM, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.LTO: + { + density = descriptor.Density switch + { + DensityType.LTO1 => Localization.MediumType_LTO, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.LTO2: + { + density = descriptor.Density switch + { + DensityType.LTO2 => Localization.MediumType_LTO2, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.DDS3: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MLR1_26GB, + DensityType.DDS3 => Localization.DDS3, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.DDS4: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.DC9200, + DensityType.DDS4 => Localization.DDS4, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.DAT72: + { + density = descriptor.Density switch + { + DensityType.DAT72 => Localization.MediumType_DAT72, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.LTO3: + case MediumTypes.LTO3WORM: + { + density = descriptor.Density switch + { + DensityType.LTO3 => Localization.MediumType_LTO3, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.DDSCleaning: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_DDSCleaning, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.LTO4: + case MediumTypes.LTO4WORM: + { + density = descriptor.Density switch + { + DensityType.LTO4 => Localization.MediumType_LTO4, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.LTO5: + case MediumTypes.LTO5WORM: + { + density = descriptor.Density switch + { + DensityType.LTO5 => Localization.MediumType_LTO5, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.LTO6: + case MediumTypes.LTO6WORM: + { + density = descriptor.Density switch + { + DensityType.LTO6 => Localization.MediumType_LTO6, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.LTO7: + case MediumTypes.LTO7WORM: + { + density = descriptor.Density switch + { + DensityType.LTO7 => Localization.MediumType_LTO7, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.LTOCD: + { + density = descriptor.Density switch + { + DensityType.LTO2 => Localization.LTO2_CDemu, + DensityType.LTO3 => Localization.LTO3_CDemu, + DensityType.LTO4 => Localization.LTO4_CDemu, + DensityType.LTO5 => Localization.LTO5_CDemu, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape15m: + { + density = descriptor.Density switch + { + DensityType.Ex8200 => Localization.EXB8200, + DensityType.Ex8200c => Localization.EXB8200_compressed, + DensityType.Ex8500 => Localization.EXB8500, + DensityType.Ex8500c => Localization.EXB8500_compressed, + DensityType.Mammoth => Localization.TapeName_Mammoth, + DensityType.IBM3590 => Localization.IBM3590, + DensityType.IBM3590E => Localization.IBM3590E, + DensityType.VXA1 => Localization.VXA1, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape28m: + { + density = descriptor.Density switch + { + DensityType.Ex8200 => Localization.EXB8200, + DensityType.Ex8200c => Localization.EXB8200_compressed, + DensityType.Ex8500 => Localization.EXB8500, + DensityType.Ex8500c => Localization.EXB8500_compressed, + DensityType.Mammoth => Localization.TapeName_Mammoth, + DensityType.CT1 => Localization.CT1, + DensityType.CT2 => Localization.CT2, + DensityType.IBM3590 => Localization.IBM3590_extended, + DensityType.IBM3590E => Localization.IBM3590E_extended, + DensityType.VXA2 => Localization.VXA2, + DensityType.VXA3 => Localization.VXA3, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape54m: + { + density = descriptor.Density switch + { + DensityType.Ex8200 => Localization.EXB8200, + DensityType.Ex8200c => Localization.EXB8200_compressed, + DensityType.Ex8500 => Localization.EXB8500, + DensityType.Ex8500c => Localization.EXB8500_compressed, + DensityType.Mammoth => Localization.TapeName_Mammoth, + DensityType.DLT3_42k => Localization.DLT3_42k, + DensityType.DLT3_56t => Localization.DLT3_56t, + DensityType.DLT3_62k or DensityType.DLT3_62kAlt => Localization.DLT3_62k, + DensityType.DLT3c => Localization.DLT3c, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape80m: + { + density = descriptor.Density switch + { + DensityType.Ex8200 => Localization.EXB8200, + DensityType.Ex8200c => Localization.EXB8200_compressed, + DensityType.Ex8500 => Localization.EXB8500, + DensityType.Ex8500c => Localization.EXB8500_compressed, + DensityType.Mammoth => Localization.TapeName_Mammoth, + DensityType.DLT3_62k or DensityType.DLT3_62kAlt => Localization.DLT3_XT, + DensityType.DLT3c => Localization.DLT3_XT_compressed, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape106m: + { + density = descriptor.Density switch + { + DensityType.Ex8200 => Localization.EXB8200, + DensityType.Ex8200c => Localization.EXB8200_compressed, + DensityType.Ex8500 => Localization.EXB8500, + DensityType.Ex8500c => Localization.EXB8500_compressed, + DensityType.Mammoth => Localization.TapeName_Mammoth, + DensityType.DLT4 or DensityType.DLT4Alt => Localization.DLT4, + DensityType.DLT4_123k or DensityType.DLT4_123kAlt => Localization + .DLT4_123k, + DensityType.DLT4_98k => Localization.DLT4_98k, + DensityType.Travan5 => Localization.Travan5, + DensityType.DLT4c => Localization.DLT4c, + DensityType.DLT4_85k => Localization.DLT4_85k, + DensityType.DLT4c_85k => Localization.DLT4c_85k, + DensityType.DLT4c_123k => Localization.DLT4c_123k, + DensityType.DLT4c_98k => Localization.DLT4c_98k, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape106mXL: + { + density = descriptor.Density switch + { + DensityType.Ex8200 => Localization.EXB8200, + DensityType.Ex8200c => Localization.EXB8200_compressed, + DensityType.Ex8500 => Localization.EXB8500, + DensityType.Ex8500c => Localization.EXB8500_compressed, + DensityType.Mammoth => Localization.TapeName_Mammoth, + DensityType.SDLT1_133k or DensityType.SDLT1_133kAlt => Localization + .SDLT1_133k, + DensityType.SDLT1 => + + //case DensityType.SDLT1Alt: + Localization.SDLT1, + DensityType.SDLT1c => Localization.SDLT1c, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SDLT2: + { + density = descriptor.Density switch + { + DensityType.SDLT2 => Localization.MediumType_SDLT2, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.VStapeI: + { + density = descriptor.Density switch + { + DensityType.VStape1 or DensityType.VStape1Alt => Localization + .MediumType_VStapeI, + DensityType.VStape1c => Localization.VStape1c, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.DLTtapeS4: + { + density = descriptor.Density switch + { + DensityType.DLTS4 => Localization.MediumType_DLTtapeS4, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape22m: + { + density = descriptor.Density switch + { + DensityType.Ex8200 => Localization.EXB8200, + DensityType.Ex8200c => Localization.EXB8200_compressed, + DensityType.Ex8500 => Localization.EXB8500, + DensityType.Ex8500c => Localization.EXB8500_compressed, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape40m: + { + density = descriptor.Density switch + { + DensityType.Ex8200 => Localization.EXB8200, + DensityType.Ex8200c => Localization.EXB8200_compressed, + DensityType.Ex8500 => Localization.EXB8500, + DensityType.Ex8500c => Localization.EXB8500_compressed, + DensityType.Mammoth => Localization.TapeName_Mammoth, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape76m: + { + density = descriptor.Density switch + { + DensityType.Ex8200 => Localization.EXB8200, + DensityType.Ex8200c => Localization.EXB8200_compressed, + DensityType.Ex8500 => Localization.EXB8500, + DensityType.Ex8500c => Localization.EXB8500_compressed, + DensityType.Mammoth => Localization.TapeName_Mammoth, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape112m: + { + density = descriptor.Density switch + { + DensityType.Ex8200 => Localization.EXB8200, + DensityType.Ex8200c => Localization.EXB8200_compressed, + DensityType.Ex8500 => Localization.EXB8500, + DensityType.Ex8500c => Localization.EXB8500_compressed, + DensityType.Mammoth => Localization.TapeName_Mammoth, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.Exatape22mAME: + case MediumTypes.Exatape170m: + case MediumTypes.Exatape125m: + case MediumTypes.Exatape45m: + case MediumTypes.Exatape225m: + case MediumTypes.Exatape150m: + case MediumTypes.Exatape75m: + { + density = descriptor.Density switch + { + DensityType.Mammoth => Localization.TapeName_Mammoth, + DensityType.Mammoth2 => Localization.Mammoth2, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.DC2900SL: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_DC2900SL, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.DC9250: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.DC9250, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLR32: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLR32, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.MLR1SL: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MLR1_26GBSL, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLRtape50: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLRtape50, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLRtape50SL: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLRtape50SL, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLR32SL: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.SLR32SL, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLR5: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLR5, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLR5SL: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.SLR5SL, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLRtape7: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLRtape7, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLRtape7SL: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLRtape7SL, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLRtape24: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLRtape24, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLRtape24SL: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLRtape24SL, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLRtape140: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLRtape140, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLRtape40: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLRtape40, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLRtape60: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLRtape60, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLRtape100: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.MediumType_SLRtape100, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + case MediumTypes.SLR40_60_100: + { + density = descriptor.Density switch + { + DensityType.Default => Localization.SLR40_60_100, + _ => string.Format(Localization.unknown_density_code_0, + (byte)descriptor.Density) + }; + } + + break; + default: + density = string.Format(Localization.unknown_density_code_0, (byte)descriptor.Density); + + break; + } + + if(density != "") + { + if(descriptor.Blocks == 0) + { + if(descriptor.BlockLength == 0) + { + sb.AppendFormat("\t" + + Localization + .All_remaining_blocks_conform_to_0_and_have_a_variable_length, + density) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + + Localization.All_remaining_blocks_conform_to_0_and_are_1_bytes_each, + density, + descriptor.BlockLength) + .AppendLine(); + } + } + else if(descriptor.BlockLength == 0) + { + sb.AppendFormat("\t" + Localization._0_blocks_conform_to_1_and_have_a_variable_length, + descriptor.Blocks, + density) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization._0_blocks_conform_to_1_and_are_2_bytes_each, + descriptor.Blocks, + density, + descriptor.BlockLength) + .AppendLine(); + } + } + else if(descriptor.Blocks == 0) + { + if(descriptor.BlockLength == 0) + { + sb.AppendFormat("\t" + Localization.All_remaining_blocks_have_a_variable_length) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization.All_remaining_blocks_are_0_bytes_each, + descriptor.BlockLength) + .AppendLine(); + } + } + else if(descriptor.BlockLength == 0) + { + sb.AppendFormat("\t" + Localization._0_blocks_have_a_variable_length, descriptor.Blocks) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization._0_blocks_are_1_bytes_each, + descriptor.Blocks, + descriptor.BlockLength) + .AppendLine(); + } + } + } + + break; + } + +#endregion Sequential access device mode header + +#region Printer device mode header + + case PeripheralDeviceTypes.PrinterDevice: + { + switch(header.Value.BufferedMode) + { + case 0: + sb.AppendLine("\t" + Localization.Device_prints_directly); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_a_print_cache); + + break; + default: + sb.AppendFormat("\t" + Localization.Unknown_buffered_mode_code_0, header.Value.BufferedMode) + .AppendLine(); + + break; + } + + break; + } + +#endregion Printer device mode header + +#region Optical device mode header + + case PeripheralDeviceTypes.OpticalDevice: + { + if(header.Value.MediumType != MediumTypes.Default) + { + sb.Append("\t" + Localization.Medium_is_); + + switch(header.Value.MediumType) + { + case MediumTypes.ReadOnly: + sb.AppendLine(Localization.GetMediumTypeDescription_ReadOnly); + + break; + case MediumTypes.WORM: + sb.AppendLine(Localization.GetMediumTypeDescription_WORM); + + break; + case MediumTypes.Erasable: + sb.AppendLine(Localization.GetMediumTypeDescription_Erasable); + + break; + case MediumTypes.RO_WORM: + sb.AppendLine(Localization.GetMediumTypeDescription_RO_WORM); + + break; + case MediumTypes.RO_RW: + sb.AppendLine(Localization.a_combination_of_read_only_and_erasable_optical); + + break; + case MediumTypes.WORM_RW: + sb.AppendLine(Localization.a_combination_of_write_once_and_erasable_optical); + + break; + case MediumTypes.DOW: + sb.AppendLine(Localization.GetMediumTypeDescription_DOW); + + break; + default: + sb.AppendFormat(Localization.an_unknown_medium_type_0, (byte)header.Value.MediumType) + .AppendLine(); + + break; + } + } + + if(header.Value.WriteProtected) sb.AppendLine("\t" + Localization.Medium_is_write_protected); + + if(header.Value.EBC) sb.AppendLine("\t" + Localization.Blank_checking_during_write_is_enabled); + + if(header.Value.DPOFUA) sb.AppendLine("\t" + Localization.Drive_supports_DPO_and_FUA_bits); + + if(header.Value.BlockDescriptors != null) + { + foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + { + var density = ""; + + switch(descriptor.Density) + { + case DensityType.Default: + break; + case DensityType.ISO10090: + density = Localization.ISO10090; + + break; + case DensityType.D581: + density = Localization.D581; + + break; + case DensityType.X3_212: + density = Localization.X3_212; + + break; + case DensityType.X3_191: + density = Localization.X3_191; + + break; + case DensityType.X3_214: + density = Localization.X3_214; + + break; + case DensityType.X3_211: + density = Localization.X3_211; + + break; + case DensityType.D407: + density = Localization.D407; + + break; + case DensityType.ISO13614: + density = Localization.ISO13614; + + break; + case DensityType.X3_200: + density = Localization.X3_200; + + break; + default: + density = string.Format(Localization.unknown_density_code_0, (byte)descriptor.Density); + + break; + } + + if(density != "") + { + if(descriptor.Blocks == 0) + { + if(descriptor.BlockLength == 0) + { + sb.AppendFormat("\t" + + Localization.All_remaining_blocks_are_0_and_have_a_variable_length, + density) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization.All_remaining_blocks_are_0_and_are_1_bytes_each, + density, + descriptor.BlockLength) + .AppendLine(); + } + } + else if(descriptor.BlockLength == 0) + { + sb.AppendFormat("\t" + Localization._0_blocks_are_1_and_have_a_variable_length, + descriptor.Blocks, + density) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization._0_blocks_are_1_and_are_2_bytes_each, + descriptor.Blocks, + density, + descriptor.BlockLength) + .AppendLine(); + } + } + else if(descriptor.Blocks == 0) + { + if(descriptor.BlockLength == 0) + { + sb.AppendFormat("\t" + Localization.All_remaining_blocks_have_a_variable_length) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization.All_remaining_blocks_are_0_bytes_each, + descriptor.BlockLength) + .AppendLine(); + } + } + else if(descriptor.BlockLength == 0) + { + sb.AppendFormat("\t" + Localization._0_blocks_have_a_variable_length, descriptor.Blocks) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization._0_blocks_are_1_bytes_each, + descriptor.Blocks, + descriptor.BlockLength) + .AppendLine(); + } + } + } + + break; + } + +#endregion Optical device mode header + +#region Multimedia device mode header + + case PeripheralDeviceTypes.MultiMediaDevice: + { + sb.Append("\t" + Localization.Medium_is_); + + switch(header.Value.MediumType) + { + case MediumTypes.CDROM: + sb.AppendLine(Localization.MediumTypes_CDROM); + + break; + case MediumTypes.CDDA: + sb.AppendLine(Localization.MediumTypes_CDDA); + + break; + case MediumTypes.MixedCD: + sb.AppendLine(Localization.MediumTypes_MixedCD); + + break; + case MediumTypes.CDROM_80: + sb.AppendLine(Localization.MediumTypes_CDROM_80); + + break; + case MediumTypes.CDDA_80: + sb.AppendLine(Localization.MediumTypes_CDDA_80); + + break; + case MediumTypes.MixedCD_80: + sb.AppendLine(Localization.MediumTypes_MixedCD_80); + + break; + case MediumTypes.Unknown_CD: + sb.AppendLine(Localization.Unknown_medium_type); + + break; + case MediumTypes.HybridCD: + sb.AppendLine(Localization.MediumTypes_HybridCD); + + break; + case MediumTypes.Unknown_CDR: + sb.AppendLine(Localization.MediumTypes_Unknown_CDR); + + break; + case MediumTypes.CDR: + sb.AppendLine(Localization.MediumTypes_CDR); + + break; + case MediumTypes.CDR_DA: + sb.AppendLine(Localization.MediumTypes_CDR_DA); + + break; + case MediumTypes.CDR_Mixed: + sb.AppendLine(Localization.MediumTypes_CDR_Mixed); + + break; + case MediumTypes.HybridCDR: + sb.AppendLine(Localization.MediumTypes_HybridCDR); + + break; + case MediumTypes.CDR_80: + sb.AppendLine(Localization.MediumTypes_CDR_80); + + break; + case MediumTypes.CDR_DA_80: + sb.AppendLine(Localization.MediumTypes_CDR_DA_80); + + break; + case MediumTypes.CDR_Mixed_80: + sb.AppendLine("80 mm CD-R with data and audio"); + + break; + case MediumTypes.HybridCDR_80: + sb.AppendLine(Localization.MediumTypes_HybridCDR_80); + + break; + case MediumTypes.Unknown_CDRW: + sb.AppendLine(Localization.MediumTypes_Unknown_CDRW); + + break; + case MediumTypes.CDRW: + sb.AppendLine(Localization.MediumTypes_CDRW); + + break; + case MediumTypes.CDRW_DA: + sb.AppendLine(Localization.MediumTypes_CDRW_DA); + + break; + case MediumTypes.CDRW_Mixed: + sb.AppendLine(Localization.MediumTypes_CDRW_Mixed); + + break; + case MediumTypes.HybridCDRW: + sb.AppendLine(Localization.MediumTypes_HybridCDRW); + + break; + case MediumTypes.CDRW_80: + sb.AppendLine(Localization.MediumTypes_CDRW_80); + + break; + case MediumTypes.CDRW_DA_80: + sb.AppendLine(Localization.MediumTypes_CDRW_DA_80); + + break; + case MediumTypes.CDRW_Mixed_80: + sb.AppendLine(Localization.MediumTypes_CDRW_Mixed_80); + + break; + case MediumTypes.HybridCDRW_80: + sb.AppendLine(Localization.MediumTypes_HybridCDRW_80); + + break; + case MediumTypes.Unknown_HD: + sb.AppendLine(Localization.MediumTypes_Unknown_HD); + + break; + case MediumTypes.HD: + sb.AppendLine(Localization.MediumTypes_HD); + + break; + case MediumTypes.HD_80: + sb.AppendLine(Localization.MediumTypes_HD_80); + + break; + case MediumTypes.NoDisc: + sb.AppendLine(Localization.No_disc_inserted_tray_closed_or_caddy_inserted); + + break; + case MediumTypes.TrayOpen: + sb.AppendLine(Localization.Tray_open_or_no_caddy_inserted); + + break; + case MediumTypes.MediumError: + sb.AppendLine(Localization.Tray_closed_or_caddy_inserted_but_medium_error); + + break; + case MediumTypes.UnknownBlockDevice: + sb.AppendLine(Localization.Unknown_block_device); + + break; + case MediumTypes.ReadOnlyBlockDevice: + sb.AppendLine(Localization.Read_only_block_device); + + break; + case MediumTypes.ReadWriteBlockDevice: + sb.AppendLine(Localization.Read_Write_block_device); + + break; + case MediumTypes.LTOCD: + sb.AppendLine(Localization.LTO_in_CD_ROM_emulation_mode); + + break; + default: + sb.AppendFormat(Localization.Unknown_medium_type_0, (byte)header.Value.MediumType).AppendLine(); + + break; + } + + if(header.Value.WriteProtected) sb.AppendLine("\t" + Localization.Medium_is_write_protected); + + if(header.Value.DPOFUA) sb.AppendLine("\t" + Localization.Drive_supports_DPO_and_FUA_bits); + + if(header.Value.BlockDescriptors != null) + { + foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + { + var density = ""; + + switch(descriptor.Density) + { + case DensityType.Default: + break; + case DensityType.User: + density = Localization.user_data_only; + + break; + case DensityType.UserAuxiliary: + density = Localization.user_data_plus_auxiliary_data; + + break; + case DensityType.UserAuxiliaryTag: + density = Localization._4byte_tag_user_data_plus_auxiliary_data; + + break; + case DensityType.Audio: + density = Localization.audio_information_only; + + break; + case DensityType.LTO2: + density = Localization.MediumType_LTO2; + + break; + case DensityType.LTO3: + density = Localization.MediumType_LTO3; + + break; + case DensityType.LTO4: + density = Localization.MediumType_LTO4; + + break; + case DensityType.LTO5: + density = Localization.MediumType_LTO5; + + break; + default: + density = string.Format(Localization.with_unknown_density_code_0, + (byte)descriptor.Density); + + break; + } + + if(density != "") + { + if(descriptor.Blocks == 0) + { + sb.AppendFormat("\t" + Localization.All_remaining_blocks_have_0_and_are_1_bytes_each, + density, + descriptor.BlockLength) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization._0_blocks_have_1_and_are_2_bytes_each, + descriptor.Blocks, + density, + descriptor.BlockLength) + .AppendLine(); + } + } + else if(descriptor.Blocks == 0) + { + sb.AppendFormat("\t" + Localization.All_remaining_blocks_are_0_bytes_each, + descriptor.BlockLength) + .AppendLine(); + } + else + { + sb.AppendFormat("\t" + Localization._0_blocks_are_1_bytes_each, + descriptor.Blocks, + descriptor.BlockLength) + .AppendLine(); + } + } + } + + break; + } + +#endregion Multimedia device mode header + } + + return sb.ToString(); + } +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/Mode10.cs b/Aaru.Decoders/SCSI/Modes/Mode10.cs new file mode 100644 index 000000000..21b4bc7ee --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/Mode10.cs @@ -0,0 +1,361 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Mode10.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes and encodines SCSI modes in MODE SENSE/SELECT (10) format. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Aaru.CommonTypes.Structs.Devices.SCSI; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ + public static ModeHeader? DecodeModeHeader10(byte[] modeResponse, PeripheralDeviceTypes deviceType) + { + if(modeResponse == null || modeResponse.Length < 8) return null; + + var modeLength = (ushort)((modeResponse[0] << 8) + modeResponse[1]); + var blockDescLength = (ushort)((modeResponse[6] << 8) + modeResponse[7]); + + if(modeResponse.Length < modeLength) return null; + + var header = new ModeHeader + { + MediumType = (MediumTypes)modeResponse[2] + }; + + bool longLBA = (modeResponse[4] & 0x01) == 0x01; + + if(blockDescLength > 0) + { + if(longLBA) + { + header.BlockDescriptors = new BlockDescriptor[blockDescLength / 16]; + + for(var i = 0; i < header.BlockDescriptors.Length; i++) + { + if(12 + i * 16 + 8 >= modeResponse.Length) break; + + header.BlockDescriptors[i] = new BlockDescriptor + { + Density = DensityType.Default + }; + + var temp = new byte[8]; + temp[0] = modeResponse[7 + i * 16 + 8]; + temp[1] = modeResponse[6 + i * 16 + 8]; + temp[2] = modeResponse[5 + i * 16 + 8]; + temp[3] = modeResponse[4 + i * 16 + 8]; + temp[4] = modeResponse[3 + i * 16 + 8]; + temp[5] = modeResponse[2 + i * 16 + 8]; + temp[6] = modeResponse[1 + i * 16 + 8]; + temp[7] = modeResponse[0 + i * 16 + 8]; + header.BlockDescriptors[i].Blocks = BitConverter.ToUInt64(temp, 0); + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[15 + i * 16 + 8] << 24); + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[14 + i * 16 + 8] << 16); + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[13 + i * 16 + 8] << 8); + header.BlockDescriptors[i].BlockLength += modeResponse[12 + i * 16 + 8]; + } + } + else + { + header.BlockDescriptors = new BlockDescriptor[blockDescLength / 8]; + + for(var i = 0; i < header.BlockDescriptors.Length; i++) + { + if(7 + i * 8 + 8 >= modeResponse.Length) break; + + header.BlockDescriptors[i] = new BlockDescriptor(); + + if(deviceType != PeripheralDeviceTypes.DirectAccess) + header.BlockDescriptors[i].Density = (DensityType)modeResponse[0 + i * 8 + 8]; + else + { + header.BlockDescriptors[i].Density = DensityType.Default; + header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[0 + i * 8 + 8] << 24); + } + + header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[1 + i * 8 + 8] << 16); + header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[2 + i * 8 + 8] << 8); + header.BlockDescriptors[i].Blocks += modeResponse[3 + i * 8 + 8]; + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[5 + i * 8 + 8] << 16); + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[6 + i * 8 + 8] << 8); + header.BlockDescriptors[i].BlockLength += modeResponse[7 + i * 8 + 8]; + } + } + } + + switch(deviceType) + { + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.MultiMediaDevice: + header.WriteProtected = (modeResponse[3] & 0x80) == 0x80; + header.DPOFUA = (modeResponse[3] & 0x10) == 0x10; + + break; + case PeripheralDeviceTypes.SequentialAccess: + header.WriteProtected = (modeResponse[3] & 0x80) == 0x80; + header.Speed = (byte)(modeResponse[3] & 0x0F); + header.BufferedMode = (byte)((modeResponse[3] & 0x70) >> 4); + + break; + case PeripheralDeviceTypes.PrinterDevice: + header.BufferedMode = (byte)((modeResponse[3] & 0x70) >> 4); + + break; + case PeripheralDeviceTypes.OpticalDevice: + header.WriteProtected = (modeResponse[3] & 0x80) == 0x80; + header.EBC = (modeResponse[3] & 0x01) == 0x01; + header.DPOFUA = (modeResponse[3] & 0x10) == 0x10; + + break; + } + + return header; + } + + public static string PrettifyModeHeader10(byte[] modeResponse, PeripheralDeviceTypes deviceType) => + PrettifyModeHeader(DecodeModeHeader10(modeResponse, deviceType), deviceType); + + public static DecodedMode? DecodeMode10(byte[] modeResponse, PeripheralDeviceTypes deviceType) + { + ModeHeader? hdr = DecodeModeHeader10(modeResponse, deviceType); + + if(!hdr.HasValue) return null; + + var decoded = new DecodedMode + { + Header = hdr.Value + }; + + bool longlba = (modeResponse[4] & 0x01) == 0x01; + int offset; + var blkDrLength = 0; + + if(decoded.Header.BlockDescriptors != null) blkDrLength = decoded.Header.BlockDescriptors.Length; + + if(longlba) + offset = 8 + blkDrLength * 16; + else + offset = 8 + blkDrLength * 8; + + int length = modeResponse[0] << 8; + length += modeResponse[1]; + length += 2; + + if(length != modeResponse.Length) return decoded; + + List listpages = []; + + while(offset < modeResponse.Length) + { + bool isSubpage = (modeResponse[offset] & 0x40) == 0x40; + var pg = new ModePage(); + var pageNo = (byte)(modeResponse[offset] & 0x3F); + + if(pageNo == 0) + { + pg.PageResponse = new byte[modeResponse.Length - offset]; + Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length); + pg.Page = 0; + pg.Subpage = 0; + offset += pg.PageResponse.Length; + } + else + { + switch(isSubpage) + { + case true when offset + 3 < modeResponse.Length: + { + pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4]; + int copyLen = pg.PageResponse.Length; + + if(pg.PageResponse.Length + offset > modeResponse.Length) + copyLen = modeResponse.Length - offset; + + Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); + pg.Page = (byte)(modeResponse[offset] & 0x3F); + pg.Subpage = modeResponse[offset + 1]; + offset += pg.PageResponse.Length; + + break; + } + case false when offset + 1 < modeResponse.Length: + { + pg.PageResponse = new byte[modeResponse[offset + 1] + 2]; + int copyLen = pg.PageResponse.Length; + + if(pg.PageResponse.Length + offset > modeResponse.Length) + copyLen = modeResponse.Length - offset; + + Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); + pg.Page = (byte)(modeResponse[offset] & 0x3F); + pg.Subpage = 0; + offset += pg.PageResponse.Length; + + break; + } + default: + offset = modeResponse.Length; + + break; + } + } + + listpages.Add(pg); + } + + decoded.Pages = listpages.ToArray(); + + return decoded; + } + + public static byte[] EncodeModeHeader10(ModeHeader header, PeripheralDeviceTypes deviceType, bool longLBA = false) + { + byte[] hdr; + + if(header.BlockDescriptors != null) + { + hdr = longLBA + ? new byte[8 + header.BlockDescriptors.Length * 16] + : new byte[8 + header.BlockDescriptors.Length * 8]; + } + else + hdr = new byte[8]; + + hdr[2] = (byte)header.MediumType; + + switch(deviceType) + { + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.MultiMediaDevice: + if(header.WriteProtected) hdr[3] += 0x80; + + if(header.DPOFUA) hdr[3] += 0x10; + + break; + case PeripheralDeviceTypes.SequentialAccess: + if(header.WriteProtected) hdr[3] += 0x80; + + hdr[3] += (byte)(header.Speed & 0x0F); + hdr[3] += (byte)(header.BufferedMode << 4 & 0x70); + + break; + case PeripheralDeviceTypes.PrinterDevice: + hdr[3] += (byte)(header.BufferedMode << 4 & 0x70); + + break; + case PeripheralDeviceTypes.OpticalDevice: + if(header.WriteProtected) hdr[3] += 0x80; + + if(header.EBC) hdr[3] += 0x01; + + if(header.DPOFUA) hdr[3] += 0x10; + + break; + } + + if(longLBA) hdr[4] += 0x01; + + if(header.BlockDescriptors == null) return hdr; + + if(longLBA) + { + for(var i = 0; i < header.BlockDescriptors.Length; i++) + { + byte[] temp = BitConverter.GetBytes(header.BlockDescriptors[i].Blocks); + hdr[7 + i * 16 + 8] = temp[0]; + hdr[6 + i * 16 + 8] = temp[1]; + hdr[5 + i * 16 + 8] = temp[2]; + hdr[4 + i * 16 + 8] = temp[3]; + hdr[3 + i * 16 + 8] = temp[4]; + hdr[2 + i * 16 + 8] = temp[5]; + hdr[1 + i * 16 + 8] = temp[6]; + hdr[0 + i * 16 + 8] = temp[7]; + hdr[12 + i * 16 + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF000000) >> 24); + hdr[13 + i * 16 + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF0000) >> 16); + hdr[14 + i * 16 + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF00) >> 8); + hdr[15 + i * 16 + 8] = (byte)(header.BlockDescriptors[i].BlockLength & 0xFF); + } + } + else + { + for(var i = 0; i < header.BlockDescriptors.Length; i++) + { + if(deviceType != PeripheralDeviceTypes.DirectAccess) + hdr[0 + i * 8 + 8] = (byte)header.BlockDescriptors[i].Density; + else + hdr[0 + i * 8 + 8] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF000000) >> 24); + + hdr[1 + i * 8 + 8] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF0000) >> 16); + hdr[2 + i * 8 + 8] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF00) >> 8); + hdr[3 + i * 8 + 8] = (byte)(header.BlockDescriptors[i].Blocks & 0xFF); + hdr[5 + i * 8 + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF0000) >> 16); + hdr[6 + i * 8 + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF00) >> 8); + hdr[7 + i * 8 + 8] = (byte)(header.BlockDescriptors[i].BlockLength & 0xFF); + } + } + + return hdr; + } + + public static byte[] EncodeMode10(DecodedMode mode, PeripheralDeviceTypes deviceType) + { + var modeSize = 0; + + if(mode.Pages != null) modeSize += mode.Pages.Sum(page => page.PageResponse.Length); + + byte[] hdr = EncodeModeHeader10(mode.Header, deviceType); + modeSize += hdr.Length; + var md = new byte[modeSize]; + + Array.Copy(hdr, 0, md, 0, hdr.Length); + + if(mode.Pages == null) return md; + + { + int offset = hdr.Length; + + foreach(ModePage page in mode.Pages) + { + Array.Copy(page.PageResponse, 0, md, offset, page.PageResponse.Length); + offset += page.PageResponse.Length; + } + } + + return md; + } +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/Mode6.cs b/Aaru.Decoders/SCSI/Modes/Mode6.cs new file mode 100644 index 000000000..09824ca76 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/Mode6.cs @@ -0,0 +1,263 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Modes.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes and encodines SCSI modes in MODE SENSE/SELECT (6) format. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Aaru.CommonTypes.Structs.Devices.SCSI; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ + public static ModeHeader? DecodeModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType) + { + if(modeResponse == null || modeResponse.Length < 4 || modeResponse.Length < modeResponse[0] + 1) return null; + + var header = new ModeHeader + { + MediumType = (MediumTypes)modeResponse[1] + }; + + if(modeResponse[3] > 0) + { + // An incorrect size field, we cannot know if the following bytes are really the pages (probably not), + // so consider the MODE SENSE(6) response as invalid + if(modeResponse[3] + 4 > modeResponse.Length) return null; + + header.BlockDescriptors = new BlockDescriptor[modeResponse[3] / 8]; + + for(var i = 0; i < header.BlockDescriptors.Length; i++) + { + header.BlockDescriptors[i].Density = (DensityType)modeResponse[0 + i * 8 + 4]; + header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[1 + i * 8 + 4] << 16); + header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[2 + i * 8 + 4] << 8); + header.BlockDescriptors[i].Blocks += modeResponse[3 + i * 8 + 4]; + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[5 + i * 8 + 4] << 16); + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[6 + i * 8 + 4] << 8); + header.BlockDescriptors[i].BlockLength += modeResponse[7 + i * 8 + 4]; + } + } + + switch(deviceType) + { + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.MultiMediaDevice: + header.WriteProtected = (modeResponse[2] & 0x80) == 0x80; + header.DPOFUA = (modeResponse[2] & 0x10) == 0x10; + + break; + case PeripheralDeviceTypes.SequentialAccess: + header.WriteProtected = (modeResponse[2] & 0x80) == 0x80; + header.Speed = (byte)(modeResponse[2] & 0x0F); + header.BufferedMode = (byte)((modeResponse[2] & 0x70) >> 4); + + break; + case PeripheralDeviceTypes.PrinterDevice: + header.BufferedMode = (byte)((modeResponse[2] & 0x70) >> 4); + + break; + case PeripheralDeviceTypes.OpticalDevice: + header.WriteProtected = (modeResponse[2] & 0x80) == 0x80; + header.EBC = (modeResponse[2] & 0x01) == 0x01; + header.DPOFUA = (modeResponse[2] & 0x10) == 0x10; + + break; + } + + return header; + } + + public static string PrettifyModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType) => + PrettifyModeHeader(DecodeModeHeader6(modeResponse, deviceType), deviceType); + + public static DecodedMode? DecodeMode6(byte[] modeResponse, PeripheralDeviceTypes deviceType) + { + ModeHeader? hdr = DecodeModeHeader6(modeResponse, deviceType); + + if(!hdr.HasValue) return null; + + var decoded = new DecodedMode + { + Header = hdr.Value + }; + + var blkDrLength = 0; + + if(decoded.Header.BlockDescriptors != null) blkDrLength = decoded.Header.BlockDescriptors.Length; + + int offset = 4 + blkDrLength * 8; + int length = modeResponse[0] + 1; + + if(length != modeResponse.Length) return decoded; + + List listpages = []; + + while(offset < modeResponse.Length) + { + bool isSubpage = (modeResponse[offset] & 0x40) == 0x40; + var pg = new ModePage(); + var pageNo = (byte)(modeResponse[offset] & 0x3F); + + if(pageNo == 0) + { + pg.PageResponse = new byte[modeResponse.Length - offset]; + Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length); + pg.Page = 0; + pg.Subpage = 0; + offset += pg.PageResponse.Length; + } + else + { + if(isSubpage) + { + if(offset + 3 >= modeResponse.Length) break; + + pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4]; + int copyLen = pg.PageResponse.Length; + + if(pg.PageResponse.Length + offset > modeResponse.Length) copyLen = modeResponse.Length - offset; + + Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); + pg.Page = (byte)(modeResponse[offset] & 0x3F); + pg.Subpage = modeResponse[offset + 1]; + offset += pg.PageResponse.Length; + } + else + { + if(offset + 1 >= modeResponse.Length) break; + + pg.PageResponse = new byte[modeResponse[offset + 1] + 2]; + int copyLen = pg.PageResponse.Length; + + if(pg.PageResponse.Length + offset > modeResponse.Length) copyLen = modeResponse.Length - offset; + + Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); + pg.Page = (byte)(modeResponse[offset] & 0x3F); + pg.Subpage = 0; + offset += pg.PageResponse.Length; + } + } + + listpages.Add(pg); + } + + decoded.Pages = listpages.ToArray(); + + return decoded; + } + + public static byte[] EncodeModeHeader6(ModeHeader header, PeripheralDeviceTypes deviceType) + { + byte[] hdr = header.BlockDescriptors != null ? new byte[4 + header.BlockDescriptors.Length * 8] : new byte[4]; + + hdr[1] = (byte)header.MediumType; + + switch(deviceType) + { + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.MultiMediaDevice: + if(header.WriteProtected) hdr[2] += 0x80; + + if(header.DPOFUA) hdr[2] += 0x10; + + break; + case PeripheralDeviceTypes.SequentialAccess: + if(header.WriteProtected) hdr[2] += 0x80; + + hdr[2] += (byte)(header.Speed & 0x0F); + hdr[2] += (byte)(header.BufferedMode << 4 & 0x70); + + break; + case PeripheralDeviceTypes.PrinterDevice: + hdr[2] += (byte)(header.BufferedMode << 4 & 0x70); + + break; + case PeripheralDeviceTypes.OpticalDevice: + if(header.WriteProtected) hdr[2] += 0x80; + + if(header.EBC) hdr[2] += 0x01; + + if(header.DPOFUA) hdr[2] += 0x10; + + break; + } + + if(header.BlockDescriptors == null) return hdr; + + hdr[3] = (byte)(header.BlockDescriptors.Length * 8); + + for(var i = 0; i < header.BlockDescriptors.Length; i++) + { + hdr[0 + i * 8 + 4] = (byte)header.BlockDescriptors[i].Density; + hdr[1 + i * 8 + 4] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF0000) >> 16); + hdr[2 + i * 8 + 4] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF00) >> 8); + hdr[3 + i * 8 + 4] = (byte)(header.BlockDescriptors[i].Blocks & 0xFF); + hdr[5 + i * 8 + 4] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF0000) >> 16); + hdr[6 + i * 8 + 4] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF00) >> 8); + hdr[7 + i * 8 + 4] = (byte)(header.BlockDescriptors[i].BlockLength & 0xFF); + } + + return hdr; + } + + public static byte[] EncodeMode6(DecodedMode mode, PeripheralDeviceTypes deviceType) + { + var modeSize = 0; + + if(mode.Pages != null) modeSize += mode.Pages.Sum(page => page.PageResponse.Length); + + byte[] hdr = EncodeModeHeader6(mode.Header, deviceType); + modeSize += hdr.Length; + var md = new byte[modeSize]; + + Array.Copy(hdr, 0, md, 0, hdr.Length); + + if(mode.Pages == null) return md; + + { + int offset = hdr.Length; + + foreach(ModePage page in mode.Pages) + { + Array.Copy(page.PageResponse, 0, md, offset, page.PageResponse.Length); + offset += page.PageResponse.Length; + } + } + + return md; + } +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Modes/Structs.cs b/Aaru.Decoders/SCSI/Modes/Structs.cs new file mode 100644 index 000000000..c8f5c3e69 --- /dev/null +++ b/Aaru.Decoders/SCSI/Modes/Structs.cs @@ -0,0 +1,88 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Common structures for MODE pages decoding and encoding. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes +{ +#region Nested type: BlockDescriptor + + public struct BlockDescriptor + { + public DensityType Density; + public ulong Blocks; + public uint BlockLength; + } + +#endregion + +#region Nested type: DecodedMode + + public struct DecodedMode + { + public ModeHeader Header; + public ModePage[] Pages; + } + +#endregion + +#region Nested type: ModeHeader + + public struct ModeHeader + { + public MediumTypes MediumType; + public bool WriteProtected; + public BlockDescriptor[] BlockDescriptors; + public byte Speed; + public byte BufferedMode; + public bool EBC; + public bool DPOFUA; + } + +#endregion + +#region Nested type: ModePage + + public struct ModePage + { + public byte Page; + public byte Subpage; + public byte[] PageResponse; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/SSC/BlockLimits.cs b/Aaru.Decoders/SCSI/SSC/BlockLimits.cs new file mode 100644 index 000000000..a929e7bd5 --- /dev/null +++ b/Aaru.Decoders/SCSI/SSC/BlockLimits.cs @@ -0,0 +1,101 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : BlockLimits.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI SSC block limits structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Localization; + +namespace Aaru.Decoders.SCSI.SSC; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class BlockLimits +{ + public static BlockLimitsData? Decode(byte[] response) + { + if(response?.Length != 6) return null; + + return new BlockLimitsData + { + granularity = (byte)(response[0] & 0x1F), + maxBlockLen = (uint)((response[1] << 16) + (response[2] << 8) + response[3]), + minBlockLen = (ushort)((response[4] << 8) + response[5]) + }; + } + + public static string Prettify(BlockLimitsData? decoded) + { + if(decoded == null) return null; + + var sb = new StringBuilder(); + + if(decoded.Value.maxBlockLen == decoded.Value.minBlockLen) + sb.AppendFormat(Core.Device_block_size_is_fixed_at_0_bytes, decoded.Value.minBlockLen).AppendLine(); + else + { + if(decoded.Value.maxBlockLen > 0) + sb.AppendFormat(Core.Device_maximum_block_size_is_0_bytes, decoded.Value.maxBlockLen).AppendLine(); + else + sb.AppendLine(Core.Device_does_not_specify_a_maximum_block_size); + + sb.AppendFormat(Core.Device_minimum_block_size_is_0_bytes, decoded.Value.minBlockLen).AppendLine(); + + if(decoded.Value.granularity > 0) + { + sb.AppendFormat(Core.Device_needs_a_block_size_granularity_of_pow_0_1_bytes, + decoded.Value.granularity, + Math.Pow(2, decoded.Value.granularity)) + .AppendLine(); + } + } + + return sb.ToString(); + } + + public static string Prettify(byte[] response) => Prettify(Decode(response)); + +#region Nested type: BlockLimitsData + + public struct BlockLimitsData + { + /// All blocks size must be multiple of 2^ + public byte granularity; + /// Maximum block length in bytes + public uint maxBlockLen; + /// Minimum block length in bytes + public ushort minBlockLen; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/SSC/DensitySupport.cs b/Aaru.Decoders/SCSI/SSC/DensitySupport.cs new file mode 100644 index 000000000..f59439d8d --- /dev/null +++ b/Aaru.Decoders/SCSI/SSC/DensitySupport.cs @@ -0,0 +1,303 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DensitySupport.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI SSC density support structures. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.SCSI.SSC; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DensitySupport +{ + public static DensitySupportHeader? DecodeDensity(byte[] response) + { + if(response is not { Length: > 56 }) return null; + + var responseLen = (ushort)((response[0] << 8) + response[1] + 2); + + if(response.Length != responseLen) return null; + + List descriptors = []; + var offset = 4; + + while(offset < response.Length) + { + var descriptor = new DensitySupportDescriptor + { + primaryCode = response[offset + 0], + secondaryCode = response[offset + 1], + writable = (response[offset + 2] & 0x80) == 0x80, + duplicate = (response[offset + 2] & 0x40) == 0x40, + defaultDensity = (response[offset + 2] & 0x20) == 0x20, + reserved = (byte)((response[offset + 2] & 0x1E) >> 1), + lenvalid = (response[offset + 2] & 0x01) == 0x01, + len = (ushort)((response[offset + 3] << 8) + response[offset + 4]), + bpmm = (uint)((response[offset + 5] << 16) + (response[offset + 6] << 8) + response[offset + 7]), + width = (ushort)((response[offset + 8] << 8) + response[offset + 9]), + tracks = (ushort)((response[offset + 10] << 8) + response[offset + 11]), + capacity = (uint)((response[offset + 12] << 24) + + (response[offset + 13] << 16) + + (response[offset + 14] << 8) + + response[offset + 15]) + }; + + var tmp = new byte[8]; + Array.Copy(response, offset + 16, tmp, 0, 8); + descriptor.organization = StringHandlers.CToString(tmp).Trim(); + tmp = new byte[8]; + Array.Copy(response, offset + 24, tmp, 0, 8); + descriptor.name = StringHandlers.CToString(tmp).Trim(); + tmp = new byte[20]; + Array.Copy(response, offset + 32, tmp, 0, 20); + descriptor.description = StringHandlers.CToString(tmp).Trim(); + + if(descriptor.lenvalid) + offset += descriptor.len + 5; + else + offset += 52; + + descriptors.Add(descriptor); + } + + var decoded = new DensitySupportHeader + { + length = responseLen, + reserved = (ushort)((response[2] << 8) + response[3] + 2), + descriptors = descriptors.ToArray() + }; + + return decoded; + } + + public static string PrettifyDensity(DensitySupportHeader? density) + { + if(density == null) return null; + + DensitySupportHeader decoded = density.Value; + var sb = new StringBuilder(); + + foreach(DensitySupportDescriptor descriptor in decoded.descriptors) + { + sb.AppendFormat(Localization.Density_0_defined_by_1, descriptor.name, descriptor.organization).AppendLine(); + + sb.AppendFormat("\t" + Localization.Primary_code_0, descriptor.primaryCode).AppendLine(); + + if(descriptor.primaryCode != descriptor.secondaryCode) + sb.AppendFormat("\t" + Localization.Secondary_code_0, descriptor.secondaryCode).AppendLine(); + + if(descriptor.writable) sb.AppendLine("\t" + Localization.Drive_can_write_this_density); + + if(descriptor.duplicate) sb.AppendLine("\t" + Localization.This_descriptor_is_duplicated); + + if(descriptor.defaultDensity) sb.AppendLine("\t" + Localization.This_is_the_default_density_on_the_drive); + + sb.AppendFormat("\t" + Localization.Density_has_0_bits_per_mm__with_1_tracks_in_a_2_mm_width_tape, + descriptor.bpmm, + descriptor.tracks, + descriptor.width / (double)10) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Density_maximum_capacity_is_0_megabytes, descriptor.capacity) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Density_description_0, descriptor.description).AppendLine(); + sb.AppendLine(); + } + + return sb.ToString(); + } + + public static string PrettifyDensity(byte[] response) => PrettifyDensity(DecodeDensity(response)); + + public static MediaTypeSupportHeader? DecodeMediumType(byte[] response) + { + if(response is not { Length: > 60 }) return null; + + var responseLen = (ushort)((response[0] << 8) + response[1] + 2); + + if(response.Length != responseLen) return null; + + List descriptors = []; + var offset = 4; + + while(offset < response.Length) + { + var descriptor = new MediaTypeSupportDescriptor + { + mediumType = response[offset + 0], + reserved1 = response[offset + 1], + len = (ushort)((response[offset + 2] << 8) + response[offset + 3]) + }; + + if(descriptor.len != 52) return null; + + descriptor.numberOfCodes = response[offset + 4]; + descriptor.densityCodes = new byte[9]; + Array.Copy(response, offset + 5, descriptor.densityCodes, 0, 9); + descriptor.width = (ushort)((response[offset + 14] << 8) + response[offset + 15]); + descriptor.length = (ushort)((response[offset + 16] << 8) + response[offset + 17]); + descriptor.reserved1 = response[offset + 18]; + descriptor.reserved1 = response[offset + 19]; + var tmp = new byte[8]; + Array.Copy(response, offset + 20, tmp, 0, 8); + descriptor.organization = StringHandlers.CToString(tmp).Trim(); + tmp = new byte[8]; + Array.Copy(response, offset + 28, tmp, 0, 8); + descriptor.name = StringHandlers.CToString(tmp).Trim(); + tmp = new byte[20]; + Array.Copy(response, offset + 36, tmp, 0, 20); + descriptor.description = StringHandlers.CToString(tmp).Trim(); + + offset += 56; + + descriptors.Add(descriptor); + } + + var decoded = new MediaTypeSupportHeader + { + length = responseLen, + reserved = (ushort)((response[2] << 8) + response[3] + 2), + descriptors = descriptors.ToArray() + }; + + return decoded; + } + + public static string PrettifyMediumType(MediaTypeSupportHeader? mediumType) + { + if(mediumType == null) return null; + + MediaTypeSupportHeader decoded = mediumType.Value; + var sb = new StringBuilder(); + + foreach(MediaTypeSupportDescriptor descriptor in decoded.descriptors) + { + sb.AppendFormat(Localization.Medium_type_0_defined_by_1, descriptor.name, descriptor.organization) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Medium_type_code_0, descriptor.mediumType).AppendLine(); + + if(descriptor.numberOfCodes > 0) + { + sb.AppendFormat("\t" + Localization.Medium_supports_following_density_codes); + + for(var i = 0; i < descriptor.numberOfCodes; i++) sb.Append($" {descriptor.densityCodes[i]:X2}h"); + + sb.AppendLine(); + } + + sb.AppendFormat("\t" + Localization.Medium_has_a_nominal_length_of_0_m_in_a_1_mm_width_tape, + descriptor.length, + descriptor.width / (double)10) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Medium_description_0, descriptor.description).AppendLine(); + sb.AppendLine(); + } + + return sb.ToString(); + } + + public static string PrettifyMediumType(byte[] response) => PrettifyMediumType(DecodeMediumType(response)); + +#region Nested type: DensitySupportDescriptor + + public struct DensitySupportDescriptor + { + public byte primaryCode; + public byte secondaryCode; + public bool writable; + public bool duplicate; + public bool defaultDensity; + public byte reserved; + public bool lenvalid; + public ushort len; + public uint bpmm; + public ushort width; + public ushort tracks; + public uint capacity; + public string organization; + public string name; + public string description; + } + +#endregion + +#region Nested type: DensitySupportHeader + + public struct DensitySupportHeader + { + public ushort length; + public ushort reserved; + public DensitySupportDescriptor[] descriptors; + } + +#endregion + +#region Nested type: MediaTypeSupportDescriptor + + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public struct MediaTypeSupportDescriptor + { + public byte mediumType; + public byte reserved1; + public ushort len; + public byte numberOfCodes; + public byte[] densityCodes; + public ushort width; + public ushort length; + public byte reserved2; + public byte reserved3; + public string organization; + public string name; + public string description; + } + +#endregion + +#region Nested type: MediaTypeSupportHeader + + public struct MediaTypeSupportHeader + { + public ushort length; + public ushort reserved; + public MediaTypeSupportDescriptor[] descriptors; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Sense.cs b/Aaru.Decoders/SCSI/Sense.cs new file mode 100644 index 000000000..15335d758 --- /dev/null +++ b/Aaru.Decoders/SCSI/Sense.cs @@ -0,0 +1,2708 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Sense.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SCSI SENSE. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Decoders.ATA; + +// ReSharper disable UnusedMember.Global + +namespace Aaru.Decoders.SCSI; + +public enum SenseType +{ + StandardSense, + ExtendedSenseFixedCurrent, + ExtendedSenseFixedPast, + ExtendedSenseDescriptorCurrent, + ExtendedSenseDescriptorPast, + Invalid, + Unknown +} + +public struct DecodedSense +{ + public FixedSense? Fixed; + public DescriptorSense? Descriptor; + + // ReSharper disable once InconsistentNaming + public readonly byte ASC => Descriptor?.ASC ?? (Fixed?.ASC ?? 0); + + // ReSharper disable once InconsistentNaming + public readonly byte ASCQ => Descriptor?.ASCQ ?? (Fixed?.ASCQ ?? 0); + public readonly SenseKeys SenseKey => Descriptor?.SenseKey ?? (Fixed?.SenseKey ?? SenseKeys.NoSense); + public readonly string Description => Sense.GetSenseDescription(ASC, ASCQ); +} + +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +[SuppressMessage("ReSharper", "InconsistentNaming")] +public struct StandardSense +{ + /// If set, is valid + public bool AddressValid; + /// Error class, 0 to 6 + public byte ErrorClass; + /// Error type + public byte ErrorType; + /// Private usage + public byte Private; + /// LBA where error happened + public uint LBA; +} + +public enum SenseKeys : byte +{ + /// No information to be reported, but bits should be checked + NoSense = 0, + /// Target performed some recovery to successfully complete last command + RecoveredError = 1, + /// Target is not ready + NotReady = 2, + /// Non-recoverable medium error occurred + MediumError = 3, + /// Non-recoverable hardware error occurred + HardwareError = 4, + /// Target has received an illegal request + IllegalRequest = 5, + /// Target requires initiator attention + UnitAttention = 6, + /// A protected command has been denied + DataProtect = 7, + /// A blank block has been tried to read or a non-rewritable one to write + BlankCheck = 8, + /// For private/vendor usage + PrivateUse = 9, + /// COPY command aborted + CopyAborted = 0xA, + /// Command aborted + AbortedCommand = 0xB, + /// SEARCH command has been satisfied + Equal = 0xC, + /// End-of-medium reached with data remaining in buffer + VolumeOverflow = 0xD, + /// COMPARE failed + Miscompare = 0xE, + /// Complated + Completed = 0xF +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnassignedField.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct FixedSense +{ + /// If set, is valid + public bool InformationValid; + /// Contains number of current segment descriptor + public byte SegmentNumber; + /// If set indicates current command has read a filemark or a setmark + public bool Filemark; + /// If set indicates device has arrived end-of-medium + public bool EOM; + /// Means the requested logical block length did not match the logical block length on the medium + public bool ILI; + /// Contains the sense key + public SenseKeys SenseKey; + /// Additional information + public uint Information; + /// Additional sense length + public byte AdditionalLength; + /// Command specific information field + public uint CommandSpecific; + /// Additional sense code + public byte ASC; + /// Additional sense code qualifier + public byte ASCQ; + public byte FieldReplaceable; + /// If set, is valid + public bool SKSV; + public uint SenseKeySpecific; + public byte[] AdditionalSense; +} + +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct DescriptorSense +{ + /// Contains the sense key + public SenseKeys SenseKey; + /// Additional sense code + public byte ASC; + /// Additional sense code qualifier + public byte ASCQ; + public bool Overflow; + /// The descriptors, indexed by type + public Dictionary Descriptors; +} + +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct AnotherProgressIndicationSenseDescriptor +{ + public SenseKeys SenseKey; + public byte ASC; + public byte ASCQ; + public ushort Progress; +} + +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Sense +{ + /// Gets the SCSI SENSE type to help chosing the correct decoding function + /// The type. + /// Sense bytes. + public static SenseType GetType(byte[] sense) + { + if(sense == null) return SenseType.Invalid; + + if(sense.Length < 4) return SenseType.Invalid; + + if((sense[0] & 0x70) != 0x70) return sense.Length != 4 ? SenseType.Invalid : SenseType.StandardSense; + + return (sense[0] & 0x0F) switch + { + 0 => SenseType.ExtendedSenseFixedCurrent, + 1 => SenseType.ExtendedSenseFixedPast, + 2 => SenseType.ExtendedSenseDescriptorCurrent, + 3 => SenseType.ExtendedSenseDescriptorPast, + _ => SenseType.Unknown + }; + } + + public static StandardSense? DecodeStandard(byte[] sense) + { + if(GetType(sense) != SenseType.StandardSense) return null; + + var decoded = new StandardSense(); + decoded.AddressValid |= (sense[0] & 0x80) == 0x80; + decoded.ErrorClass = (byte)((sense[0] & 0x70) >> 4); + decoded.ErrorType = (byte)(sense[0] & 0x0F); + decoded.Private = (byte)((sense[1] & 0x80) >> 4); + decoded.LBA = (uint)(((sense[1] & 0x0F) << 16) + (sense[2] << 8) + sense[3]); + + return decoded; + } + + public static DecodedSense? Decode(byte[] sense) + { + var decoded = new DecodedSense(); + + switch(sense[0] & 0x7F) + { + case 0x70: + case 0x71: + decoded.Fixed = DecodeFixed(sense); + + break; + case 0x72: + case 0x73: + decoded.Descriptor = DecodeDescriptor(sense); + + break; + } + + return decoded.Fixed is null && decoded.Descriptor is null ? null : decoded; + } + + public static FixedSense? DecodeFixed(byte[] sense) => DecodeFixed(sense, out _); + + public static FixedSense? DecodeFixed(byte[] sense, out string senseDescription) + { + senseDescription = null; + + if(sense is null || sense.Length == 0) return null; + + if((sense[0] & 0x7F) != 0x70 && (sense[0] & 0x7F) != 0x71) return null; + + if(sense.Length < 8) return null; + + var decoded = new FixedSense + { + InformationValid = (sense[0] & 0x80) == 0x80, + SegmentNumber = sense[1], + Filemark = (sense[2] & 0x80) == 0x80, + EOM = (sense[2] & 0x40) == 0x40, + ILI = (sense[2] & 0x20) == 0x20, + SenseKey = (SenseKeys)(sense[2] & 0x0F), + Information = (uint)((sense[3] << 24) + (sense[4] << 16) + (sense[5] << 8) + sense[6]), + AdditionalLength = sense[7] + }; + + if(sense.Length >= 12) + decoded.CommandSpecific = (uint)((sense[8] << 24) + (sense[9] << 16) + (sense[10] << 8) + sense[11]); + + if(sense.Length >= 14) + { + decoded.ASC = sense[12]; + decoded.ASCQ = sense[13]; + senseDescription = GetSenseDescription(decoded.ASC, decoded.ASCQ); + } + + if(sense.Length >= 15) decoded.FieldReplaceable = sense[14]; + + if(sense.Length >= 18) decoded.SenseKeySpecific = (uint)((sense[15] << 16) + (sense[16] << 8) + sense[17]); + + if(sense.Length <= 18) return decoded; + + decoded.AdditionalSense = new byte[sense.Length - 18]; + Array.Copy(sense, 18, decoded.AdditionalSense, 0, decoded.AdditionalSense.Length); + + return decoded; + } + + public static DescriptorSense? DecodeDescriptor(byte[] sense) => DecodeDescriptor(sense, out _); + + public static DescriptorSense? DecodeDescriptor(byte[] sense, out string senseDescription) + { + senseDescription = null; + + if(sense == null) return null; + + if(sense.Length < 8) return null; + + // Fixed sense + if((sense[0] & 0x7F) == 0x70 || (sense[0] & 0x7F) == 0x71) return null; + + var decoded = new DescriptorSense + { + SenseKey = (SenseKeys)(sense[1] & 0x0F), + ASC = sense[2], + ASCQ = sense[3], + Overflow = (sense[4] & 0x80) == 0x80, + Descriptors = new Dictionary() + }; + + senseDescription = GetSenseDescription(decoded.ASC, decoded.ASCQ); + + var offset = 8; + + while(offset < sense.Length) + { + if(offset + 2 < sense.Length) + { + byte descType = sense[offset]; + int descLen = sense[offset + 1] + 2; + + var desc = new byte[descLen]; + + if(offset + descLen >= sense.Length) descLen = sense.Length - offset; + + Array.Copy(sense, offset, desc, 0, descLen); + + decoded.Descriptors.TryAdd(descType, desc); + + offset += descLen; + } + else + break; + } + + return decoded; + } + + public static string PrettifySense(byte[] sense) + { + SenseType type = GetType(sense); + + return type switch + { + SenseType.StandardSense => PrettifySense(DecodeStandard(sense)), + SenseType.ExtendedSenseFixedCurrent or SenseType.ExtendedSenseFixedPast => + PrettifySense(DecodeFixed(sense)), + SenseType.ExtendedSenseDescriptorCurrent or SenseType.ExtendedSenseDescriptorPast => + PrettifySense(DecodeDescriptor(sense)), + _ => null + }; + } + + public static string PrettifySense(StandardSense? sense) + { + if(!sense.HasValue) return null; + + return sense.Value.AddressValid + ? string.Format(Localization.Error_class_0_type_1_happened_on_block_2 + "\n", + sense.Value.ErrorClass, + sense.Value.ErrorType, + sense.Value.LBA) + : string.Format(Localization.Error_class_0_type_1 + "\n", + sense.Value.ErrorClass, + sense.Value.ErrorType); + } + + public static string PrettifySense(FixedSense? sense) + { + if(!sense.HasValue) return null; + + FixedSense decoded = sense.Value; + + var sb = new StringBuilder(); + + sb.AppendFormat(Localization.SCSI_SENSE_0, GetSenseKey(decoded.SenseKey)).AppendLine(); + + if(decoded.SegmentNumber > 0) sb.AppendFormat(Localization.On_segment_0, decoded.SegmentNumber).AppendLine(); + + if(decoded.Filemark) sb.AppendLine(Localization.Filemark_or_setmark_found); + + if(decoded.EOM) sb.AppendLine(Localization.End_of_medium_partition_found); + + if(decoded.ILI) sb.AppendLine(Localization.Incorrect_length_indicator); + + if(decoded.InformationValid) sb.AppendFormat(Localization.On_logical_block_0, decoded.Information).AppendLine(); + + if(decoded.AdditionalLength < 6) return sb.ToString(); + + sb.AppendLine(GetSenseDescription(decoded.ASC, decoded.ASCQ)); + + if(decoded.AdditionalLength < 10) return sb.ToString(); + + if(!decoded.SKSV) return sb.ToString(); + + switch(decoded.SenseKey) + { + case SenseKeys.IllegalRequest: + { + sb.AppendLine((decoded.SenseKeySpecific & 0x400000) == 0x400000 + ? Localization.Illegal_field_in_CDB + : Localization.Illegal_field_in_data_parameters); + + if((decoded.SenseKeySpecific & 0x200000) == 0x200000) + { + sb.AppendFormat(Localization.Invalid_value_in_bit_0_in_field_1_of_CDB, + (decoded.SenseKeySpecific & 0x70000) >> 16, + decoded.SenseKeySpecific & 0xFFFF) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Invalid_value_in_field_0_of_CDB, decoded.SenseKeySpecific & 0xFFFF) + .AppendLine(); + } + } + + break; + case SenseKeys.NotReady: + sb.AppendFormat(Localization.Format_progress_0, (double)(decoded.SenseKeySpecific & 0xFFFF) / 65536) + .AppendLine(); + + break; + case SenseKeys.RecoveredError: + case SenseKeys.HardwareError: + case SenseKeys.MediumError: + sb.AppendFormat(Localization.Actual_retry_count_is_0, decoded.SenseKeySpecific & 0xFFFF).AppendLine(); + + break; + } + + return sb.ToString(); + } + + public static string PrettifySense(DescriptorSense? sense) + { + if(!sense.HasValue) return null; + + DescriptorSense decoded = sense.Value; + + var sb = new StringBuilder(); + + sb.AppendFormat(Localization.SCSI_SENSE_0, GetSenseKey(decoded.SenseKey)).AppendLine(); + sb.AppendLine(GetSenseDescription(decoded.ASC, decoded.ASCQ)); + + if(decoded.Descriptors == null || decoded.Descriptors.Count == 0) return sb.ToString(); + + foreach(KeyValuePair kvp in decoded.Descriptors) + { + switch(kvp.Key) + { + case 0x00: + sb.AppendLine(PrettifyDescriptor00(kvp.Value)); + + break; + } + } + + return sb.ToString(); + } + + /// Decodes the information sense data descriptor + /// The information value + /// Descriptor. + public static ulong DecodeDescriptor00(byte[] descriptor) + { + if(descriptor.Length != 12 || descriptor[0] != 0x00) return 0; + + var temp = new byte[8]; + + temp[0] = descriptor[11]; + temp[1] = descriptor[10]; + temp[2] = descriptor[9]; + temp[3] = descriptor[8]; + temp[4] = descriptor[7]; + temp[5] = descriptor[6]; + temp[6] = descriptor[5]; + temp[7] = descriptor[4]; + + return BitConverter.ToUInt64(temp, 0); + } + + /// Decodes the command-specific information sense data descriptor + /// The command-specific information sense data descriptor. + /// Descriptor. + public static ulong DecodeDescriptor01(byte[] descriptor) + { + if(descriptor.Length != 12 || descriptor[0] != 0x01) return 0; + + var temp = new byte[8]; + + temp[0] = descriptor[11]; + temp[1] = descriptor[10]; + temp[2] = descriptor[9]; + temp[3] = descriptor[8]; + temp[4] = descriptor[7]; + temp[5] = descriptor[6]; + temp[6] = descriptor[5]; + temp[7] = descriptor[4]; + + return BitConverter.ToUInt64(temp, 0); + } + + /// Decodes the sense key specific sense data descriptor + /// The sense key specific sense data descriptor. + /// Descriptor. + public static byte[] DecodeDescriptor02(byte[] descriptor) + { + if(descriptor.Length != 8 || descriptor[0] != 0x02) return null; + + var temp = new byte[3]; + Array.Copy(descriptor, 4, temp, 0, 3); + + return temp; + } + + /// Decodes the field replaceable unit sense data descriptor + /// The field replaceable unit sense data descriptor. + /// Descriptor. + public static byte DecodeDescriptor03(byte[] descriptor) + { + if(descriptor.Length != 4 || descriptor[0] != 0x03) return 0; + + return descriptor[3]; + } + + /// Decodes the another progress indication sense data descriptor + /// The another progress indication sense data descriptor. + /// Descriptor. + public static AnotherProgressIndicationSenseDescriptor? DecodeDescriptor0A(byte[] descriptor) + { + if(descriptor.Length != 8 || descriptor[0] != 0x0A) return null; + + return new AnotherProgressIndicationSenseDescriptor + { + SenseKey = (SenseKeys)descriptor[2], + ASC = descriptor[3], + ASCQ = descriptor[4], + Progress = (ushort)((descriptor[6] << 8) + descriptor[7]) + }; + } + + public static void DecodeDescriptor04(byte[] descriptor, out bool filemark, out bool eom, out bool ili) + { + filemark = (descriptor[3] & 0x80) > 0; + eom = (descriptor[3] & 0x40) > 0; + ili = (descriptor[3] & 0x20) > 0; + } // ReSharper disable UnusedParameter.Global + public static void DecodeDescriptor05(byte[] descriptor) => throw new NotImplementedException("Check SBC-3"); + + public static void DecodeDescriptor06(byte[] descriptor) => throw new NotImplementedException("Check OSD"); + + public static void DecodeDescriptor07(byte[] descriptor) => throw new NotImplementedException("Check OSD"); + + public static void DecodeDescriptor08(byte[] descriptor) => throw new NotImplementedException("Check OSD"); + + public static AtaErrorRegistersLba48 DecodeDescriptor09(byte[] descriptor) => new() + { + Error = descriptor[3], + SectorCount = (ushort)((descriptor[4] << 8) + descriptor[5]), + LbaLowCurrent = descriptor[6], + LbaLowPrevious = descriptor[7], + LbaMidCurrent = descriptor[8], + LbaMidPrevious = descriptor[9], + LbaHighCurrent = descriptor[10], + LbaHighPrevious = descriptor[11], + DeviceHead = descriptor[12], + Status = descriptor[13] + }; + + public static void DecodeDescriptor0B(byte[] descriptor) => throw new NotImplementedException("Check SBC-3"); + + public static void DecodeDescriptor0D(byte[] descriptor) => throw new NotImplementedException("Check SBC-3"); + + public static string PrettifyDescriptor00(ulong information) => + string.Format(Localization.Sense_PrettifyDescriptor00_On_logical_block_0 + "\n", information); + + public static string PrettifyDescriptor00(byte[] descriptor) => + PrettifyDescriptor00(DecodeDescriptor00(descriptor)); + + public static string GetSenseKey(SenseKeys key) => key switch + { + SenseKeys.AbortedCommand => "ABORTED COMMAND", + SenseKeys.BlankCheck => "BLANK CHECK", + SenseKeys.CopyAborted => "COPY ABORTED", + SenseKeys.DataProtect => "DATA PROTECT", + SenseKeys.Equal => "EQUAL", + SenseKeys.HardwareError => "HARDWARE ERROR", + SenseKeys.IllegalRequest => "ILLEGAL REQUEST", + SenseKeys.MediumError => "MEDIUM ERROR", + SenseKeys.Miscompare => "MISCOMPARE", + SenseKeys.NoSense => "NO SENSE", + SenseKeys.PrivateUse => "PRIVATE USE", + SenseKeys.RecoveredError => "RECOVERED ERROR", + SenseKeys.Completed => "COMPLETED", + SenseKeys.UnitAttention => "UNIT ATTENTION", + SenseKeys.VolumeOverflow => "VOLUME OVERFLOW", + _ => "UNKNOWN" + }; + + [SuppressMessage("ReSharper", "InconsistentNaming")] + public static string GetSenseDescription(byte ASC, byte ASCQ) + { + switch(ASC) + { + case 0x00: + switch(ASCQ) + { + case 0x00: + return "NO ADDITIONAL SENSE INFORMATION"; + case 0x01: + return "FILEMARK DETECTED"; + case 0x02: + return "END-OF-PARTITION/MEDIUM DETECTED"; + case 0x03: + return "SETMARK DETECTED"; + case 0x04: + return "BEGINNING-OF-PARTITION/MEDIUM DETECTED"; + case 0x05: + return "END-OF-DATA DETECTED"; + case 0x06: + return "I/O PROCESS TERMINATED"; + case 0x07: + return "PROGRAMMABLE EARLY WARNING DETECTED"; + case 0x11: + return "AUDIO PLAY OPERATION IN PROGRESS"; + case 0x12: + return "AUDIO PLAY OPERATION PAUSED"; + case 0x13: + return "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED"; + case 0x14: + return "AUDIO PLAY OPERATION STOPPED DUE TO ERROR"; + case 0x15: + return "NO CURRENT AUDIO STATUS TO RETURN"; + case 0x16: + return "OPERATION IN PROGRESS"; + case 0x17: + return "CLEANING REQUESTED"; + case 0x18: + return "ERASE OPERATION IN PROGRESS"; + case 0x19: + return "LOCATE OPERATION IN PROGRESS"; + case 0x1A: + return "REWIND OPERATION IN PROGRESS"; + case 0x1B: + return "SET CAPACITY OPERATION IN PROGRESS"; + case 0x1C: + return "VERIFY OPERATION IN PROGRESS"; + case 0x1D: + return "ATA PASS THROUGH INFORMATION AVAILABLE"; + case 0x1E: + return "CONFLICTING SA CREATION REQUEST"; + case 0x1F: + return "LOGICAL UNIT TRANSITIONING TO ANOTHER POWER CONDITION"; + case 0x20: + return "EXTENDED COPY INFORMATION AVAILABLE"; + case 0x21: + return "ATOMIC COMMAND ABORTED DUE TO ACA"; + } + + break; + case 0x01: + switch(ASCQ) + { + case 0x00: + return "NO INDEX/SECTOR SIGNAL"; + } + + break; + case 0x02: + switch(ASCQ) + { + case 0x00: + return "NO SEEK COMPLETE"; + } + + break; + case 0x03: + switch(ASCQ) + { + case 0x00: + return "PERIPHERAL DEVICE WRITE FAULT"; + case 0x01: + return "NO WRITE CURRENT"; + case 0x02: + return "EXCESSIVE WRITE ERRORS"; + } + + break; + case 0x04: + switch(ASCQ) + { + case 0x00: + return "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE"; + case 0x01: + return "LOGICAL UNIT IS IN PROCESS OF BECOMING READY"; + case 0x02: + return "LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED"; + case 0x03: + return "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED"; + case 0x04: + return "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS"; + case 0x05: + return "LOGICAL UNIT NOT READY, REBUILD IN PROGRESS"; + case 0x06: + return "LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS"; + case 0x07: + return "LOGICAL UNIT NOT READY, OPERATION IN PROGRESS"; + case 0x08: + return "LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS"; + case 0x09: + return "LOGICAL UNIT NOT READY, SELF-TEST IN PROGRESS"; + case 0x0A: + return "LOGICAL UNIT NOT ACCESSIBLE, ASYMMETRIC ACCESS STATE TRANSITION"; + case 0x0B: + return "LOGICAL UNIT NOT ACCESSIBLE, TARGET IN STANDBY STATE"; + case 0x0C: + return "LOGICAL UNIT NOT ACCESSIBLE, TARGET PORT IN UNAVAILABLE STATE"; + case 0x0D: + return "LOGICAL UNIT NOT READY, STRUCTURE CHECK REQUIRED"; + case 0x0E: + return "LOGICAL UNIT NOT READY, SECURITY SESSION IN PROGRESS"; + case 0x10: + return "LOGICAL UNIT NOT READY, AUXILIARY MEMORY NOT ACCESSIBLE"; + case 0x11: + return "LOGICAL UNIT NOT READY, NOTIFY (ENABLE SPINUP) REQUIRED"; + case 0x12: + return "LOGICAL UNIT NOT READY, OFFLINE"; + case 0x13: + return "LOGICAL UNIT NOT READY, SA CREATION IN PROGRESS"; + case 0x14: + return "LOGICAL UNIT NOT READY, SPACE ALLOCATION IN PROGRESS"; + case 0x15: + return "LOGICAL UNIT NOT READY, ROBOTICS DISABLED"; + case 0x16: + return "LOGICAL UNIT NOT READY, CONFIGURATION REQUIRED"; + case 0x17: + return "LOGICAL UNIT NOT READY, CALIBRATION REQUIRED"; + case 0x18: + return "LOGICAL UNIT NOT READY, A DOOR IS OPEN"; + case 0x19: + return "LOGICAL UNIT NOT READY, OPERATING IN SEQUENTIAL MODE"; + case 0x1A: + return "LOGICAL UNIT NOT READY, START STOP UNIT IN PROGRESS"; + case 0x1B: + return "LOGICAL UNIT NOT READY, SANITIZE IN PROGRESS"; + case 0x1C: + return "LOGICAL UNIT NOT READY, ADDITIONAL POWER USE NOT YET GRANTED"; + case 0x1D: + return "LOGICAL UNIT NOT READY, CONFIGURATION IN PROGRESS"; + case 0x1E: + return "LOGICAL UNIT NOT READY, MICROCODE ACTIVATION REQUIRED"; + case 0x1F: + return "LOGICAL UNIT NOT READY, MICROCODE DOWNLOAD REQUIRED"; + case 0x20: + return "LOGICAL UNIT NOT READY, LOGICAL UNIT RESET REQUIRED"; + case 0x21: + return "LOGICAL UNIT NOT READY, HARD RESET REQUIRED"; + case 0x22: + return "LOGICAL UNIT NOT READY, POWER CYCLE REQUIRED"; + } + + break; + case 0x05: + switch(ASCQ) + { + case 0x00: + return "LOGICAL UNIT DOES NOT RESPOND TO SELECTION"; + } + + break; + case 0x06: + switch(ASCQ) + { + case 0x00: + return "NO REFERENCE POSITION FOUND"; + } + + break; + case 0x07: + switch(ASCQ) + { + case 0x00: + return "MULTIPLE PERIPHERAL DEVICES SELECTED"; + } + + break; + case 0x08: + switch(ASCQ) + { + case 0x00: + return "LOGICAL UNIT COMMUNICATION FAILURE"; + case 0x01: + return "LOGICAL UNIT COMMUNICATION TIME-OUT"; + case 0x02: + return "LOGICAL UNIT COMMUNICATION PARITY ERROR"; + case 0x03: + return "LOGICAL UNIT COMMUNICATION CRC ERROR"; + case 0x04: + return "UNREACHABLE COPY TARGET"; + } + + break; + case 0x09: + switch(ASCQ) + { + case 0x00: + return "TRACK FOLLOWING ERROR"; + case 0x01: + return "TRACKING SERVO FAILURE"; + case 0x02: + return "FOCUS SERVO FAILURE"; + case 0x03: + return "SPINDLE SERVO FAILURE"; + case 0x04: + return "HEAD SELECT FAULT"; + case 0x05: + return "VIBRATION INDUCED TRACKING ERROR"; + } + + break; + case 0x0A: + switch(ASCQ) + { + case 0x00: + return "ERROR LOG OVERFLOW"; + } + + break; + case 0x0B: + switch(ASCQ) + { + case 0x00: + return "WARNING"; + case 0x01: + return "WARNING - SPECIFIED TEMPERATURE EXCEEDED"; + case 0x02: + return "WARNING - ENCLOSURE DEGRADED"; + case 0x03: + return "WARNING - BACKGROUND SELF-TEST FAILED"; + case 0x04: + return "WARNING - BACKGROUND PRE-SCAN DETECTED MEDIUM ERROR"; + case 0x05: + return "WARNING - BACKGROUND MEDIUM SCAN DETECTED MEDIUM ERROR"; + case 0x06: + return "WARNING - NON-VOLATILE CACHE NOW VOLATILE"; + case 0x07: + return "WARNING - DEGRADED POWER TO NON-VOLATILE CACHE"; + case 0x08: + return "WARNING - POWER LOSS EXPECTED"; + case 0x09: + return "WARNING - DEVICE STATISTICS NOTIFICATION ACTIVE"; + case 0x0A: + return "WARNING - HIGH CRITICAL TEMPERATURE LIMIT EXCEEDED"; + case 0x0B: + return "WARNING - LOW CRITICAL TEMPERATURE LIMIT EXCEEDED"; + case 0x0C: + return "WARNING - HIGH OPERATING TEMPERATURE LIMIT EXCEEDED"; + case 0x0D: + return "WARNING - LOW OPERATING TEMPERATURE LIMIT EXCEEDED"; + case 0x0E: + return "WARNING - HIGH CRITICAL HUMIDITY LIMIT EXCEEDED"; + case 0x0F: + return "WARNING - LOW CRITICAL HUMIDITY LIMIT EXCEEDED"; + case 0x10: + return "WARNING - HIGH OPERATING HUMIDITY LIMIT EXCEEDED"; + case 0x11: + return "WARNING - LOW OPERATING HUMIDITY LIMIT EXCEEDED"; + } + + break; + case 0x0C: + switch(ASCQ) + { + case 0x00: + return "WRITE ERROR"; + case 0x01: + return "WRITE ERROR - RECOVERED WITH AUTO REALLOCATION"; + case 0x02: + return "WRITE ERROR - AUTO REALLOCATION FAILED"; + case 0x03: + return "WRITE ERROR - RECOMMENDED REASSIGNMENT"; + case 0x04: + return "COMPRESSION CHECK MISCOMPARE ERROR"; + case 0x05: + return "DATA EXPANSION OCCURRED DURING COMPRESSION"; + case 0x06: + return "BLOCK NOT COMPRESSIBLE"; + case 0x07: + return "WRITE ERROR - RECOVERY NEEDED"; + case 0x08: + return "WRITE ERROR - RECOVERY FAILED"; + case 0x09: + return "WRITE ERROR - LOSS OF STREAMING"; + case 0x0A: + return "WRITE ERROR - PADDING BLOCKS ADDED"; + case 0x0B: + return "AUXILIARY MEMORY WRITE ERROR"; + case 0x0C: + return "WRITE ERROR - UNEXPECTED UNSOLICITED DATA"; + case 0x0D: + return "WRITE ERROR - NOT ENOUGH UNSOLICITED DATA"; + case 0x0E: + return "MULTIPLE WRITE ERRORS"; + case 0x0F: + return "DEFECTS IN ERROR WINDOW"; + case 0x10: + return "INCOMPLETE MULTIPLE ATOMIC WRITE OPERATIONS"; + case 0x11: + return "WRITE ERROR - RECOVERY SCAN NEEDED"; + case 0x12: + return "WRITE ERROR - INSUFFICIENT ZONE RESOURCES"; + } + + break; + case 0x0D: + switch(ASCQ) + { + case 0x00: + return "ERROR DETECTED BY THIRD PARTY TEMPORARY INITIATOR"; + case 0x01: + return "THIRD PARTY DEVICE FAILURE"; + case 0x02: + return "COPY TARGET DEVICE NOT REACHABLE"; + case 0x03: + return "INCORRECT COPY TARGET DEVICE TYPE"; + case 0x04: + return "COPY TARGET DEVICE DATA UNDERRUN"; + case 0x05: + return "COPY TARGET DEVICE DATA OVERRUN"; + } + + break; + case 0x0E: + switch(ASCQ) + { + case 0x00: + return "INVALID INFORMATION UNIT"; + case 0x01: + return "INFORMATION UNIT TOO SHORT"; + case 0x02: + return "INFORMATION UNIT TOO LONG"; + case 0x03: + return "INVALID FIELD IN COMMAND INFORMATION UNIT"; + } + + break; + case 0x10: + switch(ASCQ) + { + case 0x00: + return "ID CRC OR ECC ERROR"; + case 0x01: + return "LOGICAL BLOCK GUARD CHECK FAILED"; + case 0x02: + return "LOGICAL BLOCK APPLICATION TAG CHECK FAILED"; + case 0x03: + return "LOGICAL BLOCK REFERENCE TAG CHECK FAILED"; + case 0x04: + return "LOGICAL BLOCK PROTECTION ERROR ON RECOVER BUFFERED DATA"; + case 0x05: + return "LOGICAL BLOCK PROTECTION METHOD ERROR"; + } + + break; + case 0x11: + switch(ASCQ) + { + case 0x00: + return "UNRECOVERED READ ERROR"; + case 0x01: + return "READ RETRIES EXHAUSTED"; + case 0x02: + return "ERROR TOO LONG TO CORRECT"; + case 0x03: + return "MULTIPLE READ ERRORS"; + case 0x04: + return "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED"; + case 0x05: + return "L-EC UNCORRECTABLE ERROR"; + case 0x06: + return "CIRC UNRECOVERED ERROR"; + case 0x07: + return "DATA RESYNCHRONIZATION ERROR"; + case 0x08: + return "INCOMPLETE BLOCK READ"; + case 0x09: + return "NO GAP FOUND"; + case 0x0A: + return "MISCORRECTED ERROR"; + case 0x0B: + return "UNRECOVERED READ ERROR - RECOMMENDED REASSIGNMENT"; + case 0x0C: + return "UNRECOVERED READ ERROR - RECOMMENDED REWRITE THE DATA"; + case 0x0D: + return "DE-COMPRESSION CRC ERROR"; + case 0x0E: + return "CANNOT DECOMPRESS USING DECLARED ALGORITHM"; + case 0x0F: + return "ERROR READING UPC/EAN NUMBER"; + case 0x10: + return "ERROR READING ISRC NUMBER"; + case 0x11: + return "READ ERROR - LOSS OF STREAMING"; + case 0x12: + return "AUXILIARY MEMORY READ ERROR"; + case 0x13: + return "READ ERROR - FAILED RETRANSMISSION REQUEST"; + case 0x14: + return "READ ERROR - LBA MARKED BAD BY APPLICATION CLIENT"; + case 0x15: + return "WRITE AFTER SANITIZE REQUIRED"; + } + + break; + case 0x12: + switch(ASCQ) + { + case 0x00: + return "ADDRESS MARK NOT FOUND FOR ID FIELD"; + } + + break; + case 0x13: + switch(ASCQ) + { + case 0x00: + return "ADDRESS MARK NOT FOUND FOR DATA FIELD"; + } + + break; + case 0x14: + switch(ASCQ) + { + case 0x00: + return "RECORDED ENTITY NOT FOUND"; + case 0x01: + return "RECORD NOT FOUND"; + case 0x02: + return "FILEMARK OR SETMARK NOT FOUND"; + case 0x03: + return "END-OF-DATA NOT FOUND"; + case 0x04: + return "BLOCK SEQUENCE ERROR"; + case 0x05: + return "RECORD NOT FOUND - RECOMMENDED REASSIGNMENT"; + case 0x06: + return "RECORD NOT FOUND - DATA AUTO-REALLOCATED"; + case 0x07: + return "LOCATE OPERATION FAILURE"; + } + + break; + case 0x15: + switch(ASCQ) + { + case 0x00: + return "RANDOM POSITIONING ERROR"; + case 0x01: + return "MECHANICAL POSITIONING ERROR"; + case 0x02: + return "POSITIONING ERROR DETECTED BY READ OF MEDIUM"; + } + + break; + case 0x16: + switch(ASCQ) + { + case 0x00: + return "DATA SYNCHRONIZATION MARK ERROR"; + case 0x01: + return "DATA SYNC ERROR - DATA REWRITTEN"; + case 0x02: + return "DATA SYNC ERROR - RECOMMENDED REWRITE"; + case 0x03: + return "DATA SYNC ERROR - DATA AUTO-REALLOCATED"; + case 0x04: + return "DATA SYNC ERROR - RECOMMENDED REASSIGNMENT"; + } + + break; + case 0x17: + switch(ASCQ) + { + case 0x00: + return "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED"; + case 0x01: + return "RECOVERED DATA WITH RETRIES"; + case 0x02: + return "RECOVERED DATA WITH POSITIVE HEAD OFFSET"; + case 0x03: + return "RECOVERED DATA WITH NEGATIVE HEAD OFFSET"; + case 0x04: + return "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED"; + case 0x05: + return "RECOVERED DATA USING PREVIOUS SECTOR ID"; + case 0x06: + return "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED"; + case 0x07: + return "RECOVERED DATA WITHOUT ECC - RECOMMENDED REASSIGNMENT"; + case 0x08: + return "RECOVERED DATA WITHOUT ECC - RECOMMENDED REWRITE"; + case 0x09: + return "RECOVERED DATA WITHOUT ECC - DATA REWRITTEN"; + } + + break; + case 0x18: + switch(ASCQ) + { + case 0x00: + return "RECOVERED DATA WITH ERROR CORRECTION APPLIED"; + case 0x01: + return "RECOVERED DATA WITH ERROR CORRECTION & RETRIES APPLIED"; + case 0x02: + return "RECOVERED DATA - DATA AUTO-REALLOCATED"; + case 0x03: + return "RECOVERED DATA WITH CIRC"; + case 0x04: + return "RECOVERED DATA WITH L-EC"; + case 0x05: + return "RECOVERED DATA - RECOMMENDED REASSIGNMENT"; + case 0x06: + return "RECOVERED DATA - RECOMMENDED REWRITE"; + case 0x07: + return "RECOVERED DATA WITH ECC - DATA REWRITTEN"; + case 0x08: + return "RECOVERED DATA WITH LINKING"; + } + + break; + case 0x19: + switch(ASCQ) + { + case 0x00: + return "DEFECT LIST ERROR"; + case 0x01: + return "DEFECT LIST NOT AVAILABLE"; + case 0x02: + return "DEFECT LIST ERROR IN PRIMARY LIST"; + case 0x03: + return "DEFECT LIST ERROR IN GROWN LIST"; + } + + break; + case 0x1A: + switch(ASCQ) + { + case 0x00: + return "PARAMETER LIST LENGTH ERROR"; + } + + break; + case 0x1B: + switch(ASCQ) + { + case 0x00: + return "SYNCHRONOUS DATA TRANSFER ERROR"; + } + + break; + case 0x1C: + switch(ASCQ) + { + case 0x00: + return "DEFECT LIST NOT FOUND"; + case 0x01: + return "PRIMARY DEFECT LIST NOT FOUND"; + case 0x02: + return "GROWN DEFECT LIST NOT FOUND"; + } + + break; + case 0x1D: + switch(ASCQ) + { + case 0x00: + return "MISCOMPARE DURING VERIFY OPERATION"; + case 0x01: + return "MISCOMPARE VERIFY OF UNMAPPED LBA"; + } + + break; + case 0x1E: + switch(ASCQ) + { + case 0x00: + return "RECOVERED ID WITH ECC CORRECTION"; + } + + break; + case 0x1F: + switch(ASCQ) + { + case 0x00: + return "PARTIAL DEFECT LIST TRANSFER"; + } + + break; + case 0x20: + switch(ASCQ) + { + case 0x00: + return "INVALID COMMAND OPERATION CODE"; + case 0x01: + return "ACCESS DENIED - INITIATOR PENDING-ENROLLED"; + case 0x02: + return "ACCESS DENIED - NO ACCESS RIGHTS"; + case 0x03: + return "ACCESS DENIED - INVALID MGMT ID KEY"; + case 0x04: + return "ILLEGAL COMMAND WHILE IN WRITE CAPABLE STATE"; + case 0x05: + return "ILLEGAL COMMAND WHILE IN READ CAPABLE STATE"; + case 0x06: + return "ILLEGAL COMMAND WHILE IN EXPLICIT ADDRESS MODE"; + case 0x07: + return "ILLEGAL COMMAND WHILE IN IMPLICIT ADDRESS MODE"; + case 0x08: + return "ACCESS DENIED - ENROLLMENT CONFLICT"; + case 0x09: + return "ACCESS DENIED - INVALID LUN IDENTIFIER"; + case 0x0A: + return "ACCESS DENIED - INVALID PROXY TOKEN"; + case 0x0B: + return "ACCESS DENIED - ACL LUN CONFLICT"; + case 0x0C: + return "ILLEGAL COMMAND WHEN NOT IN APPEND-ONLY MODE"; + } + + break; + case 0x21: + switch(ASCQ) + { + case 0x00: + return "LOGICAL BLOCK ADDRESS OUT OF RANGE"; + case 0x01: + return "INVALID ELEMENT ADDRESS"; + case 0x02: + return "INVALID ADDRESS FOR WRITE"; + case 0x03: + return "INVALID WRITE CROSSING LAYER JUMP"; + case 0x04: + return "UNALIGNED WRITE COMMAND"; + case 0x05: + return "WRITE BOUNDARY VIOLATION"; + case 0x06: + return "ATTEMPT TO READ INVALID DATA"; + case 0x07: + return "READ BOUNDARY VIOLATION"; + } + + break; + case 0x22: + switch(ASCQ) + { + case 0x00: + return "ILLEGAL FUNCTION"; + } + + break; + case 0x23: + switch(ASCQ) + { + case 0x00: + return "INVALID TOKEN OPERATION, CAUSE NOT REPORTABLE"; + case 0x01: + return "INVALID TOKEN OPERATION, UNSUPPORTED TOKEN TYPE"; + case 0x02: + return "INVALID TOKEN OPERATION, REMOTE TOKEN USAGE NOT SUPPORTED"; + case 0x03: + return "INVALID TOKEN OPERATION, REMOTE ROD TOKEN CREATION NOT SUPPORTED"; + case 0x04: + return "INVALID TOKEN OPERATION, TOKEN UNKNOWN"; + case 0x05: + return "INVALID TOKEN OPERATION, TOKEN CORRUPT"; + case 0x06: + return "INVALID TOKEN OPERATION, TOKEN REVOKED"; + case 0x07: + return "INVALID TOKEN OPERATION, TOKEN EXPIRED"; + case 0x08: + return "INVALID TOKEN OPERATION, TOKEN CANCELLED"; + case 0x09: + return "INVALID TOKEN OPERATION, TOKEN DELETED"; + case 0x0A: + return "INVALID TOKEN OPERATION, INVALID TOKEN LENGTH"; + } + + break; + case 0x24: + switch(ASCQ) + { + case 0x00: + return "ILLEGAL FIELD IN CDB"; + case 0x01: + return "CDB DECRYPTION ERROR"; + case 0x02: + return "INVALID CDB FIELD WHILE IN EXPLICIT BLOCK ADDRESS MODEL"; + case 0x03: + return "INVALID CDB FIELD WHILE IN IMPLICIT BLOCK ADDRESS MODEL"; + case 0x04: + return "SECURITY AUDIT VALUE FROZEN"; + case 0x05: + return "SECURITY WORKING KEY FROZEN"; + case 0x06: + return "NONCE NOT UNIQUE"; + case 0x07: + return "NONCE TIMESTAMP OUT OF RANGE"; + case 0x08: + return "INVALID XCDB"; + } + + break; + case 0x25: + switch(ASCQ) + { + case 0x00: + return "LOGICAL UNIT NOT SUPPORTED"; + } + + break; + case 0x26: + switch(ASCQ) + { + case 0x00: + return "INVALID FIELD IN PARAMETER LIST"; + case 0x01: + return "PARAMETER NOT SUPPORTED"; + case 0x02: + return "PARAMETER VALUE INVALID"; + case 0x03: + return "THRESHOLD PARAMETERS NOT SUPPORTED"; + case 0x04: + return "INVALID RELEASE OF PERSISTENT RESERVATION"; + case 0x05: + return "DATA DECRYPTION ERROR"; + case 0x06: + return "TOO MANY TARGET DESCRIPTORS"; + case 0x07: + return "UNSUPPORTED TARGET DESCRIPTOR TYPE CODE"; + case 0x08: + return "TOO MANY SEGMENT DESCRIPTORS"; + case 0x09: + return "UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE"; + case 0x0A: + return "UNEXPECTED INEXACT SEGMENT"; + case 0x0B: + return "INLINE DATA LENGTH EXCEEDED"; + case 0x0C: + return "INVALID OPERATION FOR COPY SOURCE OR DESTINATION"; + case 0x0D: + return "COPY SEGMENT GRANULARITY VIOLATION"; + case 0x0E: + return "INVALID PARAMETER WHILE PORT IS ENABLED"; + case 0x0F: + return "INVALID DATA-OUT BUFFER INTEGRITY CHECK VALUE"; + case 0x10: + return "DATA DECRYPTION KEY FAIL LIMIT REACHED"; + case 0x11: + return "INCOMPLETE KEY-ASSOCIATED DATA SET"; + case 0x12: + return "VENDOR SPECIFIC KEY REFERENCE NOT FOUND"; + case 0x13: + return "APPLICATION TAG MODE PAGE IS INVALID"; + } + + break; + case 0x27: + switch(ASCQ) + { + case 0x00: + return "WRITE PROTECTED"; + case 0x01: + return "HARDWARE WRITE PROTECTED"; + case 0x02: + return "LOGICAL UNIT SOFTWARE WRITE PROTECTED"; + case 0x03: + return "ASSOCIATED WRITE PROTECT"; + case 0x04: + return "PERSISTENT WRITE PROTECT"; + case 0x05: + return "PERMANENT WRITE PROTECT"; + case 0x06: + return "CONDITIONAL WRITE PROTECT"; + case 0x07: + return "SPACE ALLOCATION FAILED WRITE PROTECT"; + case 0x08: + return "ZONE IS READ ONLY"; + } + + break; + case 0x28: + switch(ASCQ) + { + case 0x00: + return "NOT READY TO READY CHANGE (MEDIUM MAY HAVE CHANGED)"; + case 0x01: + return "IMPORT OR EXPORT ELEMENT ACCESSED"; + case 0x02: + return "FORMAT-LAYER MAY HAVE CHANGED"; + case 0x03: + return "IMPORT/EXPORT ELEMENT ACCESSED, MEDIUM CHANGED"; + } + + break; + case 0x29: + switch(ASCQ) + { + case 0x00: + return "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"; + case 0x01: + return "POWER ON OCCURRED"; + case 0x02: + return "SCSI BUS RESET OCCURRED"; + case 0x03: + return "BUS DEVICE RESET FUNCTION OCCURRED"; + case 0x04: + return "DEVICE INTERNAL RESET"; + case 0x05: + return "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED"; + case 0x06: + return "TRANSCEIVER MODE CHANGED TO LVD"; + case 0x07: + return "I_T NEXUS LOSS OCCURRED"; + } + + break; + case 0x2A: + switch(ASCQ) + { + case 0x00: + return "PARAMETERS CHANGED"; + case 0x01: + return "MODE PARAMETERS CHANGED"; + case 0x02: + return "LOG PARAMETERS CHANGED"; + case 0x03: + return "RESERVATIONS PREEMPTED"; + case 0x04: + return "RESERVATIONS RELEASED"; + case 0x05: + return "REGISTRATIONS PREEMPTED"; + case 0x06: + return "ASYMMETRIC ACCESS STATE CHANGED"; + case 0x07: + return "IMPLICIT ASYMMETRIC ACCESS STATE TRANSITION FAILED"; + case 0x08: + return "PRIORITY CHANGED"; + case 0x09: + return "CAPACITY DATA HAS CHANGED"; + case 0x0A: + return "ERROR HISTORY I_T NEXUS CLEARED"; + case 0x0B: + return "ERROR HISTORY SNAPSHOT RELEASED"; + case 0x0C: + return "ERROR RECOVERY ATTRIBUTES HAVE CHANGED"; + case 0x0D: + return "DATA ENCRYPTION CAPABILITIES CHANGED"; + case 0x10: + return "TIMESTAMP CHANGED"; + case 0x11: + return "DATA ENCRYPTION PARAMETERS CHANGED BY ANOTHER I_T NEXUS"; + case 0x12: + return "DATA ENCRYPTION PARAMETERS CHANGED BY VENDOR SPECIFIC EVENT"; + case 0x13: + return "DATA ENCRYPTION KEY INSTANCE COUNTER HAS CHANGED"; + case 0x14: + return "SA CREATION CAPABILITIES DATA HAS CHANGED"; + case 0x15: + return "MEDIUM REMOVAL PREVENTION PREEMPTED"; + } + + break; + case 0x2B: + switch(ASCQ) + { + case 0x00: + return "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT"; + } + + break; + case 0x2C: + switch(ASCQ) + { + case 0x00: + return "COMMAND SEQUENCE ERROR"; + case 0x01: + return "TOO MANY WINDOWS SPECIFIED"; + case 0x02: + return "INVALID COMBINATION OF WINDOWS SPECIFIED"; + case 0x03: + return "CURRENT PROGRAM AREA IS NOT EMPTY"; + case 0x04: + return "CURRENT PROGRAM AREA IS EMPTY"; + case 0x05: + return "ILLEGAL POWER CONDITION REQUEST"; + case 0x06: + return "PERSISTENT PREVENT CONFLICT"; + case 0x07: + return "PREVIOUS BUSY STATUS"; + case 0x08: + return "PREVIOUS TASK SET FULL STATUS"; + case 0x09: + return "PREVIOUS RESERVATION CONFLICT STATUS"; + case 0x0A: + return "PARTITION OR COLLECTION CONTAINS USER OBJECTS"; + case 0x0B: + return "NOT RESERVED"; + case 0x0C: + return "ORWRITE GENERATION DOES NOT MATCH"; + case 0x0D: + return "RESET WRITE POINTER NOT ALLOWED"; + case 0x0E: + return "ZONE IS OFFLINE"; + case 0x0F: + return "STREAM NOT OPEN"; + case 0x10: + return "UNWRITTEN DATA IN ZONE"; + } + + break; + case 0x2D: + switch(ASCQ) + { + case 0x00: + return "OVERWRITE ERROR ON UPDATE IN PLACE"; + } + + break; + case 0x2E: + switch(ASCQ) + { + case 0x00: + return "INSUFFICIENT TIME FOR OPERATION"; + case 0x01: + return "COMMAND TIMEOUT BEFORE PROCESSING"; + case 0x02: + return "COMMAND TIMEOUT DURING PROCESSING"; + case 0x03: + return "COMMAND TIMEOUT DURING PROCESSING DUE TO ERROR RECOVERY"; + } + + break; + case 0x2F: + switch(ASCQ) + { + case 0x00: + return "COMMANDS CLEARED BY ANOTHER INITIATOR"; + case 0x01: + return "COMMANDS CLEARED BY POWER LOSS NOTIFICATION"; + case 0x02: + return "COMMANDS CLEARED BY DEVICE SERVER"; + case 0x03: + return "SOME COMMANDS CLEARED BY QUEUING LAYER EVENT"; + } + + break; + case 0x30: + switch(ASCQ) + { + case 0x00: + return "INCOMPATIBLE MEDIUM INSTALLED"; + case 0x01: + return "CANNOT READ MEDIUM - UNKNOWN FORMAT"; + case 0x02: + return "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT"; + case 0x03: + return "CLEANING CARTRIDGE INSTALLED"; + case 0x04: + return "CANNOT WRITE MEDIUM - UNKNOWN FORMAT"; + case 0x05: + return "CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT"; + case 0x06: + return "CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM"; + case 0x07: + return "CLEANING FAILURE"; + case 0x08: + return "CANNOT WRITE - APPLICATION CODE MISMATCH"; + case 0x09: + return "CURRENT SESSION NOT FIXATED FOR APPEND"; + case 0x0A: + return "CLEANING REQUEST REJECTED"; + case 0x0C: + return "WORM MEDIUM - OVERWRITE ATTEMPTED"; + case 0x0D: + return "WORM MEDIUM - INTEGRITY CHECK"; + case 0x10: + return "MEDIUM NOT FORMATTED"; + case 0x11: + return "INCOMPATIBLE VOLUME TYPE"; + case 0x12: + return "INCOMPATIBLE VOLUME QUALIFIER"; + case 0x13: + return "CLEANING VOLUME EXPIRED"; + } + + break; + case 0x31: + switch(ASCQ) + { + case 0x00: + return "MEDIUM FORMAT CORRUPTED"; + case 0x01: + return "FORMAT COMMAND FAILED"; + case 0x02: + return "ZONED FORMATTING FAILED DUE TO SPARE LINKING"; + case 0x03: + return "SANITIZE COMMAND FAILED"; + } + + break; + case 0x32: + switch(ASCQ) + { + case 0x00: + return "NO DEFECT SPARE LOCATION AVAILABLE"; + case 0x01: + return "DEFECT LIST UPDATE FAILURE"; + } + + break; + case 0x33: + switch(ASCQ) + { + case 0x00: + return "TAPE LENGTH ERROR"; + } + + break; + case 0x34: + switch(ASCQ) + { + case 0x00: + return "ENCLOSURE FAILURE"; + } + + break; + case 0x35: + switch(ASCQ) + { + case 0x00: + return "ENCLOSURE SERVICES FAILURE"; + case 0x01: + return "UNSUPPORTED ENCLOSURE FUNCTION"; + case 0x02: + return "ENCLOSURE SERVICES UNAVAILABLE"; + case 0x03: + return "ENCLOSURE SERVICES TRANSFER FAILURE"; + case 0x04: + return "ENCLOSURE SERVICES TRANSFER REFUSED"; + case 0x05: + return "ENCLOSURE SERVICES CHECKSUM ERROR"; + } + + break; + case 0x36: + switch(ASCQ) + { + case 0x00: + return "RIBBON, INK, OR TONER FAILURE"; + } + + break; + case 0x37: + switch(ASCQ) + { + case 0x00: + return "ROUNDED PARAMETER"; + } + + break; + case 0x38: + switch(ASCQ) + { + case 0x00: + return "EVENT STATUS NOTIFICATION"; + case 0x02: + return "ESN - POWER MANAGEMENT CLASS EVENT"; + case 0x04: + return "ESN - MEDIA CLASS EVENT"; + case 0x06: + return "ESN - DEVICE BUSY CLASS EVENT"; + case 0x07: + return "THIN PROVISIONING SOFT THRESHOLD REACHED"; + } + + break; + case 0x39: + switch(ASCQ) + { + case 0x00: + return "SAVING PARAMETERS NOT SUPPORTED"; + } + + break; + case 0x3A: + switch(ASCQ) + { + case 0x00: + return "MEDIUM NOT PRESENT"; + case 0x01: + return "MEDIUM NOT PRESENT - TRAY CLOSED"; + case 0x02: + return "MEDIUM NOT PRESENT - TRAY OPEN"; + case 0x03: + return "MEDIUM NOT PRESENT - LOADABLE"; + case 0x04: + return "MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE"; + } + + break; + case 0x3B: + switch(ASCQ) + { + case 0x00: + return "SEQUENTIAL POSITIONING ERROR"; + case 0x01: + return "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM"; + case 0x02: + return "TAPE POSITION ERROR AT END-OF-MEDIUM"; + case 0x03: + return "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY"; + case 0x04: + return "SLEW FAILURE"; + case 0x05: + return "PAPER JAM"; + case 0x06: + return "FAILED TO SENSE TOP-OF-FORM"; + case 0x07: + return "FAILED TO SENSE BOTTOM-OF-FORM"; + case 0x08: + return "REPOSITION ERROR"; + case 0x09: + return "READ PAST END OF MEDIUM"; + case 0x0A: + return "READ PAST BEGINNING OF MEDIUM"; + case 0x0B: + return "POSITION PAST END OF MEDIUM"; + case 0x0C: + return "POSITION PAST BEGINNING OF MEDIUM"; + case 0x0D: + return "MEDIUM DESTINATION ELEMENT FULL"; + case 0x0E: + return "MEDIUM SOURCE ELEMENT EMPTY"; + case 0x0F: + return "END OF MEDIUM REACHED"; + case 0x11: + return "MEDIUM MAGAZINE NOT ACCESSIBLE"; + case 0x12: + return "MEDIUM MAGAZINE REMOVED"; + case 0x13: + return "MEDIUM MAGAZINE INSERTED"; + case 0x14: + return "MEDIUM MAGAZINE LOCKED"; + case 0x15: + return "MEDIUM MAGAZINE UNLOCKED"; + case 0x16: + return "MECHANICAL POSITIONING OR CHANGER ERROR"; + case 0x17: + return "READ PAST END OF USER OBJECT"; + case 0x18: + return "ELEMENT DISABLED"; + case 0x19: + return "ELEMENT ENABLED"; + case 0x1A: + return "DATA TRANSFER DEVICE REMOVED"; + case 0x1B: + return "DATA TRANSFER DEVICE INSERTED"; + case 0x1C: + return "TOO MANY LOGICAL OBJECTS ON PARTITION TO SUPPORT OPERATION"; + } + + break; + case 0x3D: + switch(ASCQ) + { + case 0x00: + return "INVALID BITS IN IDENTIFY MESSAGE"; + } + + break; + case 0x3E: + switch(ASCQ) + { + case 0x00: + return "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET"; + case 0x01: + return "LOGICAL UNIT FAILURE"; + case 0x02: + return "TIMEOUT ON LOGICAL UNIT"; + case 0x03: + return "LOGICAL UNIT FAILED SELF-TEST"; + case 0x04: + return "LOGICAL UNIT UNABLE TO UPDATE SELF-TEST LOG"; + } + + break; + case 0x3F: + switch(ASCQ) + { + case 0x00: + return "TARGET OPERATING CONDITIONS HAVE CHANGED"; + case 0x01: + return "MICROCODE HAS BEEN CHANGED"; + case 0x02: + return "CHANGED OPERATING DEFINITION"; + case 0x03: + return "INQUIRY DATA HAS CHANGED"; + case 0x04: + return "COMPONENT DEVICE ATTACHED"; + case 0x05: + return "DEVICE IDENTIFIED CHANGED"; + case 0x06: + return "REDUNDANCY GROUP CREATED OR MODIFIED"; + case 0x07: + return "REDUNDANCY GROUP DELETED"; + case 0x08: + return "SPARE CREATED OR MODIFIED"; + case 0x09: + return "SPARE DELETED"; + case 0x0A: + return "VOLUME SET CREATED OR MODIFIED"; + case 0x0B: + return "VOLUME SET DELETED"; + case 0x0C: + return "VOLUME SET DEASSIGNED"; + case 0x0D: + return "VOLUME SET REASSIGNED"; + case 0x0E: + return "REPORTED LUNS DATA HAS CHANGED"; + case 0x0F: + return "ECHO BUFFER OVERWRITTEN"; + case 0x10: + return "MEDIUM LOADABLE"; + case 0x11: + return "MEDIUM AUXILIARY MEMORY ACCESSIBLE"; + case 0x12: + return "iSCSI IP ADDRESS ADDED"; + case 0x13: + return "iSCSI IP ADDRESS REMOVED"; + case 0x14: + return "iSCSI IP ADDRESS CHANGED"; + case 0x15: + return "INSPECT REFERRALS SENSE DESCRIPTORS"; + case 0x16: + return "MICROCODE HAS BEEN CHANGED WITHOUT RESET"; + case 0x17: + return "ZONE TRANSITION TO FULL"; + } + + break; + case 0x40: + return ASCQ switch + { + 0x00 => "RAM FAILURE", + _ => $"DIAGNOSTIC FAILURE ON COMPONENT {ASCQ:X2}h" + }; + case 0x41: + switch(ASCQ) + { + case 0x00: + return "DATA PATH FAILURE"; + } + + break; + case 0x42: + switch(ASCQ) + { + case 0x00: + return "POWER-ON OR SELF-TEST FAILURE"; + } + + break; + case 0x43: + switch(ASCQ) + { + case 0x00: + return "MESSAGE ERROR"; + } + + break; + case 0x44: + switch(ASCQ) + { + case 0x00: + return "INTERNAL TARGET FAILURE"; + case 0x01: + return "PERSISTENT RESERVATION INFORMATION LOST"; + case 0x71: + return "ATA DEVICE FAILED SET FEATURES"; + } + + break; + case 0x45: + switch(ASCQ) + { + case 0x00: + return "SELECT OR RESELECT FAILURE"; + } + + break; + case 0x46: + switch(ASCQ) + { + case 0x00: + return "UNSUCCESSFUL SOFT RESET"; + } + + break; + case 0x47: + switch(ASCQ) + { + case 0x00: + return "SCSI PARITY ERROR"; + case 0x01: + return "DATA PHASE CRC ERROR DETECTED"; + case 0x02: + return "SCSI PARITY ERROR DETECTED DURING ST DATA PHASE"; + case 0x03: + return "INFORMATION UNIT iuCRC ERROR DETECTED"; + case 0x04: + return "ASYNCHRONOUS INFORMATION PROTECTION ERROR DETECTED"; + case 0x05: + return "PROTOCOL SERVICE CRC ERROR"; + case 0x06: + return "PHY TEST FUNCTION IN PROGRESS"; + case 0x7F: + return "SOME COMMANDS CLEARED BY iSCSI PROTOCOL EVENT"; + } + + break; + case 0x48: + switch(ASCQ) + { + case 0x00: + return "INITIATOR DETECTED ERROR MESSAGE RECEIVED"; + } + + break; + case 0x49: + switch(ASCQ) + { + case 0x00: + return "INVALID MESSAGE ERROR"; + } + + break; + case 0x4A: + switch(ASCQ) + { + case 0x00: + return "COMMAND PHASE ERROR"; + } + + break; + case 0x4B: + switch(ASCQ) + { + case 0x00: + return "DATA PHASE ERROR"; + case 0x01: + return "INVALID TARGET PORT TRANSFER TAG RECEIVED"; + case 0x02: + return "TOO MUCH WRITE DATA"; + case 0x03: + return "ACK/NAK TIMEOUT"; + case 0x04: + return "NAK RECEIVED"; + case 0x05: + return "DATA OFFSET ERROR"; + case 0x06: + return "INITIATOR RESPONSE TIMEOUT"; + case 0x07: + return "CONNECTION LOST"; + case 0x08: + return "DATA-IN BUFFER OVERFLOW - DATA BUFFER SIZE"; + case 0x09: + return "DATA-IN BUFFER OVERFLOW - DATA BUFFER DESCRIPTOR AREA"; + case 0x0A: + return "DATA-IN BUFFER ERROR"; + case 0x0B: + return "DATA-OUT BUFFER OVERFLOW - DATA BUFFER SIZE"; + case 0x0C: + return "DATA-OUT BUFFER OVERFLOW - DATA BUFFER DESCRIPTOR AREA"; + case 0x0D: + return "DATA-OUT BUFFER ERROR"; + case 0x0E: + return "PCIe FABRIC ERROR"; + case 0x0F: + return "PCIe COMPLETION TIMEOUT"; + case 0x10: + return "PCIe COMPLETION ABORT"; + case 0x11: + return "PCIe POISONED TLP RECEIVED"; + case 0x12: + return "PCIe ECRC CHECK FAILED"; + case 0x13: + return "PCIe UNSUPPORTED REQUEST"; + case 0x14: + return "PCIe ACS VIOLATION"; + case 0x15: + return "PCIe TLP PREFIX BLOCKED"; + } + + break; + case 0x4C: + switch(ASCQ) + { + case 0x00: + return "LOGICAL UNIT FAILED SELF-CONFIGURATION"; + } + + break; + case 0x4E: + return $"OVERLAPPED COMMANDS ATTEMPTED FOR TASK TAG {ASCQ:X2}h"; + case 0x50: + switch(ASCQ) + { + case 0x00: + return "WRITE APPEND ERROR"; + case 0x01: + return "WRITE APPEND POSITION ERROR"; + case 0x02: + return "POSITION ERROR RELATED TO TIMING"; + } + + break; + case 0x51: + switch(ASCQ) + { + case 0x00: + return "ERASE FAILURE"; + case 0x01: + return "ERASE FAILURE - INCOMPLETE ERASE OPERATION DETECTED"; + } + + break; + case 0x52: + switch(ASCQ) + { + case 0x00: + return "CARTRIDGE FAULT"; + } + + break; + case 0x53: + switch(ASCQ) + { + case 0x00: + return "MEDIA LOAD OR EJECT FAILED"; + case 0x01: + return "UNLOAD TAPE FAILURE"; + case 0x02: + return "MEDIUM REMOVAL PREVENTED"; + case 0x03: + return "MEDIUM REMOVAL PREVENTED BY DATA TRANSFER ELEMENT"; + case 0x04: + return "MEDIUM THREAD OR UNTHREAD FAILURE"; + case 0x05: + return "VOLUME IDENTIFIER INVALID"; + case 0x06: + return "VOLUME IDENTIFIED MISSING"; + case 0x07: + return "DUPLICATE VOLUME IDENTIFIER"; + case 0x08: + return "ELEMENT STATUS UNKNOWN"; + case 0x09: + return "DATA TRANSFER DEVICE ERROR - LOAD FAILED"; + case 0x0A: + return "DATA TRANSFER DEVICE ERROR - UNLOAD FAILED"; + case 0x0B: + return "DATA TRANSFER DEVICE ERROR - UNLOAD MISSING"; + case 0x0C: + return "DATA TRANSFER DEVICE ERROR - EJECT FAILED"; + case 0x0D: + return "DATA TRANSFER DEVICE ERROR - LIBRARY COMMUNICATION FAILED"; + } + + break; + case 0x54: + switch(ASCQ) + { + case 0x00: + return "SCSI TO HOST SYSTEM INTERFACE FAILURE"; + } + + break; + case 0x55: + switch(ASCQ) + { + case 0x00: + return "SYSTEM RESOURCE FAILURE"; + case 0x01: + return "SYSTEM BUFFER FULL"; + case 0x02: + return "INSUFFICIENT RESERVATION RESOURCES"; + case 0x03: + return "INSUFFICIENT RESOURCES"; + case 0x04: + return "INSUFFICIENT REGISTRATION RESOURCES"; + case 0x05: + return "INSUFFICIENT ACCESS CONTROL RESOURCES"; + case 0x06: + return "AUXILIARY MEMORY OUT OF SPACE"; + case 0x07: + return "QUOTA ERROR"; + case 0x08: + return "MAXIMUM NUMBER OF SUPPLEMENTAL DECRYPTION KEYS EXCEEDED"; + case 0x09: + return "MEDIUM AUXILIARY MEMORY NOT ACCESSIBLE"; + case 0x0A: + return "DATA CURRENTLY UNAVAILABLE"; + case 0x0B: + return "INSUFFICIENT POWER FOR OPERATION"; + case 0x0C: + return "INSUFFICIENT RESOURCES TO CREATE ROD"; + case 0x0D: + return "INSUFFICIENT RESOURCES TO CREATE ROD TOKEN"; + case 0x0E: + return "INSUFFICIENT ZONE RESOURCES"; + case 0x0F: + return "INSUFFICIENT ZONE RESOURCES TO COMPLETE WRITE"; + case 0x10: + return "MAXIMUM NUMBER OF STREAMS OPEN"; + } + + break; + case 0x57: + switch(ASCQ) + { + case 0x00: + return "UNABLE TO RECOVER TABLE-OF-CONTENTS"; + } + + break; + case 0x58: + switch(ASCQ) + { + case 0x00: + return "GENERATION DOES NOT EXIST"; + } + + break; + case 0x59: + switch(ASCQ) + { + case 0x00: + return "UPDATED BLOCK READ"; + } + + break; + case 0x5A: + switch(ASCQ) + { + case 0x00: + return "OPERATOR REQUEST OR STATE CHANGE INPUT"; + case 0x01: + return "OPERATOR MEDIUM REMOVAL REQUEST"; + case 0x02: + return "OPERATOR SELECTED WRITE PROTECT"; + case 0x03: + return "OPERATOR SELECTED WRITE PERMIT"; + } + + break; + case 0x5B: + switch(ASCQ) + { + case 0x00: + return "LOG EXCEPTION"; + case 0x01: + return "THRESHOLD CONDITION MET"; + case 0x02: + return "LOG COUNTER AT MAXIMUM"; + case 0x03: + return "LOG LIST CODES EXHAUSTED"; + } + + break; + case 0x5C: + switch(ASCQ) + { + case 0x00: + return "RPL STATUS CHANGE"; + case 0x01: + return "SPINDLES SYNCHRONIZED"; + case 0x02: + return "SPINDLES NOT SYNCHRONIZED"; + case 0x03: + return "SPARE AREA EXHAUSTION PREDICTION THRESHOLD EXCEEDED"; + case 0x10: + return "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x11: + return "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x12: + return "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x13: + return "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x14: + return "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x15: + return "HARDWARE IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x16: + return "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x17: + return "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x18: + return "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED"; + case 0x19: + return "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x1A: + return "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x1B: + return "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x1C: + return "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0x20: + return "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x21: + return "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x22: + return "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x23: + return "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x24: + return "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x25: + return "CONTROLLER IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x26: + return "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x27: + return "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x28: + return "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED"; + case 0x29: + return "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x2A: + return "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x2B: + return "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x2C: + return "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0x30: + return "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x31: + return "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x32: + return "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x33: + return "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x34: + return "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x35: + return "DATA CHANNEL IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x36: + return "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x37: + return "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x38: + return "DATA CHANNEL IMPENDING FAILURE DATA CHANNEL DETECTED"; + case 0x39: + return "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x3A: + return "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x3B: + return "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x3C: + return "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0x40: + return "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x41: + return "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x42: + return "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x43: + return "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x44: + return "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x45: + return "SERVO IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x46: + return "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x47: + return "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x48: + return "SERVO IMPENDING FAILURE SERVO DETECTED"; + case 0x49: + return "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x4A: + return "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x4B: + return "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x4C: + return "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0x50: + return "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x51: + return "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x52: + return "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x53: + return "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x54: + return "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x55: + return "SPINDLE IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x56: + return "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x57: + return "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x58: + return "SPINDLE IMPENDING FAILURE SPINDLE DETECTED"; + case 0x59: + return "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x5A: + return "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x5B: + return "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x5C: + return "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0x60: + return "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x61: + return "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x62: + return "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x63: + return "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x64: + return "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x65: + return "FIRMWARE IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x66: + return "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x67: + return "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x68: + return "FIRMWARE IMPENDING FAILURE FIRMWARE DETECTED"; + case 0x69: + return "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x6A: + return "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x6B: + return "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x6C: + return "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0xFF: + return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)"; + } + + break; + case 0x5E: + switch(ASCQ) + { + case 0x00: + return "LOW POWER CONDITION ON"; + case 0x01: + return "IDLE CONDITION ACTIVATED BY TIMER"; + case 0x02: + return "STANDBY CONDITION ACTIVATED BY TIMER"; + case 0x03: + return "IDLE CONDITION ACTIVATED BY COMMAND"; + case 0x04: + return "STANDBY CONDITION ACTIVATED BY COMMAND"; + case 0x05: + return "IDLE_B CONDITION ACTIVATED BY TIMER"; + case 0x06: + return "IDLE_B CONDITION ACTIVATED BY COMMAND"; + case 0x07: + return "IDLE_C CONDITION ACTIVATED BY TIMER"; + case 0x08: + return "IDLE_C CONDITION ACTIVATED BY COMMAND"; + case 0x09: + return "STANDBY_Y CONDITION ACTIVATED BY TIMER"; + case 0x0A: + return "STANDBY_Y CONDITION ACTIVATED BY COMMAND"; + case 0x41: + return "POWER STATE CHANGED TO ACTIVE"; + case 0x42: + return "POWER STATE CHANGED TO IDLE"; + case 0x43: + return "POWER STATE CHANGED TO STANDBY"; + case 0x45: + return "POWER STATE CHANGED TO SLEEP"; + case 0x47: + return "POWER STATE CHANGED TO DEVICE CONTROL"; + } + + break; + case 0x60: + switch(ASCQ) + { + case 0x00: + return "LAMP FAILURE"; + } + + break; + case 0x61: + switch(ASCQ) + { + case 0x00: + return "VIDEO ACQUISITION ERROR"; + case 0x01: + return "UNABLE TO ACQUIRE VIDEO"; + case 0x02: + return "OUT OF FOCUS"; + } + + break; + case 0x62: + switch(ASCQ) + { + case 0x00: + return "SCAN HEAD POSITIONING ERROR"; + } + + break; + case 0x63: + switch(ASCQ) + { + case 0x00: + return "END OF USER AREA ENCOUNTERED ON THIS TRACK"; + case 0x01: + return "PACKET DOES NOT FIT IN AVAILABLE SPACE"; + } + + break; + case 0x64: + switch(ASCQ) + { + case 0x00: + return "ILLEGAL MODE FOR THIS TRACK"; + case 0x01: + return "INVALID PACKET SIZE"; + } + + break; + case 0x65: + switch(ASCQ) + { + case 0x00: + return "VOLTAGE FAULT"; + } + + break; + case 0x66: + switch(ASCQ) + { + case 0x00: + return "AUTOMATIC DOCUMENT FEEDER COVER UP"; + case 0x01: + return "AUTOMATIC DOCUMENT FEEDER LIFT UP"; + case 0x02: + return "DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER"; + case 0x03: + return "DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER"; + } + + break; + case 0x67: + switch(ASCQ) + { + case 0x00: + return "CONFIGURATION FAILURE"; + case 0x01: + return "CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED"; + case 0x02: + return "ADD LOGICAL UNIT FAILED"; + case 0x03: + return "MODIFICATION OF LOGICAL UNIT FAILED"; + case 0x04: + return "EXCHANGE OF LOGICAL UNIT FAILED"; + case 0x05: + return "REMOVE OF LOGICAL UNIT FAILED"; + case 0x06: + return "ATTACHMENT OF LOGICAL UNIT FAILED"; + case 0x07: + return "CREATION OF LOGICAL UNIT FAILED"; + case 0x08: + return "ASSIGN FAILURE OCCURRED"; + case 0x09: + return "MULTIPLY ASSIGNED LOGICAL UNIT"; + case 0x0A: + return "SET TARGET PORT GROUPS COMMAND FAILED"; + case 0x0B: + return "ATA DEVICE FEATURE NOT ENABLED"; + } + + break; + case 0x68: + switch(ASCQ) + { + case 0x00: + return "LOGICAL UNIT NOT CONFIGURED"; + case 0x01: + return "SUBSIDIARY LOGICAL UNIT NOT CONFIGURED"; + } + + break; + case 0x69: + switch(ASCQ) + { + case 0x00: + return "DATA LOSS ON LOGICAL UNIT"; + case 0x01: + return "MULTIPLE LOGICAL UNIT FAILURES"; + case 0x02: + return "PARITY/DATA MISMATCH"; + } + + break; + case 0x6A: + switch(ASCQ) + { + case 0x00: + return "INFORMATIONAL, REFER TO LOG"; + } + + break; + case 0x6B: + switch(ASCQ) + { + case 0x00: + return "STATE CHANGE HAS OCCURRED"; + case 0x01: + return "REDUNDANCY LEVEL GOT BETTER"; + case 0x02: + return "REDUNDANCY LEVEL GOT WORSE"; + } + + break; + case 0x6C: + switch(ASCQ) + { + case 0x00: + return "REBUILD FAILURE OCCURRED"; + } + + break; + case 0x6D: + switch(ASCQ) + { + case 0x00: + return "RECALCULATE FAILURE OCCURRED"; + } + + break; + case 0x6E: + switch(ASCQ) + { + case 0x00: + return "COMMAND TO LOGICAL UNIT FAILED"; + } + + break; + case 0x6F: + switch(ASCQ) + { + case 0x00: + return "COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE"; + case 0x01: + return "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT"; + case 0x02: + return "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED"; + case 0x03: + return "READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION"; + case 0x04: + return "MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION"; + case 0x05: + return "DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR"; + case 0x06: + return "INSUFFICIENT BLOCK COUNT FOR BINDING NONCE RECORDING"; + case 0x07: + return "CONFLICT IN BINDING NONCE RECORDING"; + } + + break; + case 0x70: + return $"DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF {ASCQ:X2}h"; + case 0x71: + switch(ASCQ) + { + case 0x00: + return "DECOMPRESSION EXCEPTION LONG ALGORITHM ID"; + } + + break; + case 0x72: + switch(ASCQ) + { + case 0x00: + return "SESSION FIXATION ERROR"; + case 0x01: + return "SESSION FIXATION ERROR WRITING LEAD-IN"; + case 0x02: + return "SESSION FIXATION ERROR WRITING LEAD-OUT"; + case 0x03: + return "SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION"; + case 0x04: + return "EMPTY OR PARTIALLY WRITTEN RESERVED TRACK"; + case 0x05: + return "NO MORE TRACK RESERVATIONS ALLOWED"; + case 0x06: + return "RMZ EXTENSION IS NOT ALLOWED"; + case 0x07: + return "NO MORE TEST ZONE EXTENSIONS ARE ALLOWED"; + } + + break; + case 0x73: + switch(ASCQ) + { + case 0x00: + return "CD CONTROL ERROR"; + case 0x01: + return "POWER CALIBRATION AREA ALMOST FULL"; + case 0x02: + return "POWER CALIBRATION AREA IS FULL"; + case 0x03: + return "POWER CALIBRATION AREA ERROR"; + case 0x04: + return "PROGRAM MEMORY AREA UPDATE FAILURE"; + case 0x05: + return "PROGRAM MEMORY AREA IS FULL"; + case 0x06: + return "RMA/PMA IS ALMOST FULL"; + case 0x10: + return "CURRENT POWER CALIBRATION AREA ALMOST FULL"; + case 0x11: + return "CURRENT POWER CALIBRATION AREA IS FULL"; + case 0x17: + return "RDZ IS FULL"; + } + + break; + case 0x74: + switch(ASCQ) + { + case 0x00: + return "SECURITY ERROR"; + case 0x01: + return "UNABLE TO DECRYPT DATA"; + case 0x02: + return "UNENCRYPTED DATA ENCOUNTERED WHILE DECRYPTING"; + case 0x03: + return "INCORRECT DATA ENCRYPTION KEY"; + case 0x04: + return "CRYPTOGRAPHIC INTEGRITY VALIDATION FAILED"; + case 0x05: + return "ERROR DECRYPTING DATA"; + case 0x06: + return "UNKNOWN SIGNATURE VERIFICATION KEY"; + case 0x07: + return "ENCRYPTION PARAMETERS NOT USABLE"; + case 0x08: + return "DIGITAL SIGNATURE VALIDATION FAILURE"; + case 0x09: + return "ENCRYPTION MODE MISMATCH ON READ"; + case 0x0A: + return "ENCRYPTED BLOCK NOT RAW READ ENABLED"; + case 0x0B: + return "INCORRECT ENCRYPTION PARAMETERS"; + case 0x0C: + return "UNABLE TO DECRYPT PARAMETER LIST"; + case 0x0D: + return "ENCRYPTION ALGORITHM DISABLED"; + case 0x10: + return "SA CREATION PARAMETER VALUE INVALID"; + case 0x11: + return "SA CREATION PARAMETER VALUE REJECTED"; + case 0x12: + return "INVALID SA USAGE"; + case 0x21: + return "DATA ENCRYPTION CONFIGURATION PREVENTED"; + case 0x30: + return "SA CREATION PARAMETER NOT SUPPORTED"; + case 0x40: + return "AUTHENTICATION FAILED"; + case 0x61: + return "EXTERNAL DATA ENCRYPTION KEY MANAGER ACCESS ERROR"; + case 0x62: + return "EXTERNAL DATA ENCRYPTION KEY MANAGER ERROR"; + case 0x63: + return "EXTERNAL DATA ENCRYPTION KEY NOT FOUND"; + case 0x64: + return "EXTERNAL DATA ENCRYPTION REQUEST NOT AUTHORIZED"; + case 0x6E: + return "EXTERNAL DATA ENCRYPTION CONTROL TIMEOUT"; + case 0x6F: + return "EXTERNAL DATA ENCRYPTION CONTROL ERROR"; + case 0x71: + return "LOGICAL UNIT ACCESS NOT AUTHORIZED"; + case 0x79: + return "SECURITY CONFLICT IN TRANSLATED DEVICE"; + } + + break; + } + + return ASC >= 0x80 + ? ASCQ >= 0x80 + ? string.Format(Localization.VENDOR_SPECIFIC_ASC_0_WITH_VENDOR_SPECIFIC_ASCQ_1, ASC, ASCQ) + : string.Format(Localization.VENDOR_SPECIFIC_ASC_0_WITH_ASCQ_1, ASC, ASCQ) + : ASCQ >= 0x80 + ? string.Format(Localization.ASC_0_WITH_VENDOR_SPECIFIC_ASCQ_1, ASC, ASCQ) + : string.Format(Localization.ASC_0_WITH_ASCQ_1, ASC, ASCQ); + } +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/Types.cs b/Aaru.Decoders/SCSI/Types.cs new file mode 100644 index 000000000..a9ce95c52 --- /dev/null +++ b/Aaru.Decoders/SCSI/Types.cs @@ -0,0 +1,618 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Types.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains various SCSI type values. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum MediumTypes : byte +{ + Default = 0x00, + +#region Medium Types defined in ECMA-111 for Direct-Access devices + + /// ECMA-54: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on One Side + ECMA54 = 0x09, + /// + /// ECMA-59 & ANSI X3.121-1984: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad + /// on Both Sides + /// + ECMA59 = 0x0A, + /// ECMA-69: 200 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides + ECMA69 = 0x0B, + /// ECMA-66: 130 mm Flexible Disk Cartridge using Two-Frequency Recording at 7958 ftprad on One Side + ECMA66 = 0x0E, + /// + /// ECMA-70 & ANSI X3.125-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both + /// Sides; 1,9 Tracks per mm + /// + ECMA70 = 0x12, + /// + /// ECMA-78 & ANSI X3.126-1986: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both + /// Sides; 3,8 Tracks per mm + /// + ECMA78 = 0x16, + /// + /// ECMA-99 & ISO 8630-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides; + /// 3,8 Tracks per mm + /// + ECMA99 = 0x1A, + /// + /// ECMA-100 & ANSI X3.137: 90 mm Flexible Disk Cartridge using MFM Recording at 7859 ftprad on Both Sides; + /// 5,3 Tracks per mm + /// + ECMA100 = 0x1E, + +#endregion Medium Types defined in ECMA-111 for Direct-Access devices + +#region Medium Types defined in SCSI-2 for Direct-Access devices + + /// Unspecified single sided flexible disk + Unspecified_SS = 0x01, + /// Unspecified double sided flexible disk + Unspecified_DS = 0x02, + /// ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 1 side + X3_73 = 0x05, + /// ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 2 sides + X3_73_DS = 0x06, + /// ANSI X3.80-1980: 130 mm, 3979 ftprad, 1,9 Tracks per mm, 1 side + X3_82 = 0x0D, + /// 6,3 mm tape with 12 tracks at 394 ftpmm + Tape12 = 0x40, + /// 6,3 mm tape with 24 tracks at 394 ftpmm + Tape24 = 0x44, + +#endregion Medium Types defined in SCSI-2 for Direct-Access devices + +#region Medium Types defined in SCSI-3 SBC-1 for Optical devices + + /// Read-only medium + ReadOnly = 0x01, + /// Write-once Read-many medium + WORM = 0x02, + /// Erasable medium + Erasable = 0x03, + /// Combination of read-only and write-once medium + RO_WORM = 0x04, + /// Combination of read-only and erasable medium + RO_RW = 0x05, + /// Combination of write-once and erasable medium + WORM_RW = 0x06, + +#endregion Medium Types defined in SCSI-3 SBC-1 for Optical devices + +#region Medium Types defined in SCSI-2 for MultiMedia devices + + /// 120 mm CD-ROM + CDROM = 0x01, + /// 120 mm Compact Disc Digital Audio + CDDA = 0x02, + /// 120 mm Compact Disc with data and audio + MixedCD = 0x03, + /// 80 mm CD-ROM + CDROM_80 = 0x05, + /// 80 mm Compact Disc Digital Audio + CDDA_80 = 0x06, + /// 80 mm Compact Disc with data and audio + MixedCD_80 = 0x07, + +#endregion Medium Types defined in SCSI-2 for MultiMedia devices + +#region Medium Types defined in SFF-8020i + + /// Unknown medium type + Unknown_CD = 0x00, + /// 120 mm Hybrid disc (Photo CD) + HybridCD = 0x04, + /// Unknown size CD-R + Unknown_CDR = 0x10, + /// 120 mm CD-R with data only + CDR = 0x11, + /// 120 mm CD-R with audio only + CDR_DA = 0x12, + /// 120 mm CD-R with data and audio + CDR_Mixed = 0x13, + /// 120 mm Hybrid CD-R (Photo CD) + HybridCDR = 0x14, + /// 80 mm CD-R with data only + CDR_80 = 0x15, + /// 80 mm CD-R with audio only + CDR_DA_80 = 0x16, + /// 80 mm CD-R with data and audio + CDR_Mixed_80 = 0x17, + /// 80 mm Hybrid CD-R (Photo CD) + HybridCDR_80 = 0x18, + /// Unknown size CD-RW + Unknown_CDRW = 0x20, + /// 120 mm CD-RW with data only + CDRW = 0x21, + /// 120 mm CD-RW with audio only + CDRW_DA = 0x22, + /// 120 mm CD-RW with data and audio + CDRW_Mixed = 0x23, + /// 120 mm Hybrid CD-RW (Photo CD) + HybridCDRW = 0x24, + /// 80 mm CD-RW with data only + CDRW_80 = 0x25, + /// 80 mm CD-RW with audio only + CDRW_DA_80 = 0x26, + /// 80 mm CD-RW with data and audio + CDRW_Mixed_80 = 0x27, + /// 80 mm Hybrid CD-RW (Photo CD) + HybridCDRW_80 = 0x28, + /// Unknown size HD disc + Unknown_HD = 0x30, + /// 120 mm HD disc + HD = 0x31, + /// 80 mm HD disc + HD_80 = 0x35, + /// No disc inserted, tray closed or caddy inserted + NoDisc = 0x70, + /// Tray open or no caddy inserted + TrayOpen = 0x71, + /// Tray closed or caddy inserted but medium error + MediumError = 0x72, + +#endregion Medium Types defined in SFF-8020i + +#region Medium Types defined in USB Mass Storage Class - UFI Command Specification + + /// 3.5-inch, 135 tpi, 12362 bits/radian, double-sided MFM (aka 1.25Mb) + Type3Floppy = 0x93, + /// 3.5-inch, 135 tpi, 15916 bits/radian, double-sided MFM (aka 1.44Mb) + HDFloppy = 0x94, + +#endregion Medium Types defined in USB Mass Storage Class - UFI Command Specification + +#region Medium Types defined in INF-8070 + + /// Unknown type block device + UnknownBlockDevice = 0x40, + /// Read-only block device + ReadOnlyBlockDevice = 0x41, + /// Read/Write block device + ReadWriteBlockDevice = 0x42, + +#endregion Medium Types defined in INF-8070 + +#region Medium Types found in vendor documents + + /// LTO WORM as reported by HP drives + LTOWORM = 0x01, + /// LTO cleaning cartridge as reported by Certance/Seagate drives + LTOCleaning = 0x01, + /// Direct-overwrite magneto-optical + DOW = 0x07, + /// LTO Ultrium + LTO = 0x18, + /// LTO Ultrium-2 + LTO2 = 0x28, + /// DC-2900SL + DC2900SL = 0x31, + /// MLR-1 + MLR1 = 0x33, + /// DDS-3 + DDS3 = 0x33, + /// DC-9200 + DC9200 = 0x34, + /// DDS-4 + DDS4 = 0x34, + /// DAT-72 + DAT72 = 0x35, + /// LTO Ultrium-3 + LTO3 = 0x38, + /// LTO Ultrium-3 WORM + LTO3WORM = 0x3C, + /// DDS cleaning cartridge + DDSCleaning = 0x3F, + /// DC-9250 + DC9250 = 0x40, + /// SLR-32 + SLR32 = 0x43, + /// MLR-1SL + MLR1SL = 0x44, + /// SLRtape-50 + SLRtape50 = 0x47, + /// LTO Ultrium-4 + LTO4 = 0x48, + /// LTO Ultrium-4 WORM + LTO4WORM = 0x4C, + /// SLRtape-50SL + SLRtape50SL = 0x50, + /// SLR-32SL + SLR32SL = 0x54, + /// SLR-5 + SLR5 = 0x55, + /// SLR-5SL + SLR5SL = 0x56, + /// LTO Ultrium-5 + LTO5 = 0x58, + /// LTO Ultrium-5 WORM + LTO5WORM = 0x5C, + /// SLRtape-7 + SLRtape7 = 0x63, + /// SLRtape-7SL + SLRtape7SL = 0x64, + /// SLRtape-24 + SLRtape24 = 0x65, + /// SLRtape-24SL + SLRtape24SL = 0x66, + /// LTO Ultrium-6 + LTO6 = 0x68, + /// LTO Ultrium-6 WORM + LTO6WORM = 0x6C, + /// SLRtape-140 + SLRtape140 = 0x70, + /// SLRtape-40 + SLRtape40 = 0x73, + /// SLRtape-60 + SLRtape60 = 0x74, + /// SLRtape-75 + SLRtape75 = 0x74, + /// SLRtape-100 + SLRtape100 = 0x75, + /// SLR-40 or SLR-60 or SLR-100 + SLR40_60_100 = 0x76, + /// LTO Ultrium-7 + LTO7 = 0x78, + /// LTO Ultrium-7 WORM + LTO7WORM = 0x7C, + /// HP LTO emulating a CD + LTOCD = 0x80, + /// Exatape 15m + Exatape15m = 0x81, + /// IBM MagStar + MagStar = 0x81, + /// VXA + VXA = 0x81, + /// CompactTape I + CT1 = 0x82, + /// Exatape 28m + Exatape28m = 0x82, + /// CompactTape II + CT2 = 0x82, + /// VXA-2 + VXA2 = 0x82, + /// VXA-3 + VXA3 = 0x82, + /// Exatape 54m + Exatape54m = 0x83, + /// DLTtape III + DLTtapeIII = 0x83, + /// Exatape 80m + Exatape80m = 0x84, + /// DLTtape IIIxt + DLTtapeIIIxt = 0x84, + /// Exatape 106m + Exatape106m = 0x85, + /// DLTtape IV + DLTtapeIV = 0x85, + /// Travan 5 + Travan5 = 0x85, + /// Exatape 106m XL + Exatape106mXL = 0x86, + /// SuperDLT I + SDLT1 = 0x86, + /// SuperDLT II + SDLT2 = 0x87, + /// VStape I + VStapeI = 0x90, + /// DLTtape S4 + DLTtapeS4 = 0x91, + /// Travan 7 + Travan7 = 0x95, + /// Exatape 22m + Exatape22m = 0xC1, + /// Exatape 40m + Exatape40m = 0xC2, + /// Exatape 76m + Exatape76m = 0xC3, + /// Exatape 112m + Exatape112m = 0xC4, + /// Exatape 22m AME + Exatape22mAME = 0xD1, + /// Exatape 170m + Exatape170m = 0xD2, + /// Exatape 125m + Exatape125m = 0xD3, + /// Exatape 45m + Exatape45m = 0xD4, + /// Exatape 225m + Exatape225m = 0xD5, + /// Exatape 150m + Exatape150m = 0xD6, + /// Exatape 75m + Exatape75m = 0xD7, + +#endregion Medium Types found in vendor documents + +#region Medium Types found testing a Hi-MD drive + + /// Hi-MD + HiMD = 0x44, + +#endregion Medium Types found testing a Hi-MD drive +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum DensityType : byte +{ + Default = 0x00, + +#region Density Types defined in ECMA-111 for Direct-Access devices + + /// 7958 flux transitions per radian + Flux7958 = 0x01, + /// 13262 flux transitions per radian + Flux13262 = 0x02, + /// 15916 flux transitions per radian + Flux15916 = 0x03, + +#endregion Density Types defined in ECMA-111 for Direct-Access devices + +#region Density Types defined in ECMA-111 for Sequential-Access devices + + /// ECMA-62 & ANSI X3.22-1983: 12,7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZI, 32 cpmm + ECMA62 = 0x01, + /// ECMA-62 & ANSI X3.39-1986: 12,7 mm 9-Track Magnetic Tape, 126 ftpmm, Phase Encoding, 63 cpmm + ECMA62_Phase = 0x02, + /// ECMA-62 & ANSI X3.54-1986: 12,7 mm 9-Track Magnetic Tape, 356 ftpmm, NRZI, 245 cpmm GCR + ECMA62_GCR = 0x03, + /// ECMA-79 & ANSI X3.116-1986: 6,30 mm Magnetic Tape Cartridge using MFM Recording at 252 ftpmm + ECMA79 = 0x07, + /// + /// Draft ECMA & ANSI X3B5/87-099: 12,7 mm Magnetic Tape Cartridge using IFM Recording on 18 Tracks at 1944 + /// ftpmm, GCR (IBM 3480, 3490, 3490E) + /// + IBM3480 = 0x09, + /// ECMA-46 & ANSI X3.56-1986: 6,30 mm Magnetic Tape Cartridge, Phase Encoding, 63 bpmm + ECMA46 = 0x0B, + /// ECMA-98: 6,30 mm Magnetic Tape Cartridge, NRZI Recording, 394 ftpmm + ECMA98 = 0x0E, + +#endregion Density Types defined in ECMA-111 for Sequential-Access devices + +#region Density Types defined in SCSI-2 for Sequential-Access devices + + /// ANXI X3.136-1986: 6,35 mm 4 or 9-Track Magnetic Tape Cartridge, 315 bpmm, GCR (QIC-24) + X3_136 = 0x05, + /// ANXI X3.157-1987: 12,7 mm 9-Track Magnetic Tape, 126 bpmm, Phase Encoding + X3_157 = 0x06, + /// ANXI X3.158-1987: 3,81 mm 4-Track Magnetic Tape Cassette, 315 bpmm, GCR + X3_158 = 0x08, + /// ANXI X3B5/86-199: 12,7 mm 22-Track Magnetic Tape Cartridge, 262 bpmm, MFM + X3B5_86 = 0x0A, + /// HI-TC1: 12,7 mm 24-Track Magnetic Tape Cartridge, 500 bpmm, GCR + HiTC1 = 0x0C, + /// HI-TC2: 12,7 mm 24-Track Magnetic Tape Cartridge, 999 bpmm, GCR + HiTC2 = 0x0D, + /// QIC-120: 6,3 mm 15-Track Magnetic Tape Cartridge, 394 bpmm, GCR + QIC120 = 0x0F, + /// QIC-150: 6,3 mm 18-Track Magnetic Tape Cartridge, 394 bpmm, GCR + QIC150 = 0x10, + /// QIC-320: 6,3 mm 26-Track Magnetic Tape Cartridge, 630 bpmm, GCR + QIC320 = 0x11, + /// QIC-1350: 6,3 mm 30-Track Magnetic Tape Cartridge, 2034 bpmm, RLL + QIC1350 = 0x12, + /// ANXI X3B5/88-185A: 3,81 mm Magnetic Tape Cassette, 2400 bpmm, DDS + X3B5_88 = 0x13, + /// ANXI X3.202-1991: 8 mm Magnetic Tape Cassette, 1703 bpmm, RLL + X3_202 = 0x14, + /// ECMA TC17: 8 mm Magnetic Tape Cassette, 1789 bpmm, RLL + ECMA_TC17 = 0x15, + /// ANXI X3.193-1990: 12,7 mm 48-Track Magnetic Tape Cartridge, 394 bpmm, MFM + X3_193 = 0x16, + /// ANXI X3B5/97-174: 12,7 mm 48-Track Magnetic Tape Cartridge, 1673 bpmm, MFM + X3B5_91 = 0x17, + +#endregion Density Types defined in SCSI-2 for Sequential-Access devices + +#region Density Types defined in SCSI-2 for MultiMedia devices + + /// User data only + User = 0x01, + /// User data plus auxiliary data field + UserAuxiliary = 0x02, + /// 4-byt tag field, user data plus auxiliary data + UserAuxiliaryTag = 0x03, + /// Audio information only + Audio = 0x04, + +#endregion Density Types defined in SCSI-2 for MultiMedia devices + +#region Density Types defined in SCSI-2 for Optical devices + + /// ISO/IEC 10090: 86 mm Read/Write single-sided optical disc with 12500 tracks + ISO10090 = 0x01, + /// 89 mm Read/Write double-sided optical disc with 12500 tracks + D581 = 0x02, + /// ANSI X3.212: 130 mm Read/Write double-sided optical disc with 18750 tracks + X3_212 = 0x03, + /// ANSI X3.191: 130 mm Write-Once double-sided optical disc with 30000 tracks + X3_191 = 0x04, + /// ANSI X3.214: 130 mm Write-Once double-sided optical disc with 20000 tracks + X3_214 = 0x05, + /// ANSI X3.211: 130 mm Write-Once double-sided optical disc with 18750 tracks + X3_211 = 0x06, + /// 200 mm optical disc + D407 = 0x07, + /// ISO/IEC 13614: 300 mm double-sided optical disc + ISO13614 = 0x08, + /// ANSI X3.200: 356 mm double-sided optical disc with 56350 tracks + X3_200 = 0x09, + +#endregion Density Types defined in SCSI-2 for Optical devices + +#region Density Types found in vendor documents + + /// QIC-11 + QIC11 = 0x04, + /// CompactTape I + CT1 = 0x0A, + /// Exabyte 8200 format + Ex8200 = 0x14, + /// Exabyte 8500 format + Ex8500 = 0x15, + /// CompactTape II + CT2 = 0x16, + /// DLTtape III 42500 bpi + DLT3_42k = 0x17, + /// DLTtape III 56 track + DLT3_56t = 0x18, + /// DLTtape III 62500 bpi + DLT3_62k = 0x19, + /// DLTtape IV + DLT4 = 0x1A, + /// DLTtape IV 85937 bpi + DLT4_85k = 0x1B, + /// DDS-2 + DDS2 = 0x24, + /// DDS-3 + DDS3 = 0x25, + /// DDS-4 + DDS4 = 0x26, + /// Exabyte Mammoth + Mammoth = 0x27, + /// IBM 3490 & 3490E + IBM3490E = 0x28, + /// Exabyte Mammoth-2 + Mammoth2 = 0x28, + /// IBM 3590 + IBM3590 = 0x29, + /// IBM 3590E + IBM3590E = 0x2A, + /// AIT-1 + AIT1 = 0x30, + /// AIT-2 + AIT2 = 0x31, + /// AIT-3 + AIT3 = 0x32, + /// DLTtape IV 123090 bpi + DLT4_123k = 0x40, + /// Ultrium-1 + LTO1 = 0x40, + /// Super AIT-1 + SAIT1 = 0x40, + /// DLTtape IV 85937 bpi + DLT4_98k = 0x41, + /// Ultrium-2 as reported by the Certance drive + LTO2Old = 0x41, + /// Ultrium-2 + LTO2 = 0x42, + /// T9840 + T9840 = 0x42, + /// T9940 + T9940 = 0x43, + /// Ultrium- + LTO3 = 0x44, + /// T9840C + T9840C = 0x45, + /// Travan 5 + Travan5 = 0x46, + /// Ultrium-4 + LTO4 = 0x46, + /// T9840D + T9840D = 0x46, + /// DAT-72 + DAT72 = 0x47, + /// Super DLTtape I 133000 bpi + SDLT1_133k = 0x48, + /// Super DLTtape I + SDLT1 = 0x49, + /// T10000A + T10000A = 0x4A, + /// Super DLTtape II + SDLT2 = 0x4A, + /// DLTtape S4 + DLTS4 = 0x4B, + /// T10000B + T10000B = 0x4B, + /// T10000C + T10000C = 0x4C, + /// T10000D + T10000D = 0x4D, + /// VStape I + VStape1 = 0x40, + /// Ultrium-5 + LTO5 = 0x58, + /// Ultrium-6 + LTO6 = 0x5A, + /// Ultrium-7 + LTO7 = 0x5C, + /// DLTtape III 62500 bpi secondary code + DLT3_62kAlt = 0x80, + /// VXA-1 + VXA1 = 0x80, + /// DLTtape III compressed + DLT3c = 0x81, + /// VXA-2 + VXA2 = 0x81, + /// DLTtape IV secondary code + DLT4Alt = 0x82, + /// VXA-3 + VXA3 = 0x82, + /// DLTtape IV compressed + DLT4c = 0x83, + /// DLTtape IV 85937 bpi secondary code + DLT4_85kAlt = 0x84, + /// DLTtape IV 85937 bpi compressed + DLT4c_85k = 0x85, + /// DLTtape IV 123090 bpi secondary code + DLT4_123kAlt = 0x86, + /// DLTtape IV 123090 bpi compressed + DLT4c_123k = 0x87, + /// DLTtape IV 98250 bpi secondary code + DLT4_98kAlt = 0x88, + /// DLTtape IV 98250 bpi compressed + DLT4c_98k = 0x89, + /// Exabyte compressed 8200 format + Ex8500c = 0x8C, + /// Exabyte compressed 8500 format + Ex8200c = 0x90, + /// Super DLTtape I secondary code + SDLT1Alt = 0x90, + /// Super DLTtape I compressed + SDLT1c = 0x91, + /// Super DLTtape I 133000 bpi secondary code + SDLT1_133kAlt = 0x92, + /// Super DLTtape I 133000 bpi compressed + SDLT1c_133k = 0x93, + /// VStape I secondary code + VStape1Alt = 0x98, + /// VStape I compressed + VStape1c = 0x99, + +#endregion Density Types found in vendor documents +} \ No newline at end of file diff --git a/Aaru.Decoders/SCSI/VendorString.cs b/Aaru.Decoders/SCSI/VendorString.cs new file mode 100644 index 000000000..675725cb6 --- /dev/null +++ b/Aaru.Decoders/SCSI/VendorString.cs @@ -0,0 +1,866 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : VendorString.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains SCSI vendor strings. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Decoders.SCSI; + +public static class VendorString +{ + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public static string Prettify(string scsiVendorString) => scsiVendorString switch + { + "0B4C" => "MOOSIK Ltd.", + "13FE" => "PHISON", + "2AI" => "2AI (Automatisme et Avenir Informatique)", + "3M" => "3M Company", + "3nhtech" => "3NH Technologies", + "3PARdata" => "3PARdata, Inc.", + "A-Max" => "A-Max Technology Co., Ltd", + "ABSOLUTE" => "Absolute Analysis", + "ACARD" => "ACARD Technology Corp.", + "Accusys" => "Accusys INC.", + "Acer" => "Acer, Inc.", + "ACL" => "Automated Cartridge Librarys, Inc.", + "Actifio" => "Actifio", + "Acuid" => "Acuid Corporation Ltd.", + "AcuLab" => "AcuLab, Inc. (Tulsa, OK)", + "ADAPTEC" => "Adaptec", + "ADIC" => "Advanced Digital Information Corporation", + "ADSI" => + "Adaptive Data Systems, Inc. (a Western Digital subsidiary)", + "ADTX" => "ADTX Co., Ltd.", + "ADVA" => "ADVA Optical Networking AG", + "AEM" => "AEM Performance Electronics", + "AERONICS" => "Aeronics, Inc.", + "AGFA" => "AGFA", + "Agilent" => "Agilent Technologies", + "AIC" => "Advanced Industrial Computer, Inc.", + "AIPTEK" => "AIPTEK International Inc.", + "Alcohol" => "Alcohol Soft", + "ALCOR" => "Alcor Micro, Corp.", + "AMCC" => "Applied Micro Circuits Corporation", + "AMCODYNE" => "Amcodyne", + "Amgeon" => "Amgeon LLC", + "AMI" => "American Megatrends, Inc.", + "AMPEX" => "Ampex Data Systems", + "Amphenol" => "Amphenol", + "Amtl" => "Tenlon Technology Co.,Ltd", + "ANAMATIC" => "Anamartic Limited (England)", + "Ancor" => "Ancor Communications, Inc.", + "ANCOT" => "ANCOT Corp.", + "ANDATACO" => "Andataco", + "andiamo" => "Andiamo Systems, Inc.", + "ANOBIT" => "Anobit", + "ANRITSU" => "Anritsu Corporation", + "ANTONIO" => + "Antonio Precise Products Manufactory Ltd.", + "AoT" => "Art of Technology AG", + "APPLE" => "Apple Computer, Inc.", + "ARCHIVE" => "Archive", + "ARDENCE" => "Ardence Inc", + "Areca" => "Areca Technology Corporation", + "Arena" => "MaxTronic International Co., Ltd.", + "Argent" => "Argent Data Systems, Inc.", + "ARIO" => "Ario Data Networks, Inc.", + "ARISTOS" => "Aristos Logic Corp.", + "ARK" => "ARK Research Corporation", + "ARL:UT@A" => + "Applied Research Laboratories : University of Texas at Austin", + "ARTECON" => "Artecon Inc.", + "Artistic" => "Artistic Licence (UK) Ltd", + "ARTON" => "Arton Int.", + "ASACA" => "ASACA Corp.", + "ASC" => "Advanced Storage Concepts, Inc.", + "ASPEN" => "Aspen Peripherals", + "AST" => "AST Research", + "ASTEK" => "Astek Corporation", + "ASTK" => "Alcatel STK A/S", + "AStor" => "AccelStor, Inc.", + "ASTUTE" => "Astute Networks, Inc.", + "AT&T" => "AT&T", + "ATA" => + "SCSI / ATA Translator Software (Organization Not Specified)", + "ATARI" => "Atari Corporation", + "ATech" => "ATech electronics", + "ATG CYG" => "ATG Cygnet Inc.", + "ATL" => "Quantum|ATL Products", + "ATTO" => "ATTO Technology Inc.", + "ATTRATEC" => "Attratech Ltd liab. Co", + "ATX" => "Alphatronix", + "AURASEN" => "Aurasen Limited", + "Avago" => "Avago Technologies", + "AVC" => "AVC Technology Ltd", + "AVIDVIDR" => "AVID Technologies, Inc.", + "AVR" => "Advanced Vision Research", + "AXSTOR" => "AXSTOR", + "Axxana" => "Axxana Ltd.", + "B*BRIDGE" => "Blockbridge Networks LLC", + "BALLARD" => "Ballard Synergy Corp.", + "Barco" => "Barco", + "BAROMTEC" => "Barom Technologies Co., Ltd.", + "Bassett" => "Bassett Electronic Systems Ltd", + "BC Hydro" => "BC Hydro", + "BDT" => "BDT AG", + "BECEEM" => "Beceem Communications, Inc", + "BENQ" => "BENQ Corporation.", + "BERGSWD" => "Berg Software Design", + "BEZIER" => "Bezier Systems, Inc.", + "BHTi" => "Breece Hill Technologies", + "biodata" => "Biodata Devices SL", + "BIOS" => "BIOS Corporation", + "BIR" => "Bio-Imaging Research, Inc.", + "BiT" => "BiT Microsystems", + "BITMICRO" => "BiT Microsystems, Inc.", + "Blendlgy" => "Blendology Limited", + "BLOOMBAS" => "Bloombase Technologies Limited", + "BlueArc" => "BlueArc Corporation", + "bluecog" => "bluecog", + "BME-HVT" => + "Broadband Infocommunicatons and Electromagnetic Theory Department", + "BNCHMARK" => "Benchmark Tape Systems Corporation", + "Bosch" => "Robert Bosch GmbH", + "Botman" => "Botmanfamily Electronics", + "BoxHill" => "Box Hill Systems Corporation", + "BRDGWRKS" => "Bridgeworks Ltd.", + "BREA" => "BREA Technologies, Inc.", + "BREECE" => "Breece Hill LLC", + "BreqLabs" => "BreqLabs Inc.", + "Broadcom" => "Broadcom Corporation", + "BROCADE" => + "Brocade Communications Systems, Incorporated", + "BUFFALO" => "BUFFALO INC.", + "BULL" => "Bull Peripherals Corp.", + "BUSLOGIC" => "BusLogic Inc.", + "BVIRTUAL" => "B-Virtual N.V.", + "CACHEIO" => "CacheIO LLC", + "CalComp" => "CalComp, A Lockheed Company", + "CALCULEX" => "CALCULEX, Inc.", + "CALIPER" => "Caliper (California Peripheral Corp.)", + "CAMBEX" => "Cambex Corporation", + "CAMEOSYS" => "Cameo Systems Inc.", + "CANDERA" => "Candera Inc.", + "CAPTION" => "CAPTION BANK", + "CAST" => "Advanced Storage Tech", + "CATALYST" => "Catalyst Enterprises", + "CCDISK" => "iSCSI Cake", + "CDC" => "Control Data or MPI", + "CDP" => "Columbia Data Products", + "Celsia" => "A M Bromley Limited", + "CenData" => "Central Data Corporation", + "Cereva" => "Cereva Networks Inc.", + "CERTANCE" => "Certance", + "Chantil" => "Chantil Technology", + "CHEROKEE" => "Cherokee Data Systems", + "CHINON" => "Chinon", + "CHRISTMA" => + "Christmann Informationstechnik + Medien GmbH & Co KG", + "CIE&YED" => "YE Data, C.Itoh Electric Corp.", + "CIPHER" => "Cipher Data Products", + "Ciprico" => "Ciprico, Inc.", + "CIRRUSL" => "Cirrus Logic Inc.", + "CISCO" => "Cisco Systems, Inc.", + "CLEARSKY" => "ClearSky Data, Inc.", + "CLOVERLF" => "Cloverleaf Communications, Inc", + "CLS" => "Celestica", + "CMD" => "CMD Technology Inc.", + "CMTechno" => "CMTech", + "CNGR SFW" => "Congruent Software, Inc.", + "CNSi" => "Chaparral Network Storage, Inc.", + "CNT" => "Computer Network Technology", + "COBY" => "Coby Electronics Corporation, USA", + "COGITO" => "Cogito", + "COMAY" => "Corerise Electronics", + "COMPAQ" => "Compaq Computer Corporation", + "COMPELNT" => "Compellent Technologies, Inc.", + "COMPORT" => "Comport Corp.", + "COMPSIG" => "Computer Signal Corporation", + "COMPTEX" => "Comptex Pty Limited", + "CONNER" => "Conner Peripherals", + "COPANSYS" => "COPAN SYSTEMS INC", + "CORAID" => "Coraid, Inc", + "CORE" => "Core International, Inc.", + "CORERISE" => "Corerise Electronics", + "COVOTE" => "Covote GmbH & Co KG", + "COWON" => "COWON SYSTEMS, Inc.", + "CPL" => "Cross Products Ltd", + "CPU TECH" => "CPU Technology, Inc.", + "CREO" => "Creo Products Inc.", + "CROSFLD" => "Crosfield Electronics", + "CROSSRDS" => "Crossroads Systems, Inc.", + "crosswlk" => "Crosswalk, Inc.", + "CSCOVRTS" => "Cisco - Veritas", + "CSM, INC" => "Computer SM, Inc.", + "Cunuqui" => "CUNUQUI SLU", + "CYBERNET" => "Cybernetics", + "Cygnal" => "Dekimo", + "CYPRESS" => "Cypress Semiconductor Corp.", + "D Bit" => "Digby's Bitpile, Inc. DBA D Bit", + "DALSEMI" => "Dallas Semiconductor", + "DANEELEC" => "Dane-Elec", + "DANGER" => "Danger Inc.", + "DAT-MG" => "DAT Manufacturers Group", + "Data Com" => + "Data Com Information Systems Pty. Ltd.", + "DATABOOK" => "Databook, Inc.", + "DATACOPY" => "Datacopy Corp.", + "DataCore" => "DataCore Software Corporation", + "DataG" => "DataGravity", + "DATAPT" => "Datapoint Corp.", + "DATARAM" => "Dataram Corporation", + "DATC" => "Datum Champion Technology Co., Ltd", + "DAVIS" => "Daviscomms (S) Pte Ltd", + "DCS" => "ShenZhen DCS Group Co.,Ltd", + "DDN" => "DataDirect Networks, Inc.", + "DDRDRIVE" => "DDRdrive LLC", + "DE" => "Dimension Engineering LLC", + "DEC" => "Digital Equipment Corporation", + "DEI" => "Digital Engineering, Inc.", + "DELL" => "Dell, Inc.", + "Dell(tm)" => "Dell, Inc", + "DELPHI" => + "Delphi Data Div. of Sparks Industries, Inc.", + "DENON" => "Denon/Nippon Columbia", + "DenOptix" => "DenOptix, Inc.", + "DEST" => "DEST Corp.", + "DFC" => "DavioFranke.com", + "DFT" => "Data Fault Tolerance System CO.,LTD.", + "DGC" => "Data General Corp.", + "DIGIDATA" => "Digi-Data Corporation", + "DigiIntl" => "Digi International", + "Digital" => "Digital Equipment Corporation", + "DILOG" => "Distributed Logic Corp.", + "DISC" => "Document Imaging Systems Corp.", + "DiscSoft" => "Disc Soft Ltd", + "DLNET" => "Driveline", + "DNS" => "Data and Network Security", + "DNUK" => "Digital Networks Uk Ltd", + "DotHill" => "Dot Hill Systems Corp.", + "DP" => "Dell, Inc.", + "DPT" => "Distributed Processing Technology", + "Drewtech" => "Drew Technologies, Inc.", + "DROBO" => "Data Robotics, Inc.", + "DSC" => "DigitalStream Corporation", + "DSI" => "Data Spectrum, Inc.", + "DSM" => + "Deterner Steuerungs- und Maschinenbau GmbH & Co.", + "DSNET" => "Cleversafe, Inc.", + "DT" => "Double-Take Software, INC.", + "DTC QUME" => "Data Technology Qume", + "DXIMAGIN" => "DX Imaging", + "E-Motion" => "E-Motion LLC", + "EARTHLAB" => "EarthLabs", + "EarthLCD" => "Earth Computer Technologies, Inc.", + "ECCS" => "ECCS, Inc.", + "ECMA" => + "European Computer Manufacturers Association", + "EDS" => "Embedded Data Systems", + "EIM" => "InfoCore", + "ELE Intl" => "ELE International", + "ELEGANT" => "Elegant Invention, LLC", + "Elektron" => "Elektron Music Machines MAV AB", + "elipsan" => "Elipsan UK Ltd.", + "Elms" => "Elms Systems Corporation", + "ELSE" => "ELSE Ltd.", + "ELSEC" => "Littlemore Scientific", + "EMASS" => "EMASS, Inc.", + "EMC" => "EMC Corp.", + "EMiT" => "EMiT Conception Eletronique", + "EMTEC" => "EMTEC Magnetics", + "EMULEX" => "Emulex", + "ENERGY-B" => "Energybeam Corporation", + "ENGENIO" => "Engenio Information Technologies, Inc.", + "ENMOTUS" => "Enmotus Inc", + "Entacore" => "Entacore", + "EPOS" => "EPOS Technologies Ltd.", + "EPSON" => "Epson", + "EQLOGIC" => "EqualLogic", + "Eris/RSI" => "RSI Systems, Inc.", + "ETERNE" => + "EterneData Technology Co.,Ltd.(China PRC.)", + "EuroLogc" => "Eurologic Systems Limited", + "evolve" => "Evolution Technologies, Inc", + "EXABYTE" => "Exabyte Corp.", + "EXATEL" => "Exatelecom Co., Ltd.", + "EXAVIO" => "Exavio, Inc.", + "Exsequi" => "Exsequi Ltd", + "Exxotest" => "Annecy Electronique", + "FAIRHAVN" => "Fairhaven Health, LLC", + "FALCON" => "FalconStor, Inc.", + "FDS" => "Formation Data Systems", + "FFEILTD" => "FujiFilm Electonic Imaging Ltd", + "Fibxn" => "Fiberxon, Inc.", + "FID" => "First International Digital, Inc.", + "FILENET" => "FileNet Corp.", + "FirmFact" => "Firmware Factory Ltd", + "FLYFISH" => "Flyfish Technologies", + "FOXCONN" => "Foxconn Technology Group", + "FRAMDRV" => "FRAMEDRIVE Corp.", + "FREECION" => "Nable Communications, Inc.", + "FRESHDTK" => "FreshDetect GmbH", + "FSC" => "Fujitsu Siemens Computers", + "FTPL" => "Frontline Technologies Pte Ltd", + "FUJI" => "Fuji Electric Co., Ltd. (Japan)", + "FUJIFILM" => "Fuji Photo Film, Co., Ltd.", + "FUJITSU" => "Fujitsu", + "FUNAI" => "Funai Electric Co., Ltd.", + "FUSIONIO" => "Fusion-io Inc.", + "FUTURED" => "Future Domain Corp.", + "G&D" => "Giesecke & Devrient GmbH", + "G.TRONIC" => + "Globaltronic - Electronica e Telecomunicacoes, S.A.", + "Gadzoox" => "Gadzoox Networks, Inc.", + "Gammaflx" => "Gammaflux L.P.", + "GDI" => "Generic Distribution International", + "GEMALTO" => "gemalto", + "Gen_Dyn" => "General Dynamics", + "Generic" => "Generic Technology Co., Ltd.", + "GENSIG" => "General Signal Networks", + "GEO" => "Green Energy Options Ltd", + "GIGATAPE" => "GIGATAPE GmbH", + "GIGATRND" => "GigaTrend Incorporated", + "Global" => "Global Memory Test Consortium", + "Gnutek" => "Gnutek Ltd.", + "Goidelic" => "Goidelic Precision, Inc.", + "GoldKey" => "GoldKey Security Corporation", + "GoldStar" => "LG Electronics Inc.", + "GOOGLE" => "Google, Inc.", + "GORDIUS" => "Gordius", + "GOULD" => "Gould", + "HAGIWARA" => "Hagiwara Sys-Com Co., Ltd.", + "HAPP3" => "Inventec Multimedia and Telecom co., ltd", + "HDS" => "Horizon Data Systems, Inc.", + "Helldyne" => "Helldyne, Inc", + "Heydays" => "Mazo Technology Co., Ltd.", + "HGST" => "HGST a Western Digital Company", + "HI-TECH" => "HI-TECH Software Pty. Ltd.", + "HITACHI" => + "Hitachi America Ltd or Nissei Sangyo America Ltd", + "HL-DT-ST" => "Hitachi-LG Data Storage, Inc.", + "HONEYWEL" => "Honeywell Inc.", + "Hoptroff" => "HexWax Ltd", + "HORIZONT" => "Horizontigo Software", + "HP" => "Hewlett Packard", + "HPE" => "Hewlett Packard Enterprise", + "HPI" => "HP Inc.", + "HPQ" => "Hewlett Packard", + "HUALU" => "CHINA HUALU GROUP CO., LTD", + "HUASY" => "Huawei Symantec Technologies Co., Ltd.", + "HYLINX" => "Hylinx Ltd.", + "HYUNWON" => "HYUNWON inc", + "i-cubed" => "i-cubed ltd.", + "IBM" => "International Business Machines", + "Icefield" => "Icefield Tools Corporation", + "Iceweb" => "Iceweb Storage Corp", + "ICL" => "ICL", + "ICP" => "ICP vortex Computersysteme GmbH", + "IDE" => "International Data Engineering, Inc.", + "IDG" => "Interface Design Group", + "IET" => "ISCSI ENTERPRISE TARGET", + "IFT" => "Infortrend Technology, Inc.", + "IGR" => "Intergraph Corp.", + "IMAGINE" => "Imagine Communications Corp.", + "IMAGO" => "IMAGO SOFTWARE SL", + "IMATION" => "Imation", + "IMPLTD" => "Integrated Micro Products Ltd.", + "IMPRIMIS" => "Imprimis Technology Inc.", + "INCIPNT" => "Incipient Technologies Inc.", + "INCITS" => + "InterNational Committee for Information Technology", + "INDCOMP" => "Industrial Computing Limited", + "Indigita" => "Indigita Corporation", + "INFOCORE" => "InfoCore", + "INITIO" => "Initio Corporation", + "INRANGE" => "INRANGE Technologies Corporation", + "Insight" => "L-3 Insight Technology Inc", + "INSITE" => "Insite Peripherals", + "integrix" => "Integrix, Inc.", + "INTEL" => "Intel Corporation", + "Intransa" => "Intransa, Inc.", + "IOC" => "I/O Concepts, Inc.", + "iofy" => "iofy Corporation", + "IOMEGA" => "Iomega", + "IOT" => "IO Turbine, Inc.", + "iPaper" => "intelliPaper, LLC", + "iqstor" => "iQstor Networks, Inc.", + "iQue" => "iQue", + "ISi" => "Information Storage inc.", + "Isilon" => "Isilon Systems, Inc.", + "ISO" => "International Standards Organization", + "iStor" => "iStor Networks, Inc.", + "ITC" => "International Tapetronics Corporation", + "iTwin" => "iTwin Pte Ltd", + "IVIVITY" => "iVivity, Inc.", + "IVMMLTD" => "InnoVISION Multimedia Ltd.", + "JABIL001" => "Jabil Circuit", + "JETWAY" => "Jetway Information Co., Ltd", + "JMR" => "JMR Electronics Inc.", + "JOFEMAR" => "Jofemar", + "JOLLYLOG" => "Jolly Logic", + "JPC Inc." => "JPC Inc.", + "JSCSI" => "jSCSI Project", + "Juniper" => "Juniper Networks", + "JVC" => "JVC Information Products Co.", + "KASHYA" => "Kashya, Inc.", + "KENNEDY" => "Kennedy Company", + "KENWOOD" => "KENWOOD Corporation", + "KEWL" => "Shanghai KEWL Imp&Exp Co., Ltd.", + "Key Tech" => "Key Technologies, Inc", + "KMNRIO" => "Kaminario Technologies Ltd.", + "KODAK" => "Eastman Kodak", + "KONAN" => "Konan", + "koncepts" => "koncepts International Ltd.", + "KONICA" => "Konica Japan", + "KOVE" => "KOVE", + "KSCOM" => "KSCOM Co. Ltd.,", + "KUDELSKI" => "Nagravision SA - Kudelski Group", + "Kyocera" => "Kyocera Corporation", + "Lapida" => "Gonmalo Electronics", + "LAPINE" => "Lapine Technology", + "LASERDRV" => "LaserDrive Limited", + "LASERGR" => "Lasergraphics, Inc.", + "LeapFrog" => "LeapFrog Enterprises, Inc.", + "LEFTHAND" => "LeftHand Networks", + "Leica" => "Leica Camera AG", + "Lexar" => "Lexar Media, Inc.", + "LEYIO" => "LEYIO", + "LG" => "LG Electronics Inc.", + "LGE" => "LG Electronics Inc.", + "LIBNOVA" => + "LIBNOVA, SL Digital Preservation Systems", + "LION" => "Lion Optics Corporation", + "LMS" => + "Laser Magnetic Storage International Company", + "LoupTech" => "Loup Technologies, Inc.", + "LSI" => "LSI Corp. (was LSI Logic Corp.)", + "LSILOGIC" => "LSI Logic Storage Systems, Inc.", + "LTO-CVE" => + "Linear Tape - Open, Compliance Verification Entity", + "LUXPRO" => "Luxpro Corporation", + "MacroSAN" => "MacroSAN Technologies Co., Ltd.", + "Malakite" => + "Malachite Technologies (New VID is: Sandial)", + "MarcBoon" => "marcboon.com", + "Marner" => "Marner Storage Technologies, Inc.", + "MARVELL" => "Marvell Semiconductor, Inc.", + "Matrix" => "Matrix Orbital Corp.", + "MATSHITA" => "Matsushita", + "MAXELL" => "Hitachi Maxell, Ltd.", + "MAXIM-IC" => "Maxim Integrated Products", + "MaxOptix" => "Maxoptix Corp.", + "MAXSTRAT" => "Maximum Strategy, Inc.", + "MAXTOR" => "Maxtor Corp.", + "MaXXan" => "MaXXan Systems, Inc.", + "MAYCOM" => "maycom Co., Ltd.", + "MBEAT" => "K-WON C&C Co.,Ltd", + "MCC" => "Measurement Computing Corporation", + "McDATA" => "McDATA Corporation", + "MCUBE" => "Mcube Technology Co., Ltd.", + "MDI" => "Micro Design International, Inc.", + "MEADE" => "Meade Instruments Corporation", + "mediamat" => "mediamatic", + "MegaElec" => "Mega Electronics Ltd", + "MEII" => "Mountain Engineering II, Inc.", + "MELA" => "Mitsubishi Electronics America", + "MELCO" => "Mitsubishi Electric (Japan)", + "mellanox" => "Mellanox Technologies Ltd.", + "MEMOREX" => "Memorex Telex Japan Ltd.", + "MEMREL" => "Memrel Corporation", + "MEMTECH" => "MemTech Technology", + "Mendocin" => "Mendocino Software", + "MendoCno" => "Mendocino Software", + "MERIDATA" => "Oy Meridata Finland Ltd", + "METHODEI" => "Methode Electronics India pvt ltd", + "METRUM" => "Metrum, Inc.", + "MHTL" => "Matsunichi Hi-Tech Limited", + "MICROBTX" => "Microbotics Inc.", + "Microchp" => "Microchip Technology, Inc.", + "MICROLIT" => "Microlite Corporation", + "MICRON" => "Micron Technology, Inc.", + "MICROP" => "Micropolis", + "MICROTEK" => "Microtek Storage Corp", + "Minitech" => "Minitech (UK) Limited", + "Minolta" => "Minolta Corporation", + "MINSCRIB" => "Miniscribe", + "MiraLink" => "MiraLink Corporation", + "Mirifica" => "Mirifica s.r.l.", + "MITSUMI" => "Mitsumi Electric Co., Ltd.", + "MKM" => "Mitsubishi Kagaku Media Co., LTD.", + "Mobii" => "Mobii Systems (Pty.) Ltd.", + "MOL" => "Petrosoft Sdn. Bhd.", + "MOSAID" => "Mosaid Technologies Inc.", + "MOTOROLA" => "Motorola", + "MP-400" => "Daiwa Manufacturing Limited", + "MPC" => "MPC Corporation", + "MPCCORP" => "MPC Computers", + "MPEYE" => "Touchstone Technology Co., Ltd", + "MPIO" => "DKT Co.,Ltd", + "MPM" => "Mitsubishi Paper Mills, Ltd.", + "MPMan" => "MPMan.com, Inc.", + "MSFT" => "Microsoft Corporation", + "MSI" => "Micro-Star International Corp.", + "MST" => "Morning Star Technologies, Inc.", + "MSystems" => "M-Systems Flash Disk Pioneers", + "MTI" => "MTI Technology Corporation", + "MTNGATE" => "MountainGate Data Systems", + "MXI" => "Memory Experts International", + "nac" => "nac Image Technology Inc.", + "NAGRA" => "Nagravision SA - Kudelski Group", + "NAI" => "North Atlantic Industries", + "NAKAMICH" => "Nakamichi Corporation", + "NatInst" => "National Instruments", + "NatSemi" => "National Semiconductor Corp.", + "NCITS" => + "InterNational Committee for Information Technology Standards (INCITS)", + "NCL" => "NCL America", + "NCR" => "NCR Corporation", + "NDBTECH" => "NDB Technologie Inc.", + "Neartek" => "Neartek, Inc.", + "NEC" => "NEC", + "NETAPP" => "NetApp, Inc. (was Network Appliance)", + "NetBSD" => "The NetBSD Foundation", + "Netcom" => "Netcom Storage", + "NETENGIN" => "NetEngine, Inc.", + "NEWISYS" => "Newisys Data Storage", + "Newtech" => "Newtech Co., Ltd.", + "NEXSAN" => "Nexsan Technologies, Ltd.", + "NFINIDAT" => "Infinidat Ltd.", + "NHR" => "NH Research, Inc.", + "Nike" => "Nike, Inc.", + "Nimble" => "Nimble Storage", + "NISCA" => "NISCA Inc.", + "NISHAN" => "Nishan Systems Inc.", + "Nitz" => "Nitz Associates, Inc.", + "NKK" => "NKK Corp.", + "NRC" => "Nakamichi Research Corporation", + "NSD" => "Nippon Systems Development Co.,Ltd.", + "NSM" => "NSM Jukebox GmbH", + "nStor" => "nStor Technologies, Inc.", + "NT" => "Northern Telecom", + "NUCONNEX" => "NuConnex", + "NUSPEED" => "NuSpeed, Inc.", + "NVIDIA" => "NVIDIA Corporation", + "NVMe" => "NVM Express Working Group", + "OAI" => "Optical Access International", + "OCE" => "Oce Graphics", + "ODS" => "ShenZhen DCS Group Co.,Ltd", + "OHDEN" => "Ohden Co., Ltd.", + "OKI" => "OKI Electric Industry Co.,Ltd (Japan)", + "Olidata" => "Olidata S.p.A.", + "OMI" => "Optical Media International", + "OMNIFI" => "Rockford Corporation - Omnifi Media", + "OMNIS" => "OMNIS Company (FRANCE)", + "Ophidian" => "Ophidian Designs", + "opslag" => "Tyrone Systems", + "Optelec" => "Optelec BV", + "Optiarc" => "Sony Optiarc Inc.", + "OPTIMEM" => "Cipher/Optimem", + "OPTOTECH" => "Optotech", + "ORACLE" => "Oracle Corporation", + "ORANGE" => "Orange Micro, Inc.", + "ORCA" => "Orca Technology", + "Origin" => "Origin Energy", + "OSI" => "Optical Storage International", + "OSNEXUS" => "OS NEXUS, Inc.", + "OTL" => "OTL Engineering", + "OVERLAND" => "Overland Storage Inc.", + "pacdigit" => "Pacific Digital Corp", + "Packard" => "Parkard Bell", + "Panasas" => "Panasas, Inc.", + "PARALAN" => "Paralan Corporation", + "PASCOsci" => "Pasco Scientific", + "PATHLGHT" => "Pathlight Technology, Inc.", + "PCS" => "Pro Charging Systems, LLC", + "PerStor" => "Perstor", + "PERTEC" => "Pertec Peripherals Corporation", + "PFTI" => "Performance Technology Inc.", + "PFU" => "PFU Limited", + "Phigment" => "Phigment Technologies", + "PHILIPS" => "Philips Electronics", + "PICO" => "Packard Instrument Company", + "PIK" => "TECHNILIENT & MCS", + "Pillar" => "Pillar Data Systems", + "PIONEER" => "Pioneer Electronic Corp.", + "Pirus" => "Pirus Networks", + "PIVOT3" => "Pivot3, Inc.", + "PLASMON" => "Plasmon Data", + "Pliant" => "Pliant Technology, Inc.", + "PMCSIERA" => "PMC-Sierra", + "PME" => "Precision Measurement Engineering", + "PNNMed" => "PNN Medical SA", + "POKEN" => "Poken SA", + "POLYTRON" => "PT. HARTONO ISTANA TEKNOLOGI", + "PRAIRIE" => "PrairieTek", + "PREPRESS" => "PrePRESS Solutions", + "PRESOFT" => "PreSoft Architects", + "PRESTON" => "Preston Scientific", + "PRIAM" => "Priam", + "PRIMAGFX" => "Primagraphics Ltd", + "PRIMOS" => "Primos", + "PROCOM" => "Procom Technology", + "PROLIFIC" => "Prolific Technology Inc.", + "PROMISE" => "PROMISE TECHNOLOGY, Inc", + "PROSTOR" => "ProStor Systems, Inc.", + "PROSUM" => "PROSUM", + "PROWARE" => "Proware Technology Corp.", + "PTI" => "Peripheral Technology Inc.", + "PTICO" => "Pacific Technology International", + "PURE" => "PURE Storage", + "Qi-Hardw" => "Qi Hardware", + "QIC" => + "Quarter-Inch Cartridge Drive Standards, Inc.", + "QLogic" => "QLogic Corporation", + "QNAP" => "QNAP Systems", + "Qsan" => "QSAN Technology, Inc.", + "QUALSTAR" => "Qualstar", + "QUANTEL" => "Quantel Ltd.", + "QUANTUM" => "Quantum Corp.", + "QUIX" => "Quix Computerware AG", + "R-BYTE" => "R-Byte, Inc.", + "RACALREC" => "Racal Recorders", + "RADITEC" => "Radikal Technologies Deutschland GmbH", + "RADSTONE" => "Radstone Technology", + "RAIDINC" => "RAID Inc.", + "RASSYS" => "Rasilient Systems Inc.", + "RASVIA" => "Rasvia Systems, Inc.", + "rave-mp" => "Go Video", + "RDKMSTG" => "MMS Dipl. Ing. Rolf-Dieter Klein", + "RDStor" => "Rorke China", + "Readboy" => "Readboy Ltd Co.", + "Realm" => "Realm Systems", + "realtek" => "Realtek Semiconductor Corp.", + "REDUXIO" => "Reduxio Systems Ltd.", + "rehanltd" => "Rehan Electronics Ltd", + "REKA" => "REKA HEALTH PTE LTD", + "RELDATA" => "RELDATA Inc", + "RENAGmbH" => "RENA GmbH", + "ReThinkM" => "RETHINK MEDICAL, INC", + "Revivio" => "Revivio, Inc.", + "RGBLaser" => "RGB Lasersysteme GmbH", + "RGI" => "Raster Graphics, Inc.", + "RHAPSODY" => "Rhapsody Networks, Inc.", + "RHS" => "Racal-Heim Systems GmbH", + "RICOH" => "Ricoh", + "RODIME" => "Rodime", + "Rorke" => "RD DATA Technology (ShenZhen) Limited", + "Royaltek" => "RoyalTek company Ltd.", + "RPS" => "RPS", + "RTI" => "Reference Technology", + "S-D" => "Sauer-Danfoss", + "S-flex" => "Storageflex Inc", + "S-SYSTEM" => "S-SYSTEM", + "S1" => "storONE", + "SAMSUNG" => "Samsung Electronics Co., Ltd.", + "SAN" => "Storage Area Networks, Ltd.", + "Sandial" => "Sandial Systems, Inc.", + "SanDisk" => "SanDisk Corporation", + "SANKYO" => "Sankyo Seiki", + "SANRAD" => "SANRAD Inc.", + "SANYO" => "SANYO Electric Co., Ltd.", + "SC.Net" => "StorageConnections.Net", + "SCALE" => "Scale Computing, Inc.", + "SCIENTEK" => "SCIENTEK CORP", + "SCInc." => "Storage Concepts, Inc.", + "SCREEN" => "Dainippon Screen Mfg. Co., Ltd.", + "SDI" => "Storage Dimensions, Inc.", + "SDS" => "Solid Data Systems", + "SEAC" => "SeaChange International, Inc.", + "SEAGATE" => "Seagate", + "SEAGRAND" => "SEAGRAND In Japan", + "Seanodes" => "Seanodes", + "Sec. Key" => "SecureKey Technologies Inc.", + "SEQUOIA" => "Sequoia Advanced Technologies, Inc.", + "SGI" => "Silicon Graphics International", + "Shannon" => "Shannon Systems Co., Ltd.", + "Shinko" => "Shinko Electric Co., Ltd.", + "SIEMENS" => "Siemens", + "SigmaTel" => "SigmaTel, Inc.", + "SII" => "Seiko Instruments Inc.", + "SIMPLE" => "SimpleTech, Inc.", + "SIVMSD" => "IMAGO SOFTWARE SL", + "SKhynix" => "SK hynix Inc.", + "SLCNSTOR" => "SiliconStor, Inc.", + "SLI" => "Sierra Logic, Inc.", + "SMCI" => "Super Micro Computer, Inc.", + "SmrtStor" => "Smart Storage Systems", + "SMS" => "Scientific Micro Systems/OMTI", + "SMSC" => "SMSC Storage, Inc.", + "SMX" => "Smartronix, Inc.", + "SNYSIDE" => "Sunnyside Computing Inc.", + "SoftLock" => "Softlock Digital Security Provider", + "SolidFir" => "SolidFire, Inc.", + "SONIC" => "Sonic Solutions", + "SoniqCas" => "SoniqCast", + "SONY" => "Sony Corporation Japan", + "SOUL" => "Soul Storage Technology (Wuxi) Co., Ltd", + "SPD" => "Storage Products Distribution, Inc.", + "SPECIAL" => "Special Computing Co.", + "SPECTRA" => + "Spectra Logic, a Division of Western Automation Labs, Inc.", + "SPERRY" => "Sperry", + "Spintso" => "Spintso International AB", + "STARBORD" => "Starboard Storage Systems, Inc.", + "STARWIND" => "StarWind Software, Inc.", + "STEC" => "STEC, Inc.", + "Sterling" => "Sterling Diagnostic Imaging, Inc.", + "STK" => "Storage Technology Corporation", + "STNWOOD" => "Stonewood Group", + "STONEFLY" => "StoneFly Networks, Inc.", + "STOR" => "StorageNetworks, Inc.", + "STORAPP" => "StorageApps, Inc.", + "STORCIUM" => "Intelligent Systems Services Inc.", + "STORCOMP" => "Storage Computer Corporation", + "STORM" => "Storm Technology, Inc.", + "StorMagc" => "StorMagic", + "Stratus" => "Stratus Technologies", + "StrmLgc" => "StreamLogic Corp.", + "SUMITOMO" => "Sumitomo Electric Industries, Ltd.", + "SUN" => "Sun Microsystems, Inc.", + "SUNCORP" => "SunCorporation", + "suntx" => "Suntx System Co., Ltd", + "SUSE" => "SUSE Linux", + "Swinxs" => "Swinxs BV", + "SYMANTEC" => "Symantec Corporation", + "SYMBIOS" => "Symbios Logic Inc.", + "SYMWAVE" => "Symwave, Inc.", + "SYNCSORT" => "Syncsort Incorporated", + "SYNERWAY" => "Synerway", + "SYNOLOGY" => "Synology, Inc.", + "SyQuest" => "SyQuest Technology, Inc.", + "SYSGEN" => "Sysgen", + "T-MITTON" => "Transmitton England", + "T-MOBILE" => "T-Mobile USA, Inc.", + "T11" => "INCITS Technical Committee T11", + "TALARIS" => "Talaris Systems, Inc.", + "TALLGRAS" => "Tallgrass Technologies", + "TANDBERG" => "Tandberg Data A/S", + "TANDEM" => "Tandem", + "TANDON" => "Tandon", + "TCL" => "TCL Shenzhen ASIC MIcro-electronics Ltd", + "TDK" => "TDK Corporation", + "TEAC" => "TEAC Japan", + "TECOLOTE" => "Tecolote Designs", + "TEGRA" => "Tegra Varityper", + "Teilch" => "Teilch", + "Tek" => "Tektronix", + "TELLERT" => "Tellert Elektronik GmbH", + "TENTIME" => "Laura Technologies, Inc.", + "TFDATACO" => "TimeForge", + "TGEGROUP" => "TGE Group Co.,LTD.", + "Thecus" => "Thecus Technology Corp.", + "TI-DSG" => "Texas Instruments", + "TiGi" => "TiGi Corporation", + "TILDESGN" => "Tildesign bv", + "Tite" => "Tite Technology Limited", + "TKS Inc." => "TimeKeeping Systems, Inc.", + "TLMKS" => "Telemakus LLC", + "TMS" => "Texas Memory Systems, Inc.", + "TMS100" => "TechnoVas", + "TOLISGRP" => "The TOLIS Group", + "TOSHIBA" => "Toshiba Japan", + "TOYOU" => "TOYOU FEIJI ELECTRONICS CO.,LTD.", + "Tracker" => "Tracker, LLC", + "TRIOFLEX" => "Trioflex Oy", + "TRIPACE" => "Tripace", + "TRLogger" => "TrueLogger Ltd.", + "TROIKA" => "Troika Networks, Inc.", + "TRULY" => "TRULY Electronics MFG. LTD.", + "TRUSTED" => "Trusted Data Corporation", + "TSSTcorp" => + "Toshiba Samsung Storage Technology Corporation", + "TZM" => "TZ Medical", + "UD-DVR" => "Bigstone Project.", + "UDIGITAL" => "United Digital Limited", + "UIT" => "United Infomation Technology", + "ULTRA" => "UltraStor Corporation", + "UNISTOR" => "Unistor Networks, Inc.", + "UNISYS" => "Unisys", + "USCORE" => "Underscore, Inc.", + "USDC" => "US Design Corp.", + "Top VASCO" => "Vasco Data Security", + "VDS" => "Victor Data Systems Co., Ltd.", + "VELDANA" => "VELDANA MEDICAL SA", + "VENTANA" => "Ventana Medical Systems", + "Verari" => "Verari Systems, Inc.", + "VERBATIM" => "Verbatim Corporation", + "Vercet" => "Vercet LLC", + "VERITAS" => "VERITAS Software Corporation", + "Vexata" => "Vexata Inc", + "VEXCEL" => "VEXCEL IMAGING GmbH", + "VICOMSL1" => "Vicom Systems, Inc.", + "VicomSys" => "Vicom Systems, Inc.", + "VIDEXINC" => "Videx, Inc.", + "VIOLIN" => "Violin Memory, Inc.", + "VIRIDENT" => "Virident Systems, Inc.", + "VITESSE" => "Vitesse Semiconductor Corporation", + "VIXEL" => "Vixel Corporation", + "VLS" => "Van Lent Systems BV", + "VMAX" => "VMAX Technologies Corp.", + "VMware" => "VMware Inc.", + "Vobis" => "Vobis Microcomputer AG", + "VOLTAIRE" => "Voltaire Ltd.", + "VRC" => "Vermont Research Corp.", + "VRugged" => "Vanguard Rugged Storage", + "VTGadget" => "Vermont Gadget Company", + "Waitec" => "Waitec NV", + "WangDAT" => "WangDAT", + "WANGTEK" => "Wangtek", + "Wasabi" => "Wasabi Systems", + "WAVECOM" => "Wavecom", + "WD" => "Western Digital Corporation", + "WDC" => "Western Digital Corporation", + "WDIGTL" => "Western Digital", + "WDTI" => "Western Digital Technologies, Inc.", + "WEARNES" => "Wearnes Technology Corporation", + "WeeraRes" => "Weera Research Pte Ltd", + "Wildflwr" => "Wildflower Technologies, Inc.", + "WSC0001" => "Wisecom, Inc.", + "X3" => + "InterNational Committee for Information Technology Standards (INCITS)", + "XEBEC" => "Xebec Corporation", + "XENSRC" => "XenSource, Inc.", + "Xerox" => "Xerox Corporation", + "XIOtech" => "XIOtech Corporation", + "XIRANET" => "Xiranet Communications GmbH", + "XIV" => "XIV", + "XtremIO" => "XtremIO", + "XYRATEX" => "Xyratex", + "YINHE" => "NUDT Computer Co.", + "YIXUN" => "Yixun Electronic Co.,Ltd.", + "YOTTA" => "YottaYotta, Inc.", + "Zarva" => "Zarva Digital Technology Co., Ltd.", + "ZETTA" => "Zetta Systems, Inc.", + "ZTE" => "ZTE Corporation", + "ZVAULT" => "Zetavault", + _ => scsiVendorString + }; +} \ No newline at end of file diff --git a/Aaru.Decoders/SecureDigital/CID.cs b/Aaru.Decoders/SecureDigital/CID.cs new file mode 100644 index 000000000..7869ea59d --- /dev/null +++ b/Aaru.Decoders/SecureDigital/CID.cs @@ -0,0 +1,132 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CID.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SecureDigital CID. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.SecureDigital; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class CID +{ + public string ApplicationID; + public byte CRC; + public byte Manufacturer; + public ushort ManufacturingDate; + public string ProductName; + public byte ProductRevision; + public uint ProductSerialNumber; +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static partial class Decoders +{ + public static CID DecodeCID(uint[] response) + { + if(response?.Length != 4) return null; + + var data = new byte[16]; + + byte[] tmp = BitConverter.GetBytes(response[0]); + Array.Copy(tmp, 0, data, 0, 4); + tmp = BitConverter.GetBytes(response[1]); + Array.Copy(tmp, 0, data, 4, 4); + tmp = BitConverter.GetBytes(response[2]); + Array.Copy(tmp, 0, data, 8, 4); + tmp = BitConverter.GetBytes(response[3]); + Array.Copy(tmp, 0, data, 12, 4); + + return DecodeCID(data); + } + + public static CID DecodeCID(byte[] response) + { + if(response?.Length != 16) return null; + + var cid = new CID + { + Manufacturer = response[0], + ProductRevision = response[8], + ProductSerialNumber = Swapping.Swap(BitConverter.ToUInt32(response, 9)), + ManufacturingDate = (ushort)(((response[13] & 0x0F) << 8) + response[14]), + CRC = (byte)((response[15] & 0xFE) >> 1) + }; + + var tmp = new byte[2]; + Array.Copy(response, 1, tmp, 0, 2); + cid.ApplicationID = StringHandlers.CToString(tmp); + tmp = new byte[5]; + Array.Copy(response, 3, tmp, 0, 5); + cid.ProductName = StringHandlers.CToString(tmp); + + return cid; + } + + public static string PrettifyCID(CID cid) + { + if(cid == null) return null; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SecureDigital_Device_Identification_Register); + sb.AppendFormat(Localization.Manufacturer_0, VendorString.Prettify(cid.Manufacturer)).AppendLine(); + sb.AppendFormat(Localization.Application_ID_0, cid.ApplicationID).AppendLine(); + sb.AppendFormat(Localization.Product_name_0, cid.ProductName).AppendLine(); + + sb.AppendFormat(Localization.Product_revision_0_1, + (cid.ProductRevision & 0xF0) >> 4, + cid.ProductRevision & 0x0F) + .AppendLine(); + + sb.AppendFormat(Localization.Product_serial_number_0, cid.ProductSerialNumber).AppendLine(); + + sb.AppendFormat(Localization.Device_manufactured_month_0_of_1, + (cid.ManufacturingDate & 0xF00) >> 8, + (cid.ManufacturingDate & 0xFF) + 2000) + .AppendLine(); + + sb.AppendFormat(Localization.CID_CRC_0, cid.CRC).AppendLine(); + + return sb.ToString(); + } + + public static string PrettifyCID(uint[] response) => PrettifyCID(DecodeCID(response)); + + public static string PrettifyCID(byte[] response) => PrettifyCID(DecodeCID(response)); +} \ No newline at end of file diff --git a/Aaru.Decoders/SecureDigital/CSD.cs b/Aaru.Decoders/SecureDigital/CSD.cs new file mode 100644 index 000000000..3ac666bfc --- /dev/null +++ b/Aaru.Decoders/SecureDigital/CSD.cs @@ -0,0 +1,586 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CSD.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SecureDigital CSD. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SecureDigital; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class CSD +{ + public ushort Classes; + public bool Copy; + public byte CRC; + public bool DSRImplemented; + public bool EraseBlockEnable; + public byte EraseSectorSize; + public byte FileFormat; + public bool FileFormatGroup; + public byte NSAC; + public bool PermanentWriteProtect; + public byte ReadBlockLength; + public byte ReadCurrentAtVddMax; + public byte ReadCurrentAtVddMin; + public bool ReadMisalignment; + public bool ReadsPartialBlocks; + public uint Size; + public byte SizeMultiplier; + public byte Speed; + public byte Structure; + public byte TAAC; + public bool TemporaryWriteProtect; + public byte WriteBlockLength; + public byte WriteCurrentAtVddMax; + public byte WriteCurrentAtVddMin; + public bool WriteMisalignment; + public bool WriteProtectGroupEnable; + public byte WriteProtectGroupSize; + public bool WritesPartialBlocks; + public byte WriteSpeedFactor; +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static partial class Decoders +{ + public static CSD DecodeCSD(uint[] response) + { + if(response?.Length != 4) return null; + + var data = new byte[16]; + + byte[] tmp = BitConverter.GetBytes(response[0]); + Array.Copy(tmp, 0, data, 0, 4); + tmp = BitConverter.GetBytes(response[1]); + Array.Copy(tmp, 0, data, 4, 4); + tmp = BitConverter.GetBytes(response[2]); + Array.Copy(tmp, 0, data, 8, 4); + tmp = BitConverter.GetBytes(response[3]); + Array.Copy(tmp, 0, data, 12, 4); + + return DecodeCSD(data); + } + + public static CSD DecodeCSD(byte[] response) + { + if(response?.Length != 16) return null; + + var csd = new CSD + { + Structure = (byte)((response[0] & 0xC0) >> 6), + TAAC = response[1], + NSAC = response[2], + Speed = response[3], + Classes = (ushort)((response[4] << 4) + ((response[5] & 0xF0) >> 4)), + ReadBlockLength = (byte)(response[5] & 0x0F), + ReadsPartialBlocks = (response[6] & 0x80) == 0x80, + WriteMisalignment = (response[6] & 0x40) == 0x40, + ReadMisalignment = (response[6] & 0x20) == 0x20, + DSRImplemented = (response[6] & 0x10) == 0x10, + EraseBlockEnable = (response[10] & 0x40) == 0x40, + EraseSectorSize = (byte)(((response[10] & 0x3F) << 1) + ((response[11] & 0x80) >> 7)), + WriteProtectGroupSize = (byte)(response[11] & 0x7F), + WriteProtectGroupEnable = (response[12] & 0x80) == 0x80, + WriteSpeedFactor = (byte)((response[12] & 0x1C) >> 2), + WriteBlockLength = (byte)(((response[12] & 0x03) << 2) + ((response[13] & 0xC0) >> 6)), + WritesPartialBlocks = (response[13] & 0x20) == 0x20, + FileFormatGroup = (response[14] & 0x80) == 0x80, + Copy = (response[14] & 0x40) == 0x40, + PermanentWriteProtect = (response[14] & 0x20) == 0x20, + TemporaryWriteProtect = (response[14] & 0x10) == 0x10, + FileFormat = (byte)((response[14] & 0x0C) >> 2), + CRC = (byte)((response[15] & 0xFE) >> 1) + }; + + if(csd.Structure == 0) + { + csd.Size = (ushort)(((response[6] & 0x03) << 10) + (response[7] << 2) + ((response[8] & 0xC0) >> 6)); + + csd.ReadCurrentAtVddMin = (byte)((response[8] & 0x38) >> 3); + csd.ReadCurrentAtVddMax = (byte)(response[8] & 0x07); + csd.WriteCurrentAtVddMin = (byte)((response[9] & 0xE0) >> 5); + csd.WriteCurrentAtVddMax = (byte)((response[9] & 0x1C) >> 2); + csd.SizeMultiplier = (byte)(((response[9] & 0x03) << 1) + ((response[10] & 0x80) >> 7)); + } + else + csd.Size = (uint)(((response[7] & 0x3F) << 16) + (response[8] << 8) + response[9]); + + return csd; + } + + public static string PrettifyCSD(CSD csd) + { + if(csd == null) return null; + + double unitFactor = 0; + double multiplier = 0; + var unit = ""; + + var sb = new StringBuilder(); + sb.AppendLine(Localization.SecureDigital_Device_Specific_Data_Register); + + switch(csd.Structure) + { + case 0: + sb.AppendLine("\t" + Localization.Register_version_1_0); + + break; + case 1: + sb.AppendLine("\t" + Localization.Register_version_2_0); + + break; + } + + switch(csd.TAAC & 0x07) + { + case 0: + unit = Localization.unit_ns; + unitFactor = 1; + + break; + case 1: + unit = Localization.unit_ns; + unitFactor = 10; + + break; + case 2: + unit = Localization.unit_ns; + unitFactor = 100; + + break; + case 3: + unit = Localization.unit_μs; + unitFactor = 1; + + break; + case 4: + unit = Localization.unit_μs; + unitFactor = 10; + + break; + case 5: + unit = Localization.unit_μs; + unitFactor = 100; + + break; + case 6: + unit = Localization.unit_ms; + unitFactor = 1; + + break; + case 7: + unit = Localization.unit_ms; + unitFactor = 10; + + break; + } + + multiplier = ((csd.TAAC & 0x78) >> 3) switch + { + 0 => 0, + 1 => 1, + 2 => 1.2, + 3 => 1.3, + 4 => 1.5, + 5 => 2, + 6 => 2.5, + 7 => 3, + 8 => 3.5, + 9 => 4, + 10 => 4.5, + 11 => 5, + 12 => 5.5, + 13 => 6, + 14 => 7, + 15 => 8, + _ => multiplier + }; + + double result = unitFactor * multiplier; + sb.AppendFormat("\t" + Localization.Asynchronous_data_access_time_is_0_1, result, unit).AppendLine(); + + sb.AppendFormat("\t" + Localization.Clock_dependent_part_of_data_access_is_0_clock_cycles, csd.NSAC * 100) + .AppendLine(); + + unit = Localization.MBit_s; + + switch(csd.Speed & 0x07) + { + case 0: + unitFactor = 0.1; + + break; + case 1: + unitFactor = 1; + + break; + case 2: + unitFactor = 10; + + break; + case 3: + unitFactor = 100; + + break; + default: + unit = Localization.unit_unknown; + unitFactor = 0; + + break; + } + + multiplier = ((csd.Speed & 0x78) >> 3) switch + { + 0 => 0, + 1 => 1, + 2 => 1.2, + 3 => 1.3, + 4 => 1.5, + 5 => 2, + 6 => 2.6, + 7 => 3, + 8 => 3.5, + 9 => 4, + 10 => 4.5, + 11 => 5.2, + 12 => 5.5, + 13 => 6, + 14 => 7, + 15 => 8, + _ => multiplier + }; + + result = unitFactor * multiplier; + sb.AppendFormat("\t" + Localization.Device_transfer_speed_0_1, result, unit).AppendLine(); + + unit = ""; + + for(int cl = 0, mask = 1; cl <= 11; cl++, mask <<= 1) + if((csd.Classes & mask) == mask) + unit += $" {cl}"; + + sb.AppendFormat("\t" + Localization.Device_support_command_classes_0, unit).AppendLine(); + + sb.AppendFormat("\t" + Localization.Read_block_length_is_0_bytes, Math.Pow(2, csd.ReadBlockLength)) + .AppendLine(); + + if(csd.ReadsPartialBlocks) sb.AppendLine("\t" + Localization.Device_allows_reading_partial_blocks); + + if(csd.WriteMisalignment) sb.AppendLine("\t" + Localization.Write_commands_can_cross_physical_block_boundaries); + + if(csd.ReadMisalignment) sb.AppendLine("\t" + Localization.Read_commands_can_cross_physical_block_boundaries); + + if(csd.DSRImplemented) sb.AppendLine("\t" + Localization.Device_implements_configurable_driver_stage); + + if(csd.Structure == 0) + { + result = (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2); + sb.AppendFormat("\t" + Localization.Device_has_0_blocks, (int)result).AppendLine(); + + result = (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2) * Math.Pow(2, csd.ReadBlockLength); + + switch(result) + { + case > 1073741824: + sb.AppendFormat("\t" + Localization.Device_has_0_GiB, result / 1073741824.0).AppendLine(); + + break; + case > 1048576: + sb.AppendFormat("\t" + Localization.Device_has_0_MiB, result / 1048576.0).AppendLine(); + + break; + case > 1024: + sb.AppendFormat("\t" + Localization.Device_has_0_KiB, result / 1024.0).AppendLine(); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_has_0_bytes, result).AppendLine(); + + break; + } + } + else + { + sb.AppendFormat("\t" + Localization.Device_has_0_blocks, (csd.Size + 1) * 1024).AppendLine(); + result = ((ulong)csd.Size + 1) * 1024 * 512; + + switch(result) + { + case > 1099511627776: + sb.AppendFormat("\t" + Localization.Device_has_0_TiB, result / 1099511627776.0).AppendLine(); + + break; + case > 1073741824: + sb.AppendFormat("\t" + Localization.Device_has_0_GiB, result / 1073741824.0).AppendLine(); + + break; + case > 1048576: + sb.AppendFormat("\t" + Localization.Device_has_0_MiB, result / 1048576.0).AppendLine(); + + break; + case > 1024: + sb.AppendFormat("\t" + Localization.Device_has_0_KiB, result / 1024.0).AppendLine(); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_has_0_bytes, result).AppendLine(); + + break; + } + } + + if(csd.Structure == 0) + { + switch(csd.ReadCurrentAtVddMin & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_0_5mA_for_reading_at_minimum_voltage); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_1mA_for_reading_at_minimum_voltage); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_5mA_for_reading_at_minimum_voltage); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_10mA_for_reading_at_minimum_voltage); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_25mA_for_reading_at_minimum_voltage); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_35mA_for_reading_at_minimum_voltage); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_60mA_for_reading_at_minimum_voltage); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_100mA_for_reading_at_minimum_voltage); + + break; + } + + switch(csd.ReadCurrentAtVddMax & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_1mA_for_reading_at_maximum_voltage); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_5mA_for_reading_at_maximum_voltage); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_10mA_for_reading_at_maximum_voltage); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_25mA_for_reading_at_maximum_voltage); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_35mA_for_reading_at_maximum_voltage); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_45mA_for_reading_at_maximum_voltage); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_80mA_for_reading_at_maximum_voltage); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_200mA_for_reading_at_maximum_voltage); + + break; + } + + switch(csd.WriteCurrentAtVddMin & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_0_5mA_for_writing_at_minimum_voltage); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_1mA_for_writing_at_minimum_voltage); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_5mA_for_writing_at_minimum_voltage); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_10mA_for_writing_at_minimum_voltage); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_25mA_for_writing_at_minimum_voltage); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_35mA_for_writing_at_minimum_voltage); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_60mA_for_writing_at_minimum_voltage); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_100mA_for_writing_at_minimum_voltage); + + break; + } + + switch(csd.WriteCurrentAtVddMax & 0x07) + { + case 0: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_1mA_for_writing_at_maximum_voltage); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_5mA_for_writing_at_maximum_voltage); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_10mA_for_writing_at_maximum_voltage); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_25mA_for_writing_at_maximum_voltage); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_35mA_for_writing_at_maximum_voltage); + + break; + case 5: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_45mA_for_writing_at_maximum_voltage); + + break; + case 6: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_80mA_for_writing_at_maximum_voltage); + + break; + case 7: + sb.AppendLine("\t" + Localization.Device_uses_a_maximum_of_200mA_for_writing_at_maximum_voltage); + + break; + } + + if(csd.EraseBlockEnable) sb.AppendLine("\t" + Localization.Device_can_erase_multiple_blocks); + + // TODO: Check specification + sb.AppendFormat("\t" + Localization.Device_must_erase_a_minimum_of_0_blocks_at_a_time, + Convert.ToUInt32(csd.EraseSectorSize) + 1) + .AppendLine(); + + if(csd.WriteProtectGroupEnable) + { + sb.AppendLine("\t" + Localization.Device_can_write_protect_regions); + + // TODO: Check specification + // unitFactor = Convert.ToDouble(csd.WriteProtectGroupSize); + + sb.AppendFormat("\t" + Localization.Device_can_write_protect_a_minimum_of_0_blocks_at_a_time, + (int)(result + 1)) + .AppendLine(); + } + else + sb.AppendLine("\t" + Localization.Device_cant_write_protect_regions); + } + + sb.AppendFormat("\t" + Localization.Writing_is_0_times_slower_than_reading, Math.Pow(2, csd.WriteSpeedFactor)) + .AppendLine(); + + sb.AppendFormat("\t" + Localization.Write_block_length_is_0_bytes, Math.Pow(2, csd.WriteBlockLength)) + .AppendLine(); + + if(csd.WritesPartialBlocks) sb.AppendLine("\t" + Localization.Device_allows_writing_partial_blocks); + + if(!csd.Copy) sb.AppendLine("\t" + Localization.Device_contents_are_original); + + if(csd.PermanentWriteProtect) sb.AppendLine("\t" + Localization.Device_is_permanently_write_protected); + + if(csd.TemporaryWriteProtect) sb.AppendLine("\t" + Localization.Device_is_temporarily_write_protected); + + if(!csd.FileFormatGroup) + { + switch(csd.FileFormat) + { + case 0: + sb.AppendLine("\t" + Localization.Device_is_formatted_like_a_hard_disk); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_is_formatted_like_a_floppy_disk_using_Microsoft_FAT); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_Universal_File_Format); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_uses_unknown_file_format_code_0, csd.FileFormat) + .AppendLine(); + + break; + } + } + else + { + sb.AppendFormat("\t" + Localization.Device_uses_unknown_file_format_code_0_and_file_format_group_1, + csd.FileFormat) + .AppendLine(); + } + + sb.AppendFormat("\t" + Localization.CSD_CRC_0, csd.CRC).AppendLine(); + + return sb.ToString(); + } + + public static string PrettifyCSD(uint[] response) => PrettifyCSD(DecodeCSD(response)); + + public static string PrettifyCSD(byte[] response) => PrettifyCSD(DecodeCSD(response)); +} \ No newline at end of file diff --git a/Aaru.Decoders/SecureDigital/OCR.cs b/Aaru.Decoders/SecureDigital/OCR.cs new file mode 100644 index 000000000..570021b33 --- /dev/null +++ b/Aaru.Decoders/SecureDigital/OCR.cs @@ -0,0 +1,133 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : OCR.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SecureDigital OCR. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.SecureDigital; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnassignedField.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class OCR +{ + public bool CCS; + public bool LowPower; + public bool OneEight; + public bool PowerUp; + public bool ThreeFive; + public bool ThreeFour; + public bool ThreeOne; + public bool ThreeThree; + public bool ThreeTwo; + public bool ThreeZero; + public bool TwoEight; + public bool TwoNine; + public bool TwoSeven; + public bool UHS; +} + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static partial class Decoders +{ + public static OCR DecodeOCR(uint response) + { + response = Swapping.Swap(response); + + return new OCR + { + PowerUp = (response & 0x80000000) == 0x80000000, + CCS = (response & 0x40000000) == 0x40000000, + UHS = (response & 0x20000000) == 0x20000000, + OneEight = (response & 0x01000000) == 0x01000000, + ThreeFive = (response & 0x00800000) == 0x00800000, + ThreeFour = (response & 0x00400000) == 0x00400000, + ThreeThree = (response & 0x00200000) == 0x00200000, + ThreeTwo = (response & 0x00100000) == 0x00100000, + ThreeOne = (response & 0x00080000) == 0x00080000, + ThreeZero = (response & 0x00040000) == 0x00040000, + TwoNine = (response & 0x00020000) == 0x00020000, + TwoEight = (response & 0x00010000) == 0x00010000, + TwoSeven = (response & 0x00008000) == 0x00008000, + LowPower = (response & 0x00000080) == 0x00000080 + }; + } + + public static OCR DecodeOCR(byte[] response) => + response?.Length != 4 ? null : DecodeOCR(BitConverter.ToUInt32(response, 0)); + + public static string PrettifyOCR(OCR ocr) + { + if(ocr == null) return null; + + var sb = new StringBuilder(); + sb.AppendLine(Localization.SecureDigital_Operation_Conditions_Register); + + if(!ocr.PowerUp) sb.AppendLine("\t" + Localization.Device_is_powering_up); + + if(ocr.CCS) sb.AppendLine("\t" + Localization.Device_is_SDHC_SDXC_or_higher); + + if(ocr.UHS) sb.AppendLine("\t" + Localization.Device_is_UHS_II_or_higher); + + if(ocr.ThreeFive) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_3_5_3_6V); + + if(ocr.ThreeFour) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_3_4_3_5V); + + if(ocr.ThreeThree) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_3_3_3_4V); + + if(ocr.ThreeTwo) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_3_2_3_3V); + + if(ocr.ThreeOne) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_3_1_3_2V); + + if(ocr.TwoNine) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_9_3_0V); + + if(ocr.TwoEight) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_8_2_9V); + + if(ocr.TwoSeven) sb.AppendLine("\t" + Localization.Device_can_work_with_supply_2_7_2_8V); + + if(ocr.OneEight) sb.AppendLine("\t" + Localization.Device_can_switch_to_work_with_1_8V_supply); + + if(ocr.LowPower) sb.AppendLine("\t" + Localization.Device_is_in_low_power_mode); + + return sb.ToString(); + } + + public static string PrettifyOCR(byte[] response) => PrettifyOCR(DecodeOCR(response)); + + public static string PrettifyOCR(uint response) => PrettifyOCR(DecodeOCR(response)); +} \ No newline at end of file diff --git a/Aaru.Decoders/SecureDigital/SCR.cs b/Aaru.Decoders/SecureDigital/SCR.cs new file mode 100644 index 000000000..ccced6747 --- /dev/null +++ b/Aaru.Decoders/SecureDigital/SCR.cs @@ -0,0 +1,250 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SCR.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SecureDigital SCR. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; + +namespace Aaru.Decoders.SecureDigital; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class SCR +{ + public BusWidth BusWidth; + public CommandSupport CommandSupport; + public bool DataStatusAfterErase; + public byte ExtendedSecurity; + public byte[] ManufacturerReserved; + public byte Security; + public byte Spec; + public bool Spec3; + public bool Spec4; + public byte SpecX; + public byte Structure; +} + +[Flags] +public enum BusWidth : byte +{ + OneBit = 1 << 0, + FourBit = 1 << 2 +} + +[Flags] +public enum CommandSupport : byte +{ + SpeedClassControl = 1 << 0, + SetBlockCount = 1 << 1, + ExtensionRegisterSingleBlock = 1 << 2, + ExtensionRegisterMultiBlock = 1 << 3 +} + +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public static partial class Decoders +{ + public static SCR DecodeSCR(uint[] response) + { + if(response?.Length != 2) return null; + + var data = new byte[8]; + + byte[] tmp = BitConverter.GetBytes(response[0]); + Array.Copy(tmp, 0, data, 0, 4); + tmp = BitConverter.GetBytes(response[1]); + Array.Copy(tmp, 0, data, 4, 4); + + return DecodeSCR(data); + } + + public static SCR DecodeSCR(byte[] response) + { + if(response?.Length != 8) return null; + + var scr = new SCR + { + Structure = (byte)((response[0] & 0xF0) >> 4), + Spec = (byte)(response[0] & 0x0F), + DataStatusAfterErase = (response[1] & 0x80) == 0x80, + Security = (byte)((response[1] & 0x70) >> 4), + BusWidth = (BusWidth)(response[1] & 0x0F), + Spec3 = (response[2] & 0x80) == 0x80, + ExtendedSecurity = (byte)((response[2] & 0x78) >> 3), + Spec4 = (response[2] & 0x04) == 0x04, + SpecX = (byte)(((response[2] & 0x03) << 2) + ((response[3] & 0xC0) >> 6)), + CommandSupport = (CommandSupport)(response[3] & 0x0F), + ManufacturerReserved = new byte[4] + }; + + Array.Copy(response, 4, scr.ManufacturerReserved, 0, 4); + + return scr; + } + + public static string PrettifySCR(SCR scr) + { + if(scr == null) return null; + + var sb = new StringBuilder(); + sb.AppendLine(Localization.SecureDigital_Device_Configuration_Register); + + if(scr.Structure != 0) + sb.AppendFormat("\t" + Localization.Unknown_register_version_0, scr.Structure).AppendLine(); + + switch(scr.Spec) + { + case 0 when scr.Spec3 == false && scr.Spec4 == false && scr.SpecX == 0: + sb.AppendLine("\t" + + Localization.Device_follows_SecureDigital_Physical_Layer_Specification_version_1_0x); + + break; + case 1 when scr.Spec3 == false && scr.Spec4 == false && scr.SpecX == 0: + sb.AppendLine("\t" + + Localization.Device_follows_SecureDigital_Physical_Layer_Specification_version_1_10); + + break; + case 2 when scr.Spec3 == false && scr.Spec4 == false && scr.SpecX == 0: + sb.AppendLine("\t" + + Localization.Device_follows_SecureDigital_Physical_Layer_Specification_version_2_00); + + break; + case 2 when scr.Spec3 && scr.Spec4 == false && scr.SpecX == 0: + sb.AppendLine("\t" + + Localization.Device_follows_SecureDigital_Physical_Layer_Specification_version_3_0x); + + break; + case 2 when scr.Spec3 && scr.Spec4 && scr.SpecX == 0: + sb.AppendLine("\t" + + Localization.Device_follows_SecureDigital_Physical_Layer_Specification_version_4_xx); + + break; + case 2 when scr.Spec3: + switch(scr.SpecX) + { + case 1: + sb.AppendLine("\t" + + Localization + .Device_follows_SecureDigital_Physical_Layer_Specification_version_5_xx); + + break; + case 2: + sb.AppendLine("\t" + + Localization + .Device_follows_SecureDigital_Physical_Layer_Specification_version_6_xx); + + break; + case 3: + sb.AppendLine("\t" + + Localization + .Device_follows_SecureDigital_Physical_Layer_Specification_version_7_xx); + + break; + case 4: + sb.AppendLine("\t" + + Localization + .Device_follows_SecureDigital_Physical_Layer_Specification_version_8_xx); + + break; + } + + break; + default: + sb.AppendFormat("\t" + + Localization + .Device_follows_SecureDigital_Physical_Layer_Specification_with_unknown_version_0_1_2_3, + scr.Spec, + scr.Spec3, + scr.Spec4, + scr.SpecX) + .AppendLine(); + + break; + } + + switch(scr.Security) + { + case 0: + sb.AppendLine("\t" + Localization.Device_does_not_support_CPRM); + + break; + case 1: + sb.AppendLine("\t" + Localization.Device_does_not_use_CPRM); + + break; + case 2: + sb.AppendLine("\t" + Localization.Device_uses_CPRM_according_to_specification_version_1_01); + + break; + case 3: + sb.AppendLine("\t" + Localization.Device_uses_CPRM_according_to_specification_version_2_00); + + break; + case 4: + sb.AppendLine("\t" + Localization.Device_uses_CPRM_according_to_specification_version_3_xx); + + break; + default: + sb.AppendFormat("\t" + Localization.Device_uses_unknown_CPRM_specification_with_code_0, scr.Security) + .AppendLine(); + + break; + } + + if(scr.BusWidth.HasFlag(BusWidth.OneBit)) sb.AppendLine("\t" + Localization.Device_supports_1_bit_data_bus); + + if(scr.BusWidth.HasFlag(BusWidth.FourBit)) sb.AppendLine("\t" + Localization.Device_supports_4_bit_data_bus); + + if(scr.ExtendedSecurity != 0) sb.AppendLine("\t" + Localization.Device_supports_extended_security); + + if(scr.CommandSupport.HasFlag(CommandSupport.ExtensionRegisterMultiBlock)) + sb.AppendLine("\t" + Localization.Device_supports_extension_register_multi_block_commands); + + if(scr.CommandSupport.HasFlag(CommandSupport.ExtensionRegisterSingleBlock)) + sb.AppendLine("\t" + Localization.Device_supports_extension_register_single_block_commands); + + if(scr.CommandSupport.HasFlag(CommandSupport.SetBlockCount)) + sb.AppendLine("\t" + Localization.Device_supports_set_block_count_command); + + if(scr.CommandSupport.HasFlag(CommandSupport.SpeedClassControl)) + sb.AppendLine("\t" + Localization.Device_supports_speed_class_control_command); + + return sb.ToString(); + } + + public static string PrettifySCR(uint[] response) => PrettifySCR(DecodeSCR(response)); + + public static string PrettifySCR(byte[] response) => PrettifySCR(DecodeSCR(response)); +} \ No newline at end of file diff --git a/Aaru.Decoders/SecureDigital/VendorString.cs b/Aaru.Decoders/SecureDigital/VendorString.cs new file mode 100644 index 000000000..4a8749afa --- /dev/null +++ b/Aaru.Decoders/SecureDigital/VendorString.cs @@ -0,0 +1,51 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : VendorString.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes SecureDigital vendor code. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Decoders.SecureDigital; + +/// Decodes SecureDigital vendors +public static class VendorString +{ + /// Converts the byte value of a SecureDigital vendor ID to the manufacturer's name string + /// SD vendor ID + /// Manufacturer + public static string Prettify(byte sdVendorId) => sdVendorId switch + { + 0x41 => "Kingston", + 0x02 => "Kingston", + 0x03 => "Sandisk", + 0x27 => "CnMemory", + 0xAA => "QEMU", + _ => string.Format(Localization.Unknown_manufacturer_ID_0, + sdVendorId) + }; +} \ No newline at end of file diff --git a/Aaru.Decoders/Sega/CD.cs b/Aaru.Decoders/Sega/CD.cs new file mode 100644 index 000000000..aa33c3637 --- /dev/null +++ b/Aaru.Decoders/Sega/CD.cs @@ -0,0 +1,398 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CD.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Sega CD (aka Mega CD) IP.BIN. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; +using Aaru.Console; +using Aaru.Localization; +using Marshal = Aaru.Helpers.Marshal; + +namespace Aaru.Decoders.Sega; + +/// Represents the IP.BIN from a SEGA CD / MEGA CD +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class CD +{ + const string MODULE_NAME = "SegaCD IP.BIN Decoder"; + + /// Decodes an IP.BIN sector in SEGA CD / MEGA CD format + /// IP.BIN sector + /// Decoded IP.BIN + public static IPBin? DecodeIPBin(byte[] ipbin_sector) + { + if(ipbin_sector == null) return null; + + if(ipbin_sector.Length < 512) return null; + + IPBin ipbin = Marshal.ByteArrayToStructureLittleEndian(ipbin_sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "segacd_ipbin.volume_name = \"{0}\"", + Encoding.ASCII.GetString(ipbin.volume_name)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "segacd_ipbin.system_name = \"{0}\"", + Encoding.ASCII.GetString(ipbin.system_name)); + + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.volume_version = \"{0:X}\"", ipbin.volume_version); + + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.volume_type = 0x{0:X8}", ipbin.volume_type); + + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.system_version = 0x{0:X8}", ipbin.system_version); + + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.ip_address = 0x{0:X8}", ipbin.ip_address); + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.ip_loadsize = {0}", ipbin.ip_loadsize); + + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.ip_entry_address = 0x{0:X8}", ipbin.ip_entry_address); + + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.ip_work_ram_size = {0}", ipbin.ip_work_ram_size); + + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.sp_address = 0x{0:X8}", ipbin.sp_address); + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.sp_loadsize = {0}", ipbin.sp_loadsize); + + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.sp_entry_address = 0x{0:X8}", ipbin.sp_entry_address); + + AaruConsole.DebugWriteLine(MODULE_NAME, "segacd_ipbin.sp_work_ram_size = {0}", ipbin.sp_work_ram_size); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "segacd_ipbin.release_date = \"{0}\"", + Encoding.ASCII.GetString(ipbin.release_date)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "segacd_ipbin.release_date2 = \"{0}\"", + Encoding.ASCII.GetString(ipbin.release_date2)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "segacd_ipbin.developer_code = \"{0}\"", + Encoding.ASCII.GetString(ipbin.developer_code)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "segacd_ipbin.domestic_title = \"{0}\"", + Encoding.ASCII.GetString(ipbin.domestic_title)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "segacd_ipbin.overseas_title = \"{0}\"", + Encoding.ASCII.GetString(ipbin.overseas_title)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "segacd_ipbin.product_code = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_code)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "segacd_ipbin.peripherals = \"{0}\"", + Encoding.ASCII.GetString(ipbin.peripherals)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "segacd_ipbin.region_codes = \"{0}\"", + Encoding.ASCII.GetString(ipbin.region_codes)); + + string id = Encoding.ASCII.GetString(ipbin.SegaHardwareID); + + return id is "SEGADISCSYSTEM " or "SEGADATADISC " or "SEGAOS " ? ipbin : null; + } + + /// Pretty prints a decoded IP.BIN in SEGA CD / MEGA CD format + /// Decoded IP.BIN + /// Description of the IP.BIN contents + public static string Prettify(IPBin? decoded) + { + if(decoded == null) return null; + + IPBin ipbin = decoded.Value; + + var IPBinInformation = new StringBuilder(); + + IPBinInformation.AppendLine("--------------------------------"); + IPBinInformation.AppendLine(Localization.SEGA_IP_BIN_INFORMATION); + IPBinInformation.AppendLine("--------------------------------"); + + // Decoding all data + DateTime ipbindate = DateTime.MinValue; + CultureInfo provider = CultureInfo.InvariantCulture; + + try + { + ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date), "MMddyyyy", provider); + } + catch + { + try + { + ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date2), "yyyy.MMM", provider); + } +#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body + catch + { + // ignored + } +#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body + } + + /* + switch (Encoding.ASCII.GetString(application_type)) + { + case "GM": + IPBinInformation.AppendLine("Disc is a game."); + break; + case "AI": + IPBinInformation.AppendLine("Disc is an application."); + break; + default: + IPBinInformation.AppendLine("Disc is from unknown type."); + break; + } + */ + + IPBinInformation.AppendFormat(Core.Volume_name_0, Encoding.ASCII.GetString(ipbin.volume_name)).AppendLine(); + + //IPBinInformation.AppendFormat("Volume version: {0}", Encoding.ASCII.GetString(ipbin.volume_version)).AppendLine(); + //IPBinInformation.AppendFormat("{0}", Encoding.ASCII.GetString(ipbin.volume_type)).AppendLine(); + IPBinInformation.AppendFormat(Localization.System_name_0, Encoding.ASCII.GetString(ipbin.system_name)) + .AppendLine(); + + //IPBinInformation.AppendFormat("System version: {0}", Encoding.ASCII.GetString(ipbin.system_version)).AppendLine(); + IPBinInformation.AppendFormat(Localization.Initial_program_address_0, ipbin.ip_address).AppendLine(); + IPBinInformation.AppendFormat(Localization.Initial_program_load_size_0, ipbin.ip_loadsize).AppendLine(); + + IPBinInformation.AppendFormat(Localization.Initial_program_entry_address_0, ipbin.ip_entry_address) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Initial_program_work_RAM_0, ipbin.ip_work_ram_size).AppendLine(); + IPBinInformation.AppendFormat(Localization.System_program_address_0, ipbin.sp_address).AppendLine(); + IPBinInformation.AppendFormat(Localization.System_program_load_size_0, ipbin.sp_loadsize).AppendLine(); + + IPBinInformation.AppendFormat(Localization.System_program_entry_address_0, ipbin.sp_entry_address).AppendLine(); + + IPBinInformation.AppendFormat(Localization.System_program_work_RAM_0, ipbin.sp_work_ram_size).AppendLine(); + + if(ipbindate != DateTime.MinValue) + IPBinInformation.AppendFormat(Localization.Release_date_0, ipbindate).AppendLine(); + + //IPBinInformation.AppendFormat("Release date (other format): {0}", Encoding.ASCII.GetString(release_date2)).AppendLine(); + IPBinInformation.AppendFormat(Localization.Hardware_ID_0, Encoding.ASCII.GetString(ipbin.hardware_id)) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Developer_code_0, Encoding.ASCII.GetString(ipbin.developer_code)) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Domestic_title_0, Encoding.ASCII.GetString(ipbin.domestic_title)) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Overseas_title_0, Encoding.ASCII.GetString(ipbin.overseas_title)) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Product_code_0, Encoding.ASCII.GetString(ipbin.product_code)) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Peripherals).AppendLine(); + + foreach(byte peripheral in ipbin.peripherals) + { + switch((char)peripheral) + { + case 'A': + IPBinInformation.AppendLine(Localization.Game_supports_analog_controller); + + break; + case 'B': + IPBinInformation.AppendLine(Localization.Game_supports_trackball); + + break; + case 'G': + IPBinInformation.AppendLine(Localization.Game_supports_light_gun); + + break; + case 'J': + IPBinInformation.AppendLine(Localization.Game_supports_JoyPad); + + break; + case 'K': + IPBinInformation.AppendLine(Localization.Game_supports_keyboard); + + break; + case 'M': + IPBinInformation.AppendLine(Localization.Game_supports_mouse); + + break; + case 'O': + IPBinInformation.AppendLine(Localization.Game_supports_Master_System_JoyPad); + + break; + case 'P': + IPBinInformation.AppendLine(Localization.Game_supports_printer_interface); + + break; + case 'R': + IPBinInformation.AppendLine(Localization.Game_supports_serial_RS_232C_interface); + + break; + case 'T': + IPBinInformation.AppendLine(Localization.Game_supports_tablet_interface); + + break; + case 'V': + IPBinInformation.AppendLine(Localization.Game_supports_paddle_controller); + + break; + case ' ': + break; + default: + IPBinInformation.AppendFormat(Localization.Game_supports_unknown_peripheral_0, peripheral) + .AppendLine(); + + break; + } + } + + IPBinInformation.AppendLine(Localization.Regions_supported); + + foreach(byte region in ipbin.region_codes) + { + switch((char)region) + { + case 'J': + IPBinInformation.AppendLine(Localization.Japanese_NTSC); + + break; + case 'U': + IPBinInformation.AppendLine(Localization.USA_NTSC); + + break; + case 'E': + IPBinInformation.AppendLine(Localization.Europe_PAL); + + break; + case ' ': + break; + default: + IPBinInformation.AppendFormat(Localization.Game_supports_unknown_region_0, region).AppendLine(); + + break; + } + } + + return IPBinInformation.ToString(); + } + +#region Nested type: IPBin + + // TODO: Check if it is big or little endian + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IPBin + { + /// Must be "SEGADISCSYSTEM " or "SEGADATADISC " or "SEGAOS " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] SegaHardwareID; + /// 0x010, Varies + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] volume_name; + /// 0x01B, 0x00 + public byte spare_space1; + /// 0x01C, Volume version in BCD. <100 = Prerelease. + public ushort volume_version; + /// 0x01E, Bit 0 = 1 => CD-ROM. Rest should be 0. + public ushort volume_type; + /// 0x020, Unknown, varies! + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] system_name; + /// 0x02B, 0x00 + public byte spare_space2; + /// 0x02C, Should be 1 + public ushort system_version; + /// 0x02E, 0x0000 + public ushort spare_space3; + /// 0x030, Initial program address + public uint ip_address; + /// 0x034, Load size of initial program + public uint ip_loadsize; + /// 0x038, Initial program entry address + public uint ip_entry_address; + /// 0x03C, Initial program work RAM size in bytes + public uint ip_work_ram_size; + /// 0x040, System program address + public uint sp_address; + /// 0x044, Load size of system program + public uint sp_loadsize; + /// 0x048, System program entry address + public uint sp_entry_address; + /// 0x04C, System program work RAM size in bytes + public uint sp_work_ram_size; + /// 0x050, MMDDYYYY + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date; + /// 0x058, Seems to be all 0x20s + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[] unknown1; + /// 0x05F, 0x00 ? + public byte spare_space4; + /// 0x060, System Reserved Area + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 160)] + public byte[] system_reserved; + /// 0x100, Hardware ID + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] hardware_id; + /// 0x113 or 0x110, "SEGA" or "T-xx" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public byte[] developer_code; + /// 0x118, Another release date, this with month in letters? + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date2; + /// 0x120, Domestic version of the game title + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] + public byte[] domestic_title; + /// 0x150, Overseas version of the game title + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] + public byte[] overseas_title; + /// 0x180, Official product code + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] + public byte[] product_code; + /// 0x190, Supported peripherals, see above + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] peripherals; + /// 0x1A0, 0x20 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] spare_space6; + /// 0x1B0, Inside here should be modem information, but I need to get a modem-enabled game + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public byte[] spare_space7; + /// 0x1F0, Region codes, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] region_codes; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Sega/Dreamcast.cs b/Aaru.Decoders/Sega/Dreamcast.cs new file mode 100644 index 000000000..7010638d7 --- /dev/null +++ b/Aaru.Decoders/Sega/Dreamcast.cs @@ -0,0 +1,332 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Dreamcast.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Sega Dreamcast IP.BIN. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; +using Aaru.Console; +using Marshal = Aaru.Helpers.Marshal; + +namespace Aaru.Decoders.Sega; + +/// Represents the IP.BIN from a SEGA Dreamcast +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Dreamcast +{ + const string MODULE_NAME = "Dreamcast IP.BIN Decoder"; + + /// Decodes an IP.BIN sector in Dreamcast format + /// IP.BIN sector + /// Decoded IP.BIN + public static IPBin? DecodeIPBin(byte[] ipbin_sector) + { + if(ipbin_sector == null) return null; + + if(ipbin_sector.Length < 512) return null; + + IPBin ipbin = Marshal.ByteArrayToStructureLittleEndian(ipbin_sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.maker_id = \"{0}\"", + Encoding.ASCII.GetString(ipbin.maker_id)); + + AaruConsole.DebugWriteLine(MODULE_NAME, "dreamcast_ipbin.spare_space1 = \"{0}\"", (char)ipbin.spare_space1); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.dreamcast_media = \"{0}\"", + Encoding.ASCII.GetString(ipbin.dreamcast_media)); + + AaruConsole.DebugWriteLine(MODULE_NAME, "dreamcast_ipbin.disc_no = {0}", (char)ipbin.disc_no); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.disc_no_separator = \"{0}\"", + (char)ipbin.disc_no_separator); + + AaruConsole.DebugWriteLine(MODULE_NAME, "dreamcast_ipbin.disc_total_nos = \"{0}\"", (char)ipbin.disc_total_nos); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.spare_space2 = \"{0}\"", + Encoding.ASCII.GetString(ipbin.spare_space2)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.region_codes = \"{0}\"", + Encoding.ASCII.GetString(ipbin.region_codes)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.peripherals = \"{0}\"", + Encoding.ASCII.GetString(ipbin.peripherals)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.product_no = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_no)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.product_version = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_version)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.release_date = \"{0}\"", + Encoding.ASCII.GetString(ipbin.release_date)); + + AaruConsole.DebugWriteLine(MODULE_NAME, "dreamcast_ipbin.spare_space3 = \"{0}\"", (char)ipbin.spare_space3); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.boot_filename = \"{0}\"", + Encoding.ASCII.GetString(ipbin.boot_filename)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.producer = \"{0}\"", + Encoding.ASCII.GetString(ipbin.producer)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "dreamcast_ipbin.product_name = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_name)); + + return Encoding.ASCII.GetString(ipbin.SegaHardwareID) == "SEGA SEGAKATANA " ? ipbin : null; + } + + /// Pretty prints a decoded IP.BIN in Dreamcast format + /// Decoded IP.BIN + /// Description of the IP.BIN contents + public static string Prettify(IPBin? decoded) + { + if(decoded == null) return null; + + IPBin ipbin = decoded.Value; + + var IPBinInformation = new StringBuilder(); + + IPBinInformation.AppendLine("--------------------------------"); + IPBinInformation.AppendLine(Localization.SEGA_IP_BIN_INFORMATION); + IPBinInformation.AppendLine("--------------------------------"); + + // Decoding all data + CultureInfo provider = CultureInfo.InvariantCulture; + var ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date), "yyyyMMdd", provider); + + IPBinInformation.AppendFormat(Localization.Product_name_0, Encoding.ASCII.GetString(ipbin.product_name)) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Product_version_0, Encoding.ASCII.GetString(ipbin.product_version)) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Product_CRC_0, ipbin.dreamcast_crc).AppendLine(); + IPBinInformation.AppendFormat(Localization.Producer_0, Encoding.ASCII.GetString(ipbin.producer)).AppendLine(); + + IPBinInformation.AppendFormat(Localization.Disc_media_0, Encoding.ASCII.GetString(ipbin.dreamcast_media)) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Disc_number_0_of_1, (char)ipbin.disc_no, (char)ipbin.disc_total_nos) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Release_date_0, ipbindate).AppendLine(); + + switch(Encoding.ASCII.GetString(ipbin.boot_filename)) + { + case "1ST_READ.BIN": + IPBinInformation.AppendLine(Localization.Disc_boots_natively); + + break; + case "0WINCE.BIN ": + IPBinInformation.AppendLine(Localization.Disc_boots_using_Windows_CE); + + break; + default: + IPBinInformation.AppendFormat(Localization.Disc_boots_using_unknown_loader_0, + Encoding.ASCII.GetString(ipbin.boot_filename)) + .AppendLine(); + + break; + } + + IPBinInformation.AppendLine(Localization.Regions_supported); + + foreach(byte region in ipbin.region_codes) + { + switch((char)region) + { + case 'J': + IPBinInformation.AppendLine(Localization.Japanese_NTSC); + + break; + case 'U': + IPBinInformation.AppendLine(Localization.North_America_NTSC); + + break; + case 'E': + IPBinInformation.AppendLine(Localization.Europe_PAL); + + break; + case ' ': + break; + default: + IPBinInformation.AppendFormat(Localization.Game_supports_unknown_region_0, region).AppendLine(); + + break; + } + } + + var iPeripherals = int.Parse(Encoding.ASCII.GetString(ipbin.peripherals), NumberStyles.HexNumber); + + if((iPeripherals & 0x00000001) == 0x00000001) IPBinInformation.AppendLine(Localization.Game_uses_Windows_CE); + + IPBinInformation.AppendFormat(Localization.Peripherals).AppendLine(); + + if((iPeripherals & 0x00000010) == 0x00000010) + IPBinInformation.AppendLine(Localization.Game_supports_the_VGA_Box); + + if((iPeripherals & 0x00000100) == 0x00000100) + IPBinInformation.AppendLine(Localization.Game_supports_other_expansion); + + if((iPeripherals & 0x00000200) == 0x00000200) + IPBinInformation.AppendLine(Localization.Game_supports_Puru_Puru_pack); + + if((iPeripherals & 0x00000400) == 0x00000400) + IPBinInformation.AppendLine(Localization.Game_supports_Mike_Device); + + if((iPeripherals & 0x00000800) == 0x00000800) + IPBinInformation.AppendLine(Localization.Game_supports_Memory_Card); + + if((iPeripherals & 0x00001000) == 0x00001000) + IPBinInformation.AppendLine(Localization.Game_requires_A_B_Start_buttons_and_D_Pad); + + if((iPeripherals & 0x00002000) == 0x00002000) IPBinInformation.AppendLine(Localization.Game_requires_C_button); + + if((iPeripherals & 0x00004000) == 0x00004000) IPBinInformation.AppendLine(Localization.Game_requires_D_button); + + if((iPeripherals & 0x00008000) == 0x00008000) IPBinInformation.AppendLine(Localization.Game_requires_X_button); + + if((iPeripherals & 0x00010000) == 0x00010000) IPBinInformation.AppendLine(Localization.Game_requires_Y_button); + + if((iPeripherals & 0x00020000) == 0x00020000) IPBinInformation.AppendLine(Localization.Game_requires_Z_button); + + if((iPeripherals & 0x00040000) == 0x00040000) + IPBinInformation.AppendLine(Localization.Game_requires_expanded_direction_buttons); + + if((iPeripherals & 0x00080000) == 0x00080000) + IPBinInformation.AppendLine(Localization.Game_requires_analog_R_trigger); + + if((iPeripherals & 0x00100000) == 0x00100000) + IPBinInformation.AppendLine(Localization.Game_requires_analog_L_trigger); + + if((iPeripherals & 0x00200000) == 0x00200000) + IPBinInformation.AppendLine(Localization.Game_requires_analog_horizontal_controller); + + if((iPeripherals & 0x00400000) == 0x00400000) + IPBinInformation.AppendLine(Localization.Game_requires_analog_vertical_controller); + + if((iPeripherals & 0x00800000) == 0x00800000) + IPBinInformation.AppendLine(Localization.Game_requires_expanded_analog_horizontal_controller); + + if((iPeripherals & 0x01000000) == 0x01000000) + IPBinInformation.AppendLine(Localization.Game_requires_expanded_analog_vertical_controller); + + if((iPeripherals & 0x02000000) == 0x02000000) IPBinInformation.AppendLine(Localization.Game_supports_Gun); + + if((iPeripherals & 0x04000000) == 0x04000000) IPBinInformation.AppendLine(Localization.Game_supports_keyboard); + + if((iPeripherals & 0x08000000) == 0x08000000) IPBinInformation.AppendLine(Localization.Game_supports_mouse); + + if((iPeripherals & 0xEE) != 0) + IPBinInformation.AppendFormat(Localization.Game_supports_unknown_peripherals_mask_0, iPeripherals & 0xEE); + + return IPBinInformation.ToString(); + } + +#region Nested type: IPBin + + /// SEGA IP.BIN format for Dreamcast + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IPBin + { + /// Must be "SEGA SEGAKATANA " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] SegaHardwareID; + /// 0x010, "SEGA ENTERPRISES" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] maker_id; + /// 0x020, CRC of product_no and product_version + public uint dreamcast_crc; + /// 0x024, " " + public byte spare_space1; + /// 0x025, "GD-ROM" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] dreamcast_media; + /// 0x02B, Disc number + public byte disc_no; + /// 0x02C, '/' + public byte disc_no_separator; + /// 0x02D, Total number of discs + public byte disc_total_nos; + /// 0x02E, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] spare_space2; + /// 0x030, Region codes, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] region_codes; + /// 0x038, Supported peripherals, bitwise + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[] peripherals; + /// 0x03F, ' ' + public byte spare_space3; + /// 0x040, Product number + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] product_no; + /// 0x04A, Product version + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] product_version; + /// 0x050, YYYYMMDD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date; + /// 0x058, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] spare_space4; + /// 0x060, Usually "1ST_READ.BIN" or "0WINCE.BIN " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] boot_filename; + /// 0x06C, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] spare_space5; + /// 0x070, Game producer, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] producer; + /// 0x080, Game name, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public byte[] product_name; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Sega/Saturn.cs b/Aaru.Decoders/Sega/Saturn.cs new file mode 100644 index 000000000..75e0b5d1a --- /dev/null +++ b/Aaru.Decoders/Sega/Saturn.cs @@ -0,0 +1,263 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Saturn.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Sega Saturn IP.BIN. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; +using Aaru.Console; +using Marshal = Aaru.Helpers.Marshal; + +namespace Aaru.Decoders.Sega; + +/// Represents the IP.BIN from a SEGA Saturn +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Saturn +{ + const string MODULE_NAME = "Saturn IP.BIN Decoder"; + + /// Decodes an IP.BIN sector in Saturn format + /// IP.BIN sector + /// Decoded IP.BIN + public static IPBin? DecodeIPBin(byte[] ipbin_sector) + { + if(ipbin_sector == null) return null; + + if(ipbin_sector.Length < 512) return null; + + IPBin ipbin = Marshal.ByteArrayToStructureLittleEndian(ipbin_sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.maker_id = \"{0}\"", + Encoding.ASCII.GetString(ipbin.maker_id)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.product_no = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_no)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.product_version = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_version)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.release_date = \"{0}\"", + Encoding.ASCII.GetString(ipbin.release_date)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.saturn_media = \"{0}\"", + Encoding.ASCII.GetString(ipbin.saturn_media)); + + AaruConsole.DebugWriteLine(MODULE_NAME, "saturn_ipbin.disc_no = {0}", (char)ipbin.disc_no); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.disc_no_separator = \"{0}\"", + (char)ipbin.disc_no_separator); + + AaruConsole.DebugWriteLine(MODULE_NAME, "saturn_ipbin.disc_total_nos = {0}", (char)ipbin.disc_total_nos); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.release_date = \"{0}\"", + Encoding.ASCII.GetString(ipbin.release_date)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.spare_space1 = \"{0}\"", + Encoding.ASCII.GetString(ipbin.spare_space1)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.region_codes = \"{0}\"", + Encoding.ASCII.GetString(ipbin.region_codes)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.peripherals = \"{0}\"", + Encoding.ASCII.GetString(ipbin.peripherals)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "saturn_ipbin.product_name = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_name)); + + return Encoding.ASCII.GetString(ipbin.SegaHardwareID) == "SEGA SEGASATURN " ? ipbin : null; + } + + /// Pretty prints a decoded IP.BIN in Saturn format + /// Decoded IP.BIN + /// Description of the IP.BIN contents + public static string Prettify(IPBin? decoded) + { + if(decoded == null) return null; + + IPBin ipbin = decoded.Value; + + var IPBinInformation = new StringBuilder(); + + IPBinInformation.AppendLine("--------------------------------"); + IPBinInformation.AppendLine(Localization.SEGA_IP_BIN_INFORMATION); + IPBinInformation.AppendLine("--------------------------------"); + + // Decoding all data + CultureInfo provider = CultureInfo.InvariantCulture; + var ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date), "yyyyMMdd", provider); + + IPBinInformation.AppendFormat(Localization.Product_name_0, Encoding.ASCII.GetString(ipbin.product_name)) + .AppendLine(); + + IPBinInformation.Append($"Product number: {Encoding.ASCII.GetString(ipbin.product_no)}").AppendLine(); + + IPBinInformation.AppendFormat(Localization.Product_version_0, Encoding.ASCII.GetString(ipbin.product_version)) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Release_date_0, ipbindate).AppendLine(); + + IPBinInformation.AppendFormat(Localization.Disc_number_0_of_1, (char)ipbin.disc_no, (char)ipbin.disc_total_nos) + .AppendLine(); + + IPBinInformation.AppendFormat(Localization.Peripherals).AppendLine(); + + foreach(byte peripheral in ipbin.peripherals) + { + switch((char)peripheral) + { + case 'A': + IPBinInformation.AppendLine(Localization.Game_supports_analog_controller); + + break; + case 'J': + IPBinInformation.AppendLine(Localization.Game_supports_JoyPad); + + break; + case 'K': + IPBinInformation.AppendLine(Localization.Game_supports_keyboard); + + break; + case 'M': + IPBinInformation.AppendLine(Localization.Game_supports_mouse); + + break; + case 'S': + IPBinInformation.AppendLine(Localization.Game_supports_analog_steering_controller); + + break; + case 'T': + IPBinInformation.AppendLine(Localization.Game_supports_multitap); + + break; + case ' ': + break; + default: + IPBinInformation.AppendFormat(Localization.Game_supports_unknown_peripheral_0, peripheral) + .AppendLine(); + + break; + } + } + + IPBinInformation.AppendLine(Localization.Regions_supported); + + foreach(byte region in ipbin.region_codes) + { + switch((char)region) + { + case 'J': + IPBinInformation.AppendLine(Localization.Japanese_NTSC); + + break; + case 'U': + IPBinInformation.AppendLine(Localization.North_America_NTSC); + + break; + case 'E': + IPBinInformation.AppendLine(Localization.Europe_PAL); + + break; + case 'T': + IPBinInformation.AppendLine(Localization.Asia_NTSC); + + break; + case ' ': + break; + default: + IPBinInformation.AppendFormat(Localization.Game_supports_unknown_region_0, region).AppendLine(); + + break; + } + } + + return IPBinInformation.ToString(); + } + +#region Nested type: IPBin + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IPBin + { + /// Must be "SEGA SEGASATURN " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] SegaHardwareID; + /// 0x010, "SEGA ENTERPRISES" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] maker_id; + /// 0x020, Product number + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] product_no; + /// 0x02A, Product version + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] product_version; + /// 0x030, YYYYMMDD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date; + /// 0x038, "CD-" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] saturn_media; + /// 0x03B, Disc number + public byte disc_no; + /// // 0x03C, '/' + public byte disc_no_separator; + /// // 0x03D, Total number of discs + public byte disc_total_nos; + /// 0x03E, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] spare_space1; + /// 0x040, Region codes, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] region_codes; + /// 0x050, Supported peripherals, see above + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] peripherals; + /// 0x060, Game name, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 112)] + public byte[] product_name; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Xbox/DMI.cs b/Aaru.Decoders/Xbox/DMI.cs new file mode 100644 index 000000000..bc3cab460 --- /dev/null +++ b/Aaru.Decoders/Xbox/DMI.cs @@ -0,0 +1,269 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DMI.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Xbox discs DMI structure. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Helpers; + +namespace Aaru.Decoders.Xbox; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DMI +{ + public static bool IsXbox(byte[] dmi) + { + if(dmi?.Length != 2052) return false; + + // Version is 1 + if(BitConverter.ToUInt32(dmi, 4) != 1) return false; + + // Catalogue number is two letters, five numbers, one letter + for(var i = 12; i < 14; i++) + if(dmi[i] < 0x41 || dmi[i] > 0x5A) + return false; + + for(var i = 14; i < 19; i++) + if(dmi[i] < 0x30 || dmi[i] > 0x39) + return false; + + if(dmi[19] < 0x41 || dmi[19] > 0x5A) return false; + + var timestamp = BitConverter.ToInt64(dmi, 20); + + // Game cannot exist before the Xbox + return timestamp >= 0x1BD164833DFC000; + } + + public static bool IsXbox360(byte[] dmi) + { + if(dmi?.Length != 2052) return false; + + var signature = BitConverter.ToUInt32(dmi, 0x7EC); + + // "XBOX" swapped as .NET is little endian + return signature == 0x584F4258; + } + + public static XboxDMI? DecodeXbox(byte[] response) + { + bool isXbox = IsXbox(response); + + if(!isXbox) return null; + + var dmi = new XboxDMI + { + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + Version = BitConverter.ToUInt32(response, 4), + Timestamp = BitConverter.ToInt64(response, 20) + }; + + var tmp = new byte[8]; + Array.Copy(response, 12, tmp, 0, 8); + dmi.CatalogNumber = StringHandlers.CToString(tmp); + + return dmi; + } + + public static Xbox360DMI? DecodeXbox360(byte[] response) + { + bool isX360 = IsXbox360(response); + + if(!isX360) return null; + + var dmi = new Xbox360DMI + { + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + Version = BitConverter.ToUInt32(response, 4), + Timestamp = BitConverter.ToInt64(response, 20), + MediaID = new byte[16] + }; + + Array.Copy(response, 36, dmi.MediaID, 0, 16); + var tmp = new byte[16]; + Array.Copy(response, 68, tmp, 0, 16); + dmi.CatalogNumber = StringHandlers.CToString(tmp); + + return dmi.CatalogNumber == null || dmi.CatalogNumber.Length < 13 ? null : dmi; + } + + public static string PrettifyXbox(XboxDMI? dmi) + { + if(dmi == null) return null; + + XboxDMI decoded = dmi.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.Catalogue_number); + + for(var i = 0; i < 2; i++) sb.Append($"{decoded.CatalogNumber[i]}"); + + sb.Append("-"); + + for(var i = 2; i < 7; i++) sb.Append($"{decoded.CatalogNumber[i]}"); + + sb.Append("-"); + sb.Append($"{decoded.CatalogNumber[7]}"); + sb.AppendLine(); + + sb.AppendFormat(Localization.Timestamp_0, DateTime.FromFileTimeUtc(decoded.Timestamp)).AppendLine(); + + return sb.ToString(); + } + + public static string PrettifyXbox360(Xbox360DMI? dmi) + { + if(dmi == null) return null; + + Xbox360DMI decoded = dmi.Value; + var sb = new StringBuilder(); + + sb.Append(Localization.Catalogue_number); + + for(var i = 0; i < 2; i++) sb.Append($"{decoded.CatalogNumber[i]}"); + + sb.Append("-"); + + for(var i = 2; i < 6; i++) sb.Append($"{decoded.CatalogNumber[i]}"); + + sb.Append("-"); + + for(var i = 6; i < 8; i++) sb.Append($"{decoded.CatalogNumber[i]}"); + + sb.Append("-"); + + switch(decoded.CatalogNumber.Length) + { + case 13: + for(var i = 8; i < 10; i++) sb.Append($"{decoded.CatalogNumber[i]}"); + + sb.Append("-"); + + for(var i = 10; i < 13; i++) sb.Append($"{decoded.CatalogNumber[i]}"); + + break; + case 14: + for(var i = 8; i < 11; i++) sb.Append($"{decoded.CatalogNumber[i]}"); + + sb.Append("-"); + + for(var i = 11; i < 14; i++) sb.Append($"{decoded.CatalogNumber[i]}"); + + break; + default: + for(var i = 8; i < decoded.CatalogNumber.Length - 3; i++) sb.Append($"{decoded.CatalogNumber[i]}"); + + sb.Append("-"); + + for(int i = decoded.CatalogNumber.Length - 3; i < decoded.CatalogNumber.Length; i++) + sb.Append($"{decoded.CatalogNumber[i]}"); + + break; + } + + sb.AppendLine(); + + sb.Append(Localization.Media_ID); + + for(var i = 0; i < 12; i++) sb.Append($"{decoded.MediaID[i]:X2}"); + + sb.Append("-"); + + for(var i = 12; i < 16; i++) sb.Append($"{decoded.MediaID[i]:X2}"); + + sb.AppendLine(); + + sb.AppendFormat(Localization.Timestamp_0, DateTime.FromFileTimeUtc(decoded.Timestamp)).AppendLine(); + + return sb.ToString(); + } + + public static string PrettifyXbox(byte[] response) => PrettifyXbox(DecodeXbox(response)); + + public static string PrettifyXbox360(byte[] response) => PrettifyXbox360(DecodeXbox360(response)); + +#region Nested type: Xbox360DMI + + public struct Xbox360DMI + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + + /// Bytes 4 to 7 0x02 in XGD2 and XGD3 + public uint Version; + + /// Bytes 20 to 27 DMI timestamp + public long Timestamp; + + /// Bytes 36 to 51 Media ID in hex XXXXXXXXXXXX-XXXXXXXX + public byte[] MediaID; + + /// Bytes 68 to 83 Catalogue number in XX-XXXX-XX-XXY-XXX, Y not always exists + public string CatalogNumber; + } + +#endregion + +#region Nested type: XboxDMI + + public struct XboxDMI + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + + /// Bytes 4 to 7 0x01 in XGD + public uint Version; + + /// Bytes 12 to 16 Catalogue number in XX-XXXXX-X + public string CatalogNumber; + + /// Bytes 20 to 27 DMI timestamp + public long Timestamp; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decoders/Xbox/SS.cs b/Aaru.Decoders/Xbox/SS.cs new file mode 100644 index 000000000..cb40b2567 --- /dev/null +++ b/Aaru.Decoders/Xbox/SS.cs @@ -0,0 +1,432 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SS.cs +// Author(s) : Natalia Portillo +// +// Component : Device structures decoders. +// +// --[ Description ] ---------------------------------------------------------- +// +// Decodes Xbox security sectors +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.Decoders.DVD; + +namespace Aaru.Decoders.Xbox; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class SS +{ + public static SecuritySector? Decode(byte[] response) + { + if(response == null) return null; + + if(response.Length < 2048) return null; + + var ss = new SecuritySector + { + DiskCategory = (DiskCategory)((response[0] & 0xF0) >> 4), + PartVersion = (byte)(response[0] & 0x0F), + DiscSize = (DVDSize)((response[1] & 0xF0) >> 4), + MaximumRate = (MaximumRateField)(response[1] & 0x0F), + Reserved3 = (response[2] & 0x80) == 0x80, + Layers = (byte)((response[2] & 0x60) >> 5), + TrackPath = (response[2] & 0x08) == 0x08, + LayerType = (LayerTypeFieldMask)(response[2] & 0x07), + LinearDensity = (LinearDensityField)((response[3] & 0xF0) >> 4), + TrackDensity = (TrackDensityField)(response[3] & 0x0F), + DataAreaStartPSN = (uint)((response[4] << 24) + (response[5] << 16) + (response[6] << 8) + response[7]), + DataAreaEndPSN = (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]), + Layer0EndPSN = (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]), + Unknown1 = response[27], + Unknown2 = new byte[28], + Unknown3 = new byte[436], + Unknown4 = new byte[4], + Unknown5 = new byte[43], + ChallengeTableVersion = response[768], + NoChallengeEntries = response[769], + ChallengeEntries = new ChallengeEntry[23], + Unknown6 = response[1023], + Unknown7 = new byte[48], + Unknown8 = new byte[16], + Unknown9 = new byte[16], + Unknown10 = new byte[303], + Unknown11 = new byte[104], + Extents = new SecuritySectorExtent[23], + ExtentsCopy = new SecuritySectorExtent[23] + }; + + Array.Copy(response, 256, ss.Unknown2, 0, 28); + Array.Copy(response, 284, ss.Unknown3, 0, 436); + Array.Copy(response, 720, ss.Unknown4, 0, 4); + Array.Copy(response, 724, ss.Unknown5, 0, 43); + + for(var i = 0; i < 23; i++) + { + ss.ChallengeEntries[i] = new ChallengeEntry + { + Level = response[770 + i * 11 + 0], + ChallengeId = response[770 + i * 11 + 1], + ChallengeValue = + (uint)((response[770 + i * 11 + 2] << 24) + + (response[770 + i * 11 + 3] << 16) + + (response[770 + i * 11 + 4] << 8) + + response[770 + i * 11 + 5]), + ResponseModifier = response[770 + i * 11 + 6], + ResponseValue = (uint)((response[770 + i * 11 + 7] << 24) + + (response[770 + i * 11 + 8] << 16) + + (response[770 + i * 11 + 9] << 8) + + response[770 + i * 11 + 10]) + }; + } + + Array.Copy(response, 1052, ss.Unknown7, 0, 48); + Array.Copy(response, 1120, ss.Unknown8, 0, 16); + Array.Copy(response, 1180, ss.Unknown9, 0, 16); + Array.Copy(response, 1208, ss.Unknown10, 0, 303); + Array.Copy(response, 1528, ss.Unknown11, 0, 104); + + for(var i = 0; i < 23; i++) + { + ss.Extents[i] = new SecuritySectorExtent + { + Unknown = + (uint)((response[1633 + i * 9 + 0] << 16) + + (response[1633 + i * 9 + 1] << 8) + + response[1633 + i * 9 + 2]), + StartPSN = (uint)((response[1633 + i * 9 + 3] << 16) + + (response[1633 + i * 9 + 4] << 8) + + response[1633 + i * 9 + 5]), + EndPSN = (uint)((response[1633 + i * 9 + 6] << 16) + + (response[1633 + i * 9 + 7] << 8) + + response[1633 + i * 9 + 8]) + }; + } + + for(var i = 0; i < 23; i++) + { + ss.ExtentsCopy[i] = new SecuritySectorExtent + { + Unknown = + (uint)((response[1840 + i * 9 + 0] << 16) + + (response[1840 + i * 9 + 1] << 8) + + response[1840 + i * 9 + 2]), + StartPSN = (uint)((response[1840 + i * 9 + 3] << 16) + + (response[1840 + i * 9 + 4] << 8) + + response[1840 + i * 9 + 5]), + EndPSN = (uint)((response[1840 + i * 9 + 6] << 16) + + (response[1840 + i * 9 + 7] << 8) + + response[1840 + i * 9 + 8]) + }; + } + + return ss; + } + + public static string Prettify(SecuritySector? ss) + { + if(ss == null) return null; + + SecuritySector decoded = ss.Value; + var sb = new StringBuilder(); + + string sizeString = decoded.DiscSize switch + { + DVDSize.Eighty => Localization._80mm, + DVDSize.OneTwenty => Localization._120mm, + _ => string.Format(Localization.unknown_size_identifier_0, decoded.DiscSize) + }; + + string categorySentence = Localization.Disc_is_a_0_1_version_2; + + switch(decoded.DiskCategory) + { + case DiskCategory.DVDPRWDL: + sb.AppendFormat(categorySentence, sizeString, Localization.Xbox_Game_Disc, decoded.PartVersion) + .AppendLine(); + + break; + case DiskCategory.DVDPRDL: + sb.AppendFormat(categorySentence, sizeString, Localization.Xbox_360_Game_Disc, decoded.PartVersion) + .AppendLine(); + + break; + default: + sb.AppendFormat(categorySentence, sizeString, Localization.unknown_disc_type, decoded.PartVersion) + .AppendLine(); + + break; + } + + switch(decoded.MaximumRate) + { + case MaximumRateField.TwoMbps: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_2_52_Mbit_sec); + + break; + case MaximumRateField.FiveMbps: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_5_04_Mbit_sec); + + break; + case MaximumRateField.TenMbps: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_10_08_Mbit_sec); + + break; + case MaximumRateField.TwentyMbps: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_20_16_Mbit_sec); + + break; + case MaximumRateField.ThirtyMbps: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_30_24_Mbit_sec); + + break; + case MaximumRateField.Unspecified: + sb.AppendLine(Localization.Disc_maximum_transfer_rate_is_unspecified); + + break; + default: + sb.AppendFormat(Localization.Disc_maximum_transfer_rate_is_specified_by_unknown_key_0, + decoded.MaximumRate) + .AppendLine(); + + break; + } + + sb.AppendFormat(Localization.Disc_has_0_layers, decoded.Layers + 1).AppendLine(); + + switch(decoded.TrackPath) + { + case true when decoded.Layers == 1: + sb.AppendLine(Localization.Layers_are_in_parallel_track_path); + + break; + case false when decoded.Layers == 1: + sb.AppendLine(Localization.Layers_are_in_opposite_track_path); + + break; + } + + switch(decoded.LinearDensity) + { + case LinearDensityField.TwoSix: + sb.AppendLine(Localization.Pitch_size_is_0_267_μm_bit); + + break; + case LinearDensityField.TwoNine: + sb.AppendLine(Localization.Pitch_size_is_0_147_μm_bit); + + break; + case LinearDensityField.FourZero: + sb.AppendLine(Localization.Pitch_size_is_between_0_409_μm_bit_and_0_435_μm_bit); + + break; + case LinearDensityField.TwoEight: + sb.AppendLine(Localization.Pitch_size_is_between_0_140_μm_bit_and_0_148_μm_bit); + + break; + case LinearDensityField.OneFive: + sb.AppendLine(Localization.Pitch_size_is_0_153_μm_bit); + + break; + case LinearDensityField.OneThree: + sb.AppendLine(Localization.Pitch_size_is_between_0_130_μm_bit_and_0_140_μm_bit); + + break; + case LinearDensityField.ThreeFive: + sb.AppendLine(Localization.Pitch_size_is_0_353_μm_bit); + + break; + default: + sb.AppendFormat(Localization.Unknown_pitch_size_key_0, decoded.LinearDensity).AppendLine(); + + break; + } + + switch(decoded.TrackDensity) + { + case TrackDensityField.Seven: + sb.AppendLine(Localization.Track_size_is_0_74_μm); + + break; + case TrackDensityField.Eight: + sb.AppendLine(Localization.Track_size_is_0_80_μm); + + break; + case TrackDensityField.Six: + sb.AppendLine(Localization.Track_size_is_0_615_μm); + + break; + case TrackDensityField.Four: + sb.AppendLine(Localization.Track_size_is_0_40_μm); + + break; + case TrackDensityField.Three: + sb.AppendLine(Localization.Track_size_is_0_34_μm); + + break; + default: + sb.AppendFormat(Localization.Unknown_track_size_key__0_, decoded.LinearDensity).AppendLine(); + + break; + } + + if(decoded.DataAreaStartPSN > 0) + { + if(decoded.DataAreaEndPSN > 0) + { + sb.AppendFormat(Localization.Data_area_starts_at_PSN_0, decoded.DataAreaStartPSN).AppendLine(); + sb.AppendFormat(Localization.Data_area_ends_at_PSN_0, decoded.DataAreaEndPSN).AppendLine(); + + if(decoded is { Layers: 1, TrackPath: false }) + sb.AppendFormat(Localization.Layer_zero_ends_at_PSN_0, decoded.Layer0EndPSN).AppendLine(); + } + else + sb.AppendLine(Localization.Disc_is_empty); + } + else + sb.AppendLine(Localization.Disc_is_empty); + + sb.AppendLine("Challenges:"); + + foreach(ChallengeEntry entry in decoded.ChallengeEntries) + { + sb.AppendFormat("\t" + Localization.Challenge_ID_0, entry.ChallengeId).AppendLine(); + sb.AppendFormat("\t" + Localization.Challenge_level_0, entry.Level).AppendLine(); + sb.AppendFormat("\t" + Localization.Challenge_value_0, entry.ChallengeValue).AppendLine(); + sb.AppendFormat("\t" + Localization.Response_modifier_0, entry.ResponseModifier).AppendLine(); + sb.AppendFormat("\t" + Localization.Response_value_0, entry.ResponseValue).AppendLine(); + } + + for(var i = 0; i < 16; i++) + { + sb.AppendFormat(Localization.Extent_starts_at_PSN_0_and_ends_at_PSN_1, + decoded.Extents[i].StartPSN, + decoded.Extents[i].EndPSN) + .AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify(byte[] response) => Prettify(Decode(response)); + +#region Nested type: ChallengeEntry + + public struct ChallengeEntry + { + public byte Level; + public byte ChallengeId; + public uint ChallengeValue; + public byte ResponseModifier; + public uint ResponseValue; + } + +#endregion + +#region Nested type: SecuritySector + + public struct SecuritySector + { + /// Byte 0, bits 7 to 4 Disk category field + public DiskCategory DiskCategory; + /// Byte 0, bits 3 to 0 Media version + public byte PartVersion; + /// Byte 1, bits 7 to 4 120mm if 0, 80mm if 1. If UMD (60mm) 0 also. Reserved rest of values + public DVDSize DiscSize; + /// Byte 1, bits 3 to 0 Maximum data rate + public MaximumRateField MaximumRate; + /// Byte 2, bit 7 Reserved + public bool Reserved3; + /// Byte 2, bits 6 to 5 Number of layers + public byte Layers; + /// Byte 2, bit 4 Track path + public bool TrackPath; + /// Byte 2, bits 3 to 0 Layer type + public LayerTypeFieldMask LayerType; + /// Byte 3, bits 7 to 4 Linear density field + public LinearDensityField LinearDensity; + /// Byte 3, bits 3 to 0 Track density field + public TrackDensityField TrackDensity; + /// Bytes 4 to 7 PSN where Data Area starts + public uint DataAreaStartPSN; + /// Bytes 8 to 11 PSN where Data Area ends + public uint DataAreaEndPSN; + /// Bytes 12 to 15 PSN where Data Area ends in Layer 0 + public uint Layer0EndPSN; + + /// Byte 27 Always 0x06 on XGD3 + public byte Unknown1; + /// Bytes 256 to 283 Unknown, XGD2 and XGD3 + public byte[] Unknown2; + /// Bytes 284 to 719 Unknown, XGD3 + public byte[] Unknown3; + /// Bytes 720 to 723 Unknown + public byte[] Unknown4; + /// Bytes 724 to 767 Unknown, XGD3 + public byte[] Unknown5; + /// Byte 768 Version of challenge table + public byte ChallengeTableVersion; + /// Byte 769 Number of challenge entries + public byte NoChallengeEntries; + /// Bytes 770 to 1022 Unknown + public ChallengeEntry[] ChallengeEntries; + /// Byte 1023 Unknown + public byte Unknown6; + /// Bytes 1052 to 1099 Unknown, XGD1 only + public byte[] Unknown7; + /// Bytes 1120 to 1135 Unknown, XGD2 and XGD3 + public byte[] Unknown8; + /// Bytes 1180 to 1195 Unknown + public byte[] Unknown9; + /// Bytes 1208 to 1511 Unknown + public byte[] Unknown10; + /// Bytes 1528 to 1632 + public byte[] Unknown11; + /// Bytes 1633 to 1839 Security extents, 23 entries of 9 bytes + public SecuritySectorExtent[] Extents; + /// Bytes 1840 to 2047 Copy of the security extents, 23 entries of 9 bytes + public SecuritySectorExtent[] ExtentsCopy; + } + +#endregion + +#region Nested type: SecuritySectorExtent + + public struct SecuritySectorExtent + { + /// Bytes 0 to 2 Unknown + public uint Unknown; + /// Bytes 3 to 5 Start PSN of this security extent + public uint StartPSN; + /// Bytes 6 to 8 End PSN of this security extent + public uint EndPSN; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decryption b/Aaru.Decryption deleted file mode 160000 index 5bb198ff9..000000000 --- a/Aaru.Decryption +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5bb198ff96fb64a6d5bf0b35525d8bbfebe2947f diff --git a/Aaru.Decryption/.gitignore b/Aaru.Decryption/.gitignore new file mode 100644 index 000000000..47d474d72 --- /dev/null +++ b/Aaru.Decryption/.gitignore @@ -0,0 +1,608 @@ +### VisualStudio template +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ +### Linux template + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +### C++ template +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o + +# Precompiled Headers +*.gch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### MonoDevelop template +#User Specific +*.usertasks + +#Mono Project Files +*.resources +test-results/ +### GPG template +secring.* + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### CMake template +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +### C template +# Object files +*.ko +*.elf + +# Linker output +*.map +*.exp + +*.so.* + +# Executables +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# NuGet Packages Directory +packages/ +## TODO: If the tool you use requires repositories.config uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +# This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) +!packages/build/ + + +# Others +sql/ +*.Cache + +# Visual Studio 2017 +.vs + +workspace.xml +cmake-build-debug +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +pkg/**/pkg +pkg/**/src +pkg/**/*.asc +pkg/**/*.sig +pkg/**/*.tar.xz +pkg/**/*.zip +pkg/**/aaru + +.sonarqube + +build/* \ No newline at end of file diff --git a/Aaru.Decryption/Aaru.Decryption.csproj b/Aaru.Decryption/Aaru.Decryption.csproj new file mode 100644 index 000000000..5bb71d141 --- /dev/null +++ b/Aaru.Decryption/Aaru.Decryption.csproj @@ -0,0 +1,106 @@ + + + + 2.0 + Library + Aaru.Decryption + Aaru.Decryption + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Decryption + $(Version) + net8.0 + 12 + Decryption algorithms used by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + MIT + https://github.com/aaru-dps/Aaru.Decryption + true + en-US + true + true + snupkg + Rebecca Wallander <sakcheen@gmail.com> + enable + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + + + + + + + + ResXFileCodeGenerator + Localization.Designer.cs + + + + + + True + True + Localization.resx + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/Aaru.Decryption/Aaru.Decryption.csproj.DotSettings b/Aaru.Decryption/Aaru.Decryption.csproj.DotSettings new file mode 100644 index 000000000..67ed7f8db --- /dev/null +++ b/Aaru.Decryption/Aaru.Decryption.csproj.DotSettings @@ -0,0 +1,5 @@ + + True \ No newline at end of file diff --git a/Aaru.Decryption/DVD/CSS.cs b/Aaru.Decryption/DVD/CSS.cs new file mode 100644 index 000000000..34132591f --- /dev/null +++ b/Aaru.Decryption/DVD/CSS.cs @@ -0,0 +1,1037 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CSS.cs +// Author(s) : Rebecca Wallander +// +// --[ Description ] ---------------------------------------------------------- +// +// Handles Content Scrambling System crypto functionality. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2020-2024 Rebecca Wallander +// ****************************************************************************/ + +// Based on information gathered from: +// ISO/IEC13818-1 Second Edition +// Mt. Fuji Commands for Multimedia Devices +// https://www.cs.cmu.edu/~dst/DeCSS/Kesden/ +// http://groups.csail.mit.edu/mac/users/hal/css/css.html +// http://www.staroceans.org/e-book/css/css_auth.html +// libdvdcpxm (https://offog.org/git/dvdaexplorer/src/libdvdcpxm/) +// libdvdcss (https://www.videolan.org/developers/libdvdcss.html) + +using System; +using System.Collections.Generic; +using System.Linq; +using Aaru.CommonTypes; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.CommonTypes.Structs; +using Aaru.Decoders.DVD; + +namespace Aaru.Decryption.DVD; + +public class CSS +{ + static readonly byte[,] _playerKeys = + { + { + 0x01, 0xaf, 0xe3, 0x12, 0x80 + }, + { + 0x12, 0x11, 0xca, 0x04, 0x3b + }, + { + 0x14, 0x0c, 0x9e, 0xd0, 0x09 + }, + { + 0x14, 0x71, 0x35, 0xba, 0xe2 + }, + { + 0x1a, 0xa4, 0x33, 0x21, 0xa6 + }, + { + 0x26, 0xec, 0xc4, 0xa7, 0x4e + }, + { + 0x2c, 0xb2, 0xc1, 0x09, 0xee + }, + { + 0x2f, 0x25, 0x9e, 0x96, 0xdd + }, + { + 0x33, 0x2f, 0x49, 0x6c, 0xe0 + }, + { + 0x35, 0x5b, 0xc1, 0x31, 0x0f + }, + { + 0x36, 0x67, 0xb2, 0xe3, 0x85 + }, + { + 0x39, 0x3d, 0xf1, 0xf1, 0xbd + }, + { + 0x3b, 0x31, 0x34, 0x0d, 0x91 + }, + { + 0x45, 0xed, 0x28, 0xeb, 0xd3 + }, + { + 0x48, 0xb7, 0x6c, 0xce, 0x69 + }, + { + 0x4b, 0x65, 0x0d, 0xc1, 0xee + }, + { + 0x4c, 0xbb, 0xf5, 0x5b, 0x23 + }, + { + 0x51, 0x67, 0x67, 0xc5, 0xe0 + }, + { + 0x53, 0x94, 0xe1, 0x75, 0xbf + }, + { + 0x57, 0x2c, 0x8b, 0x31, 0xae + }, + { + 0x63, 0xdb, 0x4c, 0x5b, 0x4a + }, + { + 0x7b, 0x1e, 0x5e, 0x2b, 0x57 + }, + { + 0x85, 0xf3, 0x85, 0xa0, 0xe0 + }, + { + 0xab, 0x1e, 0xe7, 0x7b, 0x72 + }, + { + 0xab, 0x36, 0xe3, 0xeb, 0x76 + }, + { + 0xb1, 0xb8, 0xf9, 0x38, 0x03 + }, + { + 0xb8, 0x5d, 0xd8, 0x53, 0xbd + }, + { + 0xbf, 0x92, 0xc3, 0xb0, 0xe2 + }, + { + 0xcf, 0x1a, 0xb2, 0xf8, 0x0a + }, + { + 0xec, 0xa0, 0xcf, 0xb3, 0xff + }, + { + 0xfc, 0x95, 0xa9, 0x87, 0x35 + } + }; + + static readonly byte[] _cssTable1 = + [ + 0x33, 0x73, 0x3b, 0x26, 0x63, 0x23, 0x6b, 0x76, 0x3e, 0x7e, 0x36, 0x2b, 0x6e, 0x2e, 0x66, 0x7b, 0xd3, 0x93, + 0xdb, 0x06, 0x43, 0x03, 0x4b, 0x96, 0xde, 0x9e, 0xd6, 0x0b, 0x4e, 0x0e, 0x46, 0x9b, 0x57, 0x17, 0x5f, 0x82, + 0xc7, 0x87, 0xcf, 0x12, 0x5a, 0x1a, 0x52, 0x8f, 0xca, 0x8a, 0xc2, 0x1f, 0xd9, 0x99, 0xd1, 0x00, 0x49, 0x09, + 0x41, 0x90, 0xd8, 0x98, 0xd0, 0x01, 0x48, 0x08, 0x40, 0x91, 0x3d, 0x7d, 0x35, 0x24, 0x6d, 0x2d, 0x65, 0x74, + 0x3c, 0x7c, 0x34, 0x25, 0x6c, 0x2c, 0x64, 0x75, 0xdd, 0x9d, 0xd5, 0x04, 0x4d, 0x0d, 0x45, 0x94, 0xdc, 0x9c, + 0xd4, 0x05, 0x4c, 0x0c, 0x44, 0x95, 0x59, 0x19, 0x51, 0x80, 0xc9, 0x89, 0xc1, 0x10, 0x58, 0x18, 0x50, 0x81, + 0xc8, 0x88, 0xc0, 0x11, 0xd7, 0x97, 0xdf, 0x02, 0x47, 0x07, 0x4f, 0x92, 0xda, 0x9a, 0xd2, 0x0f, 0x4a, 0x0a, + 0x42, 0x9f, 0x53, 0x13, 0x5b, 0x86, 0xc3, 0x83, 0xcb, 0x16, 0x5e, 0x1e, 0x56, 0x8b, 0xce, 0x8e, 0xc6, 0x1b, + 0xb3, 0xf3, 0xbb, 0xa6, 0xe3, 0xa3, 0xeb, 0xf6, 0xbe, 0xfe, 0xb6, 0xab, 0xee, 0xae, 0xe6, 0xfb, 0x37, 0x77, + 0x3f, 0x22, 0x67, 0x27, 0x6f, 0x72, 0x3a, 0x7a, 0x32, 0x2f, 0x6a, 0x2a, 0x62, 0x7f, 0xb9, 0xf9, 0xb1, 0xa0, + 0xe9, 0xa9, 0xe1, 0xf0, 0xb8, 0xf8, 0xb0, 0xa1, 0xe8, 0xa8, 0xe0, 0xf1, 0x5d, 0x1d, 0x55, 0x84, 0xcd, 0x8d, + 0xc5, 0x14, 0x5c, 0x1c, 0x54, 0x85, 0xcc, 0x8c, 0xc4, 0x15, 0xbd, 0xfd, 0xb5, 0xa4, 0xed, 0xad, 0xe5, 0xf4, + 0xbc, 0xfc, 0xb4, 0xa5, 0xec, 0xac, 0xe4, 0xf5, 0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70, 0x38, 0x78, + 0x30, 0x21, 0x68, 0x28, 0x60, 0x71, 0xb7, 0xf7, 0xbf, 0xa2, 0xe7, 0xa7, 0xef, 0xf2, 0xba, 0xfa, 0xb2, 0xaf, + 0xea, 0xaa, 0xe2, 0xff + ]; + + static readonly byte[] _cssTable2 = + [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x12, 0x13, + 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x24, 0x25, 0x26, 0x27, + 0x20, 0x21, 0x22, 0x23, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, + 0x30, 0x31, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x49, 0x48, 0x4b, 0x4a, 0x4d, 0x4c, 0x4f, 0x4e, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x5b, 0x5a, 0x59, 0x58, 0x5f, 0x5e, 0x5d, 0x5c, 0x52, 0x53, + 0x50, 0x51, 0x56, 0x57, 0x54, 0x55, 0x6d, 0x6c, 0x6f, 0x6e, 0x69, 0x68, 0x6b, 0x6a, 0x64, 0x65, 0x66, 0x67, + 0x60, 0x61, 0x62, 0x63, 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0x76, 0x77, 0x74, 0x75, 0x72, 0x73, + 0x70, 0x71, 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0x9b, 0x9a, 0x99, 0x98, 0x9f, 0x9e, 0x9d, 0x9c, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x89, 0x88, 0x8b, 0x8a, 0x8d, 0x8c, 0x8f, 0x8e, 0xb6, 0xb7, + 0xb4, 0xb5, 0xb2, 0xb3, 0xb0, 0xb1, 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa0, 0xa1, 0xa2, 0xa3, 0xad, 0xac, 0xaf, 0xae, 0xa9, 0xa8, 0xab, 0xaa, 0xdb, 0xda, 0xd9, 0xd8, 0xdf, 0xde, + 0xdd, 0xdc, 0xd2, 0xd3, 0xd0, 0xd1, 0xd6, 0xd7, 0xd4, 0xd5, 0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf6, 0xf7, + 0xf4, 0xf5, 0xf2, 0xf3, 0xf0, 0xf1, 0xed, 0xec, 0xef, 0xee, 0xe9, 0xe8, 0xeb, 0xea, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe0, 0xe1, 0xe2, 0xe3 + ]; + + static readonly byte[] _cssTable3 = + [ + 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, + 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, + 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, + 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, + 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, + 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, + 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, + 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, + 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, + 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, + 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, + 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, + 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, + 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, + 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, + 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, + 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, + 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, + 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, + 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, + 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, + 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, + 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, + 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, + 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, + 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, + 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, + 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff, + 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff + ]; + + static readonly byte[] _cssTable4 = + [ + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, + 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, + 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, + 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, + 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, + 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, + 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, + 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, + 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, + 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, + 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, + 0x3f, 0xbf, 0x7f, 0xff + ]; + + static readonly byte[] _cssTable5 = + [ + 0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f, 0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0x0f, 0xf7, 0x77, + 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17, 0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x07, 0xfb, 0x7b, 0xbb, 0x3b, + 0xdb, 0x5b, 0x9b, 0x1b, 0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0x0b, 0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, + 0x93, 0x13, 0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x03, 0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d, + 0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0x0d, 0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15, 0xe5, 0x65, + 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x05, 0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19, 0xe9, 0x69, 0xa9, 0x29, + 0xc9, 0x49, 0x89, 0x09, 0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11, 0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, + 0x81, 0x01, 0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e, 0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0x0e, + 0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16, 0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x06, 0xfa, 0x7a, + 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a, 0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0x0a, 0xf2, 0x72, 0xb2, 0x32, + 0xd2, 0x52, 0x92, 0x12, 0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x02, 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, + 0x9c, 0x1c, 0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0x0c, 0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14, + 0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x04, 0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18, 0xe8, 0x68, + 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x08, 0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10, 0xe0, 0x60, 0xa0, 0x20, + 0xc0, 0x40, 0x80, 0x00 + ]; + + static readonly byte[] _encryptTable0 = + [ + 0xB7, 0xF4, 0x82, 0x57, 0xDA, 0x4D, 0xDB, 0xE2, 0x2F, 0x52, 0x1A, 0xA8, 0x68, 0x5A, 0x8A, 0xFF, 0xFB, 0x0E, + 0x6D, 0x35, 0xF7, 0x5C, 0x76, 0x12, 0xCE, 0x25, 0x79, 0x29, 0x39, 0x62, 0x08, 0x24, 0xA5, 0x85, 0x7B, 0x56, + 0x01, 0x23, 0x68, 0xCF, 0x0A, 0xE2, 0x5A, 0xED, 0x3D, 0x59, 0xB0, 0xA9, 0xB0, 0x2C, 0xF2, 0xB8, 0xEF, 0x32, + 0xA9, 0x40, 0x80, 0x71, 0xAF, 0x1E, 0xDE, 0x8F, 0x58, 0x88, 0xB8, 0x3A, 0xD0, 0xFC, 0xC4, 0x1E, 0xB5, 0xA0, + 0xBB, 0x3B, 0x0F, 0x01, 0x7E, 0x1F, 0x9F, 0xD9, 0xAA, 0xB8, 0x3D, 0x9D, 0x74, 0x1E, 0x25, 0xDB, 0x37, 0x56, + 0x8F, 0x16, 0xBA, 0x49, 0x2B, 0xAC, 0xD0, 0xBD, 0x95, 0x20, 0xBE, 0x7A, 0x28, 0xD0, 0x51, 0x64, 0x63, 0x1C, + 0x7F, 0x66, 0x10, 0xBB, 0xC4, 0x56, 0x1A, 0x04, 0x6E, 0x0A, 0xEC, 0x9C, 0xD6, 0xE8, 0x9A, 0x7A, 0xCF, 0x8C, + 0xDB, 0xB1, 0xEF, 0x71, 0xDE, 0x31, 0xFF, 0x54, 0x3E, 0x5E, 0x07, 0x69, 0x96, 0xB0, 0xCF, 0xDD, 0x9E, 0x47, + 0xC7, 0x96, 0x8F, 0xE4, 0x2B, 0x59, 0xC6, 0xEE, 0xB9, 0x86, 0x9A, 0x64, 0x84, 0x72, 0xE2, 0x5B, 0xA2, 0x96, + 0x58, 0x99, 0x50, 0x03, 0xF5, 0x38, 0x4D, 0x02, 0x7D, 0xE7, 0x7D, 0x75, 0xA7, 0xB8, 0x67, 0x87, 0x84, 0x3F, + 0x1D, 0x11, 0xE5, 0xFC, 0x1E, 0xD3, 0x83, 0x16, 0xA5, 0x29, 0xF6, 0xC7, 0x15, 0x61, 0x29, 0x1A, 0x43, 0x4F, + 0x9B, 0xAF, 0xC5, 0x87, 0x34, 0x6C, 0x0F, 0x3B, 0xA8, 0x1D, 0x45, 0x58, 0x25, 0xDC, 0xA8, 0xA3, 0x3B, 0xD1, + 0x79, 0x1B, 0x48, 0xF2, 0xE9, 0x93, 0x1F, 0xFC, 0xDB, 0x2A, 0x90, 0xA9, 0x8A, 0x3D, 0x39, 0x18, 0xA3, 0x8E, + 0x58, 0x6C, 0xE0, 0x12, 0xBB, 0x25, 0xCD, 0x71, 0x22, 0xA2, 0x64, 0xC6, 0xE7, 0xFB, 0xAD, 0x94, 0x77, 0x04, + 0x9A, 0x39, 0xCF, 0x7C + ]; + + static readonly byte[] _encryptTable1 = + [ + 0x8C, 0x47, 0xB0, 0xE1, 0xEB, 0xFC, 0xEB, 0x56, 0x10, 0xE5, 0x2C, 0x1A, 0x5D, 0xEF, 0xBE, 0x4F, 0x08, 0x75, + 0x97, 0x4B, 0x0E, 0x25, 0x8E, 0x6E, 0x39, 0x5A, 0x87, 0x53, 0xC4, 0x1F, 0xF4, 0x5C, 0x4E, 0xE6, 0x99, 0x30, + 0xE0, 0x42, 0x88, 0xAB, 0xE5, 0x85, 0xBC, 0x8F, 0xD8, 0x3C, 0x54, 0xC9, 0x53, 0x47, 0x18, 0xD6, 0x06, 0x5B, + 0x41, 0x2C, 0x67, 0x1E, 0x41, 0x74, 0x33, 0xE2, 0xB4, 0xE0, 0x23, 0x29, 0x42, 0xEA, 0x55, 0x0F, 0x25, 0xB4, + 0x24, 0x2C, 0x99, 0x13, 0xEB, 0x0A, 0x0B, 0xC9, 0xF9, 0x63, 0x67, 0x43, 0x2D, 0xC7, 0x7D, 0x07, 0x60, 0x89, + 0xD1, 0xCC, 0xE7, 0x94, 0x77, 0x74, 0x9B, 0x7E, 0xD7, 0xE6, 0xFF, 0xBB, 0x68, 0x14, 0x1E, 0xA3, 0x25, 0xDE, + 0x3A, 0xA3, 0x54, 0x7B, 0x87, 0x9D, 0x50, 0xCA, 0x27, 0xC3, 0xA4, 0x50, 0x91, 0x27, 0xD4, 0xB0, 0x82, 0x41, + 0x97, 0x79, 0x94, 0x82, 0xAC, 0xC7, 0x8E, 0xA5, 0x4E, 0xAA, 0x78, 0x9E, 0xE0, 0x42, 0xBA, 0x28, 0xEA, 0xB7, + 0x74, 0xAD, 0x35, 0xDA, 0x92, 0x60, 0x7E, 0xD2, 0x0E, 0xB9, 0x24, 0x5E, 0x39, 0x4F, 0x5E, 0x63, 0x09, 0xB5, + 0xFA, 0xBF, 0xF1, 0x22, 0x55, 0x1C, 0xE2, 0x25, 0xDB, 0xC5, 0xD8, 0x50, 0x03, 0x98, 0xC4, 0xAC, 0x2E, 0x11, + 0xB4, 0x38, 0x4D, 0xD0, 0xB9, 0xFC, 0x2D, 0x3C, 0x08, 0x04, 0x5A, 0xEF, 0xCE, 0x32, 0xFB, 0x4C, 0x92, 0x1E, + 0x4B, 0xFB, 0x1A, 0xD0, 0xE2, 0x3E, 0xDA, 0x6E, 0x7C, 0x4D, 0x56, 0xC3, 0x3F, 0x42, 0xB1, 0x3A, 0x23, 0x4D, + 0x6E, 0x84, 0x56, 0x68, 0xF4, 0x0E, 0x03, 0x64, 0xD0, 0xA9, 0x92, 0x2F, 0x8B, 0xBC, 0x39, 0x9C, 0xAC, 0x09, + 0x5E, 0xEE, 0xE5, 0x97, 0xBF, 0xA5, 0xCE, 0xFA, 0x28, 0x2C, 0x6D, 0x4F, 0xEF, 0x77, 0xAA, 0x1B, 0x79, 0x8E, + 0x97, 0xB4, 0xC3, 0xF4 + ]; + + static readonly byte[] _encryptTable2 = + [ + 0xB7, 0x75, 0x81, 0xD5, 0xDC, 0xCA, 0xDE, 0x66, 0x23, 0xDF, 0x15, 0x26, 0x62, 0xD1, 0x83, 0x77, 0xE3, 0x97, + 0x76, 0xAF, 0xE9, 0xC3, 0x6B, 0x8E, 0xDA, 0xB0, 0x6E, 0xBF, 0x2B, 0xF1, 0x19, 0xB4, 0x95, 0x34, 0x48, 0xE4, + 0x37, 0x94, 0x5D, 0x7B, 0x36, 0x5F, 0x65, 0x53, 0x07, 0xE2, 0x89, 0x11, 0x98, 0x85, 0xD9, 0x12, 0xC1, 0x9D, + 0x84, 0xEC, 0xA4, 0xD4, 0x88, 0xB8, 0xFC, 0x2C, 0x79, 0x28, 0xD8, 0xDB, 0xB3, 0x1E, 0xA2, 0xF9, 0xD0, 0x44, + 0xD7, 0xD6, 0x60, 0xEF, 0x14, 0xF4, 0xF6, 0x31, 0xD2, 0x41, 0x46, 0x67, 0x0A, 0xE1, 0x58, 0x27, 0x43, 0xA3, + 0xF8, 0xE0, 0xC8, 0xBA, 0x5A, 0x5C, 0x80, 0x6C, 0xC6, 0xF2, 0xE8, 0xAD, 0x7D, 0x04, 0x0D, 0xB9, 0x3C, 0xC2, + 0x25, 0xBD, 0x49, 0x63, 0x8C, 0x9F, 0x51, 0xCE, 0x20, 0xC5, 0xA1, 0x50, 0x92, 0x2D, 0xDD, 0xBC, 0x8D, 0x4F, + 0x9A, 0x71, 0x2F, 0x30, 0x1D, 0x73, 0x39, 0x13, 0xFB, 0x1A, 0xCB, 0x24, 0x59, 0xFE, 0x05, 0x96, 0x57, 0x0F, + 0x1F, 0xCF, 0x54, 0xBE, 0xF5, 0x06, 0x1B, 0xB2, 0x6D, 0xD3, 0x4D, 0x32, 0x56, 0x21, 0x33, 0x0B, 0x52, 0xE7, + 0xAB, 0xEB, 0xA6, 0x74, 0x00, 0x4C, 0xB1, 0x7F, 0x82, 0x99, 0x87, 0x0E, 0x5E, 0xC0, 0x8F, 0xEE, 0x6F, 0x55, + 0xF3, 0x7E, 0x08, 0x90, 0xFA, 0xB6, 0x64, 0x70, 0x47, 0x4A, 0x17, 0xA7, 0xB5, 0x40, 0x8A, 0x38, 0xE5, 0x68, + 0x3E, 0x8B, 0x69, 0xAA, 0x9B, 0x42, 0xA5, 0x10, 0x01, 0x35, 0xFD, 0x61, 0x9E, 0xE6, 0x16, 0x9C, 0x86, 0xED, + 0xCD, 0x2E, 0xFF, 0xC4, 0x5B, 0xA0, 0xAE, 0xCC, 0x4B, 0x3B, 0x03, 0xBB, 0x1C, 0x2A, 0xAC, 0x0C, 0x3F, 0x93, + 0xC7, 0x72, 0x7A, 0x09, 0x22, 0x3D, 0x45, 0x78, 0xA9, 0xA8, 0xEA, 0xC9, 0x6A, 0xF7, 0x29, 0x91, 0xF0, 0x02, + 0x18, 0x3A, 0x4E, 0x7C + ]; + + static readonly byte[] _encryptTable3 = + [ + 0x73, 0x51, 0x95, 0xE1, 0x12, 0xE4, 0xC0, 0x58, 0xEE, 0xF2, 0x08, 0x1B, 0xA9, 0xFA, 0x98, 0x4C, 0xA7, 0x33, + 0xE2, 0x1B, 0xA7, 0x6D, 0xF5, 0x30, 0x97, 0x1D, 0xF3, 0x02, 0x60, 0x5A, 0x82, 0x0F, 0x91, 0xD0, 0x9C, 0x10, + 0x39, 0x7A, 0x83, 0x85, 0x3B, 0xB2, 0xB8, 0xAE, 0x0C, 0x09, 0x52, 0xEA, 0x1C, 0xE1, 0x8D, 0x66, 0x4F, 0xF3, + 0xDA, 0x92, 0x29, 0xB9, 0xD5, 0xC5, 0x77, 0x47, 0x22, 0x53, 0x14, 0xF7, 0xAF, 0x22, 0x64, 0xDF, 0xC6, 0x72, + 0x12, 0xF3, 0x75, 0xDA, 0xD7, 0xD7, 0xE5, 0x02, 0x9E, 0xED, 0xDA, 0xDB, 0x4C, 0x47, 0xCE, 0x91, 0x06, 0x06, + 0x6D, 0x55, 0x8B, 0x19, 0xC9, 0xEF, 0x8C, 0x80, 0x1A, 0x0E, 0xEE, 0x4B, 0xAB, 0xF2, 0x08, 0x5C, 0xE9, 0x37, + 0x26, 0x5E, 0x9A, 0x90, 0x00, 0xF3, 0x0D, 0xB2, 0xA6, 0xA3, 0xF7, 0x26, 0x17, 0x48, 0x88, 0xC9, 0x0E, 0x2C, + 0xC9, 0x02, 0xE7, 0x18, 0x05, 0x4B, 0xF3, 0x39, 0xE1, 0x20, 0x02, 0x0D, 0x40, 0xC7, 0xCA, 0xB9, 0x48, 0x30, + 0x57, 0x67, 0xCC, 0x06, 0xBF, 0xAC, 0x81, 0x08, 0x24, 0x7A, 0xD4, 0x8B, 0x19, 0x8E, 0xAC, 0xB4, 0x5A, 0x0F, + 0x73, 0x13, 0xAC, 0x9E, 0xDA, 0xB6, 0xB8, 0x96, 0x5B, 0x60, 0x88, 0xE1, 0x81, 0x3F, 0x07, 0x86, 0x37, 0x2D, + 0x79, 0x14, 0x52, 0xEA, 0x73, 0xDF, 0x3D, 0x09, 0xC8, 0x25, 0x48, 0xD8, 0x75, 0x60, 0x9A, 0x08, 0x27, 0x4A, + 0x2C, 0xB9, 0xA8, 0x8B, 0x8A, 0x73, 0x62, 0x37, 0x16, 0x02, 0xBD, 0xC1, 0x0E, 0x56, 0x54, 0x3E, 0x14, 0x5F, + 0x8C, 0x8F, 0x6E, 0x75, 0x1C, 0x07, 0x39, 0x7B, 0x4B, 0xDB, 0xD3, 0x4B, 0x1E, 0xC8, 0x7E, 0xFE, 0x3E, 0x72, + 0x16, 0x83, 0x7D, 0xEE, 0xF5, 0xCA, 0xC5, 0x18, 0xF9, 0xD8, 0x68, 0xAB, 0x38, 0x85, 0xA8, 0xF0, 0xA1, 0x73, + 0x9F, 0x5D, 0x19, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x72, 0x39, 0x25, 0x67, 0x26, + 0x6D, 0x71, 0x36, 0x77, 0x3C, 0x20, 0x62, 0x23, 0x68, 0x74, 0xC3, 0x82, 0xC9, 0x15, 0x57, 0x16, 0x5D, 0x81 + ]; + + static readonly byte[,] _permutationChallenge = + { + { + 1, 3, 0, 7, 5, 2, 9, 6, 4, 8 + }, + { + 6, 1, 9, 3, 8, 5, 7, 4, 0, 2 + }, + { + 4, 0, 3, 5, 7, 2, 8, 6, 1, 9 + } + }; + + static readonly byte[,] _permutationVariant = + { + { + 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d, 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d, 0x02, 0x00, + 0x06, 0x04, 0x03, 0x01, 0x07, 0x05, 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 + }, + { + 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e, 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c, 0x13, 0x1b, + 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f, 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d + } + }; + + static readonly byte[] _variants = + [ + 0xB7, 0x74, 0x85, 0xD0, 0xCC, 0xDB, 0xCA, 0x73, 0x03, 0xFE, 0x31, 0x03, 0x52, 0xE0, 0xB7, 0x42, 0x63, 0x16, + 0xF2, 0x2A, 0x79, 0x52, 0xFF, 0x1B, 0x7A, 0x11, 0xCA, 0x1A, 0x9B, 0x40, 0xAD, 0x01 + ]; + + static readonly byte[] _secret = [0x55, 0xD6, 0xC4, 0xC5, 0x28]; + + /// + /// The disc key returned by the logical unit is encoded with the bus key to prevent man-in-the-middle attacks. + /// This method returns a structure with the decoded key included. + /// + /// The encoded key from the logical unit. + /// The bus key from the logical unit. + /// A DiscKey struct with the decoded key. + public static CSS_CPRM.DiscKey? DecodeDiscKey(byte[] response, byte[] busKey) + { + if(response.Length != 2052 || busKey.Length != 5) return null; + + byte[] key = response.Skip(4).Take(2048).ToArray(); + + for(uint i = 0; i < key.Length; i++) key[i] ^= busKey[4 - i % busKey.Length]; + + return new CSS_CPRM.DiscKey + { + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + Key = key + }; + } + + /// + /// The title key returned by the logical unit is encoded with the bus key to prevent man-in-the-middle attacks. + /// This method returns a structure with the decoded key included. + /// + /// The encoded key from the logical unit. + /// The bus key from the logical unit. + /// A TitleKey struct with the decoded key. + public static CSS_CPRM.TitleKey? DecodeTitleKey(byte[] response, byte[] busKey) + { + if(response.Length != 12 || busKey.Length != 5) return null; + + byte[] key = response.Skip(5).Take(5).ToArray(); + + for(uint i = 0; i < key.Length; i++) key[i] ^= busKey[4 - i % busKey.Length]; + + return new CSS_CPRM.TitleKey + { + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + CMI = response[4], + Key = key, + Reserved3 = response[10], + Reserved4 = response[11] + }; + } + + /// Takes a challenge and a variant and encrypts it according to the key type. + /// The type of key to encrypt. + /// + /// The challenge sent to the logical unit. + /// The encrypted key. + /// The encrypted key. + public static void EncryptKey(DvdCssKeyType keyType, uint variant, byte[] challenge, out byte[] key) + { + var bits = new byte[30]; + var scratch = new byte[10]; + byte index = sizeof(byte) * 30; + var temp1 = new byte[5]; + var temp2 = new byte[5]; + byte carry = 0; + key = new byte[5]; + + for(var i = 9; i >= 0; --i) scratch[i] = challenge[_permutationChallenge[(uint)keyType, i]]; + + var cssVariant = (byte)(keyType == 0 ? variant : _permutationVariant[(uint)keyType - 1, variant]); + + for(var i = 5; --i >= 0;) temp1[i] = (byte)(scratch[5 + i] ^ _secret[i] ^ _encryptTable2[i]); + + var lfsr0 = (uint)(temp1[0] << 17 | temp1[1] << 9 | (temp1[2] & ~7) << 1 | 8 | temp1[2] & 7); + var lfsr1 = (uint)(temp1[3] << 9 | 0x100 | temp1[4]); + + do + { + byte val = 0; + + for(var bit = 0; bit < 8; ++bit) + { + var oLfsr0 = (byte)((lfsr0 >> 24 ^ lfsr0 >> 21 ^ lfsr0 >> 20 ^ lfsr0 >> 12) & 1); + lfsr0 = lfsr0 << 1 | oLfsr0; + + var oLfsr1 = (byte)((lfsr1 >> 16 ^ lfsr1 >> 2) & 1); + lfsr1 = lfsr1 << 1 | oLfsr1; + + var combined = (byte)(Convert.ToByte(oLfsr1 == 0) + carry + Convert.ToByte(oLfsr0 == 0)); + carry = (byte)(combined >> 1 & 1); + val |= (byte)((combined & 1) << bit); + } + + bits[--index] = val; + } while(index > 0); + + var cse = (byte)(_variants[cssVariant] ^ _encryptTable2[cssVariant]); + var term = 0; + + for(var i = 5; --i >= 0; term = scratch[i]) + { + index = (byte)(bits[25 + i] ^ scratch[i]); + index = (byte)(_encryptTable1[index] ^ ~_encryptTable2[index] ^ cse); + + temp1[i] = (byte)(_encryptTable2[index] ^ _encryptTable3[index] ^ term); + } + + temp1[4] ^= temp1[0]; + term = 0; + + for(var i = 5; --i >= 0; term = temp1[i]) + { + index = (byte)(bits[20 + i] ^ temp1[i]); + index = (byte)(_encryptTable1[index] ^ ~_encryptTable2[index] ^ cse); + + temp2[i] = (byte)(_encryptTable2[index] ^ _encryptTable3[index] ^ term); + } + + temp2[4] ^= temp2[0]; + term = 0; + + for(var i = 5; --i >= 0; term = temp2[i]) + { + index = (byte)(bits[15 + i] ^ temp2[i]); + index = (byte)(_encryptTable1[index] ^ ~_encryptTable2[index] ^ cse); + index = (byte)(_encryptTable2[index] ^ _encryptTable3[index] ^ term); + + temp1[i] = (byte)(_encryptTable0[index] ^ _encryptTable2[index]); + } + + temp1[4] ^= temp1[0]; + term = 0; + + for(var i = 5; --i >= 0; term = temp1[i]) + { + index = (byte)(bits[10 + i] ^ temp1[i]); + index = (byte)(_encryptTable1[index] ^ ~_encryptTable2[index] ^ cse); + index = (byte)(_encryptTable2[index] ^ _encryptTable3[index] ^ term); + + temp2[i] = (byte)(_encryptTable0[index] ^ _encryptTable2[index]); + } + + temp2[4] ^= temp2[0]; + term = 0; + + for(var i = 5; --i >= 0; term = temp2[i]) + { + index = (byte)(bits[5 + i] ^ temp2[i]); + index = (byte)(_encryptTable1[index] ^ ~_encryptTable2[index] ^ cse); + + temp1[i] = (byte)(_encryptTable2[index] ^ _encryptTable3[index] ^ term); + } + + temp1[4] ^= temp1[0]; + term = 0; + + for(var i = 5; --i >= 0; term = temp1[i]) + { + index = (byte)(bits[i] ^ temp1[i]); + index = (byte)(_encryptTable1[index] ^ ~_encryptTable2[index] ^ cse); + + key[i] = (byte)(_encryptTable2[index] ^ _encryptTable3[index] ^ term); + } + } + + /// Takes an encrypted key and its crypto and returns the key decrypted. + /// For disc keys, invert is 0x00. For title keys, invert if 0xff. + /// The key used to encrypt the data. + /// The encrypted data. + /// The decrypted data. + static void DecryptKey(byte invert, byte[] cryptoKey, byte[] encryptedKey, out byte[] decryptedKey) + { + decryptedKey = new byte[5]; + var k = new byte[5]; + + var lfsr1Lo = (uint)(cryptoKey[0] | 0x100); + uint lfsr1Hi = cryptoKey[1]; + + var lfsr0 = (uint)((cryptoKey[4] << 17 | cryptoKey[3] << 9 | cryptoKey[2] << 1) + 8 - (cryptoKey[2] & 7)); + + lfsr0 = (uint)(_cssTable4[lfsr0 & 0xff] << 24 | + _cssTable4[lfsr0 >> 8 & 0xff] << 16 | + _cssTable4[lfsr0 >> 16 & 0xff] << 8 | + _cssTable4[lfsr0 >> 24 & 0xff]); + + uint combined = 0; + + for(uint i = 0; i < 5; i++) + { + var oLfsr1 = (byte)(_cssTable2[lfsr1Hi] ^ _cssTable3[lfsr1Lo]); + lfsr1Hi = lfsr1Lo >> 1; + lfsr1Lo = (lfsr1Lo & 1) << 8 ^ oLfsr1; + oLfsr1 = _cssTable4[oLfsr1]; + var oLfsr0 = (byte)((((lfsr0 >> 8 ^ lfsr0) >> 1 ^ lfsr0) >> 3 ^ lfsr0) >> 7); + lfsr0 = lfsr0 >> 8 | (uint)oLfsr0 << 24; + combined += (uint)((oLfsr0 ^ invert) + oLfsr1); + k[i] = (byte)(combined & 0xff); + combined >>= 8; + } + + decryptedKey[4] = (byte)(k[4] ^ _cssTable1[encryptedKey[4]] ^ encryptedKey[3]); + decryptedKey[3] = (byte)(k[3] ^ _cssTable1[encryptedKey[3]] ^ encryptedKey[2]); + decryptedKey[2] = (byte)(k[2] ^ _cssTable1[encryptedKey[2]] ^ encryptedKey[1]); + decryptedKey[1] = (byte)(k[1] ^ _cssTable1[encryptedKey[1]] ^ encryptedKey[0]); + decryptedKey[0] = (byte)(k[0] ^ _cssTable1[encryptedKey[0]] ^ decryptedKey[4]); + + decryptedKey[4] = (byte)(k[4] ^ _cssTable1[decryptedKey[4]] ^ decryptedKey[3]); + decryptedKey[3] = (byte)(k[3] ^ _cssTable1[decryptedKey[3]] ^ decryptedKey[2]); + decryptedKey[2] = (byte)(k[2] ^ _cssTable1[decryptedKey[2]] ^ decryptedKey[1]); + decryptedKey[1] = (byte)(k[1] ^ _cssTable1[decryptedKey[1]] ^ decryptedKey[0]); + decryptedKey[0] = (byte)(k[0] ^ _cssTable1[decryptedKey[0]]); + } + + public static void DecryptTitleKey(byte[] cryptoKey, byte[] encryptedKey, out byte[] decryptedKey) => + DecryptKey(0xff, cryptoKey, encryptedKey, out decryptedKey); + + /// Takes an bytearray of encrypted keys, decrypts them and returns the correctly decrypted key. + /// Encrypted keys to try to decrypt. + /// The decrypted key if found. + public static void DecryptDiscKey(byte[] encryptedKeys, out byte[]? decryptedKey) + { + decryptedKey = new byte[5]; + byte[] verificationKey = encryptedKeys.Take(5).ToArray(); + + for(uint n = 0; n < _playerKeys.GetLength(0); n++) + { + byte[] currentPlayerKey = + Enumerable.Range(0, _playerKeys.GetLength(1)).Select(x => _playerKeys[n, x]).ToArray(); + + for(uint i = 1; i < 409; i++) + { + DecryptKey(0, currentPlayerKey, encryptedKeys.Skip(5 * (int)i).Take(5).ToArray(), out decryptedKey); + + // The first key in the structure is the key encrypted with itself, so we can use it to verify + // we found the correct key. + DecryptKey(0, decryptedKey, verificationKey, out byte[] verify); + + if(decryptedKey.SequenceEqual(verify)) return; + } + } + + // No correct key was found. + decryptedKey = null; + } + + /// Takes a sector and a decrypted title key and returns the decrypted sector. + /// Encrypted sector data. + /// The Copyright Management Information. + /// The encryption keys. + /// Number of sectors in sectorData. + /// Size of one sector. + /// The decrypted sector. + public static byte[] DecryptSector(byte[] sectorData, byte[] keyData, byte[]? cmiData, uint blocks = 1, + uint blockSize = 2048) + { + // None of the sectors are encrypted + if(cmiData != null && cmiData.All(static cmi => (cmi & 0x80) >> 7 == 0) || keyData.All(static k => k == 0)) + return sectorData; + + var decryptedBuffer = new byte[sectorData.Length]; + + for(uint i = 0; i < blocks; i++) + { + byte[] currentKey = keyData.Skip((int)(i * 5)).Take(5).ToArray(); + byte[] currentSector = sectorData.Skip((int)(i * blockSize)).Take((int)blockSize).ToArray(); + + if(!IsEncrypted(cmiData?[i], currentKey, currentSector)) + { + Array.Copy(currentSector, 0, decryptedBuffer, (int)(i * blockSize), blockSize); + + continue; + } + + Array.Copy(UnscrambleSector(currentKey, currentSector), + 0, + decryptedBuffer, + (int)(i * blockSize), + blockSize); + } + + return decryptedBuffer; + } + + /// Takes a sector and a decrypted title key and returns the decrypted sector. + /// Encrypted sector data. + /// The Copyright Management Information. + /// The encryption keys. + /// Number of sectors in sectorData. + /// Size of one sector. + /// The decrypted sector. + public static byte[] DecryptSectorLong(byte[] sectorData, byte[] keyData, byte[]? cmiData, uint blocks = 1, + uint blockSize = 2048) + { + // None of the sectors are encrypted + if(cmiData != null && cmiData.All(static cmi => (cmi & 0x80) >> 7 == 0) || keyData.All(static k => k == 0)) + return sectorData; + + var decryptedBuffer = new byte[sectorData.Length]; + + for(uint i = 0; i < blocks; i++) + { + byte[] currentKey = keyData.Skip((int)(i * 5)).Take(5).ToArray(); + byte[] currentPrefix = sectorData.Skip((int)(i * 2064)).Take(12).ToArray(); + byte[] currentSuffix = sectorData.Skip((int)(2060 + i * 2064)).Take(4).ToArray(); + byte[] currentSector = sectorData.Skip((int)(12 + i * blockSize + 16 * i)).Take((int)blockSize).ToArray(); + + Array.Copy(currentPrefix, 0, decryptedBuffer, (int)(i * 2064), 12); + Array.Copy(currentSuffix, 0, decryptedBuffer, (int)(2060 + i * 2064), 4); + + if(!IsEncrypted(cmiData?[i], currentKey, currentSector)) + { + Array.Copy(currentSector, 0, decryptedBuffer, (int)(12 + i * blockSize + 16 * i), blockSize); + + continue; + } + + Array.Copy(UnscrambleSector(currentKey, currentSector), + 0, + decryptedBuffer, + (int)(12 + i * blockSize + 16 * i), + blockSize); + } + + return decryptedBuffer; + } + + /// + /// Unscrambles a DVD sector with a title key. + /// + /// The title key. + /// The scrambled sector. + /// The unscrambled sector. + static byte[] UnscrambleSector(IReadOnlyList key, byte[] sector) + { + long lfsr1Lo = key[0] ^ sector[0x54] | 0x100; + long lfsr1Hi = key[1] ^ sector[0x55]; + + long lfsr0 = (key[2] | key[3] << 8 | key[4] << 16) ^ (sector[0x56] | sector[0x57] << 8 | sector[0x58] << 16); + + long oLfsr1 = lfsr0 & 7; + lfsr0 = lfsr0 * 2 + 8 - oLfsr1; + + long combined = 0; + + for(uint i = 0x80; i < 2048; i++) + { + oLfsr1 = _cssTable2[lfsr1Hi] ^ _cssTable3[lfsr1Lo]; + lfsr1Hi = lfsr1Lo >> 1; + lfsr1Lo = (lfsr1Lo & 1) << 8 ^ oLfsr1; + oLfsr1 = _cssTable5[oLfsr1]; + long oLfsr0 = (((lfsr0 >> 3 ^ lfsr0) >> 1 ^ lfsr0) >> 8 ^ lfsr0) >> 5 & 0xff; + lfsr0 = lfsr0 << 8 | oLfsr0; + oLfsr0 = _cssTable4[oLfsr0]; + combined += oLfsr0 + oLfsr1; + sector[i] = (byte)(_cssTable1[sector[i]] ^ combined & 0xff); + combined >>= 8; + } + + // Since we unscrambled the sector, we need to set the MPEG Packetized Elementary Stream + // scrambling control value to "not scrambled". + sector[20] ^= 1 << 4; + + return sector; + } + + /// + /// Analyzes data to try to figure out if the sector is encrypted, including + /// + /// If the packet is not an MPEG packet + /// If the CMI tells us the sector isn't encrypted + /// If the key is all zeroes + /// If the MPEG Packetized Elementary Stream scrambling control value tells us the packet is not scrambled + /// + /// If if the packet is system_header, padding_stream or private_stream2 (cannot be encrypted according to + /// libdvdcss) + /// + /// + /// + /// The Copyright Management Information. + /// The title key. + /// The sector data. + /// True if encrypted + static bool IsEncrypted(byte? cmi, byte[]? key, IReadOnlyList sector) + { + // Only MPEG packets can be encrypted. + if(!Mpeg.IsMpegPacket(sector)) return false; + + // The CMI tells us the sector is not encrypted. + if(cmi != null && (cmi & 0x80) >> 7 == 0) return false; + + // We have the key but it's all zeroes, so sector is unencrypted. + if(key != null && key.All(static k => k == 0)) return false; + + // These packet types cannot be encrypted + if(sector[17] == (byte)Mpeg.Mpeg2StreamId.SystemHeader || + sector[17] == (byte)Mpeg.Mpeg2StreamId.PaddingStream || + sector[17] == (byte)Mpeg.Mpeg2StreamId.PrivateStream2) + return false; + + // MPEG Packetized Elementary Stream scrambling control value + return (sector[20] & 0x30) >> 4 == 1; + } + + /// Takes an RPC state from the drive and a CMI from a disc and checks if the regions are compatible. + /// The RegionalPlaybackControlState from drive. + /// The LeadInCopyright from disc. + /// true if the regions are compatible, else false + public static bool CheckRegion(CSS_CPRM.RegionalPlaybackControlState rpc, CSS_CPRM.LeadInCopyright cmi) + { + // if disc region is all or none, we cannot do anything but try to read it as is + if(cmi.RegionInformation is 0xFF or 0x00) return true; + + return (rpc.RegionMask & 0x01) == (cmi.RegionInformation & 0x01) && (rpc.RegionMask & 0x01) != 0x01 || + (rpc.RegionMask & 0x02) == (cmi.RegionInformation & 0x02) && (rpc.RegionMask & 0x02) != 0x02 || + (rpc.RegionMask & 0x04) == (cmi.RegionInformation & 0x04) && (rpc.RegionMask & 0x04) != 0x04 || + (rpc.RegionMask & 0x08) == (cmi.RegionInformation & 0x08) && (rpc.RegionMask & 0x08) != 0x08 || + (rpc.RegionMask & 0x10) == (cmi.RegionInformation & 0x10) && (rpc.RegionMask & 0x10) != 0x10 || + (rpc.RegionMask & 0x20) == (cmi.RegionInformation & 0x20) && (rpc.RegionMask & 0x20) != 0x20 || + (rpc.RegionMask & 0x40) == (cmi.RegionInformation & 0x40) && (rpc.RegionMask & 0x40) != 0x40 || + (rpc.RegionMask & 0x80) == (cmi.RegionInformation & 0x80) && (rpc.RegionMask & 0x80) != 0x80; + } + + /// + /// This tries to find a title key for a range of sectors by doing a brute force pattern search developed by + /// Ethan Hawke of DeCSSPlus. CSS encrypted sectors have parts of them that are unencrypted (byte 0x0 - 0x80). + /// We try to find a long pattern of repeated bytes just before the encryption starts. If we assume this + /// pattern continues into the encrypted part, we can force keys until one of them satisfies this condition. + /// + /// The sector to analyze. + /// The key found. + /// true if a key was found. + static bool AttackPattern(byte[] sector, out byte[] key) + { + uint bestPatternLength = 0; + uint bestPattern = 0; + key = new byte[5]; + + for(uint i = 2; i < 0x30; i++) + { + // Find the number of bytes that repeats in cycles. + for(uint j = i + 1; j < 0x80 && sector[0x7F - j % i] == sector[0x7F - j]; j++) + { + if(j <= bestPatternLength) continue; + + bestPatternLength = j; + bestPattern = i; + } + } + + // If we found an adequate pattern. + if(bestPattern <= 0 || bestPatternLength <= 3 || bestPatternLength / bestPattern < 2) return false; + + var offset = (int)(0x80 - bestPatternLength / bestPattern * bestPattern); + + int result = RecoverTitleKey(0, + sector.Skip(0x80).Take(sector.Length - 0x80).ToArray(), + sector.Skip(offset).Take(sector.Length - offset).ToArray(), + sector.Skip(0x54).Take(5).ToArray(), + out key); + + return result >= 0; + } + + /// + /// Takes a guessed plain text and a encrypted bytes and tries to recover the title key + /// from those. Attack developed by Frank Stevenson. + /// + /// Start position. + /// Buffer with encrypted bytes. + /// Buffer with decrypted bytes. + /// This sector's seed values. + /// The title key. + /// Positive values on success. + static int RecoverTitleKey(uint start, byte[] encryptedBytes, byte[] decryptedBytes, byte[] sectorSeed, + out byte[] key) + { + var buffer = new byte[10]; + long iTry; + uint i; + int exit = -1; + key = new byte[5]; + + for(i = 0; i < 10; i++) buffer[i] = (byte)(_cssTable1[encryptedBytes[i]] ^ decryptedBytes[i]); + + for(iTry = start; iTry < 0x10000; iTry++) + { + long lfsr1Lo = iTry >> 8 | 0x100; + long lfsr1Hi = iTry & 0xff; + long lfsr0 = 0; + long combined = 0; + + // Iterate cipher 4 times to reconstruct LFSR2 + long oLfsr1; + long oLfsr0; + + for(i = 0; i < 4; i++) + { + // Advance LFSR1 normally + oLfsr1 = _cssTable2[lfsr1Hi] ^ _cssTable3[lfsr1Lo]; + lfsr1Hi = lfsr1Lo >> 1; + lfsr1Lo = (lfsr1Lo & 1) << 8 ^ oLfsr1; + oLfsr1 = _cssTable5[oLfsr1]; + oLfsr0 = buffer[i]; + + if(combined > 0) oLfsr0 = oLfsr0 + 0xff & 0x0ff; + + if(oLfsr0 < oLfsr1) oLfsr0 += 0x100; + + oLfsr0 -= oLfsr1; + combined += oLfsr0 + oLfsr1; + oLfsr0 = _cssTable4[oLfsr0]; + lfsr0 = lfsr0 << 8 | oLfsr0; + combined >>= 8; + } + + long candidate = lfsr0; + + // Iterate 6 more times to validate candidate key + for(; i < 10; i++) + { + oLfsr1 = _cssTable2[lfsr1Hi] ^ _cssTable3[lfsr1Lo]; + lfsr1Hi = lfsr1Lo >> 1; + lfsr1Lo = (lfsr1Lo & 1) << 8 ^ oLfsr1; + oLfsr1 = _cssTable5[oLfsr1]; + oLfsr0 = (((lfsr0 >> 3 ^ lfsr0) >> 1 ^ lfsr0) >> 8 ^ lfsr0) >> 5 & 0xff; + lfsr0 = lfsr0 << 8 | oLfsr0; + oLfsr0 = _cssTable4[oLfsr0]; + combined += oLfsr0 + oLfsr1; + + if((combined & 0xff) != buffer[i]) break; + + combined >>= 8; + } + + if(i != 10) continue; + + lfsr0 = candidate; + + for(i = 0; i < 4; i++) + { + lfsr1Lo = lfsr0 & 0xff; + lfsr0 >>= 8; + + for(uint j = 0; j < 256; j++) + { + lfsr0 = lfsr0 & 0x1ffff | j << 17; + oLfsr0 = (((lfsr0 >> 3 ^ lfsr0) >> 1 ^ lfsr0) >> 8 ^ lfsr0) >> 5 & 0xff; + + if(oLfsr0 == lfsr1Lo) break; + } + } + + oLfsr1 = (lfsr0 >> 1) - 4; + + for(combined = 0; combined < 8; combined++) + { + if((oLfsr1 + combined) * 2 + 8 - (oLfsr1 + combined & 7) != lfsr0) continue; + + key[0] = (byte)(iTry >> 8); + key[1] = (byte)(iTry & 0xFF); + key[2] = (byte)(oLfsr1 + combined >> 0 & 0xFF); + key[3] = (byte)(oLfsr1 + combined >> 8 & 0xFF); + key[4] = (byte)(oLfsr1 + combined >> 16 & 0xFF); + exit = (int)(iTry + 1); + } + } + + if(exit < 0) return exit; + + key[0] ^= sectorSeed[0]; + key[1] ^= sectorSeed[1]; + key[2] ^= sectorSeed[2]; + key[3] ^= sectorSeed[3]; + key[4] ^= sectorSeed[4]; + + return exit; + } + + /// + /// Tries to find a title key by attacking CSS vulnerabilities. + /// + /// IOpticalMediaImage to find the title key in. + /// Sector index to begin search. + /// Amount of sectors to search before giving up. + /// The title key. + static byte[] FindTitleKey(IOpticalMediaImage input, ulong startSector, ulong sectorsToSearch = 20000) + { + var titleKey = new byte[5]; + + for(ulong i = 0; i < sectorsToSearch; i++) + { + input.ReadSector(startSector + i, out byte[] sector); + + if(!IsEncrypted(null, null, sector)) continue; + + if(AttackPattern(sector, out byte[] key)) return key; + } + + return titleKey; + } + + /// + /// Generates title keys for all sectors in a track. + /// + /// IOpticalMediaImage to generate keys for. + /// List of Partition to analyze. + /// Total number of sectors for track. + /// + /// A byte array with keys for every sector in the track. One key is 5 bytes. + public static byte[] GenerateTitleKeys(IOpticalMediaImage input, List partitions, ulong trackSectors, + IReadOnlyFilesystem fs) + { + var keys = new byte[trackSectors * 5]; + + foreach(Partition partition in partitions) + { + if(fs is null) continue; + + if(!HasVideoTsFolder(input, fs, partition)) continue; + + if(fs.Mount(input, partition, null, null, null) != ErrorNumber.NoError) continue; + + if(fs.OpenDir("VIDEO_TS", out IDirNode node) == ErrorNumber.NoError) + { + while(fs.ReadDir(node, out string entry) == ErrorNumber.NoError && entry is not null) + { + if(!entry.EndsWith(".vob", StringComparison.InvariantCultureIgnoreCase)) continue; + + fs.Stat("VIDEO_TS" + "/" + entry, out FileEntryInfo stat); + + byte[] key = FindTitleKey(input, stat.Inode); + + for(long i = 0; i < stat.Blocks; i++) key.CopyTo(keys, (long)(5 * (stat.Inode + (ulong)i))); + } + + fs.CloseDir(node); + } + + fs.Unmount(); + } + + return keys; + } + + /// + /// DVD video discs always have a VIDEO_TS folder. If it doesn't have one, it's not a DVD video. + /// + /// IOpticalMediaImage to check for VIDEO_TS folder in. + /// IReadOnlyFilesystem to check in. + /// Partition to check in. + /// true if VIDEO_TS folder was found. + static bool HasVideoTsFolder(IOpticalMediaImage input, IReadOnlyFilesystem fs, Partition partition) + { + ErrorNumber error = fs.Mount(input, partition, null, null, null); + + if(error != ErrorNumber.NoError) return false; + + error = fs.Stat("VIDEO_TS", out FileEntryInfo stat); + fs.Unmount(); + + return error == ErrorNumber.NoError && stat.Attributes == FileAttributes.Directory; + } +} \ No newline at end of file diff --git a/Aaru.Decryption/DVD/Dump.cs b/Aaru.Decryption/DVD/Dump.cs new file mode 100644 index 000000000..3c445723c --- /dev/null +++ b/Aaru.Decryption/DVD/Dump.cs @@ -0,0 +1,505 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Dump.cs +// Author(s) : Rebecca Wallander +// +// --[ Description ] ---------------------------------------------------------- +// +// SCSI read commands related to Content Scrambling System. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2020-2024 Rebecca Wallander +// ****************************************************************************/ + +using System; +using System.Linq; +using Aaru.Console; +using Aaru.Decoders.DVD; +using Aaru.Devices; + +namespace Aaru.Decryption.DVD; + +public sealed class Dump(Device dev) +{ + const byte KEY_SIZE = 5; + const byte CHALLENGE_SIZE = 2 * KEY_SIZE; + const string MODULE_NAME = "DVD decryption"; + + public byte Agid { get; private set; } + public byte[] BusKey { get; private set; } = []; + + /// Returns the Authentication Success Flag of the logical unit. + /// true if the command failed and contains the sense buffer. + /// Buffer where the Authentication Success Flag will be stored. + /// Sense buffer. + /// Key class. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadAsf(out byte[] buffer, out byte[] senseBuffer, DvdCssKeyClass keyClass, uint timeout, + out double duration) + { + senseBuffer = new byte[64]; + var cdb = new byte[12]; + buffer = new byte[8]; + + cdb[0] = (byte)ScsiCommands.ReportKey; + cdb[7] = (byte)keyClass; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((byte)CssReportKeyFormat.Asf ^ (Agid & 0x03) << 6); + + dev.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.REPORT_ASF_AGID_1_Sense_2_Last_Error_3_took_0_ms, + duration, + Agid, + sense, + dev.LastError); + + return sense; + } + + /// Returns the Regional Playback Control State of the logical unit. + /// true if the command failed and contains the sense buffer. + /// Buffer where the Regional Playback Control State will be stored. + /// Sense buffer. + /// Key class. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadRpc(out byte[] buffer, out byte[] senseBuffer, DvdCssKeyClass keyClass, uint timeout, + out double duration) + { + senseBuffer = new byte[64]; + var cdb = new byte[12]; + buffer = new byte[8]; + + cdb[0] = (byte)ScsiCommands.ReportKey; + cdb[7] = (byte)keyClass; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((byte)CssReportKeyFormat.RpcState ^ (Agid & 0x03) << 6); + + dev.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.REPORT_ASF_AGID_1_Sense_2_Last_Error_3_took_0_ms, + duration, + Agid, + sense, + dev.LastError); + + return sense; + } + + /// Invalidates an Authentication Grant ID. + /// Buffer where the Regional Playback Control State will be stored. + /// Sense buffer. + /// Key class. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// true if the command failed and contains the sense buffer. + public bool InvalidateAgid(out byte[] buffer, out byte[] senseBuffer, DvdCssKeyClass keyClass, uint timeout, + out double duration) + { + senseBuffer = new byte[64]; + var cdb = new byte[12]; + buffer = []; + + cdb[0] = (byte)ScsiCommands.ReportKey; + cdb[7] = (byte)keyClass; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((byte)CssReportKeyFormat.InvalidateAgid ^ (Agid & 0x03) << 6); + + dev.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.INVALIDATE_AGID_AGID_1_Sense_2_Last_Error_3_took_0_ms, + duration, + Agid, + sense, + dev.LastError); + + return sense; + } + + /// Returns a valid Authentication Grant ID for CSS/CPPM. + /// Buffer where the Regional Playback Control State will be stored. + /// Sense buffer. + /// Key class. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// true if the command failed and contains the sense buffer. + public bool ReportAgidCssCppm(out byte[] buffer, out byte[] senseBuffer, DvdCssKeyClass keyClass, uint timeout, + out double duration) + { + senseBuffer = new byte[64]; + var cdb = new byte[12]; + buffer = new byte[8]; + + cdb[0] = (byte)ScsiCommands.ReportKey; + cdb[7] = (byte)keyClass; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((byte)CssReportKeyFormat.AgidForCssCppm ^ (Agid & 0x03) << 6); + + dev.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.REPORT_AGID_CSS_CPPM_AGID_1_Sense_2_Last_Error_3_took_0_ms, + duration, + Agid, + sense, + dev.LastError); + + return sense; + } + + /// Returns KEY1 from the logical unit. + /// Buffer where the Regional Playback Control State will be stored. + /// Sense buffer. + /// Key class. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// true if the command failed and contains the sense buffer. + public bool ReportKey1(out byte[] buffer, out byte[] senseBuffer, DvdCssKeyClass keyClass, uint timeout, + out double duration) + { + senseBuffer = new byte[64]; + var cdb = new byte[12]; + buffer = new byte[12]; + + cdb[0] = (byte)ScsiCommands.ReportKey; + cdb[7] = (byte)keyClass; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((byte)CssReportKeyFormat.Key1 ^ (Agid & 0x03) << 6); + + dev.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.REPORT_KEY1_AGID_1_Sense_2_Last_Error_3_took_0_ms, + duration, + Agid, + sense, + dev.LastError); + + return sense; + } + + /// Returns the challenge from the logical unit. + /// Buffer where the Regional Playback Control State will be stored. + /// Sense buffer. + /// Key class. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// true if the command failed and contains the sense buffer. + public bool ReportChallenge(out byte[] buffer, out byte[] senseBuffer, DvdCssKeyClass keyClass, uint timeout, + out double duration) + { + senseBuffer = new byte[64]; + var cdb = new byte[12]; + buffer = new byte[16]; + + cdb[0] = (byte)ScsiCommands.ReportKey; + cdb[7] = (byte)keyClass; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((byte)CssReportKeyFormat.ChallengeKey ^ (Agid & 0x03) << 6); + + dev.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.REPORT_CHALLENGE_AGID_1_Sense_2_Last_Error_3_took_0_ms, + duration, + Agid, + sense, + dev.LastError); + + return sense; + } + + /// Send a challenge to the logical unit. + /// Buffer where the Regional Playback Control State will be stored. + /// Sense buffer. + /// Key class. + /// The challenge; can be any 10 bytes. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// true if the command failed and contains the sense buffer. + public bool SendChallenge(out byte[] buffer, out byte[] senseBuffer, DvdCssKeyClass keyClass, byte[] challengeKey, + uint timeout, out double duration) + { + senseBuffer = new byte[64]; + var cdb = new byte[12]; + buffer = new byte[16]; + + cdb[0] = (byte)ScsiCommands.SendKey; + cdb[7] = (byte)keyClass; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((byte)CssSendKeyFormat.ChallengeKey ^ (Agid & 0x03) << 6); + buffer[0] = (byte)((buffer.Length - 2 & 0xFF00) >> 8); + buffer[1] = (byte)(buffer.Length - 2 & 0xFF); + buffer[4] = challengeKey[9]; + buffer[5] = challengeKey[8]; + buffer[6] = challengeKey[7]; + buffer[7] = challengeKey[6]; + buffer[8] = challengeKey[5]; + buffer[9] = challengeKey[4]; + buffer[10] = challengeKey[3]; + buffer[11] = challengeKey[2]; + buffer[12] = challengeKey[1]; + buffer[13] = challengeKey[0]; + + dev.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.Out, out duration, out bool sense); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SEND_CHALLENGE_AGID_1_Challenge_2_Sense_3_Last_Error_4_took_0_ms, + duration, + Agid, + challengeKey, + sense, + dev.LastError); + + return sense; + } + + /// Send KEY2 to the logical unit. + /// Buffer where the Regional Playback Control State will be stored. + /// Sense buffer. + /// Key class. + /// The KEY2 message. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// true if the command failed and contains the sense buffer. + public bool SendKey2(out byte[] buffer, out byte[] senseBuffer, DvdCssKeyClass keyClass, byte[] key2, uint timeout, + out double duration) + { + senseBuffer = new byte[64]; + var cdb = new byte[12]; + buffer = new byte[12]; + + cdb[0] = (byte)ScsiCommands.SendKey; + cdb[7] = (byte)keyClass; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((byte)CssSendKeyFormat.Key2 ^ (Agid & 0x03) << 6); + buffer[0] = (byte)((buffer.Length - 2 & 0xFF00) >> 8); + buffer[1] = (byte)(buffer.Length - 2 & 0xFF); + buffer[4] = key2[4]; + buffer[5] = key2[3]; + buffer[6] = key2[2]; + buffer[7] = key2[1]; + buffer[8] = key2[0]; + + dev.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.Out, out duration, out bool sense); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.SEND_CHALLENGE_AGID_1_KEY2_2_Sense_3_Last_Error_4_took_0_ms, + duration, + Agid, + key2, + sense, + dev.LastError); + + return sense; + } + + /// Returns the encrypted disc key of the MMC logical unit + /// true if the command failed and contains the sense buffer. + /// Buffer where the bus key will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadDiscKey(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + senseBuffer = new byte[64]; + var cdb = new byte[12]; + buffer = new byte[2052]; + + cdb[0] = (byte)ScsiCommands.ReadDiscStructure; + cdb[1] = (byte)MmcDiscStructureMediaType.Dvd & 0x0F; + cdb[6] = 0; + cdb[7] = (byte)MmcDiscStructureFormat.DiscKey; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((Agid & 0x03) << 6); + + dev.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); + + return sense; + } + + /// Returns the bus key of the MMC logical unit + /// true if the command failed and contains the sense buffer. + /// Buffer where the bus key will be stored + /// Sense buffer. + /// The type of protection the logical unit reports + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadBusKey(out byte[] buffer, out byte[] senseBuffer, CopyrightType protectionType, uint timeout, + out double duration) + { + duration = 0; + buffer = []; + senseBuffer = new byte[64]; + + var sense = false; + var challenge = new byte[CHALLENGE_SIZE]; + var key1 = new byte[KEY_SIZE]; + byte variant = 0; + + for(byte i = 0; i < 4; i++) + { + // Invalidate AGID to reset any previous drive communications + Agid = i; + + sense = InvalidateAgid(out buffer, out senseBuffer, DvdCssKeyClass.DvdCssCppmOrCprm, timeout, out duration); + + switch(protectionType) + { + // Get AGID + case CopyrightType.CSS: + sense = ReportAgidCssCppm(out buffer, + out senseBuffer, + DvdCssKeyClass.DvdCssCppmOrCprm, + timeout, + out duration); + + break; + case CopyrightType.CPRM: + throw new NotImplementedException(); + } + + if(sense) continue; + + Agid = (byte)(buffer[7] >> 6); + + break; + } + + if(sense) return true; + + for(byte i = 0; i < CHALLENGE_SIZE; i++) challenge[i] = i; + + sense = SendChallenge(out buffer, + out senseBuffer, + DvdCssKeyClass.DvdCssCppmOrCprm, + challenge, + timeout, + out duration); + + if(sense) return true; + + sense = ReportKey1(out buffer, out senseBuffer, DvdCssKeyClass.DvdCssCppmOrCprm, timeout, out duration); + + if(sense) return true; + + for(byte i = 0; i < KEY_SIZE; i++) key1[i] = buffer[8 - i]; + + for(byte i = 0; i < 32; i++) + { + CSS.EncryptKey(DvdCssKeyType.Key1, i, challenge, out byte[] keyCheck); + + if(key1.SequenceEqual(keyCheck)) + { + variant = i; + + break; + } + + if(i < 31) continue; + + senseBuffer = []; + + return true; + } + + sense = ReportChallenge(out buffer, out senseBuffer, DvdCssKeyClass.DvdCssCppmOrCprm, timeout, out duration); + + if(sense) return true; + + for(byte i = 0; i < CHALLENGE_SIZE; i++) challenge[i] = buffer[13 - i]; + + CSS.EncryptKey(DvdCssKeyType.Key2, variant, challenge, out byte[] key2); + + sense = SendKey2(out buffer, out senseBuffer, DvdCssKeyClass.DvdCssCppmOrCprm, key2, timeout, out duration); + + if(sense) return true; + + key1.CopyTo(challenge, 0); + key2.CopyTo(challenge, key1.Length); + CSS.EncryptKey(DvdCssKeyType.BusKey, variant, challenge, out buffer); + + BusKey = buffer; + + return false; + } + + /// Reads a title key for a sector on the disc. + /// Buffer where the bus key will be stored + /// Sense buffer. + /// Key class. + /// The sector address to get the key for. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// true if the command failed and contains the sense buffer. + public bool ReadTitleKey(out byte[] buffer, out byte[] senseBuffer, DvdCssKeyClass keyClass, ulong address, + uint timeout, out double duration) + { + // We need to be in a bus key state to read title keys. Only CSS has title keys. + ReadBusKey(out buffer, out senseBuffer, CopyrightType.CSS, timeout, out duration); + + BusKey = buffer; + + senseBuffer = new byte[64]; + var cdb = new byte[12]; + buffer = new byte[12]; + + cdb[0] = (byte)ScsiCommands.ReportKey; + cdb[2] = (byte)((address & 0xFF000000) >> 24); + cdb[3] = (byte)((address & 0xFF0000) >> 16); + cdb[4] = (byte)((address & 0xFF00) >> 8); + cdb[5] = (byte)(address & 0xFF); + cdb[7] = (byte)keyClass; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((byte)CssReportKeyFormat.TitleKey ^ (Agid & 0x03) << 6); + + dev.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.GET_TITLE_KEY_AGID_1_LBA_2_Sense_3_took_0_ms, + duration, + Agid, + address, + sense); + + return sense; + } +} \ No newline at end of file diff --git a/Aaru.Decryption/DVD/MPEG.cs b/Aaru.Decryption/DVD/MPEG.cs new file mode 100644 index 000000000..92a5cf63c --- /dev/null +++ b/Aaru.Decryption/DVD/MPEG.cs @@ -0,0 +1,163 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : MPEG.cs +// Author(s) : Rebecca Wallander +// +// --[ Description ] ---------------------------------------------------------- +// +// Handles MPEG packets functionality. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2023-2024 Rebecca Wallander +// ****************************************************************************/ + +// http://www.mpucoder.com/DVD/vobov.html + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.InteropServices; + +// ReSharper disable UnusedMember.Global + +namespace Aaru.Decryption.DVD; + +[SuppressMessage("ReSharper", "UnusedType.Global")] +public class Mpeg +{ +#region Mpeg2StreamId enum + + public enum Mpeg2StreamId : byte + { + ProgramEnd = 0xB9, + PackHeader = 0xBA, + SystemHeader = 0xBB, + ProgramStreamMap = 0xBC, + PrivateStream1 = 0xBD, + PaddingStream = 0xBE, + PrivateStream2 = 0xBF, + EcmStream = 0xF0, + EmmStream = 0xF1, + ItuTRecH222_0_Or_IsoIec13818_1AnnexA_Or_IsoIec13818_6DsmccStream = 0xF2, + IsoIec13522Stream = 0xF3, + ItuTRecH222_1TypeA = 0xF4, + ItuTRecH222_1TypeB = 0xF5, + ItuTRecH222_1TypeC = 0xF6, + ItuTRecH222_1TypeD = 0xF7, + ItuTRecH222_1TypeE = 0xF8, + AncillaryStream = 0xF9, + Reserved1 = 0xFA, + Reserved2 = 0xFB, + Reserved3 = 0xFC, + Reserved4 = 0xFD, + Reserved5 = 0xFE, + ProgramStreamDirectory = 0xFF, + + // DVD Video can only hold 8 audio streams + MpegAudioStream1 = 0xC0, + MpegAudioStream2 = 0xC1, + MpegAudioStream3 = 0xC2, + MpegAudioStream4 = 0xC3, + MpegAudioStream5 = 0xC4, + MpegAudioStream6 = 0xC5, + MpegAudioStream7 = 0xC6, + MpegAudioStream8 = 0xC7, + MpegAudioStream9 = 0xC8, + MpegAudioStream10 = 0xC9, + MpegAudioStream11 = 0xCA, + MpegAudioStream12 = 0xCB, + MpegAudioStream13 = 0xCC, + MpegAudioStream14 = 0xCD, + MpegAudioStream15 = 0xCE, + MpegAudioStream16 = 0xCF, + MpegAudioStream17 = 0xD0, + MpegAudioStream18 = 0xD1, + MpegAudioStream19 = 0xD2, + MpegAudioStream20 = 0xD3, + MpegAudioStream21 = 0xD4, + MpegAudioStream22 = 0xD5, + MpegAudioStream23 = 0xD6, + MpegAudioStream24 = 0xD7, + MpegAudioStream25 = 0xD8, + MpegAudioStream26 = 0xD9, + MpegAudioStream27 = 0xDA, + MpegAudioStream28 = 0xDB, + MpegAudioStream29 = 0xDC, + MpegAudioStream30 = 0xDD, + MpegAudioStream31 = 0xDE, + MpegAudioStream32 = 0xDF, + + // DVD Video can only hold 1 video stream + MpegVideStream1 = 0xE0, + MpegVideStream2 = 0xE1, + MpegVideStream3 = 0xE2, + MpegVideStream4 = 0xE3, + MpegVideStream5 = 0xE4, + MpegVideStream6 = 0xE5, + MpegVideStream7 = 0xE6, + MpegVideStream8 = 0xE7, + MpegVideStream9 = 0xE8, + MpegVideStream10 = 0xE9, + MpegVideStream11 = 0xEA, + MpegVideStream12 = 0xEB, + MpegVideStream13 = 0xEC, + MpegVideStream14 = 0xED, + MpegVideStream15 = 0xEE, + MpegVideStream16 = 0xEF + } + +#endregion + + static readonly byte[] _mpeg2PackHeaderStartCode = [0x0, 0x0, 0x1]; + + public static bool ContainsMpegPackets(byte[] sectorData, uint blocks = 1, uint blockSize = 2048) + { + for(uint i = 0; i < blocks; i++) + if(IsMpegPacket(sectorData.Skip((int)(i * blockSize)))) + return true; + + return false; + } + + public static bool IsMpegPacket(IEnumerable sector) => + sector.Take(3).ToArray().SequenceEqual(_mpeg2PackHeaderStartCode); + +#region Nested type: MpegHeader + + public struct MpegHeader + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] StartCode; + public byte PackIdentifier; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] SCRBlock; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] ProgramMuxRateBlock; + byte _packStuffingLengthBlock; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Decryption/Enums.cs b/Aaru.Decryption/Enums.cs new file mode 100644 index 000000000..b3684dd58 --- /dev/null +++ b/Aaru.Decryption/Enums.cs @@ -0,0 +1,16 @@ +// ReSharper disable UnusedMember.Global + +namespace Aaru.Decryption; + +public enum DvdCssKeyClass : byte +{ + DvdCssCppmOrCprm = 0, + RewritableSecurityServicesA = 1 +} + +public enum DvdCssKeyType +{ + Key1 = 0, + Key2 = 1, + BusKey = 2 +} \ No newline at end of file diff --git a/Aaru.Decryption/LICENSE b/Aaru.Decryption/LICENSE new file mode 100644 index 000000000..94f0a2c67 --- /dev/null +++ b/Aaru.Decryption/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2024 Natalia Portillo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Aaru.Decryption/Localization/Localization.Designer.cs b/Aaru.Decryption/Localization/Localization.Designer.cs new file mode 100644 index 000000000..5c7744828 --- /dev/null +++ b/Aaru.Decryption/Localization/Localization.Designer.cs @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Aaru.Decryption { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Localization { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Localization() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aaru.Decryption.Localization.Localization", typeof(Localization).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to GET TITLE KEY (AGID: {1}, LBA: {2}, Sense: {3}) took {0} ms.. + /// + internal static string GET_TITLE_KEY_AGID_1_LBA_2_Sense_3_took_0_ms { + get { + return ResourceManager.GetString("GET_TITLE_KEY_AGID_1_LBA_2_Sense_3_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to INVALIDATE AGID (AGID: {1}, Sense: {2}, Last Error: {3}) took {0} ms.. + /// + internal static string INVALIDATE_AGID_AGID_1_Sense_2_Last_Error_3_took_0_ms { + get { + return ResourceManager.GetString("INVALIDATE_AGID_AGID_1_Sense_2_Last_Error_3_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to REPORT AGID CSS/CPPM (AGID: {1}, Sense: {2}, Last Error: {3}) took {0} ms.. + /// + internal static string REPORT_AGID_CSS_CPPM_AGID_1_Sense_2_Last_Error_3_took_0_ms { + get { + return ResourceManager.GetString("REPORT_AGID_CSS_CPPM_AGID_1_Sense_2_Last_Error_3_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to REPORT ASF (AGID: {1}, Sense: {2}, Last Error: {3}) took {0} ms.. + /// + internal static string REPORT_ASF_AGID_1_Sense_2_Last_Error_3_took_0_ms { + get { + return ResourceManager.GetString("REPORT_ASF_AGID_1_Sense_2_Last_Error_3_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to REPORT CHALLENGE (AGID: {1}, Sense: {2}, Last Error: {3}) took {0} ms.. + /// + internal static string REPORT_CHALLENGE_AGID_1_Sense_2_Last_Error_3_took_0_ms { + get { + return ResourceManager.GetString("REPORT_CHALLENGE_AGID_1_Sense_2_Last_Error_3_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to REPORT KEY1 (AGID: {1}, Sense: {2}, Last Error: {3}) took {0} ms.. + /// + internal static string REPORT_KEY1_AGID_1_Sense_2_Last_Error_3_took_0_ms { + get { + return ResourceManager.GetString("REPORT_KEY1_AGID_1_Sense_2_Last_Error_3_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEND CHALLENGE (AGID: {1}, Challenge {2}, Sense: {3}, Last Error: {4}) took {0} ms.. + /// + internal static string SEND_CHALLENGE_AGID_1_Challenge_2_Sense_3_Last_Error_4_took_0_ms { + get { + return ResourceManager.GetString("SEND_CHALLENGE_AGID_1_Challenge_2_Sense_3_Last_Error_4_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEND CHALLENGE (AGID: {1}, KEY2 {2}, Sense: {3}, Last Error: {4}) took {0} ms.. + /// + internal static string SEND_CHALLENGE_AGID_1_KEY2_2_Sense_3_Last_Error_4_took_0_ms { + get { + return ResourceManager.GetString("SEND_CHALLENGE_AGID_1_KEY2_2_Sense_3_Last_Error_4_took_0_ms", resourceCulture); + } + } + } +} diff --git a/Aaru.Decryption/Localization/Localization.es.resx b/Aaru.Decryption/Localization/Localization.es.resx new file mode 100644 index 000000000..6905f0a28 --- /dev/null +++ b/Aaru.Decryption/Localization/Localization.es.resx @@ -0,0 +1,43 @@ + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + GET TITLE KEY (AGID: {1}, LBA: {2}, Sense: {3}) tardó {0} ms. + + + INVALIDATE AGID (AGID: {1}, Sense: {2}, Error: {3}) tardó {0} ms. + + + REPORT AGID CSS/CPPM (AGID: {1}, Sense: {2}, Error: {3}) tardó {0} ms. + + + REPORT ASF (AGID: {1}, Sense: {2}, Error: {3}) tardó {0} ms. + + + REPORT CHALLENGE (AGID: {1}, Sense: {2}, Error: {3}) tardó {0} ms. + + + REPORT KEY1 (AGID: {1}, Sense: {2}, Error: {3}) tardó {0} ms. + + + SEND CHALLENGE (AGID: {1}, Desafío {2}, Sense: {3}, Error: {4}) tardó {0} ms. + + + SEND CHALLENGE (AGID: {1}, KEY2 {2}, Sense: {3}, Error: {4}) tardó {0} ms. + + \ No newline at end of file diff --git a/Aaru.Decryption/Localization/Localization.resx b/Aaru.Decryption/Localization/Localization.resx new file mode 100644 index 000000000..6df08245a --- /dev/null +++ b/Aaru.Decryption/Localization/Localization.resx @@ -0,0 +1,50 @@ + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + REPORT ASF (AGID: {1}, Sense: {2}, Last Error: {3}) took {0} ms. + + + INVALIDATE AGID (AGID: {1}, Sense: {2}, Last Error: {3}) took {0} ms. + + + REPORT AGID CSS/CPPM (AGID: {1}, Sense: {2}, Last Error: {3}) took {0} ms. + + + REPORT KEY1 (AGID: {1}, Sense: {2}, Last Error: {3}) took {0} ms. + + + REPORT CHALLENGE (AGID: {1}, Sense: {2}, Last Error: {3}) took {0} ms. + + + SEND CHALLENGE (AGID: {1}, Challenge {2}, Sense: {3}, Last Error: {4}) took {0} ms. + + + SEND CHALLENGE (AGID: {1}, KEY2 {2}, Sense: {3}, Last Error: {4}) took {0} ms. + + + GET TITLE KEY (AGID: {1}, LBA: {2}, Sense: {3}) took {0} ms. + + \ No newline at end of file diff --git a/Aaru.Devices/Aaru.Devices.csproj b/Aaru.Devices/Aaru.Devices.csproj index 9b0f09e57..36a59da6c 100644 --- a/Aaru.Devices/Aaru.Devices.csproj +++ b/Aaru.Devices/Aaru.Devices.csproj @@ -1,163 +1,102 @@  - - Debug - AnyCPU - 2.0 - {57BB2341-AB62-48FD-91B8-46F5A2F9ED51} - Library - Aaru.Devices - Aaru.Devices - $(Version) - false - true - 6.0.0-alpha8 - Claunia.com - Copyright © 2011-2022 Natalia Portillo - Aaru Data Preservation Suite - Aaru.Devices - $(Version) - net6.0 - 10 - Media device hardware interface implementation used by the Aaru Data Preservation Suite. - https://github.com/aaru-dps/ - LGPL-2.1-only - https://github.com/aaru-dps/Aaru - true - en-US - true - true - snupkg - Natalia Portillo <claunia@claunia.com> - true - - - $(Version)+{chash:8} - true - true - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - AnyCPU - - - full - true - bin\Release - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LICENSE.LGPL - - - - - - - /Library/Frameworks/Mono.framework/Versions/Current/lib/mono - /usr/lib/mono - /usr/local/lib/mono - - $(BaseFrameworkPathOverrideForMono)/4.0-api - $(BaseFrameworkPathOverrideForMono)/4.5-api - $(BaseFrameworkPathOverrideForMono)/4.5.1-api - $(BaseFrameworkPathOverrideForMono)/4.5.2-api - $(BaseFrameworkPathOverrideForMono)/4.6-api - $(BaseFrameworkPathOverrideForMono)/4.6.1-api - $(BaseFrameworkPathOverrideForMono)/4.6.2-api - $(BaseFrameworkPathOverrideForMono)/4.7-api - $(BaseFrameworkPathOverrideForMono)/4.7.1-api - true - - $(FrameworkPathOverride)/Facades;$(AssemblySearchPaths) - + + 2.0 + {57BB2341-AB62-48FD-91B8-46F5A2F9ED51} + Library + Aaru.Devices + Aaru.Devices + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Devices + $(Version) + net8.0 + 12 + Media device hardware interface implementation used by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + LGPL-2.1-only + https://github.com/aaru-dps/Aaru + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + LICENSE.LGPL + + + ResXFileCodeGenerator + Localization.Designer.cs + + \ No newline at end of file diff --git a/Aaru.Devices/Aaru.Devices.csproj.DotSettings b/Aaru.Devices/Aaru.Devices.csproj.DotSettings index 53bef25e6..9fc7c1de8 100644 --- a/Aaru.Devices/Aaru.Devices.csproj.DotSettings +++ b/Aaru.Devices/Aaru.Devices.csproj.DotSettings @@ -1,5 +1,9 @@ - + True - True - True - True \ No newline at end of file + True + True + True + True \ No newline at end of file diff --git a/Aaru.Devices/Device/AtaCommands/Ata28.cs b/Aaru.Devices/Device/AtaCommands/Ata28.cs index 9b1993a6c..d0eed75c3 100644 --- a/Aaru.Devices/Device/AtaCommands/Ata28.cs +++ b/Aaru.Devices/Device/AtaCommands/Ata28.cs @@ -27,15 +27,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - -using System; using Aaru.Console; using Aaru.Decoders.ATA; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + public partial class Device { /// Reads the drive buffer using PIO transfer @@ -54,12 +55,19 @@ public partial class Device Command = (byte)AtaCommands.ReadBuffer }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ BUFFER took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_BUFFER_took_0_ms, duration); return sense; } @@ -80,12 +88,19 @@ public partial class Device Command = (byte)AtaCommands.ReadBufferDma }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.Dma, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.Dma, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ BUFFER DMA took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_BUFFER_DMA_took_0_ms, duration); return sense; } @@ -98,8 +113,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadDma(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint lba, byte count, - uint timeout, out double duration) => + public bool ReadDma(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint lba, byte count, + uint timeout, out double duration) => ReadDma(out buffer, out statusRegisters, true, lba, count, timeout, out duration); /// Reads sectors using 48-bit addressing and DMA transfer @@ -112,7 +127,7 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool ReadDma(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, bool retry, uint lba, byte count, - uint timeout, out double duration) + uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 256] : new byte[512 * count]; @@ -128,12 +143,19 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.Dma, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.Dma, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ DMA took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_DMA_took_0_ms, duration); return sense; } @@ -149,8 +171,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadMultiple(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint lba, byte count, - uint timeout, out double duration) + public bool ReadMultiple(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint lba, byte count, + uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 256] : new byte[512 * count]; @@ -166,12 +188,19 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ MULTIPLE took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_MULTIPLE_took_0_ms, duration); return sense; } @@ -182,11 +211,11 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadNativeMaxAddress(out uint lba, out AtaErrorRegistersLba28 statusRegisters, uint timeout, + public bool ReadNativeMaxAddress(out uint lba, out AtaErrorRegistersLba28 statusRegisters, uint timeout, out double duration) { lba = 0; - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba28 { @@ -195,8 +224,15 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; @@ -209,7 +245,7 @@ public partial class Device lba += statusRegisters.LbaLow; } - AaruConsole.DebugWriteLine("ATA Device", "READ NATIVE MAX ADDRESS took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_NATIVE_MAX_ADDRESS_took_0_ms, duration); return sense; } @@ -235,8 +271,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool Read(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, bool retry, uint lba, byte count, - uint timeout, out double duration) + public bool Read(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, bool retry, uint lba, byte count, + uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 256] : new byte[512 * count]; @@ -252,12 +288,19 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ SECTORS took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_SECTORS_took_0_ms, duration); return sense; } @@ -270,8 +313,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadLong(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint lba, uint blockSize, - uint timeout, out double duration) => + public bool ReadLong(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, uint lba, uint blockSize, + uint timeout, out double duration) => ReadLong(out buffer, out statusRegisters, true, lba, blockSize, timeout, out duration); /// Reads a long sector using 28-bit addressing and PIO transfer, retrying on error @@ -283,8 +326,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadLong(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, bool retry, uint lba, - uint blockSize, uint timeout, out double duration) + public bool ReadLong(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, bool retry, uint lba, + uint blockSize, uint timeout, out double duration) { buffer = new byte[blockSize]; @@ -300,12 +343,19 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ LONG took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_LONG_took_0_ms, duration); return sense; } @@ -318,7 +368,7 @@ public partial class Device /// true if the device set an error condition, false otherwise public bool Seek(out AtaErrorRegistersLba28 statusRegisters, uint lba, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba28 { @@ -331,12 +381,19 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SEEK took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SEEK_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/AtaCommands/Ata48.cs b/Aaru.Devices/Device/AtaCommands/Ata48.cs index 5a9ee5c99..cf20b2302 100644 --- a/Aaru.Devices/Device/AtaCommands/Ata48.cs +++ b/Aaru.Devices/Device/AtaCommands/Ata48.cs @@ -27,15 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - -using System; using Aaru.Console; using Aaru.Decoders.ATA; +namespace Aaru.Devices; + public partial class Device { /// Gets native max address using 48-bit addressing @@ -44,11 +43,11 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool GetNativeMaxAddressExt(out ulong lba, out AtaErrorRegistersLba48 statusRegisters, uint timeout, + public bool GetNativeMaxAddressExt(out ulong lba, out AtaErrorRegistersLba48 statusRegisters, uint timeout, out double duration) { lba = 0; - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba48 { @@ -56,23 +55,32 @@ public partial class Device Feature = 0x0000 }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; if((statusRegisters.Status & 0x23) == 0) { - lba = (ulong)((statusRegisters.LbaHighCurrent << 16) + (statusRegisters.LbaMidCurrent << 8) + + lba = (ulong)((statusRegisters.LbaHighCurrent << 16) + + (statusRegisters.LbaMidCurrent << 8) + statusRegisters.LbaLowCurrent); lba <<= 24; - lba += (ulong)((statusRegisters.LbaHighPrevious << 16) + (statusRegisters.LbaMidPrevious << 8) + + lba += (ulong)((statusRegisters.LbaHighPrevious << 16) + + (statusRegisters.LbaMidPrevious << 8) + statusRegisters.LbaLowPrevious); } - AaruConsole.DebugWriteLine("ATA Device", "GET NATIVE MAX ADDRESS EXT took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.GET_NATIVE_MAX_ADDRESS_EXT_took_0_ms, duration); return sense; } @@ -85,8 +93,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadDma(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, ulong lba, ushort count, - uint timeout, out double duration) + public bool ReadDma(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, ulong lba, ushort count, + uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 65536] : new byte[512 * count]; @@ -104,12 +112,19 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.Dma, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.Dma, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ DMA EXT took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_DMA_EXT_took_0_ms, duration); return sense; } @@ -123,8 +138,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadLog(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, byte logAddress, - ushort pageNumber, ushort count, uint timeout, out double duration) + public bool ReadLog(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, byte logAddress, + ushort pageNumber, ushort count, uint timeout, out double duration) { buffer = new byte[512 * count]; @@ -133,17 +148,23 @@ public partial class Device Command = (byte)AtaCommands.ReadLogExt, SectorCount = count, LbaMidCurrent = (byte)(pageNumber & 0xFF), - LbaMidPrevious = (byte)((pageNumber & 0xFF00) / 0x100) + LbaMidPrevious = (byte)((pageNumber & 0xFF00) / 0x100), + LbaLowCurrent = logAddress }; - registers.LbaLowCurrent = logAddress; - - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ LOG EXT took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_LOG_EXT_took_0_ms, duration); return sense; } @@ -157,8 +178,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadLogDma(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, byte logAddress, - ushort pageNumber, ushort count, uint timeout, out double duration) + public bool ReadLogDma(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, byte logAddress, + ushort pageNumber, ushort count, uint timeout, out double duration) { buffer = new byte[512 * count]; @@ -167,17 +188,23 @@ public partial class Device Command = (byte)AtaCommands.ReadLogDmaExt, SectorCount = count, LbaMidCurrent = (byte)(pageNumber & 0xFF), - LbaMidPrevious = (byte)((pageNumber & 0xFF00) / 0x100) + LbaMidPrevious = (byte)((pageNumber & 0xFF00) / 0x100), + LbaLowCurrent = logAddress }; - registers.LbaLowCurrent = logAddress; - - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.Dma, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.Dma, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ LOG DMA EXT took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_LOG_DMA_EXT_took_0_ms, duration); return sense; } @@ -193,8 +220,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadMultiple(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, ulong lba, ushort count, - uint timeout, out double duration) + public bool ReadMultiple(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, ulong lba, ushort count, + uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 65536] : new byte[512 * count]; @@ -212,12 +239,19 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ MULTIPLE EXT took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_MULTIPLE_EXT_took_0_ms, duration); return sense; } @@ -228,11 +262,11 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadNativeMaxAddress(out ulong lba, out AtaErrorRegistersLba48 statusRegisters, uint timeout, + public bool ReadNativeMaxAddress(out ulong lba, out AtaErrorRegistersLba48 statusRegisters, uint timeout, out double duration) { lba = 0; - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba48 { @@ -241,23 +275,32 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; if((statusRegisters.Status & 0x23) == 0) { - lba = (ulong)((statusRegisters.LbaHighCurrent << 16) + (statusRegisters.LbaMidCurrent << 8) + + lba = (ulong)((statusRegisters.LbaHighCurrent << 16) + + (statusRegisters.LbaMidCurrent << 8) + statusRegisters.LbaLowCurrent); lba <<= 24; - lba += (ulong)((statusRegisters.LbaHighPrevious << 16) + (statusRegisters.LbaMidPrevious << 8) + + lba += (ulong)((statusRegisters.LbaHighPrevious << 16) + + (statusRegisters.LbaMidPrevious << 8) + statusRegisters.LbaLowPrevious); } - AaruConsole.DebugWriteLine("ATA Device", "READ NATIVE MAX ADDRESS EXT took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_NATIVE_MAX_ADDRESS_EXT_took_0_ms, duration); return sense; } @@ -270,8 +313,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool Read(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, ulong lba, ushort count, - uint timeout, out double duration) + public bool Read(out byte[] buffer, out AtaErrorRegistersLba48 statusRegisters, ulong lba, ushort count, + uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 65536] : new byte[512 * count]; @@ -289,12 +332,19 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ SECTORS EXT took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_SECTORS_EXT_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/AtaCommands/AtaCHS.cs b/Aaru.Devices/Device/AtaCommands/AtaCHS.cs index a00e6b686..c23040057 100644 --- a/Aaru.Devices/Device/AtaCommands/AtaCHS.cs +++ b/Aaru.Devices/Device/AtaCommands/AtaCHS.cs @@ -27,15 +27,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - -using System; +using System.Diagnostics.CodeAnalysis; using Aaru.Console; using Aaru.Decoders.ATA; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "OutParameterValueIsAlwaysDiscarded.Global")] public partial class Device { /// Sends the ATA IDENTIFY DEVICE command to the device, using default device timeout @@ -74,15 +78,23 @@ public partial class Device var registers = new AtaRegistersChs { - Command = (byte)AtaCommands.IdentifyDevice + Command = (byte)AtaCommands.IdentifyDevice, + SectorCount = 1 }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "IDENTIFY DEVICE took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, "IDENTIFY DEVICE took {0} ms.", duration); return sense; } @@ -98,7 +110,7 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool ReadDma(out byte[] buffer, out AtaErrorRegistersChs statusRegisters, ushort cylinder, byte head, - byte sector, byte count, uint timeout, out double duration) => + byte sector, byte count, uint timeout, out double duration) => ReadDma(out buffer, out statusRegisters, true, cylinder, head, sector, count, timeout, out duration); /// Reads sectors using CHS addressing and DMA transfer @@ -113,7 +125,7 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool ReadDma(out byte[] buffer, out AtaErrorRegistersChs statusRegisters, bool retry, ushort cylinder, - byte head, byte sector, byte count, uint timeout, out double duration) + byte head, byte sector, byte count, uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 256] : new byte[512 * count]; @@ -127,12 +139,19 @@ public partial class Device Command = retry ? (byte)AtaCommands.ReadDmaRetry : (byte)AtaCommands.ReadDma }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.Dma, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.Dma, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ DMA took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_DMA_took_0_ms, duration); return sense; } @@ -151,7 +170,7 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool ReadMultiple(out byte[] buffer, out AtaErrorRegistersChs statusRegisters, ushort cylinder, byte head, - byte sector, byte count, uint timeout, out double duration) + byte sector, byte count, uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 256] : new byte[512 * count]; @@ -165,12 +184,19 @@ public partial class Device Sector = sector }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ MULTIPLE took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_MULTIPLE_took_0_ms, duration); return sense; } @@ -186,7 +212,7 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool Read(out byte[] buffer, out AtaErrorRegistersChs statusRegisters, ushort cylinder, byte head, - byte sector, byte count, uint timeout, out double duration) => + byte sector, byte count, uint timeout, out double duration) => Read(out buffer, out statusRegisters, true, cylinder, head, sector, count, timeout, out duration); /// Reads sectors using CHS addressing and PIO transfer @@ -201,7 +227,7 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool Read(out byte[] buffer, out AtaErrorRegistersChs statusRegisters, bool retry, ushort cylinder, - byte head, byte sector, byte count, uint timeout, out double duration) + byte head, byte sector, byte count, uint timeout, out double duration) { buffer = count == 0 ? new byte[512 * 256] : new byte[512 * count]; @@ -215,12 +241,19 @@ public partial class Device Sector = sector }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ SECTORS took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_SECTORS_took_0_ms, duration); return sense; } @@ -236,7 +269,7 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool ReadLong(out byte[] buffer, out AtaErrorRegistersChs statusRegisters, ushort cylinder, byte head, - byte sector, uint blockSize, uint timeout, out double duration) => + byte sector, uint blockSize, uint timeout, out double duration) => ReadLong(out buffer, out statusRegisters, true, cylinder, head, sector, blockSize, timeout, out duration); /// Reads a long sector using CHS addressing and PIO transfer, retrying on error @@ -251,7 +284,7 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool ReadLong(out byte[] buffer, out AtaErrorRegistersChs statusRegisters, bool retry, ushort cylinder, - byte head, byte sector, uint blockSize, uint timeout, out double duration) + byte head, byte sector, uint blockSize, uint timeout, out double duration) { buffer = new byte[blockSize]; @@ -265,12 +298,19 @@ public partial class Device Sector = sector }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.SectorCount, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "READ LONG took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.READ_LONG_took_0_ms, duration); return sense; } @@ -284,9 +324,9 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool Seek(out AtaErrorRegistersChs statusRegisters, ushort cylinder, byte head, byte sector, uint timeout, - out double duration) + out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersChs { @@ -297,12 +337,19 @@ public partial class Device Sector = sector }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SEEK took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SEEK_took_0_ms, duration); return sense; } @@ -314,7 +361,7 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool SetFeatures(out AtaErrorRegistersChs statusRegisters, AtaFeatures feature, uint timeout, - out double duration) => + out double duration) => SetFeatures(out statusRegisters, feature, 0, 0, 0, 0, timeout, out duration); /// Enables drive features @@ -328,9 +375,9 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool SetFeatures(out AtaErrorRegistersChs statusRegisters, AtaFeatures feature, ushort cylinder, byte head, - byte sector, byte sectorCount, uint timeout, out double duration) + byte sector, byte sectorCount, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersChs { @@ -343,12 +390,19 @@ public partial class Device Feature = (byte)feature }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SET FEATURES took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SET_FEATURES_took_0_ms, duration); return sense; } @@ -360,19 +414,26 @@ public partial class Device /// true if the device set an error condition, false otherwise public bool DoorLock(out AtaErrorRegistersChs statusRegisters, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersChs { Command = (byte)AtaCommands.DoorLock }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "DOOR LOCK took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.DOOR_LOCK_took_0_ms, duration); return sense; } @@ -384,19 +445,26 @@ public partial class Device /// true if the device set an error condition, false otherwise public bool DoorUnlock(out AtaErrorRegistersChs statusRegisters, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersChs { Command = (byte)AtaCommands.DoorUnLock }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "DOOR UNLOCK took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.DOOR_UNLOCK_took_0_ms, duration); return sense; } @@ -408,19 +476,26 @@ public partial class Device /// true if the device set an error condition, false otherwise public bool MediaEject(out AtaErrorRegistersChs statusRegisters, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersChs { Command = (byte)AtaCommands.MediaEject }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, true, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "MEDIA EJECT took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.MEDIA_EJECT_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/AtaCommands/Atapi.cs b/Aaru.Devices/Device/AtaCommands/Atapi.cs index 6a87a5e75..898ac4c2f 100644 --- a/Aaru.Devices/Device/AtaCommands/Atapi.cs +++ b/Aaru.Devices/Device/AtaCommands/Atapi.cs @@ -27,14 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using Aaru.Console; using Aaru.Decoders.ATA; +namespace Aaru.Devices; + public partial class Device { /// Sends the ATA IDENTIFY PACKET DEVICE command to the device, using default device timeout @@ -73,15 +73,23 @@ public partial class Device var registers = new AtaRegistersChs { - Command = (byte)AtaCommands.IdentifyPacketDevice + Command = (byte)AtaCommands.IdentifyPacketDevice, + Sector = 1 }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.SectorCount, + ref buffer, + timeout, + true, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "IDENTIFY PACKET DEVICE took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.IDENTIFY_PACKET_DEVICE_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/AtaCommands/Cfa.cs b/Aaru.Devices/Device/AtaCommands/Cfa.cs index 8298b52fc..af1d9d33c 100644 --- a/Aaru.Devices/Device/AtaCommands/Cfa.cs +++ b/Aaru.Devices/Device/AtaCommands/Cfa.cs @@ -27,15 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - -using System; using Aaru.Console; using Aaru.Decoders.ATA; +namespace Aaru.Devices; + public partial class Device { /// Requests to translate an LBA to a card physical address @@ -61,12 +60,19 @@ public partial class Device registers.DeviceHead += 0x40; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "CFA TRANSLATE SECTOR took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.CFA_TRANSLATE_SECTOR_took_0_ms, duration); return sense; } @@ -81,7 +87,7 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool TranslateSector(out byte[] buffer, out AtaErrorRegistersChs statusRegisters, ushort cylinder, byte head, - byte sector, uint timeout, out double duration) + byte sector, uint timeout, out double duration) { buffer = new byte[512]; @@ -94,12 +100,19 @@ public partial class Device DeviceHead = (byte)(head & 0x0F) }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "CFA TRANSLATE SECTOR took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.CFA_TRANSLATE_SECTOR_took_0_ms, duration); return sense; } @@ -110,24 +123,31 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool RequestExtendedErrorCode(out byte errorCode, out AtaErrorRegistersLba28 statusRegisters, uint timeout, + public bool RequestExtendedErrorCode(out byte errorCode, out AtaErrorRegistersLba28 statusRegisters, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba28 { Command = (byte)AtaCommands.RequestSense }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; errorCode = statusRegisters.Error; - AaruConsole.DebugWriteLine("ATA Device", "CFA REQUEST EXTENDED ERROR CODE took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.CFA_REQUEST_EXTENDED_ERROR_CODE_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/AtaCommands/MCPT.cs b/Aaru.Devices/Device/AtaCommands/MCPT.cs index dd74f25fe..4755f8586 100644 --- a/Aaru.Devices/Device/AtaCommands/MCPT.cs +++ b/Aaru.Devices/Device/AtaCommands/MCPT.cs @@ -27,15 +27,20 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - -using System; +using System.Diagnostics.CodeAnalysis; using Aaru.Console; using Aaru.Decoders.ATA; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "OutParameterValueIsAlwaysDiscarded.Global")] +[SuppressMessage("ReSharper", "MemberCanBeInternal")] public partial class Device { /// Enables media card pass through @@ -44,7 +49,7 @@ public partial class Device /// Time it took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool EnableMediaCardPassThrough(out AtaErrorRegistersChs statusRegisters, uint timeout, - out double duration) => + out double duration) => CheckMediaCardType(1, out statusRegisters, timeout, out duration); /// Disables media card pass through @@ -53,7 +58,7 @@ public partial class Device /// Time it took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool DisableMediaCardPassThrough(out AtaErrorRegistersChs statusRegisters, uint timeout, - out double duration) => + out double duration) => CheckMediaCardType(0, out statusRegisters, timeout, out duration); /// Checks media card pass through @@ -62,10 +67,10 @@ public partial class Device /// Timeout in seconds /// Time it took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool CheckMediaCardType(byte feature, out AtaErrorRegistersChs statusRegisters, uint timeout, + public bool CheckMediaCardType(byte feature, out AtaErrorRegistersChs statusRegisters, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersChs { @@ -73,12 +78,19 @@ public partial class Device Feature = feature }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "CHECK MEDIA CARD TYPE took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.CHECK_MEDIA_CARD_TYPE_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/AtaCommands/Smart.cs b/Aaru.Devices/Device/AtaCommands/Smart.cs index 63983c6a5..553c0715a 100644 --- a/Aaru.Devices/Device/AtaCommands/Smart.cs +++ b/Aaru.Devices/Device/AtaCommands/Smart.cs @@ -27,15 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - -using System; using Aaru.Console; using Aaru.Decoders.ATA; +namespace Aaru.Devices; + public partial class Device { /// Disables S.M.A.R.T. @@ -45,7 +44,7 @@ public partial class Device /// true if the device set an error condition, false otherwise public bool SmartDisable(out AtaErrorRegistersLba28 statusRegisters, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba28 { @@ -55,12 +54,19 @@ public partial class Device LbaMid = 0x4F }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SMART DISABLE OPERATIONS took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SMART_DISABLE_OPERATIONS_took_0_ms, duration); return sense; } @@ -71,9 +77,9 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool SmartEnableAttributeAutosave(out AtaErrorRegistersLba28 statusRegisters, uint timeout, - out double duration) + out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba28 { @@ -84,12 +90,19 @@ public partial class Device SectorCount = 0xF1 }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SMART ENABLE ATTRIBUTE AUTOSAVE took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SMART_ENABLE_ATTRIBUTE_AUTOSAVE_took_0_ms, duration); return sense; } @@ -100,9 +113,9 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool SmartDisableAttributeAutosave(out AtaErrorRegistersLba28 statusRegisters, uint timeout, - out double duration) + out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba28 { @@ -112,12 +125,19 @@ public partial class Device LbaMid = 0x4F }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SMART DISABLE ATTRIBUTE AUTOSAVE took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SMART_DISABLE_ATTRIBUTE_AUTOSAVE_took_0_ms, duration); return sense; } @@ -129,7 +149,7 @@ public partial class Device /// true if the device set an error condition, false otherwise public bool SmartEnable(out AtaErrorRegistersLba28 statusRegisters, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba28 { @@ -139,12 +159,19 @@ public partial class Device LbaMid = 0x4F }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SMART ENABLE OPERATIONS took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SMART_ENABLE_OPERATIONS_took_0_ms, duration); return sense; } @@ -156,9 +183,9 @@ public partial class Device /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise public bool SmartExecuteOffLineImmediate(out AtaErrorRegistersLba28 statusRegisters, byte subcommand, uint timeout, - out double duration) + out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba28 { @@ -169,12 +196,19 @@ public partial class Device LbaLow = subcommand }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SMART EXECUTE OFF-LINE IMMEDIATE took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SMART_EXECUTE_OFF_LINE_IMMEDIATE_took_0_ms, duration); return sense; } @@ -198,12 +232,19 @@ public partial class Device LbaMid = 0x4F }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SMART READ DATA took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SMART_READ_DATA_took_0_ms, duration); return sense; } @@ -215,8 +256,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool SmartReadLog(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, byte logAddress, - uint timeout, out double duration) + public bool SmartReadLog(out byte[] buffer, out AtaErrorRegistersLba28 statusRegisters, byte logAddress, + uint timeout, out double duration) { buffer = new byte[512]; @@ -229,12 +270,19 @@ public partial class Device LbaLow = logAddress }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.PioIn, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.PioIn, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SMART READ LOG took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SMART_READ_LOG_took_0_ms, duration); return sense; } @@ -246,7 +294,7 @@ public partial class Device /// true if the device set an error condition, false otherwise public bool SmartReturnStatus(out AtaErrorRegistersLba28 statusRegisters, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var registers = new AtaRegistersLba28 { @@ -256,12 +304,19 @@ public partial class Device LbaMid = 0x4F }; - LastError = SendAtaCommand(registers, out statusRegisters, AtaProtocol.NonData, AtaTransferRegister.NoTransfer, - ref buffer, timeout, false, out duration, out bool sense); + LastError = SendAtaCommand(registers, + out statusRegisters, + AtaProtocol.NonData, + AtaTransferRegister.NoTransfer, + ref buffer, + timeout, + false, + out duration, + out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("ATA Device", "SMART RETURN STATUS took {0} ms.", duration); + AaruConsole.DebugWriteLine(ATA_MODULE_NAME, Localization.SMART_RETURN_STATUS_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/Commands.cs b/Aaru.Devices/Device/Commands.cs index ffc2b8f22..016cca7dd 100644 --- a/Aaru.Devices/Device/Commands.cs +++ b/Aaru.Devices/Device/Commands.cs @@ -27,14 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using System.Diagnostics.CodeAnalysis; using Aaru.Decoders.ATA; +namespace Aaru.Devices; + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public partial class Device { @@ -50,7 +50,7 @@ public partial class Device /// True if SCSI command returned non-OK status and contains /// SCSI sense /// - public virtual int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, + public virtual int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, ScsiDirection direction, out double duration, out bool sense) { duration = 0; @@ -75,8 +75,8 @@ public partial class Device /// Time it took to execute the command in milliseconds /// True if ATA/ATAPI command returned non-OK status public virtual int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters, - AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, - uint timeout, bool transferBlocks, out double duration, out bool sense) + AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, + uint timeout, bool transferBlocks, out double duration, out bool sense) { duration = 0; sense = true; @@ -149,9 +149,9 @@ public partial class Device /// Command argument /// Response registers /// Size of block in bytes - public virtual int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, - uint argument, uint blockSize, uint blocks, ref byte[] buffer, - out uint[] response, out double duration, out bool sense, uint timeout = 15) + public virtual int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, + uint argument, uint blockSize, uint blocks, ref byte[] buffer, + out uint[] response, out double duration, out bool sense, uint timeout = 15) { response = null; duration = 0; @@ -160,30 +160,6 @@ public partial class Device return -1; } - /// Encapsulates a single MMC command to send in a queue - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] - public class MmcSingleCommand - { - /// Command argument - public uint argument; - /// How many blocks to transfer - public uint blocks; - /// Size of block in bytes - public uint blockSize; - /// Buffer for MMC/SD command response - public byte[] buffer; - /// MMC/SD opcode - public MmcCommands command; - /// Flags indicating kind and place of response - public MmcFlags flags; - /// True if command should be preceded with CMD55 - public bool isApplication; - /// Response registers - public uint[] response; - /// True if data is sent from host to card - public bool write; - } - /// /// Concatenates a queue of commands to be send to a remote SecureDigital or MultiMediaCard attached to an SDHCI /// controller @@ -194,7 +170,7 @@ public partial class Device /// Maximum allowed time to execute a single command /// 0 if no error occurred, otherwise, errno public virtual int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense, - uint timeout = 15) + uint timeout = 15) { duration = 0; sense = true; @@ -219,4 +195,33 @@ public partial class Device return false; } + +#region Nested type: MmcSingleCommand + + /// Encapsulates a single MMC command to send in a queue + [SuppressMessage("ReSharper", "InconsistentNaming")] + [SuppressMessage("ReSharper", "MemberCanBeInternal")] + public class MmcSingleCommand + { + /// Command argument + public uint argument; + /// How many blocks to transfer + public uint blocks; + /// Size of block in bytes + public uint blockSize; + /// Buffer for MMC/SD command response + public byte[] buffer; + /// MMC/SD opcode + public MmcCommands command; + /// Flags indicating kind and place of response + public MmcFlags flags; + /// True if command should be preceded with CMD55 + public bool isApplication; + /// Response registers + public uint[] response; + /// True if data is sent from host to card + public bool write; + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Devices/Device/Constructor.cs b/Aaru.Devices/Device/Constructor.cs index 638adb433..b1ac21aae 100644 --- a/Aaru.Devices/Device/Constructor.cs +++ b/Aaru.Devices/Device/Constructor.cs @@ -27,11 +27,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using System; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -43,13 +41,20 @@ using Aaru.Decoders.SCSI.MMC; using Aaru.Helpers; using Inquiry = Aaru.CommonTypes.Structs.Devices.SCSI.Inquiry; +namespace Aaru.Devices; + /// Implements a device or media containing drive -[SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnusedMember.Global"), - SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] public partial class Device { + protected Device() {} + /// Opens the device for sending direct commands /// Device path + /// Sets the error if a device cannot be opened + /// Device public static Device Create(string devicePath, out ErrorNumber errno) { Device dev = null; @@ -74,11 +79,9 @@ public partial class Device else errno = ErrorNumber.NotSupported; - if(dev is null) - return null; + if(dev is null) return null; - if(dev.Type == DeviceType.SCSI || - dev.Type == DeviceType.ATAPI) + if(dev.Type is DeviceType.SCSI or DeviceType.ATAPI) { dev.ScsiInquiry(out byte[] inqBuf, out _); @@ -87,25 +90,21 @@ public partial class Device dev.Type = DeviceType.SCSI; bool serialSense = dev.ScsiInquiry(out inqBuf, out _, 0x80); - if(!serialSense) - dev.Serial = EVPD.DecodePage80(inqBuf); + if(!serialSense) dev.Serial = EVPD.DecodePage80(inqBuf); if(inquiry.HasValue) { string tmp = StringHandlers.CToString(inquiry.Value.ProductRevisionLevel); - if(tmp != null) - dev.FirmwareRevision = tmp.Trim(); + if(tmp != null) dev.FirmwareRevision = tmp.Trim(); tmp = StringHandlers.CToString(inquiry.Value.ProductIdentification); - if(tmp != null) - dev.Model = tmp.Trim(); + if(tmp != null) dev.Model = tmp.Trim(); tmp = StringHandlers.CToString(inquiry.Value.VendorIdentification); - if(tmp != null) - dev.Manufacturer = tmp.Trim(); + if(tmp != null) dev.Manufacturer = tmp.Trim(); dev.IsRemovable = inquiry.Value.RMB; @@ -119,8 +118,7 @@ public partial class Device dev.Type = DeviceType.ATAPI; Identify.IdentifyDevice? ataId = Identify.Decode(ataBuf); - if(ataId.HasValue) - dev.Serial = ataId.Value.SerialNumber; + if(ataId.HasValue) dev.Serial = ataId.Value.SerialNumber; } dev.LastError = 0; @@ -155,9 +153,11 @@ public partial class Device dev.ScsiType = PeripheralDeviceTypes.DirectAccess; if((ushort)ataid.Value.GeneralConfiguration != 0x848A) + { dev.IsRemovable |= (ataid.Value.GeneralConfiguration & Identify.GeneralConfigurationBit.Removable) == Identify.GeneralConfigurationBit.Removable; + } else dev.IsCompactFlash = true; } @@ -174,11 +174,9 @@ public partial class Device if(dev.IsUsb) { - if(string.IsNullOrEmpty(dev.Manufacturer)) - dev.Manufacturer = dev.UsbManufacturerString; + if(string.IsNullOrEmpty(dev.Manufacturer)) dev.Manufacturer = dev.UsbManufacturerString; - if(string.IsNullOrEmpty(dev.Model)) - dev.Model = dev.UsbProductString; + if(string.IsNullOrEmpty(dev.Model)) dev.Model = dev.UsbProductString; if(string.IsNullOrEmpty(dev.Serial)) dev.Serial = dev.UsbSerialString; @@ -189,14 +187,12 @@ public partial class Device if(dev.IsFireWire) { - if(string.IsNullOrEmpty(dev.Manufacturer)) - dev.Manufacturer = dev.FireWireVendorName; + if(string.IsNullOrEmpty(dev.Manufacturer)) dev.Manufacturer = dev.FireWireVendorName; - if(string.IsNullOrEmpty(dev.Model)) - dev.Model = dev.FireWireModelName; + if(string.IsNullOrEmpty(dev.Model)) dev.Model = dev.FireWireModelName; if(string.IsNullOrEmpty(dev.Serial)) - dev.Serial = $"{dev._firewireGuid:X16}"; + dev.Serial = $"{dev.FirewireGuid:X16}"; else foreach(char c in dev.Serial.Where(c => !char.IsControl(c))) dev.Serial = $"{dev.Serial}{c:X2}"; @@ -204,30 +200,27 @@ public partial class Device // Some optical drives are not getting the correct serial, and IDENTIFY PACKET DEVICE is blocked without // administrator privileges - if(dev.ScsiType != PeripheralDeviceTypes.MultiMediaDevice) - return dev; + if(dev.ScsiType != PeripheralDeviceTypes.MultiMediaDevice) return dev; - bool featureSense = dev.GetConfiguration(out byte[] featureBuffer, out _, 0x0108, MmcGetConfigurationRt.Single, - dev.Timeout, out _); + bool featureSense = dev.GetConfiguration(out byte[] featureBuffer, + out _, + 0x0108, + MmcGetConfigurationRt.Single, + dev.Timeout, + out _); - if(featureSense) - return dev; + if(featureSense) return dev; Features.SeparatedFeatures features = Features.Separate(featureBuffer); - if(features.Descriptors?.Length != 1 || - features.Descriptors[0].Code != 0x0108) - return dev; + if(features.Descriptors?.Length != 1 || features.Descriptors[0].Code != 0x0108) return dev; Feature_0108? serialFeature = Features.Decode_0108(features.Descriptors[0].Data); - if(serialFeature is null) - return dev; + if(serialFeature is null) return dev; dev.Serial = serialFeature.Value.Serial; return dev; } - - protected Device() {} } \ No newline at end of file diff --git a/Aaru.Devices/Device/Destructor.cs b/Aaru.Devices/Device/Destructor.cs index c2dd9be04..94c3e63c6 100644 --- a/Aaru.Devices/Device/Destructor.cs +++ b/Aaru.Devices/Device/Destructor.cs @@ -27,7 +27,7 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Devices; diff --git a/Aaru.Devices/Device/List.cs b/Aaru.Devices/Device/List.cs index a1c222b5f..d497a07fb 100644 --- a/Aaru.Devices/Device/List.cs +++ b/Aaru.Devices/Device/List.cs @@ -27,16 +27,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using System; using System.Runtime.InteropServices; using Aaru.CommonTypes.Interop; using Aaru.Console; +namespace Aaru.Devices; + /// Contains device information [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] public struct DeviceInfo @@ -89,7 +89,7 @@ public partial class Device /// Remote URI /// List of devices /// - public static DeviceInfo[] ListDevices(out bool isRemote, out string serverApplication, out string serverVersion, + public static DeviceInfo[] ListDevices(out bool isRemote, out string serverApplication, out string serverVersion, out string serverOperatingSystem, out string serverOperatingSystemVersion, out string serverArchitecture, string aaruRemote = null) { @@ -102,25 +102,23 @@ public partial class Device if(aaruRemote is null) { - if(OperatingSystem.IsWindows()) - return Windows.ListDevices.GetList(); + if(OperatingSystem.IsWindows()) return Windows.ListDevices.GetList(); - if(OperatingSystem.IsLinux()) - return Linux.ListDevices.GetList(); + if(OperatingSystem.IsLinux()) return Linux.ListDevices.GetList(); - throw new InvalidOperationException($"Platform {DetectOS.GetRealPlatformID()} not yet supported."); + throw new InvalidOperationException(string.Format(Localization.Platform_0_not_yet_supported, + DetectOS.GetRealPlatformID())); } try { var aaruUri = new Uri(aaruRemote); - if(aaruUri.Scheme != "aaru" && - aaruUri.Scheme != "dic") + if(aaruUri.Scheme != "aaru" && aaruUri.Scheme != "dic") { - AaruConsole.ErrorWriteLine("Invalid remote URI."); + AaruConsole.ErrorWriteLine(Localization.Invalid_remote_URI); - return Array.Empty(); + return []; } using var remote = new Remote.Remote(aaruUri); @@ -136,9 +134,9 @@ public partial class Device } catch(Exception) { - AaruConsole.ErrorWriteLine("Error connecting to host."); + AaruConsole.ErrorWriteLine(Localization.Error_connecting_to_host); - return Array.Empty(); + return []; } } } \ No newline at end of file diff --git a/Aaru.Devices/Device/MmcCommands/MMC.cs b/Aaru.Devices/Device/MmcCommands/MMC.cs index 43de1d9c3..d7541182a 100644 --- a/Aaru.Devices/Device/MmcCommands/MMC.cs +++ b/Aaru.Devices/Device/MmcCommands/MMC.cs @@ -27,16 +27,22 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using System; using Aaru.Console; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + public partial class Device { +#pragma warning disable PH2070 // Risks are known. TODO: Maybe protected property? + protected static bool _readMultipleBlockCannotSetBlockCount; +#pragma warning restore PH2070 + /// Reads the CSD register from a SecureDigital or MultiMediaCard device /// Data buffer /// Response @@ -47,13 +53,22 @@ public partial class Device { buffer = new byte[16]; - LastError = SendMmcCommand(MmcCommands.SendCsd, false, false, - MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16, 1, - ref buffer, out response, out duration, out bool sense, timeout); + LastError = SendMmcCommand(MmcCommands.SendCsd, + false, + false, + MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, + 0, + 16, + 1, + ref buffer, + out response, + out duration, + out bool sense, + timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("MMC Device", "SEND_CSD took {0} ms.", duration); + AaruConsole.DebugWriteLine(MMC_MODULE_NAME, Localization.SEND_CSD_took_0_ms, duration); return sense; } @@ -68,13 +83,22 @@ public partial class Device { buffer = new byte[16]; - LastError = SendMmcCommand(MmcCommands.SendCid, false, false, - MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16, 1, - ref buffer, out response, out duration, out bool sense, timeout); + LastError = SendMmcCommand(MmcCommands.SendCid, + false, + false, + MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, + 0, + 16, + 1, + ref buffer, + out response, + out duration, + out bool sense, + timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("MMC Device", "SEND_CID took {0} ms.", duration); + AaruConsole.DebugWriteLine(MMC_MODULE_NAME, Localization.SEND_CID_took_0_ms, duration); return sense; } @@ -89,13 +113,22 @@ public partial class Device { buffer = new byte[4]; - LastError = SendMmcCommand(MmcCommands.SendOpCond, false, true, - MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, 0, 4, 1, - ref buffer, out response, out duration, out bool sense, timeout); + LastError = SendMmcCommand(MmcCommands.SendOpCond, + false, + true, + MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, + 0, + 4, + 1, + ref buffer, + out response, + out duration, + out bool sense, + timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("SecureDigital Device", "SEND_OP_COND took {0} ms.", duration); + AaruConsole.DebugWriteLine(MMC_MODULE_NAME, Localization.SEND_OP_COND_took_0_ms, duration); return sense; } @@ -110,13 +143,22 @@ public partial class Device { buffer = new byte[512]; - LastError = SendMmcCommand(MmcCommands.SendExtCsd, false, false, - MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, 0, 512, 1, - ref buffer, out response, out duration, out bool sense, timeout); + LastError = SendMmcCommand(MmcCommands.SendExtCsd, + false, + false, + MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, + 0, + 512, + 1, + ref buffer, + out response, + out duration, + out bool sense, + timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("MMC Device", "SEND_EXT_CSD took {0} ms.", duration); + AaruConsole.DebugWriteLine(MMC_MODULE_NAME, Localization.SEND_EXT_CSD_took_0_ms, duration); return sense; } @@ -129,15 +171,24 @@ public partial class Device /// true if the device set an error condition, false otherwise public bool SetBlockLength(uint length, out uint[] response, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; - LastError = SendMmcCommand(MmcCommands.SetBlocklen, false, false, - MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAc, length, 0, 0, - ref buffer, out response, out duration, out bool sense, timeout); + LastError = SendMmcCommand(MmcCommands.SetBlocklen, + false, + false, + MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAc, + length, + 0, + 0, + ref buffer, + out response, + out duration, + out bool sense, + timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("MMC Device", "SET_BLOCKLEN took {0} ms.", duration); + AaruConsole.DebugWriteLine(MMC_MODULE_NAME, Localization.SET_BLOCKLEN_took_0_ms, duration); return sense; } @@ -152,8 +203,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool Read(out byte[] buffer, out uint[] response, uint lba, uint blockSize, ushort transferLength, - bool byteAddressed, uint timeout, out double duration) + public bool Read(out byte[] buffer, out uint[] response, uint lba, uint blockSize, ushort transferLength, + bool byteAddressed, uint timeout, out double duration) { var sense = true; buffer = null; @@ -164,12 +215,28 @@ public partial class Device return ReadSingleBlock(out buffer, out response, lba, blockSize, byteAddressed, timeout, out duration); if(!_readMultipleBlockCannotSetBlockCount) - sense = ReadMultipleBlock(out buffer, out response, lba, blockSize, transferLength, byteAddressed, timeout, + { + sense = ReadMultipleBlock(out buffer, + out response, + lba, + blockSize, + transferLength, + byteAddressed, + timeout, out duration); + } if(_readMultipleBlockCannotSetBlockCount) - return ReadMultipleUsingSingle(out buffer, out response, lba, blockSize, transferLength, byteAddressed, - timeout, out duration); + { + return ReadMultipleUsingSingle(out buffer, + out response, + lba, + blockSize, + transferLength, + byteAddressed, + timeout, + out duration); + } return sense; } @@ -183,8 +250,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadSingleBlock(out byte[] buffer, out uint[] response, uint lba, uint blockSize, bool byteAddressed, - uint timeout, out double duration) + public bool ReadSingleBlock(out byte[] buffer, out uint[] response, uint lba, uint blockSize, bool byteAddressed, + uint timeout, out double duration) { uint address; buffer = new byte[blockSize]; @@ -195,19 +262,26 @@ public partial class Device else address = lba; - LastError = SendMmcCommand(MmcCommands.ReadSingleBlock, false, false, - MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, address, - blockSize, 1, ref buffer, out response, out duration, out bool sense, timeout); + LastError = SendMmcCommand(MmcCommands.ReadSingleBlock, + false, + false, + MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, + address, + blockSize, + 1, + ref buffer, + out response, + out duration, + out bool sense, + timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("MMC Device", "READ_SINGLE_BLOCK took {0} ms.", duration); + AaruConsole.DebugWriteLine(MMC_MODULE_NAME, Localization.READ_SINGLE_BLOCK_took_0_ms, duration); return sense; } - protected static bool _readMultipleBlockCannotSetBlockCount; - /// Reads multiple blocks from a SecureDigital or MultiMediaCard device /// Data buffer /// Response @@ -218,12 +292,11 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadMultipleBlock(out byte[] buffer, out uint[] response, uint lba, uint blockSize, - ushort transferLength, bool byteAddressed, uint timeout, out double duration) + public bool ReadMultipleBlock(out byte[] buffer, out uint[] response, uint lba, uint blockSize, + ushort transferLength, bool byteAddressed, uint timeout, out double duration) { buffer = new byte[transferLength * blockSize]; - double setDuration = 0; - uint address; + uint address; response = null; if(byteAddressed) @@ -231,20 +304,26 @@ public partial class Device else address = lba; - LastError = SendMmcCommand(MmcCommands.ReadMultipleBlock, false, false, - MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, address, - blockSize, transferLength, ref buffer, out response, out duration, out bool sense, + LastError = SendMmcCommand(MmcCommands.ReadMultipleBlock, + false, + false, + MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, + address, + blockSize, + transferLength, + ref buffer, + out response, + out duration, + out bool sense, timeout); Error = LastError != 0; - if(transferLength > 1) - { - duration += setDuration; - AaruConsole.DebugWriteLine("MMC Device", "READ_MULTIPLE_BLOCK took {0} ms.", duration); - } - else - AaruConsole.DebugWriteLine("MMC Device", "READ_SINGLE_BLOCK took {0} ms.", duration); + AaruConsole.DebugWriteLine(MMC_MODULE_NAME, + transferLength > 1 + ? Localization.READ_MULTIPLE_BLOCK_took_0_ms + : Localization.READ_SINGLE_BLOCK_took_0_ms, + duration); return sense; } @@ -277,22 +356,29 @@ public partial class Device else address = lba + i; - LastError = SendMmcCommand(MmcCommands.ReadSingleBlock, false, false, - MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, address, - blockSize, 1, ref blockBuffer, out response, out double blockDuration, out sense, + LastError = SendMmcCommand(MmcCommands.ReadSingleBlock, + false, + false, + MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, + address, + blockSize, + 1, + ref blockBuffer, + out response, + out double blockDuration, + out sense, timeout); Error = LastError != 0; duration += blockDuration; - if(Error || sense) - break; + if(Error || sense) break; Array.Copy(blockBuffer, 0, buffer, i * blockSize, blockSize); } - AaruConsole.DebugWriteLine("MMC Device", "Multiple READ_SINGLE_BLOCKs took {0} ms.", duration); + AaruConsole.DebugWriteLine(MMC_MODULE_NAME, Localization.Multiple_READ_SINGLE_BLOCKs_took_0_ms, duration); return sense; } @@ -307,13 +393,22 @@ public partial class Device { buffer = new byte[4]; - LastError = SendMmcCommand(MmcCommands.SendStatus, false, true, - MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAc, 0, 4, 1, - ref buffer, out response, out duration, out bool sense, timeout); + LastError = SendMmcCommand(MmcCommands.SendStatus, + false, + true, + MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAc, + 0, + 4, + 1, + ref buffer, + out response, + out duration, + out bool sense, + timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("SecureDigital Device", "SEND_STATUS took {0} ms.", duration); + AaruConsole.DebugWriteLine(MMC_MODULE_NAME, Localization.SEND_STATUS_took_0_ms, duration); return sense; } @@ -328,8 +423,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool ReadWithBlockCount(out byte[] buffer, out uint[] response, uint lba, uint blockSize, - ushort transferLength, bool byteAddressed, uint timeout, out double duration) + public bool ReadWithBlockCount(out byte[] buffer, out uint[] response, uint lba, uint blockSize, + ushort transferLength, bool byteAddressed, uint timeout, out double duration) { uint address = byteAddressed ? lba * blockSize : lba; var commands = new MmcSingleCommand[3]; @@ -344,7 +439,7 @@ public partial class Device argument = transferLength, blockSize = 0, blocks = 0, - buffer = Array.Empty() + buffer = [] }; // READ_MULTIPLE_BLOCK @@ -371,14 +466,14 @@ public partial class Device argument = 0, blockSize = 0, blocks = 0, - buffer = Array.Empty() + buffer = [] }; LastError = SendMultipleMmcCommands(commands, out duration, out bool sense, timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("SecureDigital Device", "READ_MULTIPLE_BLOCK took {0} ms.", duration); + AaruConsole.DebugWriteLine(MMC_MODULE_NAME, Localization.READ_MULTIPLE_BLOCK_took_0_ms, duration); buffer = commands[1].buffer; response = commands[1].response; diff --git a/Aaru.Devices/Device/MmcCommands/SecureDigital.cs b/Aaru.Devices/Device/MmcCommands/SecureDigital.cs index 8d72e28d6..9ed0c78b6 100644 --- a/Aaru.Devices/Device/MmcCommands/SecureDigital.cs +++ b/Aaru.Devices/Device/MmcCommands/SecureDigital.cs @@ -27,13 +27,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using Aaru.Console; +namespace Aaru.Devices; + public partial class Device { /// Reads the status register from a SecureDigital device @@ -46,13 +46,22 @@ public partial class Device { buffer = new byte[64]; - LastError = SendMmcCommand((MmcCommands)SecureDigitalCommands.SendStatus, false, true, - MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, 0, 64, 1, - ref buffer, out response, out duration, out bool sense, timeout); + LastError = SendMmcCommand((MmcCommands)SecureDigitalCommands.SendStatus, + false, + true, + MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, + 0, + 64, + 1, + ref buffer, + out response, + out duration, + out bool sense, + timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("SecureDigital Device", "SD_STATUS took {0} ms.", duration); + AaruConsole.DebugWriteLine(SD_MODULE_NAME, Localization.SD_STATUS_took_0_ms, duration); return sense; } @@ -67,13 +76,22 @@ public partial class Device { buffer = new byte[4]; - LastError = SendMmcCommand((MmcCommands)SecureDigitalCommands.SendOperatingCondition, false, true, - MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, 0, 4, 1, - ref buffer, out response, out duration, out bool sense, timeout); + LastError = SendMmcCommand((MmcCommands)SecureDigitalCommands.SendOperatingCondition, + false, + true, + MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, + 0, + 4, + 1, + ref buffer, + out response, + out duration, + out bool sense, + timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("SecureDigital Device", "SD_SEND_OP_COND took {0} ms.", duration); + AaruConsole.DebugWriteLine(SD_MODULE_NAME, Localization.SD_SEND_OP_COND_took_0_ms, duration); return sense; } @@ -88,13 +106,22 @@ public partial class Device { buffer = new byte[8]; - LastError = SendMmcCommand((MmcCommands)SecureDigitalCommands.SendScr, false, true, - MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, 0, 8, 1, - ref buffer, out response, out duration, out bool sense, timeout); + LastError = SendMmcCommand((MmcCommands)SecureDigitalCommands.SendScr, + false, + true, + MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, + 0, + 8, + 1, + ref buffer, + out response, + out duration, + out bool sense, + timeout); Error = LastError != 0; - AaruConsole.DebugWriteLine("SecureDigital Device", "SEND_SCR took {0} ms.", duration); + AaruConsole.DebugWriteLine(SD_MODULE_NAME, Localization.SEND_SCR_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/Adaptec.cs b/Aaru.Devices/Device/ScsiCommands/Adaptec.cs index ad721c54e..e3e6c3b2d 100644 --- a/Aaru.Devices/Device/ScsiCommands/Adaptec.cs +++ b/Aaru.Devices/Device/ScsiCommands/Adaptec.cs @@ -28,14 +28,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using System; using Aaru.Console; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + public partial class Device { /// Gets the underlying drive cylinder, head and index bytes for the specified SCSI LBA. @@ -67,15 +69,19 @@ public partial class Device cdb[2] = (byte)((lba & 0xFF00) >> 8); cdb[3] = (byte)(lba & 0xFF); - if(drive1) - cdb[1] += 0x20; + if(drive1) cdb[1] += 0x20; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "ADAPTEC TRANSLATE took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.ADAPTEC_TRANSLATE_took_0_ms, duration); return sense; } @@ -96,7 +102,7 @@ public partial class Device /// If set to true set the threshold from drive 1. /// Timeout. /// Duration. - public bool AdaptecSetErrorThreshold(byte threshold, out byte[] senseBuffer, bool drive1, uint timeout, + public bool AdaptecSetErrorThreshold(byte threshold, out byte[] senseBuffer, bool drive1, uint timeout, out double duration) { var buffer = new byte[1]; @@ -106,17 +112,21 @@ public partial class Device cdb[0] = (byte)ScsiCommands.AdaptecSetErrorThreshold; - if(drive1) - cdb[1] += 0x20; + if(drive1) cdb[1] += 0x20; cdb[4] = 1; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.Out, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.Out, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "ADAPTEC SET ERROR THRESHOLD took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.ADAPTEC_SET_ERROR_THRESHOLD_took_0_ms, duration); return sense; } @@ -144,17 +154,21 @@ public partial class Device cdb[0] = (byte)ScsiCommands.AdaptecTranslate; - if(drive1) - cdb[1] += 0x20; + if(drive1) cdb[1] += 0x20; cdb[4] = (byte)buffer.Length; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "ADAPTEC READ/RESET USAGE COUNTER took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.ADAPTEC_READ_RESET_USAGE_COUNTER_took_0_ms, duration); return sense; } @@ -174,12 +188,17 @@ public partial class Device cdb[0] = (byte)ScsiCommands.AdaptecWriteBuffer; - LastError = SendScsiCommand(cdb, ref oneKBuffer, out senseBuffer, timeout, ScsiDirection.Out, out duration, + LastError = SendScsiCommand(cdb, + ref oneKBuffer, + out senseBuffer, + timeout, + ScsiDirection.Out, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "ADAPTEC WRITE DATA BUFFER took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.ADAPTEC_WRITE_DATA_BUFFER_took_0_ms, duration); return sense; } @@ -197,12 +216,17 @@ public partial class Device cdb[0] = (byte)ScsiCommands.AdaptecReadBuffer; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "ADAPTEC READ DATA BUFFER took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.ADAPTEC_READ_DATA_BUFFER_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/ArchiveCorp.cs b/Aaru.Devices/Device/ScsiCommands/ArchiveCorp.cs index a2372aa1b..22cfb96c4 100644 --- a/Aaru.Devices/Device/ScsiCommands/ArchiveCorp.cs +++ b/Aaru.Devices/Device/ScsiCommands/ArchiveCorp.cs @@ -27,14 +27,15 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - -using System; using Aaru.Console; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + public partial class Device { /// Gets the underlying drive cylinder, head and index bytes for the specified SCSI LBA. @@ -56,12 +57,19 @@ public partial class Device cdb[3] = (byte)(lba & 0xFF); cdb[4] = 3; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "ARCHIVE CORP. REQUEST BLOCK ADDRESS took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.ARCHIVE_CORP_REQUEST_BLOCK_ADDRESS_took_0_ms, + duration); return sense; } @@ -83,7 +91,7 @@ public partial class Device public bool ArchiveCorpSeekBlock(out byte[] senseBuffer, bool immediate, uint lba, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var cdb = new byte[6]; senseBuffer = new byte[64]; @@ -92,15 +100,19 @@ public partial class Device cdb[2] = (byte)((lba & 0xFF00) >> 8); cdb[3] = (byte)(lba & 0xFF); - if(immediate) - cdb[1] += 0x01; + if(immediate) cdb[1] += 0x01; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "ARCHIVE CORP. SEEK BLOCK took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.ARCHIVE_CORP_SEEK_BLOCK_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/Certance.cs b/Aaru.Devices/Device/ScsiCommands/Certance.cs index 55bfaa5c8..127feeaeb 100644 --- a/Aaru.Devices/Device/ScsiCommands/Certance.cs +++ b/Aaru.Devices/Device/ScsiCommands/Certance.cs @@ -27,15 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - -using System; using System.Diagnostics.CodeAnalysis; using Aaru.Console; +namespace Aaru.Devices; + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public partial class Device { @@ -60,21 +59,25 @@ public partial class Device /// Duration. public bool CertanceParkUnpark(out byte[] senseBuffer, bool park, uint timeout, out double duration) { - byte[] buffer = Array.Empty(); + byte[] buffer = []; var cdb = new byte[6]; senseBuffer = new byte[64]; cdb[0] = (byte)ScsiCommands.CertanceParkUnpark; - if(park) - cdb[4] = 1; + if(park) cdb[4] = 1; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "CERTANCE PARK UNPARK took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.CERTANCE_PARK_UNPARK_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/Fujitsu.cs b/Aaru.Devices/Device/ScsiCommands/Fujitsu.cs index 26f0fdb37..5a4b6895a 100644 --- a/Aaru.Devices/Device/ScsiCommands/Fujitsu.cs +++ b/Aaru.Devices/Device/ScsiCommands/Fujitsu.cs @@ -27,16 +27,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using System; using System.Text; using Aaru.Console; using Aaru.Helpers; +namespace Aaru.Devices; + public partial class Device { /// Sets the data for the integrated display @@ -48,8 +48,8 @@ public partial class Device /// Timeout to wait for command execution /// Time the device took to execute the command in milliseconds /// true if the device set an error condition, false otherwise - public bool FujitsuDisplay(out byte[] senseBuffer, bool flash, FujitsuDisplayModes mode, string firstHalf, - string secondHalf, uint timeout, out double duration) + public bool FujitsuDisplay(out byte[] senseBuffer, bool flash, FujitsuDisplayModes mode, string firstHalf, + string secondHalf, uint timeout, out double duration) { byte[] tmp; var firstHalfBytes = new byte[8]; @@ -72,38 +72,42 @@ public partial class Device } if(mode != FujitsuDisplayModes.Half) + { if(!ArrayHelpers.ArrayIsNullOrWhiteSpace(firstHalfBytes) && !ArrayHelpers.ArrayIsNullOrWhiteSpace(secondHalfBytes)) displayLen = true; else if(!ArrayHelpers.ArrayIsNullOrWhiteSpace(firstHalfBytes) && ArrayHelpers.ArrayIsNullOrWhiteSpace(secondHalfBytes)) halfMsg = true; + } buffer[0] = (byte)((byte)mode << 5); - if(displayLen) - buffer[0] += 0x10; + if(displayLen) buffer[0] += 0x10; - if(flash) - buffer[0] += 0x08; + if(flash) buffer[0] += 0x08; - if(halfMsg) - buffer[0] += 0x04; + if(halfMsg) buffer[0] += 0x04; buffer[0] += 0x01; // Always ASCII - Array.Copy(firstHalfBytes, 0, buffer, 1, 8); + Array.Copy(firstHalfBytes, 0, buffer, 1, 8); Array.Copy(secondHalfBytes, 0, buffer, 9, 8); cdb[0] = (byte)ScsiCommands.FujitsuDisplay; cdb[6] = (byte)buffer.Length; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.Out, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.Out, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "FUJITSU DISPLAY took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.FUJITSU_DISPLAY_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/HL-DT-ST.cs b/Aaru.Devices/Device/ScsiCommands/HL-DT-ST.cs index b21f2b97a..dca8dfd60 100644 --- a/Aaru.Devices/Device/ScsiCommands/HL-DT-ST.cs +++ b/Aaru.Devices/Device/ScsiCommands/HL-DT-ST.cs @@ -27,15 +27,21 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System.Collections.Generic; +using Aaru.CommonTypes.Enums; +using Aaru.Console; +using Aaru.Decoders.DVD; +using Aaru.Helpers; + namespace Aaru.Devices; -using Aaru.Console; - public partial class Device { + readonly Sector _decoding = new(); + /// Reads a "raw" sector from DVD on HL-DT-ST drives. /// true if the command failed and contains the sense buffer. /// Buffer where the HL-DT-ST READ DVD (RAW) response will be stored @@ -51,25 +57,59 @@ public partial class Device var cdb = new byte[12]; buffer = new byte[2064 * transferLength]; + uint cacheDataOffset = 0x80000000 + lba % 96 * 2064; + cdb[0] = (byte)ScsiCommands.HlDtStVendor; cdb[1] = 0x48; cdb[2] = 0x49; cdb[3] = 0x54; cdb[4] = 0x01; - cdb[6] = (byte)((lba & 0xFF000000) >> 24); - cdb[7] = (byte)((lba & 0xFF0000) >> 16); - cdb[8] = (byte)((lba & 0xFF00) >> 8); - cdb[9] = (byte)(lba & 0xFF); + cdb[6] = (byte)((cacheDataOffset & 0xFF000000) >> 24); + cdb[7] = (byte)((cacheDataOffset & 0xFF0000) >> 16); + cdb[8] = (byte)((cacheDataOffset & 0xFF00) >> 8); + cdb[9] = (byte)(cacheDataOffset & 0xFF); cdb[10] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[11] = (byte)(buffer.Length & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "HL-DT-ST READ DVD (RAW) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.HL_DT_ST_READ_DVD_RAW_took_0_ms, duration); + + if(!CheckSectorNumber(buffer, lba, transferLength)) return true; + + if(_decoding.Scramble(buffer, transferLength, out byte[] scrambledBuffer) != ErrorNumber.NoError) return true; + + buffer = scrambledBuffer; return sense; } + + /// + /// Makes sure the data's sector number is the one expected. + /// + /// Data buffer + /// First consecutive LBA of the buffer + /// How many blocks to in buffer + /// false if any sector is not matching expected value, else true + static bool CheckSectorNumber(IReadOnlyList buffer, uint firstLba, uint transferLength) + { + for(var i = 0; i < transferLength; i++) + { + byte[] sectorBuffer = [0x0, buffer[1 + 2064 * i], buffer[2 + 2064 * i], buffer[3 + 2064 * i]]; + + var sectorNumber = BigEndianBitConverter.ToUInt32(sectorBuffer, 0); + + if(sectorNumber != firstLba + i + 0x30000) return false; + } + + return true; + } } \ No newline at end of file diff --git a/Aaru.Devices/Device/ScsiCommands/HP.cs b/Aaru.Devices/Device/ScsiCommands/HP.cs index 82ea451cf..77674dd8e 100644 --- a/Aaru.Devices/Device/ScsiCommands/HP.cs +++ b/Aaru.Devices/Device/ScsiCommands/HP.cs @@ -27,13 +27,15 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using Aaru.Console; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + public partial class Device { /// Sends the HP READ LONG vendor command @@ -47,7 +49,7 @@ public partial class Device /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. public bool HpReadLong(out byte[] buffer, out byte[] senseBuffer, bool relAddr, uint address, ushort blockBytes, - bool pba, uint timeout, out double duration) => + bool pba, uint timeout, out double duration) => HpReadLong(out buffer, out senseBuffer, relAddr, address, 0, blockBytes, pba, false, timeout, out duration); /// Sends the HP READ LONG vendor command @@ -66,15 +68,14 @@ public partial class Device /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. public bool HpReadLong(out byte[] buffer, out byte[] senseBuffer, bool relAddr, uint address, ushort transferLen, - ushort blockBytes, bool pba, bool sectorCount, uint timeout, out double duration) + ushort blockBytes, bool pba, bool sectorCount, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; cdb[0] = (byte)ScsiCommands.ReadLong; - if(relAddr) - cdb[1] += 0x01; + if(relAddr) cdb[1] += 0x01; cdb[2] = (byte)((address & 0xFF000000) >> 24); cdb[3] = (byte)((address & 0xFF0000) >> 16); @@ -83,20 +84,23 @@ public partial class Device cdb[7] = (byte)((transferLen & 0xFF00) >> 8); cdb[8] = (byte)(transferLen & 0xFF); - if(pba) - cdb[9] += 0x80; + if(pba) cdb[9] += 0x80; - if(sectorCount) - cdb[9] += 0x40; + if(sectorCount) cdb[9] += 0x40; buffer = sectorCount ? new byte[blockBytes * transferLen] : new byte[transferLen]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "HP READ LONG took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.HP_READ_LONG_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/Kreon.cs b/Aaru.Devices/Device/ScsiCommands/Kreon.cs index 4e530528e..99692bd8e 100644 --- a/Aaru.Devices/Device/ScsiCommands/Kreon.cs +++ b/Aaru.Devices/Device/ScsiCommands/Kreon.cs @@ -27,14 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using System; using Aaru.Console; +namespace Aaru.Devices; + public partial class Device { /// Sets the drive to the xtreme unlocked state @@ -46,19 +46,24 @@ public partial class Device { senseBuffer = new byte[64]; var cdb = new byte[6]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.KreonCommand; cdb[1] = 0x08; cdb[2] = 0x01; cdb[3] = 0x01; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "KREON DEPRECATED UNLOCK took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.KREON_DEPRECATED_UNLOCK_took_0_ms, duration); return sense; } @@ -97,7 +102,7 @@ public partial class Device { senseBuffer = new byte[64]; var cdb = new byte[6]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.KreonCommand; cdb[1] = 0x08; @@ -105,12 +110,17 @@ public partial class Device cdb[3] = 0x11; cdb[4] = (byte)state; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "KREON SET LOCK STATE took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.KREON_SET_LOCK_STATE_took_0_ms, duration); return sense || Error; } @@ -134,28 +144,27 @@ public partial class Device cdb[2] = 0x01; cdb[3] = 0x10; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "KREON GET FEATURE LIST took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.KREON_GET_FEATURE_LIST_took_0_ms, duration); - if(sense) - return true; + if(sense) return true; - if(buffer[0] != 0xA5 || - buffer[1] != 0x5A || - buffer[2] != 0x5A || - buffer[3] != 0xA5) - return true; + if(buffer[0] != 0xA5 || buffer[1] != 0x5A || buffer[2] != 0x5A || buffer[3] != 0xA5) return true; for(var i = 4; i < 26; i += 2) { var feature = BitConverter.ToUInt16(buffer, i); - if(feature == 0x0000) - break; + if(feature == 0x0000) break; switch(feature) { @@ -213,7 +222,7 @@ public partial class Device /// The SS sector. /// Request number. public bool KreonExtractSs(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration, - byte requestNumber = 0x00) + byte requestNumber = 0x00) { buffer = new byte[2048]; var cdb = new byte[12]; @@ -232,12 +241,17 @@ public partial class Device cdb[10] = requestNumber; cdb[11] = 0xC0; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "KREON EXTRACT SS took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.KREON_EXTRACT_SS_took_0_ms, duration); return sense || Error; } diff --git a/Aaru.Devices/Device/ScsiCommands/MMC.cs b/Aaru.Devices/Device/ScsiCommands/MMC.cs index 98c31e8f8..b57b9c16d 100644 --- a/Aaru.Devices/Device/ScsiCommands/MMC.cs +++ b/Aaru.Devices/Device/ScsiCommands/MMC.cs @@ -27,16 +27,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using System; using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Console; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] public partial class Device { /// Sends the MMC GET CONFIGURATION command for all Features @@ -57,7 +60,11 @@ public partial class Device /// Duration in milliseconds it took for the device to execute the command. public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, uint timeout, out double duration) => - GetConfiguration(out buffer, out senseBuffer, startingFeatureNumber, MmcGetConfigurationRt.All, timeout, + GetConfiguration(out buffer, + out senseBuffer, + startingFeatureNumber, + MmcGetConfigurationRt.All, + timeout, out duration); /// Sends the MMC GET CONFIGURATION command @@ -68,8 +75,8 @@ public partial class Device /// Duration in milliseconds it took for the device to execute the command. /// Starting Feature number. /// Return type, . - public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, - MmcGetConfigurationRt rt, uint timeout, out double duration) + public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, + MmcGetConfigurationRt rt, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; @@ -83,13 +90,17 @@ public partial class Device cdb[8] = (byte)(buffer.Length & 0xFF); cdb[9] = 0; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - if(sense) - return true; + if(sense) return true; var confLength = (ushort)((buffer[2] << 8) + buffer[3] + 4); buffer = new byte[confLength]; @@ -97,14 +108,24 @@ public partial class Device cdb[8] = (byte)(buffer.Length & 0xFF); senseBuffer = new byte[64]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", - "GET CONFIGURATION (Starting Feature Number: {1}, Return Type: {2}, Sense: {3}, Last Error: {4}) took {0} ms.", - duration, startingFeatureNumber, rt, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .GET_CONFIGURATION_Starting_Feature_Number_1_Return_Type_2_Sense_3_Last_Error_4_took_0_ms, + duration, + startingFeatureNumber, + rt, + sense, + LastError); return sense; } @@ -120,9 +141,9 @@ public partial class Device /// Which disc structure are we requesting /// AGID used in medium copy protection /// Duration in milliseconds it took for the device to execute the command. - public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType, - uint address, byte layerNumber, MmcDiscStructureFormat format, byte agid, - uint timeout, out double duration) + public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType, + uint address, byte layerNumber, MmcDiscStructureFormat format, byte agid, + uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[12]; @@ -140,45 +161,33 @@ public partial class Device cdb[9] = (byte)(buffer.Length & 0xFF); cdb[10] = (byte)((agid & 0x03) << 6); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - if(sense) - return true; + if(sense) return true; var strctLength = (ushort)((buffer[0] << 8) + buffer[1] + 2); // WORKAROUND: Some drives return incorrect length information. As these structures are fixed length just apply known length. if(mediaType == MmcDiscStructureMediaType.Bd) - switch(format) - { - case MmcDiscStructureFormat.DiscInformation: - buffer = new byte[4100]; - - break; - case MmcDiscStructureFormat.BdBurstCuttingArea: - buffer = new byte[68]; - - break; - case MmcDiscStructureFormat.BdDds: - buffer = new byte[strctLength < 100 ? 100 : strctLength]; - - break; - case MmcDiscStructureFormat.CartridgeStatus: - buffer = new byte[8]; - - break; - case MmcDiscStructureFormat.BdSpareAreaInformation: - buffer = new byte[16]; - - break; - default: - buffer = new byte[strctLength]; - - break; - } + { + buffer = format switch + { + MmcDiscStructureFormat.DiscInformation => new byte[4100], + MmcDiscStructureFormat.BdBurstCuttingArea => new byte[68], + MmcDiscStructureFormat.BdDds => new byte[strctLength < 100 ? 100 : strctLength], + MmcDiscStructureFormat.CartridgeStatus => new byte[8], + MmcDiscStructureFormat.BdSpareAreaInformation => new byte[16], + _ => new byte[strctLength] + }; + } else buffer = new byte[strctLength]; @@ -186,14 +195,27 @@ public partial class Device cdb[9] = (byte)(buffer.Length & 0xFF); senseBuffer = new byte[64]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", - "READ DISC STRUCTURE (Media Type: {1}, Address: {2}, Layer Number: {3}, Format: {4}, AGID: {5}, Sense: {6}, Last Error: {7}) took {0} ms.", - duration, mediaType, address, layerNumber, format, agid, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .READ_DISC_STRUCTURE_Media_Type_1_Address_2_Layer_Number_3_Format_4_AGID_5_Sense_6_Last_Error_7_took_0_ms, + duration, + mediaType, + address, + layerNumber, + format, + agid, + sense, + LastError); return sense; } @@ -287,8 +309,8 @@ public partial class Device /// Track/Session number /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. - public bool ReadTocPmaAtip(out byte[] buffer, out byte[] senseBuffer, bool msf, byte format, - byte trackSessionNumber, uint timeout, out double duration) + public bool ReadTocPmaAtip(out byte[] buffer, out byte[] senseBuffer, bool msf, byte format, + byte trackSessionNumber, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; @@ -297,15 +319,19 @@ public partial class Device cdb[0] = (byte)ScsiCommands.ReadTocPmaAtip; - if(msf) - cdb[1] = 0x02; + if(msf) cdb[1] = 0x02; cdb[2] = (byte)(format & 0x0F); cdb[6] = trackSessionNumber; cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8); cdb[8] = (byte)(tmpBuffer.Length & 0xFF); - LastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref tmpBuffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; @@ -317,25 +343,42 @@ public partial class Device { Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length); - AaruConsole.DebugWriteLine("SCSI Device", - "READ TOC/PMA/ATIP took (MSF: {1}, Format: {2}, Track/Session Number: {3}, Sense: {4}, LastError: {5}) {0} ms.", - duration, msf, format, trackSessionNumber, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .READ_TOC_PMA_ATIP_took_MSF_1_Format_2_Track_Session_Number_3_Sense_4_LastError_5_0_ms, + duration, + msf, + format, + trackSessionNumber, + sense, + LastError); return sense; } double tmpDuration = duration; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); Error = LastError != 0; duration += tmpDuration; - AaruConsole.DebugWriteLine("SCSI Device", - "READ TOC/PMA/ATIP took (MSF: {1}, Format: {2}, Track/Session Number: {3}, Sense: {4}, LastError: {5}) {0} ms.", - duration, msf, format, trackSessionNumber, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .READ_TOC_PMA_ATIP_took_MSF_1_Format_2_Track_Session_Number_3_Sense_4_LastError_5_0_ms, + duration, + msf, + format, + trackSessionNumber, + sense, + LastError); return sense; } @@ -347,7 +390,10 @@ public partial class Device /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) => - ReadDiscInformation(out buffer, out senseBuffer, MmcDiscInformationDataTypes.DiscInformation, timeout, + ReadDiscInformation(out buffer, + out senseBuffer, + MmcDiscInformationDataTypes.DiscInformation, + timeout, out duration); /// Sends the MMC READ DISC INFORMATION command @@ -357,8 +403,8 @@ public partial class Device /// Which disc information to read /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. - public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, MmcDiscInformationDataTypes dataType, - uint timeout, out double duration) + public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, MmcDiscInformationDataTypes dataType, + uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; @@ -369,22 +415,29 @@ public partial class Device cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8); cdb[8] = (byte)(tmpBuffer.Length & 0xFF); - LastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref tmpBuffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; var strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2); - if(strctLength > tmpBuffer.Length) - strctLength = (uint)tmpBuffer.Length; + if(strctLength > tmpBuffer.Length) strctLength = (uint)tmpBuffer.Length; buffer = new byte[strctLength]; Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length); - AaruConsole.DebugWriteLine("SCSI Device", - "READ DISC INFORMATION (Data Type: {1}, Sense: {2}, Last Error: {3}) took {0} ms.", - duration, dataType, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.READ_DISC_INFORMATION_Data_Type_1_Sense_2_Last_Error_3_took_0_ms, + duration, + dataType, + sense, + LastError); return sense; } @@ -418,11 +471,9 @@ public partial class Device cdb[0] = (byte)ScsiCommands.ReadCd; cdb[1] = (byte)((byte)expectedSectorType << 2); - if(dap) - cdb[1] += 0x02; + if(dap) cdb[1] += 0x02; - if(relAddr) - cdb[1] += 0x01; + if(relAddr) cdb[1] += 0x01; cdb[2] = (byte)((lba & 0xFF000000) >> 24); cdb[3] = (byte)((lba & 0xFF0000) >> 16); @@ -434,28 +485,44 @@ public partial class Device cdb[9] = (byte)((byte)c2Error << 1); cdb[9] += (byte)((byte)headerCodes << 5); - if(sync) - cdb[9] += 0x80; + if(sync) cdb[9] += 0x80; - if(userData) - cdb[9] += 0x10; + if(userData) cdb[9] += 0x10; - if(edcEcc) - cdb[9] += 0x08; + if(edcEcc) cdb[9] += 0x08; cdb[10] = (byte)subchannel; buffer = new byte[blockSize * transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", - "READ CD (LBA: {1}, Block Size: {2}, Transfer Length: {3}, Expected Sector Type: {4}, DAP: {5}, Relative Address: {6}, Sync: {7}, Headers: {8}, User Data: {9}, ECC/EDC: {10}, C2: {11}, Subchannel: {12}, Sense: {13}, Last Error: {14}) took {0} ms.", - duration, lba, blockSize, transferLength, expectedSectorType, dap, relAddr, sync, - headerCodes, userData, edcEcc, c2Error, subchannel, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .READ_CD_LBA_1_Block_Size_2_Transfer_Length_3_Expected_Sector_Type_4_DAP_5_Relative_Address_6_Sync_7_Headers_8_User_Data_9_ECC_EDC_10_C2_11_Subchannel_12_Sense_13_Last_Error_14_took_0_ms, + duration, + lba, + blockSize, + transferLength, + expectedSectorType, + dap, + relAddr, + sync, + headerCodes, + userData, + edcEcc, + c2Error, + subchannel, + sense, + LastError); return sense; } @@ -488,8 +555,7 @@ public partial class Device cdb[0] = (byte)ScsiCommands.ReadCdMsf; cdb[1] = (byte)((byte)expectedSectorType << 2); - if(dap) - cdb[1] += 0x02; + if(dap) cdb[1] += 0x02; cdb[3] = (byte)((startMsf & 0xFF0000) >> 16); cdb[4] = (byte)((startMsf & 0xFF00) >> 8); @@ -500,14 +566,11 @@ public partial class Device cdb[9] = (byte)((byte)c2Error << 1); cdb[9] += (byte)((byte)headerCodes << 5); - if(sync) - cdb[9] += 0x80; + if(sync) cdb[9] += 0x80; - if(userData) - cdb[9] += 0x10; + if(userData) cdb[9] += 0x10; - if(edcEcc) - cdb[9] += 0x08; + if(edcEcc) cdb[9] += 0x08; cdb[10] = (byte)subchannel; @@ -515,15 +578,33 @@ public partial class Device buffer = new byte[blockSize * transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", - "READ CD MSF (Start MSF: {1}, End MSF: {2}, Block Size: {3}, Expected Sector Type: {4}, DAP: {5}, Sync: {6}, Headers: {7}, User Data: {8}, ECC/EDC: {9}, C2: {10}, Subchannel: {11}, Sense: {12}, LastError: {13}) took {0} ms.", - duration, startMsf, endMsf, blockSize, expectedSectorType, dap, sync, headerCodes, - userData, edcEcc, c2Error, subchannel, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .READ_CD_MSF_Start_MSF_1_End_MSF_2_Block_Size_3_Expected_Sector_Type_4_DAP_5_Sync_6_Headers_7_User_Data_8_ECC_EDC_9_C2_10_Subchannel_11_Sense_12_LastError_13_took_0_ms, + duration, + startMsf, + endMsf, + blockSize, + expectedSectorType, + dap, + sync, + headerCodes, + userData, + edcEcc, + c2Error, + subchannel, + sense, + LastError); return sense; } @@ -556,24 +637,32 @@ public partial class Device { senseBuffer = new byte[64]; var cdb = new byte[6]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.PreventAllowMediumRemoval; - if(prevent) - cdb[4] += 0x01; + if(prevent) cdb[4] += 0x01; - if(persistent) - cdb[4] += 0x02; + if(persistent) cdb[4] += 0x02; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", - "PREVENT ALLOW MEDIUM REMOVAL (Persistent: {1}, Prevent: {2}, Sense: {3}, LastError: {4}) took {0} ms.", - duration, persistent, prevent, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .PREVENT_ALLOW_MEDIUM_REMOVAL_Persistent_1_Prevent_2_Sense_3_LastError_4_took_0_ms, + duration, + persistent, + prevent, + sense, + LastError); return sense; } @@ -626,12 +715,11 @@ public partial class Device { senseBuffer = new byte[64]; var cdb = new byte[6]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.StartStopUnit; - if(immediate) - cdb[1] += 0x01; + if(immediate) cdb[1] += 0x01; if(changeFormatLayer) { @@ -640,24 +728,35 @@ public partial class Device } else { - if(loadEject) - cdb[4] += 0x02; + if(loadEject) cdb[4] += 0x02; - if(start) - cdb[4] += 0x01; + if(start) cdb[4] += 0x01; } cdb[4] += (byte)((powerConditions & 0x0F) << 4); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", - "START STOP UNIT (Immediate: {1}, FormatLayer: {2}, Power Conditions: {3}, Change Format Layer: {4}, Load/Eject: {5}, Start: {6}, Sense: {7}, Last Error: {8}) took {0} ms.", - duration, immediate, formatLayer, powerConditions, changeFormatLayer, loadEject, - start, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .START_STOP_UNIT_Immediate_1_FormatLayer_2_Power_Conditions_3_Change_Format_Layer_4_Load_Eject_5_Start_6_Sense_7_Last_Error_8_took_0_ms, + duration, + immediate, + formatLayer, + powerConditions, + changeFormatLayer, + loadEject, + start, + sense, + LastError); return sense; } @@ -685,17 +784,23 @@ public partial class Device buffer = new byte[23]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ READ SUB-CHANNEL (MCN, Sense {1}, Last Error {2}) took {0} ms.", - duration, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.READ_READ_SUB_CHANNEL_MCN_Sense_1_Last_Error_2_took_0_ms, + duration, + sense, + LastError); - if(!sense && - (buffer[8] & 0x80) == 0x80) - mcn = Encoding.ASCII.GetString(buffer, 9, 13); + if(!sense && (buffer[8] & 0x80) == 0x80) mcn = Encoding.ASCII.GetString(buffer, 9, 13); return sense; } @@ -726,18 +831,25 @@ public partial class Device buffer = new byte[23]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", - "READ READ SUB-CHANNEL (ISRC, Track Number: {1}, Sense: {2}, Last Error: {3}) took {0} ms.", - duration, trackNumber, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .READ_READ_SUB_CHANNEL_ISRC_Track_Number_1_Sense_2_Last_Error_3_took_0_ms, + duration, + trackNumber, + sense, + LastError); - if(!sense && - (buffer[8] & 0x80) == 0x80) - isrc = Encoding.ASCII.GetString(buffer, 9, 12); + if(!sense && (buffer[8] & 0x80) == 0x80) isrc = Encoding.ASCII.GetString(buffer, 9, 12); return sense; } @@ -750,12 +862,12 @@ public partial class Device /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. /// true if the command failed and contains the sense buffer. - public bool SetCdSpeed(out byte[] senseBuffer, RotationalControl rotationalControl, ushort readSpeed, - ushort writeSpeed, uint timeout, out double duration) + public bool SetCdSpeed(out byte[] senseBuffer, RotationalControl rotationalControl, ushort readSpeed, + ushort writeSpeed, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[12]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.SetCdRomSpeed; cdb[1] = (byte)((byte)rotationalControl & 0x03); @@ -764,14 +876,25 @@ public partial class Device cdb[4] = (byte)((writeSpeed & 0xFF00) >> 8); cdb[5] = (byte)(writeSpeed & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", - "SET CD SPEED (Rotational Control: {1}, Read Speed: {2}, Write Speed: {3}, Sense: {4}, Last Error: {5}) took {0} ms.", - duration, rotationalControl, readSpeed, writeSpeed, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .SET_CD_SPEED_Rotational_Control_1_Read_Speed_2_Write_Speed_3_Sense_4_Last_Error_5_took_0_ms, + duration, + rotationalControl, + readSpeed, + writeSpeed, + sense, + LastError); return sense; } @@ -785,8 +908,8 @@ public partial class Device /// Duration in milliseconds it took for the device to execute the command. /// Report information of non-closed tracks /// Type of information to retrieve - public bool ReadTrackInformation(out byte[] buffer, out byte[] senseBuffer, bool open, TrackInformationType type, - uint address, uint timeout, out double duration) + public bool ReadTrackInformation(out byte[] buffer, out byte[] senseBuffer, bool open, TrackInformationType type, + uint address, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; @@ -801,17 +924,24 @@ public partial class Device cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[8] = (byte)(buffer.Length & 0xFF); - if(open) - cdb[1] += 4; + if(open) cdb[1] += 4; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", - "READ TRACK INFORMATION (Data Type: {1}, Sense: {2}, Last Error: {3}) took {0} ms.", - duration, type, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.READ_TRACK_INFORMATION_Data_Type_1_Sense_2_Last_Error_3_took_0_ms, + duration, + type, + sense, + LastError); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/MediaTek.cs b/Aaru.Devices/Device/ScsiCommands/MediaTek.cs index 584353f57..aa08ae47a 100644 --- a/Aaru.Devices/Device/ScsiCommands/MediaTek.cs +++ b/Aaru.Devices/Device/ScsiCommands/MediaTek.cs @@ -27,13 +27,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using Aaru.Console; +namespace Aaru.Devices; + public partial class Device { /// Reads from the drive's DRAM. @@ -62,12 +62,17 @@ public partial class Device cdb[8] = (byte)((length & 0xFF00) >> 8); cdb[9] = (byte)(length & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MediaTek READ DRAM took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MediaTek_READ_DRAM_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/MiniDisc.cs b/Aaru.Devices/Device/ScsiCommands/MiniDisc.cs index 0e10ff229..ab326e019 100644 --- a/Aaru.Devices/Device/ScsiCommands/MiniDisc.cs +++ b/Aaru.Devices/Device/ScsiCommands/MiniDisc.cs @@ -27,18 +27,17 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable InconsistentNaming -namespace Aaru.Devices; - -using System; using Aaru.Console; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + public partial class Device { /// Reads the data TOC from an MD-DATA @@ -49,23 +48,28 @@ public partial class Device /// true if the command failed and contains the sense buffer. public bool MiniDiscReadDataTOC(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) { - ushort transferLength = 2336; + const ushort transferLength = 2336; senseBuffer = new byte[64]; var cdb = new byte[10]; cdb[0] = (byte)ScsiCommands.MiniDiscReadDTOC; - cdb[7] = (byte)((transferLength & 0xFF00) >> 8); - cdb[8] = (byte)(transferLength & 0xFF); + cdb[7] = (transferLength & 0xFF00) >> 8; + cdb[8] = transferLength & 0xFF; buffer = new byte[transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MINIDISC READ DTOC took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MINIDISC_READ_DTOC_took_0_ms, duration); return sense; } @@ -80,7 +84,7 @@ public partial class Device public bool MiniDiscReadUserTOC(out byte[] buffer, out byte[] senseBuffer, uint sector, uint timeout, out double duration) { - ushort transferLength = 2336; + const ushort transferLength = 2336; senseBuffer = new byte[64]; var cdb = new byte[10]; @@ -89,18 +93,23 @@ public partial class Device cdb[2] = (byte)((sector & 0xFF000000) >> 24); cdb[3] = (byte)((sector & 0xFF0000) >> 16); cdb[4] = (byte)((sector & 0xFF00) >> 8); - cdb[5] = (byte)(sector & 0xFF); - cdb[7] = (byte)((transferLength & 0xFF00) >> 8); - cdb[8] = (byte)(transferLength & 0xFF); + cdb[5] = (byte)(sector & 0xFF); + cdb[7] = (transferLength & 0xFF00) >> 8; + cdb[8] = transferLength & 0xFF; buffer = new byte[transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MINIDISC READ UTOC took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MINIDISC_READ_UTOC_took_0_ms, duration); return sense; } @@ -113,23 +122,28 @@ public partial class Device /// true if the command failed and contains the sense buffer. public bool MiniDiscD5(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) { - ushort transferLength = 4; + const ushort transferLength = 4; senseBuffer = new byte[64]; var cdb = new byte[10]; cdb[0] = (byte)ScsiCommands.MiniDiscD5; - cdb[7] = (byte)((transferLength & 0xFF00) >> 8); - cdb[8] = (byte)(transferLength & 0xFF); + cdb[7] = 0; + cdb[8] = transferLength & 0xFF; buffer = new byte[transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MINIDISC command D5h took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MINIDISC_command_D5h_took_0_ms, duration); return sense; } @@ -147,14 +161,19 @@ public partial class Device cdb[0] = (byte)ScsiCommands.MiniDiscStopPlay; - buffer = Array.Empty(); + buffer = []; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MINIDISC STOP PLAY took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MINIDISC_STOP_PLAY_took_0_ms, duration); return sense; } @@ -167,23 +186,28 @@ public partial class Device /// true if the command failed and contains the sense buffer. public bool MiniDiscReadPosition(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) { - ushort transferLength = 4; + const ushort transferLength = 4; senseBuffer = new byte[64]; var cdb = new byte[10]; cdb[0] = (byte)ScsiCommands.MiniDiscReadPosition; - cdb[7] = (byte)((transferLength & 0xFF00) >> 8); - cdb[8] = (byte)(transferLength & 0xFF); + cdb[7] = 0; + cdb[8] = transferLength & 0xFF; buffer = new byte[transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MINIDISC READ POSITION took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MINIDISC_READ_POSITION_took_0_ms, duration); return sense; } @@ -196,23 +220,28 @@ public partial class Device /// true if the command failed and contains the sense buffer. public bool MiniDiscGetType(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) { - ushort transferLength = 8; + const ushort transferLength = 8; senseBuffer = new byte[64]; var cdb = new byte[10]; cdb[0] = (byte)ScsiCommands.MiniDiscGetType; - cdb[7] = (byte)((transferLength & 0xFF00) >> 8); - cdb[8] = (byte)(transferLength & 0xFF); + cdb[7] = 0; + cdb[8] = transferLength & 0xFF; buffer = new byte[transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MINIDISC GET TYPE took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MINIDISC_GET_TYPE_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/NEC.cs b/Aaru.Devices/Device/ScsiCommands/NEC.cs index 3fa30dfdc..06284c4a5 100644 --- a/Aaru.Devices/Device/ScsiCommands/NEC.cs +++ b/Aaru.Devices/Device/ScsiCommands/NEC.cs @@ -27,13 +27,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using Aaru.Console; +namespace Aaru.Devices; + public partial class Device { /// Sends the NEC READ CD-DA command @@ -60,12 +60,17 @@ public partial class Device buffer = new byte[2352 * transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ CD-DA took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.NEC_READ_CD_DA_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/Optical.cs b/Aaru.Devices/Device/ScsiCommands/Optical.cs index 1fa238fa4..1085ffd0e 100644 --- a/Aaru.Devices/Device/ScsiCommands/Optical.cs +++ b/Aaru.Devices/Device/ScsiCommands/Optical.cs @@ -27,15 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - -using System; using Aaru.Console; using Aaru.Decoders.SCSI; +namespace Aaru.Devices; + public partial class Device { /// Scan the medium for a contiguous set of written or blank logical blocks @@ -59,39 +58,33 @@ public partial class Device /// Number of contiguous blocks to find /// First LBA found public bool MediumScan(out byte[] senseBuffer, bool written, bool advancedScan, bool reverse, bool partial, - bool relAddr, uint lba, uint requested, uint scanLength, out uint foundLba, - out uint foundBlocks, uint timeout, out double duration) + bool relAddr, uint lba, uint requested, uint scanLength, out uint foundLba, + out uint foundBlocks, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; foundLba = 0; foundBlocks = 0; cdb[0] = (byte)ScsiCommands.MediumScan; - if(written) - cdb[1] += 0x10; + if(written) cdb[1] += 0x10; - if(advancedScan) - cdb[1] += 0x08; + if(advancedScan) cdb[1] += 0x08; - if(reverse) - cdb[1] += 0x04; + if(reverse) cdb[1] += 0x04; - if(partial) - cdb[1] += 0x02; + if(partial) cdb[1] += 0x02; - if(relAddr) - cdb[1] += 0x01; + if(relAddr) cdb[1] += 0x01; cdb[2] = (byte)((lba & 0xFF000000) >> 24); cdb[3] = (byte)((lba & 0xFF0000) >> 16); cdb[4] = (byte)((lba & 0xFF00) >> 8); cdb[5] = (byte)(lba & 0xFF); - if(requested > 0 || - scanLength > 1) + if(requested > 0 || scanLength > 1) { buffer = new byte[8]; buffer[0] = (byte)((requested & 0xFF000000) >> 24); @@ -105,28 +98,33 @@ public partial class Device cdb[8] = 8; } - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, - buffer.Length == 0 ? ScsiDirection.None : ScsiDirection.Out, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + buffer.Length == 0 ? ScsiDirection.None : ScsiDirection.Out, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MEDIUM SCAN took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MEDIUM_SCAN_took_0_ms, duration); - if(Error) - return sense; + if(Error) return sense; DecodedSense? decodedSense = Sense.Decode(senseBuffer); switch(decodedSense?.SenseKey) { - case SenseKeys.NoSense: return false; + case SenseKeys.NoSense: + return false; case SenseKeys.Equal when decodedSense.Value.Fixed?.InformationValid == true: foundBlocks = decodedSense.Value.Fixed.Value.CommandSpecific; foundLba = decodedSense.Value.Fixed.Value.Information; return false; - default: return sense; + default: + return sense; } } } \ No newline at end of file diff --git a/Aaru.Devices/Device/ScsiCommands/Pioneer.cs b/Aaru.Devices/Device/ScsiCommands/Pioneer.cs index 1f80cdd8f..efb6c51a5 100644 --- a/Aaru.Devices/Device/ScsiCommands/Pioneer.cs +++ b/Aaru.Devices/Device/ScsiCommands/Pioneer.cs @@ -27,13 +27,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using Aaru.Console; +namespace Aaru.Devices; + public partial class Device { /// Sends the Pioneer READ CD-DA command @@ -64,12 +64,17 @@ public partial class Device buffer = new byte[blockSize * transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PIONEER READ CD-DA took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PIONEER_READ_CD_DA_took_0_ms, duration); return sense; } @@ -102,12 +107,17 @@ public partial class Device var transferLength = (uint)((cdb[7] - cdb[3]) * 60 * 75 + (cdb[8] - cdb[4]) * 75 + (cdb[9] - cdb[5])); buffer = new byte[blockSize * transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PIONEER READ CD-DA MSF took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PIONEER_READ_CD_DA_MSF_took_0_ms, duration); return sense; } @@ -125,8 +135,8 @@ public partial class Device /// If set to true, returns all 2352 bytes of sector data. /// Start block address. /// How many blocks to read. - public bool PioneerReadCdXa(out byte[] buffer, out byte[] senseBuffer, uint lba, uint transferLength, - bool errorFlags, bool wholeSector, uint timeout, out double duration) + public bool PioneerReadCdXa(out byte[] buffer, out byte[] senseBuffer, uint lba, uint transferLength, + bool errorFlags, bool wholeSector, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[12]; @@ -156,12 +166,17 @@ public partial class Device cdb[6] = 0x00; } - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PIONEER READ CD-XA took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PIONEER_READ_CD_XA_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/Plasmon.cs b/Aaru.Devices/Device/ScsiCommands/Plasmon.cs index 2455d1d08..4b519e517 100644 --- a/Aaru.Devices/Device/ScsiCommands/Plasmon.cs +++ b/Aaru.Devices/Device/ScsiCommands/Plasmon.cs @@ -27,13 +27,15 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using Aaru.Console; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + public partial class Device { /// Sends the Plasmon READ LONG vendor command @@ -46,8 +48,8 @@ public partial class Device /// If set to true address contain physical block address. /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. - public bool PlasmonReadLong(out byte[] buffer, out byte[] senseBuffer, bool relAddr, uint address, - ushort blockBytes, bool pba, uint timeout, out double duration) => + public bool PlasmonReadLong(out byte[] buffer, out byte[] senseBuffer, bool relAddr, uint address, + ushort blockBytes, bool pba, uint timeout, out double duration) => HpReadLong(out buffer, out senseBuffer, relAddr, address, 0, blockBytes, pba, false, timeout, out duration); /// Sends the Plasmon READ LONG vendor command @@ -65,10 +67,17 @@ public partial class Device /// /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. - public bool PlasmonReadLong(out byte[] buffer, out byte[] senseBuffer, bool relAddr, uint address, - ushort transferLen, ushort blockBytes, bool pba, bool sectorCount, uint timeout, - out double duration) => HpReadLong(out buffer, out senseBuffer, relAddr, address, - transferLen, blockBytes, pba, sectorCount, timeout, + public bool PlasmonReadLong(out byte[] buffer, out byte[] senseBuffer, bool relAddr, uint address, + ushort transferLen, ushort blockBytes, bool pba, bool sectorCount, uint timeout, + out double duration) => HpReadLong(out buffer, + out senseBuffer, + relAddr, + address, + transferLen, + blockBytes, + pba, + sectorCount, + timeout, out duration); /// Retrieves the logical or physical block address for the specified @@ -79,8 +88,8 @@ public partial class Device /// If set to true address contain a physical block address. /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. - public bool PlasmonReadSectorLocation(out byte[] buffer, out byte[] senseBuffer, uint address, bool pba, - uint timeout, out double duration) + public bool PlasmonReadSectorLocation(out byte[] buffer, out byte[] senseBuffer, uint address, bool pba, + uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; @@ -91,17 +100,21 @@ public partial class Device cdb[4] = (byte)((address & 0xFF00) >> 8); cdb[5] = (byte)(address & 0xFF); - if(pba) - cdb[9] += 0x80; + if(pba) cdb[9] += 0x80; buffer = new byte[8]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLASMON READ SECTOR LOCATION took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLASMON_READ_SECTOR_LOCATION_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/Plextor.cs b/Aaru.Devices/Device/ScsiCommands/Plextor.cs index 86fba3685..398cbd548 100644 --- a/Aaru.Devices/Device/ScsiCommands/Plextor.cs +++ b/Aaru.Devices/Device/ScsiCommands/Plextor.cs @@ -27,14 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using Aaru.Console; using Aaru.Helpers; +namespace Aaru.Devices; + public partial class Device { /// Sends the Plextor READ CD-DA command @@ -66,14 +66,26 @@ public partial class Device buffer = new byte[blockSize * transferLength]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", - "Plextor READ CD-DA (LBA: {1}, Block Size: {2}, Transfer Length: {3}, Subchannel: {4}, Sense: {5}, Last Error: {6}) took {0} ms.", - duration, lba, blockSize, transferLength, subchannel, sense, LastError); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization + .Plextor_READ_CD_DA_LBA_1_Block_Size_2_Transfer_Length_3_Subchannel_4_Sense_5_Last_Error_6_took_0_ms, + duration, + lba, + blockSize, + transferLength, + subchannel, + sense, + LastError); return sense; } @@ -86,8 +98,8 @@ public partial class Device /// Duration in milliseconds it took for the device to execute the command. /// Start block address. /// How many blocks to read. - public bool PlextorReadRawDvd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint transferLength, - uint timeout, out double duration) + public bool PlextorReadRawDvd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint transferLength, + uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; @@ -102,12 +114,17 @@ public partial class Device cdb[4] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[5] = (byte)(buffer.Length & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "Plextor READ DVD (RAW) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.Plextor_READ_DVD_RAW_took_0_ms, duration); return sense; } @@ -127,12 +144,17 @@ public partial class Device cdb[0] = (byte)ScsiCommands.PlextorReadEeprom; cdb[8] = 1; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR READ EEPROM took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_READ_EEPROM_took_0_ms, duration); return sense; } @@ -152,12 +174,17 @@ public partial class Device cdb[0] = (byte)ScsiCommands.PlextorReadEeprom; cdb[8] = 2; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR READ EEPROM took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_READ_EEPROM_took_0_ms, duration); return sense; } @@ -170,8 +197,8 @@ public partial class Device /// How many bytes are in the EEPROM block /// Timeout. /// Duration. - public bool PlextorReadEepromBlock(out byte[] buffer, out byte[] senseBuffer, byte block, ushort blockSize, - uint timeout, out double duration) + public bool PlextorReadEepromBlock(out byte[] buffer, out byte[] senseBuffer, byte block, ushort blockSize, + uint timeout, out double duration) { buffer = new byte[blockSize]; senseBuffer = new byte[64]; @@ -183,12 +210,17 @@ public partial class Device cdb[8] = (byte)((blockSize & 0xFF00) >> 8); cdb[9] = (byte)(blockSize & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR READ EEPROM took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_READ_EEPROM_took_0_ms, duration); return sense; } @@ -202,7 +234,7 @@ public partial class Device /// Timeout. /// Duration. public bool PlextorGetSpeeds(out byte[] senseBuffer, out ushort selected, out ushort max, out ushort last, - uint timeout, out double duration) + uint timeout, out double duration) { var buf = new byte[10]; senseBuffer = new byte[64]; @@ -215,15 +247,19 @@ public partial class Device cdb[0] = (byte)ScsiCommands.PlextorPoweRec; cdb[9] = (byte)buf.Length; - LastError = SendScsiCommand(cdb, ref buf, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buf, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR POWEREC GET SPEEDS took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_POWEREC_GET_SPEEDS_took_0_ms, duration); - if(sense || Error) - return sense; + if(sense || Error) return sense; selected = BigEndianBitConverter.ToUInt16(buf, 4); max = BigEndianBitConverter.ToUInt16(buf, 6); @@ -253,15 +289,19 @@ public partial class Device cdb[1] = (byte)PlextorSubCommands.GetMode; cdb[9] = (byte)buf.Length; - LastError = SendScsiCommand(cdb, ref buf, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buf, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR POWEREC GET SPEEDS took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_POWEREC_GET_SPEEDS_took_0_ms, duration); - if(sense || Error) - return sense; + if(sense || Error) return sense; enabled = buf[2] != 0; speed = BigEndianBitConverter.ToUInt16(buf, 4); @@ -287,12 +327,17 @@ public partial class Device cdb[3] = 4; cdb[10] = (byte)buffer.Length; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SILENT MODE took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_GET_SILENT_MODE_took_0_ms, duration); return sense; } @@ -314,12 +359,17 @@ public partial class Device cdb[2] = (byte)PlextorSubCommands.GigaRec; cdb[10] = (byte)buffer.Length; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET GIGAREC took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_GET_GIGAREC_took_0_ms, duration); return sense; } @@ -348,12 +398,17 @@ public partial class Device else cdb[3] = 0x02; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET VARIREC took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_GET_VARIREC_took_0_ms, duration); return sense; } @@ -374,12 +429,17 @@ public partial class Device cdb[2] = (byte)PlextorSubCommands.SecuRec; cdb[10] = (byte)buffer.Length; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SECUREC took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_GET_SECUREC_took_0_ms, duration); return sense; } @@ -401,12 +461,17 @@ public partial class Device cdb[2] = (byte)PlextorSubCommands.SpeedRead; cdb[10] = (byte)buffer.Length; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SPEEDREAD took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_GET_SPEEDREAD_took_0_ms, duration); return sense; } @@ -428,12 +493,19 @@ public partial class Device cdb[2] = (byte)PlextorSubCommands.SessionHide; cdb[9] = (byte)buffer.Length; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SINGLE-SESSION / HIDE CD-R took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, + Localization.PLEXTOR_GET_SINGLE_SESSION_HIDE_CD_R_took_0_ms, + duration); return sense; } @@ -462,12 +534,17 @@ public partial class Device else cdb[3] = (byte)PlextorSubCommands.BitSetR; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET BOOK BITSETTING took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_GET_BOOK_BITSETTING_took_0_ms, duration); return sense; } @@ -489,12 +566,17 @@ public partial class Device cdb[2] = (byte)PlextorSubCommands.TestWriteDvdPlus; cdb[10] = (byte)buffer.Length; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET TEST WRITE DVD+ took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PLEXTOR_GET_TEST_WRITE_DVD_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/SBC.cs b/Aaru.Devices/Device/ScsiCommands/SBC.cs index 9a093eccb..2843fd5ad 100644 --- a/Aaru.Devices/Device/ScsiCommands/SBC.cs +++ b/Aaru.Devices/Device/ScsiCommands/SBC.cs @@ -27,14 +27,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using System; using Aaru.Console; +namespace Aaru.Devices; + public partial class Device { /// Sends the SBC READ (6) command @@ -58,8 +58,8 @@ public partial class Device /// Starting block. /// Block size in bytes. /// How many blocks to read. - public bool Read6(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, byte transferLength, - uint timeout, out double duration) + public bool Read6(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, byte transferLength, + uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[6]; @@ -70,17 +70,19 @@ public partial class Device cdb[3] = (byte)(lba & 0xFF); cdb[4] = transferLength; - if(transferLength == 0) - buffer = new byte[256 * blockSize]; - else - buffer = new byte[transferLength * blockSize]; + buffer = transferLength == 0 ? new byte[256 * blockSize] : new byte[transferLength * blockSize]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ (6) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_6_took_0_ms, duration); return sense; } @@ -96,7 +98,7 @@ public partial class Device /// If set to true requested blocks shall be assigned the lowest retention priority on cache /// fetch/retain. /// - /// If set to true requested blocks MUST bu read from medium and not the cache. + /// If set to true requested blocks MUST be read from medium and not the cache. /// /// If set to true requested blocks will be returned from non-volatile cache. If they're not /// present they shall be stored there. @@ -116,17 +118,13 @@ public partial class Device cdb[0] = (byte)ScsiCommands.Read10; cdb[1] = (byte)((rdprotect & 0x07) << 5); - if(dpo) - cdb[1] += 0x10; + if(dpo) cdb[1] += 0x10; - if(fua) - cdb[1] += 0x08; + if(fua) cdb[1] += 0x08; - if(fuaNv) - cdb[1] += 0x02; + if(fuaNv) cdb[1] += 0x02; - if(relAddr) - cdb[1] += 0x01; + if(relAddr) cdb[1] += 0x01; cdb[2] = (byte)((lba & 0xFF000000) >> 24); cdb[3] = (byte)((lba & 0xFF0000) >> 16); @@ -138,12 +136,17 @@ public partial class Device buffer = new byte[transferLength * blockSize]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ (10) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_10_took_0_ms, duration); return sense; } @@ -180,17 +183,13 @@ public partial class Device cdb[0] = (byte)ScsiCommands.Read12; cdb[1] = (byte)((rdprotect & 0x07) << 5); - if(dpo) - cdb[1] += 0x10; + if(dpo) cdb[1] += 0x10; - if(fua) - cdb[1] += 0x08; + if(fua) cdb[1] += 0x08; - if(fuaNv) - cdb[1] += 0x02; + if(fuaNv) cdb[1] += 0x02; - if(relAddr) - cdb[1] += 0x01; + if(relAddr) cdb[1] += 0x01; cdb[2] = (byte)((lba & 0xFF000000) >> 24); cdb[3] = (byte)((lba & 0xFF0000) >> 16); @@ -202,17 +201,21 @@ public partial class Device cdb[9] = (byte)(transferLength & 0xFF); cdb[10] = (byte)(groupNumber & 0x1F); - if(streaming) - cdb[10] += 0x80; + if(streaming) cdb[10] += 0x80; buffer = new byte[transferLength * blockSize]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ (12) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_12_took_0_ms, duration); return sense; } @@ -249,14 +252,11 @@ public partial class Device cdb[0] = (byte)ScsiCommands.Read16; cdb[1] = (byte)((rdprotect & 0x07) << 5); - if(dpo) - cdb[1] += 0x10; + if(dpo) cdb[1] += 0x10; - if(fua) - cdb[1] += 0x08; + if(fua) cdb[1] += 0x08; - if(fuaNv) - cdb[1] += 0x02; + if(fuaNv) cdb[1] += 0x02; cdb[2] = lbaBytes[7]; cdb[3] = lbaBytes[6]; @@ -272,17 +272,21 @@ public partial class Device cdb[13] = (byte)(transferLength & 0xFF); cdb[14] = (byte)(groupNumber & 0x1F); - if(streaming) - cdb[14] += 0x80; + if(streaming) cdb[14] += 0x80; buffer = new byte[transferLength * blockSize]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ (16) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_16_took_0_ms, duration); return sense; } @@ -300,19 +304,17 @@ public partial class Device /// How many bytes to read. If the number is not exactly the drive's size, the command will /// fail and incidate a delta of the size in SENSE. /// - public bool ReadLong10(out byte[] buffer, out byte[] senseBuffer, bool correct, bool relAddr, uint lba, - ushort transferBytes, uint timeout, out double duration) + public bool ReadLong10(out byte[] buffer, out byte[] senseBuffer, bool correct, bool relAddr, uint lba, + ushort transferBytes, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; cdb[0] = (byte)ScsiCommands.ReadLong; - if(correct) - cdb[1] += 0x02; + if(correct) cdb[1] += 0x02; - if(relAddr) - cdb[1] += 0x01; + if(relAddr) cdb[1] += 0x01; cdb[2] = (byte)((lba & 0xFF000000) >> 24); cdb[3] = (byte)((lba & 0xFF0000) >> 16); @@ -323,12 +325,17 @@ public partial class Device buffer = new byte[transferBytes]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ LONG (10) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_LONG_10_took_0_ms, duration); return sense; } @@ -345,8 +352,8 @@ public partial class Device /// How many bytes to read. If the number is not exactly the drive's size, the command will /// fail and incidate a delta of the size in SENSE. /// - public bool ReadLong16(out byte[] buffer, out byte[] senseBuffer, bool correct, ulong lba, uint transferBytes, - uint timeout, out double duration) + public bool ReadLong16(out byte[] buffer, out byte[] senseBuffer, bool correct, ulong lba, uint transferBytes, + uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[16]; @@ -365,17 +372,21 @@ public partial class Device cdb[12] = (byte)((transferBytes & 0xFF00) >> 8); cdb[13] = (byte)(transferBytes & 0xFF); - if(correct) - cdb[14] += 0x01; + if(correct) cdb[14] += 0x01; buffer = new byte[transferBytes]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ LONG (16) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_LONG_16_took_0_ms, duration); return sense; } @@ -389,19 +400,24 @@ public partial class Device { senseBuffer = new byte[64]; var cdb = new byte[6]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.Seek6; cdb[1] = (byte)((lba & 0x1F0000) >> 16); cdb[2] = (byte)((lba & 0xFF00) >> 8); cdb[3] = (byte)(lba & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "SEEK (6) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.SEEK_6_took_0_ms, duration); return sense; } @@ -415,7 +431,7 @@ public partial class Device { senseBuffer = new byte[64]; var cdb = new byte[10]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.Seek10; cdb[2] = (byte)((lba & 0xFF000000) >> 24); @@ -423,12 +439,17 @@ public partial class Device cdb[4] = (byte)((lba & 0xFF00) >> 8); cdb[5] = (byte)(lba & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "SEEK (10) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.SEEK_10_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/SMC.cs b/Aaru.Devices/Device/ScsiCommands/SMC.cs index ce15f3542..e75701708 100644 --- a/Aaru.Devices/Device/ScsiCommands/SMC.cs +++ b/Aaru.Devices/Device/ScsiCommands/SMC.cs @@ -27,13 +27,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using Aaru.Console; +namespace Aaru.Devices; + public partial class Device { /// Reads an attribute from the medium auxiliary memory, or reports which elements in the changer contain one @@ -49,8 +49,8 @@ public partial class Device /// Timeout. /// Duration. public bool ReadAttribute(out byte[] buffer, out byte[] senseBuffer, ScsiAttributeAction action, ushort element, - byte elementType, byte volume, byte partition, ushort firstAttribute, bool cache, - uint timeout, out double duration) + byte elementType, byte volume, byte partition, ushort firstAttribute, bool cache, + uint timeout, out double duration) { buffer = new byte[256]; var cdb = new byte[16]; @@ -70,16 +70,19 @@ public partial class Device cdb[12] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[13] = (byte)(buffer.Length & 0xFF); - if(cache) - cdb[14] += 0x01; + if(cache) cdb[14] += 0x01; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - if(sense) - return true; + if(sense) return true; var attrLen = (uint)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3] + 4); buffer = new byte[attrLen]; @@ -89,12 +92,17 @@ public partial class Device cdb[13] = (byte)(buffer.Length & 0xFF); senseBuffer = new byte[64]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ ATTRIBUTE took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_ATTRIBUTE_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/SPC.cs b/Aaru.Devices/Device/ScsiCommands/SPC.cs index 0cdefbaa3..c3f1d3af9 100644 --- a/Aaru.Devices/Device/ScsiCommands/SPC.cs +++ b/Aaru.Devices/Device/ScsiCommands/SPC.cs @@ -27,17 +27,20 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using System; using System.Diagnostics.CodeAnalysis; using Aaru.Console; using PlatformID = Aaru.CommonTypes.Interop.PlatformID; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] public partial class Device { /// Sends the SPC INQUIRY command to the device using default device timeout. @@ -74,35 +77,38 @@ public partial class Device buffer = new byte[36]; senseBuffer = new byte[64]; - byte[] cdb = - { - (byte)ScsiCommands.Inquiry, 0, 0, 0, 36, 0 - }; + byte[] cdb = [(byte)ScsiCommands.Inquiry, 0, 0, 0, 36, 0]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - if(sense) - return true; + if(sense) return true; var pagesLength = (byte)(buffer[4] + 5); - cdb = new byte[] - { - (byte)ScsiCommands.Inquiry, 0, 0, 0, pagesLength, 0 - }; + cdb = [(byte)ScsiCommands.Inquiry, 0, 0, 0, pagesLength, 0]; buffer = new byte[pagesLength]; senseBuffer = new byte[64]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "INQUIRY took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.INQUIRY_took_0_ms, duration); return sense; } @@ -151,39 +157,41 @@ public partial class Device buffer = new byte[36]; senseBuffer = new byte[64]; - byte[] cdb = - { - (byte)ScsiCommands.Inquiry, 1, page, 0, 36, 0 - }; + byte[] cdb = [(byte)ScsiCommands.Inquiry, 1, page, 0, 36, 0]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - if(sense) - return true; + if(sense) return true; // This is because INQ was returned instead of EVPD - if(buffer[1] != page) - return true; + if(buffer[1] != page) return true; var pagesLength = (byte)(buffer[3] + 4); - cdb = new byte[] - { - (byte)ScsiCommands.Inquiry, 1, page, 0, pagesLength, 0 - }; + cdb = [(byte)ScsiCommands.Inquiry, 1, page, 0, pagesLength, 0]; buffer = new byte[pagesLength]; senseBuffer = new byte[64]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "INQUIRY took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.INQUIRY_took_0_ms, duration); return sense; } @@ -197,19 +205,21 @@ public partial class Device { senseBuffer = new byte[64]; - byte[] cdb = - { - (byte)ScsiCommands.TestUnitReady, 0, 0, 0, 0, 0 - }; + byte[] cdb = [(byte)ScsiCommands.TestUnitReady, 0, 0, 0, 0, 0]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "TEST UNIT READY took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.TEST_UNIT_READY_took_0_ms, duration); return sense; } @@ -232,8 +242,8 @@ public partial class Device /// If set to true device MUST not return any block descriptor. /// Page control. /// Page code. - public bool ModeSense6(out byte[] buffer, out byte[] senseBuffer, bool dbd, ScsiModeSensePageControl pageControl, - byte pageCode, uint timeout, out double duration) => + public bool ModeSense6(out byte[] buffer, out byte[] senseBuffer, bool dbd, ScsiModeSensePageControl pageControl, + byte pageCode, uint timeout, out double duration) => ModeSense6(out buffer, out senseBuffer, dbd, pageControl, pageCode, 0, timeout, out duration); /// Sends the SPC MODE SENSE(6) command to the device as introduced in SCSI-3 SPC-3 @@ -246,17 +256,16 @@ public partial class Device /// Page control. /// Page code. /// Sub-page code. - public bool ModeSense6(out byte[] buffer, out byte[] senseBuffer, bool dbd, ScsiModeSensePageControl pageControl, - byte pageCode, byte subPageCode, uint timeout, out double duration) + public bool ModeSense6(out byte[] buffer, out byte[] senseBuffer, bool dbd, ScsiModeSensePageControl pageControl, + byte pageCode, byte subPageCode, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[6]; - buffer = new byte[255]; + buffer = new byte[254]; cdb[0] = (byte)ScsiCommands.ModeSense; - if(dbd) - cdb[1] = 0x08; + if(dbd) cdb[1] = 0x08; cdb[2] |= (byte)pageControl; cdb[2] |= (byte)(pageCode & 0x3F); @@ -264,25 +273,36 @@ public partial class Device cdb[4] = (byte)buffer.Length; cdb[5] = 0; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - if(sense) - return true; + if(sense) return true; var modeLength = (byte)(buffer[0] + 1); + if(modeLength % 2 != 0) modeLength++; + buffer = new byte[modeLength]; cdb[4] = (byte)buffer.Length; senseBuffer = new byte[64]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MODE SENSE(6) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MODE_SENSE_6_took_0_ms, duration); return sense; } @@ -296,8 +316,8 @@ public partial class Device /// If set to true device MUST not return any block descriptor. /// Page control. /// Page code. - public bool ModeSense10(out byte[] buffer, out byte[] senseBuffer, bool dbd, ScsiModeSensePageControl pageControl, - byte pageCode, uint timeout, out double duration) => + public bool ModeSense10(out byte[] buffer, out byte[] senseBuffer, bool dbd, ScsiModeSensePageControl pageControl, + byte pageCode, uint timeout, out double duration) => ModeSense10(out buffer, out senseBuffer, false, dbd, pageControl, pageCode, 0, timeout, out duration); /// Sends the SPC MODE SENSE(10) command to the device as introduced in SCSI-3 SPC-2 @@ -310,7 +330,7 @@ public partial class Device /// Page control. /// Page code. /// If set means 64-bit LBAs are accepted by the caller. - public bool ModeSense10(out byte[] buffer, out byte[] senseBuffer, bool llbaa, bool dbd, + public bool ModeSense10(out byte[] buffer, out byte[] senseBuffer, bool llbaa, bool dbd, ScsiModeSensePageControl pageControl, byte pageCode, uint timeout, out double duration) => ModeSense10(out buffer, out senseBuffer, llbaa, dbd, pageControl, pageCode, 0, timeout, out duration); @@ -325,9 +345,9 @@ public partial class Device /// Page code. /// Sub-page code. /// If set means 64-bit LBAs are accepted by the caller. - public bool ModeSense10(out byte[] buffer, out byte[] senseBuffer, bool llbaa, bool dbd, - ScsiModeSensePageControl pageControl, byte pageCode, byte subPageCode, uint timeout, - out double duration) + public bool ModeSense10(out byte[] buffer, out byte[] senseBuffer, bool llbaa, bool dbd, + ScsiModeSensePageControl pageControl, byte pageCode, byte subPageCode, uint timeout, + out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; @@ -335,11 +355,9 @@ public partial class Device cdb[0] = (byte)ScsiCommands.ModeSense10; - if(llbaa) - cdb[1] |= 0x10; + if(llbaa) cdb[1] |= 0x10; - if(dbd) - cdb[1] |= 0x08; + if(dbd) cdb[1] |= 0x08; cdb[2] |= (byte)pageControl; cdb[2] |= (byte)(pageCode & 0x3F); @@ -348,26 +366,37 @@ public partial class Device cdb[8] = (byte)(buffer.Length & 0xFF); cdb[9] = 0; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - if(sense) - return true; + if(sense) return true; var modeLength = (ushort)((buffer[0] << 8) + buffer[1] + 2); + if(modeLength % 2 != 0) modeLength++; + buffer = new byte[modeLength]; cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[8] = (byte)(buffer.Length & 0xFF); senseBuffer = new byte[64]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MODE SENSE(10) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MODE_SENSE_10_took_0_ms, duration); return sense; } @@ -394,13 +423,10 @@ public partial class Device /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. /// true to prevent medium removal, false to allow it. - public bool SpcPreventAllowMediumRemoval(out byte[] senseBuffer, bool prevent, uint timeout, out double duration) - { - if(prevent) - return SpcPreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Prevent, timeout, out duration); - - return SpcPreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Allow, timeout, out duration); - } + public bool SpcPreventAllowMediumRemoval(out byte[] senseBuffer, bool prevent, uint timeout, out double duration) => + prevent + ? SpcPreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Prevent, timeout, out duration) + : SpcPreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Allow, timeout, out duration); /// Sends the SPC PREVENT ALLOW MEDIUM REMOVAL command /// true if the command failed and contains the sense buffer. @@ -413,17 +439,22 @@ public partial class Device { senseBuffer = new byte[64]; var cdb = new byte[6]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.PreventAllowMediumRemoval; cdb[4] = (byte)((byte)preventMode & 0x03); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "PREVENT ALLOW MEDIUM REMOVAL took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.PREVENT_ALLOW_MEDIUM_REMOVAL_took_0_ms, duration); return sense; } @@ -446,8 +477,8 @@ public partial class Device /// If set, it is requesting partial media capacity /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. - public bool ReadCapacity(out byte[] buffer, out byte[] senseBuffer, bool relAddr, uint address, bool pmi, - uint timeout, out double duration) + public bool ReadCapacity(out byte[] buffer, out byte[] senseBuffer, bool relAddr, uint address, bool pmi, + uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; @@ -459,8 +490,7 @@ public partial class Device { cdb[8] = 0x01; - if(relAddr) - cdb[1] = 0x01; + if(relAddr) cdb[1] = 0x01; cdb[2] = (byte)((address & 0xFF000000) >> 24); cdb[3] = (byte)((address & 0xFF0000) >> 16); @@ -468,12 +498,17 @@ public partial class Device cdb[5] = (byte)(address & 0xFF); } - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ CAPACITY took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_CAPACITY_took_0_ms, duration); return sense; } @@ -524,12 +559,17 @@ public partial class Device cdb[12] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[13] = (byte)(buffer.Length & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ CAPACITY(16) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_CAPACITY_16_took_0_ms, duration); return sense; } @@ -553,13 +593,17 @@ public partial class Device cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[9] = (byte)(buffer.Length & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - if(sense) - return true; + if(sense) return true; var strctLength = (uint)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3] + 4); buffer = new byte[strctLength]; @@ -569,12 +613,17 @@ public partial class Device cdb[9] = (byte)(buffer.Length & 0xFF); senseBuffer = new byte[64]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ MEDIA SERIAL NUMBER took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_MEDIA_SERIAL_NUMBER_took_0_ms, duration); return sense; } @@ -589,8 +638,17 @@ public partial class Device /// Timeout. /// Duration. public bool ReadAttribute(out byte[] buffer, out byte[] senseBuffer, ScsiAttributeAction action, byte partition, - ushort firstAttribute, bool cache, uint timeout, out double duration) => - ReadAttribute(out buffer, out senseBuffer, action, 0, 0, 0, partition, firstAttribute, cache, timeout, + ushort firstAttribute, bool cache, uint timeout, out double duration) => + ReadAttribute(out buffer, + out senseBuffer, + action, + 0, + 0, + 0, + partition, + firstAttribute, + cache, + timeout, out duration); /// Reads an attribute from the medium auxiliary memory @@ -601,8 +659,8 @@ public partial class Device /// If set to true device can return cached data. /// Timeout. /// Duration. - public bool ReadAttribute(out byte[] buffer, out byte[] senseBuffer, ScsiAttributeAction action, - ushort firstAttribute, bool cache, uint timeout, out double duration) => + public bool ReadAttribute(out byte[] buffer, out byte[] senseBuffer, ScsiAttributeAction action, + ushort firstAttribute, bool cache, uint timeout, out double duration) => ReadAttribute(out buffer, out senseBuffer, action, 0, 0, 0, 0, firstAttribute, cache, timeout, out duration); /// Reads an attribute from the medium auxiliary memory @@ -614,8 +672,17 @@ public partial class Device /// Timeout. /// Duration. public bool ReadAttribute(out byte[] buffer, out byte[] senseBuffer, ScsiAttributeAction action, byte partition, - ushort firstAttribute, uint timeout, out double duration) => - ReadAttribute(out buffer, out senseBuffer, action, 0, 0, 0, partition, firstAttribute, false, timeout, + ushort firstAttribute, uint timeout, out double duration) => + ReadAttribute(out buffer, + out senseBuffer, + action, + 0, + 0, + 0, + partition, + firstAttribute, + false, + timeout, out duration); /// Reads an attribute from the medium auxiliary memory @@ -625,8 +692,8 @@ public partial class Device /// First attribute identifier. /// Timeout. /// Duration. - public bool ReadAttribute(out byte[] buffer, out byte[] senseBuffer, ScsiAttributeAction action, - ushort firstAttribute, uint timeout, out double duration) => + public bool ReadAttribute(out byte[] buffer, out byte[] senseBuffer, ScsiAttributeAction action, + ushort firstAttribute, uint timeout, out double duration) => ReadAttribute(out buffer, out senseBuffer, action, 0, 0, 0, 0, firstAttribute, false, timeout, out duration); /// Reads an attribute from the medium auxiliary memory @@ -638,9 +705,18 @@ public partial class Device /// First attribute identifier. /// Timeout. /// Duration. - public bool ReadAttribute(out byte[] buffer, out byte[] senseBuffer, ScsiAttributeAction action, byte volume, - byte partition, ushort firstAttribute, uint timeout, out double duration) => - ReadAttribute(out buffer, out senseBuffer, action, 0, 0, volume, partition, firstAttribute, false, timeout, + public bool ReadAttribute(out byte[] buffer, out byte[] senseBuffer, ScsiAttributeAction action, byte volume, + byte partition, ushort firstAttribute, uint timeout, out double duration) => + ReadAttribute(out buffer, + out senseBuffer, + action, + 0, + 0, + volume, + partition, + firstAttribute, + false, + timeout, out duration); /// Reads an attribute from the medium auxiliary memory @@ -655,7 +731,16 @@ public partial class Device /// Duration. public bool ReadAttribute(out byte[] buffer, out byte[] senseBuffer, ScsiAttributeAction action, byte volume, byte partition, ushort firstAttribute, bool cache, uint timeout, out double duration) => - ReadAttribute(out buffer, out senseBuffer, action, 0, 0, volume, partition, firstAttribute, cache, timeout, + ReadAttribute(out buffer, + out senseBuffer, + action, + 0, + 0, + volume, + partition, + firstAttribute, + cache, + timeout, out duration); /// Sends the SPC MODE SELECT(6) command @@ -666,7 +751,7 @@ public partial class Device /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. /// Set if page is formatted. - public bool ModeSelect(byte[] buffer, out byte[] senseBuffer, bool pageFormat, bool savePages, uint timeout, + public bool ModeSelect(byte[] buffer, out byte[] senseBuffer, bool pageFormat, bool savePages, uint timeout, out double duration) { senseBuffer = new byte[64]; @@ -694,20 +779,23 @@ public partial class Device cdb[0] = (byte)ScsiCommands.ModeSelect; - if(pageFormat) - cdb[1] += 0x10; + if(pageFormat) cdb[1] += 0x10; - if(savePages) - cdb[1] += 0x01; + if(savePages) cdb[1] += 0x01; cdb[4] = (byte)buffer.Length; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.Out, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.Out, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MODE SELECT(6) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MODE_SELECT_6_took_0_ms, duration); return sense; } @@ -720,7 +808,7 @@ public partial class Device /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. /// Set if page is formatted. - public bool ModeSelect10(byte[] buffer, out byte[] senseBuffer, bool pageFormat, bool savePages, uint timeout, + public bool ModeSelect10(byte[] buffer, out byte[] senseBuffer, bool pageFormat, bool savePages, uint timeout, out double duration) { senseBuffer = new byte[64]; @@ -748,21 +836,24 @@ public partial class Device cdb[0] = (byte)ScsiCommands.ModeSelect10; - if(pageFormat) - cdb[1] += 0x10; + if(pageFormat) cdb[1] += 0x10; - if(savePages) - cdb[1] += 0x01; + if(savePages) cdb[1] += 0x01; cdb[7] = (byte)((buffer.Length & 0xFF00) << 8); cdb[8] = (byte)(buffer.Length & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.Out, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.Out, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "MODE SELECT(10) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.MODE_SELECT_10_took_0_ms, duration); return sense; } @@ -788,8 +879,7 @@ public partial class Device cdb[0] = (byte)ScsiCommands.RequestSense; - if(descriptor) - cdb[1] = 0x01; + if(descriptor) cdb[1] = 0x01; cdb[2] = 0; cdb[3] = 0; @@ -800,7 +890,7 @@ public partial class Device Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "REQUEST SENSE took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.REQUEST_SENSE_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/SSC.cs b/Aaru.Devices/Device/ScsiCommands/SSC.cs index da407f366..98c82f939 100644 --- a/Aaru.Devices/Device/ScsiCommands/SSC.cs +++ b/Aaru.Devices/Device/ScsiCommands/SSC.cs @@ -27,14 +27,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.Console; + +// ReSharper disable UnusedMember.Global + namespace Aaru.Devices; -using System; -using Aaru.Console; - +[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")] public partial class Device { /// Prepares the medium for reading @@ -67,35 +71,35 @@ public partial class Device /// Timeout. /// Duration. public bool LoadUnload(out byte[] senseBuffer, bool immediate, bool load, bool retense, bool endOfTape, bool hold, - uint timeout, out double duration) + uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[6]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.LoadUnload; - if(immediate) - cdb[1] = 0x01; + if(immediate) cdb[1] = 0x01; - if(load) - cdb[4] += 0x01; + if(load) cdb[4] += 0x01; - if(retense) - cdb[4] += 0x02; + if(retense) cdb[4] += 0x02; - if(endOfTape) - cdb[4] += 0x04; + if(endOfTape) cdb[4] += 0x04; - if(hold) - cdb[4] += 0x08; + if(hold) cdb[4] += 0x08; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "LOAD UNLOAD (6) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.LOAD_UNLOAD_6_took_0_ms, duration); return sense; } @@ -134,7 +138,13 @@ public partial class Device /// Timeout. /// Duration. public bool Locate(out byte[] senseBuffer, bool immediate, byte partition, uint lba, uint timeout, - out double duration) => Locate(out senseBuffer, immediate, false, false, partition, lba, timeout, + out double duration) => Locate(out senseBuffer, + immediate, + false, + false, + partition, + lba, + timeout, out duration); /// Positions the medium to the specified object identifier @@ -147,22 +157,19 @@ public partial class Device /// Timeout. /// Duration. public bool Locate(out byte[] senseBuffer, bool immediate, bool blockType, bool changePartition, byte partition, - uint objectId, uint timeout, out double duration) + uint objectId, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[10]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.Locate; - if(immediate) - cdb[1] += 0x01; + if(immediate) cdb[1] += 0x01; - if(changePartition) - cdb[1] += 0x02; + if(changePartition) cdb[1] += 0x02; - if(blockType) - cdb[1] += 0x04; + if(blockType) cdb[1] += 0x04; cdb[3] = (byte)((objectId & 0xFF000000) >> 24); cdb[4] = (byte)((objectId & 0xFF0000) >> 16); @@ -170,12 +177,17 @@ public partial class Device cdb[6] = (byte)(objectId & 0xFF); cdb[8] = partition; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "LOCATE (10) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.LOCATE_10_took_0_ms, duration); return sense; } @@ -195,7 +207,14 @@ public partial class Device /// Timeout. /// Duration. public bool Locate16(out byte[] senseBuffer, byte partition, ulong lba, uint timeout, out double duration) => - Locate16(out senseBuffer, false, false, SscLogicalIdTypes.ObjectId, false, partition, lba, timeout, + Locate16(out senseBuffer, + false, + false, + SscLogicalIdTypes.ObjectId, + false, + partition, + lba, + timeout, out duration); /// Positions the medium to the specified block in the current partition @@ -215,8 +234,15 @@ public partial class Device /// Timeout. /// Duration. public bool Locate16(out byte[] senseBuffer, bool immediate, byte partition, ulong lba, uint timeout, - out double duration) => Locate16(out senseBuffer, immediate, false, SscLogicalIdTypes.ObjectId, - false, partition, lba, timeout, out duration); + out double duration) => Locate16(out senseBuffer, + immediate, + false, + SscLogicalIdTypes.ObjectId, + false, + partition, + lba, + timeout, + out duration); /// Positions the medium to the specified object identifier /// Sense buffer. @@ -228,25 +254,22 @@ public partial class Device /// Destination identifier. /// Timeout. /// Duration. - public bool Locate16(out byte[] senseBuffer, bool immediate, bool changePartition, SscLogicalIdTypes destType, - bool bam, byte partition, ulong identifier, uint timeout, out double duration) + public bool Locate16(out byte[] senseBuffer, bool immediate, bool changePartition, SscLogicalIdTypes destType, + bool bam, byte partition, ulong identifier, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[16]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; byte[] idBytes = BitConverter.GetBytes(identifier); cdb[0] = (byte)ScsiCommands.Locate16; cdb[1] = (byte)((byte)destType << 3); - if(immediate) - cdb[1] += 0x01; + if(immediate) cdb[1] += 0x01; - if(changePartition) - cdb[1] += 0x02; + if(changePartition) cdb[1] += 0x02; - if(bam) - cdb[2] = 0x01; + if(bam) cdb[2] = 0x01; cdb[3] = partition; @@ -259,12 +282,17 @@ public partial class Device cdb[10] = idBytes[1]; cdb[11] = idBytes[0]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "LOCATE (16) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.LOCATE_16_took_0_ms, duration); return sense; } @@ -291,9 +319,15 @@ public partial class Device /// Block size in bytes. /// Timeout. /// Duration. - public bool Read6(out byte[] buffer, out byte[] senseBuffer, bool sili, uint transferLen, uint blockSize, - uint timeout, out double duration) => Read6(out buffer, out senseBuffer, sili, false, transferLen, - blockSize, timeout, out duration); + public bool Read6(out byte[] buffer, out byte[] senseBuffer, bool sili, uint transferLen, uint blockSize, + uint timeout, out double duration) => Read6(out buffer, + out senseBuffer, + sili, + false, + transferLen, + blockSize, + timeout, + out duration); /// Reads the specified number of bytes or of blocks from the medium /// Buffer. @@ -310,8 +344,8 @@ public partial class Device /// Block size in bytes. /// Timeout. /// Duration. - public bool Read6(out byte[] buffer, out byte[] senseBuffer, bool sili, bool fixedLen, uint transferLen, - uint blockSize, uint timeout, out double duration) + public bool Read6(out byte[] buffer, out byte[] senseBuffer, bool sili, bool fixedLen, uint transferLen, + uint blockSize, uint timeout, out double duration) { buffer = fixedLen ? new byte[blockSize * transferLen] : new byte[transferLen]; var cdb = new byte[6]; @@ -319,22 +353,25 @@ public partial class Device cdb[0] = (byte)ScsiCommands.Read6; - if(fixedLen) - cdb[1] += 0x01; + if(fixedLen) cdb[1] += 0x01; - if(sili) - cdb[1] += 0x02; + if(sili) cdb[1] += 0x02; cdb[2] = (byte)((transferLen & 0xFF0000) >> 16); cdb[3] = (byte)((transferLen & 0xFF00) >> 8); cdb[4] = (byte)(transferLen & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ (6) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_6_took_0_ms, duration); return sense; } @@ -348,8 +385,8 @@ public partial class Device /// Object size in bytes. /// Timeout. /// Duration. - public bool Read16(out byte[] buffer, out byte[] senseBuffer, bool sili, ulong objectId, uint blocks, - uint blockSize, uint timeout, out double duration) => + public bool Read16(out byte[] buffer, out byte[] senseBuffer, bool sili, ulong objectId, uint blocks, + uint blockSize, uint timeout, out double duration) => Read16(out buffer, out senseBuffer, sili, false, 0, objectId, blocks, blockSize, timeout, out duration); /// Reads a number of fixed-length blocks starting at specified block from the specified partition @@ -362,8 +399,8 @@ public partial class Device /// Object size in bytes. /// Timeout. /// Duration. - public bool Read16(out byte[] buffer, out byte[] senseBuffer, bool sili, byte partition, ulong objectId, - uint blocks, uint blockSize, uint timeout, out double duration) => + public bool Read16(out byte[] buffer, out byte[] senseBuffer, bool sili, byte partition, ulong objectId, + uint blocks, uint blockSize, uint timeout, out double duration) => Read16(out buffer, out senseBuffer, sili, false, partition, objectId, blocks, blockSize, timeout, out duration); /// Reads a number of fixed-length blocks starting at specified object @@ -374,9 +411,17 @@ public partial class Device /// Object size in bytes. /// Timeout. /// Duration. - public bool Read16(out byte[] buffer, out byte[] senseBuffer, ulong objectId, uint blocks, uint blockSize, - uint timeout, out double duration) => Read16(out buffer, out senseBuffer, false, true, 0, - objectId, blocks, blockSize, timeout, out duration); + public bool Read16(out byte[] buffer, out byte[] senseBuffer, ulong objectId, uint blocks, uint blockSize, + uint timeout, out double duration) => Read16(out buffer, + out senseBuffer, + false, + true, + 0, + objectId, + blocks, + blockSize, + timeout, + out duration); /// Reads a number of fixed-length blocks starting at specified block from the specified partition /// Buffer. @@ -387,8 +432,8 @@ public partial class Device /// Object size in bytes. /// Timeout. /// Duration. - public bool Read16(out byte[] buffer, out byte[] senseBuffer, byte partition, ulong objectId, uint blocks, - uint blockSize, uint timeout, out double duration) => + public bool Read16(out byte[] buffer, out byte[] senseBuffer, byte partition, ulong objectId, uint blocks, + uint blockSize, uint timeout, out double duration) => Read16(out buffer, out senseBuffer, false, true, partition, objectId, blocks, blockSize, timeout, out duration); /// Reads a number of bytes or objects starting at specified object from the specified partition @@ -408,8 +453,8 @@ public partial class Device /// Object size in bytes. /// Timeout. /// Duration. - public bool Read16(out byte[] buffer, out byte[] senseBuffer, bool sili, bool fixedLen, byte partition, - ulong objectId, uint transferLen, uint objectSize, uint timeout, out double duration) + public bool Read16(out byte[] buffer, out byte[] senseBuffer, bool sili, bool fixedLen, byte partition, + ulong objectId, uint transferLen, uint objectSize, uint timeout, out double duration) { buffer = fixedLen ? new byte[objectSize * transferLen] : new byte[transferLen]; var cdb = new byte[6]; @@ -418,11 +463,9 @@ public partial class Device cdb[0] = (byte)ScsiCommands.Read16; - if(fixedLen) - cdb[1] += 0x01; + if(fixedLen) cdb[1] += 0x01; - if(sili) - cdb[1] += 0x02; + if(sili) cdb[1] += 0x02; cdb[3] = partition; cdb[4] = idBytes[7]; @@ -437,12 +480,17 @@ public partial class Device cdb[13] = (byte)((transferLen & 0xFF00) >> 8); cdb[14] = (byte)(transferLen & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ (16) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_16_took_0_ms, duration); return sense; } @@ -460,12 +508,17 @@ public partial class Device cdb[0] = (byte)ScsiCommands.ReadBlockLimits; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ BLOCK LIMITS took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_BLOCK_LIMITS_took_0_ms, duration); return sense; } @@ -494,19 +547,16 @@ public partial class Device /// Requests current logical position. /// Timeout. /// Duration. - public bool ReadPosition(out byte[] buffer, out byte[] senseBuffer, bool vendorType, bool longForm, - bool totalPosition, uint timeout, out double duration) + public bool ReadPosition(out byte[] buffer, out byte[] senseBuffer, bool vendorType, bool longForm, + bool totalPosition, uint timeout, out double duration) { byte responseForm = 0; - if(vendorType) - responseForm += 0x01; + if(vendorType) responseForm += 0x01; - if(longForm) - responseForm += 0x02; + if(longForm) responseForm += 0x02; - if(totalPosition) - responseForm += 0x04; + if(totalPosition) responseForm += 0x04; return ReadPosition(out buffer, out senseBuffer, (SscPositionForms)responseForm, timeout, out duration); } @@ -520,28 +570,19 @@ public partial class Device public bool ReadPosition(out byte[] buffer, out byte[] senseBuffer, SscPositionForms responseForm, uint timeout, out double duration) { - switch(responseForm) - { - case SscPositionForms.Long: - case SscPositionForms.OldLong: - case SscPositionForms.OldLongTclpVendor: - case SscPositionForms.OldLongVendor: - case SscPositionForms.Extended: - buffer = new byte[32]; - - break; - case SscPositionForms.OldTclp: - case SscPositionForms.OldTclpVendor: - case SscPositionForms.Short: - case SscPositionForms.VendorShort: - buffer = new byte[20]; - - break; - default: - buffer = new byte[32]; // Invalid - - break; - } + buffer = responseForm switch + { + SscPositionForms.Long + or SscPositionForms.OldLong + or SscPositionForms.OldLongTclpVendor + or SscPositionForms.OldLongVendor + or SscPositionForms.Extended => new byte[32], + SscPositionForms.OldTclp + or SscPositionForms.OldTclpVendor + or SscPositionForms.Short + or SscPositionForms.VendorShort => new byte[20], + _ => new byte[32] + }; var cdb = new byte[10]; senseBuffer = new byte[64]; @@ -555,12 +596,17 @@ public partial class Device cdb[8] = (byte)(buffer.Length & 0xFF); } - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ POSITION took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_POSITION_took_0_ms, duration); return sense; } @@ -573,8 +619,15 @@ public partial class Device /// Timeout. /// Duration. public bool ReadReverse6(out byte[] buffer, out byte[] senseBuffer, uint blocks, uint blockSize, uint timeout, - out double duration) => ReadReverse6(out buffer, out senseBuffer, false, false, true, - blocks, blockSize, timeout, out duration); + out double duration) => ReadReverse6(out buffer, + out senseBuffer, + false, + false, + true, + blocks, + blockSize, + timeout, + out duration); /// Reads the specified number of bytes or of blocks from the medium, backwards /// Buffer. @@ -584,8 +637,8 @@ public partial class Device /// Block size in bytes. /// Timeout. /// Duration. - public bool ReadReverse6(out byte[] buffer, out byte[] senseBuffer, bool sili, uint transferLen, uint blockSize, - uint timeout, out double duration) => + public bool ReadReverse6(out byte[] buffer, out byte[] senseBuffer, bool sili, uint transferLen, uint blockSize, + uint timeout, out double duration) => ReadReverse6(out buffer, out senseBuffer, false, sili, false, transferLen, blockSize, timeout, out duration); /// Reads the specified number of bytes or of blocks from the medium, backwards @@ -604,8 +657,8 @@ public partial class Device /// Block size in bytes. /// Timeout. /// Duration. - public bool ReadReverse6(out byte[] buffer, out byte[] senseBuffer, bool byteOrder, bool sili, bool fixedLen, - uint transferLen, uint blockSize, uint timeout, out double duration) + public bool ReadReverse6(out byte[] buffer, out byte[] senseBuffer, bool byteOrder, bool sili, bool fixedLen, + uint transferLen, uint blockSize, uint timeout, out double duration) { buffer = fixedLen ? new byte[blockSize * transferLen] : new byte[transferLen]; var cdb = new byte[6]; @@ -613,25 +666,27 @@ public partial class Device cdb[0] = (byte)ScsiCommands.ReadReverse; - if(fixedLen) - cdb[1] += 0x01; + if(fixedLen) cdb[1] += 0x01; - if(sili) - cdb[1] += 0x02; + if(sili) cdb[1] += 0x02; - if(byteOrder) - cdb[1] += 0x04; + if(byteOrder) cdb[1] += 0x04; cdb[2] = (byte)((transferLen & 0xFF0000) >> 16); cdb[3] = (byte)((transferLen & 0xFF00) >> 8); cdb[4] = (byte)(transferLen & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ REVERSE (6) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_REVERSE_6_took_0_ms, duration); return sense; } @@ -645,9 +700,18 @@ public partial class Device /// Object size in bytes. /// Timeout. /// Duration. - public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, bool sili, ulong objectId, uint blocks, - uint blockSize, uint timeout, out double duration) => - ReadReverse16(out buffer, out senseBuffer, false, sili, false, 0, objectId, blocks, blockSize, timeout, + public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, bool sili, ulong objectId, uint blocks, + uint blockSize, uint timeout, out double duration) => + ReadReverse16(out buffer, + out senseBuffer, + false, + sili, + false, + 0, + objectId, + blocks, + blockSize, + timeout, out duration); /// Reads a number of fixed-length blocks starting at specified block from the specified partition, backwards @@ -660,9 +724,18 @@ public partial class Device /// Object size in bytes. /// Timeout. /// Duration. - public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, bool sili, byte partition, ulong objectId, - uint blocks, uint blockSize, uint timeout, out double duration) => - ReadReverse16(out buffer, out senseBuffer, false, sili, false, partition, objectId, blocks, blockSize, timeout, + public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, bool sili, byte partition, ulong objectId, + uint blocks, uint blockSize, uint timeout, out double duration) => + ReadReverse16(out buffer, + out senseBuffer, + false, + sili, + false, + partition, + objectId, + blocks, + blockSize, + timeout, out duration); /// Reads a number of fixed-length blocks starting at specified object, backwards @@ -673,9 +746,18 @@ public partial class Device /// Object size in bytes. /// Timeout. /// Duration. - public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, ulong objectId, uint blocks, uint blockSize, - uint timeout, out double duration) => - ReadReverse16(out buffer, out senseBuffer, false, false, true, 0, objectId, blocks, blockSize, timeout, + public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, ulong objectId, uint blocks, uint blockSize, + uint timeout, out double duration) => + ReadReverse16(out buffer, + out senseBuffer, + false, + false, + true, + 0, + objectId, + blocks, + blockSize, + timeout, out duration); /// Reads a number of fixed-length blocks starting at specified block from the specified partition, backwards @@ -687,9 +769,18 @@ public partial class Device /// Object size in bytes. /// Timeout. /// Duration. - public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, byte partition, ulong objectId, uint blocks, - uint blockSize, uint timeout, out double duration) => - ReadReverse16(out buffer, out senseBuffer, false, false, true, partition, objectId, blocks, blockSize, timeout, + public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, byte partition, ulong objectId, uint blocks, + uint blockSize, uint timeout, out double duration) => + ReadReverse16(out buffer, + out senseBuffer, + false, + false, + true, + partition, + objectId, + blocks, + blockSize, + timeout, out duration); /// Reads a number of bytes or objects starting at specified object from the specified partition, backwards @@ -710,8 +801,8 @@ public partial class Device /// Object size in bytes. /// Timeout. /// Duration. - public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, bool byteOrder, bool sili, bool fixedLen, - byte partition, ulong objectId, uint transferLen, uint objectSize, uint timeout, + public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, bool byteOrder, bool sili, bool fixedLen, + byte partition, ulong objectId, uint transferLen, uint objectSize, uint timeout, out double duration) { buffer = fixedLen ? new byte[objectSize * transferLen] : new byte[transferLen]; @@ -721,14 +812,11 @@ public partial class Device cdb[0] = (byte)ScsiCommands.Read16; - if(fixedLen) - cdb[1] += 0x01; + if(fixedLen) cdb[1] += 0x01; - if(sili) - cdb[1] += 0x02; + if(sili) cdb[1] += 0x02; - if(byteOrder) - cdb[1] += 0x04; + if(byteOrder) cdb[1] += 0x04; cdb[3] = partition; cdb[4] = idBytes[7]; @@ -743,12 +831,17 @@ public partial class Device cdb[13] = (byte)((transferLen & 0xFF00) >> 8); cdb[14] = (byte)(transferLen & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "READ REVERSE (16) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.READ_REVERSE_16_took_0_ms, duration); return sense; } @@ -760,8 +853,8 @@ public partial class Device /// Block size in bytes. /// Timeout. /// Duration. - public bool RecoverBufferedData(out byte[] buffer, out byte[] senseBuffer, uint blocks, uint blockSize, - uint timeout, out double duration) => + public bool RecoverBufferedData(out byte[] buffer, out byte[] senseBuffer, uint blocks, uint blockSize, + uint timeout, out double duration) => RecoverBufferedData(out buffer, out senseBuffer, false, true, blocks, blockSize, timeout, out duration); /// Reads the specified number of bytes or of blocks from the device's buffer @@ -772,8 +865,8 @@ public partial class Device /// Block size in bytes. /// Timeout. /// Duration. - public bool RecoverBufferedData(out byte[] buffer, out byte[] senseBuffer, bool sili, uint transferLen, - uint blockSize, uint timeout, out double duration) => + public bool RecoverBufferedData(out byte[] buffer, out byte[] senseBuffer, bool sili, uint transferLen, + uint blockSize, uint timeout, out double duration) => RecoverBufferedData(out buffer, out senseBuffer, sili, false, transferLen, blockSize, timeout, out duration); /// Reads the specified number of bytes or of blocks from the device's buffer @@ -791,8 +884,8 @@ public partial class Device /// Block size in bytes. /// Timeout. /// Duration. - public bool RecoverBufferedData(out byte[] buffer, out byte[] senseBuffer, bool sili, bool fixedLen, - uint transferLen, uint blockSize, uint timeout, out double duration) + public bool RecoverBufferedData(out byte[] buffer, out byte[] senseBuffer, bool sili, bool fixedLen, + uint transferLen, uint blockSize, uint timeout, out double duration) { buffer = fixedLen ? new byte[blockSize * transferLen] : new byte[transferLen]; var cdb = new byte[6]; @@ -800,22 +893,25 @@ public partial class Device cdb[0] = (byte)ScsiCommands.RecoverBufferedData; - if(fixedLen) - cdb[1] += 0x01; + if(fixedLen) cdb[1] += 0x01; - if(sili) - cdb[1] += 0x02; + if(sili) cdb[1] += 0x02; cdb[2] = (byte)((transferLen & 0xFF0000) >> 16); cdb[3] = (byte)((transferLen & 0xFF00) >> 8); cdb[4] = (byte)(transferLen & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "RECOVER BUFFERED DATA took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.RECOVER_BUFFERED_DATA_took_0_ms, duration); return sense; } @@ -845,8 +941,8 @@ public partial class Device /// If set to true descriptors should apply to currently inserted media. /// Timeout. /// Duration. - public bool ReportDensitySupport(out byte[] buffer, out byte[] senseBuffer, bool mediumType, bool currentMedia, - uint timeout, out double duration) + public bool ReportDensitySupport(out byte[] buffer, out byte[] senseBuffer, bool mediumType, bool currentMedia, + uint timeout, out double duration) { buffer = new byte[256]; var cdb = new byte[10]; @@ -854,22 +950,24 @@ public partial class Device cdb[0] = (byte)ScsiCommands.ReportDensitySupport; - if(currentMedia) - cdb[1] += 0x01; + if(currentMedia) cdb[1] += 0x01; - if(mediumType) - cdb[1] += 0x02; + if(mediumType) cdb[1] += 0x02; cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[8] = (byte)(buffer.Length & 0xFF); - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out bool sense); Error = LastError != 0; - if(sense) - return true; + if(sense) return true; var availableLength = (ushort)((buffer[0] << 8) + buffer[1] + 2); buffer = new byte[availableLength]; @@ -877,12 +975,17 @@ public partial class Device cdb[8] = (byte)(buffer.Length & 0xFF); senseBuffer = new byte[64]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "REPORT DENSITY SUPPORT took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.REPORT_DENSITY_SUPPORT_took_0_ms, duration); return sense; } @@ -903,19 +1006,23 @@ public partial class Device { senseBuffer = new byte[64]; var cdb = new byte[6]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.Rewind; - if(immediate) - cdb[1] += 0x01; + if(immediate) cdb[1] += 0x01; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "REWIND took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.REWIND_took_0_ms, duration); return sense; } @@ -930,17 +1037,22 @@ public partial class Device { senseBuffer = new byte[64]; var cdb = new byte[6]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; cdb[0] = (byte)ScsiCommands.TrackSelect; cdb[5] = track; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "TRACK SELECT took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.TRACK_SELECT_took_0_ms, duration); return sense; } @@ -956,7 +1068,7 @@ public partial class Device { senseBuffer = new byte[64]; var cdb = new byte[6]; - byte[] buffer = Array.Empty(); + byte[] buffer = []; byte[] countB = BitConverter.GetBytes(count); cdb[0] = (byte)ScsiCommands.Space; @@ -965,12 +1077,17 @@ public partial class Device cdb[3] = countB[1]; cdb[4] = countB[0]; - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out bool sense); Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "SPACE took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.SPACE_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/ScsiCommands/SyQuest.cs b/Aaru.Devices/Device/ScsiCommands/SyQuest.cs index d4e14ce25..ed7f3656a 100644 --- a/Aaru.Devices/Device/ScsiCommands/SyQuest.cs +++ b/Aaru.Devices/Device/ScsiCommands/SyQuest.cs @@ -27,14 +27,15 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - -using System; using Aaru.Console; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Devices; + public partial class Device { /// Sends the SyQuest READ (6) command @@ -46,8 +47,15 @@ public partial class Device /// Starting block. /// Block size in bytes. public bool SyQuestRead6(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint timeout, - out double duration) => SyQuestRead6(out buffer, out senseBuffer, lba, blockSize, 1, false, - false, timeout, out duration); + out double duration) => SyQuestRead6(out buffer, + out senseBuffer, + lba, + blockSize, + 1, + false, + false, + timeout, + out duration); /// Sends the SyQuest READ LONG (6) command /// true if the command failed and contains the sense buffer. @@ -73,7 +81,7 @@ public partial class Device /// Block size in bytes. /// How many blocks to read. public bool SyQuestRead6(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, byte transferLength, - bool inhibitDma, bool readLong, uint timeout, out double duration) + bool inhibitDma, bool readLong, uint timeout, out double duration) { senseBuffer = new byte[64]; var cdb = new byte[6]; @@ -85,14 +93,11 @@ public partial class Device cdb[3] = (byte)(lba & 0xFF); cdb[4] = transferLength; - if(inhibitDma) - cdb[5] += 0x80; + if(inhibitDma) cdb[5] += 0x80; - if(readLong) - cdb[5] += 0x40; + if(readLong) cdb[5] += 0x40; - if(!inhibitDma && - !readLong) + if(!inhibitDma && !readLong) buffer = transferLength == 0 ? new byte[256 * blockSize] : new byte[transferLength * blockSize]; else if(readLong) { @@ -100,18 +105,32 @@ public partial class Device cdb[4] = 1; } else - buffer = Array.Empty(); + buffer = []; if(!inhibitDma) - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + { + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); + } else - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + { + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out sense); + } Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "SYQUEST READ (6) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.SYQUEST_READ_6_took_0_ms, duration); return sense; } @@ -162,14 +181,11 @@ public partial class Device cdb[7] = (byte)((transferLength & 0xFF00) >> 8); cdb[8] = (byte)(transferLength & 0xFF); - if(inhibitDma) - cdb[9] += 0x80; + if(inhibitDma) cdb[9] += 0x80; - if(readLong) - cdb[9] += 0x40; + if(readLong) cdb[9] += 0x40; - if(!inhibitDma && - !readLong) + if(!inhibitDma && !readLong) buffer = new byte[transferLength * blockSize]; else if(readLong) { @@ -177,18 +193,32 @@ public partial class Device cdb[4] = 1; } else - buffer = Array.Empty(); + buffer = []; if(!inhibitDma) - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + { + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.In, + out duration, out sense); + } else - LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, + { + LastError = SendScsiCommand(cdb, + ref buffer, + out senseBuffer, + timeout, + ScsiDirection.None, + out duration, out sense); + } Error = LastError != 0; - AaruConsole.DebugWriteLine("SCSI Device", "SYQUEST READ (10) took {0} ms.", duration); + AaruConsole.DebugWriteLine(SCSI_MODULE_NAME, Localization.SYQUEST_READ_10_took_0_ms, duration); return sense; } diff --git a/Aaru.Devices/Device/Variables.cs b/Aaru.Devices/Device/Variables.cs index 5280936e3..41e8800b6 100644 --- a/Aaru.Devices/Device/Variables.cs +++ b/Aaru.Devices/Device/Variables.cs @@ -27,29 +27,21 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices; - using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interop; using Aaru.CommonTypes.Structs.Devices.SCSI; +namespace Aaru.Devices; + public partial class Device { - private protected ushort _usbVendor; - private protected ushort _usbProduct; - private protected ulong _firewireGuid; - private protected uint _firewireModel; - private protected uint _firewireVendor; - - // MMC and SecureDigital, values that need to be get with card idle, something that may - // not be possible to do but usually is already done by the SDHCI driver. - private protected byte[] _cachedCsd; - private protected byte[] _cachedCid; - private protected byte[] _cachedScr; - private protected byte[] _cachedOcr; + const string ATA_MODULE_NAME = "ATA Device"; + const string SCSI_MODULE_NAME = "SCSI Device"; + const string SD_MODULE_NAME = "SecureDigital Device"; + const string MMC_MODULE_NAME = "MultiMediaCard Device"; /// Gets the Platform ID for this device /// The Platform ID @@ -101,11 +93,11 @@ public partial class Device /// Gets the USB vendor ID. /// The USB vendor ID. - public ushort UsbVendorId => _usbVendor; + public ushort UsbVendorId => UsbVendor; /// Gets the USB product ID. /// The USB product ID. - public ushort UsbProductId => _usbProduct; + public ushort UsbProductId => UsbProduct; /// Gets the USB descriptors. /// The USB descriptors. @@ -129,11 +121,11 @@ public partial class Device /// Gets the FireWire GUID /// The FireWire GUID. - public ulong FireWireGuid => _firewireGuid; + public ulong FireWireGuid => FirewireGuid; /// Gets the FireWire model number /// The FireWire model. - public uint FireWireModel => _firewireModel; + public uint FireWireModel => FirewireModel; /// Gets the FireWire model name. /// The FireWire model name. @@ -141,7 +133,7 @@ public partial class Device /// Gets the FireWire vendor number. /// The FireWire vendor number. - public uint FireWireVendor => _firewireVendor; + public uint FireWireVendor => FirewireVendor; /// Gets the FireWire vendor name. /// The FireWire vendor name. @@ -158,5 +150,19 @@ public partial class Device /// Contains the PCMCIA CIS if applicable public byte[] Cis { get; private protected set; } - private protected string _devicePath; + // MMC and SecureDigital, values that need to be get with card idle, something that may + // not be possible to do but usually is already done by the SDHCI driver. +#pragma warning disable PH2070 // Risks are known. TODO: Maybe protected property? + private protected byte[] CachedCid; + private protected byte[] CachedCsd; + private protected byte[] CachedOcr; + private protected byte[] CachedScr; + + private protected string DevicePath; + private protected ulong FirewireGuid; + private protected uint FirewireModel; + private protected uint FirewireVendor; + private protected ushort UsbProduct; + private protected ushort UsbVendor; +#pragma warning restore PH2070 } \ No newline at end of file diff --git a/Aaru.Devices/Enums.cs b/Aaru.Devices/Enums.cs index e91960161..93094b942 100644 --- a/Aaru.Devices/Enums.cs +++ b/Aaru.Devices/Enums.cs @@ -27,9 +27,12 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System; +using System.Diagnostics.CodeAnalysis; + #pragma warning disable 1591 // ReSharper disable UnusedType.Global @@ -40,14 +43,13 @@ namespace Aaru.Devices; -using System; -using System.Diagnostics.CodeAnalysis; - #region ATA Commands + /// All known ATA commands public enum AtaCommands : byte { - #region Commands defined on Western Digital WD1000 Winchester Disk Controller +#region Commands defined on Western Digital WD1000 Winchester Disk Controller + /// Formats a track FormatTrack = 0x50, @@ -65,9 +67,11 @@ public enum AtaCommands : byte /// Writes sectors WriteOld = 0x30, - #endregion Commands defined on Western Digital WD1000 Winchester Disk Controller - #region Commands defined on ATA rev. 4c +#endregion Commands defined on Western Digital WD1000 Winchester Disk Controller + +#region Commands defined on ATA rev. 4c + /// Acknowledges media change AckMediaChange = 0xDB, @@ -268,17 +272,21 @@ public enum AtaCommands : byte /// Unknown vendor command VendorFf = 0xFF, - #endregion Commands defined on ATA rev. 4c - #region Commands defined on ATA-2 rev. 4c +#endregion Commands defined on ATA rev. 4c + +#region Commands defined on ATA-2 rev. 4c + /// Alters the device microcode DownloadMicrocode = 0x92, /// Ejects the removable medium on the device MediaEject = 0xED, - #endregion Commands defined on ATA-2 rev. 4c - #region Commands defined on ATA-3 rev. 7b +#endregion Commands defined on ATA-2 rev. 4c + +#region Commands defined on ATA-3 rev. 7b + /// Gets a sector containing drive identification and capabilities IdentifyDriveDma = 0xEE, @@ -302,9 +310,11 @@ public enum AtaCommands : byte /// SMART operations Smart = 0xB0, - #endregion Commands defined on ATA-3 rev. 7b - #region Commands defined on CompactFlash Specification +#endregion Commands defined on ATA-3 rev. 7b + +#region Commands defined on CompactFlash Specification + /// Pre-erases and conditions data sectors EraseSectors = 0xC0, @@ -325,9 +335,11 @@ public enum AtaCommands : byte /// Writes sectors without erasing them previously WriteWithoutErase = 0x38, - #endregion Commands defined on CompactFlash Specification - #region Commands defined on ATA/ATAPI-4 rev. 18 +#endregion Commands defined on CompactFlash Specification + +#region Commands defined on ATA/ATAPI-4 rev. 18 + /// Resets a device DeviceReset = 0x08, @@ -366,9 +378,11 @@ public enum AtaCommands : byte /// Queues a write of sectors WriteDmaQueued = 0xCC, - #endregion Commands defined on ATA/ATAPI-4 rev. 18 - #region Commands defined on ATA/ATAPI-6 rev. 3b +#endregion Commands defined on ATA/ATAPI-4 rev. 18 + +#region Commands defined on ATA/ATAPI-6 rev. 3b + /// Determines if the device supports the Media Card Pass Through Command feature set CheckMediaCardType = 0xD1, @@ -419,9 +433,11 @@ public enum AtaCommands : byte /// Writes several sectors at once setting interrupts on end of block (48-bit) WriteMultipleExt = 0x39, - #endregion Commands defined on ATA/ATAPI-6 rev. 3b - #region Commands defined on ATA/ATAPI-7 rev. 4b +#endregion Commands defined on ATA/ATAPI-6 rev. 3b + +#region Commands defined on ATA/ATAPI-7 rev. 4b + /// Configures the operating parameters for a stream ConfigureStream = 0x51, @@ -436,9 +452,11 @@ public enum AtaCommands : byte /// Writes data on an allotted time using PIO WriteStreamExt = 0x3B, - #endregion Commands defined on ATA/ATAPI-7 rev. 4b - #region Commands defined on ATA/ATAPI-8 rev. 3f +#endregion Commands defined on ATA/ATAPI-7 rev. 4b + +#region Commands defined on ATA/ATAPI-8 rev. 3f + /// Sends a Non Volatile Cache subcommand. NonVolatileCacheCommand = 0xB6, @@ -471,9 +489,11 @@ public enum AtaCommands : byte /// Writes a sector that will give an uncorrectable error on any read operation WriteUncorrectableExt = 0x45, - #endregion Commands defined on ATA/ATAPI-8 rev. 3f - #region Commands defined on ATA/ATAPI Command Set 2 (ACS-2) rev. 2 +#endregion Commands defined on ATA/ATAPI-8 rev. 3f + +#region Commands defined on ATA/ATAPI Command Set 2 (ACS-2) rev. 2 + /// Provides information for device optimization In SSDs, this contains trimming DataSetManagement = 0x06, @@ -490,7 +510,8 @@ public enum AtaCommands : byte ReadLogDmaExt = 0x47, /// Requests SPC-4 style error data - RequestSenseDataExt = 0x0B, SanitizeCommands = 0xB4, + RequestSenseDataExt = 0x0B, + SanitizeCommands = 0xB4, /// Executes a Security Protocol command that does not require a transfer of data TrustedNonData = 0x5B, @@ -500,26 +521,35 @@ public enum AtaCommands : byte /// Writes sectors using NCQ WriteFpDmaQueued = 0x61, - #endregion Commands defined on ATA/ATAPI Command Set 2 (ACS-2) rev. 2 - #region Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 +#endregion Commands defined on ATA/ATAPI Command Set 2 (ACS-2) rev. 2 + +#region Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 + /// Sends NcqQueueManagement = 0x63, /// Sets the device date and time SetDateAndTimeExt = 0x77, - #endregion Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 - #region Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 6 +#endregion Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 + +#region Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 6 + NativeMaxAddress = 0x78 - #endregion Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 6 + +#endregion Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 6 } + #endregion ATA Commands + #region ATA SMART SubCommands + /// All known ATA SMART sub-commands public enum AtaSmartSubCommands : byte { - #region Commands defined on ATA-3 rev. 7b +#region Commands defined on ATA-3 rev. 7b + /// Disables all SMART capabilities Disable = 0xD9, @@ -540,30 +570,39 @@ public enum AtaSmartSubCommands : byte /// Saves any attribute values immediately SaveAttributeValues = 0xD3, - #endregion Commands defined on ATA-3 rev. 7b - #region Commands defined on ATA/ATAPI-4 rev. 18 +#endregion Commands defined on ATA-3 rev. 7b + +#region Commands defined on ATA/ATAPI-4 rev. 18 + /// Causes the device to immediately initiate a SMART data collection and saves it to the device ExecuteOfflineImmediate = 0xD4, /// Returns the device's SMART attributes values ReadData = ReadAttributeValues, - #endregion Commands defined on ATA/ATAPI-4 rev. 18 - #region Commands defined on ATA/ATAPI-5 rev. 3 +#endregion Commands defined on ATA/ATAPI-4 rev. 18 + +#region Commands defined on ATA/ATAPI-5 rev. 3 + /// Returns the indicated log to the host ReadLog = 0xD5, /// Writes data to the indicated log WriteLog = 0xD6 - #endregion Commands defined on ATA/ATAPI-5 rev. 3 + +#endregion Commands defined on ATA/ATAPI-5 rev. 3 } + #endregion ATA SMART SubCommands + #region ATA Device Configuration Overlay SubCommands + /// All known ATA DEVICE CONFIGURATION sub-commands public enum AtaDeviceConfigurationSubCommands : byte { - #region Commands defined on ATA/ATAPI-6 rev. 3b +#region Commands defined on ATA/ATAPI-6 rev. 3b + /// Disables any change made by Restore = 0xC0, @@ -575,14 +614,19 @@ public enum AtaDeviceConfigurationSubCommands : byte /// Modifies the commands, modes and features sets the device will obey to Set = 0xC3 - #endregion Commands defined on ATA/ATAPI-6 rev. 3b + +#endregion Commands defined on ATA/ATAPI-6 rev. 3b } + #endregion ATA Device Configuration Overlay SubCommands + #region ATA SET MAX SubCommands + /// All known ATA SET MAX sub-commands public enum AtaSetMaxSubCommands : byte { - #region Commands defined on ATA/ATAPI-6 rev. 3b +#region Commands defined on ATA/ATAPI-6 rev. 3b + /// Redefines the maximum user-accessible address space Address = 0x00, @@ -600,14 +644,19 @@ public enum AtaSetMaxSubCommands : byte /// Disables UnLock = 0x03, - #endregion Commands defined on ATA/ATAPI-6 rev. 3b + +#endregion Commands defined on ATA/ATAPI-6 rev. 3b } + #endregion ATA SET MAX SubCommands + #region ATA Non Volatile Cache SubCommands + /// All known ATA NV CACHE sub-commands public enum AtaNonVolatileCacheSubCommands : byte { - #region Commands defined on ATA/ATAPI-8 rev. 3f +#region Commands defined on ATA/ATAPI-8 rev. 3f + /// Adds the specified LBA to the Non Volatile Cache AddLbaToNvCache = 0x10, @@ -631,14 +680,19 @@ public enum AtaNonVolatileCacheSubCommands : byte /// Cache /// SetNvCachePowerMode = 0x00 - #endregion Commands defined on ATA/ATAPI-8 rev. 3f + +#endregion Commands defined on ATA/ATAPI-8 rev. 3f } + #endregion ATA Non Volatile Cache SubCommands + #region ATA Sanitize SubCommands + /// All known ATA SANITIZE sub-commands public enum AtaSanitizeSubCommands : ushort { - #region Commands defined on ATA/ATAPI Command Set 2 (ACS-2) rev. 2 +#region Commands defined on ATA/ATAPI Command Set 2 (ACS-2) rev. 2 + /// Causes a block erase on all user data BlockEraseExt = 0x0012, @@ -653,36 +707,48 @@ public enum AtaSanitizeSubCommands : ushort /// Gets the status of the sanitizing Status = 0x0000, - #endregion Commands defined on ATA/ATAPI Command Set 2 (ACS-2) rev. 2 - #region Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 +#endregion Commands defined on ATA/ATAPI Command Set 2 (ACS-2) rev. 2 + +#region Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 + /// Disables the command AntiFreezeLockExt = 0x0040 - #endregion Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 + +#endregion Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 } + #endregion ATA Sanitize SubCommands + #region ATA NCQ Queue Management SubCommands + /// All known ATA NCQ QUEUE MANAGEMENT sub-commands public enum AtaNcqQueueManagementSubcommands : byte { - #region Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 +#region Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 + /// Aborts pending NCQ commands AbortNcqQueue = 0x00, /// Controls how NCQ Streaming commands are processed by the device DeadlineHandling = 0x01, - #endregion Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 + +#endregion Commands defined on ATA/ATAPI Command Set 3 (ACS-3) rev. 5 } + #endregion ATA NCQ Queue Management SubCommands /// /// All known SASI commands Commands 0x00 to 0x1F are 6-byte Commands 0x20 to 0x3F are 10-byte Commands 0x40 to /// 0x5F are 8-byte Commands 0xA0 to 0xBF are 12-byte /// + #region SASI Commands + public enum SasiCommands : byte { - #region SASI Class 0 commands +#region SASI Class 0 commands + /// Returns zero status if requested unit is on and ready. SASI rev. 0a TestUnitReady = 0x00, @@ -790,9 +856,11 @@ public enum SasiCommands : byte /// Gets information about a device SASI rev. 0c InquiryOld = 0x1F, - #endregion SASI Class 0 commands - #region SASI Class 1 commands +#endregion SASI Class 0 commands + +#region SASI Class 1 commands + /// SASI rev. 0a Unknown Copy = 0x20, @@ -828,9 +896,11 @@ public enum SasiCommands : byte /// Searches data on blocks using minor than or equal comparison ANSI X3T9.3 No. 185 (SASI) SearchDataLow = 0x32, - #endregion SASI Class 1 commands - #region SASI Class 2 commands +#endregion SASI Class 1 commands + +#region SASI Class 2 commands + /// Unknown SASI rev. 0a Load = 0x40, @@ -893,9 +963,11 @@ public enum SasiCommands : byte /// Searches data on blocks using minor than or equal comparison SASI rev. 0c SearchDataLow8 = 0x59, - #endregion SASI Class 2 commands - #region SASI Class 3 commands +#endregion SASI Class 2 commands + +#region SASI Class 3 commands + /// SASI rev. 0a Skip = 0x60, @@ -916,17 +988,21 @@ public enum SasiCommands : byte /// SASI rev. 0a WriteControl = 0x66, - #endregion SASI Class 3 commands - #region SASI Class 5 commands +#endregion SASI Class 3 commands + +#region SASI Class 5 commands + /// Gets the number of blocks in device. ANSI X3T9.3 No. 185 (SASI) ReadCapacity = 0xA5, /// Sets write or read limits from a specified block ANSI X3T9.3 No. 185 (SASI) SetBlockLimits = 0xA9, - #endregion SASI Class 5 commands - #region SASI Class 6 commands +#endregion SASI Class 5 commands + +#region SASI Class 6 commands + /// SASI rev. 0a DefineFloppyDiskTrackFormat = 0xC0, @@ -941,9 +1017,11 @@ public enum SasiCommands : byte /// SASI rev. 0a ReadDriveType = 0xC6, - #endregion SASI Class 6 commands - #region SASI Class 7 commands +#endregion SASI Class 6 commands + +#region SASI Class 7 commands + /// SASI rev. 0a RamDiagnostic = 0xE0, @@ -964,14 +1042,19 @@ public enum SasiCommands : byte /// Found on a vendor document WriteLong = 0xE6 - #endregion SASI Class 7 commands + +#endregion SASI Class 7 commands } + #endregion SASI Commands + #region SCSI Commands + /// All known SCSI and ATAPI commands public enum ScsiCommands : byte { - #region SCSI Primary Commands (SPC) +#region SCSI Primary Commands (SPC) + /// Commands used to obtain information about the access controls that are active SPC-4 rev. 16 AccessControlIn = 0x86, @@ -1085,14 +1168,17 @@ public enum ScsiCommands : byte /// Writes to the device's buffer SCSI-2 X3T9.2/375R rev. 10l WriteBuffer = 0x3B, - #endregion SCSI Primary Commands (SPC) - #region SCSI Block Commands (SBC) +#endregion SCSI Primary Commands (SPC) + +#region SCSI Block Commands (SBC) + /// Compares blocks with sent data, and if equal, writes those block to device, atomically SBC-3 rev. 25 CompareAndWrite = 0x89, /// Formats the medium into addressable logical blocks ECMA-111 (SCSI-1) - FormatUnit = SasiCommands.FormatUnit, FormatWithPreset = 0x38, + FormatUnit = SasiCommands.FormatUnit, + FormatWithPreset = 0x38, /// Locks blocks from eviction of device's cache SCSI-2 X3T9.2/375R rev. 10l LockUnlockCache = 0x36, @@ -1147,7 +1233,8 @@ public enum ScsiCommands : byte Regenerate = 0x82, /// Requests the device to set the LUN in a vendor specific state ECMA-111 (SCSI-1) - RezeroUnit = SasiCommands.RezeroUnit, Sanitize = 0x48, + RezeroUnit = SasiCommands.RezeroUnit, + Sanitize = 0x48, /// Searches data on blocks ECMA-111 (SCSI-1) SearchDataEqual = SasiCommands.SearchDataEqual, @@ -1235,9 +1322,11 @@ public enum ScsiCommands : byte /// rev. 8c /// XpWrite = 0x51, - #endregion SCSI Block Commands (SBC) - #region SCSI Streaming Commands (SSC) +#endregion SCSI Block Commands (SBC) + +#region SCSI Streaming Commands (SSC) + /// Prepares the medium for use by the LUN SSC-1 rev. 22 FormatMedium = 0x04, @@ -1288,9 +1377,11 @@ public enum ScsiCommands : byte /// Writes the specified number of filemarks or setmarks in the current position ECMA-111 (SCSI-1) WriteFileMarks = 0x10, - #endregion SCSI Streaming Commands (SSC) - #region SCSI Streaming Commands for Printers (SSC) +#endregion SCSI Streaming Commands (SSC) + +#region SCSI Streaming Commands for Printers (SSC) + /// /// Assures that the data in the buffer has been printed, or, for other devices, written to media ECMA-111 /// (SCSI-1) @@ -1314,17 +1405,21 @@ public enum ScsiCommands : byte /// X3T9.2/375R rev. 10l /// SynchronizeBuffer = FlushBuffer, - #endregion SCSI Streaming Commands for Printers (SSC) - #region SCSI Processor Commands +#endregion SCSI Streaming Commands for Printers (SSC) + +#region SCSI Processor Commands + /// Transfers data from the device ECMA-111 (SCSI-1) Receive = 0x08, /// Sends data to the device ECMA-111 (SCSI-1) Send = 0x0A, - #endregion SCSI Processor Commands - #region SCSI Multimedia Commands (MMC) +#endregion SCSI Processor Commands + +#region SCSI Multimedia Commands (MMC) + /// Erases any part of a CD-RW MMC-1 rev. 9 Blank = 0xA1, @@ -1462,9 +1557,11 @@ public enum ScsiCommands : byte /// Stops a scan and continues audio playback from current scanning position MMC-1 rev. 9 StopPlayScan = 0x4E, - #endregion SCSI Multimedia Commands (MMC) - #region SCSI Scanner Commands +#endregion SCSI Multimedia Commands (MMC) + +#region SCSI Scanner Commands + /// Gets information about the data buffer SCSI-2 X3T9.2/375R rev. 10l GetDataBufferStatus = 0x34, @@ -1482,9 +1579,11 @@ public enum ScsiCommands : byte /// Sends data to the device SCSI-2 X3T9.2/375R rev. 10l Send10 = 0x2A, - #endregion SCSI Scanner Commands - #region SCSI Block Commands for Optical Media (SBC) +#endregion SCSI Scanner Commands + +#region SCSI Block Commands for Optical Media (SBC) + /// Erases the specified number of blocks Erase10 = 0x2C, @@ -1529,9 +1628,11 @@ public enum ScsiCommands : byte /// Writes blocks to the device and then verifies them SCSI-2 X3T9.2/375R rev. 10l WriteAndVerify12 = 0xAE, - #endregion SCSI Block Commands for Optical Media (SBC) - #region SCSI Medium Changer Commands (SMC) +#endregion SCSI Block Commands for Optical Media (SBC) + +#region SCSI Medium Changer Commands (SMC) + /// /// Provides a means to exchange the medium in the source element with the medium at destination element SCSI-2 /// X3T9.2/375R rev. 10l @@ -1585,9 +1686,11 @@ public enum ScsiCommands : byte /// X3T9.2/375R rev. 10l /// SendVolumeTag = 0xB6, - #endregion SCSI Medium Changer Commands (SMC) - #region SCSI Communication Commands +#endregion SCSI Medium Changer Commands (SMC) + +#region SCSI Communication Commands + /// Gets data from the device SCSI-2 X3T9.2/375R rev. 10l GetMessage = 0x08, @@ -1605,9 +1708,11 @@ public enum ScsiCommands : byte /// Sends data to the device SCSI-2 X3T9.2/375R rev. 10l SendMessage12 = 0xAA, - #endregion SCSI Communication Commands - #region SCSI Controller Commands +#endregion SCSI Communication Commands + +#region SCSI Controller Commands + /// Commands that get information about redundancy groups SCC-2 rev. 4 RedundancyGroupIn = 0xBA, @@ -1619,9 +1724,11 @@ public enum ScsiCommands : byte /// Commands that set information about volume sets SCC-2 rev. 4 VolumeSetOut = 0xBF, - #endregion SCSI Controller Commands - #region Pioneer CD-ROM SCSI-2 Command Set +#endregion SCSI Controller Commands + +#region Pioneer CD-ROM SCSI-2 Command Set + /// Scans for a block playing a block on each track cross AudioScan = 0xCD, @@ -1644,34 +1751,43 @@ public enum ScsiCommands : byte ReadAllSubCode = 0xDF, /// Sets the spindle speed to be used while reading/writing data to a CD - SetCdSpeed = 0xDA, WriteCdp = 0xE3, - #endregion + SetCdSpeed = 0xDA, + WriteCdp = 0xE3, + +#endregion + +#region ATA Command Pass-Through - #region ATA Command Pass-Through /// Sends a 24-bit ATA command to the device Clashes with ATA CPT rev. 8a AtaPassThrough = 0xA1, /// Sends a 48-bit ATA command to the device ATA CPT rev. 8a AtaPassThrough16 = 0x85, - #endregion ATA Command Pass-Through - #region 6-byte CDB aliases +#endregion ATA Command Pass-Through + +#region 6-byte CDB aliases + ModeSelect6 = ModeSelect, ModeSense6 = ModeSense, Read6 = Read, Seek6 = Seek, Write6 = Write, - #endregion 6-byte CDB aliases - #region SCSI Zoned Block Commands +#endregion 6-byte CDB aliases + +#region SCSI Zoned Block Commands + /// ZBC commands with host->device information ZbcOut = 0x94, /// ZBC commands with device->host information ZbcIn = 0x95, - #endregion - #region SCSI Commands with unknown meaning, mostly vendor specific +#endregion + +#region SCSI Commands with unknown meaning, mostly vendor specific + SetCdSpeedUnk = 0xB8, WriteCdMsf = 0xA2, WriteCd = 0xAA, @@ -1685,9 +1801,11 @@ public enum ScsiCommands : byte WriteLong2 = 0xEA, UnknownCdCommand = 0xD4, UnknownCdCommand2 = 0xD5, - #endregion SCSI Commands with unknown meaning, mostly vendor specific - #region SEGA Packet Interface (all are 12-byte CDB) +#endregion SCSI Commands with unknown meaning, mostly vendor specific + +#region SEGA Packet Interface (all are 12-byte CDB) + /// Verifies that the device can be accessed Sega SPI ver. 1.30 SegaTestUnit = TestUnitReady, @@ -1735,12 +1853,14 @@ public enum ScsiCommands : byte /// Reads disc subcode Sega SPI ver. 1.30 SegaGetSubcode = 0x40, - #endregion SEGA Packet Interface (all are 12-byte CDB) + +#endregion SEGA Packet Interface (all are 12-byte CDB) /// Variable sized Command Description Block SPC-4 rev. 16 VariableSizedCdb = 0x7F, - #region Plextor vendor commands +#region Plextor vendor commands + /// Sends extended commands (like SpeedRead) to Plextor drives PlextorExtend = 0xE9, @@ -1755,19 +1875,25 @@ public enum ScsiCommands : byte /// Reads drive statistics from Plextor drives EEPROM PlextorReadEeprom = 0xF1, - #endregion Plextor vendor commands - #region HL-DT-ST vendor commands +#endregion Plextor vendor commands + +#region HL-DT-ST vendor commands + /// Sends debugging commands to HL-DT-ST DVD drives HlDtStVendor = 0xE7, - #endregion HL-DT-ST vendor commands - #region NEC vendor commands +#endregion HL-DT-ST vendor commands + +#region NEC vendor commands + /// Reads CD-DA data NecReadCdDa = 0xD4, - #endregion NEC vendor commands - #region Adaptec vendor commands +#endregion NEC vendor commands + +#region Adaptec vendor commands + /// Translates a SCSI LBA to a drive's CHS AdaptecTranslate = 0x0F, @@ -1782,54 +1908,68 @@ public enum ScsiCommands : byte /// Reads controller's RAM AdaptecReadBuffer = 0x14, - #endregion Adaptec vendor commands - #region Archive Corp. vendor commands +#endregion Adaptec vendor commands + +#region Archive Corp. vendor commands + /// Gets current position's block address ArchiveRequestBlockAddress = 0x02, /// Seeks to specified block address ArchiveSeekBlock = 0x0C, - #endregion Archive Corp. vendor commands - #region Certance vendor commands +#endregion Archive Corp. vendor commands + +#region Certance vendor commands + /// Parks the load arm in preparation for transport CertanceParkUnpark = 0x06, - #endregion Certance vendor commands - #region Fujitsu vendor commands +#endregion Certance vendor commands + +#region Fujitsu vendor commands + /// Used to check the controller's data and control path FujitsuLoopWriteToRead = 0xC1, /// Used to display a message on the operator panel FujitsuDisplay = 0xCF, - #endregion Fujitsu vendor commands - #region M-Systems vendor commands +#endregion Fujitsu vendor commands + +#region M-Systems vendor commands + /// Securely erases all flash blocks, including defective, spared and unused MSystemsSecurityErase = 0xFF, /// Securely erases all flash blocks, including defective, spared and unused MSystemsSecurityEraseOld = 0xDF, - #endregion M-Systems vendor commands - #region Plasmon vendor commands +#endregion M-Systems vendor commands + +#region Plasmon vendor commands + /// Retrieves sector address PlasmonReadSectorLocation = 0xE6, /// Makes a Compliant WORM block completely unreadable PlasmonShred = 0xEE, - #endregion Plasmon vendor commands - #region Kreon vendor commands +#endregion Plasmon vendor commands + +#region Kreon vendor commands + /// Most Kreon commands start with this KreonCommand = 0xFF, /// Kreon extract Security Sectors command start with this KreonSsCommand = 0xAD, - #endregion Kreon vendor commands - #region MiniDisc vendor commands +#endregion Kreon vendor commands + +#region MiniDisc vendor commands + /// Gets some list of pointers only present on MD-DATA discs MiniDiscReadDTOC = 0xD1, /// Writes some list of pointers only present on MD-DATA discs @@ -1844,12 +1984,16 @@ public enum ScsiCommands : byte MiniDiscReadPosition = 0xD7, /// Gets some values that are identical amongst audio discs and data discs, different between them MiniDiscGetType = 0xD8, - #endregion - #region MediaTek vendor commands +#endregion + +#region MediaTek vendor commands + MediaTekVendorCommand = 0xF1 - #endregion + +#endregion } + #endregion SCSI Commands /// SCSI command transfer direction @@ -1872,6 +2016,7 @@ public enum ScsiDirection } #region SCSI's ATA Command Pass-Through + public enum AtaProtocol : byte { /// Requests a device hard reset (pin 1) @@ -1929,6 +2074,7 @@ public enum AtaTransferRegister : byte /// The STPSIU contains the data length Sptsiu = 3 } + #endregion SCSI's ATA Command Pass-Through /// ZBC sub-commands, mask 0x1F @@ -2001,7 +2147,8 @@ public enum MmcGetConfigurationRt : byte Current = 0x01, /// Drive shall return only the Feature Header with the chosen Feature Descriptor - Single = 0x02, Reserved = 0x03 + Single = 0x02, + Reserved = 0x03 } public enum MmcDiscStructureMediaType : byte @@ -2433,14 +2580,16 @@ public enum SscSpaceCodes : byte SequentialFilemark = 2, /// End-of-data - EndOfData = 3, Obsolete1 = 4, - Obsolete2 = 5 + EndOfData = 3, + Obsolete1 = 4, + Obsolete2 = 5 } /// MMC / SecureDigital commands public enum MmcCommands : byte { - #region Class 1 MMC Commands (Basic and read-stream) +#region Class 1 MMC Commands (Basic and read-stream) + /// Resets device to idle (BC) GoIdle = 0, @@ -2503,11 +2652,14 @@ public enum MmcCommands : byte GoInactiveState = 15, /// The host sends the bus testing data pattern to a device (ADTC, R1) - BusTestWrite = 19, SpiReadOcr = 58, - SpicrcOnOff = 59, - #endregion Class 1 MMC Commands (Basic and read-stream) + BusTestWrite = 19, + SpiReadOcr = 58, + SpicrcOnOff = 59, + +#endregion Class 1 MMC Commands (Basic and read-stream) + +#region Class 2 MMC Commands (Block-oriented read) - #region Class 2 MMC Commands (Block-oriented read) /// Sets the block length in bytes (AC, R1) SetBlocklen = 16, @@ -2519,15 +2671,19 @@ public enum MmcCommands : byte /// 128 blocks of tuning pattern is sent for HS200 optimal sampling point detection (ADTC, R1) SendTuningBlockHs200 = 21, - #endregion Class 2 MMC Commands (Block-oriented read) - #region Class 3 MMC Commands (Stream write) +#endregion Class 2 MMC Commands (Block-oriented read) + +#region Class 3 MMC Commands (Stream write) + /// Writes data stream from host until a follows (ADTC, R1) [Obsolete] WriteDatUntilStop = 20, - #endregion Class 3 MMC Commands (Stream write) - #region Class 4 MMC Commands (Block-oriented write) +#endregion Class 3 MMC Commands (Stream write) + +#region Class 4 MMC Commands (Block-oriented write) + /// /// Defines the number of blocks which are going to be transferred in the immediately succeeding multiple block /// command (AC, R1) @@ -2548,9 +2704,11 @@ public enum MmcCommands : byte /// Sets the real time clock according to information in block (ADTC, R1) SetTime = 49, - #endregion Class 4 MMC Commands (Block-oriented write) - #region Class 5 MMC Commands (Erase) +#endregion Class 4 MMC Commands (Block-oriented write) + +#region Class 5 MMC Commands (Erase) + /// Sets the address of the first erase group (AC, R1) EraseGroupStart = 35, @@ -2559,9 +2717,11 @@ public enum MmcCommands : byte /// Erases previously selected write blocks (AC, R1b) Erase = 38, - #endregion Class 5 MMC Commands (Erase) - #region Class 6 MMC Commands (Block-oriented write protection) +#endregion Class 5 MMC Commands (Erase) + +#region Class 6 MMC Commands (Block-oriented write protection) + /// Sets the write protection bit (AC, R1b) SetWriteProtect = 28, @@ -2573,22 +2733,28 @@ public enum MmcCommands : byte /// Sends the type of write protection that is set for the different write protection groups (ADTC, R1) SentWriteProtectType = 31, - #endregion Class 6 MMC Commands (Block-oriented write protection) - #region Class 7 MMC Commands (Lock) +#endregion Class 6 MMC Commands (Block-oriented write protection) + +#region Class 7 MMC Commands (Lock) + /// Used to set/reset the password or lock/unlock the card (ADTC, R1b) LockUnlock = 42, - #endregion Class 7 MMC Commands (Lock) - #region Class 8 MMC Commands (Application-specific) +#endregion Class 7 MMC Commands (Lock) + +#region Class 8 MMC Commands (Application-specific) + /// Indicates the card that the next command is an application specific command (AC, R1) ApplicationCommand = 55, /// Transfers a data block to/from the card for general purpose / application specific commands (ADTC, R1b) GenericCommand = 56, - #endregion Class 8 MMC Commands (Application-specific) - #region Class 9 MMC Commands (I/O mode) +#endregion Class 8 MMC Commands (Application-specific) + +#region Class 9 MMC Commands (I/O mode) + /// /// Used to write and read 8 bit data field, used to access application dependent registers not defined in MMC /// standard (AC, R4) @@ -2597,17 +2763,21 @@ public enum MmcCommands : byte /// Sets the system into interrupt mode (BCR, R5) GoIrqState = 40, - #endregion Class 9 MMC Commands (I/O mode) - #region Class 10 MMC Commands (Security Protocols) +#endregion Class 9 MMC Commands (I/O mode) + +#region Class 10 MMC Commands (Security Protocols) + /// Reads data blocks (ADTC, R1) ProtocolRead = 53, /// Writes data blocks (ADTC, R1) ProtocolWrite = 54, - #endregion Class 10 MMC Commands (Security Protocols) - #region Class 11 MMC Commands (Command Queue) +#endregion Class 10 MMC Commands (Security Protocols) + +#region Class 11 MMC Commands (Command Queue) + /// Defines data direction, priority, task ID and block count of queued task (AC, R1) QueuedTaskParameters = 44, @@ -2622,25 +2792,31 @@ public enum MmcCommands : byte /// Manages queues and tasks (AC, R1b) CmdQTaskManagement = 48, - #endregion Class 11 MMC Commands (Command Queue) - #region Class 1 SecureDigital Commands (Basic) +#endregion Class 11 MMC Commands (Command Queue) + +#region Class 1 SecureDigital Commands (Basic) + /// Sends SD interface condition (BCR, R7) SendInterfaceCondition = 8, /// Switch to 1.8V bus signaling level (AC, R1) VoltageSwitch = 11, - #endregion Class 1 SecureDigital Commands (Basic) - #region Class 2 SecureDigital Commands (Block-oriented read) +#endregion Class 1 SecureDigital Commands (Basic) + +#region Class 2 SecureDigital Commands (Block-oriented read) + /// 64 bytes of tuning pattern is sent for SDR50 and SDR104 optimal sampling point detection (ADTC, R1) SendTuningBlock = 19, /// Speed class control command (AC, R1b) SpeedClassControl = 20, - #endregion Class 2 SecureDigital Commands (Block-oriented read) - #region Class 11 SecureDigital Commands (Function Extension) +#endregion Class 2 SecureDigital Commands (Block-oriented read) + +#region Class 11 SecureDigital Commands (Function Extension) + /// Single block read type (ADTC, R1) ReadExtraSingle = 48, @@ -2652,7 +2828,8 @@ public enum MmcCommands : byte /// Multiple block write type (ADTC, R1) WriteExtraMulti = 59, - #endregion Class 11 SecureDigital Commands (Function Extension) + +#endregion Class 11 SecureDigital Commands (Function Extension) } /// SecureDigital application-specific commands @@ -2680,7 +2857,8 @@ public enum SecureDigitalCommands : byte SendScr = 51 } -[Flags, SuppressMessage("ReSharper", "ShiftExpressionZeroLeftOperand")] +[Flags] +[SuppressMessage("ReSharper", "ShiftExpressionZeroLeftOperand")] public enum MmcFlags : uint { ResponsePresent = 1 << 0, @@ -2893,7 +3071,8 @@ public enum AtaFeatures : byte DisableReleaseInterrupt = 0xDD, /// Disable SERVICE interrupt - DisableServiceInterrupt = 0xDE, VendorSpecific = 0xE0 + DisableServiceInterrupt = 0xDE, + VendorSpecific = 0xE0 } public enum KreonLockStates : byte diff --git a/Aaru.Devices/Linux/Command.cs b/Aaru.Devices/Linux/Command.cs index fd4e53237..dd996fefe 100644 --- a/Aaru.Devices/Linux/Command.cs +++ b/Aaru.Devices/Linux/Command.cs @@ -28,59 +28,41 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Linux; - using System; +using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; using Aaru.CommonTypes.Interop; using Aaru.Decoders.ATA; +namespace Aaru.Devices.Linux; + partial class Device { /// - public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, + public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, ScsiDirection direction, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; senseBuffer = null; duration = 0; sense = false; - if(buffer == null) - return -1; + if(buffer == null) return -1; - ScsiIoctlDirection dir; - - switch(direction) - { - case ScsiDirection.In: - dir = ScsiIoctlDirection.In; - - break; - case ScsiDirection.Out: - dir = ScsiIoctlDirection.Out; - - break; - case ScsiDirection.Bidirectional: - dir = ScsiIoctlDirection.Unspecified; - - break; - case ScsiDirection.None: - dir = ScsiIoctlDirection.None; - - break; - default: - dir = ScsiIoctlDirection.Unknown; - - break; - } + ScsiIoctlDirection dir = direction switch + { + ScsiDirection.In => ScsiIoctlDirection.In, + ScsiDirection.Out => ScsiIoctlDirection.Out, + ScsiDirection.Bidirectional => ScsiIoctlDirection.Unspecified, + ScsiDirection.None => ScsiIoctlDirection.None, + _ => ScsiIoctlDirection.Unknown + }; var ioHdr = new SgIoHdrT(); @@ -97,24 +79,24 @@ partial class Device ioHdr.timeout = timeout * 1000; ioHdr.flags = (uint)SgFlags.DirectIo; - Marshal.Copy(buffer, 0, ioHdr.dxferp, buffer.Length); - Marshal.Copy(cdb, 0, ioHdr.cmdp, cdb.Length); - Marshal.Copy(senseBuffer, 0, ioHdr.sbp, senseBuffer.Length); + Marshal.Copy(buffer, 0, ioHdr.dxferp, buffer.Length); + Marshal.Copy(cdb, 0, ioHdr.cmdp, cdb.Length); + Marshal.Copy(senseBuffer, 0, ioHdr.sbp, senseBuffer.Length); - DateTime start = DateTime.UtcNow; - int error = Extern.ioctlSg(_fileDescriptor, LinuxIoctl.SgIo, ref ioHdr); - DateTime end = DateTime.UtcNow; + var cmdStopWatch = new Stopwatch(); + cmdStopWatch.Start(); + int error = Extern.ioctlSg(_fileDescriptor, LinuxIoctl.SgIo, ref ioHdr); + cmdStopWatch.Stop(); - if(error < 0) - error = Marshal.GetLastWin32Error(); + if(error < 0) error = Marshal.GetLastWin32Error(); - Marshal.Copy(ioHdr.dxferp, buffer, 0, buffer.Length); - Marshal.Copy(ioHdr.cmdp, cdb, 0, cdb.Length); - Marshal.Copy(ioHdr.sbp, senseBuffer, 0, senseBuffer.Length); + Marshal.Copy(ioHdr.dxferp, buffer, 0, buffer.Length); + Marshal.Copy(ioHdr.cmdp, cdb, 0, cdb.Length); + Marshal.Copy(ioHdr.sbp, senseBuffer, 0, senseBuffer.Length); sense |= (ioHdr.info & SgInfo.OkMask) != SgInfo.Ok; - duration = ioHdr.duration > 0 ? ioHdr.duration : (end - start).TotalMilliseconds; + duration = ioHdr.duration > 0 ? ioHdr.duration : cmdStopWatch.Elapsed.TotalMilliseconds; Marshal.FreeHGlobal(ioHdr.dxferp); Marshal.FreeHGlobal(ioHdr.cmdp); @@ -128,20 +110,18 @@ partial class Device /// SG_IO direction static ScsiDirection AtaProtocolToScsiDirection(AtaProtocol protocol) { - switch(protocol) - { - case AtaProtocol.DeviceDiagnostic: - case AtaProtocol.DeviceReset: - case AtaProtocol.HardReset: - case AtaProtocol.NonData: - case AtaProtocol.SoftReset: - case AtaProtocol.ReturnResponse: return ScsiDirection.None; - case AtaProtocol.PioIn: - case AtaProtocol.UDmaIn: return ScsiDirection.In; - case AtaProtocol.PioOut: - case AtaProtocol.UDmaOut: return ScsiDirection.Out; - default: return ScsiDirection.Unspecified; - } + return protocol switch + { + AtaProtocol.DeviceDiagnostic + or AtaProtocol.DeviceReset + or AtaProtocol.HardReset + or AtaProtocol.NonData + or AtaProtocol.SoftReset + or AtaProtocol.ReturnResponse => ScsiDirection.None, + AtaProtocol.PioIn or AtaProtocol.UDmaIn => ScsiDirection.In, + AtaProtocol.PioOut or AtaProtocol.UDmaOut => ScsiDirection.Out, + _ => ScsiDirection.Unspecified + }; } /// @@ -150,38 +130,27 @@ partial class Device uint timeout, bool transferBlocks, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; duration = 0; sense = false; errorRegisters = new AtaErrorRegistersChs(); - if(buffer == null) - return -1; + if(buffer == null) return -1; var cdb = new byte[16]; cdb[0] = (byte)ScsiCommands.AtaPassThrough16; - cdb[1] = (byte)(((byte)protocol << 1) & 0x1E); + cdb[1] = (byte)((byte)protocol << 1 & 0x1E); - if(transferRegister != AtaTransferRegister.NoTransfer && - protocol != AtaProtocol.NonData) + if(transferRegister != AtaTransferRegister.NoTransfer && protocol != AtaProtocol.NonData) { - switch(protocol) - { - case AtaProtocol.PioIn: - case AtaProtocol.UDmaIn: - cdb[2] = 0x08; + cdb[2] = protocol switch + { + AtaProtocol.PioIn or AtaProtocol.UDmaIn => 0x08, + _ => 0x00 + }; - break; - default: - cdb[2] = 0x00; - - break; - } - - if(transferBlocks) - cdb[2] |= 0x04; + if(transferBlocks) cdb[2] |= 0x04; cdb[2] |= (byte)((int)transferRegister & 0x03); } @@ -196,12 +165,15 @@ partial class Device cdb[13] = registers.DeviceHead; cdb[14] = registers.Command; - int error = SendScsiCommand(cdb, ref buffer, out byte[] senseBuffer, timeout, - AtaProtocolToScsiDirection(protocol), out duration, out sense); + int error = SendScsiCommand(cdb, + ref buffer, + out byte[] senseBuffer, + timeout, + AtaProtocolToScsiDirection(protocol), + out duration, + out sense); - if(senseBuffer.Length < 22 || - senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) - return error; + if(senseBuffer.Length < 22 || senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) return error; errorRegisters.Error = senseBuffer[11]; @@ -223,38 +195,27 @@ partial class Device uint timeout, bool transferBlocks, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba28(); - if(buffer == null) - return -1; + if(buffer == null) return -1; var cdb = new byte[16]; cdb[0] = (byte)ScsiCommands.AtaPassThrough16; - cdb[1] = (byte)(((byte)protocol << 1) & 0x1E); + cdb[1] = (byte)((byte)protocol << 1 & 0x1E); - if(transferRegister != AtaTransferRegister.NoTransfer && - protocol != AtaProtocol.NonData) + if(transferRegister != AtaTransferRegister.NoTransfer && protocol != AtaProtocol.NonData) { - switch(protocol) - { - case AtaProtocol.PioIn: - case AtaProtocol.UDmaIn: - cdb[2] = 0x08; + cdb[2] = protocol switch + { + AtaProtocol.PioIn or AtaProtocol.UDmaIn => 0x08, + _ => 0x00 + }; - break; - default: - cdb[2] = 0x00; - - break; - } - - if(transferBlocks) - cdb[2] |= 0x04; + if(transferBlocks) cdb[2] |= 0x04; cdb[2] |= (byte)((int)transferRegister & 0x03); } @@ -269,12 +230,15 @@ partial class Device cdb[13] = registers.DeviceHead; cdb[14] = registers.Command; - int error = SendScsiCommand(cdb, ref buffer, out byte[] senseBuffer, timeout, - AtaProtocolToScsiDirection(protocol), out duration, out sense); + int error = SendScsiCommand(cdb, + ref buffer, + out byte[] senseBuffer, + timeout, + AtaProtocolToScsiDirection(protocol), + out duration, + out sense); - if(senseBuffer.Length < 22 || - senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) - return error; + if(senseBuffer.Length < 22 || senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) return error; errorRegisters.Error = senseBuffer[11]; @@ -296,39 +260,28 @@ partial class Device uint timeout, bool transferBlocks, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba48(); - if(buffer == null) - return -1; + if(buffer == null) return -1; var cdb = new byte[16]; cdb[0] = (byte)ScsiCommands.AtaPassThrough16; - cdb[1] = (byte)(((byte)protocol << 1) & 0x1E); + cdb[1] = (byte)((byte)protocol << 1 & 0x1E); cdb[1] |= 0x01; - if(transferRegister != AtaTransferRegister.NoTransfer && - protocol != AtaProtocol.NonData) + if(transferRegister != AtaTransferRegister.NoTransfer && protocol != AtaProtocol.NonData) { - switch(protocol) - { - case AtaProtocol.PioIn: - case AtaProtocol.UDmaIn: - cdb[2] = 0x08; + cdb[2] = protocol switch + { + AtaProtocol.PioIn or AtaProtocol.UDmaIn => 0x08, + _ => 0x00 + }; - break; - default: - cdb[2] = 0x00; - - break; - } - - if(transferBlocks) - cdb[2] |= 0x04; + if(transferBlocks) cdb[2] |= 0x04; cdb[2] |= (byte)((int)transferRegister & 0x03); } @@ -348,12 +301,15 @@ partial class Device cdb[13] = registers.DeviceHead; cdb[14] = registers.Command; - int error = SendScsiCommand(cdb, ref buffer, out byte[] senseBuffer, timeout, - AtaProtocolToScsiDirection(protocol), out duration, out sense); + int error = SendScsiCommand(cdb, + ref buffer, + out byte[] senseBuffer, + timeout, + AtaProtocolToScsiDirection(protocol), + out duration, + out sense); - if(senseBuffer.Length < 22 || - senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) - return error; + if(senseBuffer.Length < 22 || senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) return error; errorRegisters.Error = senseBuffer[11]; @@ -375,65 +331,63 @@ partial class Device } /// - public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, - uint argument, uint blockSize, uint blocks, ref byte[] buffer, - out uint[] response, out double duration, out bool sense, uint timeout = 15) + public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, + uint argument, uint blockSize, uint blocks, ref byte[] buffer, + out uint[] response, out double duration, out bool sense, uint timeout = 15) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; - DateTime start; - DateTime end; + var cmdStopwatch = new Stopwatch(); switch(command) { - case MmcCommands.SendCid when _cachedCid != null: + case MmcCommands.SendCid when CachedCid != null: { - start = DateTime.Now; - buffer = new byte[_cachedCid.Length]; - Array.Copy(_cachedCid, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedCid.Length]; + Array.Copy(CachedCid, buffer, buffer.Length); response = new uint[4]; sense = false; - end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } - case MmcCommands.SendCsd when _cachedCid != null: + case MmcCommands.SendCsd when CachedCid != null: { - start = DateTime.Now; - buffer = new byte[_cachedCsd.Length]; - Array.Copy(_cachedCsd, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedCsd.Length]; + Array.Copy(CachedCsd, buffer, buffer.Length); response = new uint[4]; sense = false; - end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } - case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null: + case (MmcCommands)SecureDigitalCommands.SendScr when CachedScr != null: { - start = DateTime.Now; - buffer = new byte[_cachedScr.Length]; - Array.Copy(_cachedScr, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedScr.Length]; + Array.Copy(CachedScr, buffer, buffer.Length); response = new uint[4]; sense = false; - end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } - case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null: - case MmcCommands.SendOpCond when _cachedOcr != null: + case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when CachedOcr != null: + case MmcCommands.SendOpCond when CachedOcr != null: { - start = DateTime.Now; - buffer = new byte[_cachedOcr.Length]; - Array.Copy(_cachedOcr, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedOcr.Length]; + Array.Copy(CachedOcr, buffer, buffer.Length); response = new uint[4]; sense = false; - end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } @@ -443,12 +397,11 @@ partial class Device duration = 0; sense = false; - if(buffer == null) - return -1; + if(buffer == null) return -1; var ioCmd = new MmcIocCmd(); - IntPtr bufPtr = Marshal.AllocHGlobal(buffer.Length); + nint bufPtr = Marshal.AllocHGlobal(buffer.Length); ioCmd.write_flag = write; ioCmd.is_ascmd = isApplication; @@ -468,19 +421,19 @@ partial class Device Marshal.Copy(buffer, 0, bufPtr, buffer.Length); - start = DateTime.UtcNow; + var stopWatch = new Stopwatch(); + stopWatch.Restart(); int error = Extern.ioctlMmc(_fileDescriptor, LinuxIoctl.MmcIocCmd, ref ioCmd); - end = DateTime.UtcNow; + stopWatch.Stop(); sense |= error < 0; - if(error < 0) - error = Marshal.GetLastWin32Error(); + if(error < 0) error = Marshal.GetLastWin32Error(); Marshal.Copy(bufPtr, buffer, 0, buffer.Length); response = ioCmd.response; - duration = (end - start).TotalMilliseconds; + duration = stopWatch.Elapsed.TotalMilliseconds; Marshal.FreeHGlobal(bufPtr); @@ -489,18 +442,16 @@ partial class Device /// public override int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense, - uint timeout = 15) + uint timeout = 15) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; duration = 0; sense = false; - int off; // Create array for buffers - var bufferPointers = new IntPtr[commands.Length]; + var bufferPointers = new nint[commands.Length]; // Allocate memory for the array for commands var ioMultiCmd = new byte[sizeof(ulong) + Marshal.SizeOf() * commands.Length]; @@ -508,7 +459,7 @@ partial class Device // First value of array is uint64 with count of commands Array.Copy(BitConverter.GetBytes((ulong)commands.Length), 0, ioMultiCmd, 0, sizeof(ulong)); - off = sizeof(ulong); + int off = sizeof(ulong); for(var i = 0; i < commands.Length; i++) { @@ -547,22 +498,22 @@ partial class Device } // Allocate unmanaged memory for array of commands - IntPtr ioMultiCmdPtr = Marshal.AllocHGlobal(ioMultiCmd.Length); + nint ioMultiCmdPtr = Marshal.AllocHGlobal(ioMultiCmd.Length); // Copy array of commands to unmanaged memory Marshal.Copy(ioMultiCmd, 0, ioMultiCmdPtr, ioMultiCmd.Length); // Send command - DateTime start = DateTime.UtcNow; - int error = Extern.ioctlMmcMulti(_fileDescriptor, LinuxIoctl.MmcIocMultiCmd, ioMultiCmdPtr); - DateTime end = DateTime.UtcNow; + var cmdStopwatch = new Stopwatch(); + cmdStopwatch.Start(); + int error = Extern.ioctlMmcMulti(_fileDescriptor, LinuxIoctl.MmcIocMultiCmd, ioMultiCmdPtr); + cmdStopwatch.Stop(); sense |= error < 0; - if(error < 0) - error = Marshal.GetLastWin32Error(); + if(error < 0) error = Marshal.GetLastWin32Error(); - duration = (end - start).TotalMilliseconds; + duration = cmdStopwatch.Elapsed.TotalMilliseconds; off = sizeof(ulong); @@ -611,7 +562,7 @@ partial class Device return true; } - int newFd = Extern.open(_devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew); + int newFd = Extern.open(DevicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew); if(newFd >= 0) { @@ -623,8 +574,7 @@ partial class Device int error = Marshal.GetLastWin32Error(); - if(error != 13 && - error != 30) + if(error != 13 && error != 30) { LastError = Marshal.GetLastWin32Error(); Error = true; @@ -632,7 +582,7 @@ partial class Device return true; } - newFd = Extern.open(_devicePath, FileFlags.Readonly | FileFlags.NonBlocking); + newFd = Extern.open(DevicePath, FileFlags.Readonly | FileFlags.NonBlocking); if(newFd < 0) { @@ -653,15 +603,14 @@ partial class Device /// Contents of the symbolic link static string ReadLink(string path) { - IntPtr buf = Marshal.AllocHGlobal(4096); - int resultSize; + nint buf = Marshal.AllocHGlobal(4096); + int resultSize; if(DetectOS.Is64Bit) { long result64 = Extern.readlink64(path, buf, 4096); - if(result64 <= 0) - return null; + if(result64 <= 0) return null; resultSize = (int)result64; } @@ -669,8 +618,7 @@ partial class Device { int result = Extern.readlink(path, buf, 4096); - if(result <= 0) - return null; + if(result <= 0) return null; resultSize = result; } @@ -688,15 +636,15 @@ partial class Device { buffer = new byte[length]; - DateTime start = DateTime.Now; + var cmdStopwatch = new Stopwatch(); + cmdStopwatch.Start(); long sense = Extern.lseek(_fileDescriptor, offset, SeekWhence.Begin); - DateTime end = DateTime.Now; - if(sense < 0) { - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; Error = true; LastError = Marshal.GetLastWin32Error(); @@ -704,18 +652,18 @@ partial class Device return true; } - sense = DetectOS.Is64Bit ? Extern.read64(_fileDescriptor, buffer, length) + sense = DetectOS.Is64Bit + ? Extern.read64(_fileDescriptor, buffer, length) : Extern.read(_fileDescriptor, buffer, (int)length); - end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; int errno = Marshal.GetLastWin32Error(); if(sense == length) - errno = 0; - else if(errno == 0) - errno = -22; + errno = 0; + else if(errno == 0) errno = -22; LastError = errno; Error = errno == 0; diff --git a/Aaru.Devices/Linux/Device.cs b/Aaru.Devices/Linux/Device.cs index ec096cc78..ea6e68f79 100644 --- a/Aaru.Devices/Linux/Device.cs +++ b/Aaru.Devices/Linux/Device.cs @@ -27,23 +27,24 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Linux; - using System; using System.Globalization; using System.IO; -using System.Runtime.InteropServices; using System.Runtime.Versioning; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interop; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.SecureDigital; +using Aaru.Helpers; +using Marshal = System.Runtime.InteropServices.Marshal; using PlatformID = Aaru.CommonTypes.Interop.PlatformID; using VendorString = Aaru.Decoders.MMC.VendorString; +namespace Aaru.Devices.Linux; + /// [SupportedOSPlatform("linux")] partial class Device : Devices.Device @@ -95,8 +96,7 @@ partial class Device : Devices.Device } // Seems ioctl(2) does not allow the atomicity needed - if(dev.PlatformId == PlatformID.Linux) - _readMultipleBlockCannotSetBlockCount = true; + if(dev.PlatformId == PlatformID.Linux) _readMultipleBlockCannotSetBlockCount = true; dev.Type = DeviceType.Unknown; dev.ScsiType = PeripheralDeviceTypes.UnknownDevice; @@ -114,6 +114,7 @@ partial class Device : Devices.Device devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || devicePath.StartsWith("/dev/st", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sg", StringComparison.Ordinal)) + { if(!dev.ScsiInquiry(out byte[] _, out _)) dev.Type = DeviceType.SCSI; @@ -124,47 +125,45 @@ partial class Device : Devices.Device if(File.Exists("/sys/block/" + devPath + "/device/csd")) { - int len = ConvertFromFileHexAscii("/sys/block/" + devPath + "/device/csd", out dev._cachedCsd); + int len = ConvertFromFileHexAscii("/sys/block/" + devPath + "/device/csd", out dev.CachedCsd); - if(len == 0) - dev._cachedCsd = null; + if(len == 0) dev.CachedCsd = null; } if(File.Exists("/sys/block/" + devPath + "/device/cid")) { - int len = ConvertFromFileHexAscii("/sys/block/" + devPath + "/device/cid", out dev._cachedCid); + int len = ConvertFromFileHexAscii("/sys/block/" + devPath + "/device/cid", out dev.CachedCid); - if(len == 0) - dev._cachedCid = null; + if(len == 0) dev.CachedCid = null; } if(File.Exists("/sys/block/" + devPath + "/device/scr")) { - int len = ConvertFromFileHexAscii("/sys/block/" + devPath + "/device/scr", out dev._cachedScr); + int len = ConvertFromFileHexAscii("/sys/block/" + devPath + "/device/scr", out dev.CachedScr); - if(len == 0) - dev._cachedScr = null; + if(len == 0) dev.CachedScr = null; } if(File.Exists("/sys/block/" + devPath + "/device/ocr")) { - int len = ConvertFromFileHexAscii("/sys/block/" + devPath + "/device/ocr", out dev._cachedOcr); + int len = ConvertFromFileHexAscii("/sys/block/" + devPath + "/device/ocr", out dev.CachedOcr); - if(len == 0) - dev._cachedOcr = null; + if(len == 0) dev.CachedOcr = null; } } + } - #region SecureDigital / MultiMediaCard - if(dev._cachedCid != null) +#region SecureDigital / MultiMediaCard + + if(dev.CachedCid != null) { dev.ScsiType = PeripheralDeviceTypes.DirectAccess; dev.IsRemovable = false; - if(dev._cachedScr != null) + if(dev.CachedScr != null) { dev.Type = DeviceType.SecureDigital; - CID decoded = Decoders.DecodeCID(dev._cachedCid); + CID decoded = Decoders.SecureDigital.Decoders.DecodeCID(dev.CachedCid); dev.Manufacturer = VendorString.Prettify(decoded.Manufacturer); dev.Model = decoded.ProductName; @@ -176,7 +175,7 @@ partial class Device : Devices.Device else { dev.Type = DeviceType.MMC; - Aaru.Decoders.MMC.CID decoded = Aaru.Decoders.MMC.Decoders.DecodeCID(dev._cachedCid); + Decoders.MMC.CID decoded = Decoders.MMC.Decoders.DecodeCID(dev.CachedCid); dev.Manufacturer = VendorString.Prettify(decoded.Manufacturer); dev.Model = decoded.ProductName; @@ -188,9 +187,11 @@ partial class Device : Devices.Device return dev; } - #endregion SecureDigital / MultiMediaCard - #region USB +#endregion SecureDigital / MultiMediaCard + +#region USB + string resolvedLink; if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || @@ -219,7 +220,7 @@ partial class Device : Devices.Device var usbFs = new FileStream(resolvedLink + "/descriptors", FileMode.Open, FileAccess.Read); var usbBuf = new byte[65536]; - int usbCount = usbFs.Read(usbBuf, 0, 65536); + int usbCount = usbFs.EnsureRead(usbBuf, 0, 65536); dev.UsbDescriptors = new byte[usbCount]; Array.Copy(usbBuf, 0, dev.UsbDescriptors, 0, usbCount); usbFs.Close(); @@ -227,16 +228,20 @@ partial class Device : Devices.Device var usbSr = new StreamReader(resolvedLink + "/idProduct"); string usbTemp = usbSr.ReadToEnd(); - ushort.TryParse(usbTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, - out dev._usbProduct); + ushort.TryParse(usbTemp, + NumberStyles.HexNumber, + CultureInfo.InvariantCulture, + out dev.UsbProduct); usbSr.Close(); usbSr = new StreamReader(resolvedLink + "/idVendor"); usbTemp = usbSr.ReadToEnd(); - ushort.TryParse(usbTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, - out dev._usbVendor); + ushort.TryParse(usbTemp, + NumberStyles.HexNumber, + CultureInfo.InvariantCulture, + out dev.UsbVendor); usbSr.Close(); @@ -268,9 +273,11 @@ partial class Device : Devices.Device } } } - #endregion USB - #region FireWire +#endregion USB + +#region FireWire + if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || devicePath.StartsWith("/dev/st", StringComparison.Ordinal)) @@ -283,6 +290,7 @@ partial class Device : Devices.Device resolvedLink = "/sys" + resolvedLink[2..]; if(!string.IsNullOrEmpty(resolvedLink)) + { while(resolvedLink?.Contains("firewire") == true) { resolvedLink = Path.GetDirectoryName(resolvedLink); @@ -295,24 +303,30 @@ partial class Device : Devices.Device var fwSr = new StreamReader(resolvedLink + "/model"); string fwTemp = fwSr.ReadToEnd(); - uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, - out dev._firewireModel); + uint.TryParse(fwTemp, + NumberStyles.HexNumber, + CultureInfo.InvariantCulture, + out dev.FirewireModel); fwSr.Close(); fwSr = new StreamReader(resolvedLink + "/vendor"); fwTemp = fwSr.ReadToEnd(); - uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, - out dev._firewireVendor); + uint.TryParse(fwTemp, + NumberStyles.HexNumber, + CultureInfo.InvariantCulture, + out dev.FirewireVendor); fwSr.Close(); fwSr = new StreamReader(resolvedLink + "/guid"); fwTemp = fwSr.ReadToEnd(); - ulong.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, - out dev._firewireGuid); + ulong.TryParse(fwTemp, + NumberStyles.HexNumber, + CultureInfo.InvariantCulture, + out dev.FirewireGuid); fwSr.Close(); @@ -334,11 +348,14 @@ partial class Device : Devices.Device break; } + } } } - #endregion FireWire - #region PCMCIA +#endregion FireWire + +#region PCMCIA + if(!devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) && !devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) && !devicePath.StartsWith("/dev/st", StringComparison.Ordinal)) @@ -346,38 +363,33 @@ partial class Device : Devices.Device devPath = devicePath[5..]; - if(!Directory.Exists("/sys/block/" + devPath)) - return dev; + if(!Directory.Exists("/sys/block/" + devPath)) return dev; resolvedLink = ReadLink("/sys/block/" + devPath); resolvedLink = "/sys" + resolvedLink[2..]; - if(string.IsNullOrEmpty(resolvedLink)) - return dev; + if(string.IsNullOrEmpty(resolvedLink)) return dev; while(resolvedLink.Contains("/sys/devices")) { resolvedLink = Path.GetDirectoryName(resolvedLink); - if(!Directory.Exists(resolvedLink + "/pcmcia_socket")) - continue; + if(!Directory.Exists(resolvedLink + "/pcmcia_socket")) continue; - string[] subdirs = Directory.GetDirectories(resolvedLink + "/pcmcia_socket", "pcmcia_socket*", + string[] subdirs = Directory.GetDirectories(resolvedLink + "/pcmcia_socket", + "pcmcia_socket*", SearchOption.TopDirectoryOnly); - if(subdirs.Length <= 0) - continue; + if(subdirs.Length <= 0) continue; string possibleDir = Path.Combine(resolvedLink, "pcmcia_socket", subdirs[0]); - if(!File.Exists(possibleDir + "/card_type") || - !File.Exists(possibleDir + "/cis")) - continue; + if(!File.Exists(possibleDir + "/card_type") || !File.Exists(possibleDir + "/cis")) continue; var cisFs = new FileStream(possibleDir + "/cis", FileMode.Open, FileAccess.Read); var cisBuf = new byte[65536]; - int cisCount = cisFs.Read(cisBuf, 0, 65536); + int cisCount = cisFs.EnsureRead(cisBuf, 0, 65536); dev.Cis = new byte[cisCount]; Array.Copy(cisBuf, 0, dev.Cis, 0, cisCount); cisFs.Close(); @@ -386,7 +398,8 @@ partial class Device : Devices.Device break; } - #endregion PCMCIA + +#endregion PCMCIA return dev; } @@ -406,8 +419,7 @@ partial class Device : Devices.Device /// public override void Close() { - if(_fileDescriptor == 0) - return; + if(_fileDescriptor == 0) return; Extern.close(_fileDescriptor); diff --git a/Aaru.Devices/Linux/Enums.cs b/Aaru.Devices/Linux/Enums.cs index 4d87c0156..10525a3fb 100644 --- a/Aaru.Devices/Linux/Enums.cs +++ b/Aaru.Devices/Linux/Enums.cs @@ -28,15 +28,17 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System; +using System.Diagnostics.CodeAnalysis; + namespace Aaru.Devices.Linux; -using System; - [Flags] -enum FileFlags +[SuppressMessage("ReSharper", "UnusedMember.Global")] +enum FileFlags : uint { /// O_RDONLY Readonly = 0x0, @@ -89,6 +91,7 @@ enum ScsiIoctlDirection Unknown = -5 } +[SuppressMessage("ReSharper", "UnusedMember.Global")] enum LinuxIoctl : uint { // SCSI IOCtls @@ -101,6 +104,7 @@ enum LinuxIoctl : uint } [Flags] +[SuppressMessage("ReSharper", "UnusedMember.Global")] enum SgInfo : uint { /// Mask to check OK @@ -121,6 +125,7 @@ enum SgInfo : uint } [Flags] +[SuppressMessage("ReSharper", "UnusedMember.Global")] enum SgFlags : uint { DirectIo = 1, @@ -131,6 +136,7 @@ enum SgFlags : uint QAtHead = 0x20 } +[SuppressMessage("ReSharper", "UnusedMember.Global")] enum SeekWhence { Begin = 0, diff --git a/Aaru.Devices/Linux/Extern.cs b/Aaru.Devices/Linux/Extern.cs index ceb261b74..392b310ab 100644 --- a/Aaru.Devices/Linux/Extern.cs +++ b/Aaru.Devices/Linux/Extern.cs @@ -28,55 +28,68 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + namespace Aaru.Devices.Linux; -using System; -using System.Runtime.InteropServices; - -static class Extern +static partial class Extern { - [DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern int open(string pathname, [MarshalAs(UnmanagedType.U4)] FileFlags flags); + [LibraryImport("libc", + SetLastError = true, + StringMarshalling = StringMarshalling.Custom, + StringMarshallingCustomType = typeof(AnsiStringMarshaller))] + internal static partial int open(string pathname, FileFlags flags); - [DllImport("libc")] - internal static extern int close(int fd); + [LibraryImport("libc")] + internal static partial int close(int fd); - [DllImport("libc", EntryPoint = "ioctl", SetLastError = true)] - internal static extern int ioctlInt(int fd, LinuxIoctl request, out int value); - - [DllImport("libc", EntryPoint = "ioctl", SetLastError = true)] - internal static extern int ioctlSg(int fd, LinuxIoctl request, ref SgIoHdrT value); + [LibraryImport("libc", EntryPoint = "ioctl", SetLastError = true)] + internal static partial int ioctlSg(int fd, LinuxIoctl request, ref SgIoHdrT value); [DllImport("libc", EntryPoint = "ioctl", SetLastError = true)] internal static extern int ioctlMmc(int fd, LinuxIoctl request, ref MmcIocCmd value); - [DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern int readlink(string path, IntPtr buf, int bufsize); + [LibraryImport("libc", + SetLastError = true, + StringMarshalling = StringMarshalling.Custom, + StringMarshallingCustomType = typeof(AnsiStringMarshaller))] + internal static partial int readlink(string path, nint buf, int bufsize); - [DllImport("libc", CharSet = CharSet.Ansi, EntryPoint = "readlink", SetLastError = true)] - internal static extern long readlink64(string path, IntPtr buf, long bufsize); + [LibraryImport("libc", + EntryPoint = "readlink", + SetLastError = true, + StringMarshalling = StringMarshalling.Custom, + StringMarshallingCustomType = typeof(AnsiStringMarshaller))] + internal static partial long readlink64(string path, nint buf, long bufsize); - [DllImport("libudev", CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern IntPtr udev_new(); + [LibraryImport("libudev", SetLastError = true)] + internal static partial nint udev_new(); - [DllImport("libudev", CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern IntPtr udev_device_new_from_subsystem_sysname(IntPtr udev, string subsystem, string sysname); + [LibraryImport("libudev", + SetLastError = true, + StringMarshalling = StringMarshalling.Custom, + StringMarshallingCustomType = typeof(AnsiStringMarshaller))] + internal static partial nint udev_device_new_from_subsystem_sysname(nint udev, string subsystem, string sysname); - [DllImport("libudev", CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern string udev_device_get_property_value(IntPtr udevDevice, string key); + [LibraryImport("libudev", + SetLastError = true, + StringMarshalling = StringMarshalling.Custom, + StringMarshallingCustomType = typeof(AnsiStringMarshaller))] + internal static partial string udev_device_get_property_value(nint udevDevice, string key); - [DllImport("libc", EntryPoint = "ioctl", SetLastError = true)] - internal static extern int ioctlMmcMulti(int fd, LinuxIoctl request, IntPtr value); + [LibraryImport("libc", EntryPoint = "ioctl", SetLastError = true)] + internal static partial int ioctlMmcMulti(int fd, LinuxIoctl request, nint value); - [DllImport("libc", SetLastError = true)] - internal static extern long lseek(int fd, long offset, SeekWhence whence); + [LibraryImport("libc", SetLastError = true)] + internal static partial long lseek(int fd, long offset, SeekWhence whence); - [DllImport("libc", SetLastError = true)] - internal static extern int read(int fd, byte[] buf, int count); + [LibraryImport("libc", SetLastError = true)] + internal static partial int read(int fd, byte[] buf, int count); - [DllImport("libc", EntryPoint = "read", SetLastError = true)] - internal static extern long read64(int fd, byte[] buf, long count); + [LibraryImport("libc", EntryPoint = "read", SetLastError = true)] + internal static partial long read64(int fd, byte[] buf, long count); } \ No newline at end of file diff --git a/Aaru.Devices/Linux/ListDevices.cs b/Aaru.Devices/Linux/ListDevices.cs index 61441e027..22aa49e3c 100644 --- a/Aaru.Devices/Linux/ListDevices.cs +++ b/Aaru.Devices/Linux/ListDevices.cs @@ -27,16 +27,17 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Linux; - using System; using System.IO; +using System.Runtime.Versioning; using System.Text; -[System.Runtime.Versioning.SupportedOSPlatform("linux")] +namespace Aaru.Devices.Linux; + +[SupportedOSPlatform("linux")] static class ListDevices { const string PATH_SYS_DEVBLOCK = "/sys/block/"; @@ -77,8 +78,7 @@ static class ListDevices devices[i].Vendor = Extern.udev_device_get_property_value(udevDev, "ID_VENDOR"); devices[i].Model = Extern.udev_device_get_property_value(udevDev, "ID_MODEL"); - if(!string.IsNullOrEmpty(devices[i].Model)) - devices[i].Model = devices[i].Model.Replace('_', ' '); + if(!string.IsNullOrEmpty(devices[i].Model)) devices[i].Model = devices[i].Model.Replace('_', ' '); devices[i].Serial = Extern.udev_device_get_property_value(udevDev, "ID_SCSI_SERIAL"); @@ -90,8 +90,7 @@ static class ListDevices StreamReader sr; - if(File.Exists(Path.Combine(sysdevs[i], "device/vendor")) && - string.IsNullOrEmpty(devices[i].Vendor)) + if(File.Exists(Path.Combine(sysdevs[i], "device/vendor")) && string.IsNullOrEmpty(devices[i].Vendor)) { sr = new StreamReader(Path.Combine(sysdevs[i], "device/vendor"), Encoding.ASCII); devices[i].Vendor = sr.ReadLine()?.Trim(); @@ -108,15 +107,14 @@ static class ListDevices else if(devices[i].Path.StartsWith("/dev/loop", StringComparison.CurrentCulture)) devices[i].Model = "Linux"; - if(File.Exists(Path.Combine(sysdevs[i], "device/serial")) && - string.IsNullOrEmpty(devices[i].Serial)) + if(File.Exists(Path.Combine(sysdevs[i], "device/serial")) && string.IsNullOrEmpty(devices[i].Serial)) { sr = new StreamReader(Path.Combine(sysdevs[i], "device/serial"), Encoding.ASCII); devices[i].Serial = sr.ReadLine()?.Trim(); } - if(string.IsNullOrEmpty(devices[i].Vendor) || - devices[i].Vendor == "ATA") + if(string.IsNullOrEmpty(devices[i].Vendor) || devices[i].Vendor == "ATA") + { if(devices[i].Model != null) { string[] pieces = devices[i].Model.Split(' '); @@ -124,9 +122,10 @@ static class ListDevices if(pieces.Length > 1) { devices[i].Vendor = pieces[0]; - devices[i].Model = devices[i].Model.Substring(pieces[0].Length + 1); + devices[i].Model = devices[i].Model[(pieces[0].Length + 1)..]; } } + } // TODO: Get better device type from sysfs paths if(string.IsNullOrEmpty(devices[i].Bus)) @@ -141,19 +140,12 @@ static class ListDevices else devices[i].Bus = devices[i].Bus.ToUpper(); - switch(devices[i].Bus) - { - case "ATA": - case "ATAPI": - case "SCSI": - case "USB": - case "PCMCIA": - case "FireWire": - case "MMC/SD": - devices[i].Supported = true; - - break; - } + devices[i].Supported = devices[i].Bus switch + { + "ATA" or "ATAPI" or "SCSI" or "USB" or "PCMCIA" or "FireWire" or "MMC/SD" => + true, + _ => devices[i].Supported + }; } return devices; diff --git a/Aaru.Devices/Linux/Structs.cs b/Aaru.Devices/Linux/Structs.cs index 63314f9ab..f61334e5c 100644 --- a/Aaru.Devices/Linux/Structs.cs +++ b/Aaru.Devices/Linux/Structs.cs @@ -28,16 +28,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Linux; - -using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +namespace Aaru.Devices.Linux; + +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] struct SgIoHdrT { /// Always 'S' for SG v3 @@ -47,13 +47,13 @@ struct SgIoHdrT public byte mx_sb_len; /* [i] */ public ushort iovec_count; /* [i] */ public uint dxfer_len; /* [i] */ - public IntPtr dxferp; /* [i], [*io] */ - public IntPtr cmdp; /* [i], [*i] */ - public IntPtr sbp; /* [i], [*o] */ + public nint dxferp; /* [i], [*io] */ + public nint cmdp; /* [i], [*i] */ + public nint sbp; /* [i], [*o] */ public uint timeout; /* [i] unit: millisecs */ public uint flags; /* [i] */ public int pack_id; /* [i->o] */ - public IntPtr usr_ptr; /* [i->o] */ + public nint usr_ptr; /* [i->o] */ public byte status; /* [o] */ public byte masked_status; /* [o] */ public byte msg_status; /* [o] */ @@ -65,7 +65,8 @@ struct SgIoHdrT public SgInfo info; /* [o] */ } -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] struct MmcIocCmd { /// Implies direction of data. true = write, false = read diff --git a/Aaru.Devices/Localization/Localization.Designer.cs b/Aaru.Devices/Localization/Localization.Designer.cs new file mode 100644 index 000000000..d0677465c --- /dev/null +++ b/Aaru.Devices/Localization/Localization.Designer.cs @@ -0,0 +1,1495 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Aaru.Devices { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Localization { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Localization() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aaru.Devices.Localization.Localization", typeof(Localization).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to ADAPTEC READ DATA BUFFER took {0} ms.. + /// + internal static string ADAPTEC_READ_DATA_BUFFER_took_0_ms { + get { + return ResourceManager.GetString("ADAPTEC_READ_DATA_BUFFER_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ADAPTEC READ/RESET USAGE COUNTER took {0} ms.. + /// + internal static string ADAPTEC_READ_RESET_USAGE_COUNTER_took_0_ms { + get { + return ResourceManager.GetString("ADAPTEC_READ_RESET_USAGE_COUNTER_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ADAPTEC SET ERROR THRESHOLD took {0} ms.. + /// + internal static string ADAPTEC_SET_ERROR_THRESHOLD_took_0_ms { + get { + return ResourceManager.GetString("ADAPTEC_SET_ERROR_THRESHOLD_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ADAPTEC TRANSLATE took {0} ms.. + /// + internal static string ADAPTEC_TRANSLATE_took_0_ms { + get { + return ResourceManager.GetString("ADAPTEC_TRANSLATE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ADAPTEC WRITE DATA BUFFER took {0} ms.. + /// + internal static string ADAPTEC_WRITE_DATA_BUFFER_took_0_ms { + get { + return ResourceManager.GetString("ADAPTEC_WRITE_DATA_BUFFER_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ARCHIVE CORP. REQUEST BLOCK ADDRESS took {0} ms.. + /// + internal static string ARCHIVE_CORP_REQUEST_BLOCK_ADDRESS_took_0_ms { + get { + return ResourceManager.GetString("ARCHIVE_CORP_REQUEST_BLOCK_ADDRESS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ARCHIVE CORP. SEEK BLOCK took {0} ms.. + /// + internal static string ARCHIVE_CORP_SEEK_BLOCK_took_0_ms { + get { + return ResourceManager.GetString("ARCHIVE_CORP_SEEK_BLOCK_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CERTANCE PARK UNPARK took {0} ms.. + /// + internal static string CERTANCE_PARK_UNPARK_took_0_ms { + get { + return ResourceManager.GetString("CERTANCE_PARK_UNPARK_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CFA REQUEST EXTENDED ERROR CODE took {0} ms.. + /// + internal static string CFA_REQUEST_EXTENDED_ERROR_CODE_took_0_ms { + get { + return ResourceManager.GetString("CFA_REQUEST_EXTENDED_ERROR_CODE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CFA TRANSLATE SECTOR took {0} ms.. + /// + internal static string CFA_TRANSLATE_SECTOR_took_0_ms { + get { + return ResourceManager.GetString("CFA_TRANSLATE_SECTOR_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CHECK MEDIA CARD TYPE took {0} ms.. + /// + internal static string CHECK_MEDIA_CARD_TYPE_took_0_ms { + get { + return ResourceManager.GetString("CHECK_MEDIA_CARD_TYPE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Connected to {0}. + /// + internal static string Connected_to_0 { + get { + return ResourceManager.GetString("Connected_to_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not read from the network.... + /// + internal static string Could_not_read_from_the_network { + get { + return ResourceManager.GetString("Could_not_read_from_the_network", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not write to the network.... + /// + internal static string Could_not_write_to_the_network { + get { + return ResourceManager.GetString("Could_not_write_to_the_network", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DOOR LOCK took {0} ms.. + /// + internal static string DOOR_LOCK_took_0_ms { + get { + return ResourceManager.GetString("DOOR_LOCK_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DOOR UNLOCK took {0} ms.. + /// + internal static string DOOR_UNLOCK_took_0_ms { + get { + return ResourceManager.GetString("DOOR_UNLOCK_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error connecting to host.. + /// + internal static string Error_connecting_to_host { + get { + return ResourceManager.GetString("Error_connecting_to_host", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected ATA CHS Response Packet, got packet type {0}.... + /// + internal static string Expected_ATA_CHS_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_ATA_CHS_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected ATA LBA28 Response Packet, got packet type {0}.... + /// + internal static string Expected_ATA_LBA28_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_ATA_LBA28_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected ATA LBA48 Response Packet, got packet type {0}.... + /// + internal static string Expected_ATA_LBA48_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_ATA_LBA48_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected Device Type Response Packet, got packet type {0}.... + /// + internal static string Expected_Device_Type_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_Device_Type_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected FireWire Data Response Packet, got packet type {0}.... + /// + internal static string Expected_FireWire_Data_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_FireWire_Data_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected Hello Packet, got packet type {0}.... + /// + internal static string Expected_Hello_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_Hello_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected multi MMC/SD command Response Packet, got packet type {0}.... + /// + internal static string Expected_multi_MMC_SD_command_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_multi_MMC_SD_command_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected NOP Packet, got packet type {0}.... + /// + internal static string Expected_NOP_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_NOP_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected OS Read Response Packet, got packet type {0}.... + /// + internal static string Expected_OS_Read_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_OS_Read_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected PCMCIA Data Response Packet, got packet type {0}.... + /// + internal static string Expected_PCMCIA_Data_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_PCMCIA_Data_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected SCSI Response Packet, got packet type {0}.... + /// + internal static string Expected_SCSI_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_SCSI_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected SDHCI Response Packet, got packet type {0}.... + /// + internal static string Expected_SDHCI_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_SDHCI_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected the response to {0} SD/MMC commands, but got {1} responses.... + /// + internal static string Expected_the_response_to_0_SD_MMC_commands_but_got_1_responses { + get { + return ResourceManager.GetString("Expected_the_response_to_0_SD_MMC_commands_but_got_1_responses", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected USB Data Response Packet, got packet type {0}.... + /// + internal static string Expected_USB_Data_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Expected_USB_Data_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FUJITSU DISPLAY took {0} ms.. + /// + internal static string FUJITSU_DISPLAY_took_0_ms { + get { + return ResourceManager.GetString("FUJITSU_DISPLAY_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to GET CONFIGURATION (Starting Feature Number: {1}, Return Type: {2}, Sense: {3}, Last Error: {4}) took {0} ms.. + /// + internal static string GET_CONFIGURATION_Starting_Feature_Number_1_Return_Type_2_Sense_3_Last_Error_4_took_0_ms { + get { + return ResourceManager.GetString("GET_CONFIGURATION_Starting_Feature_Number_1_Return_Type_2_Sense_3_Last_Error_4_to" + + "ok_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to GET NATIVE MAX ADDRESS EXT took {0} ms.. + /// + internal static string GET_NATIVE_MAX_ADDRESS_EXT_took_0_ms { + get { + return ResourceManager.GetString("GET_NATIVE_MAX_ADDRESS_EXT_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HL-DT-ST READ DVD (RAW) took {0} ms.. + /// + internal static string HL_DT_ST_READ_DVD_RAW_took_0_ms { + get { + return ResourceManager.GetString("HL_DT_ST_READ_DVD_RAW_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Host not found. + /// + internal static string Host_not_found { + get { + return ResourceManager.GetString("Host_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP READ LONG took {0} ms.. + /// + internal static string HP_READ_LONG_took_0_ms { + get { + return ResourceManager.GetString("HP_READ_LONG_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IDENTIFY PACKET DEVICE took {0} ms.. + /// + internal static string IDENTIFY_PACKET_DEVICE_took_0_ms { + get { + return ResourceManager.GetString("IDENTIFY_PACKET_DEVICE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to INQUIRY took {0} ms.. + /// + internal static string INQUIRY_took_0_ms { + get { + return ResourceManager.GetString("INQUIRY_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid remote protocol.. + /// + internal static string Invalid_remote_protocol { + get { + return ResourceManager.GetString("Invalid_remote_protocol", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid remote URI.. + /// + internal static string Invalid_remote_URI { + get { + return ResourceManager.GetString("Invalid_remote_URI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to KREON DEPRECATED UNLOCK took {0} ms.. + /// + internal static string KREON_DEPRECATED_UNLOCK_took_0_ms { + get { + return ResourceManager.GetString("KREON_DEPRECATED_UNLOCK_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to KREON EXTRACT SS took {0} ms.. + /// + internal static string KREON_EXTRACT_SS_took_0_ms { + get { + return ResourceManager.GetString("KREON_EXTRACT_SS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to KREON GET FEATURE LIST took {0} ms.. + /// + internal static string KREON_GET_FEATURE_LIST_took_0_ms { + get { + return ResourceManager.GetString("KREON_GET_FEATURE_LIST_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to KREON SET LOCK STATE took {0} ms.. + /// + internal static string KREON_SET_LOCK_STATE_took_0_ms { + get { + return ResourceManager.GetString("KREON_SET_LOCK_STATE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LOAD UNLOAD (6) took {0} ms.. + /// + internal static string LOAD_UNLOAD_6_took_0_ms { + get { + return ResourceManager.GetString("LOAD_UNLOAD_6_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LOCATE (10) took {0} ms.. + /// + internal static string LOCATE_10_took_0_ms { + get { + return ResourceManager.GetString("LOCATE_10_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LOCATE (16) took {0} ms.. + /// + internal static string LOCATE_16_took_0_ms { + get { + return ResourceManager.GetString("LOCATE_16_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MEDIA EJECT took {0} ms.. + /// + internal static string MEDIA_EJECT_took_0_ms { + get { + return ResourceManager.GetString("MEDIA_EJECT_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MediaTek READ DRAM took {0} ms.. + /// + internal static string MediaTek_READ_DRAM_took_0_ms { + get { + return ResourceManager.GetString("MediaTek_READ_DRAM_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MEDIUM SCAN took {0} ms.. + /// + internal static string MEDIUM_SCAN_took_0_ms { + get { + return ResourceManager.GetString("MEDIUM_SCAN_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MINIDISC command D5h took {0} ms.. + /// + internal static string MINIDISC_command_D5h_took_0_ms { + get { + return ResourceManager.GetString("MINIDISC_command_D5h_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MINIDISC GET TYPE took {0} ms.. + /// + internal static string MINIDISC_GET_TYPE_took_0_ms { + get { + return ResourceManager.GetString("MINIDISC_GET_TYPE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MINIDISC READ DTOC took {0} ms.. + /// + internal static string MINIDISC_READ_DTOC_took_0_ms { + get { + return ResourceManager.GetString("MINIDISC_READ_DTOC_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MINIDISC READ POSITION took {0} ms.. + /// + internal static string MINIDISC_READ_POSITION_took_0_ms { + get { + return ResourceManager.GetString("MINIDISC_READ_POSITION_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MINIDISC READ UTOC took {0} ms.. + /// + internal static string MINIDISC_READ_UTOC_took_0_ms { + get { + return ResourceManager.GetString("MINIDISC_READ_UTOC_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MINIDISC STOP PLAY took {0} ms.. + /// + internal static string MINIDISC_STOP_PLAY_took_0_ms { + get { + return ResourceManager.GetString("MINIDISC_STOP_PLAY_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MODE SELECT(10) took {0} ms.. + /// + internal static string MODE_SELECT_10_took_0_ms { + get { + return ResourceManager.GetString("MODE_SELECT_10_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MODE SELECT(6) took {0} ms.. + /// + internal static string MODE_SELECT_6_took_0_ms { + get { + return ResourceManager.GetString("MODE_SELECT_6_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MODE SENSE(10) took {0} ms.. + /// + internal static string MODE_SENSE_10_took_0_ms { + get { + return ResourceManager.GetString("MODE_SENSE_10_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MODE SENSE(6) took {0} ms.. + /// + internal static string MODE_SENSE_6_took_0_ms { + get { + return ResourceManager.GetString("MODE_SENSE_6_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multiple READ_SINGLE_BLOCKs took {0} ms.. + /// + internal static string Multiple_READ_SINGLE_BLOCKs_took_0_ms { + get { + return ResourceManager.GetString("Multiple_READ_SINGLE_BLOCKs_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NEC READ CD-DA took {0} ms.. + /// + internal static string NEC_READ_CD_DA_took_0_ms { + get { + return ResourceManager.GetString("NEC_READ_CD_DA_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PIONEER READ CD-DA MSF took {0} ms.. + /// + internal static string PIONEER_READ_CD_DA_MSF_took_0_ms { + get { + return ResourceManager.GetString("PIONEER_READ_CD_DA_MSF_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PIONEER READ CD-DA took {0} ms.. + /// + internal static string PIONEER_READ_CD_DA_took_0_ms { + get { + return ResourceManager.GetString("PIONEER_READ_CD_DA_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PIONEER READ CD-XA took {0} ms.. + /// + internal static string PIONEER_READ_CD_XA_took_0_ms { + get { + return ResourceManager.GetString("PIONEER_READ_CD_XA_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLASMON READ SECTOR LOCATION took {0} ms.. + /// + internal static string PLASMON_READ_SECTOR_LOCATION_took_0_ms { + get { + return ResourceManager.GetString("PLASMON_READ_SECTOR_LOCATION_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Platform {0} not yet supported.. + /// + internal static string Platform_0_not_yet_supported { + get { + return ResourceManager.GetString("Platform_0_not_yet_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLEXTOR GET BOOK BITSETTING took {0} ms.. + /// + internal static string PLEXTOR_GET_BOOK_BITSETTING_took_0_ms { + get { + return ResourceManager.GetString("PLEXTOR_GET_BOOK_BITSETTING_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLEXTOR GET GIGAREC took {0} ms.. + /// + internal static string PLEXTOR_GET_GIGAREC_took_0_ms { + get { + return ResourceManager.GetString("PLEXTOR_GET_GIGAREC_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLEXTOR GET SECUREC took {0} ms.. + /// + internal static string PLEXTOR_GET_SECUREC_took_0_ms { + get { + return ResourceManager.GetString("PLEXTOR_GET_SECUREC_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLEXTOR GET SILENT MODE took {0} ms.. + /// + internal static string PLEXTOR_GET_SILENT_MODE_took_0_ms { + get { + return ResourceManager.GetString("PLEXTOR_GET_SILENT_MODE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLEXTOR GET SINGLE-SESSION / HIDE CD-R took {0} ms.. + /// + internal static string PLEXTOR_GET_SINGLE_SESSION_HIDE_CD_R_took_0_ms { + get { + return ResourceManager.GetString("PLEXTOR_GET_SINGLE_SESSION_HIDE_CD_R_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLEXTOR GET SPEEDREAD took {0} ms.. + /// + internal static string PLEXTOR_GET_SPEEDREAD_took_0_ms { + get { + return ResourceManager.GetString("PLEXTOR_GET_SPEEDREAD_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLEXTOR GET TEST WRITE DVD+ took {0} ms.. + /// + internal static string PLEXTOR_GET_TEST_WRITE_DVD_took_0_ms { + get { + return ResourceManager.GetString("PLEXTOR_GET_TEST_WRITE_DVD_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLEXTOR GET VARIREC took {0} ms.. + /// + internal static string PLEXTOR_GET_VARIREC_took_0_ms { + get { + return ResourceManager.GetString("PLEXTOR_GET_VARIREC_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLEXTOR POWEREC GET SPEEDS took {0} ms.. + /// + internal static string PLEXTOR_POWEREC_GET_SPEEDS_took_0_ms { + get { + return ResourceManager.GetString("PLEXTOR_POWEREC_GET_SPEEDS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Plextor READ CD-DA (LBA: {1}, Block Size: {2}, Transfer Length: {3}, Subchannel: {4}, Sense: {5}, Last Error: {6}) took {0} ms.. + /// + internal static string Plextor_READ_CD_DA_LBA_1_Block_Size_2_Transfer_Length_3_Subchannel_4_Sense_5_Last_Error_6_took_0_ms { + get { + return ResourceManager.GetString("Plextor_READ_CD_DA_LBA_1_Block_Size_2_Transfer_Length_3_Subchannel_4_Sense_5_Last" + + "_Error_6_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Plextor READ DVD (RAW) took {0} ms.. + /// + internal static string Plextor_READ_DVD_RAW_took_0_ms { + get { + return ResourceManager.GetString("Plextor_READ_DVD_RAW_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PLEXTOR READ EEPROM took {0} ms.. + /// + internal static string PLEXTOR_READ_EEPROM_took_0_ms { + get { + return ResourceManager.GetString("PLEXTOR_READ_EEPROM_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PREVENT ALLOW MEDIUM REMOVAL (Persistent: {1}, Prevent: {2}, Sense: {3}, LastError: {4}) took {0} ms.. + /// + internal static string PREVENT_ALLOW_MEDIUM_REMOVAL_Persistent_1_Prevent_2_Sense_3_LastError_4_took_0_ms { + get { + return ResourceManager.GetString("PREVENT_ALLOW_MEDIUM_REMOVAL_Persistent_1_Prevent_2_Sense_3_LastError_4_took_0_ms" + + "", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PREVENT ALLOW MEDIUM REMOVAL took {0} ms.. + /// + internal static string PREVENT_ALLOW_MEDIUM_REMOVAL_took_0_ms { + get { + return ResourceManager.GetString("PREVENT_ALLOW_MEDIUM_REMOVAL_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ (10) took {0} ms.. + /// + internal static string READ_10_took_0_ms { + get { + return ResourceManager.GetString("READ_10_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ (12) took {0} ms.. + /// + internal static string READ_12_took_0_ms { + get { + return ResourceManager.GetString("READ_12_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ (16) took {0} ms.. + /// + internal static string READ_16_took_0_ms { + get { + return ResourceManager.GetString("READ_16_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ (6) took {0} ms.. + /// + internal static string READ_6_took_0_ms { + get { + return ResourceManager.GetString("READ_6_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ ATTRIBUTE took {0} ms.. + /// + internal static string READ_ATTRIBUTE_took_0_ms { + get { + return ResourceManager.GetString("READ_ATTRIBUTE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ BLOCK LIMITS took {0} ms.. + /// + internal static string READ_BLOCK_LIMITS_took_0_ms { + get { + return ResourceManager.GetString("READ_BLOCK_LIMITS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ BUFFER DMA took {0} ms.. + /// + internal static string READ_BUFFER_DMA_took_0_ms { + get { + return ResourceManager.GetString("READ_BUFFER_DMA_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ BUFFER took {0} ms.. + /// + internal static string READ_BUFFER_took_0_ms { + get { + return ResourceManager.GetString("READ_BUFFER_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ CAPACITY(16) took {0} ms.. + /// + internal static string READ_CAPACITY_16_took_0_ms { + get { + return ResourceManager.GetString("READ_CAPACITY_16_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ CAPACITY took {0} ms.. + /// + internal static string READ_CAPACITY_took_0_ms { + get { + return ResourceManager.GetString("READ_CAPACITY_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ CD (LBA: {1}, Block Size: {2}, Transfer Length: {3}, Expected Sector Type: {4}, DAP: {5}, Relative Address: {6}, Sync: {7}, Headers: {8}, User Data: {9}, ECC/EDC: {10}, C2: {11}, Subchannel: {12}, Sense: {13}, Last Error: {14}) took {0} ms.. + /// + internal static string READ_CD_LBA_1_Block_Size_2_Transfer_Length_3_Expected_Sector_Type_4_DAP_5_Relative_Address_6_Sync_7_Headers_8_User_Data_9_ECC_EDC_10_C2_11_Subchannel_12_Sense_13_Last_Error_14_took_0_ms { + get { + return ResourceManager.GetString("READ_CD_LBA_1_Block_Size_2_Transfer_Length_3_Expected_Sector_Type_4_DAP_5_Relativ" + + "e_Address_6_Sync_7_Headers_8_User_Data_9_ECC_EDC_10_C2_11_Subchannel_12_Sense_13" + + "_Last_Error_14_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ CD MSF (Start MSF: {1}, End MSF: {2}, Block Size: {3}, Expected Sector Type: {4}, DAP: {5}, Sync: {6}, Headers: {7}, User Data: {8}, ECC/EDC: {9}, C2: {10}, Subchannel: {11}, Sense: {12}, LastError: {13}) took {0} ms.. + /// + internal static string READ_CD_MSF_Start_MSF_1_End_MSF_2_Block_Size_3_Expected_Sector_Type_4_DAP_5_Sync_6_Headers_7_User_Data_8_ECC_EDC_9_C2_10_Subchannel_11_Sense_12_LastError_13_took_0_ms { + get { + return ResourceManager.GetString("READ_CD_MSF_Start_MSF_1_End_MSF_2_Block_Size_3_Expected_Sector_Type_4_DAP_5_Sync_" + + "6_Headers_7_User_Data_8_ECC_EDC_9_C2_10_Subchannel_11_Sense_12_LastError_13_took" + + "_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ DISC INFORMATION (Data Type: {1}, Sense: {2}, Last Error: {3}) took {0} ms.. + /// + internal static string READ_DISC_INFORMATION_Data_Type_1_Sense_2_Last_Error_3_took_0_ms { + get { + return ResourceManager.GetString("READ_DISC_INFORMATION_Data_Type_1_Sense_2_Last_Error_3_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ DISC STRUCTURE (Media Type: {1}, Address: {2}, Layer Number: {3}, Format: {4}, AGID: {5}, Sense: {6}, Last Error: {7}) took {0} ms.. + /// + internal static string READ_DISC_STRUCTURE_Media_Type_1_Address_2_Layer_Number_3_Format_4_AGID_5_Sense_6_Last_Error_7_took_0_ms { + get { + return ResourceManager.GetString("READ_DISC_STRUCTURE_Media_Type_1_Address_2_Layer_Number_3_Format_4_AGID_5_Sense_6" + + "_Last_Error_7_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ DMA EXT took {0} ms.. + /// + internal static string READ_DMA_EXT_took_0_ms { + get { + return ResourceManager.GetString("READ_DMA_EXT_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ DMA took {0} ms.. + /// + internal static string READ_DMA_took_0_ms { + get { + return ResourceManager.GetString("READ_DMA_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ LOG DMA EXT took {0} ms.. + /// + internal static string READ_LOG_DMA_EXT_took_0_ms { + get { + return ResourceManager.GetString("READ_LOG_DMA_EXT_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ LOG EXT took {0} ms.. + /// + internal static string READ_LOG_EXT_took_0_ms { + get { + return ResourceManager.GetString("READ_LOG_EXT_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ LONG (10) took {0} ms.. + /// + internal static string READ_LONG_10_took_0_ms { + get { + return ResourceManager.GetString("READ_LONG_10_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ LONG (16) took {0} ms.. + /// + internal static string READ_LONG_16_took_0_ms { + get { + return ResourceManager.GetString("READ_LONG_16_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ LONG took {0} ms.. + /// + internal static string READ_LONG_took_0_ms { + get { + return ResourceManager.GetString("READ_LONG_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ MEDIA SERIAL NUMBER took {0} ms.. + /// + internal static string READ_MEDIA_SERIAL_NUMBER_took_0_ms { + get { + return ResourceManager.GetString("READ_MEDIA_SERIAL_NUMBER_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ_MULTIPLE_BLOCK took {0} ms.. + /// + internal static string READ_MULTIPLE_BLOCK_took_0_ms { + get { + return ResourceManager.GetString("READ_MULTIPLE_BLOCK_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ MULTIPLE EXT took {0} ms.. + /// + internal static string READ_MULTIPLE_EXT_took_0_ms { + get { + return ResourceManager.GetString("READ_MULTIPLE_EXT_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ MULTIPLE took {0} ms.. + /// + internal static string READ_MULTIPLE_took_0_ms { + get { + return ResourceManager.GetString("READ_MULTIPLE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ NATIVE MAX ADDRESS EXT took {0} ms.. + /// + internal static string READ_NATIVE_MAX_ADDRESS_EXT_took_0_ms { + get { + return ResourceManager.GetString("READ_NATIVE_MAX_ADDRESS_EXT_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ NATIVE MAX ADDRESS took {0} ms.. + /// + internal static string READ_NATIVE_MAX_ADDRESS_took_0_ms { + get { + return ResourceManager.GetString("READ_NATIVE_MAX_ADDRESS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ POSITION took {0} ms.. + /// + internal static string READ_POSITION_took_0_ms { + get { + return ResourceManager.GetString("READ_POSITION_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ READ SUB-CHANNEL (ISRC, Track Number: {1}, Sense: {2}, Last Error: {3}) took {0} ms.. + /// + internal static string READ_READ_SUB_CHANNEL_ISRC_Track_Number_1_Sense_2_Last_Error_3_took_0_ms { + get { + return ResourceManager.GetString("READ_READ_SUB_CHANNEL_ISRC_Track_Number_1_Sense_2_Last_Error_3_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ READ SUB-CHANNEL (MCN, Sense {1}, Last Error {2}) took {0} ms.. + /// + internal static string READ_READ_SUB_CHANNEL_MCN_Sense_1_Last_Error_2_took_0_ms { + get { + return ResourceManager.GetString("READ_READ_SUB_CHANNEL_MCN_Sense_1_Last_Error_2_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ REVERSE (16) took {0} ms.. + /// + internal static string READ_REVERSE_16_took_0_ms { + get { + return ResourceManager.GetString("READ_REVERSE_16_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ REVERSE (6) took {0} ms.. + /// + internal static string READ_REVERSE_6_took_0_ms { + get { + return ResourceManager.GetString("READ_REVERSE_6_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ SECTORS EXT took {0} ms.. + /// + internal static string READ_SECTORS_EXT_took_0_ms { + get { + return ResourceManager.GetString("READ_SECTORS_EXT_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ SECTORS took {0} ms.. + /// + internal static string READ_SECTORS_took_0_ms { + get { + return ResourceManager.GetString("READ_SECTORS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ_SINGLE_BLOCK took {0} ms.. + /// + internal static string READ_SINGLE_BLOCK_took_0_ms { + get { + return ResourceManager.GetString("READ_SINGLE_BLOCK_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ TOC/PMA/ATIP took (MSF: {1}, Format: {2}, Track/Session Number: {3}, Sense: {4}, LastError: {5}) {0} ms.. + /// + internal static string READ_TOC_PMA_ATIP_took_MSF_1_Format_2_Track_Session_Number_3_Sense_4_LastError_5_0_ms { + get { + return ResourceManager.GetString("READ_TOC_PMA_ATIP_took_MSF_1_Format_2_Track_Session_Number_3_Sense_4_LastError_5_" + + "0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to READ TRACK INFORMATION (Data Type: {1}, Sense: {2}, Last Error: {3}) took {0} ms.. + /// + internal static string READ_TRACK_INFORMATION_Data_Type_1_Sense_2_Last_Error_3_took_0_ms { + get { + return ResourceManager.GetString("READ_TRACK_INFORMATION_Data_Type_1_Sense_2_Last_Error_3_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Received data is not an Aaru Remote Packet.... + /// + internal static string Received_data_is_not_an_Aaru_Remote_Packet { + get { + return ResourceManager.GetString("Received_data_is_not_an_Aaru_Remote_Packet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to RECOVER BUFFERED DATA took {0} ms.. + /// + internal static string RECOVER_BUFFERED_DATA_took_0_ms { + get { + return ResourceManager.GetString("RECOVER_BUFFERED_DATA_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Remote error {0} in OS Read.... + /// + internal static string Remote_error_0_in_OS_Read { + get { + return ResourceManager.GetString("Remote_error_0_in_OS_Read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected Am I Root? Response Packet, got packet type {0}.... + /// + internal static string Remote_IsRoot_Expected_Am_I_Root_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Remote_IsRoot_Expected_Am_I_Root_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected List Devices Response Packet, got packet type {0}.... + /// + internal static string Remote_ListDevices_Expected_List_Devices_Response_Packet_got_packet_type_0 { + get { + return ResourceManager.GetString("Remote_ListDevices_Expected_List_Devices_Response_Packet_got_packet_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ReOpen error {0} with reason: {1}.... + /// + internal static string ReOpen_error_0_with_reason_1 { + get { + return ResourceManager.GetString("ReOpen_error_0_with_reason_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ReOpen error closing device.... + /// + internal static string ReOpen_error_closing_device { + get { + return ResourceManager.GetString("ReOpen_error_closing_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to REPORT DENSITY SUPPORT took {0} ms.. + /// + internal static string REPORT_DENSITY_SUPPORT_took_0_ms { + get { + return ResourceManager.GetString("REPORT_DENSITY_SUPPORT_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to REQUEST SENSE took {0} ms.. + /// + internal static string REQUEST_SENSE_took_0_ms { + get { + return ResourceManager.GetString("REQUEST_SENSE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to REWIND took {0} ms.. + /// + internal static string REWIND_took_0_ms { + get { + return ResourceManager.GetString("REWIND_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SD_SEND_OP_COND took {0} ms.. + /// + internal static string SD_SEND_OP_COND_took_0_ms { + get { + return ResourceManager.GetString("SD_SEND_OP_COND_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SD_STATUS took {0} ms.. + /// + internal static string SD_STATUS_took_0_ms { + get { + return ResourceManager.GetString("SD_STATUS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEEK (10) took {0} ms.. + /// + internal static string SEEK_10_took_0_ms { + get { + return ResourceManager.GetString("SEEK_10_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEEK (6) took {0} ms.. + /// + internal static string SEEK_6_took_0_ms { + get { + return ResourceManager.GetString("SEEK_6_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEEK took {0} ms.. + /// + internal static string SEEK_took_0_ms { + get { + return ResourceManager.GetString("SEEK_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEND_CID took {0} ms.. + /// + internal static string SEND_CID_took_0_ms { + get { + return ResourceManager.GetString("SEND_CID_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEND_CSD took {0} ms.. + /// + internal static string SEND_CSD_took_0_ms { + get { + return ResourceManager.GetString("SEND_CSD_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEND_EXT_CSD took {0} ms.. + /// + internal static string SEND_EXT_CSD_took_0_ms { + get { + return ResourceManager.GetString("SEND_EXT_CSD_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEND_OP_COND took {0} ms.. + /// + internal static string SEND_OP_COND_took_0_ms { + get { + return ResourceManager.GetString("SEND_OP_COND_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEND_SCR took {0} ms.. + /// + internal static string SEND_SCR_took_0_ms { + get { + return ResourceManager.GetString("SEND_SCR_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SEND_STATUS took {0} ms.. + /// + internal static string SEND_STATUS_took_0_ms { + get { + return ResourceManager.GetString("SEND_STATUS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SET_BLOCKLEN took {0} ms.. + /// + internal static string SET_BLOCKLEN_took_0_ms { + get { + return ResourceManager.GetString("SET_BLOCKLEN_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SET CD SPEED (Rotational Control: {1}, Read Speed: {2}, Write Speed: {3}, Sense: {4}, Last Error: {5}) took {0} ms.. + /// + internal static string SET_CD_SPEED_Rotational_Control_1_Read_Speed_2_Write_Speed_3_Sense_4_Last_Error_5_took_0_ms { + get { + return ResourceManager.GetString("SET_CD_SPEED_Rotational_Control_1_Read_Speed_2_Write_Speed_3_Sense_4_Last_Error_5" + + "_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SET FEATURES took {0} ms.. + /// + internal static string SET_FEATURES_took_0_ms { + get { + return ResourceManager.GetString("SET_FEATURES_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SMART DISABLE ATTRIBUTE AUTOSAVE took {0} ms.. + /// + internal static string SMART_DISABLE_ATTRIBUTE_AUTOSAVE_took_0_ms { + get { + return ResourceManager.GetString("SMART_DISABLE_ATTRIBUTE_AUTOSAVE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SMART DISABLE OPERATIONS took {0} ms.. + /// + internal static string SMART_DISABLE_OPERATIONS_took_0_ms { + get { + return ResourceManager.GetString("SMART_DISABLE_OPERATIONS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SMART ENABLE ATTRIBUTE AUTOSAVE took {0} ms.. + /// + internal static string SMART_ENABLE_ATTRIBUTE_AUTOSAVE_took_0_ms { + get { + return ResourceManager.GetString("SMART_ENABLE_ATTRIBUTE_AUTOSAVE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SMART ENABLE OPERATIONS took {0} ms.. + /// + internal static string SMART_ENABLE_OPERATIONS_took_0_ms { + get { + return ResourceManager.GetString("SMART_ENABLE_OPERATIONS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SMART EXECUTE OFF-LINE IMMEDIATE took {0} ms.. + /// + internal static string SMART_EXECUTE_OFF_LINE_IMMEDIATE_took_0_ms { + get { + return ResourceManager.GetString("SMART_EXECUTE_OFF_LINE_IMMEDIATE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SMART READ DATA took {0} ms.. + /// + internal static string SMART_READ_DATA_took_0_ms { + get { + return ResourceManager.GetString("SMART_READ_DATA_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SMART READ LOG took {0} ms.. + /// + internal static string SMART_READ_LOG_took_0_ms { + get { + return ResourceManager.GetString("SMART_READ_LOG_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SMART RETURN STATUS took {0} ms.. + /// + internal static string SMART_RETURN_STATUS_took_0_ms { + get { + return ResourceManager.GetString("SMART_RETURN_STATUS_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SPACE took {0} ms.. + /// + internal static string SPACE_took_0_ms { + get { + return ResourceManager.GetString("SPACE_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to START STOP UNIT (Immediate: {1}, FormatLayer: {2}, Power Conditions: {3}, Change Format Layer: {4}, Load/Eject: {5}, Start: {6}, Sense: {7}, Last Error: {8}) took {0} ms.. + /// + internal static string START_STOP_UNIT_Immediate_1_FormatLayer_2_Power_Conditions_3_Change_Format_Layer_4_Load_Eject_5_Start_6_Sense_7_Last_Error_8_took_0_ms { + get { + return ResourceManager.GetString("START_STOP_UNIT_Immediate_1_FormatLayer_2_Power_Conditions_3_Change_Format_Layer_" + + "4_Load_Eject_5_Start_6_Sense_7_Last_Error_8_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SYQUEST READ (10) took {0} ms.. + /// + internal static string SYQUEST_READ_10_took_0_ms { + get { + return ResourceManager.GetString("SYQUEST_READ_10_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SYQUEST READ (6) took {0} ms.. + /// + internal static string SYQUEST_READ_6_took_0_ms { + get { + return ResourceManager.GetString("SYQUEST_READ_6_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TEST UNIT READY took {0} ms.. + /// + internal static string TEST_UNIT_READY_took_0_ms { + get { + return ResourceManager.GetString("TEST_UNIT_READY_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TRACK SELECT took {0} ms.. + /// + internal static string TRACK_SELECT_took_0_ms { + get { + return ResourceManager.GetString("TRACK_SELECT_took_0_ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unrecognized packet version.... + /// + internal static string Unrecognized_packet_version { + get { + return ResourceManager.GetString("Unrecognized_packet_version", resourceCulture); + } + } + } +} diff --git a/Aaru.Devices/Localization/Localization.es.resx b/Aaru.Devices/Localization/Localization.es.resx new file mode 100644 index 000000000..db8b2b4eb --- /dev/null +++ b/Aaru.Devices/Localization/Localization.es.resx @@ -0,0 +1,504 @@ + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + READ BUFFER tomó {0} ms. + + + READ BUFFER DMA tomó {0} ms. + + + READ DMA tomó {0} ms. + + + READ MULTIPLE tomó {0} ms. + + + READ NATIVE MAX ADDRESS tomó {0} ms. + + + READ SECTORS tomó {0} ms. + + + READ LONG tomó {0} ms. + + + SEEK tomó {0} ms. + + + GET NATIVE MAX ADDRESS EXT tomó {0} ms. + + + READ DMA EXT tomó {0} ms. + + + READ LOG EXT tomó {0} ms. + + + READ LOG DMA EXT tomó {0} ms. + + + READ MULTIPLE EXT tomó {0} ms. + + + READ NATIVE MAX ADDRESS EXT tomó {0} ms. + + + READ SECTORS EXT tomó {0} ms. + + + SET FEATURES tomó {0} ms. + + + DOOR LOCK tomó {0} ms. + + + DOOR UNLOCK tomó {0} ms. + + + MEDIA EJECT tomó {0} ms. + + + IDENTIFY PACKET DEVICE tomó {0} ms. + + + CFA TRANSLATE SECTOR tomó {0} ms. + + + CFA REQUEST EXTENDED ERROR CODE tomó {0} ms. + + + CHECK MEDIA CARD TYPE tomó {0} ms. + + + SMART DISABLE OPERATIONS tomó {0} ms. + + + SMART ENABLE ATTRIBUTE AUTOSAVE tomó {0} ms. + + + SMART DISABLE ATTRIBUTE AUTOSAVE tomó {0} ms. + + + SMART ENABLE OPERATIONS tomó {0} ms. + + + SMART EXECUTE OFF-LINE IMMEDIATE tomó {0} ms. + + + SMART READ DATA tomó {0} ms. + + + SMART READ LOG tomó {0} ms. + + + SMART RETURN STATUS tomó {0} ms. + + + SEND_CSD tomó {0} ms. + + + SEND_CID tomó {0} ms. + + + SEND_OP_COND tomó {0} ms. + + + SEND_EXT_CSD tomó {0} ms. + + + SET_BLOCKLEN tomó {0} ms. + + + READ_SINGLE_BLOCK tomó {0} ms. + + + READ_MULTIPLE_BLOCK tomó {0} ms. + + + Múltiples READ_SINGLE_BLOCKs tomaron {0} ms. + + + SEND_STATUS tomó {0} ms. + + + SD_STATUS tomó {0} ms. + + + SD_SEND_OP_COND tomó {0} ms. + + + SEND_SCR tomó {0} ms. + + + ADAPTEC TRANSLATE tomó {0} ms. + + + ADAPTEC SET ERROR THRESHOLD tomó {0} ms. + + + ADAPTEC READ/RESET USAGE COUNTER tomó {0} ms. + + + ADAPTEC WRITE DATA BUFFER tomó {0} ms. + + + ADAPTEC READ DATA BUFFER tomó {0} ms. + + + ARCHIVE CORP. REQUEST BLOCK ADDRESS tomó {0} ms. + + + ARCHIVE CORP. SEEK BLOCK tomó {0} ms. + + + CERTANCE PARK UNPARK tomó {0} ms. + + + FUJITSU DISPLAY tomó {0} ms. + + + HL-DT-ST READ DVD (RAW) tomó {0} ms. + + + HP READ LONG tomó {0} ms. + + + KREON DEPRECATED UNLOCK tomó {0} ms. + + + KREON SET LOCK STATE tomó {0} ms. + + + KREON GET FEATURE LIST tomó {0} ms. + + + KREON EXTRACT SS tomó {0} ms. + + + MediaTek READ DRAM tomó {0} ms. + + + MINIDISC READ DTOC tomó {0} ms. + + + MINIDISC READ UTOC tomó {0} ms. + + + MINIDISC command D5h tomó {0} ms. + + + MINIDISC STOP PLAY tomó {0} ms. + + + MINIDISC READ POSITION tomó {0} ms. + + + MINIDISC GET TYPE tomó {0} ms. + + + GET CONFIGURATION (Número de primera funcionalidad Feature Number: {1}, Tipo de retorno: {2}, Sense: {3}, Error: {4}) tomó {0} ms. + + + READ DISC STRUCTURE (Tipo de medio: {1}, Dirección: {2}, Capa: {3}, Formato: {4}, AGID: {5}, Sense: {6}, Error: {7}) tomó {0} ms. + + + READ TOC/PMA/ATIP tomó (MSF: {1}, Formato: {2}, Pista/Sesión: {3}, Sense: {4}, Error: {5}) {0} ms. + + + READ DISC INFORMATION (Tipo de datos: {1}, Sense: {2}, Last Error: {3}) tomó {0} ms. + + + READ CD (LBA: {1}, Tamaño del bloque: {2}, Longitud de la transferencia: {3}, Tipo de sector esperado: {4}, DAP: {5}, Dirección relativa: {6}, Síncrono: {7}, Cabeceras: {8}, Datos de usuario: {9}, ECC/EDC: {10}, C2: {11}, Subcanal: {12}, Sense: {13}, Error: {14}) tomó {0} ms. + + + READ CD MSF (Start MSF: {1}, End MSF: {2}, Block Size: {3}, Expected Sector Type: {4}, DAP: {5}, Sync: {6}, Headers: {7}, User Data: {8}, ECC/EDC: {9}, C2: {10}, Subchannel: {11}, Sense: {12}, LastError: {13}) tomó {0} ms. + + + PREVENT ALLOW MEDIUM REMOVAL (Persistente: {1}, Evitar: {2}, Sense: {3}, Error: {4}) tomó {0} ms. + + + START STOP UNIT (Inmediato: {1}, Formato de capa: {2}, Condiciones de energía: {3}, Cambiar capa de formato: {4}, Cargar/Expulsar: {5}, Iniciar: {6}, Sense: {7}, Error: {8}) tomó {0} ms. + + + READ READ SUB-CHANNEL (MCN, Sense {1}, Error {2}) tomó {0} ms. + + + READ READ SUB-CHANNEL (ISRC, Pista: {1}, Sense: {2}, Error: {3}) tomó {0} ms. + + + SET CD SPEED (Control rotación: {1}, Velocidad de lectura: {2}, Velocidad de escritura: {3}, Sense: {4}, Error: {5}) tomó {0} ms. + + + READ TRACK INFORMATION (Data Type: {1}, Sense: {2}, Last Error: {3}) tomó {0} ms. + + + NEC READ CD-DA tomó {0} ms. + + + MEDIUM SCAN tomó {0} ms. + + + PIONEER READ CD-DA tomó {0} ms. + + + PIONEER READ CD-DA MSF tomó {0} ms. + + + PIONEER READ CD-XA tomó {0} ms. + + + PLASMON READ SECTOR LOCATION tomó {0} ms. + + + Plextor READ CD-DA (LBA: {1}, Tamaño del bloque: {2}, Longitud de la transferencia: {3}, Subcanal: {4}, Sense: {5}, Error: {6}) tomó {0} ms. + + + Plextor READ DVD (RAW) tomó {0} ms. + + + PLEXTOR READ EEPROM tomó {0} ms. + + + PLEXTOR POWEREC GET SPEEDS tomó {0} ms. + + + PLEXTOR GET SILENT MODE tomó {0} ms. + + + PLEXTOR GET GIGAREC tomó {0} ms. + + + PLEXTOR GET VARIREC tomó {0} ms. + + + PLEXTOR GET SECUREC tomó {0} ms. + + + PLEXTOR GET SPEEDREAD tomó {0} ms. + + + PLEXTOR GET SINGLE-SESSION / HIDE CD-R tomó {0} ms. + + + PLEXTOR GET BOOK BITSETTING tomó {0} ms. + + + PLEXTOR GET TEST WRITE DVD+ tomó {0} ms. + + + READ (6) tomó {0} ms. + + + READ (10) tomó {0} ms. + + + READ (12) tomó {0} ms. + + + READ (16) tomó {0} ms. + + + READ LONG (10) tomó {0} ms. + + + READ LONG (16) tomó {0} ms. + + + SEEK (6) tomó {0} ms. + + + SEEK (10) tomó {0} ms. + + + READ ATTRIBUTE tomó {0} ms. + + + INQUIRY tomó {0} ms. + + + TEST UNIT READY tomó {0} ms. + + + MODE SENSE(6) tomó {0} ms. + + + MODE SENSE(10) tomó {0} ms. + + + PREVENT ALLOW MEDIUM REMOVAL tomó {0} ms. + + + READ CAPACITY tomó {0} ms. + + + READ CAPACITY(16) tomó {0} ms. + + + READ MEDIA SERIAL NUMBER tomó {0} ms. + + + MODE SELECT(6) tomó {0} ms. + + + MODE SELECT(10) tomó {0} ms. + + + REQUEST SENSE tomó {0} ms. + + + LOAD UNLOAD (6) tomó {0} ms. + + + LOCATE (10) tomó {0} ms. + + + LOCATE (16) tomó {0} ms. + + + READ BLOCK LIMITS tomó {0} ms. + + + READ POSITION tomó {0} ms. + + + READ REVERSE (6) tomó {0} ms. + + + READ REVERSE (16) tomó {0} ms. + + + RECOVER BUFFERED DATA tomó {0} ms. + + + REPORT DENSITY SUPPORT tomó {0} ms. + + + REWIND tomó {0} ms. + + + TRACK SELECT tomó {0} ms. + + + SPACE tomó {0} ms. + + + SYQUEST READ (6) tomó {0} ms. + + + SYQUEST READ (10) tomó {0} ms. + + + La plataforma {0} no está soportada. + + + URI remota inválida. + + + Error al conectar al servidor. + + + Protocolo remoto inválido. + + + Servidor no encontrado + + + Conectado a {0} + + + No se pudo leer desde la red... + + + Los datos recibidos no son un paquete Aaru Remote... + + + Se esperaba paquete de saludo, se recibió paquete tipo {0}... + + + Versión de paquete no reconocida... + + + No se pudo escribir hacia la red... + + + Se esperaba paquete de respuesta ¿Soy root?, pero se recibió paquete tipo {0} + + + Se esperaba paquete de respuesta de listado de dispositivos, pero se recibió paquete tipo {0} + + + Se esperaba paquete de respuesta SCSI, se recibió paquete tipo {0}... + + + Se esperaba paquete de respuesta ATA CHS, se recibió paquete tipo {0}... + + + Se esperaba paquete de respuesta ATA LBA48, se recibió paquete tipo {0}... + + + Se esperaba paquete de respuesta ATA LBA48, se recibió paquete tipo {0}... + + + Se esperaba paquete de respuesta SDHCI, se recibió paquete tipo {0} + + + Se esperaba paquete de respuesta Tipo de Dispositivo, se recibió paquete tipo {0}... + + + Se esperaba paquete de respuesta de datos USB, pero se recibió paquete tipo {0}... + + + Se esperaba paquete de respuesta de datos FireWire, se recibió paquete tipo {0}... + + + Se esperaba paquete de respuesta de datos PCMCIA, se recibió paquete tipo {0}... + + + Se esperaba paquete de respuesta de multi comando MMC/SD, se recibió paquete tipo {0}... + + + Se esperaban {0} respuestas a comandos SD/MMC, pero se recibieron {1} respuestas... + + + Se esperaba paquete NOP, se recibió paquete tipo {0}... + + + Error de reapertura cerrando dispositivo... + + + Error {0} al reabrir con razón: {1}... + + + Se esperaba paquete de respuesta de lectura de SO, se recibió paquete tipo {0}... + + + Error remoto {0} en lectura de OS... + + \ No newline at end of file diff --git a/Aaru.Devices/Localization/Localization.resx b/Aaru.Devices/Localization/Localization.resx new file mode 100644 index 000000000..b87667258 --- /dev/null +++ b/Aaru.Devices/Localization/Localization.resx @@ -0,0 +1,511 @@ + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + READ BUFFER took {0} ms. + + + READ BUFFER DMA took {0} ms. + + + READ DMA took {0} ms. + + + READ MULTIPLE took {0} ms. + + + READ NATIVE MAX ADDRESS took {0} ms. + + + READ SECTORS took {0} ms. + + + READ LONG took {0} ms. + + + SEEK took {0} ms. + + + GET NATIVE MAX ADDRESS EXT took {0} ms. + + + READ DMA EXT took {0} ms. + + + READ LOG EXT took {0} ms. + + + READ LOG DMA EXT took {0} ms. + + + READ MULTIPLE EXT took {0} ms. + + + READ NATIVE MAX ADDRESS EXT took {0} ms. + + + READ SECTORS EXT took {0} ms. + + + SET FEATURES took {0} ms. + + + DOOR LOCK took {0} ms. + + + DOOR UNLOCK took {0} ms. + + + MEDIA EJECT took {0} ms. + + + IDENTIFY PACKET DEVICE took {0} ms. + + + CFA TRANSLATE SECTOR took {0} ms. + + + CFA REQUEST EXTENDED ERROR CODE took {0} ms. + + + CHECK MEDIA CARD TYPE took {0} ms. + + + SMART DISABLE OPERATIONS took {0} ms. + + + SMART ENABLE ATTRIBUTE AUTOSAVE took {0} ms. + + + SMART DISABLE ATTRIBUTE AUTOSAVE took {0} ms. + + + SMART ENABLE OPERATIONS took {0} ms. + + + SMART EXECUTE OFF-LINE IMMEDIATE took {0} ms. + + + SMART READ DATA took {0} ms. + + + SMART READ LOG took {0} ms. + + + SMART RETURN STATUS took {0} ms. + + + SEND_CSD took {0} ms. + + + SEND_CID took {0} ms. + + + SEND_OP_COND took {0} ms. + + + SEND_EXT_CSD took {0} ms. + + + SET_BLOCKLEN took {0} ms. + + + READ_SINGLE_BLOCK took {0} ms. + + + READ_MULTIPLE_BLOCK took {0} ms. + + + Multiple READ_SINGLE_BLOCKs took {0} ms. + + + SEND_STATUS took {0} ms. + + + SD_STATUS took {0} ms. + + + SD_SEND_OP_COND took {0} ms. + + + SEND_SCR took {0} ms. + + + ADAPTEC TRANSLATE took {0} ms. + + + ADAPTEC SET ERROR THRESHOLD took {0} ms. + + + ADAPTEC READ/RESET USAGE COUNTER took {0} ms. + + + ADAPTEC WRITE DATA BUFFER took {0} ms. + + + ADAPTEC READ DATA BUFFER took {0} ms. + + + ARCHIVE CORP. REQUEST BLOCK ADDRESS took {0} ms. + + + ARCHIVE CORP. SEEK BLOCK took {0} ms. + + + CERTANCE PARK UNPARK took {0} ms. + + + FUJITSU DISPLAY took {0} ms. + + + HL-DT-ST READ DVD (RAW) took {0} ms. + + + HP READ LONG took {0} ms. + + + KREON DEPRECATED UNLOCK took {0} ms. + + + KREON SET LOCK STATE took {0} ms. + + + KREON GET FEATURE LIST took {0} ms. + + + KREON EXTRACT SS took {0} ms. + + + MediaTek READ DRAM took {0} ms. + + + MINIDISC READ DTOC took {0} ms. + + + MINIDISC READ UTOC took {0} ms. + + + MINIDISC command D5h took {0} ms. + + + MINIDISC STOP PLAY took {0} ms. + + + MINIDISC READ POSITION took {0} ms. + + + MINIDISC GET TYPE took {0} ms. + + + GET CONFIGURATION (Starting Feature Number: {1}, Return Type: {2}, Sense: {3}, Last Error: {4}) took {0} ms. + + + READ DISC STRUCTURE (Media Type: {1}, Address: {2}, Layer Number: {3}, Format: {4}, AGID: {5}, Sense: {6}, Last Error: {7}) took {0} ms. + + + READ TOC/PMA/ATIP took (MSF: {1}, Format: {2}, Track/Session Number: {3}, Sense: {4}, LastError: {5}) {0} ms. + + + READ DISC INFORMATION (Data Type: {1}, Sense: {2}, Last Error: {3}) took {0} ms. + + + READ CD (LBA: {1}, Block Size: {2}, Transfer Length: {3}, Expected Sector Type: {4}, DAP: {5}, Relative Address: {6}, Sync: {7}, Headers: {8}, User Data: {9}, ECC/EDC: {10}, C2: {11}, Subchannel: {12}, Sense: {13}, Last Error: {14}) took {0} ms. + + + READ CD MSF (Start MSF: {1}, End MSF: {2}, Block Size: {3}, Expected Sector Type: {4}, DAP: {5}, Sync: {6}, Headers: {7}, User Data: {8}, ECC/EDC: {9}, C2: {10}, Subchannel: {11}, Sense: {12}, LastError: {13}) took {0} ms. + + + PREVENT ALLOW MEDIUM REMOVAL (Persistent: {1}, Prevent: {2}, Sense: {3}, LastError: {4}) took {0} ms. + + + START STOP UNIT (Immediate: {1}, FormatLayer: {2}, Power Conditions: {3}, Change Format Layer: {4}, Load/Eject: {5}, Start: {6}, Sense: {7}, Last Error: {8}) took {0} ms. + + + READ READ SUB-CHANNEL (MCN, Sense {1}, Last Error {2}) took {0} ms. + + + READ READ SUB-CHANNEL (ISRC, Track Number: {1}, Sense: {2}, Last Error: {3}) took {0} ms. + + + SET CD SPEED (Rotational Control: {1}, Read Speed: {2}, Write Speed: {3}, Sense: {4}, Last Error: {5}) took {0} ms. + + + READ TRACK INFORMATION (Data Type: {1}, Sense: {2}, Last Error: {3}) took {0} ms. + + + NEC READ CD-DA took {0} ms. + + + MEDIUM SCAN took {0} ms. + + + PIONEER READ CD-DA took {0} ms. + + + PIONEER READ CD-DA MSF took {0} ms. + + + PIONEER READ CD-XA took {0} ms. + + + PLASMON READ SECTOR LOCATION took {0} ms. + + + Plextor READ CD-DA (LBA: {1}, Block Size: {2}, Transfer Length: {3}, Subchannel: {4}, Sense: {5}, Last Error: {6}) took {0} ms. + + + Plextor READ DVD (RAW) took {0} ms. + + + PLEXTOR READ EEPROM took {0} ms. + + + PLEXTOR POWEREC GET SPEEDS took {0} ms. + + + PLEXTOR GET SILENT MODE took {0} ms. + + + PLEXTOR GET GIGAREC took {0} ms. + + + PLEXTOR GET VARIREC took {0} ms. + + + PLEXTOR GET SECUREC took {0} ms. + + + PLEXTOR GET SPEEDREAD took {0} ms. + + + PLEXTOR GET SINGLE-SESSION / HIDE CD-R took {0} ms. + + + PLEXTOR GET BOOK BITSETTING took {0} ms. + + + PLEXTOR GET TEST WRITE DVD+ took {0} ms. + + + READ (6) took {0} ms. + + + READ (10) took {0} ms. + + + READ (12) took {0} ms. + + + READ (16) took {0} ms. + + + READ LONG (10) took {0} ms. + + + READ LONG (16) took {0} ms. + + + SEEK (6) took {0} ms. + + + SEEK (10) took {0} ms. + + + READ ATTRIBUTE took {0} ms. + + + INQUIRY took {0} ms. + + + TEST UNIT READY took {0} ms. + + + MODE SENSE(6) took {0} ms. + + + MODE SENSE(10) took {0} ms. + + + PREVENT ALLOW MEDIUM REMOVAL took {0} ms. + + + READ CAPACITY took {0} ms. + + + READ CAPACITY(16) took {0} ms. + + + READ MEDIA SERIAL NUMBER took {0} ms. + + + MODE SELECT(6) took {0} ms. + + + MODE SELECT(10) took {0} ms. + + + REQUEST SENSE took {0} ms. + + + LOAD UNLOAD (6) took {0} ms. + + + LOCATE (10) took {0} ms. + + + LOCATE (16) took {0} ms. + + + READ BLOCK LIMITS took {0} ms. + + + READ POSITION took {0} ms. + + + READ REVERSE (6) took {0} ms. + + + READ REVERSE (16) took {0} ms. + + + RECOVER BUFFERED DATA took {0} ms. + + + REPORT DENSITY SUPPORT took {0} ms. + + + REWIND took {0} ms. + + + TRACK SELECT took {0} ms. + + + SPACE took {0} ms. + + + SYQUEST READ (6) took {0} ms. + + + SYQUEST READ (10) took {0} ms. + + + Platform {0} not yet supported. + + + Invalid remote URI. + + + Error connecting to host. + + + Invalid remote protocol. + + + Host not found + + + Connected to {0} + + + Could not read from the network... + + + Received data is not an Aaru Remote Packet... + + + Expected Hello Packet, got packet type {0}... + + + Unrecognized packet version... + + + Could not write to the network... + + + Expected Am I Root? Response Packet, got packet type {0}... + + + Expected List Devices Response Packet, got packet type {0}... + + + Expected SCSI Response Packet, got packet type {0}... + + + Expected ATA CHS Response Packet, got packet type {0}... + + + Expected ATA LBA28 Response Packet, got packet type {0}... + + + Expected ATA LBA48 Response Packet, got packet type {0}... + + + Expected SDHCI Response Packet, got packet type {0}... + + + Expected Device Type Response Packet, got packet type {0}... + + + Expected USB Data Response Packet, got packet type {0}... + + + Expected FireWire Data Response Packet, got packet type {0}... + + + Expected PCMCIA Data Response Packet, got packet type {0}... + + + Expected multi MMC/SD command Response Packet, got packet type {0}... + + + Expected the response to {0} SD/MMC commands, but got {1} responses... + + + Expected NOP Packet, got packet type {0}... + + + ReOpen error closing device... + + + ReOpen error {0} with reason: {1}... + + + Expected OS Read Response Packet, got packet type {0}... + + + Remote error {0} in OS Read... + + \ No newline at end of file diff --git a/Aaru.Devices/Remote/Command.cs b/Aaru.Devices/Remote/Command.cs index 8f0b52035..a0357278d 100644 --- a/Aaru.Devices/Remote/Command.cs +++ b/Aaru.Devices/Remote/Command.cs @@ -27,25 +27,25 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Remote; - using System; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Aaru.Decoders.ATA; +namespace Aaru.Devices.Remote; + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public partial class Device { /// - public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, + public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, ScsiDirection direction, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; return _remote.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, direction, out duration, out sense); } @@ -56,11 +56,17 @@ public partial class Device uint timeout, bool transferBlocks, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; - return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout, - transferBlocks, out duration, out sense); + return _remote.SendAtaCommand(registers, + out errorRegisters, + protocol, + transferRegister, + ref buffer, + timeout, + transferBlocks, + out duration, + out sense); } /// @@ -69,11 +75,17 @@ public partial class Device uint timeout, bool transferBlocks, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; - return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout, - transferBlocks, out duration, out sense); + return _remote.SendAtaCommand(registers, + out errorRegisters, + protocol, + transferRegister, + ref buffer, + timeout, + transferBlocks, + out duration, + out sense); } /// @@ -82,86 +94,102 @@ public partial class Device uint timeout, bool transferBlocks, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; - return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout, - transferBlocks, out duration, out sense); + return _remote.SendAtaCommand(registers, + out errorRegisters, + protocol, + transferRegister, + ref buffer, + timeout, + transferBlocks, + out duration, + out sense); } /// - public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, - uint argument, uint blockSize, uint blocks, ref byte[] buffer, - out uint[] response, out double duration, out bool sense, uint timeout = 15) + public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, + uint argument, uint blockSize, uint blocks, ref byte[] buffer, + out uint[] response, out double duration, out bool sense, uint timeout = 15) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; + + var cmdStopwatch = new Stopwatch(); switch(command) { - case MmcCommands.SendCid when _cachedCid != null: + case MmcCommands.SendCid when CachedCid != null: { - DateTime start = DateTime.Now; - buffer = new byte[_cachedCid.Length]; - Array.Copy(_cachedCid, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedCid.Length]; + Array.Copy(CachedCid, buffer, buffer.Length); response = new uint[4]; sense = false; - DateTime end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } - case MmcCommands.SendCsd when _cachedCid != null: + case MmcCommands.SendCsd when CachedCid != null: { - DateTime start = DateTime.Now; - buffer = new byte[_cachedCsd.Length]; - Array.Copy(_cachedCsd, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedCsd.Length]; + Array.Copy(CachedCsd, buffer, buffer.Length); response = new uint[4]; sense = false; - DateTime end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } - case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null: + case (MmcCommands)SecureDigitalCommands.SendScr when CachedScr != null: { - DateTime start = DateTime.Now; - buffer = new byte[_cachedScr.Length]; - Array.Copy(_cachedScr, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedScr.Length]; + Array.Copy(CachedScr, buffer, buffer.Length); response = new uint[4]; sense = false; - DateTime end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } - case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null: - case MmcCommands.SendOpCond when _cachedOcr != null: + case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when CachedOcr != null: + case MmcCommands.SendOpCond when CachedOcr != null: { - DateTime start = DateTime.Now; - buffer = new byte[_cachedOcr.Length]; - Array.Copy(_cachedOcr, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedOcr.Length]; + Array.Copy(CachedOcr, buffer, buffer.Length); response = new uint[4]; sense = false; - DateTime end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } } - return _remote.SendMmcCommand(command, write, isApplication, flags, argument, blockSize, blocks, ref buffer, - out response, out duration, out sense, timeout); + return _remote.SendMmcCommand(command, + write, + isApplication, + flags, + argument, + blockSize, + blocks, + ref buffer, + out response, + out duration, + out sense, + timeout); } /// public override int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense, - uint timeout = 15) + uint timeout = 15) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; if(_remote.ServerProtocolVersion >= 2) return _remote.SendMultipleMmcCommands(commands, out duration, out sense, timeout); @@ -172,19 +200,24 @@ public partial class Device foreach(MmcSingleCommand command in commands) { - int singleError = _remote.SendMmcCommand(command.command, command.write, command.isApplication, - command.flags, command.argument, command.blockSize, command.blocks, - ref command.buffer, out command.response, out double cmdDuration, - out bool cmdSense, timeout); + int singleError = _remote.SendMmcCommand(command.command, + command.write, + command.isApplication, + command.flags, + command.argument, + command.blockSize, + command.blocks, + ref command.buffer, + out command.response, + out double cmdDuration, + out bool cmdSense, + timeout); - if(error == 0 && - singleError != 0) - error = singleError; + if(error == 0 && singleError != 0) error = singleError; duration += cmdDuration; - if(cmdSense) - sense = true; + if(cmdSense) sense = true; } return error; diff --git a/Aaru.Devices/Remote/Consts.cs b/Aaru.Devices/Remote/Consts.cs index a1f43bac4..a5a2f1ef4 100644 --- a/Aaru.Devices/Remote/Consts.cs +++ b/Aaru.Devices/Remote/Consts.cs @@ -27,7 +27,7 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Devices.Remote; diff --git a/Aaru.Devices/Remote/Device.cs b/Aaru.Devices/Remote/Device.cs index 74209d23d..fbc261a19 100644 --- a/Aaru.Devices/Remote/Device.cs +++ b/Aaru.Devices/Remote/Device.cs @@ -27,11 +27,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Remote; - using System; using System.Net.Sockets; using Aaru.CommonTypes.Enums; @@ -39,11 +37,16 @@ using Aaru.CommonTypes.Interop; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.SecureDigital; +namespace Aaru.Devices.Remote; + /// public sealed partial class Device : Devices.Device { + bool? _isRemoteAdmin; Remote _remote; + Device() {} + /// Returns if remote is running under administrative (aka root) privileges public bool IsAdmin { @@ -56,25 +59,31 @@ public sealed partial class Device : Devices.Device } /// Current device is remote + + // ReSharper disable once UnusedMember.Global public bool IsRemote => _remote != null; + /// Remote application public string RemoteApplication => _remote?.ServerApplication; + /// Remote application server public string RemoteVersion => _remote?.ServerVersion; + /// Remote operating system name public string RemoteOperatingSystem => _remote?.ServerOperatingSystem; + /// Remote operating system version public string RemoteOperatingSystemVersion => _remote?.ServerOperatingSystemVersion; + /// Remote architecture public string RemoteArchitecture => _remote?.ServerArchitecture; + /// Remote protocol version public int RemoteProtocolVersion => _remote?.ServerProtocolVersion ?? 0; - bool? _isRemoteAdmin; - - Device() {} /// Opens the device for sending direct commands /// AaruRemote URI + /// Sets the error if a device cannot be opened /// Device internal static Device Create(Uri aaruUri, out ErrorNumber errno) { @@ -88,18 +97,15 @@ public sealed partial class Device : Devices.Device IsRemovable = false }; - if(aaruUri.Scheme is not ("dic" or "aaru")) - return null; + if(aaruUri.Scheme is not ("dic" or "aaru")) return null; string devicePath = aaruUri.AbsolutePath; - if(devicePath.StartsWith('/')) - devicePath = devicePath[1..]; + if(devicePath.StartsWith('/')) devicePath = devicePath[1..]; - if(devicePath.StartsWith("dev", StringComparison.Ordinal)) - devicePath = $"/{devicePath}"; + if(devicePath.StartsWith("dev", StringComparison.Ordinal)) devicePath = $"/{devicePath}"; - dev._devicePath = devicePath; + dev.DevicePath = devicePath; try { @@ -126,19 +132,17 @@ public sealed partial class Device : Devices.Device return null; } - if(dev._remote.ServerOperatingSystem == "Linux") - _readMultipleBlockCannotSetBlockCount = true; + if(dev._remote.ServerOperatingSystem == "Linux") _readMultipleBlockCannotSetBlockCount = true; dev.Type = DeviceType.Unknown; dev.ScsiType = PeripheralDeviceTypes.UnknownDevice; if(dev.Error) - if(dev.Error) - { - errno = (ErrorNumber)dev.LastError; + { + errno = (ErrorNumber)dev.LastError; - return null; - } + return null; + } dev.Type = dev._remote.GetDeviceType(); @@ -146,8 +150,10 @@ public sealed partial class Device : Devices.Device { case DeviceType.SecureDigital: case DeviceType.MMC: - if(!dev._remote.GetSdhciRegisters(out dev._cachedCsd, out dev._cachedCid, out dev._cachedOcr, - out dev._cachedScr)) + if(!dev._remote.GetSdhciRegisters(out dev.CachedCsd, + out dev.CachedCid, + out dev.CachedOcr, + out dev.CachedScr)) { dev.Type = DeviceType.SCSI; dev.ScsiType = PeripheralDeviceTypes.DirectAccess; @@ -156,16 +162,17 @@ public sealed partial class Device : Devices.Device break; } - #region SecureDigital / MultiMediaCard - if(dev._cachedCid != null) +#region SecureDigital / MultiMediaCard + + if(dev.CachedCid != null) { dev.ScsiType = PeripheralDeviceTypes.DirectAccess; dev.IsRemovable = false; - if(dev._cachedScr != null) + if(dev.CachedScr != null) { dev.Type = DeviceType.SecureDigital; - CID decoded = Decoders.DecodeCID(dev._cachedCid); + CID decoded = Decoders.SecureDigital.Decoders.DecodeCID(dev.CachedCid); dev.Manufacturer = VendorString.Prettify(decoded.Manufacturer); dev.Model = decoded.ProductName; @@ -177,8 +184,8 @@ public sealed partial class Device : Devices.Device else { dev.Type = DeviceType.MMC; - Aaru.Decoders.MMC.CID decoded = Aaru.Decoders.MMC.Decoders.DecodeCID(dev._cachedCid); - dev.Manufacturer = Aaru.Decoders.MMC.VendorString.Prettify(decoded.Manufacturer); + Decoders.MMC.CID decoded = Decoders.MMC.Decoders.DecodeCID(dev.CachedCid); + dev.Manufacturer = Decoders.MMC.VendorString.Prettify(decoded.Manufacturer); dev.Model = decoded.ProductName; dev.FirmwareRevision = @@ -189,39 +196,52 @@ public sealed partial class Device : Devices.Device return dev; } - #endregion SecureDigital / MultiMediaCard - #region USB - if(dev._remote.GetUsbData(out byte[] remoteUsbDescriptors, out ushort remoteUsbVendor, - out ushort remoteUsbProduct, out string remoteUsbManufacturer, - out string remoteUsbProductString, out string remoteUsbSerial)) +#endregion SecureDigital / MultiMediaCard + +#region USB + + if(dev._remote.GetUsbData(out byte[] remoteUsbDescriptors, + out ushort remoteUsbVendor, + out ushort remoteUsbProduct, + out string remoteUsbManufacturer, + out string remoteUsbProductString, + out string remoteUsbSerial)) { dev.IsUsb = true; dev.UsbDescriptors = remoteUsbDescriptors; - dev._usbVendor = remoteUsbVendor; - dev._usbProduct = remoteUsbProduct; + dev.UsbVendor = remoteUsbVendor; + dev.UsbProduct = remoteUsbProduct; dev.UsbManufacturerString = remoteUsbManufacturer; dev.UsbProductString = remoteUsbProductString; dev.UsbSerialString = remoteUsbSerial; } - #endregion USB - #region FireWire - if(dev._remote.GetFireWireData(out dev._firewireVendor, out dev._firewireModel, out dev._firewireGuid, - out string remoteFireWireVendorName, out string remoteFireWireModelName)) +#endregion USB + +#region FireWire + + if(dev._remote.GetFireWireData(out dev.FirewireVendor, + out dev.FirewireModel, + out dev.FirewireGuid, + out string remoteFireWireVendorName, + out string remoteFireWireModelName)) { dev.IsFireWire = true; dev.FireWireVendorName = remoteFireWireVendorName; dev.FireWireModelName = remoteFireWireModelName; } - #endregion FireWire - #region PCMCIA - if(dev._remote.GetPcmciaData(out byte[] cisBuf)) - { - dev.IsPcmcia = true; - dev.Cis = cisBuf; - } - #endregion PCMCIA + +#endregion FireWire + +#region PCMCIA + + if(!dev._remote.GetPcmciaData(out byte[] cisBuf)) return dev; + + dev.IsPcmcia = true; + dev.Cis = cisBuf; + +#endregion PCMCIA return dev; } @@ -229,8 +249,7 @@ public sealed partial class Device : Devices.Device /// public override void Close() { - if(_remote == null) - return; + if(_remote == null) return; _remote.Close(); _remote.Disconnect(); diff --git a/Aaru.Devices/Remote/Enums.cs b/Aaru.Devices/Remote/Enums.cs index 3640c9e96..c8b33ac2f 100644 --- a/Aaru.Devices/Remote/Enums.cs +++ b/Aaru.Devices/Remote/Enums.cs @@ -27,15 +27,17 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System.Diagnostics.CodeAnalysis; + namespace Aaru.Devices.Remote; /// Packet type enumeration public enum AaruPacketType : sbyte { - #pragma warning disable 1591 +#pragma warning disable 1591 Nop = -1, Hello = 1, CommandListDevices = 2, @@ -69,10 +71,11 @@ public enum AaruPacketType : sbyte CommandReOpenDevice = 30, CommandOsRead = 31, ResponseOsRead = 32 - #pragma warning restore 1591 +#pragma warning restore 1591 } /// Reasons for non-data request or response +[SuppressMessage("ReSharper", "UnusedMember.Global")] public enum AaruNopReason : byte { /// Request or response has arrived unexpectedly diff --git a/Aaru.Devices/Remote/Remote.cs b/Aaru.Devices/Remote/Remote.cs index 2736e3c24..832103924 100644 --- a/Aaru.Devices/Remote/Remote.cs +++ b/Aaru.Devices/Remote/Remote.cs @@ -27,15 +27,11 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable MemberCanBeInternal -namespace Aaru.Devices.Remote; - using System; using System.Collections.Generic; using System.IO; @@ -50,6 +46,8 @@ using Aaru.Decoders.ATA; using Marshal = Aaru.Helpers.Marshal; using Version = Aaru.CommonTypes.Interop.Version; +namespace Aaru.Devices.Remote; + /// /// Handles communication with a remote device that's connected using the AaruRemote protocol public class Remote : IDisposable @@ -64,9 +62,8 @@ public class Remote : IDisposable /// Network error. public Remote(Uri uri) { - if(uri.Scheme != "aaru" && - uri.Scheme != "dic") - throw new ArgumentException("Invalid remote protocol.", nameof(uri.Scheme)); + if(uri.Scheme != "aaru" && uri.Scheme != "dic") + throw new ArgumentException(Localization.Invalid_remote_protocol, nameof(uri.Scheme)); _host = uri.DnsSafeHost; @@ -79,7 +76,7 @@ public class Remote : IDisposable if(ipAddress is null) { - AaruConsole.ErrorWriteLine("Host not found"); + AaruConsole.ErrorWriteLine(Localization.Host_not_found); throw new SocketException(11001); } @@ -89,7 +86,7 @@ public class Remote : IDisposable _socket.Connect(ipEndPoint); - AaruConsole.WriteLine("Connected to {0}", uri.Host); + AaruConsole.WriteLine(Localization.Connected_to_0, uri.Host); var hdrBuf = new byte[Marshal.SizeOf()]; @@ -97,17 +94,16 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); throw new IOException(); } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); throw new ArgumentException(); } @@ -118,7 +114,7 @@ public class Remote : IDisposable { if(hdr.packetType != AaruPacketType.Nop) { - AaruConsole.ErrorWriteLine("Expected Hello Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_Hello_Packet_got_packet_type_0, hdr.packetType); throw new ArgumentException(); } @@ -128,7 +124,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); throw new IOException(); } @@ -142,7 +138,7 @@ public class Remote : IDisposable if(hdr.version != Consts.PACKET_VERSION) { - AaruConsole.ErrorWriteLine("Unrecognized packet version..."); + AaruConsole.ErrorWriteLine(Localization.Unrecognized_packet_version); throw new ArgumentException(); } @@ -152,7 +148,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); throw new IOException(); } @@ -188,24 +184,28 @@ public class Remote : IDisposable len = _socket.Send(buf, SocketFlags.None); - if(len >= buf.Length) - return; + if(len >= buf.Length) return; - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); throw new IOException(); } /// Remote server application public string ServerApplication { get; } + /// Remote server application version public string ServerVersion { get; } + /// Remote server operating system public string ServerOperatingSystem { get; } + /// Remote server operating system version public string ServerOperatingSystemVersion { get; } + /// Remote server architecture public string ServerArchitecture { get; } + /// Remote server protocol version public int ServerProtocolVersion { get; } @@ -232,7 +232,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return false; } @@ -243,24 +243,24 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return false; } if(hdr.packetType != AaruPacketType.ResponseAmIRoot) { - AaruConsole.ErrorWriteLine("Expected Am I Root? Response Packet, got packet type {0}...", + AaruConsole.ErrorWriteLine(Localization + .Remote_IsRoot_Expected_Am_I_Root_Response_Packet_got_packet_type_0, hdr.packetType); return false; @@ -271,7 +271,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } @@ -282,9 +282,13 @@ public class Remote : IDisposable } } +#region IDisposable Members + /// public void Dispose() => Disconnect(); +#endregion + /// Disconnects from remote public void Disconnect() { @@ -321,9 +325,9 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); - return Array.Empty(); + return []; } var hdrBuf = new byte[Marshal.SizeOf()]; @@ -332,29 +336,29 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); - return Array.Empty(); + return []; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); - return Array.Empty(); + return []; } if(hdr.packetType != AaruPacketType.ResponseListDevices) { if(hdr.packetType != AaruPacketType.Nop) { - AaruConsole.ErrorWriteLine("Expected List Devices Response Packet, got packet type {0}...", + AaruConsole.ErrorWriteLine(Localization + .Remote_ListDevices_Expected_List_Devices_Response_Packet_got_packet_type_0, hdr.packetType); - return Array.Empty(); + return []; } buf = new byte[hdr.len]; @@ -362,23 +366,23 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); - return Array.Empty(); + return []; } AaruPacketNop nop = Marshal.ByteArrayToStructureLittleEndian(buf); AaruConsole.ErrorWriteLine($"{nop.reason}"); - return Array.Empty(); + return []; } if(hdr.version != Consts.PACKET_VERSION) { - AaruConsole.ErrorWriteLine("Unrecognized packet version..."); + AaruConsole.ErrorWriteLine(Localization.Unrecognized_packet_version); - return Array.Empty(); + return []; } buf = new byte[hdr.len]; @@ -386,17 +390,17 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); - return Array.Empty(); + return []; } AaruPacketResponseListDevices response = Marshal.ByteArrayToStructureLittleEndian(buf); - var devices = new List(); - int offset = Marshal.SizeOf(); - int devInfoLen = Marshal.SizeOf(); + List devices = []; + int offset = Marshal.SizeOf(); + int devInfoLen = Marshal.SizeOf(); for(ushort i = 0; i < response.devices; i++) { @@ -440,7 +444,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); lastError = -1; return false; @@ -452,7 +456,7 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); lastError = -1; return false; @@ -460,10 +464,9 @@ public class Remote : IDisposable AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); lastError = -1; return false; @@ -471,7 +474,9 @@ public class Remote : IDisposable if(hdr.packetType != AaruPacketType.Nop) { - AaruConsole.ErrorWriteLine("Expected List Devices Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization + .Remote_ListDevices_Expected_List_Devices_Response_Packet_got_packet_type_0, + hdr.packetType); lastError = -1; @@ -483,7 +488,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); lastError = -1; return false; @@ -493,8 +498,10 @@ public class Remote : IDisposable switch(nop.reasonCode) { - case AaruNopReason.OpenOk: return true; - case AaruNopReason.NotImplemented: throw new NotImplementedException($"{nop.reason}"); + case AaruNopReason.OpenOk: + return true; + case AaruNopReason.NotImplemented: + throw new NotImplementedException($"{nop.reason}"); } AaruConsole.ErrorWriteLine($"{nop.reason}"); @@ -515,8 +522,8 @@ public class Remote : IDisposable /// True if SCSI command returned non-OK status and contains /// SCSI sense /// - public int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, - ScsiDirection direction, out double duration, out bool sense) + public int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, + ScsiDirection direction, out double duration, out bool sense) { senseBuffer = null; duration = 0; @@ -535,11 +542,9 @@ public class Remote : IDisposable timeout = timeout * 1000 }; - if(cdb != null) - cmdPkt.cdb_len = (uint)cdb.Length; + if(cdb != null) cmdPkt.cdb_len = (uint)cdb.Length; - if(buffer != null) - cmdPkt.buf_len = (uint)buffer.Length; + if(buffer != null) cmdPkt.buf_len = (uint)buffer.Length; cmdPkt.hdr.len = (uint)(Marshal.SizeOf() + cmdPkt.cdb_len + cmdPkt.buf_len); @@ -548,8 +553,7 @@ public class Remote : IDisposable Array.Copy(pktBuf, 0, buf, 0, Marshal.SizeOf()); - if(cdb != null) - Array.Copy(cdb, 0, buf, Marshal.SizeOf(), cmdPkt.cdb_len); + if(cdb != null) Array.Copy(cdb, 0, buf, Marshal.SizeOf(), cmdPkt.cdb_len); if(buffer != null) Array.Copy(buffer, 0, buf, Marshal.SizeOf() + cmdPkt.cdb_len, cmdPkt.buf_len); @@ -558,7 +562,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return -1; } @@ -569,24 +573,23 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return -1; } if(hdr.packetType != AaruPacketType.ResponseScsi) { - AaruConsole.ErrorWriteLine("Expected SCSI Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_SCSI_Response_Packet_got_packet_type_0, hdr.packetType); return -1; } @@ -596,7 +599,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } @@ -651,8 +654,7 @@ public class Remote : IDisposable timeout = timeout * 1000 }; - if(buffer != null) - cmdPkt.buf_len = (uint)buffer.Length; + if(buffer != null) cmdPkt.buf_len = (uint)buffer.Length; cmdPkt.hdr.len = (uint)(Marshal.SizeOf() + cmdPkt.buf_len); @@ -661,14 +663,13 @@ public class Remote : IDisposable Array.Copy(pktBuf, 0, buf, 0, Marshal.SizeOf()); - if(buffer != null) - Array.Copy(buffer, 0, buf, Marshal.SizeOf(), cmdPkt.buf_len); + if(buffer != null) Array.Copy(buffer, 0, buf, Marshal.SizeOf(), cmdPkt.buf_len); int len = _socket.Send(buf, SocketFlags.None); if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return -1; } @@ -679,24 +680,23 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return -1; } if(hdr.packetType != AaruPacketType.ResponseAtaChs) { - AaruConsole.ErrorWriteLine("Expected ATA CHS Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_ATA_CHS_Response_Packet_got_packet_type_0, hdr.packetType); return -1; } @@ -706,7 +706,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } @@ -737,8 +737,8 @@ public class Remote : IDisposable /// Time it took to execute the command in milliseconds /// True if ATA/ATAPI command returned non-OK status public int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, - AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, - uint timeout, bool transferBlocks, out double duration, out bool sense) + AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, + uint timeout, bool transferBlocks, out double duration, out bool sense) { duration = 0; sense = true; @@ -760,8 +760,7 @@ public class Remote : IDisposable timeout = timeout * 1000 }; - if(buffer != null) - cmdPkt.buf_len = (uint)buffer.Length; + if(buffer != null) cmdPkt.buf_len = (uint)buffer.Length; cmdPkt.hdr.len = (uint)(Marshal.SizeOf() + cmdPkt.buf_len); @@ -770,14 +769,13 @@ public class Remote : IDisposable Array.Copy(pktBuf, 0, buf, 0, Marshal.SizeOf()); - if(buffer != null) - Array.Copy(buffer, 0, buf, Marshal.SizeOf(), cmdPkt.buf_len); + if(buffer != null) Array.Copy(buffer, 0, buf, Marshal.SizeOf(), cmdPkt.buf_len); int len = _socket.Send(buf, SocketFlags.None); if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return -1; } @@ -788,24 +786,24 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return -1; } if(hdr.packetType != AaruPacketType.ResponseAtaLba28) { - AaruConsole.ErrorWriteLine("Expected ATA LBA28 Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_ATA_LBA28_Response_Packet_got_packet_type_0, + hdr.packetType); return -1; } @@ -815,7 +813,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } @@ -846,8 +844,8 @@ public class Remote : IDisposable /// Time it took to execute the command in milliseconds /// True if ATA/ATAPI command returned non-OK status public int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, - AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, - uint timeout, bool transferBlocks, out double duration, out bool sense) + AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, + uint timeout, bool transferBlocks, out double duration, out bool sense) { duration = 0; sense = true; @@ -869,8 +867,7 @@ public class Remote : IDisposable timeout = timeout * 1000 }; - if(buffer != null) - cmdPkt.buf_len = (uint)buffer.Length; + if(buffer != null) cmdPkt.buf_len = (uint)buffer.Length; cmdPkt.hdr.len = (uint)(Marshal.SizeOf() + cmdPkt.buf_len); @@ -879,14 +876,13 @@ public class Remote : IDisposable Array.Copy(pktBuf, 0, buf, 0, Marshal.SizeOf()); - if(buffer != null) - Array.Copy(buffer, 0, buf, Marshal.SizeOf(), cmdPkt.buf_len); + if(buffer != null) Array.Copy(buffer, 0, buf, Marshal.SizeOf(), cmdPkt.buf_len); int len = _socket.Send(buf, SocketFlags.None); if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return -1; } @@ -897,24 +893,24 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return -1; } if(hdr.packetType != AaruPacketType.ResponseAtaLba48) { - AaruConsole.ErrorWriteLine("Expected ATA LBA48 Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_ATA_LBA48_Response_Packet_got_packet_type_0, + hdr.packetType); return -1; } @@ -924,7 +920,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } @@ -984,8 +980,7 @@ public class Remote : IDisposable } }; - if(buffer != null) - cmdPkt.command.buf_len = (uint)buffer.Length; + if(buffer != null) cmdPkt.command.buf_len = (uint)buffer.Length; cmdPkt.hdr.len = (uint)(Marshal.SizeOf() + cmdPkt.command.buf_len); @@ -994,14 +989,13 @@ public class Remote : IDisposable Array.Copy(pktBuf, 0, buf, 0, Marshal.SizeOf()); - if(buffer != null) - Array.Copy(buffer, 0, buf, Marshal.SizeOf(), cmdPkt.command.buf_len); + if(buffer != null) Array.Copy(buffer, 0, buf, Marshal.SizeOf(), cmdPkt.command.buf_len); int len = _socket.Send(buf, SocketFlags.None); if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return -1; } @@ -1012,24 +1006,23 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return -1; } if(hdr.packetType != AaruPacketType.ResponseSdhci) { - AaruConsole.ErrorWriteLine("Expected SDHCI Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_SDHCI_Response_Packet_got_packet_type_0, hdr.packetType); return -1; } @@ -1039,7 +1032,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } @@ -1083,7 +1076,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return DeviceType.Unknown; } @@ -1094,24 +1087,24 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return DeviceType.Unknown; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return DeviceType.Unknown; } if(hdr.packetType != AaruPacketType.ResponseGetType) { - AaruConsole.ErrorWriteLine("Expected Device Type Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_Device_Type_Response_Packet_got_packet_type_0, + hdr.packetType); return DeviceType.Unknown; } @@ -1121,7 +1114,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return DeviceType.Unknown; } @@ -1162,7 +1155,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return false; } @@ -1173,24 +1166,24 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return false; } if(hdr.packetType != AaruPacketType.ResponseGetSdhciRegisters) { - AaruConsole.ErrorWriteLine("Expected Device Type Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_Device_Type_Response_Packet_got_packet_type_0, + hdr.packetType); return false; } @@ -1200,7 +1193,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } @@ -1210,8 +1203,7 @@ public class Remote : IDisposable if(res.csd_len > 0) { - if(res.csd_len > 16) - res.csd_len = 16; + if(res.csd_len > 16) res.csd_len = 16; csd = new byte[res.csd_len]; @@ -1220,8 +1212,7 @@ public class Remote : IDisposable if(res.cid_len > 0) { - if(res.cid_len > 16) - res.cid_len = 16; + if(res.cid_len > 16) res.cid_len = 16; cid = new byte[res.cid_len]; @@ -1230,24 +1221,27 @@ public class Remote : IDisposable if(res.ocr_len > 0) { - if(res.ocr_len > 16) - res.ocr_len = 16; + if(res.ocr_len > 16) res.ocr_len = 16; ocr = new byte[res.ocr_len]; Array.Copy(res.ocr, 0, ocr, 0, res.ocr_len); } - if(res.scr_len > 0) + switch(res.scr_len) { - if(res.scr_len > 16) + case <= 0: + return res.isSdhci; + case > 16: res.scr_len = 16; - scr = new byte[res.scr_len]; - - Array.Copy(res.scr, 0, scr, 0, res.scr_len); + break; } + scr = new byte[res.scr_len]; + + Array.Copy(res.scr, 0, scr, 0, res.scr_len); + return res.isSdhci; } @@ -1260,7 +1254,7 @@ public class Remote : IDisposable /// USB serial number string /// true if the device is attached via USB, false otherwise public bool GetUsbData(out byte[] descriptors, out ushort idVendor, out ushort idProduct, out string manufacturer, - out string product, out string serial) + out string product, out string serial) { descriptors = null; idVendor = 0; @@ -1287,7 +1281,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return false; } @@ -1298,24 +1292,24 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return false; } if(hdr.packetType != AaruPacketType.ResponseGetUsbData) { - AaruConsole.ErrorWriteLine("Expected USB Data Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_USB_Data_Response_Packet_got_packet_type_0, + hdr.packetType); return false; } @@ -1325,15 +1319,14 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } AaruPacketResGetUsbData res = Marshal.ByteArrayToStructureLittleEndian(buf); - if(!res.isUsb) - return false; + if(!res.isUsb) return false; descriptors = new byte[res.descLen]; Array.Copy(res.descriptors, 0, descriptors, 0, res.descLen); @@ -1353,7 +1346,7 @@ public class Remote : IDisposable /// FireWire model string /// FireWire GUID /// true if the device is attached via FireWire, false otherwise - public bool GetFireWireData(out uint idVendor, out uint idProduct, out ulong guid, out string vendor, + public bool GetFireWireData(out uint idVendor, out uint idProduct, out ulong guid, out string vendor, out string model) { idVendor = 0; @@ -1380,7 +1373,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return false; } @@ -1391,24 +1384,23 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return false; } if(hdr.packetType != AaruPacketType.ResponseGetFireWireData) { - AaruConsole.ErrorWriteLine("Expected FireWire Data Response Packet, got packet type {0}...", + AaruConsole.ErrorWriteLine(Localization.Expected_FireWire_Data_Response_Packet_got_packet_type_0, hdr.packetType); return false; @@ -1419,15 +1411,14 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } AaruPacketResGetFireWireData res = Marshal.ByteArrayToStructureLittleEndian(buf); - if(!res.isFireWire) - return false; + if(!res.isFireWire) return false; idVendor = res.idVendor; idProduct = res.idModel; @@ -1463,7 +1454,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return false; } @@ -1474,24 +1465,24 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return false; } if(hdr.packetType != AaruPacketType.ResponseGetPcmciaData) { - AaruConsole.ErrorWriteLine("Expected PCMCIA Data Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_PCMCIA_Data_Response_Packet_got_packet_type_0, + hdr.packetType); return false; } @@ -1501,15 +1492,14 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } AaruPacketResGetPcmciaData res = Marshal.ByteArrayToStructureLittleEndian(buf); - if(!res.isPcmcia) - return false; + if(!res.isPcmcia) return false; cis = res.cis; @@ -1530,8 +1520,7 @@ public class Remote : IDisposable { int got = socket.Receive(buffer, offset, size, socketFlags); - if(got <= 0) - break; + if(got <= 0) break; offset += got; size -= got; @@ -1576,11 +1565,10 @@ public class Remote : IDisposable /// Set to true if any of the commands returned an error status, false otherwise /// Maximum allowed time to execute a single command /// 0 if no error occurred, otherwise, errno - public int SendMultipleMmcCommands(Device.MmcSingleCommand[] commands, out double duration, out bool sense, - uint timeout = 0) + public int SendMultipleMmcCommands(Devices.Device.MmcSingleCommand[] commands, out double duration, out bool sense, + uint timeout = 0) { - if(ServerProtocolVersion < 2) - return SendMultipleMmcCommandsV1(commands, out duration, out sense, timeout); + if(ServerProtocolVersion < 2) return SendMultipleMmcCommandsV1(commands, out duration, out sense, timeout); sense = false; duration = 0; @@ -1588,8 +1576,7 @@ public class Remote : IDisposable long packetSize = Marshal.SizeOf() + Marshal.SizeOf() * commands.LongLength; - foreach(Device.MmcSingleCommand command in commands) - packetSize += command.buffer?.Length ?? 0; + packetSize = commands.Aggregate(packetSize, (current, command) => current + (command.buffer?.Length ?? 0)); var packet = new AaruPacketMultiCmdSdhci { @@ -1630,7 +1617,8 @@ public class Remote : IDisposable off += tmp.Length; } - foreach(Device.MmcSingleCommand command in commands.Where(command => (command.buffer?.Length ?? 0) != 0)) + foreach(Devices.Device.MmcSingleCommand command in + commands.Where(command => (command.buffer?.Length ?? 0) != 0)) { Array.Copy(command.buffer, 0, buf, off, command.buffer.Length); @@ -1641,7 +1629,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return -1; } @@ -1652,24 +1640,23 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return -1; } if(hdr.packetType != AaruPacketType.ResponseMultiSdhci) { - AaruConsole.ErrorWriteLine("Expected multi MMC/SD command Response Packet, got packet type {0}...", + AaruConsole.ErrorWriteLine(Localization.Expected_multi_MMC_SD_command_Response_Packet_got_packet_type_0, hdr.packetType); return -1; @@ -1680,7 +1667,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return -1; } @@ -1689,8 +1676,9 @@ public class Remote : IDisposable if(res.cmd_count != (ulong)commands.Length) { - AaruConsole.ErrorWriteLine("Expected the response to {0} SD/MMC commands, but got {1} responses...", - commands.Length, res.cmd_count); + AaruConsole.ErrorWriteLine(Localization.Expected_the_response_to_0_SD_MMC_commands_but_got_1_responses, + commands.Length, + res.cmd_count); return -1; } @@ -1699,7 +1687,7 @@ public class Remote : IDisposable var error = 0; - foreach(Device.MmcSingleCommand command in commands) + foreach(Devices.Device.MmcSingleCommand command in commands) { AaruResSdhci cmdRes = Marshal.ByteArrayToStructureLittleEndian(buf, off, Marshal.SizeOf()); @@ -1707,20 +1695,16 @@ public class Remote : IDisposable command.response = cmdRes.response; duration += cmdRes.duration; - if(cmdRes.error_no != 0 && - error == 0) - error = (int)cmdRes.error_no; + if(cmdRes.error_no != 0 && error == 0) error = (int)cmdRes.error_no; - if(cmdRes.sense != 0) - sense = true; + if(cmdRes.sense != 0) sense = true; - if(cmdRes.buf_len > 0) - command.buffer = new byte[cmdRes.buf_len]; + if(cmdRes.buf_len > 0) command.buffer = new byte[cmdRes.buf_len]; off += Marshal.SizeOf(); } - foreach(Device.MmcSingleCommand command in commands) + foreach(Devices.Device.MmcSingleCommand command in commands) { Array.Copy(buf, off, command.buffer, 0, command.buffer.Length); off += command.buffer.Length; @@ -1738,20 +1722,29 @@ public class Remote : IDisposable /// Set to true if any of the commands returned an error status, false otherwise /// Maximum allowed time to execute a single command /// 0 if no error occurred, otherwise, errno - int SendMultipleMmcCommandsV1(Device.MmcSingleCommand[] commands, out double duration, out bool sense, uint timeout) + int SendMultipleMmcCommandsV1(Devices.Device.MmcSingleCommand[] commands, out double duration, out bool sense, + uint timeout) { sense = false; duration = 0; var error = 0; - foreach(Device.MmcSingleCommand command in commands) + foreach(Devices.Device.MmcSingleCommand command in commands) { - error = SendMmcCommand(command.command, command.write, command.isApplication, command.flags, - command.argument, command.blockSize, command.blocks, ref command.buffer, - out command.response, out double cmdDuration, out bool cmdSense, timeout); + error = SendMmcCommand(command.command, + command.write, + command.isApplication, + command.flags, + command.argument, + command.blockSize, + command.blocks, + ref command.buffer, + out command.response, + out double cmdDuration, + out bool cmdSense, + timeout); - if(cmdSense) - sense = true; + if(cmdSense) sense = true; duration += cmdDuration; } @@ -1763,8 +1756,7 @@ public class Remote : IDisposable /// Returned error number if any public bool ReOpen() { - if(ServerProtocolVersion < 2) - return false; + if(ServerProtocolVersion < 2) return false; var cmdPkt = new AaruPacketCmdReOpen { @@ -1784,7 +1776,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return false; } @@ -1795,31 +1787,30 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return false; } if(hdr.packetType != AaruPacketType.Nop) { - AaruConsole.ErrorWriteLine("Expected NOP Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_NOP_Packet_got_packet_type_0, hdr.packetType); return false; } if(hdr.version != Consts.PACKET_VERSION) { - AaruConsole.ErrorWriteLine("Unrecognized packet version..."); + AaruConsole.ErrorWriteLine(Localization.Unrecognized_packet_version); return false; } @@ -1829,7 +1820,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } @@ -1838,14 +1829,15 @@ public class Remote : IDisposable switch(nop.reasonCode) { - case AaruNopReason.ReOpenOk: return true; + case AaruNopReason.ReOpenOk: + return true; case AaruNopReason.CloseError: case AaruNopReason.OpenError: - AaruConsole.ErrorWriteLine("ReOpen error closing device..."); + AaruConsole.ErrorWriteLine(Localization.ReOpen_error_closing_device); break; default: - AaruConsole.ErrorWriteLine("ReOpen error {0} with reason: {1}...", nop.errno, nop.reason); + AaruConsole.ErrorWriteLine(Localization.ReOpen_error_0_with_reason_1, nop.errno, nop.reason); break; } @@ -1864,8 +1856,7 @@ public class Remote : IDisposable duration = 0; buffer = null; - if(ServerProtocolVersion < 2) - return false; + if(ServerProtocolVersion < 2) return false; var cmdPkt = new AaruPacketCmdOsRead { @@ -1887,7 +1878,7 @@ public class Remote : IDisposable if(len != buf.Length) { - AaruConsole.ErrorWriteLine("Could not write to the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_write_to_the_network); return false; } @@ -1898,31 +1889,30 @@ public class Remote : IDisposable if(len < hdrBuf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); - if(hdr.remote_id != Consts.REMOTE_ID || - hdr.packet_id != Consts.PACKET_ID) + if(hdr.remote_id != Consts.REMOTE_ID || hdr.packet_id != Consts.PACKET_ID) { - AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); + AaruConsole.ErrorWriteLine(Localization.Received_data_is_not_an_Aaru_Remote_Packet); return false; } if(hdr.packetType != AaruPacketType.ResponseOsRead) { - AaruConsole.ErrorWriteLine("Expected OS Read Response Packet, got packet type {0}...", hdr.packetType); + AaruConsole.ErrorWriteLine(Localization.Expected_OS_Read_Response_Packet_got_packet_type_0, hdr.packetType); return false; } if(hdr.version != Consts.PACKET_VERSION) { - AaruConsole.ErrorWriteLine("Unrecognized packet version..."); + AaruConsole.ErrorWriteLine(Localization.Unrecognized_packet_version); return false; } @@ -1932,7 +1922,7 @@ public class Remote : IDisposable if(len < buf.Length) { - AaruConsole.ErrorWriteLine("Could not read from the network..."); + AaruConsole.ErrorWriteLine(Localization.Could_not_read_from_the_network); return false; } @@ -1943,7 +1933,7 @@ public class Remote : IDisposable if(osRead.errno != 0) { - AaruConsole.ErrorWriteLine("Remote error {0} in OS Read...", osRead.errno); + AaruConsole.ErrorWriteLine(Localization.Remote_error_0_in_OS_Read, osRead.errno); return false; } diff --git a/Aaru.Devices/Remote/Structs.cs b/Aaru.Devices/Remote/Structs.cs index 4a855c0fa..f7b51667e 100644 --- a/Aaru.Devices/Remote/Structs.cs +++ b/Aaru.Devices/Remote/Structs.cs @@ -27,22 +27,20 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable MemberCanBeInternal // ReSharper disable MemberCanBePrivate.Global // ReSharper disable FieldCanBeMadeReadOnly.Global // ReSharper disable IdentifierTypo -namespace Aaru.Devices.Remote; - using System.Runtime.InteropServices; using Aaru.CommonTypes.Enums; using Aaru.Decoders.ATA; +namespace Aaru.Devices.Remote; + /// Header for any Aaru remote packet [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] public struct AaruPacketHeader diff --git a/Aaru.Devices/Windows/Command.cs b/Aaru.Devices/Windows/Command.cs index 1f1896e4c..8105ac88b 100644 --- a/Aaru.Devices/Windows/Command.cs +++ b/Aaru.Devices/Windows/Command.cs @@ -28,52 +28,40 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Windows; - using System; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Aaru.Decoders.ATA; using Microsoft.Win32.SafeHandles; +namespace Aaru.Devices.Windows; + [SuppressMessage("ReSharper", "UnusedParameter.Global")] partial class Device { /// - public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, + public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, ScsiDirection direction, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; senseBuffer = null; duration = 0; sense = false; - if(buffer == null) - return -1; + if(buffer == null) return -1; - ScsiIoctlDirection dir; - - switch(direction) - { - case ScsiDirection.In: - dir = ScsiIoctlDirection.In; - - break; - case ScsiDirection.Out: - dir = ScsiIoctlDirection.Out; - - break; - default: - dir = ScsiIoctlDirection.Unspecified; - - break; - } + ScsiIoctlDirection dir = direction switch + { + ScsiDirection.In => ScsiIoctlDirection.In, + ScsiDirection.Out => ScsiIoctlDirection.Out, + _ => ScsiIoctlDirection.Unspecified + }; var sptdSb = new ScsiPassThroughDirectAndSenseBuffer { @@ -99,16 +87,21 @@ partial class Device Marshal.Copy(buffer, 0, sptdSb.sptd.DataBuffer, buffer.Length); - DateTime start = DateTime.Now; + var cmdStopwatch = new Stopwatch(); + cmdStopwatch.Start(); - bool hasError = !Extern.DeviceIoControlScsi(_fileHandle, WindowsIoctl.IoctlScsiPassThroughDirect, ref sptdSb, - (uint)Marshal.SizeOf(sptdSb), ref sptdSb, - (uint)Marshal.SizeOf(sptdSb), ref k, IntPtr.Zero); + bool hasError = !Extern.DeviceIoControlScsi(_fileHandle, + WindowsIoctl.IoctlScsiPassThroughDirect, + ref sptdSb, + (uint)Marshal.SizeOf(sptdSb), + ref sptdSb, + (uint)Marshal.SizeOf(sptdSb), + ref k, + IntPtr.Zero); - DateTime end = DateTime.Now; + cmdStopwatch.Stop(); - if(hasError) - error = Marshal.GetLastWin32Error(); + if(hasError) error = Marshal.GetLastWin32Error(); Marshal.Copy(sptdSb.sptd.DataBuffer, buffer, 0, buffer.Length); @@ -117,7 +110,7 @@ partial class Device senseBuffer = new byte[64]; Array.Copy(sptdSb.SenseBuf, senseBuffer, 32); - duration = (end - start).TotalMilliseconds; + duration = cmdStopwatch.Elapsed.TotalMilliseconds; Marshal.FreeHGlobal(sptdSb.sptd.DataBuffer); @@ -130,15 +123,13 @@ partial class Device uint timeout, bool transferBlocks, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; duration = 0; sense = false; errorRegisters = new AtaErrorRegistersChs(); - if(buffer == null) - return -1; + if(buffer == null) return -1; var aptd = new AtaPassThroughDirect { @@ -159,20 +150,12 @@ partial class Device } }; - switch(protocol) - { - case AtaProtocol.PioIn: - case AtaProtocol.UDmaIn: - case AtaProtocol.Dma: - aptd.AtaFlags = AtaFlags.DataIn; - - break; - case AtaProtocol.PioOut: - case AtaProtocol.UDmaOut: - aptd.AtaFlags = AtaFlags.DataOut; - - break; - } + aptd.AtaFlags = protocol switch + { + AtaProtocol.PioIn or AtaProtocol.UDmaIn or AtaProtocol.Dma => AtaFlags.DataIn, + AtaProtocol.PioOut or AtaProtocol.UDmaOut => AtaFlags.DataOut, + _ => aptd.AtaFlags + }; switch(protocol) { @@ -194,20 +177,25 @@ partial class Device Marshal.Copy(buffer, 0, aptd.DataBuffer, buffer.Length); - DateTime start = DateTime.Now; + var cmdStopwatch = new Stopwatch(); + cmdStopwatch.Start(); - sense = !Extern.DeviceIoControlAta(_fileHandle, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd, - (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k, + sense = !Extern.DeviceIoControlAta(_fileHandle, + WindowsIoctl.IoctlAtaPassThroughDirect, + ref aptd, + (uint)Marshal.SizeOf(aptd), + ref aptd, + (uint)Marshal.SizeOf(aptd), + ref k, IntPtr.Zero); - DateTime end = DateTime.Now; + cmdStopwatch.Stop(); - if(sense) - error = Marshal.GetLastWin32Error(); + if(sense) error = Marshal.GetLastWin32Error(); Marshal.Copy(aptd.DataBuffer, buffer, 0, buffer.Length); - duration = (end - start).TotalMilliseconds; + duration = cmdStopwatch.Elapsed.TotalMilliseconds; errorRegisters.CylinderHigh = aptd.CurrentTaskFile.CylinderHigh; errorRegisters.CylinderLow = aptd.CurrentTaskFile.CylinderLow; @@ -230,15 +218,13 @@ partial class Device uint timeout, bool transferBlocks, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba28(); - if(buffer == null) - return -1; + if(buffer == null) return -1; var aptd = new AtaPassThroughDirect { @@ -259,20 +245,12 @@ partial class Device } }; - switch(protocol) - { - case AtaProtocol.PioIn: - case AtaProtocol.UDmaIn: - case AtaProtocol.Dma: - aptd.AtaFlags = AtaFlags.DataIn; - - break; - case AtaProtocol.PioOut: - case AtaProtocol.UDmaOut: - aptd.AtaFlags = AtaFlags.DataOut; - - break; - } + aptd.AtaFlags = protocol switch + { + AtaProtocol.PioIn or AtaProtocol.UDmaIn or AtaProtocol.Dma => AtaFlags.DataIn, + AtaProtocol.PioOut or AtaProtocol.UDmaOut => AtaFlags.DataOut, + _ => aptd.AtaFlags + }; switch(protocol) { @@ -294,20 +272,25 @@ partial class Device Marshal.Copy(buffer, 0, aptd.DataBuffer, buffer.Length); - DateTime start = DateTime.Now; + var cmdStopwatch = new Stopwatch(); + cmdStopwatch.Start(); - sense = !Extern.DeviceIoControlAta(_fileHandle, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd, - (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k, + sense = !Extern.DeviceIoControlAta(_fileHandle, + WindowsIoctl.IoctlAtaPassThroughDirect, + ref aptd, + (uint)Marshal.SizeOf(aptd), + ref aptd, + (uint)Marshal.SizeOf(aptd), + ref k, IntPtr.Zero); - DateTime end = DateTime.Now; + cmdStopwatch.Stop(); - if(sense) - error = Marshal.GetLastWin32Error(); + if(sense) error = Marshal.GetLastWin32Error(); Marshal.Copy(aptd.DataBuffer, buffer, 0, buffer.Length); - duration = (end - start).TotalMilliseconds; + duration = cmdStopwatch.Elapsed.TotalMilliseconds; errorRegisters.LbaHigh = aptd.CurrentTaskFile.CylinderHigh; errorRegisters.LbaMid = aptd.CurrentTaskFile.CylinderLow; @@ -330,15 +313,13 @@ partial class Device uint timeout, bool transferBlocks, out double duration, out bool sense) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba48(); - if(buffer == null) - return -1; + if(buffer == null) return -1; var aptd = new AtaPassThroughDirect { @@ -366,20 +347,12 @@ partial class Device } }; - switch(protocol) - { - case AtaProtocol.PioIn: - case AtaProtocol.UDmaIn: - case AtaProtocol.Dma: - aptd.AtaFlags = AtaFlags.DataIn; - - break; - case AtaProtocol.PioOut: - case AtaProtocol.UDmaOut: - aptd.AtaFlags = AtaFlags.DataOut; - - break; - } + aptd.AtaFlags = protocol switch + { + AtaProtocol.PioIn or AtaProtocol.UDmaIn or AtaProtocol.Dma => AtaFlags.DataIn, + AtaProtocol.PioOut or AtaProtocol.UDmaOut => AtaFlags.DataOut, + _ => aptd.AtaFlags + }; switch(protocol) { @@ -403,20 +376,25 @@ partial class Device Marshal.Copy(buffer, 0, aptd.DataBuffer, buffer.Length); - DateTime start = DateTime.Now; + var cmdStopwatch = new Stopwatch(); + cmdStopwatch.Start(); - sense = !Extern.DeviceIoControlAta(_fileHandle, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd, - (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k, + sense = !Extern.DeviceIoControlAta(_fileHandle, + WindowsIoctl.IoctlAtaPassThroughDirect, + ref aptd, + (uint)Marshal.SizeOf(aptd), + ref aptd, + (uint)Marshal.SizeOf(aptd), + ref k, IntPtr.Zero); - DateTime end = DateTime.Now; + cmdStopwatch.Stop(); - if(sense) - error = Marshal.GetLastWin32Error(); + if(sense) error = Marshal.GetLastWin32Error(); Marshal.Copy(aptd.DataBuffer, buffer, 0, buffer.Length); - duration = (end - start).TotalMilliseconds; + duration = cmdStopwatch.Elapsed.TotalMilliseconds; errorRegisters.SectorCount = (ushort)((aptd.PreviousTaskFile.SectorCount << 8) + aptd.CurrentTaskFile.SectorCount); @@ -446,69 +424,74 @@ partial class Device var queryData1 = new SffdiskQueryDeviceProtocolData(); queryData1.size = (ushort)Marshal.SizeOf(queryData1); - Extern.DeviceIoControl(fd, WindowsIoctl.IoctlSffdiskQueryDeviceProtocol, IntPtr.Zero, 0, ref queryData1, - queryData1.size, out _, IntPtr.Zero); + Extern.DeviceIoControl(fd, + WindowsIoctl.IoctlSffdiskQueryDeviceProtocol, + IntPtr.Zero, + 0, + ref queryData1, + queryData1.size, + out _, + IntPtr.Zero); return queryData1.protocolGuid.Equals(Consts.GuidSffProtocolSd) || queryData1.protocolGuid.Equals(Consts.GuidSffProtocolMmc); } /// - public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, - uint argument, uint blockSize, uint blocks, ref byte[] buffer, - out uint[] response, out double duration, out bool sense, uint timeout = 15) + public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, + uint argument, uint blockSize, uint blocks, ref byte[] buffer, + out uint[] response, out double duration, out bool sense, uint timeout = 15) { - DateTime start; - DateTime end; + var cmdStopwatch = new Stopwatch(); switch(command) { - case MmcCommands.SendCid when _cachedCid != null: + case MmcCommands.SendCid when CachedCid != null: { - start = DateTime.Now; - buffer = new byte[_cachedCid.Length]; - Array.Copy(_cachedCid, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedCid.Length]; + Array.Copy(CachedCid, buffer, buffer.Length); response = new uint[4]; sense = false; - end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } - case MmcCommands.SendCsd when _cachedCid != null: + case MmcCommands.SendCsd when CachedCid != null: { - start = DateTime.Now; - buffer = new byte[_cachedCsd.Length]; - Array.Copy(_cachedCsd, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedCsd.Length]; + Array.Copy(CachedCsd, buffer, buffer.Length); response = new uint[4]; sense = false; - end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } - case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null: + case (MmcCommands)SecureDigitalCommands.SendScr when CachedScr != null: { - start = DateTime.Now; - buffer = new byte[_cachedScr.Length]; - Array.Copy(_cachedScr, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedScr.Length]; + Array.Copy(CachedScr, buffer, buffer.Length); response = new uint[4]; sense = false; - end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } - case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null: - case MmcCommands.SendOpCond when _cachedOcr != null: + case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when CachedOcr != null: + case MmcCommands.SendOpCond when CachedOcr != null: { - start = DateTime.Now; - buffer = new byte[_cachedOcr.Length]; - Array.Copy(_cachedOcr, buffer, buffer.Length); + cmdStopwatch.Restart(); + buffer = new byte[CachedOcr.Length]; + Array.Copy(CachedOcr, buffer, buffer.Length); response = new uint[4]; sense = false; - end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return 0; } @@ -524,39 +507,33 @@ partial class Device commandDescriptor.cmdClass = isApplication ? SdCommandClass.AppCmd : SdCommandClass.Standard; commandDescriptor.transferDirection = write ? SdTransferDirection.Write : SdTransferDirection.Read; - commandDescriptor.transferType = flags.HasFlag(MmcFlags.CommandAdtc) ? command == MmcCommands.ReadMultipleBlock - ? SdTransferType.MultiBlock - : SdTransferType.SingleBlock + commandDescriptor.transferType = flags.HasFlag(MmcFlags.CommandAdtc) + ? command == MmcCommands.ReadMultipleBlock + ? SdTransferType.MultiBlock + : SdTransferType.SingleBlock : SdTransferType.CmdOnly; commandDescriptor.responseType = 0; - if(flags.HasFlag(MmcFlags.ResponseR1) || - flags.HasFlag(MmcFlags.ResponseSpiR1)) + if(flags.HasFlag(MmcFlags.ResponseR1) || flags.HasFlag(MmcFlags.ResponseSpiR1)) commandDescriptor.responseType = SdResponseType.R1; - if(flags.HasFlag(MmcFlags.ResponseR1B) || - flags.HasFlag(MmcFlags.ResponseSpiR1B)) + if(flags.HasFlag(MmcFlags.ResponseR1B) || flags.HasFlag(MmcFlags.ResponseSpiR1B)) commandDescriptor.responseType = SdResponseType.R1b; - if(flags.HasFlag(MmcFlags.ResponseR2) || - flags.HasFlag(MmcFlags.ResponseSpiR2)) + if(flags.HasFlag(MmcFlags.ResponseR2) || flags.HasFlag(MmcFlags.ResponseSpiR2)) commandDescriptor.responseType = SdResponseType.R2; - if(flags.HasFlag(MmcFlags.ResponseR3) || - flags.HasFlag(MmcFlags.ResponseSpiR3)) + if(flags.HasFlag(MmcFlags.ResponseR3) || flags.HasFlag(MmcFlags.ResponseSpiR3)) commandDescriptor.responseType = SdResponseType.R3; - if(flags.HasFlag(MmcFlags.ResponseR4) || - flags.HasFlag(MmcFlags.ResponseSpiR4)) + if(flags.HasFlag(MmcFlags.ResponseR4) || flags.HasFlag(MmcFlags.ResponseSpiR4)) commandDescriptor.responseType = SdResponseType.R4; - if(flags.HasFlag(MmcFlags.ResponseR5) || - flags.HasFlag(MmcFlags.ResponseSpiR5)) + if(flags.HasFlag(MmcFlags.ResponseR5) || flags.HasFlag(MmcFlags.ResponseSpiR5)) commandDescriptor.responseType = SdResponseType.R5; - if(flags.HasFlag(MmcFlags.ResponseR6)) - commandDescriptor.responseType = SdResponseType.R6; + if(flags.HasFlag(MmcFlags.ResponseR6)) commandDescriptor.responseType = SdResponseType.R6; var commandB = new byte[commandData.size + commandData.protocolArgumentSize + commandData.deviceDataBufferSize]; @@ -569,32 +546,36 @@ partial class Device Marshal.FreeHGlobal(hBuf); var error = 0; - start = DateTime.Now; + cmdStopwatch.Restart(); - sense = !Extern.DeviceIoControl(_fileHandle, WindowsIoctl.IoctlSffdiskDeviceCommand, commandB, - (uint)commandB.Length, commandB, (uint)commandB.Length, out _, IntPtr.Zero); + sense = !Extern.DeviceIoControl(_fileHandle, + WindowsIoctl.IoctlSffdiskDeviceCommand, + commandB, + (uint)commandB.Length, + commandB, + (uint)commandB.Length, + out _, + IntPtr.Zero); - end = DateTime.Now; + cmdStopwatch.Stop(); - if(sense) - error = Marshal.GetLastWin32Error(); + if(sense) error = Marshal.GetLastWin32Error(); buffer = new byte[blockSize * blocks]; Buffer.BlockCopy(commandB, commandB.Length - buffer.Length, buffer, 0, buffer.Length); response = new uint[4]; - duration = (end - start).TotalMilliseconds; + duration = cmdStopwatch.Elapsed.TotalMilliseconds; return error; } /// public override int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense, - uint timeout = 15) + uint timeout = 15) { // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; var error = 0; duration = 0; @@ -604,24 +585,41 @@ partial class Device commands[0].command == MmcCommands.SetBlocklen && commands[1].command == MmcCommands.ReadMultipleBlock && commands[2].command == MmcCommands.StopTransmission) - return SendMmcCommand(commands[1].command, commands[1].write, commands[1].isApplication, commands[1].flags, - commands[1].argument, commands[1].blockSize, commands[1].blocks, - ref commands[1].buffer, out commands[1].response, out duration, out sense, timeout); + { + return SendMmcCommand(commands[1].command, + commands[1].write, + commands[1].isApplication, + commands[1].flags, + commands[1].argument, + commands[1].blockSize, + commands[1].blocks, + ref commands[1].buffer, + out commands[1].response, + out duration, + out sense, + timeout); + } foreach(MmcSingleCommand command in commands) { - int singleError = SendMmcCommand(command.command, command.write, command.isApplication, command.flags, - command.argument, command.blockSize, command.blocks, ref command.buffer, - out command.response, out double cmdDuration, out bool cmdSense, timeout); + int singleError = SendMmcCommand(command.command, + command.write, + command.isApplication, + command.flags, + command.argument, + command.blockSize, + command.blocks, + ref command.buffer, + out command.response, + out double cmdDuration, + out bool cmdSense, + timeout); - if(error == 0 && - singleError != 0) - error = singleError; + if(error == 0 && singleError != 0) error = singleError; duration += cmdDuration; - if(cmdSense) - sense = true; + if(cmdSense) sense = true; } return error; @@ -632,9 +630,13 @@ partial class Device { Extern.CloseHandle(_fileHandle); - SafeFileHandle newFd = Extern.CreateFile(_devicePath, FileAccess.GenericRead | FileAccess.GenericWrite, - FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting, - FileAttributes.Normal, IntPtr.Zero); + SafeFileHandle newFd = Extern.CreateFile(DevicePath, + FileAccess.GenericRead | FileAccess.GenericWrite, + FileShare.Read | FileShare.Write, + IntPtr.Zero, + FileMode.OpenExisting, + FileAttributes.Normal, + IntPtr.Zero); if(newFd.IsInvalid) { @@ -654,15 +656,17 @@ partial class Device { buffer = new byte[length]; - DateTime start = DateTime.Now; + var cmdStopwatch = new Stopwatch(); + cmdStopwatch.Start(); bool sense = !Extern.SetFilePointerEx(_fileHandle, offset, out _, MoveMethod.Begin); - DateTime end = DateTime.Now; + cmdStopwatch.Stop(); if(sense) { - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; LastError = Marshal.GetLastWin32Error(); Error = true; @@ -672,8 +676,8 @@ partial class Device sense = !Extern.ReadFile(_fileHandle, buffer, length, out _, IntPtr.Zero); - end = DateTime.Now; - duration = (end - start).TotalMilliseconds; + cmdStopwatch.Stop(); + duration = cmdStopwatch.Elapsed.TotalMilliseconds; if(sense) { diff --git a/Aaru.Devices/Windows/Device.cs b/Aaru.Devices/Windows/Device.cs index d611c4ede..caa94c97f 100644 --- a/Aaru.Devices/Windows/Device.cs +++ b/Aaru.Devices/Windows/Device.cs @@ -27,11 +27,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Windows; - using System; using System.Runtime.InteropServices; using System.Runtime.Versioning; @@ -41,6 +39,8 @@ using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.SecureDigital; using Microsoft.Win32.SafeHandles; +namespace Aaru.Devices.Windows; + /// [SupportedOSPlatform("windows")] partial class Device : Devices.Device @@ -57,13 +57,17 @@ partial class Device : Devices.Device var dev = new Device { - PlatformId = DetectOS.GetRealPlatformID(), - Timeout = 15, - Error = false, + PlatformId = DetectOS.GetRealPlatformID(), + Timeout = 15, + Error = false, IsRemovable = false, - _fileHandle = Extern.CreateFile(devicePath, FileAccess.GenericRead | FileAccess.GenericWrite, - FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting, - FileAttributes.Normal, IntPtr.Zero) + _fileHandle = Extern.CreateFile(devicePath, + FileAccess.GenericRead | FileAccess.GenericWrite, + FileShare.Read | FileShare.Write, + IntPtr.Zero, + FileMode.OpenExisting, + FileAttributes.Normal, + IntPtr.Zero) }; if(dev._fileHandle.IsInvalid) @@ -90,10 +94,12 @@ partial class Device : Devices.Device } // Windows is answering SCSI INQUIRY for all device types so it needs to be detected first - var query = new StoragePropertyQuery(); - query.PropertyId = StoragePropertyId.Device; - query.QueryType = StorageQueryType.Standard; - query.AdditionalParameters = new byte[1]; + var query = new StoragePropertyQuery + { + PropertyId = StoragePropertyId.Device, + QueryType = StorageQueryType.Standard, + AdditionalParameters = new byte[1] + }; IntPtr descriptorPtr = Marshal.AllocHGlobal(1000); var descriptorB = new byte[1000]; @@ -101,17 +107,20 @@ partial class Device : Devices.Device uint returned = 0; var error = 0; - bool hasError = !Extern.DeviceIoControlStorageQuery(dev._fileHandle, WindowsIoctl.IoctlStorageQueryProperty, - ref query, (uint)Marshal.SizeOf(query), descriptorPtr, 1000, - ref returned, IntPtr.Zero); + bool hasError = !Extern.DeviceIoControlStorageQuery(dev._fileHandle, + WindowsIoctl.IoctlStorageQueryProperty, + ref query, + (uint)Marshal.SizeOf(query), + descriptorPtr, + 1000, + ref returned, + IntPtr.Zero); - if(hasError) - error = Marshal.GetLastWin32Error(); + if(hasError) error = Marshal.GetLastWin32Error(); Marshal.Copy(descriptorPtr, descriptorB, 0, 1000); - if(!hasError && - error == 0) + if(!hasError && error == 0) { var descriptor = new StorageDeviceDescriptor { @@ -196,64 +205,99 @@ partial class Device : Devices.Device { var sdBuffer = new byte[16]; - dev.LastError = dev.SendMmcCommand(MmcCommands.SendCsd, false, false, - MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16, - 1, ref sdBuffer, out _, out _, out bool sense); + dev.LastError = dev.SendMmcCommand(MmcCommands.SendCsd, + false, + false, + MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, + 0, + 16, + 1, + ref sdBuffer, + out _, + out _, + out bool sense); if(!sense) { - dev._cachedCsd = new byte[16]; - Array.Copy(sdBuffer, 0, dev._cachedCsd, 0, 16); + dev.CachedCsd = new byte[16]; + Array.Copy(sdBuffer, 0, dev.CachedCsd, 0, 16); } sdBuffer = new byte[16]; - dev.LastError = dev.SendMmcCommand(MmcCommands.SendCid, false, false, - MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16, - 1, ref sdBuffer, out _, out _, out sense); + dev.LastError = dev.SendMmcCommand(MmcCommands.SendCid, + false, + false, + MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, + 0, + 16, + 1, + ref sdBuffer, + out _, + out _, + out sense); if(!sense) { - dev._cachedCid = new byte[16]; - Array.Copy(sdBuffer, 0, dev._cachedCid, 0, 16); + dev.CachedCid = new byte[16]; + Array.Copy(sdBuffer, 0, dev.CachedCid, 0, 16); } sdBuffer = new byte[8]; - dev.LastError = dev.SendMmcCommand((MmcCommands)SecureDigitalCommands.SendScr, false, true, - MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, 0, - 8, 1, ref sdBuffer, out _, out _, out sense); + dev.LastError = dev.SendMmcCommand((MmcCommands)SecureDigitalCommands.SendScr, + false, + true, + MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, + 0, + 8, + 1, + ref sdBuffer, + out _, + out _, + out sense); if(!sense) { - dev._cachedScr = new byte[8]; - Array.Copy(sdBuffer, 0, dev._cachedScr, 0, 8); + dev.CachedScr = new byte[8]; + Array.Copy(sdBuffer, 0, dev.CachedScr, 0, 8); } sdBuffer = new byte[4]; dev.LastError = - dev.SendMmcCommand(dev._cachedScr != null ? (MmcCommands)SecureDigitalCommands.SendOperatingCondition : MmcCommands.SendOpCond, - false, true, MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, 0, - 4, 1, ref sdBuffer, out _, out _, out sense); + dev.SendMmcCommand(dev.CachedScr != null + ? (MmcCommands)SecureDigitalCommands.SendOperatingCondition + : MmcCommands.SendOpCond, + false, + true, + MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, + 0, + 4, + 1, + ref sdBuffer, + out _, + out _, + out sense); if(!sense) { - dev._cachedScr = new byte[4]; - Array.Copy(sdBuffer, 0, dev._cachedScr, 0, 4); + dev.CachedScr = new byte[4]; + Array.Copy(sdBuffer, 0, dev.CachedScr, 0, 4); } } - #region SecureDigital / MultiMediaCard - if(dev._cachedCid != null) +#region SecureDigital / MultiMediaCard + + if(dev.CachedCid != null) { dev.ScsiType = PeripheralDeviceTypes.DirectAccess; dev.IsRemovable = false; - if(dev._cachedScr != null) + if(dev.CachedScr != null) { dev.Type = DeviceType.SecureDigital; - CID decoded = Decoders.DecodeCID(dev._cachedCid); + CID decoded = Decoders.SecureDigital.Decoders.DecodeCID(dev.CachedCid); dev.Manufacturer = VendorString.Prettify(decoded.Manufacturer); dev.Model = decoded.ProductName; @@ -265,8 +309,8 @@ partial class Device : Devices.Device else { dev.Type = DeviceType.MMC; - Aaru.Decoders.MMC.CID decoded = Aaru.Decoders.MMC.Decoders.DecodeCID(dev._cachedCid); - dev.Manufacturer = Aaru.Decoders.MMC.VendorString.Prettify(decoded.Manufacturer); + Decoders.MMC.CID decoded = Decoders.MMC.Decoders.DecodeCID(dev.CachedCid); + dev.Manufacturer = Decoders.MMC.VendorString.Prettify(decoded.Manufacturer); dev.Model = decoded.ProductName; dev.FirmwareRevision = @@ -277,9 +321,11 @@ partial class Device : Devices.Device return dev; } - #endregion SecureDigital / MultiMediaCard - #region USB +#endregion SecureDigital / MultiMediaCard + +#region USB + Usb.UsbDevice usbDevice = null; // I have to search for USB disks, floppies and CD-ROMs as separate device types @@ -291,32 +337,36 @@ partial class Device : Devices.Device { usbDevice = Usb.FindDrivePath(devicePath, devGuid); - if(usbDevice != null) - break; + if(usbDevice != null) break; } if(usbDevice != null) { dev.UsbDescriptors = usbDevice.BinaryDescriptors; - dev._usbVendor = (ushort)usbDevice._deviceDescriptor.idVendor; - dev._usbProduct = (ushort)usbDevice._deviceDescriptor.idProduct; + dev.UsbVendor = (ushort)usbDevice.DeviceDescriptor.idVendor; + dev.UsbProduct = (ushort)usbDevice.DeviceDescriptor.idProduct; dev.UsbManufacturerString = usbDevice.Manufacturer; dev.UsbProductString = usbDevice.Product; dev.UsbSerialString = usbDevice.SerialNumber; // This is incorrect filled by Windows with SCSI/ATA serial number } - #endregion USB - #region FireWire +#endregion USB + +#region FireWire + // TODO: Implement dev.IsFireWire = false; - #endregion FireWire - #region PCMCIA +#endregion FireWire + +#region PCMCIA + // TODO: Implement - #endregion PCMCIA + +#endregion PCMCIA return dev; } @@ -324,8 +374,7 @@ partial class Device : Devices.Device /// public override void Close() { - if(_fileHandle == null) - return; + if(_fileHandle == null) return; _fileHandle?.Close(); diff --git a/Aaru.Devices/Windows/Enums.cs b/Aaru.Devices/Windows/Enums.cs index afe1e79a6..07c69b956 100644 --- a/Aaru.Devices/Windows/Enums.cs +++ b/Aaru.Devices/Windows/Enums.cs @@ -28,18 +28,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable UnusedMember.Global -namespace Aaru.Devices.Windows; - using System; using System.Diagnostics.CodeAnalysis; +namespace Aaru.Devices.Windows; + [Flags] enum FileAttributes : uint { @@ -246,11 +244,12 @@ enum WindowsIoctl : uint IoctlScsiPassThroughDirect = 0x4D014, /// ScsiGetAddress - IoctlScsiGetAddress = 0x41018, IoctlStorageQueryProperty = 0x2D1400, - IoctlIdePassThrough = 0x4D028, - IoctlStorageGetDeviceNumber = 0x2D1080, - IoctlSffdiskQueryDeviceProtocol = 0x71E80, - IoctlSffdiskDeviceCommand = 0x79E84 + IoctlScsiGetAddress = 0x41018, + IoctlStorageQueryProperty = 0x2D1400, + IoctlIdePassThrough = 0x4D028, + IoctlStorageGetDeviceNumber = 0x2D1080, + IoctlSffdiskQueryDeviceProtocol = 0x71E80, + IoctlSffdiskDeviceCommand = 0x79E84 } [Flags] diff --git a/Aaru.Devices/Windows/Extern.cs b/Aaru.Devices/Windows/Extern.cs index b42de11b6..0e6913ced 100644 --- a/Aaru.Devices/Windows/Extern.cs +++ b/Aaru.Devices/Windows/Extern.cs @@ -28,94 +28,107 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Windows; - using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; -static class Extern +namespace Aaru.Devices.Windows; + +[SuppressMessage("ReSharper", "UnusedMember.Global")] +static partial class Extern { - [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - internal static extern SafeFileHandle CreateFile([MarshalAs(UnmanagedType.LPTStr)] string filename, - [MarshalAs(UnmanagedType.U4)] FileAccess access, - [MarshalAs(UnmanagedType.U4)] FileShare share, - IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero - [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, - [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes, - IntPtr templateFile); + [LibraryImport("kernel32.dll", + EntryPoint = "CreateFileW", + SetLastError = true, + StringMarshalling = StringMarshalling.Utf16)] + internal static partial SafeFileHandle CreateFile([MarshalAs(UnmanagedType.LPTStr)] string filename, + FileAccess access, FileShare share, + nint securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero + FileMode creationDisposition, FileAttributes flagsAndAttributes, + nint templateFile); [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] internal static extern bool DeviceIoControlScsi(SafeFileHandle hDevice, WindowsIoctl ioControlCode, ref ScsiPassThroughDirectAndSenseBuffer inBuffer, uint nInBufferSize, ref ScsiPassThroughDirectAndSenseBuffer outBuffer, - uint nOutBufferSize, ref uint pBytesReturned, IntPtr overlapped); + uint nOutBufferSize, ref uint pBytesReturned, nint overlapped); - [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] - internal static extern bool DeviceIoControlAta(SafeFileHandle hDevice, WindowsIoctl ioControlCode, - ref AtaPassThroughDirect inBuffer, uint nInBufferSize, - ref AtaPassThroughDirect outBuffer, uint nOutBufferSize, - ref uint pBytesReturned, IntPtr overlapped); + [LibraryImport("Kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static partial bool DeviceIoControlAta(SafeFileHandle hDevice, WindowsIoctl ioControlCode, + ref AtaPassThroughDirect inBuffer, uint nInBufferSize, + ref AtaPassThroughDirect outBuffer, uint nOutBufferSize, + ref uint pBytesReturned, nint overlapped); [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] internal static extern bool DeviceIoControlStorageQuery(SafeFileHandle hDevice, WindowsIoctl ioControlCode, ref StoragePropertyQuery inBuffer, uint nInBufferSize, - IntPtr outBuffer, uint nOutBufferSize, - ref uint pBytesReturned, IntPtr overlapped); + nint outBuffer, uint nOutBufferSize, + ref uint pBytesReturned, nint overlapped); [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] - internal static extern bool DeviceIoControlIde(SafeFileHandle hDevice, WindowsIoctl ioControlCode, - ref IdePassThroughDirect inBuffer, uint nInBufferSize, - ref IdePassThroughDirect outBuffer, uint nOutBufferSize, - ref uint pBytesReturned, IntPtr overlapped); + internal static extern bool DeviceIoControlIde(SafeFileHandle hDevice, WindowsIoctl ioControlCode, + ref IdePassThroughDirect inBuffer, uint nInBufferSize, + ref IdePassThroughDirect outBuffer, uint nOutBufferSize, + ref uint pBytesReturned, nint overlapped); - [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] - internal static extern bool DeviceIoControlGetDeviceNumber(SafeFileHandle hDevice, WindowsIoctl ioControlCode, - IntPtr inBuffer, uint nInBufferSize, - ref StorageDeviceNumber outBuffer, uint nOutBufferSize, - ref uint pBytesReturned, IntPtr overlapped); + [LibraryImport("Kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static partial bool DeviceIoControlGetDeviceNumber(SafeFileHandle hDevice, WindowsIoctl ioControlCode, + nint inBuffer, uint nInBufferSize, + ref StorageDeviceNumber outBuffer, uint nOutBufferSize, + ref uint pBytesReturned, nint overlapped); - [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] - internal static extern bool DeviceIoControl(SafeFileHandle hDevice, WindowsIoctl ioControlCode, IntPtr inBuffer, - uint nInBufferSize, ref SffdiskQueryDeviceProtocolData outBuffer, - uint nOutBufferSize, out uint pBytesReturned, IntPtr overlapped); + [LibraryImport("Kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static partial bool DeviceIoControl(SafeFileHandle hDevice, WindowsIoctl ioControlCode, nint inBuffer, + uint nInBufferSize, ref SffdiskQueryDeviceProtocolData outBuffer, + uint nOutBufferSize, out uint pBytesReturned, nint overlapped); - [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] - internal static extern bool DeviceIoControl(SafeFileHandle hDevice, WindowsIoctl ioControlCode, byte[] inBuffer, - uint nInBufferSize, byte[] outBuffer, uint nOutBufferSize, - out uint pBytesReturned, IntPtr overlapped); + [LibraryImport("Kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static partial bool DeviceIoControl(SafeFileHandle hDevice, WindowsIoctl ioControlCode, byte[] inBuffer, + uint nInBufferSize, byte[] outBuffer, uint nOutBufferSize, + out uint pBytesReturned, nint overlapped); - [DllImport("setupapi.dll", CharSet = CharSet.Auto)] - internal static extern SafeFileHandle SetupDiGetClassDevs(ref Guid classGuid, IntPtr enumerator, IntPtr hwndParent, - DeviceGetClassFlags flags); + [LibraryImport("setupapi.dll", EntryPoint = "SetupDiGetClassDevsW")] + internal static partial SafeFileHandle SetupDiGetClassDevs(ref Guid classGuid, nint enumerator, nint hwndParent, + DeviceGetClassFlags flags); - [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern bool SetupDiEnumDeviceInterfaces(SafeFileHandle hDevInfo, IntPtr devInfo, - ref Guid interfaceClassGuid, uint memberIndex, - ref DeviceInterfaceData deviceInterfaceData); + [LibraryImport("setupapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool SetupDiEnumDeviceInterfaces(SafeFileHandle hDevInfo, nint devInfo, + ref Guid interfaceClassGuid, uint memberIndex, + ref DeviceInterfaceData deviceInterfaceData); - [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern bool SetupDiGetDeviceInterfaceDetail(SafeFileHandle hDevInfo, - ref DeviceInterfaceData deviceInterfaceData, - IntPtr deviceInterfaceDetailData, - uint deviceInterfaceDetailDataSize, ref uint requiredSize, - IntPtr deviceInfoData); + [LibraryImport("setupapi.dll", EntryPoint = "SetupDiGetDeviceInterfaceDetailW", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool SetupDiGetDeviceInterfaceDetail(SafeFileHandle hDevInfo, + ref DeviceInterfaceData deviceInterfaceData, + nint deviceInterfaceDetailData, + uint deviceInterfaceDetailDataSize, + ref uint requiredSize, nint deviceInfoData); - [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern bool SetupDiDestroyDeviceInfoList(SafeFileHandle hDevInfo); + [LibraryImport("setupapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool SetupDiDestroyDeviceInfoList(SafeFileHandle hDevInfo); - [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] - internal static extern bool CloseHandle(SafeFileHandle hDevice); + [LibraryImport("Kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static partial bool CloseHandle(SafeFileHandle hDevice); - [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern bool SetFilePointerEx(SafeFileHandle hFile, long liDistanceToMove, out long lpNewFilePointer, - MoveMethod dwMoveMethod); + [LibraryImport("Kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool SetFilePointerEx(SafeFileHandle hFile, long liDistanceToMove, out long lpNewFilePointer, + MoveMethod dwMoveMethod); - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern bool ReadFile(SafeFileHandle hFile, byte[] lpBuffer, uint nNumberOfBytesToRead, - out uint lpNumberOfBytesRead, IntPtr lpOverlapped); + [LibraryImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool ReadFile(SafeFileHandle hFile, byte[] lpBuffer, uint nNumberOfBytesToRead, + out uint lpNumberOfBytesRead, nint lpOverlapped); } \ No newline at end of file diff --git a/Aaru.Devices/Windows/ListDevices.cs b/Aaru.Devices/Windows/ListDevices.cs index 251992dfb..31742bcef 100644 --- a/Aaru.Devices/Windows/ListDevices.cs +++ b/Aaru.Devices/Windows/ListDevices.cs @@ -27,22 +27,23 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Windows; - using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Management; +using System.Runtime.Versioning; using System.Text; using Aaru.Helpers; using Microsoft.Win32.SafeHandles; using Marshal = System.Runtime.InteropServices.Marshal; -[System.Runtime.Versioning.SupportedOSPlatform("windows")] +namespace Aaru.Devices.Windows; + +[SupportedOSPlatform("windows")] static class ListDevices { /// Converts a hex dump string to the ASCII string it represents @@ -86,32 +87,33 @@ static class ListDevices } catch(Exception) { - #if DEBUG +#if DEBUG throw; - #else +#else return null; - #endif +#endif } var devList = new List(); foreach(string devId in deviceIDs) { - if(devId is null) - continue; + if(devId is null) continue; string physId = devId; // TODO: This can be done better - if(devId.Length == 2 && - devId[1] == ':') - physId = "\\\\?\\" + devId; + if(devId.Length == 2 && devId[1] == ':') physId = "\\\\?\\" + devId; - SafeFileHandle fd = Extern.CreateFile(physId, 0, FileShare.Read | FileShare.Write, IntPtr.Zero, - FileMode.OpenExisting, 0, IntPtr.Zero); + SafeFileHandle fd = Extern.CreateFile(physId, + 0, + FileShare.Read | FileShare.Write, + IntPtr.Zero, + FileMode.OpenExisting, + 0, + IntPtr.Zero); - if(fd.IsInvalid) - continue; + if(fd.IsInvalid) continue; var query = new StoragePropertyQuery { @@ -129,17 +131,20 @@ static class ListDevices uint returned = 0; var error = 0; - bool hasError = !Extern.DeviceIoControlStorageQuery(fd, WindowsIoctl.IoctlStorageQueryProperty, ref query, - (uint)Marshal.SizeOf(query), descriptorPtr, 1000, - ref returned, IntPtr.Zero); + bool hasError = !Extern.DeviceIoControlStorageQuery(fd, + WindowsIoctl.IoctlStorageQueryProperty, + ref query, + (uint)Marshal.SizeOf(query), + descriptorPtr, + 1000, + ref returned, + IntPtr.Zero); - if(hasError) - error = Marshal.GetLastWin32Error(); + if(hasError) error = Marshal.GetLastWin32Error(); Marshal.Copy(descriptorPtr, descriptorB, 0, 1000); - if(hasError && error != 0) - continue; + if(hasError && error != 0) continue; var descriptor = new StorageDeviceDescriptor { @@ -181,36 +186,33 @@ static class ListDevices info.Serial = HexStringToString(info.Serial).Trim(); } - if(string.IsNullOrEmpty(info.Vendor) || - info.Vendor == "ATA") + if(string.IsNullOrEmpty(info.Vendor) || info.Vendor == "ATA") { string[] pieces = info.Model?.Split(' '); if(pieces?.Length > 1) { info.Vendor = pieces[0]; - info.Model = info.Model.Substring(pieces[0].Length + 1); + info.Model = info.Model[(pieces[0].Length + 1)..]; } } - switch(descriptor.BusType) - { - case StorageBusType.SCSI: - case StorageBusType.ATAPI: - case StorageBusType.ATA: - case StorageBusType.FireWire: - case StorageBusType.SSA: - case StorageBusType.Fibre: - case StorageBusType.USB: - case StorageBusType.iSCSI: - case StorageBusType.SAS: - case StorageBusType.SATA: - case StorageBusType.SecureDigital: - case StorageBusType.MultiMediaCard: - info.Supported = true; - - break; - } + info.Supported = descriptor.BusType switch + { + StorageBusType.SCSI + or StorageBusType.ATAPI + or StorageBusType.ATA + or StorageBusType.FireWire + or StorageBusType.SSA + or StorageBusType.Fibre + or StorageBusType.USB + or StorageBusType.iSCSI + or StorageBusType.SAS + or StorageBusType.SATA + or StorageBusType.SecureDigital + or StorageBusType.MultiMediaCard => true, + _ => info.Supported + }; Marshal.FreeHGlobal(descriptorPtr); devList.Add(info); diff --git a/Aaru.Devices/Windows/Structs.cs b/Aaru.Devices/Windows/Structs.cs index bd32a8b7e..17a24342a 100644 --- a/Aaru.Devices/Windows/Structs.cs +++ b/Aaru.Devices/Windows/Structs.cs @@ -28,16 +28,17 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Devices.Windows; - using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +namespace Aaru.Devices.Windows; + +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] struct ScsiPassThroughDirect { public ushort Length; @@ -49,10 +50,10 @@ struct ScsiPassThroughDirect public byte SenseInfoLength; [MarshalAs(UnmanagedType.U1)] public ScsiIoctlDirection DataIn; - public uint DataTransferLength; - public uint TimeOutValue; - public IntPtr DataBuffer; - public uint SenseInfoOffset; + public uint DataTransferLength; + public uint TimeOutValue; + public nint DataBuffer; + public uint SenseInfoOffset; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] Cdb; @@ -67,7 +68,8 @@ struct ScsiPassThroughDirectAndSenseBuffer public byte[] SenseBuf; } -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] struct AtaPassThroughDirect { /// Length in bytes of this structure @@ -99,7 +101,7 @@ struct AtaPassThroughDirect public uint ReservedAsUlong; /// Pointer to data buffer - public IntPtr DataBuffer; + public nint DataBuffer; /// Previous ATA registers, for LBA48 public AtaTaskFile PreviousTaskFile; @@ -108,7 +110,8 @@ struct AtaPassThroughDirect public AtaTaskFile CurrentTaskFile; } -[StructLayout(LayoutKind.Explicit), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Explicit)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] struct AtaTaskFile { // Fields for commands sent @@ -150,7 +153,9 @@ struct StoragePropertyQuery public byte[] AdditionalParameters; } -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] struct StorageDescriptorHeader { public uint Version; @@ -191,7 +196,8 @@ struct IdePassThroughDirect public byte[] DataBuffer; } -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] struct StorageDeviceNumber { public int deviceType; @@ -199,25 +205,29 @@ struct StorageDeviceNumber public int partitionNumber; } -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] struct DeviceInfoData { - public int cbSize; - public Guid classGuid; - public uint devInst; - public IntPtr reserved; + public int cbSize; + public Guid classGuid; + public uint devInst; + public nint reserved; } -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] struct DeviceInterfaceData { - public int cbSize; - public Guid interfaceClassGuid; - public uint flags; - readonly IntPtr reserved; + public int cbSize; + public Guid interfaceClassGuid; + public uint flags; + readonly nint reserved; } -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] struct UsbSetupPacket { public byte bmRequest; @@ -227,7 +237,9 @@ struct UsbSetupPacket public short wLength; } -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[SuppressMessage("ReSharper", "UnusedType.Global")] struct UsbDescriptorRequest { public int ConnectionIndex; @@ -237,7 +249,8 @@ struct UsbDescriptorRequest //public byte[] Data; } -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] struct SffdiskQueryDeviceProtocolData { public ushort size; @@ -245,7 +258,8 @@ struct SffdiskQueryDeviceProtocolData public Guid protocolGuid; } -[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +[StructLayout(LayoutKind.Sequential)] +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] struct SffdiskDeviceCommandData { public ushort size; diff --git a/Aaru.Devices/Windows/Usb.cs b/Aaru.Devices/Windows/Usb.cs index 86013d2e2..bd1f83ff7 100644 --- a/Aaru.Devices/Windows/Usb.cs +++ b/Aaru.Devices/Windows/Usb.cs @@ -27,12 +27,10 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // Copyright © 2007 Fort Hood TX, herethen, Public Domain // ****************************************************************************/ -namespace Aaru.Devices.Windows; - using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -40,9 +38,13 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; +namespace Aaru.Devices.Windows; + // TODO: Even after cleaning, refactoring and xml-documenting, this code needs some love /// Implements functions for getting and accessing information from the USB bus -[SuppressMessage("ReSharper", "UnusedMember.Local"), SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "UnusedMember.Global")] static partial class Usb { /// Return a list of USB Host Controllers @@ -56,8 +58,7 @@ static partial class Usb // devices that match the interface GUID of a Hub Controller IntPtr h = SetupDiGetClassDevs(ref hostGuid, 0, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if(h == _invalidHandleValue) - return new ReadOnlyCollection(hostList); + if(h == _invalidHandleValue) return new ReadOnlyCollection(hostList); IntPtr ptrBuf = Marshal.AllocHGlobal(BUFFER_SIZE); bool success; @@ -67,7 +68,7 @@ static partial class Usb { var host = new UsbController { - _controllerIndex = i + ControllerIndex = i }; // create a Device Interface Data structure @@ -86,30 +87,39 @@ static partial class Usb // build a Device Interface Detail Data structure var didd = new SpDeviceInterfaceDetailData { - cbSize = 4 + Marshal.SystemDefaultCharSize + cbSize = IntPtr.Size == 8 ? 8 : 4 + Marshal.SystemDefaultCharSize }; // trust me :) // now we can get some more detailed information - var nRequiredSize = 0; - const int nBytes = BUFFER_SIZE; + var nRequiredSize = 0; - if(SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, nBytes, ref nRequiredSize, ref da)) + if(SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, BUFFER_SIZE, ref nRequiredSize, ref da)) { - host._controllerDevicePath = didd.DevicePath; + host.ControllerDevicePath = didd.DevicePath; // get the Device Description and DriverKeyName var requiredSize = 0; int regType = REG_SZ; - if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DEVICEDESC, ref regType, ptrBuf, BUFFER_SIZE, + if(SetupDiGetDeviceRegistryProperty(h, + ref da, + SPDRP_DEVICEDESC, + ref regType, + ptrBuf, + BUFFER_SIZE, ref requiredSize)) - host._controllerDeviceDesc = Marshal.PtrToStringAuto(ptrBuf); + host.ControllerDeviceDesc = Marshal.PtrToStringAuto(ptrBuf); - if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DRIVER, ref regType, ptrBuf, BUFFER_SIZE, + if(SetupDiGetDeviceRegistryProperty(h, + ref da, + SPDRP_DRIVER, + ref regType, + ptrBuf, + BUFFER_SIZE, ref requiredSize)) - host._controllerDriverKeyName = Marshal.PtrToStringAuto(ptrBuf); + host.ControllerDriverKeyName = Marshal.PtrToStringAuto(ptrBuf); } hostList.Add(host); @@ -130,15 +140,13 @@ static partial class Usb /// USB device description static string GetDescriptionByKeyName(string driverKeyName) { - var ans = ""; - const string devEnum = REGSTR_KEY_USB; + var ans = ""; // Use the "enumerator form" of the SetupDiGetClassDevs API // to generate a list of all USB devices - IntPtr h = SetupDiGetClassDevs(0, devEnum, IntPtr.Zero, DIGCF_PRESENT | DIGCF_ALLCLASSES); + IntPtr h = SetupDiGetClassDevs(0, REGSTR_KEY_USB, IntPtr.Zero, DIGCF_PRESENT | DIGCF_ALLCLASSES); - if(h == _invalidHandleValue) - return ans; + if(h == _invalidHandleValue) return ans; IntPtr ptrBuf = Marshal.AllocHGlobal(BUFFER_SIZE); @@ -160,14 +168,24 @@ static partial class Usb int regType = REG_SZ; var keyName = ""; - if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DRIVER, ref regType, ptrBuf, BUFFER_SIZE, + if(SetupDiGetDeviceRegistryProperty(h, + ref da, + SPDRP_DRIVER, + ref regType, + ptrBuf, + BUFFER_SIZE, ref requiredSize)) keyName = Marshal.PtrToStringAuto(ptrBuf); // is it a match? if(keyName == driverKeyName) { - if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DEVICEDESC, ref regType, ptrBuf, BUFFER_SIZE, + if(SetupDiGetDeviceRegistryProperty(h, + ref da, + SPDRP_DEVICEDESC, + ref regType, + ptrBuf, + BUFFER_SIZE, ref requiredSize)) ans = Marshal.PtrToStringAuto(ptrBuf); @@ -189,15 +207,13 @@ static partial class Usb /// Device instance ID static string GetInstanceIdByKeyName(string driverKeyName) { - var ans = ""; - const string devEnum = REGSTR_KEY_USB; + var ans = ""; // Use the "enumerator form" of the SetupDiGetClassDevs API // to generate a list of all USB devices - IntPtr h = SetupDiGetClassDevs(0, devEnum, IntPtr.Zero, DIGCF_PRESENT | DIGCF_ALLCLASSES); + IntPtr h = SetupDiGetClassDevs(0, REGSTR_KEY_USB, IntPtr.Zero, DIGCF_PRESENT | DIGCF_ALLCLASSES); - if(h == _invalidHandleValue) - return ans; + if(h == _invalidHandleValue) return ans; IntPtr ptrBuf = Marshal.AllocHGlobal(BUFFER_SIZE); @@ -220,16 +236,20 @@ static partial class Usb var keyName = ""; - if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DRIVER, ref regType, ptrBuf, BUFFER_SIZE, + if(SetupDiGetDeviceRegistryProperty(h, + ref da, + SPDRP_DRIVER, + ref regType, + ptrBuf, + BUFFER_SIZE, ref requiredSize)) keyName = Marshal.PtrToStringAuto(ptrBuf); // is it a match? if(keyName == driverKeyName) { - const int nBytes = BUFFER_SIZE; - var sb = new StringBuilder(nBytes); - SetupDiGetDeviceInstanceId(h, ref da, sb, nBytes, out requiredSize); + var sb = new StringBuilder(BUFFER_SIZE); + SetupDiGetDeviceInstanceId(h, ref da, sb, BUFFER_SIZE, out requiredSize); ans = sb.ToString(); break; @@ -245,72 +265,87 @@ static partial class Usb return ans; } +#region Nested type: UsbController + /// Represents a USB Host Controller sealed class UsbController { - internal string _controllerDriverKeyName, _controllerDevicePath, _controllerDeviceDesc; - internal int _controllerIndex; + internal string ControllerDriverKeyName, ControllerDevicePath, ControllerDeviceDesc; + internal int ControllerIndex; /// A simple default constructor internal UsbController() { - _controllerIndex = 0; - _controllerDevicePath = ""; - _controllerDeviceDesc = ""; - _controllerDriverKeyName = ""; + ControllerIndex = 0; + ControllerDevicePath = ""; + ControllerDeviceDesc = ""; + ControllerDriverKeyName = ""; } /// Return the index of the instance - internal int Index => _controllerIndex; + internal int Index => ControllerIndex; /// /// Return the Device Path, such as "\\?\pci#ven_10de&dev_005a&subsys_815a1043&rev_a2#3&267a616a&0& /// 58#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}" /// - internal string DevicePath => _controllerDevicePath; + internal string DevicePath => ControllerDevicePath; /// The DriverKeyName may be useful as a search key - internal string DriverKeyName => _controllerDriverKeyName; + internal string DriverKeyName => ControllerDriverKeyName; /// Return the Friendly Name, such as "VIA USB Enhanced Host Controller" - internal string Name => _controllerDeviceDesc; + internal string Name => ControllerDeviceDesc; /// Return Root Hub for this Controller internal UsbHub GetRootHub() { - IntPtr h, h2; - var root = new UsbHub { - _hubIsRootHub = true, - _hubDeviceDesc = "Root Hub" + HubIsRootHub = true, + HubDeviceDesc = "Root Hub" }; // Open a handle to the Host Controller - h = CreateFile(_controllerDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, - IntPtr.Zero); + IntPtr h = CreateFile(ControllerDevicePath, + GENERIC_WRITE, + FILE_SHARE_WRITE, + IntPtr.Zero, + OPEN_EXISTING, + 0, + IntPtr.Zero); - if(h == _invalidHandleValue) - return root; + if(h == _invalidHandleValue) return root; var hubName = new UsbRootHubName(); int nBytes = Marshal.SizeOf(hubName); IntPtr ptrHubName = Marshal.AllocHGlobal(nBytes); // get the Hub Name - if(DeviceIoControl(h, IOCTL_USB_GET_ROOT_HUB_NAME, ptrHubName, nBytes, ptrHubName, nBytes, out _, + if(DeviceIoControl(h, + IOCTL_USB_GET_ROOT_HUB_NAME, + ptrHubName, + nBytes, + ptrHubName, + nBytes, + out _, IntPtr.Zero)) { hubName = (UsbRootHubName)(Marshal.PtrToStructure(ptrHubName, typeof(UsbRootHubName)) ?? default(UsbRootHubName)); - root._hubDevicePath = @"\\.\" + hubName.RootHubName; + + root.HubDevicePath = @"\\.\" + hubName.RootHubName; } // TODO: Get DriverKeyName for Root Hub - // Now let's open the Hub (based upon the HubName we got above) - h2 = CreateFile(root._hubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, - IntPtr.Zero); + IntPtr h2 = CreateFile(root.HubDevicePath, + GENERIC_WRITE, + FILE_SHARE_WRITE, + IntPtr.Zero, + OPEN_EXISTING, + 0, + IntPtr.Zero); if(h2 != _invalidHandleValue) { @@ -324,14 +359,20 @@ static partial class Usb Marshal.StructureToPtr(nodeInfo, ptrNodeInfo, true); // get the Hub Information - if(DeviceIoControl(h2, IOCTL_USB_GET_NODE_INFORMATION, ptrNodeInfo, nBytes, ptrNodeInfo, nBytes, out _, + if(DeviceIoControl(h2, + IOCTL_USB_GET_NODE_INFORMATION, + ptrNodeInfo, + nBytes, + ptrNodeInfo, + nBytes, + out _, IntPtr.Zero)) { nodeInfo = (UsbNodeInformation)(Marshal.PtrToStructure(ptrNodeInfo, typeof(UsbNodeInformation)) ?? default(UsbNodeInformation)); - root._hubIsBusPowered = Convert.ToBoolean(nodeInfo.HubInformation.HubIsBusPowered); - root._hubPortCount = nodeInfo.HubInformation.HubDescriptor.bNumberOfPorts; + root.HubIsBusPowered = Convert.ToBoolean(nodeInfo.HubInformation.HubIsBusPowered); + root.HubPortCount = nodeInfo.HubInformation.HubDescriptor.bNumberOfPorts; } Marshal.FreeHGlobal(ptrNodeInfo); @@ -345,58 +386,113 @@ static partial class Usb } } +#endregion + +#region Nested type: UsbDevice + + /// Represents an USB device + internal class UsbDevice + { + internal byte[] BinaryDeviceDescriptors; + internal UsbDeviceDescriptor DeviceDescriptor; + internal string DeviceDriverKey, DeviceHubDevicePath, DeviceInstanceId, DeviceName; + internal string DeviceManufacturer, DeviceProduct, DeviceSerialNumber; + internal int DevicePortNumber; + + /// a simple default constructor + internal UsbDevice() + { + DevicePortNumber = 0; + DeviceHubDevicePath = ""; + DeviceDriverKey = ""; + DeviceManufacturer = ""; + DeviceProduct = "Unknown USB Device"; + DeviceSerialNumber = ""; + DeviceName = ""; + DeviceInstanceId = ""; + BinaryDeviceDescriptors = null; + } + + /// return Port Index of the Hub + internal int PortNumber => DevicePortNumber; + + /// return the Device Path of the Hub (the parent device) + internal string HubDevicePath => DeviceHubDevicePath; + + /// useful as a search key + internal string DriverKey => DeviceDriverKey; + + /// the device path of this device + internal string InstanceId => DeviceInstanceId; + + /// the friendly name + internal string Name => DeviceName; + + internal string Manufacturer => DeviceManufacturer; + + internal string Product => DeviceProduct; + + internal string SerialNumber => DeviceSerialNumber; + + internal byte[] BinaryDescriptors => BinaryDeviceDescriptors; + } + +#endregion + +#region Nested type: UsbHub + /// The Hub class internal class UsbHub { - internal string _hubDriverKey, _hubDevicePath, _hubDeviceDesc; - internal bool _hubIsBusPowered, _hubIsRootHub; - internal string _hubManufacturer, _hubProduct, _hubSerialNumber, _hubInstanceId; - internal int _hubPortCount; + internal string HubDriverKey, HubDevicePath, HubDeviceDesc; + internal bool HubIsBusPowered, HubIsRootHub; + internal string HubManufacturer, HubProduct, HubSerialNumber, HubInstanceId; + internal int HubPortCount; /// a simple default constructor internal UsbHub() { - _hubPortCount = 0; - _hubDevicePath = ""; - _hubDeviceDesc = ""; - _hubDriverKey = ""; - _hubIsBusPowered = false; - _hubIsRootHub = false; - _hubManufacturer = ""; - _hubProduct = ""; - _hubSerialNumber = ""; - _hubInstanceId = ""; + HubPortCount = 0; + HubDevicePath = ""; + HubDeviceDesc = ""; + HubDriverKey = ""; + HubIsBusPowered = false; + HubIsRootHub = false; + HubManufacturer = ""; + HubProduct = ""; + HubSerialNumber = ""; + HubInstanceId = ""; } /// return Port Count - internal int PortCount => _hubPortCount; + internal int PortCount => HubPortCount; /// /// return the Device Path, such as "\\?\pci#ven_10de&dev_005a&subsys_815a1043&rev_a2#3&267a616a&0& /// 58#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}" /// - internal string DevicePath => _hubDevicePath; + internal string DevicePath => HubDevicePath; /// The DriverKey may be useful as a search key - internal string DriverKey => _hubDriverKey; + internal string DriverKey => HubDriverKey; /// return the Friendly Name, such as "VIA USB Enhanced Host Controller" - internal string Name => _hubDeviceDesc; + internal string Name => HubDeviceDesc; /// the device path of this device - internal string InstanceId => _hubInstanceId; + internal string InstanceId => HubInstanceId; /// is is this a self-powered hub? - internal bool IsBusPowered => _hubIsBusPowered; + internal bool IsBusPowered => HubIsBusPowered; /// is this a root hub? - internal bool IsRootHub => _hubIsRootHub; + internal bool IsRootHub => HubIsRootHub; - internal string Manufacturer => _hubManufacturer; + internal string Manufacturer => HubManufacturer; - internal string Product => _hubProduct; + internal string Product => HubProduct; - internal string SerialNumber => _hubSerialNumber; + internal string SerialNumber => HubSerialNumber; /// return a list of the down stream ports /// List of downstream ports @@ -405,18 +501,22 @@ static partial class Usb var portList = new List(); // Open a handle to the Hub device - IntPtr h = CreateFile(_hubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, + IntPtr h = CreateFile(HubDevicePath, + GENERIC_WRITE, + FILE_SHARE_WRITE, + IntPtr.Zero, + OPEN_EXISTING, + 0, IntPtr.Zero); - if(h == _invalidHandleValue) - return new ReadOnlyCollection(portList); + if(h == _invalidHandleValue) return new ReadOnlyCollection(portList); int nBytes = Marshal.SizeOf(typeof(UsbNodeConnectionInformationEx)); IntPtr ptrNodeConnection = Marshal.AllocHGlobal(nBytes); // loop thru all of the ports on the hub // BTW: Ports are numbered starting at 1 - for(var i = 1; i <= _hubPortCount; i++) + for(var i = 1; i <= HubPortCount; i++) { var nodeConnection = new UsbNodeConnectionInformationEx { @@ -425,8 +525,14 @@ static partial class Usb Marshal.StructureToPtr(nodeConnection, ptrNodeConnection, true); - if(!DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, ptrNodeConnection, nBytes, - ptrNodeConnection, nBytes, out _, IntPtr.Zero)) + if(!DeviceIoControl(h, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, + ptrNodeConnection, + nBytes, + ptrNodeConnection, + nBytes, + out _, + IntPtr.Zero)) continue; nodeConnection = @@ -437,13 +543,13 @@ static partial class Usb // load up the USBPort class var port = new UsbPort { - _portPortNumber = i, - _portHubDevicePath = _hubDevicePath, - _portStatus = ((UsbConnectionStatus)nodeConnection.ConnectionStatus).ToString(), - _portSpeed = ((UsbDeviceSpeed)nodeConnection.Speed).ToString(), - _portIsDeviceConnected = nodeConnection.ConnectionStatus == (int)UsbConnectionStatus.DeviceConnected, - _portIsHub = Convert.ToBoolean(nodeConnection.DeviceIsHub), - _portDeviceDescriptor = nodeConnection.DeviceDescriptor + PortPortNumber = i, + PortHubDevicePath = HubDevicePath, + PortStatus = ((UsbConnectionStatus)nodeConnection.ConnectionStatus).ToString(), + PortSpeed = ((UsbDeviceSpeed)nodeConnection.Speed).ToString(), + PortIsDeviceConnected = nodeConnection.ConnectionStatus == (int)UsbConnectionStatus.DeviceConnected, + PortIsHub = Convert.ToBoolean(nodeConnection.DeviceIsHub), + PortDeviceDescriptor = nodeConnection.DeviceDescriptor }; // add it to the list @@ -458,65 +564,72 @@ static partial class Usb } } +#endregion + +#region Nested type: UsbPort + /// Represents an USB port internal class UsbPort { - internal UsbDeviceDescriptor _portDeviceDescriptor; - internal bool _portIsHub, _portIsDeviceConnected; - internal int _portPortNumber; - internal string _portStatus, _portHubDevicePath, _portSpeed; + internal UsbDeviceDescriptor PortDeviceDescriptor; + internal bool PortIsHub, PortIsDeviceConnected; + internal int PortPortNumber; + internal string PortStatus, PortHubDevicePath, PortSpeed; /// a simple default constructor internal UsbPort() { - _portPortNumber = 0; - _portStatus = ""; - _portHubDevicePath = ""; - _portSpeed = ""; - _portIsHub = false; - _portIsDeviceConnected = false; + PortPortNumber = 0; + PortStatus = ""; + PortHubDevicePath = ""; + PortSpeed = ""; + PortIsHub = false; + PortIsDeviceConnected = false; } /// return Port Index of the Hub - internal int PortNumber => _portPortNumber; + internal int PortNumber => PortPortNumber; /// return the Device Path of the Hub - internal string HubDevicePath => _portHubDevicePath; + internal string HubDevicePath => PortHubDevicePath; /// the status (see USB_CONNECTION_STATUS above) - internal string Status => _portStatus; + internal string Status => PortStatus; /// the speed of the connection (see USB_DEVICE_SPEED above) - internal string Speed => _portSpeed; + internal string Speed => PortSpeed; /// is this a downstream external hub? - internal bool IsHub => _portIsHub; + internal bool IsHub => PortIsHub; /// is anybody home? - internal bool IsDeviceConnected => _portIsDeviceConnected; + internal bool IsDeviceConnected => PortIsDeviceConnected; /// return a down stream external hub /// Downstream external hub internal UsbDevice GetDevice() { - if(!_portIsDeviceConnected) - return null; + if(!PortIsDeviceConnected) return null; // Copy over some values from the Port class // Ya know, I've given some thought about making Device a derived class... var device = new UsbDevice { - _devicePortNumber = _portPortNumber, - _deviceHubDevicePath = _portHubDevicePath, - _deviceDescriptor = _portDeviceDescriptor + DevicePortNumber = PortPortNumber, + DeviceHubDevicePath = PortHubDevicePath, + DeviceDescriptor = PortDeviceDescriptor }; // Open a handle to the Hub device - IntPtr h = CreateFile(_portHubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, + IntPtr h = CreateFile(PortHubDevicePath, + GENERIC_WRITE, + FILE_SHARE_WRITE, + IntPtr.Zero, + OPEN_EXISTING, + 0, IntPtr.Zero); - if(h == _invalidHandleValue) - return device; + if(h == _invalidHandleValue) return device; int nBytesReturned; int nBytes = BUFFER_SIZE; @@ -528,17 +641,17 @@ static partial class Usb // Device Descriptor are really just indexes. So, we have to // request a String Descriptor to get the values for those strings. - if(_portDeviceDescriptor.iManufacturer > 0) + if(PortDeviceDescriptor.iManufacturer > 0) { // build a request for string descriptor var request = new UsbDescriptorRequest { - ConnectionIndex = _portPortNumber, + ConnectionIndex = PortPortNumber, SetupPacket = { // Language Code wIndex = 0x409, - wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + _portDeviceDescriptor.iManufacturer) + wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + PortDeviceDescriptor.iManufacturer) } }; @@ -549,8 +662,14 @@ static partial class Usb Marshal.StructureToPtr(request, ptrRequest, true); // Use an IOCTL call to request the String Descriptor - if(DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ptrRequest, nBytes, ptrRequest, - nBytes, out nBytesReturned, IntPtr.Zero)) + if(DeviceIoControl(h, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + ptrRequest, + nBytes, + ptrRequest, + nBytes, + out nBytesReturned, + IntPtr.Zero)) { // The location of the string descriptor is immediately after // the Request structure. Because this location is not "covered" @@ -562,23 +681,23 @@ static partial class Usb (UsbStringDescriptor)(Marshal.PtrToStructure(ptrStringDesc, typeof(UsbStringDescriptor)) ?? default(UsbStringDescriptor)); - device._deviceManufacturer = stringDesc.bString; + device.DeviceManufacturer = stringDesc.bString; } Marshal.FreeHGlobal(ptrRequest); } - if(_portDeviceDescriptor.iProduct > 0) + if(PortDeviceDescriptor.iProduct > 0) { // build a request for string descriptor var request = new UsbDescriptorRequest { - ConnectionIndex = _portPortNumber, + ConnectionIndex = PortPortNumber, SetupPacket = { // Language Code wIndex = 0x409, - wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + _portDeviceDescriptor.iProduct) + wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + PortDeviceDescriptor.iProduct) } }; @@ -589,8 +708,14 @@ static partial class Usb Marshal.StructureToPtr(request, ptrRequest, true); // Use an IOCTL call to request the String Descriptor - if(DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ptrRequest, nBytes, ptrRequest, - nBytes, out nBytesReturned, IntPtr.Zero)) + if(DeviceIoControl(h, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + ptrRequest, + nBytes, + ptrRequest, + nBytes, + out nBytesReturned, + IntPtr.Zero)) { // the location of the string descriptor is immediately after the Request structure var ptrStringDesc = IntPtr.Add(ptrRequest, Marshal.SizeOf(request)); @@ -599,23 +724,23 @@ static partial class Usb (UsbStringDescriptor)(Marshal.PtrToStructure(ptrStringDesc, typeof(UsbStringDescriptor)) ?? default(UsbStringDescriptor)); - device._deviceProduct = stringDesc.bString; + device.DeviceProduct = stringDesc.bString; } Marshal.FreeHGlobal(ptrRequest); } - if(_portDeviceDescriptor.iSerialNumber > 0) + if(PortDeviceDescriptor.iSerialNumber > 0) { // build a request for string descriptor var request = new UsbDescriptorRequest { - ConnectionIndex = _portPortNumber, + ConnectionIndex = PortPortNumber, SetupPacket = { // Language Code wIndex = 0x409, - wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + _portDeviceDescriptor.iSerialNumber) + wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + PortDeviceDescriptor.iSerialNumber) } }; @@ -626,8 +751,14 @@ static partial class Usb Marshal.StructureToPtr(request, ptrRequest, true); // Use an IOCTL call to request the String Descriptor - if(DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ptrRequest, nBytes, ptrRequest, - nBytes, out nBytesReturned, IntPtr.Zero)) + if(DeviceIoControl(h, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + ptrRequest, + nBytes, + ptrRequest, + nBytes, + out nBytesReturned, + IntPtr.Zero)) { // the location of the string descriptor is immediately after the Request structure var ptrStringDesc = IntPtr.Add(ptrRequest, Marshal.SizeOf(request)); @@ -636,7 +767,7 @@ static partial class Usb (UsbStringDescriptor)(Marshal.PtrToStructure(ptrStringDesc, typeof(UsbStringDescriptor)) ?? default(UsbStringDescriptor)); - device._deviceSerialNumber = stringDesc.bString; + device.DeviceSerialNumber = stringDesc.bString; } Marshal.FreeHGlobal(ptrRequest); @@ -645,7 +776,7 @@ static partial class Usb // build a request for configuration descriptor var dcrRequest = new UsbDescriptorRequest { - ConnectionIndex = _portPortNumber, + ConnectionIndex = PortPortNumber, SetupPacket = { wIndex = 0, @@ -660,12 +791,18 @@ static partial class Usb Marshal.StructureToPtr(dcrRequest, dcrPtrRequest, true); // Use an IOCTL call to request the String Descriptor - if(DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, dcrPtrRequest, nBytes, dcrPtrRequest, - nBytes, out nBytesReturned, IntPtr.Zero)) + if(DeviceIoControl(h, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + dcrPtrRequest, + nBytes, + dcrPtrRequest, + nBytes, + out nBytesReturned, + IntPtr.Zero)) { var ptrStringDesc = IntPtr.Add(dcrPtrRequest, Marshal.SizeOf(dcrRequest)); - device._binaryDeviceDescriptors = new byte[nBytesReturned]; - Marshal.Copy(ptrStringDesc, device._binaryDeviceDescriptors, 0, nBytesReturned); + device.BinaryDeviceDescriptors = new byte[nBytesReturned]; + Marshal.Copy(ptrStringDesc, device.BinaryDeviceDescriptors, 0, nBytesReturned); } Marshal.FreeHGlobal(dcrPtrRequest); @@ -673,7 +810,7 @@ static partial class Usb // Get the Driver Key Name (usefull in locating a device) var driverKey = new UsbNodeConnectionDriverkeyName { - ConnectionIndex = _portPortNumber + ConnectionIndex = PortPortNumber }; nBytes = Marshal.SizeOf(driverKey); @@ -681,18 +818,24 @@ static partial class Usb Marshal.StructureToPtr(driverKey, ptrDriverKey, true); // Use an IOCTL call to request the Driver Key Name - if(DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ptrDriverKey, nBytes, ptrDriverKey, - nBytes, out nBytesReturned, IntPtr.Zero)) + if(DeviceIoControl(h, + IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, + ptrDriverKey, + nBytes, + ptrDriverKey, + nBytes, + out nBytesReturned, + IntPtr.Zero)) { driverKey = (UsbNodeConnectionDriverkeyName)(Marshal.PtrToStructure(ptrDriverKey, typeof(UsbNodeConnectionDriverkeyName)) ?? default(UsbNodeConnectionDriverkeyName)); - device._deviceDriverKey = driverKey.DriverKeyName; + device.DeviceDriverKey = driverKey.DriverKeyName; // use the DriverKeyName to get the Device Description and Instance ID - device._deviceName = GetDescriptionByKeyName(device._deviceDriverKey); - device._deviceInstanceId = GetInstanceIdByKeyName(device._deviceDriverKey); + device.DeviceName = GetDescriptionByKeyName(device.DeviceDriverKey); + device.DeviceInstanceId = GetInstanceIdByKeyName(device.DeviceDriverKey); } Marshal.FreeHGlobal(ptrDriverKey); @@ -705,25 +848,29 @@ static partial class Usb /// Downstream external hub internal UsbHub GetHub() { - if(!_portIsHub) - return null; + if(!PortIsHub) return null; - var hub = new UsbHub(); - IntPtr h, h2; - hub._hubIsRootHub = false; - hub._hubDeviceDesc = "External Hub"; + var hub = new UsbHub + { + HubIsRootHub = false, + HubDeviceDesc = "External Hub" + }; // Open a handle to the Host Controller - h = CreateFile(_portHubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, - IntPtr.Zero); + IntPtr h = CreateFile(PortHubDevicePath, + GENERIC_WRITE, + FILE_SHARE_WRITE, + IntPtr.Zero, + OPEN_EXISTING, + 0, + IntPtr.Zero); - if(h == _invalidHandleValue) - return hub; + if(h == _invalidHandleValue) return hub; // Get the DevicePath for downstream hub var nodeName = new UsbNodeConnectionName { - ConnectionIndex = _portPortNumber + ConnectionIndex = PortPortNumber }; int nBytes = Marshal.SizeOf(nodeName); @@ -731,18 +878,29 @@ static partial class Usb Marshal.StructureToPtr(nodeName, ptrNodeName, true); // Use an IOCTL call to request the Node Name - if(DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_NAME, ptrNodeName, nBytes, ptrNodeName, nBytes, out _, + if(DeviceIoControl(h, + IOCTL_USB_GET_NODE_CONNECTION_NAME, + ptrNodeName, + nBytes, + ptrNodeName, + nBytes, + out _, IntPtr.Zero)) { nodeName = (UsbNodeConnectionName)(Marshal.PtrToStructure(ptrNodeName, typeof(UsbNodeConnectionName)) ?? default(UsbNodeConnectionName)); - hub._hubDevicePath = @"\\.\" + nodeName.NodeName; + hub.HubDevicePath = @"\\.\" + nodeName.NodeName; } // Now let's open the Hub (based upon the HubName we got above) - h2 = CreateFile(hub._hubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, - IntPtr.Zero); + IntPtr h2 = CreateFile(hub.HubDevicePath, + GENERIC_WRITE, + FILE_SHARE_WRITE, + IntPtr.Zero, + OPEN_EXISTING, + 0, + IntPtr.Zero); if(h2 != _invalidHandleValue) { @@ -756,14 +914,20 @@ static partial class Usb Marshal.StructureToPtr(nodeInfo, ptrNodeInfo, true); // get the Hub Information - if(DeviceIoControl(h2, IOCTL_USB_GET_NODE_INFORMATION, ptrNodeInfo, nBytes, ptrNodeInfo, nBytes, out _, + if(DeviceIoControl(h2, + IOCTL_USB_GET_NODE_INFORMATION, + ptrNodeInfo, + nBytes, + ptrNodeInfo, + nBytes, + out _, IntPtr.Zero)) { nodeInfo = (UsbNodeInformation)(Marshal.PtrToStructure(ptrNodeInfo, typeof(UsbNodeInformation)) ?? default(UsbNodeInformation)); - hub._hubIsBusPowered = Convert.ToBoolean(nodeInfo.HubInformation.HubIsBusPowered); - hub._hubPortCount = nodeInfo.HubInformation.HubDescriptor.bNumberOfPorts; + hub.HubIsBusPowered = Convert.ToBoolean(nodeInfo.HubInformation.HubIsBusPowered); + hub.HubPortCount = nodeInfo.HubInformation.HubDescriptor.bNumberOfPorts; } Marshal.FreeHGlobal(ptrNodeInfo); @@ -773,11 +937,11 @@ static partial class Usb // Fill in the missing Manufacture, Product, and SerialNumber values // values by just creating a Device instance and copying the values UsbDevice device = GetDevice(); - hub._hubInstanceId = device._deviceInstanceId; - hub._hubManufacturer = device.Manufacturer; - hub._hubProduct = device.Product; - hub._hubSerialNumber = device.SerialNumber; - hub._hubDriverKey = device.DriverKey; + hub.HubInstanceId = device.DeviceInstanceId; + hub.HubManufacturer = device.Manufacturer; + hub.HubProduct = device.Product; + hub.HubSerialNumber = device.SerialNumber; + hub.HubDriverKey = device.DriverKey; Marshal.FreeHGlobal(ptrNodeName); CloseHandle(h); @@ -786,60 +950,16 @@ static partial class Usb } } - /// Represents an USB device - internal class UsbDevice - { - internal byte[] _binaryDeviceDescriptors; - internal UsbDeviceDescriptor _deviceDescriptor; - internal string _deviceDriverKey, _deviceHubDevicePath, _deviceInstanceId, _deviceName; - internal string _deviceManufacturer, _deviceProduct, _deviceSerialNumber; - internal int _devicePortNumber; +#endregion - /// a simple default constructor - internal UsbDevice() - { - _devicePortNumber = 0; - _deviceHubDevicePath = ""; - _deviceDriverKey = ""; - _deviceManufacturer = ""; - _deviceProduct = "Unknown USB Device"; - _deviceSerialNumber = ""; - _deviceName = ""; - _deviceInstanceId = ""; - _binaryDeviceDescriptors = null; - } +#region "API Region" - /// return Port Index of the Hub - internal int PortNumber => _devicePortNumber; - - /// return the Device Path of the Hub (the parent device) - internal string HubDevicePath => _deviceHubDevicePath; - - /// useful as a search key - internal string DriverKey => _deviceDriverKey; - - /// the device path of this device - internal string InstanceId => _deviceInstanceId; - - /// the friendly name - internal string Name => _deviceName; - - internal string Manufacturer => _deviceManufacturer; - - internal string Product => _deviceProduct; - - internal string SerialNumber => _deviceSerialNumber; - - internal byte[] BinaryDescriptors => _binaryDeviceDescriptors; - } - - #region "API Region" // ********************** Constants ************************ - const int GENERIC_WRITE = 0x40000000; - const int FILE_SHARE_READ = 0x1; - const int FILE_SHARE_WRITE = 0x2; - const int OPEN_EXISTING = 0x3; + const int GENERIC_WRITE = 0x40000000; + const int FILE_SHARE_READ = 0x1; + const int FILE_SHARE_WRITE = 0x2; + const int OPEN_EXISTING = 0x3; static readonly IntPtr _invalidHandleValue = new(-1); const int IOCTL_GET_HCD_DRIVERKEY_NAME = 0x220424; @@ -901,7 +1021,7 @@ static partial class Usb { internal int cbSize; internal readonly Guid ClassGuid; - internal readonly IntPtr DevInst; + internal readonly uint DevInst; internal readonly IntPtr Reserved; } @@ -981,7 +1101,8 @@ static partial class Usb //internal IntPtr PipeList; } - [StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] internal struct UsbDeviceDescriptor { internal byte bLength; @@ -1049,53 +1170,73 @@ static partial class Usb // ********************** API Definitions ************************ - [DllImport("setupapi.dll", CharSet = CharSet.Auto)] - static extern IntPtr SetupDiGetClassDevs( // 1st form using a ClassGUID + [LibraryImport("setupapi.dll", EntryPoint = "SetupDiGetClassDevsW")] + private static partial IntPtr SetupDiGetClassDevs( // 1st form using a ClassGUID ref Guid classGuid, int enumerator, IntPtr hwndParent, int flags); - [DllImport("setupapi.dll", CharSet = CharSet.Auto)] // 2nd form uses an Enumerator - static extern IntPtr SetupDiGetClassDevs(int classGuid, string enumerator, IntPtr hwndParent, int flags); + [LibraryImport("setupapi.dll", + EntryPoint = "SetupDiGetClassDevsW", + StringMarshalling = StringMarshalling.Utf16)] // 2nd form uses an Enumerator + private static partial IntPtr SetupDiGetClassDevs(int classGuid, string enumerator, + IntPtr hwndParent, int flags); + + [LibraryImport("setupapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData, + ref Guid interfaceClassGuid, int memberIndex, + ref SpDeviceInterfaceData + deviceInterfaceData); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] - static extern bool SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData, - ref Guid interfaceClassGuid, int memberIndex, - ref SpDeviceInterfaceData deviceInterfaceData); - - [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] - static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, + static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, ref SpDeviceInterfaceData deviceInterfaceData, - ref SpDeviceInterfaceDetailData deviceInterfaceDetailData, - int deviceInterfaceDetailDataSize, ref int requiredSize, + ref SpDeviceInterfaceDetailData + deviceInterfaceDetailData, + int deviceInterfaceDetailDataSize, + ref int requiredSize, ref SpDevinfoData deviceInfoData); - [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] - static extern bool SetupDiGetDeviceRegistryProperty(IntPtr deviceInfoSet, ref SpDevinfoData deviceInfoData, - int iProperty, ref int propertyRegDataType, - IntPtr propertyBuffer, int propertyBufferSize, - ref int requiredSize); + [LibraryImport("setupapi.dll", + EntryPoint = "SetupDiGetDeviceRegistryPropertyW", + SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool SetupDiGetDeviceRegistryProperty( + IntPtr deviceInfoSet, ref SpDevinfoData deviceInfoData, int iProperty, + ref int propertyRegDataType, IntPtr propertyBuffer, int propertyBufferSize, + ref int requiredSize); + + [LibraryImport("setupapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool SetupDiEnumDeviceInfo(IntPtr deviceInfoSet, int memberIndex, + ref SpDevinfoData deviceInfoData); + + [LibraryImport("setupapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] - static extern bool SetupDiEnumDeviceInfo(IntPtr deviceInfoSet, int memberIndex, ref SpDevinfoData deviceInfoData); + static extern bool SetupDiGetDeviceInstanceId(IntPtr deviceInfoSet, ref SpDevinfoData deviceInfoData, + StringBuilder deviceInstanceId, + int deviceInstanceIdSize, out int requiredSize); - [DllImport("setupapi.dll", SetLastError = true)] - static extern bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet); + [LibraryImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool DeviceIoControl(IntPtr hDevice, int dwIoControlCode, IntPtr lpInBuffer, + int nInBufferSize, IntPtr lpOutBuffer, + int nOutBufferSize, out int lpBytesReturned, + IntPtr lpOverlapped); - [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] - static extern bool SetupDiGetDeviceInstanceId(IntPtr deviceInfoSet, ref SpDevinfoData deviceInfoData, - StringBuilder deviceInstanceId, int deviceInstanceIdSize, - out int requiredSize); + [LibraryImport("kernel32.dll", + EntryPoint = "CreateFileW", + SetLastError = true, + StringMarshalling = StringMarshalling.Utf16)] + private static partial IntPtr CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, + IntPtr lpSecurityAttributes, int dwCreationDisposition, + int dwFlagsAndAttributes, IntPtr hTemplateFile); - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] - static extern bool DeviceIoControl(IntPtr hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize, - IntPtr lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, - IntPtr lpOverlapped); + [LibraryImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool CloseHandle(IntPtr hObject); - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] - static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, - IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, - IntPtr hTemplateFile); - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] - static extern bool CloseHandle(IntPtr hObject); - #endregion +#endregion } \ No newline at end of file diff --git a/Aaru.Devices/Windows/UsbFunctions.cs b/Aaru.Devices/Windows/UsbFunctions.cs index a9fe7e30b..f802d5ed4 100644 --- a/Aaru.Devices/Windows/UsbFunctions.cs +++ b/Aaru.Devices/Windows/UsbFunctions.cs @@ -27,29 +27,31 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // Copyright © 2007 Fort Hood TX, herethen, Public Domain // ****************************************************************************/ -namespace Aaru.Devices.Windows; - using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +namespace Aaru.Devices.Windows; + // // A place for "higher level" related functions // You might not want to keep these in the USB class... your choice // // TODO: Even after cleaning, refactoring and xml-documenting, this code needs some love /// Implements functions for getting and accessing information from the USB bus +[SuppressMessage("ReSharper", "UnusedMember.Global")] static partial class Usb { const int IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x2D1080; - internal const string GUID_DEVINTERFACE_DISK = "53f56307-b6bf-11d0-94f2-00a0c91efb8b"; - internal const string GUID_DEVINTERFACE_CDROM = "53f56308-b6bf-11d0-94f2-00a0c91efb8b"; - internal const string GUID_DEVINTERFACE_FLOPPY = "53f56311-b6bf-11d0-94f2-00a0c91efb8b"; - internal const string GUID_DEVINTERFACE_TAPE = "53f5630b-b6bf-11d0-94f2-00a0c91efb8b"; + internal const string GUID_DEVINTERFACE_DISK = "53f56307-b6bf-11d0-94f2-00a0c91efb8b"; + internal const string GUID_DEVINTERFACE_CDROM = "53f56308-b6bf-11d0-94f2-00a0c91efb8b"; + internal const string GUID_DEVINTERFACE_FLOPPY = "53f56311-b6bf-11d0-94f2-00a0c91efb8b"; + internal const string GUID_DEVINTERFACE_TAPE = "53f5630b-b6bf-11d0-94f2-00a0c91efb8b"; /// Get a list of all connected devices /// List of usb devices @@ -57,8 +59,7 @@ static partial class Usb { var devList = new List(); - foreach(UsbController controller in GetHostControllers()) - ListHub(controller.GetRootHub(), devList); + foreach(UsbController controller in GetHostControllers()) ListHub(controller.GetRootHub(), devList); return devList; } @@ -69,13 +70,14 @@ static partial class Usb static void ListHub(UsbHub hub, ICollection devList) { foreach(UsbPort port in hub.GetPorts()) + { if(port.IsHub) ListHub(port.GetHub(), devList); else { - if(port.IsDeviceConnected) - devList.Add(port.GetDevice()); + if(port.IsDeviceConnected) devList.Add(port.GetDevice()); } + } } /// Find a device based upon it's DriverKeyName @@ -89,8 +91,7 @@ static partial class Usb { SearchHubDriverKeyName(controller.GetRootHub(), ref foundDevice, driverKeyName); - if(foundDevice != null) - break; + if(foundDevice != null) break; } return foundDevice; @@ -103,22 +104,22 @@ static partial class Usb static void SearchHubDriverKeyName(UsbHub hub, ref UsbDevice foundDevice, string driverKeyName) { foreach(UsbPort port in hub.GetPorts()) + { if(port.IsHub) SearchHubDriverKeyName(port.GetHub(), ref foundDevice, driverKeyName); else { - if(!port.IsDeviceConnected) - continue; + if(!port.IsDeviceConnected) continue; UsbDevice device = port.GetDevice(); - if(device._deviceDriverKey != driverKeyName) - continue; + if(device.DeviceDriverKey != driverKeyName) continue; foundDevice = device; break; } + } } /// Find a device based upon it's Instance ID @@ -132,8 +133,7 @@ static partial class Usb { SearchHubInstanceId(controller.GetRootHub(), ref foundDevice, instanceId); - if(foundDevice != null) - break; + if(foundDevice != null) break; } return foundDevice; @@ -146,29 +146,29 @@ static partial class Usb static void SearchHubInstanceId(UsbHub hub, ref UsbDevice foundDevice, string instanceId) { foreach(UsbPort port in hub.GetPorts()) + { if(port.IsHub) SearchHubInstanceId(port.GetHub(), ref foundDevice, instanceId); else { - if(!port.IsDeviceConnected) - continue; + if(!port.IsDeviceConnected) continue; UsbDevice device = port.GetDevice(); - if(device.InstanceId != instanceId) - continue; + if(device.InstanceId != instanceId) continue; foundDevice = device; break; } + } } - [DllImport("setupapi.dll")] - static extern int CM_Get_Parent(out IntPtr pdnDevInst, IntPtr dnDevInst, int ulFlags); + [LibraryImport("setupapi.dll")] + private static partial int CM_Get_Parent(out uint pdnDevInst, uint dnDevInst, int ulFlags); - [DllImport("setupapi.dll", CharSet = CharSet.Auto)] - static extern int CM_Get_Device_ID(IntPtr dnDevInst, IntPtr buffer, int bufferLen, int ulFlags); + [LibraryImport("setupapi.dll", EntryPoint = "CM_Get_Device_IDW")] + private static partial int CM_Get_Device_ID(uint dnDevInst, IntPtr buffer, int bufferLen, int ulFlags); /// Find a device based upon a Drive Letter /// Drive letter @@ -236,23 +236,23 @@ static partial class Usb // build a Device Interface Detail Data structure var didd = new SpDeviceInterfaceDetailData { - cbSize = 4 + Marshal.SystemDefaultCharSize - }; // trust me :) + cbSize = IntPtr.Size == 8 ? 8 : 4 + Marshal.SystemDefaultCharSize + }; // now we can get some more detailed information - var nRequiredSize = 0; - const int nBytes = BUFFER_SIZE; + var nRequiredSize = 0; - if(SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, nBytes, ref nRequiredSize, ref da)) + if(SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, BUFFER_SIZE, ref nRequiredSize, ref da)) + { if(GetDeviceNumber(didd.DevicePath) == devNum) { // current InstanceID is at the "USBSTOR" level, so we // need up "move up" one level to get to the "USB" level - CM_Get_Parent(out IntPtr ptrPrevious, da.DevInst, 0); + CM_Get_Parent(out uint ptrPrevious, da.DevInst, 0); // Now we get the InstanceID of the USB level device - IntPtr ptrInstanceBuf = Marshal.AllocHGlobal(nBytes); - CM_Get_Device_ID(ptrPrevious, ptrInstanceBuf, nBytes, 0); + nint ptrInstanceBuf = Marshal.AllocHGlobal(BUFFER_SIZE); + CM_Get_Device_ID(ptrPrevious, ptrInstanceBuf, BUFFER_SIZE, 0); instanceId = Marshal.PtrToStringAuto(ptrInstanceBuf); Marshal.FreeHGlobal(ptrInstanceBuf); @@ -260,6 +260,7 @@ static partial class Usb //System.Console.WriteLine("InstanceId: {0}", instanceId); //break; } + } } i++; @@ -284,8 +285,7 @@ static partial class Usb IntPtr h = CreateFile(devicePath.TrimEnd('\\'), 0, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); - if(h == _invalidHandleValue) - return ans; + if(h == _invalidHandleValue) return ans; var sdn = new StorageDeviceNumber(); int nBytes = Marshal.SizeOf(sdn); @@ -307,6 +307,8 @@ static partial class Usb return ans; } +#region Nested type: StorageDeviceNumber + [StructLayout(LayoutKind.Sequential)] readonly struct StorageDeviceNumber { @@ -314,4 +316,6 @@ static partial class Usb internal readonly int DeviceNumber; internal readonly int PartitionNumber; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Dto b/Aaru.Dto deleted file mode 160000 index 6befd3dd6..000000000 --- a/Aaru.Dto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6befd3dd6e82a53bca52c4207377036556690042 diff --git a/Aaru.Dto/.gitignore b/Aaru.Dto/.gitignore new file mode 100644 index 000000000..05c540d38 --- /dev/null +++ b/Aaru.Dto/.gitignore @@ -0,0 +1,595 @@ +### VisualStudio template +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ +### Linux template + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +### C++ template +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o + +# Precompiled Headers +*.gch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### MonoDevelop template +#User Specific +*.usertasks + +#Mono Project Files +*.resources +test-results/ +### GPG template +secring.* + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests +### CMake template +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +### C template +# Object files +*.ko +*.elf + +# Linker output +*.map +*.exp + +*.so.* + +# Executables +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# NuGet Packages Directory +packages/ +## TODO: If the tool you use requires repositories.config uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +# This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) +!packages/build/ + + +# Others +sql/ +*.Cache + +# Visual Studio 2017 +.vs + +workspace.xml +cmake-build-debug +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +pkg/**/pkg +pkg/**/src +pkg/**/*.asc +pkg/**/*.sig +pkg/**/*.tar.xz +pkg/**/*.zip +pkg/**/aaru + +.sonarqube \ No newline at end of file diff --git a/Aaru.Dto/Aaru.Dto.csproj b/Aaru.Dto/Aaru.Dto.csproj new file mode 100644 index 000000000..24da144fe --- /dev/null +++ b/Aaru.Dto/Aaru.Dto.csproj @@ -0,0 +1,92 @@ + + + + 2.0 + {F4399FF5-9BD0-475A-9EA7-3DAE45291FE2} + Library + Aaru.Dto + Aaru.Dto + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Dto + $(Version) + net8.0 + 12 + Data transfer objects used to interchange data between Aaru and Aaru.Server. + https://github.com/aaru-dps/ + LGPL-2.1-only + https://github.com/aaru-dps/Aaru + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + LICENSE.LGPL + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + \ No newline at end of file diff --git a/Aaru.Dto/CdOffsetDto.cs b/Aaru.Dto/CdOffsetDto.cs new file mode 100644 index 000000000..bd30f1217 --- /dev/null +++ b/Aaru.Dto/CdOffsetDto.cs @@ -0,0 +1,61 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CdOffsetDto.cs +// Author(s) : Natalia Portillo +// +// Component : DTOs. +// +// --[ Description ] ---------------------------------------------------------- +// +// DTO for syncing Compact Disc read offsets. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Metadata; + +namespace Aaru.Dto; + +/// +/// DTO from a CD drive read offset +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public class CdOffsetDto : CdOffset +{ + /// Build an empty DTO + public CdOffsetDto() {} + + /// Build a DTO using the specified offset and database ID + /// CD reading offset + /// Database ID + public CdOffsetDto(CdOffset offset, int id) + { + Manufacturer = offset.Manufacturer; + Model = offset.Model; + Offset = offset.Offset; + Submissions = offset.Submissions; + Agreement = offset.Agreement; + Id = id; + } + + /// Database ID + public int Id { get; set; } +} \ No newline at end of file diff --git a/Aaru.Dto/DeviceDto.cs b/Aaru.Dto/DeviceDto.cs new file mode 100644 index 000000000..8a74b36ff --- /dev/null +++ b/Aaru.Dto/DeviceDto.cs @@ -0,0 +1,257 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DeviceDto.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// DTO for syncing processed device reports in database. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable VirtualMemberCallInConstructor + +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Metadata; + +namespace Aaru.Dto; + +/// DTO for known device +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public class DeviceDto : DeviceReport +{ + /// Build an empty DTO + public DeviceDto() {} + + /// Build a DTO from a device report + /// Device report + public DeviceDto(DeviceReport report) + { + ATA = report.ATA; + ATAPI = report.ATAPI; + CompactFlash = report.CompactFlash; + FireWire = report.FireWire; + MultiMediaCard = report.MultiMediaCard; + PCMCIA = report.PCMCIA; + SCSI = report.SCSI; + SecureDigital = report.SecureDigital; + USB = report.USB; + Manufacturer = report.Manufacturer; + Model = report.Model; + Revision = report.Revision; + Type = report.Type; + GdRomSwapDiscCapabilities = report.GdRomSwapDiscCapabilities; + } + + /// Build a DTO from a device report with the specified parameters + /// Device report + /// Database ID + /// Optimal number of blocks for read + /// Can read GD-ROM using swap trick? + public DeviceDto(DeviceReport report, int id, int optimalMultipleSectorsRead, bool? canReadGdRomUsingSwapDisc) + { + ATA = report.ATA; + ATAPI = report.ATAPI; + CompactFlash = report.CompactFlash; + FireWire = report.FireWire; + MultiMediaCard = report.MultiMediaCard; + PCMCIA = report.PCMCIA; + SCSI = report.SCSI; + SecureDigital = report.SecureDigital; + USB = report.USB; + Manufacturer = report.Manufacturer; + Model = report.Model; + Revision = report.Revision; + Type = report.Type; + GdRomSwapDiscCapabilities = report.GdRomSwapDiscCapabilities; + + if(ATA != null) + { + ATA.Identify = null; + ATA.ReadCapabilities = ClearBinaries(ATA.ReadCapabilities); + + if(ATA.RemovableMedias != null) + { + TestedMedia[] medias = ATA.RemovableMedias.ToArray(); + ATA.RemovableMedias = []; + + foreach(TestedMedia media in medias) ATA.RemovableMedias.Add(ClearBinaries(media)); + } + } + + if(ATAPI != null) + { + ATAPI.Identify = null; + ATAPI.ReadCapabilities = ClearBinaries(ATAPI.ReadCapabilities); + + if(ATAPI.RemovableMedias != null) + { + TestedMedia[] medias = ATAPI.RemovableMedias.ToArray(); + ATAPI.RemovableMedias = []; + + foreach(TestedMedia media in medias) ATAPI.RemovableMedias.Add(ClearBinaries(media)); + } + } + + if(PCMCIA != null) + { + PCMCIA.AdditionalInformation = null; + PCMCIA.CIS = null; + } + + MultiMediaCard = null; + SecureDigital = null; + + if(SCSI != null) + { + SCSI.EVPDPages = null; + SCSI.InquiryData = null; + SCSI.ModeSense6Data = null; + SCSI.ModeSense10Data = null; + SCSI.ModeSense6CurrentData = null; + SCSI.ModeSense10CurrentData = null; + SCSI.ModeSense6ChangeableData = null; + SCSI.ModeSense10ChangeableData = null; + SCSI.ReadCapabilities = ClearBinaries(SCSI.ReadCapabilities); + + if(SCSI.ModeSense != null) + { + SCSI.ModeSense.BlockDescriptors = null; + SCSI.ModeSense.ModePages = null; + } + + if(SCSI.RemovableMedias != null) + { + TestedMedia[] medias = SCSI.RemovableMedias.ToArray(); + SCSI.RemovableMedias = []; + + foreach(TestedMedia media in medias) SCSI.RemovableMedias.Add(ClearBinaries(media)); + } + + if(SCSI.MultiMediaDevice != null) + { + SCSI.MultiMediaDevice.ModeSense2AData = null; + + if(SCSI.MultiMediaDevice.Features != null) SCSI.MultiMediaDevice.Features.BinaryData = null; + + if(SCSI.MultiMediaDevice.TestedMedia != null) + { + TestedMedia[] medias = SCSI.MultiMediaDevice.TestedMedia.ToArray(); + SCSI.MultiMediaDevice.TestedMedia = []; + + foreach(TestedMedia media in medias) SCSI.MultiMediaDevice.TestedMedia.Add(ClearBinaries(media)); + } + } + + SCSI.SequentialDevice = null; + } + + if(USB != null) USB.Descriptors = null; + + Id = id; + OptimalMultipleSectorsRead = optimalMultipleSectorsRead; + CanReadGdRomUsingSwapDisc = canReadGdRomUsingSwapDisc; + } + + /// Optimal maximum number of transfer blocks to read + public int OptimalMultipleSectorsRead { get; set; } + + /// Can read GD-ROM using disc swap trick? + public bool? CanReadGdRomUsingSwapDisc { get; set; } + + /// Database ID + public new int Id { get; set; } + + static TestedMedia ClearBinaries(TestedMedia media) + { + if(media is null) return null; + + media.AdipData = null; + media.AtipData = null; + media.BluBcaData = null; + media.BluDdsData = null; + media.BluDiData = null; + media.BluPacData = null; + media.BluSaiData = null; + media.C2PointersData = null; + media.CmiData = null; + media.CorrectedSubchannelData = null; + media.CorrectedSubchannelWithC2Data = null; + media.DcbData = null; + media.DmiData = null; + media.DvdAacsData = null; + media.DvdBcaData = null; + media.DvdDdsData = null; + media.DvdLayerData = null; + media.DvdSaiData = null; + media.EmbossedPfiData = null; + media.FullTocData = null; + media.HdCmiData = null; + media.HLDTSTReadRawDVDData = null; + media.IdentifyData = null; + media.LeadInData = null; + media.LeadOutData = null; + media.ModeSense6Data = null; + media.ModeSense10Data = null; + media.NecReadCddaData = null; + media.PfiData = null; + media.PioneerReadCddaData = null; + media.PioneerReadCddaMsfData = null; + media.PlextorReadCddaData = null; + media.PlextorReadRawDVDData = null; + media.PmaData = null; + media.PQSubchannelData = null; + media.PQSubchannelWithC2Data = null; + media.PriData = null; + media.Read6Data = null; + media.Read10Data = null; + media.Read12Data = null; + media.Read16Data = null; + media.ReadCdData = null; + media.ReadCdFullData = null; + media.ReadCdMsfData = null; + media.ReadCdMsfFullData = null; + media.ReadDmaData = null; + media.ReadDmaLba48Data = null; + media.ReadDmaLbaData = null; + media.ReadDmaRetryData = null; + media.ReadLba48Data = null; + media.ReadLbaData = null; + media.ReadLong10Data = null; + media.ReadLong16Data = null; + media.ReadLongData = null; + media.ReadLongLbaData = null; + media.ReadLongRetryData = null; + media.ReadLongRetryLbaData = null; + media.ReadRetryLbaData = null; + media.ReadSectorsData = null; + media.ReadSectorsRetryData = null; + media.RWSubchannelData = null; + media.RWSubchannelWithC2Data = null; + media.TocData = null; + media.Track1PregapData = null; + + return media; + } +} \ No newline at end of file diff --git a/Aaru.Dto/NesHeaderDto.cs b/Aaru.Dto/NesHeaderDto.cs new file mode 100644 index 000000000..cb96530f6 --- /dev/null +++ b/Aaru.Dto/NesHeaderDto.cs @@ -0,0 +1,45 @@ +using Aaru.CommonTypes.Enums; + +namespace Aaru.Dto; + +/// DTO for iNES/NES 2.0 headers +public class NesHeaderDto +{ + public int Id { get; set; } + + /// ROM hash + public string Sha256 { get; set; } + + /// If true vertical mirroring is hard-wired, horizontal or mapper defined otherwise + public bool NametableMirroring { get; set; } + + /// If true a battery is present + public bool BatteryPresent { get; set; } + + /// If true the four player screen mode is hardwired + public bool FourScreenMode { get; set; } + + /// Mapper number (NES 2.0 when in conflict) + public ushort Mapper { get; set; } + + /// Console type + public NesConsoleType ConsoleType { get; set; } + + /// Submapper number + public byte Submapper { get; set; } + + /// Timing mode + public NesTimingMode TimingMode { get; set; } + + /// Vs. PPU type + public NesVsPpuType VsPpuType { get; set; } + + /// Vs. hardware type + public NesVsHardwareType VsHardwareType { get; set; } + + /// Extended console type + public NesExtendedConsoleType ExtendedConsoleType { get; set; } + + /// Default expansion device + public NesDefaultExpansionDevice DefaultExpansionDevice { get; set; } +} \ No newline at end of file diff --git a/Aaru.Dto/SyncDto.cs b/Aaru.Dto/SyncDto.cs new file mode 100644 index 000000000..e2efe40d2 --- /dev/null +++ b/Aaru.Dto/SyncDto.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SyncDto.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// DTO for syncing server and client databases. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; + +namespace Aaru.Dto; + +/// DTO for database synchronization. +public class SyncDto +{ + /// List of USB vendors + public List UsbVendors { get; set; } + + /// List of USB products + public List UsbProducts { get; set; } + + /// List of CD read offsets + public List Offsets { get; set; } + + /// List of known devices + public List Devices { get; set; } + + /// List of known iNES/NES 2.0 headers + public List NesHeaders { get; set; } +} \ No newline at end of file diff --git a/Aaru.Dto/UsbProductDto.cs b/Aaru.Dto/UsbProductDto.cs new file mode 100644 index 000000000..8c1b15082 --- /dev/null +++ b/Aaru.Dto/UsbProductDto.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : UsbProductDto.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// DTO for syncing USB product identifiers in database. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Dto; + +/// DTO for USB product field +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public class UsbProductDto +{ + /// Database ID + public int Id { get; set; } + + /// Product ID + public ushort ProductId { get; set; } + + /// Product name + public string Product { get; set; } + + /// Vendor ID + public ushort VendorId { get; set; } +} \ No newline at end of file diff --git a/Aaru.Dto/UsbVendorDto.cs b/Aaru.Dto/UsbVendorDto.cs new file mode 100644 index 000000000..ca456c45a --- /dev/null +++ b/Aaru.Dto/UsbVendorDto.cs @@ -0,0 +1,43 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : UsbVendorDto.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru Server. +// +// --[ Description ] ---------------------------------------------------------- +// +// DTO for syncing USB vendor identifiers in database. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Dto; + +/// DTO for USB vendor field +public class UsbVendorDto +{ + /// Vendor ID + public ushort VendorId { get; set; } + + /// Vendor + public string Vendor { get; set; } +} \ No newline at end of file diff --git a/Aaru.Filesystems/AODOS.cs b/Aaru.Filesystems/AODOS.cs deleted file mode 100644 index de8632361..000000000 --- a/Aaru.Filesystems/AODOS.cs +++ /dev/null @@ -1,150 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : AODOS.cs -// Author(s) : Natalia Portillo -// -// Component : Commodore file system plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the AO-DOS file system and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Information has been extracted looking at available disk images -// This may be missing fields, or not, I don't know russian so any help is appreciated -/// -/// Implements detection of the AO-DOS filesystem -public sealed class AODOS : IFilesystem -{ - readonly byte[] _identifier = - { - 0x20, 0x41, 0x4F, 0x2D, 0x44, 0x4F, 0x53, 0x20 - }; - /// - public FileSystemType XmlFsType { get; private set; } - /// - public string Name => "Alexander Osipov DOS file system"; - /// - public Guid Id => new("668E5039-9DDD-442A-BE1B-A315D6E38E26"); - /// - public Encoding Encoding { get; private set; } - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - // Does AO-DOS support hard disks? - if(partition.Start > 0) - return false; - - // How is it really? - if(imagePlugin.Info.SectorSize != 512) - return false; - - // Does AO-DOS support any other kind of disk? - if(imagePlugin.Info.Sectors != 800 && - imagePlugin.Info.Sectors != 1600) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(0, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - BootBlock bb = Marshal.ByteArrayToStructureLittleEndian(sector); - - return bb.identifier.SequenceEqual(_identifier); - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - information = ""; - Encoding = Encoding.GetEncoding("koi8-r"); - ErrorNumber errno = imagePlugin.ReadSector(0, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - BootBlock bb = Marshal.ByteArrayToStructureLittleEndian(sector); - - var sbInformation = new StringBuilder(); - - sbInformation.AppendLine("Alexander Osipov DOS file system"); - - XmlFsType = new FileSystemType - { - Type = "Alexander Osipov DOS file system", - Clusters = imagePlugin.Info.Sectors, - ClusterSize = imagePlugin.Info.SectorSize, - Files = bb.files, - FilesSpecified = true, - FreeClusters = imagePlugin.Info.Sectors - bb.usedSectors, - FreeClustersSpecified = true, - VolumeName = StringHandlers.SpacePaddedToString(bb.volumeLabel, Encoding), - Bootable = true - }; - - sbInformation.AppendFormat("{0} files on volume", bb.files).AppendLine(); - sbInformation.AppendFormat("{0} used sectors on volume", bb.usedSectors).AppendLine(); - - sbInformation.AppendFormat("Disk name: {0}", StringHandlers.CToString(bb.volumeLabel, Encoding)).AppendLine(); - - information = sbInformation.ToString(); - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct BootBlock - { - /// A NOP opcode - public readonly byte nop; - /// A branch to real bootloader - public readonly ushort branch; - /// Unused - public readonly byte unused; - /// " AO-DOS " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] identifier; - /// Volume label - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] volumeLabel; - /// How many files are present in disk - public readonly ushort files; - /// How many sectors are used - public readonly ushort usedSectors; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/AODOS/AODOS.cs b/Aaru.Filesystems/AODOS/AODOS.cs new file mode 100644 index 000000000..7d3be5764 --- /dev/null +++ b/Aaru.Filesystems/AODOS/AODOS.cs @@ -0,0 +1,56 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : AODOS.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the AO-DOS file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information has been extracted looking at available disk images +// This may be missing fields, or not, I don't know russian so any help is appreciated +/// +/// Implements detection of the AO-DOS filesystem +public sealed partial class AODOS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.AODOS_Name; + + /// + public Guid Id => new("668E5039-9DDD-442A-BE1B-A315D6E38E26"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/AODOS/Consts.cs b/Aaru.Filesystems/AODOS/Consts.cs new file mode 100644 index 000000000..aa15d75a8 --- /dev/null +++ b/Aaru.Filesystems/AODOS/Consts.cs @@ -0,0 +1,43 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the AO-DOS file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Information has been extracted looking at available disk images +// This may be missing fields, or not, I don't know russian so any help is appreciated +/// +/// Implements detection of the AO-DOS filesystem +public sealed partial class AODOS +{ + const string FS_TYPE = "aodos"; + readonly byte[] _identifier = " AO-DOS "u8.ToArray(); +} \ No newline at end of file diff --git a/Aaru.Filesystems/AODOS/Info.cs b/Aaru.Filesystems/AODOS/Info.cs new file mode 100644 index 000000000..f11ec32d3 --- /dev/null +++ b/Aaru.Filesystems/AODOS/Info.cs @@ -0,0 +1,110 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the AO-DOS file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Linq; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information has been extracted looking at available disk images +// This may be missing fields, or not, I don't know russian so any help is appreciated +/// +/// Implements detection of the AO-DOS filesystem +public sealed partial class AODOS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + // Does AO-DOS support hard disks? + if(partition.Start > 0) return false; + + // How is it really? + if(imagePlugin.Info.SectorSize != 512) return false; + + // Does AO-DOS support any other kind of disk? + if(imagePlugin.Info.Sectors != 800 && imagePlugin.Info.Sectors != 1600) return false; + + ErrorNumber errno = imagePlugin.ReadSector(0, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + BootBlock bb = Marshal.ByteArrayToStructureLittleEndian(sector); + + return bb.identifier.SequenceEqual(_identifier); + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + encoding = Encoding.GetEncoding("koi8-r"); + ErrorNumber errno = imagePlugin.ReadSector(0, out byte[] sector); + metadata = new FileSystem(); + + if(errno != ErrorNumber.NoError) return; + + BootBlock bb = Marshal.ByteArrayToStructureLittleEndian(sector); + + var sbInformation = new StringBuilder(); + + sbInformation.AppendLine(Localization.Alexander_Osipov_DOS_file_system); + + metadata = new FileSystem + { + Type = FS_TYPE, + Clusters = imagePlugin.Info.Sectors, + ClusterSize = imagePlugin.Info.SectorSize, + Files = bb.files, + FreeClusters = imagePlugin.Info.Sectors - bb.usedSectors, + VolumeName = StringHandlers.SpacePaddedToString(bb.volumeLabel, encoding), + Bootable = true + }; + + sbInformation.AppendFormat(Localization._0_files_in_volume, bb.files).AppendLine(); + sbInformation.AppendFormat(Localization._0_used_sectors_on_volume, bb.usedSectors).AppendLine(); + + sbInformation.AppendFormat(Localization.Disk_name_0, StringHandlers.CToString(bb.volumeLabel, encoding)) + .AppendLine(); + + information = sbInformation.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/AODOS/Structs.cs b/Aaru.Filesystems/AODOS/Structs.cs new file mode 100644 index 000000000..500b44645 --- /dev/null +++ b/Aaru.Filesystems/AODOS/Structs.cs @@ -0,0 +1,67 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the AO-DOS file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Information has been extracted looking at available disk images +// This may be missing fields, or not, I don't know russian so any help is appreciated +/// +/// Implements detection of the AO-DOS filesystem +public sealed partial class AODOS +{ +#region Nested type: BootBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct BootBlock + { + /// A NOP opcode + public readonly byte nop; + /// A branch to real bootloader + public readonly ushort branch; + /// Unused + public readonly byte unused; + /// " AO-DOS " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] identifier; + /// Volume label + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] volumeLabel; + /// How many files are present in disk + public readonly ushort files; + /// How many sectors are used + public readonly ushort usedSectors; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/APFS/APFS.cs b/Aaru.Filesystems/APFS/APFS.cs new file mode 100644 index 000000000..6a5914e91 --- /dev/null +++ b/Aaru.Filesystems/APFS/APFS.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : APFS.cs +// Author(s) : Natalia Portillo +// +// Component : Apple filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Apple File System (APFS) +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class APFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.APFS_Name; + + /// + public Guid Id => new("A4060F9D-2909-42E2-9D95-DB31FA7EA797"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/APFS/Consts.cs b/Aaru.Filesystems/APFS/Consts.cs new file mode 100644 index 000000000..7e08614ad --- /dev/null +++ b/Aaru.Filesystems/APFS/Consts.cs @@ -0,0 +1,41 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Apple filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Apple File System (APFS) +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class APFS +{ + const uint APFS_CONTAINER_MAGIC = 0x4253584E; // "NXSB" + const uint APFS_VOLUME_MAGIC = 0x42535041; // "APSB" + const string FS_TYPE = "apfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/APFS.cs b/Aaru.Filesystems/APFS/Info.cs similarity index 54% rename from Aaru.Filesystems/APFS.cs rename to Aaru.Filesystems/APFS/Info.cs index 9de47325e..c4a5d9e7b 100644 --- a/Aaru.Filesystems/APFS.cs +++ b/Aaru.Filesystems/APFS/Info.cs @@ -2,15 +2,11 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : APFS.cs +// Filename : Info.cs // Author(s) : Natalia Portillo // // Component : Apple filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Apple filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,50 +23,34 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - -using System; using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; /// /// Implements detection of the Apple File System (APFS) [SuppressMessage("ReSharper", "UnusedMember.Local")] -public sealed class APFS : IFilesystem +public sealed partial class APFS { - const uint APFS_CONTAINER_MAGIC = 0x4253584E; // "NXSB" - const uint APFS_VOLUME_MAGIC = 0x42535041; // "APSB" - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Apple File System"; - /// - public Guid Id => new("A4060F9D-2909-42E2-9D95-DB31FA7EA797"); - /// - public string Author => "Natalia Portillo"; +#region IFilesystem Members /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(partition.Start >= partition.End) - return false; + if(partition.Start >= partition.End) return false; ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; ContainerSuperBlock nxSb; @@ -87,20 +67,18 @@ public sealed class APFS : IFilesystem } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = Encoding.UTF8; var sbInformation = new StringBuilder(); - XmlFsType = new FileSystemType(); + metadata = new FileSystem(); information = ""; - if(partition.Start >= partition.End) - return; + if(partition.Start >= partition.End) return; ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; ContainerSuperBlock nxSb; @@ -113,36 +91,27 @@ public sealed class APFS : IFilesystem return; } - if(nxSb.magic != APFS_CONTAINER_MAGIC) - return; + if(nxSb.magic != APFS_CONTAINER_MAGIC) return; - sbInformation.AppendLine("Apple File System"); + sbInformation.AppendLine(Localization.Apple_File_System); sbInformation.AppendLine(); - sbInformation.AppendFormat("{0} bytes per block", nxSb.blockSize).AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_per_block, nxSb.blockSize).AppendLine(); - sbInformation.AppendFormat("Container has {0} bytes in {1} blocks", nxSb.containerBlocks * nxSb.blockSize, - nxSb.containerBlocks).AppendLine(); + sbInformation.AppendFormat(Localization.Container_has_0_bytes_in_1_blocks, + nxSb.containerBlocks * nxSb.blockSize, + nxSb.containerBlocks) + .AppendLine(); information = sbInformation.ToString(); - XmlFsType = new FileSystemType + metadata = new FileSystem { Bootable = false, Clusters = nxSb.containerBlocks, ClusterSize = nxSb.blockSize, - Type = "Apple File System" + Type = FS_TYPE }; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ContainerSuperBlock - { - public readonly ulong unknown1; // Varies between copies of the superblock - public readonly ulong unknown2; - public readonly ulong unknown3; // Varies by 1 between copies of the superblock - public readonly ulong unknown4; - public readonly uint magic; - public readonly uint blockSize; - public readonly ulong containerBlocks; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/APFS/Structs.cs b/Aaru.Filesystems/APFS/Structs.cs new file mode 100644 index 000000000..6fe51d965 --- /dev/null +++ b/Aaru.Filesystems/APFS/Structs.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Apple filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Apple File System (APFS) +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class APFS +{ +#region Nested type: ContainerSuperBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ContainerSuperBlock + { + public readonly ulong unknown1; // Varies between copies of the superblock + public readonly ulong unknown2; + public readonly ulong unknown3; // Varies by 1 between copies of the superblock + public readonly ulong unknown4; + public readonly uint magic; + public readonly uint blockSize; + public readonly ulong containerBlocks; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Aaru.Filesystems.csproj b/Aaru.Filesystems/Aaru.Filesystems.csproj index 093245d1a..66e4f9e99 100644 --- a/Aaru.Filesystems/Aaru.Filesystems.csproj +++ b/Aaru.Filesystems/Aaru.Filesystems.csproj @@ -1,288 +1,121 @@  - - Debug - AnyCPU - 2.0 - {D7016DF2-5A5E-4524-B40D-BA2D59576688} - Library - Aaru.Filesystems - Aaru.Filesystems - $(Version) - false - true - 6.0.0-alpha8 - Claunia.com - Copyright © 2011-2022 Natalia Portillo - Aaru Data Preservation Suite - Aaru.Filesystems - $(Version) - net6.0 - CS0649 - 10 - Filesystem implementations used by the Aaru Data Preservation Suite. - https://github.com/aaru-dps/ - LGPL-2.1-only - https://github.com/aaru-dps/Aaru - true - en-US - true - true - snupkg - Natalia Portillo <claunia@claunia.com> - true - - - $(Version)+{chash:8} - true - true - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - full - true - bin\Release - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LICENSE.LGPL - - - - - - - - - - - - - - - - - - - - - /Library/Frameworks/Mono.framework/Versions/Current/lib/mono - /usr/lib/mono - /usr/local/lib/mono - - $(BaseFrameworkPathOverrideForMono)/4.0-api - $(BaseFrameworkPathOverrideForMono)/4.5-api - $(BaseFrameworkPathOverrideForMono)/4.5.1-api - $(BaseFrameworkPathOverrideForMono)/4.5.2-api - $(BaseFrameworkPathOverrideForMono)/4.6-api - $(BaseFrameworkPathOverrideForMono)/4.6.1-api - $(BaseFrameworkPathOverrideForMono)/4.6.2-api - $(BaseFrameworkPathOverrideForMono)/4.7-api - $(BaseFrameworkPathOverrideForMono)/4.7.1-api - true - - $(FrameworkPathOverride)/Facades;$(AssemblySearchPaths) - + + 2.0 + {D7016DF2-5A5E-4524-B40D-BA2D59576688} + Library + Aaru.Filesystems + Aaru.Filesystems + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Filesystems + $(Version) + net8.0 + CS0649 + 12 + Filesystem implementations used by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + LGPL-2.1-only + https://github.com/aaru-dps/Aaru + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + + LICENSE.LGPL + + + + ResXFileCodeGenerator + Localization.Designer.cs + + + + + \ No newline at end of file diff --git a/Aaru.Filesystems/Aaru.Filesystems.csproj.DotSettings b/Aaru.Filesystems/Aaru.Filesystems.csproj.DotSettings index 36f7cc74a..4cbd7fcd6 100644 --- a/Aaru.Filesystems/Aaru.Filesystems.csproj.DotSettings +++ b/Aaru.Filesystems/Aaru.Filesystems.csproj.DotSettings @@ -1,13 +1,130 @@ - - True - True - True - True - True - True - True - True - True - True - True - True \ No newline at end of file + + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True \ No newline at end of file diff --git a/Aaru.Filesystems/Acorn.cs b/Aaru.Filesystems/Acorn.cs deleted file mode 100644 index b0abfcd68..000000000 --- a/Aaru.Filesystems/Acorn.cs +++ /dev/null @@ -1,840 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Acorn.cs -// Author(s) : Natalia Portillo -// -// Component : Acorn filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Acorn filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of Acorn's Advanced Data Filing System (ADFS) -public sealed class AcornADFS : IFilesystem -{ - /// Location for boot block, in bytes - const ulong BOOT_BLOCK_LOCATION = 0xC00; - /// Size of boot block, in bytes - const uint BOOT_BLOCK_SIZE = 0x200; - /// Location of new directory, in bytes - const ulong NEW_DIRECTORY_LOCATION = 0x400; - /// Location of old directory, in bytes - const ulong OLD_DIRECTORY_LOCATION = 0x200; - /// Size of old directory - const uint OLD_DIRECTORY_SIZE = 1280; - /// Size of new directory - const uint NEW_DIRECTORY_SIZE = 2048; - - /// New directory format magic number, "Nick" - const uint NEW_DIR_MAGIC = 0x6B63694E; - /// Old directory format magic number, "Hugo" - const uint OLD_DIR_MAGIC = 0x6F677548; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public string Name => "Acorn Advanced Disc Filing System"; - /// - public Guid Id => new("BAFC1E50-9C64-4CD3-8400-80628CC27AFA"); - /// - public Encoding Encoding { get; private set; } - /// - public string Author => "Natalia Portillo"; - - // TODO: BBC Master hard disks are untested... - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start >= partition.End) - return false; - - ulong sbSector; - uint sectorsToRead; - - if(imagePlugin.Info.SectorSize < 256) - return false; - - byte[] sector; - ErrorNumber errno; - - // ADFS-S, ADFS-M, ADFS-L, ADFS-D without partitions - if(partition.Start == 0) - { - errno = imagePlugin.ReadSector(0, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - byte oldChk0 = AcornMapChecksum(sector, 255); - OldMapSector0 oldMap0 = Marshal.ByteArrayToStructureLittleEndian(sector); - - errno = imagePlugin.ReadSector(1, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - byte oldChk1 = AcornMapChecksum(sector, 255); - OldMapSector1 oldMap1 = Marshal.ByteArrayToStructureLittleEndian(sector); - - AaruConsole.DebugWriteLine("ADFS Plugin", "oldMap0.checksum = {0}", oldMap0.checksum); - AaruConsole.DebugWriteLine("ADFS Plugin", "oldChk0 = {0}", oldChk0); - - // According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400) - if(oldMap0.checksum == oldChk0 && - oldMap1.checksum != oldChk1 && - sector.Length >= 512) - { - errno = imagePlugin.ReadSector(0, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - var tmp = new byte[256]; - Array.Copy(sector, 256, tmp, 0, 256); - oldChk1 = AcornMapChecksum(tmp, 255); - oldMap1 = Marshal.ByteArrayToStructureLittleEndian(tmp); - } - - AaruConsole.DebugWriteLine("ADFS Plugin", "oldMap1.checksum = {0}", oldMap1.checksum); - AaruConsole.DebugWriteLine("ADFS Plugin", "oldChk1 = {0}", oldChk1); - - if(oldMap0.checksum == oldChk0 && - oldMap1.checksum == oldChk1 && - oldMap0.checksum != 0 && - oldMap1.checksum != 0) - { - sbSector = OLD_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize; - sectorsToRead = OLD_DIRECTORY_SIZE / imagePlugin.Info.SectorSize; - - if(OLD_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0) - sectorsToRead++; - - errno = imagePlugin.ReadSectors(sbSector, sectorsToRead, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length > OLD_DIRECTORY_SIZE) - { - var tmp = new byte[OLD_DIRECTORY_SIZE]; - Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53); - Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53); - sector = tmp; - } - - OldDirectory oldRoot = Marshal.ByteArrayToStructureLittleEndian(sector); - byte dirChk = AcornDirectoryChecksum(sector, (int)OLD_DIRECTORY_SIZE - 1); - - AaruConsole.DebugWriteLine("ADFS Plugin", "oldRoot.header.magic at 0x200 = {0}", oldRoot.header.magic); - - AaruConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.magic at 0x200 = {0}", oldRoot.tail.magic); - - AaruConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.checkByte at 0x200 = {0}", - oldRoot.tail.checkByte); - - AaruConsole.DebugWriteLine("ADFS Plugin", "dirChk at 0x200 = {0}", dirChk); - - if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC || - oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC) - return true; - - // RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that... - sbSector = NEW_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize; - sectorsToRead = NEW_DIRECTORY_SIZE / imagePlugin.Info.SectorSize; - - if(NEW_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0) - sectorsToRead++; - - errno = imagePlugin.ReadSectors(sbSector, sectorsToRead, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length > OLD_DIRECTORY_SIZE) - { - var tmp = new byte[OLD_DIRECTORY_SIZE]; - Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53); - Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53); - sector = tmp; - } - - oldRoot = Marshal.ByteArrayToStructureLittleEndian(sector); - dirChk = AcornDirectoryChecksum(sector, (int)OLD_DIRECTORY_SIZE - 1); - - AaruConsole.DebugWriteLine("ADFS Plugin", "oldRoot.header.magic at 0x400 = {0}", oldRoot.header.magic); - - AaruConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.magic at 0x400 = {0}", oldRoot.tail.magic); - - AaruConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.checkByte at 0x400 = {0}", - oldRoot.tail.checkByte); - - AaruConsole.DebugWriteLine("ADFS Plugin", "dirChk at 0x400 = {0}", dirChk); - - if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC || - oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC) - return true; - } - } - - // Partitioning or not, new formats follow: - DiscRecord drSb; - - errno = imagePlugin.ReadSector(partition.Start, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - byte newChk = NewMapChecksum(sector); - AaruConsole.DebugWriteLine("ADFS Plugin", "newChk = {0}", newChk); - AaruConsole.DebugWriteLine("ADFS Plugin", "map.zoneChecksum = {0}", sector[0]); - - sbSector = BOOT_BLOCK_LOCATION / imagePlugin.Info.SectorSize; - sectorsToRead = BOOT_BLOCK_SIZE / imagePlugin.Info.SectorSize; - - if(BOOT_BLOCK_SIZE % imagePlugin.Info.SectorSize > 0) - sectorsToRead++; - - if(sbSector + partition.Start + sectorsToRead >= partition.End) - return false; - - errno = imagePlugin.ReadSectors(sbSector + partition.Start, sectorsToRead, out byte[] bootSector); - - if(errno != ErrorNumber.NoError) - return false; - - var bootChk = 0; - - if(bootSector.Length < 512) - return false; - - for(var i = 0; i < 0x1FF; i++) - bootChk = (bootChk & 0xFF) + (bootChk >> 8) + bootSector[i]; - - AaruConsole.DebugWriteLine("ADFS Plugin", "bootChk = {0}", bootChk); - AaruConsole.DebugWriteLine("ADFS Plugin", "bBlock.checksum = {0}", bootSector[0x1FF]); - - if(newChk == sector[0] && - newChk != 0) - { - NewMap nmap = Marshal.ByteArrayToStructureLittleEndian(sector); - drSb = nmap.discRecord; - } - else if(bootChk == bootSector[0x1FF]) - { - BootBlock bBlock = Marshal.ByteArrayToStructureLittleEndian(bootSector); - drSb = bBlock.discRecord; - } - else - return false; - - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.log2secsize = {0}", drSb.log2secsize); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.idlen = {0}", drSb.idlen); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size_high = {0}", drSb.disc_size_high); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size = {0}", drSb.disc_size); - - AaruConsole.DebugWriteLine("ADFS Plugin", "IsNullOrEmpty(drSb.reserved) = {0}", - ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved)); - - if(drSb.log2secsize is < 8 or > 10) - return false; - - if(drSb.idlen < drSb.log2secsize + 3 || - drSb.idlen > 19) - return false; - - if(drSb.disc_size_high >> drSb.log2secsize != 0) - return false; - - if(!ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved)) - return false; - - ulong bytes = drSb.disc_size_high; - bytes *= 0x100000000; - bytes += drSb.disc_size; - - return bytes <= imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize; - } - - // TODO: Find root directory on volumes with DiscRecord - // TODO: Support big directories (ADFS-G?) - // TODO: Find the real freemap on volumes with DiscRecord, as DiscRecord's discid may be empty but this one isn't - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); - var sbInformation = new StringBuilder(); - XmlFsType = new FileSystemType(); - information = ""; - ErrorNumber errno; - - ulong sbSector; - byte[] sector; - uint sectorsToRead; - ulong bytes; - - // ADFS-S, ADFS-M, ADFS-L, ADFS-D without partitions - if(partition.Start == 0) - { - errno = imagePlugin.ReadSector(0, out sector); - - if(errno != ErrorNumber.NoError) - return; - - byte oldChk0 = AcornMapChecksum(sector, 255); - OldMapSector0 oldMap0 = Marshal.ByteArrayToStructureLittleEndian(sector); - - errno = imagePlugin.ReadSector(1, out sector); - - if(errno != ErrorNumber.NoError) - return; - - byte oldChk1 = AcornMapChecksum(sector, 255); - OldMapSector1 oldMap1 = Marshal.ByteArrayToStructureLittleEndian(sector); - - // According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400) - if(oldMap0.checksum == oldChk0 && - oldMap1.checksum != oldChk1 && - sector.Length >= 512) - { - errno = imagePlugin.ReadSector(0, out sector); - - if(errno != ErrorNumber.NoError) - return; - - var tmp = new byte[256]; - Array.Copy(sector, 256, tmp, 0, 256); - oldChk1 = AcornMapChecksum(tmp, 255); - oldMap1 = Marshal.ByteArrayToStructureLittleEndian(tmp); - } - - if(oldMap0.checksum == oldChk0 && - oldMap1.checksum == oldChk1 && - oldMap0.checksum != 0 && - oldMap1.checksum != 0) - { - bytes = (ulong)((oldMap0.size[2] << 16) + (oldMap0.size[1] << 8) + oldMap0.size[0]) * 256; - var namebytes = new byte[10]; - - for(var i = 0; i < 5; i++) - { - namebytes[i * 2] = oldMap0.name[i]; - namebytes[i * 2 + 1] = oldMap1.name[i]; - } - - XmlFsType = new FileSystemType - { - Bootable = oldMap1.boot != 0, // Or not? - Clusters = bytes / imagePlugin.Info.SectorSize, - ClusterSize = imagePlugin.Info.SectorSize, - Type = "Acorn Advanced Disc Filing System" - }; - - if(ArrayHelpers.ArrayIsNullOrEmpty(namebytes)) - { - sbSector = OLD_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize; - sectorsToRead = OLD_DIRECTORY_SIZE / imagePlugin.Info.SectorSize; - - if(OLD_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0) - sectorsToRead++; - - errno = imagePlugin.ReadSectors(sbSector, sectorsToRead, out sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length > OLD_DIRECTORY_SIZE) - { - var tmp = new byte[OLD_DIRECTORY_SIZE]; - Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53); - Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53); - sector = tmp; - } - - OldDirectory oldRoot = Marshal.ByteArrayToStructureLittleEndian(sector); - - if(oldRoot.header.magic == OLD_DIR_MAGIC && - oldRoot.tail.magic == OLD_DIR_MAGIC) - namebytes = oldRoot.tail.name; - else - { - // RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that... - sbSector = NEW_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize; - sectorsToRead = NEW_DIRECTORY_SIZE / imagePlugin.Info.SectorSize; - - if(NEW_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0) - sectorsToRead++; - - errno = imagePlugin.ReadSectors(sbSector, sectorsToRead, out sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length > OLD_DIRECTORY_SIZE) - { - var tmp = new byte[OLD_DIRECTORY_SIZE]; - Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53); - - Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53); - - sector = tmp; - } - - oldRoot = Marshal.ByteArrayToStructureLittleEndian(sector); - - if(oldRoot.header.magic == OLD_DIR_MAGIC && - oldRoot.tail.magic == OLD_DIR_MAGIC) - namebytes = oldRoot.tail.name; - else - { - errno = imagePlugin.ReadSectors(sbSector, sectorsToRead, out sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length > NEW_DIRECTORY_SIZE) - { - var tmp = new byte[NEW_DIRECTORY_SIZE]; - Array.Copy(sector, 0, tmp, 0, NEW_DIRECTORY_SIZE - 41); - - Array.Copy(sector, sector.Length - 42, tmp, NEW_DIRECTORY_SIZE - 42, 41); - - sector = tmp; - } - - NewDirectory newRoot = Marshal.ByteArrayToStructureLittleEndian(sector); - - if(newRoot.header.magic == NEW_DIR_MAGIC && - newRoot.tail.magic == NEW_DIR_MAGIC) - namebytes = newRoot.tail.title; - } - } - } - - sbInformation.AppendLine("Acorn Advanced Disc Filing System"); - sbInformation.AppendLine(); - sbInformation.AppendFormat("{0} bytes per sector", imagePlugin.Info.SectorSize).AppendLine(); - sbInformation.AppendFormat("Volume has {0} bytes", bytes).AppendLine(); - - sbInformation.AppendFormat("Volume name: {0}", StringHandlers.CToString(namebytes, Encoding)). - AppendLine(); - - if(oldMap1.discId > 0) - { - XmlFsType.VolumeSerial = $"{oldMap1.discId:X4}"; - sbInformation.AppendFormat("Volume ID: {0:X4}", oldMap1.discId).AppendLine(); - } - - if(!ArrayHelpers.ArrayIsNullOrEmpty(namebytes)) - XmlFsType.VolumeName = StringHandlers.CToString(namebytes, Encoding); - - information = sbInformation.ToString(); - - return; - } - } - - // Partitioning or not, new formats follow: - DiscRecord drSb; - - errno = imagePlugin.ReadSector(partition.Start, out sector); - - if(errno != ErrorNumber.NoError) - return; - - byte newChk = NewMapChecksum(sector); - AaruConsole.DebugWriteLine("ADFS Plugin", "newChk = {0}", newChk); - AaruConsole.DebugWriteLine("ADFS Plugin", "map.zoneChecksum = {0}", sector[0]); - - sbSector = BOOT_BLOCK_LOCATION / imagePlugin.Info.SectorSize; - sectorsToRead = BOOT_BLOCK_SIZE / imagePlugin.Info.SectorSize; - - if(BOOT_BLOCK_SIZE % imagePlugin.Info.SectorSize > 0) - sectorsToRead++; - - errno = imagePlugin.ReadSectors(sbSector + partition.Start, sectorsToRead, out byte[] bootSector); - - if(errno != ErrorNumber.NoError) - return; - - var bootChk = 0; - - for(var i = 0; i < 0x1FF; i++) - bootChk = (bootChk & 0xFF) + (bootChk >> 8) + bootSector[i]; - - AaruConsole.DebugWriteLine("ADFS Plugin", "bootChk = {0}", bootChk); - AaruConsole.DebugWriteLine("ADFS Plugin", "bBlock.checksum = {0}", bootSector[0x1FF]); - - if(newChk == sector[0] && - newChk != 0) - { - NewMap nmap = Marshal.ByteArrayToStructureLittleEndian(sector); - drSb = nmap.discRecord; - } - else if(bootChk == bootSector[0x1FF]) - { - BootBlock bBlock = Marshal.ByteArrayToStructureLittleEndian(bootSector); - drSb = bBlock.discRecord; - } - else - return; - - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.log2secsize = {0}", drSb.log2secsize); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.spt = {0}", drSb.spt); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.heads = {0}", drSb.heads); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.density = {0}", drSb.density); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.idlen = {0}", drSb.idlen); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.log2bpmb = {0}", drSb.log2bpmb); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.skew = {0}", drSb.skew); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.bootoption = {0}", drSb.bootoption); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.lowsector = {0}", drSb.lowsector); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.nzones = {0}", drSb.nzones); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.zone_spare = {0}", drSb.zone_spare); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.root = {0}", drSb.root); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size = {0}", drSb.disc_size); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_id = {0}", drSb.disc_id); - - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_name = {0}", - StringHandlers.CToString(drSb.disc_name, Encoding)); - - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_type = {0}", drSb.disc_type); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size_high = {0}", drSb.disc_size_high); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.flags = {0}", drSb.flags); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.nzones_high = {0}", drSb.nzones_high); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.format_version = {0}", drSb.format_version); - AaruConsole.DebugWriteLine("ADFS Plugin", "drSb.root_size = {0}", drSb.root_size); - - if(drSb.log2secsize is < 8 or > 10) - return; - - if(drSb.idlen < drSb.log2secsize + 3 || - drSb.idlen > 19) - return; - - if(drSb.disc_size_high >> drSb.log2secsize != 0) - return; - - if(!ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved)) - return; - - bytes = drSb.disc_size_high; - bytes *= 0x100000000; - bytes += drSb.disc_size; - - ulong zones = drSb.nzones_high; - zones *= 0x100000000; - zones += drSb.nzones; - - if(bytes > imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize) - return; - - XmlFsType = new FileSystemType(); - - sbInformation.AppendLine("Acorn Advanced Disc Filing System"); - sbInformation.AppendLine(); - sbInformation.AppendFormat("Version {0}", drSb.format_version).AppendLine(); - sbInformation.AppendFormat("{0} bytes per sector", 1 << drSb.log2secsize).AppendLine(); - sbInformation.AppendFormat("{0} sectors per track", drSb.spt).AppendLine(); - sbInformation.AppendFormat("{0} heads", drSb.heads).AppendLine(); - sbInformation.AppendFormat("Density code: {0}", drSb.density).AppendLine(); - sbInformation.AppendFormat("Skew: {0}", drSb.skew).AppendLine(); - sbInformation.AppendFormat("Boot option: {0}", drSb.bootoption).AppendLine(); - - // TODO: What the hell is this field refering to? - sbInformation.AppendFormat("Root starts at frag {0}", drSb.root).AppendLine(); - - //sbInformation.AppendFormat("Root is {0} bytes long", drSb.root_size).AppendLine(); - sbInformation.AppendFormat("Volume has {0} bytes in {1} zones", bytes, zones).AppendLine(); - sbInformation.AppendFormat("Volume flags: 0x{0:X4}", drSb.flags).AppendLine(); - - if(drSb.disc_id > 0) - { - XmlFsType.VolumeSerial = $"{drSb.disc_id:X4}"; - sbInformation.AppendFormat("Volume ID: {0:X4}", drSb.disc_id).AppendLine(); - } - - if(!ArrayHelpers.ArrayIsNullOrEmpty(drSb.disc_name)) - { - string discname = StringHandlers.CToString(drSb.disc_name, Encoding); - XmlFsType.VolumeName = discname; - sbInformation.AppendFormat("Volume name: {0}", discname).AppendLine(); - } - - information = sbInformation.ToString(); - - XmlFsType.Bootable |= drSb.bootoption != 0; // Or not? - XmlFsType.Clusters = bytes / (ulong)(1 << drSb.log2secsize); - XmlFsType.ClusterSize = (uint)(1 << drSb.log2secsize); - XmlFsType.Type = "Acorn Advanced Disc Filing System"; - } - - byte AcornMapChecksum(byte[] data, int length) - { - var sum = 0; - var carry = 0; - - if(length > data.Length) - length = data.Length; - - // ADC r0, r0, r1 - // MOVS r0, r0, LSL #24 - // MOV r0, r0, LSR #24 - for(int i = length - 1; i >= 0; i--) - { - sum += data[i] + carry; - - if(sum > 0xFF) - { - carry = 1; - sum &= 0xFF; - } - else - carry = 0; - } - - return (byte)(sum & 0xFF); - } - - static byte NewMapChecksum(byte[] mapBase) - { - uint rover; - uint sumVector0 = 0; - uint sumVector1 = 0; - uint sumVector2 = 0; - uint sumVector3 = 0; - - for(rover = (uint)(mapBase.Length - 4); rover > 0; rover -= 4) - { - sumVector0 += mapBase[rover + 0] + (sumVector3 >> 8); - sumVector3 &= 0xff; - sumVector1 += mapBase[rover + 1] + (sumVector0 >> 8); - sumVector0 &= 0xff; - sumVector2 += mapBase[rover + 2] + (sumVector1 >> 8); - sumVector1 &= 0xff; - sumVector3 += mapBase[rover + 3] + (sumVector2 >> 8); - sumVector2 &= 0xff; - } - - /* - Don't add the check byte when calculating its value - */ - sumVector0 += sumVector3 >> 8; - sumVector1 += mapBase[1] + (sumVector0 >> 8); - sumVector2 += mapBase[2] + (sumVector1 >> 8); - sumVector3 += mapBase[3] + (sumVector2 >> 8); - - return (byte)((sumVector0 ^ sumVector1 ^ sumVector2 ^ sumVector3) & 0xff); - } - - // TODO: This is not correct... - static byte AcornDirectoryChecksum(IList data, int length) - { - uint sum = 0; - - if(length > data.Count) - length = data.Count; - - // EOR r0, r1, r0, ROR #13 - for(var i = 0; i < length; i++) - { - uint carry = sum & 0x1FFF; - sum >>= 13; - sum ^= data[i]; - sum += carry << 19; - } - - return (byte)(((sum & 0xFF000000) >> 24) ^ ((sum & 0xFF0000) >> 16) ^ ((sum & 0xFF00) >> 8) ^ (sum & 0xFF)); - } - - /// Boot block, used in hard disks and ADFS-F and higher. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct BootBlock - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1C0)] - public readonly byte[] spare; - public readonly DiscRecord discRecord; - public readonly byte flags; - public readonly ushort startCylinder; - public readonly byte checksum; - } - - /// Disc record, used in hard disks and ADFS-E and higher. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DiscRecord - { - public readonly byte log2secsize; - public readonly byte spt; - public readonly byte heads; - public readonly byte density; - public readonly byte idlen; - public readonly byte log2bpmb; - public readonly byte skew; - public readonly byte bootoption; - public readonly byte lowsector; - public readonly byte nzones; - public readonly ushort zone_spare; - public readonly uint root; - public readonly uint disc_size; - public readonly ushort disc_id; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public readonly byte[] disc_name; - public readonly uint disc_type; - public readonly uint disc_size_high; - public readonly byte flags; - public readonly byte nzones_high; - public readonly uint format_version; - public readonly uint root_size; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] reserved; - } - - /// Free block map, sector 0, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct OldMapSector0 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)] - public readonly byte[] freeStart; - public readonly byte reserved; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public readonly byte[] name; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] size; - public readonly byte checksum; - } - - /// Free block map, sector 1, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct OldMapSector1 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)] - public readonly byte[] freeStart; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public readonly byte[] name; - public readonly ushort discId; - public readonly byte boot; - public readonly byte freeEnd; - public readonly byte checksum; - } - - /// Free block map, sector 0, used in ADFS-E - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct NewMap - { - public readonly byte zoneChecksum; - public readonly ushort freeLink; - public readonly byte crossChecksum; - public readonly DiscRecord discRecord; - } - - /// Directory header, common to "old" and "new" directories - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DirectoryHeader - { - public readonly byte masterSequence; - public readonly uint magic; - } - - /// Directory header, common to "old" and "new" directories - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DirectoryEntry - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public readonly byte[] name; - public readonly uint load; - public readonly uint exec; - public readonly uint length; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] address; - public readonly byte atts; - } - - /// Directory tail, new format - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct NewDirectoryTail - { - public readonly byte lastMark; - public readonly ushort reserved; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] parent; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)] - public readonly byte[] title; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public readonly byte[] name; - public readonly byte endMasSeq; - public readonly uint magic; - public readonly byte checkByte; - } - - /// Directory tail, old format - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct OldDirectoryTail - { - public readonly byte lastMark; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public readonly byte[] name; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] parent; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)] - public readonly byte[] title; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] - public readonly byte[] reserved; - public readonly byte endMasSeq; - public readonly uint magic; - public readonly byte checkByte; - } - - /// Directory, old format - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct OldDirectory - { - public readonly DirectoryHeader header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 47)] - public readonly DirectoryEntry[] entries; - public readonly OldDirectoryTail tail; - } - - /// Directory, new format - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct NewDirectory - { - public readonly DirectoryHeader header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 77)] - public readonly DirectoryEntry[] entries; - public readonly NewDirectoryTail tail; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/Acorn/Acorn.cs b/Aaru.Filesystems/Acorn/Acorn.cs new file mode 100644 index 000000000..2ef47ed7b --- /dev/null +++ b/Aaru.Filesystems/Acorn/Acorn.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Acorn.cs +// Author(s) : Natalia Portillo +// +// Component : Acorn filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Acorn's Advanced Data Filing System (ADFS) +public sealed partial class AcornADFS : IFilesystem +{ + const string MODULE_NAME = "ADFS Plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.AcornADFS_Name; + + /// + public Guid Id => new("BAFC1E50-9C64-4CD3-8400-80628CC27AFA"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Acorn/Consts.cs b/Aaru.Filesystems/Acorn/Consts.cs new file mode 100644 index 000000000..9fbed2b33 --- /dev/null +++ b/Aaru.Filesystems/Acorn/Consts.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Acorn filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Acorn's Advanced Data Filing System (ADFS) +public sealed partial class AcornADFS +{ + /// Location for boot block, in bytes + const ulong BOOT_BLOCK_LOCATION = 0xC00; + /// Size of boot block, in bytes + const uint BOOT_BLOCK_SIZE = 0x200; + /// Location of new directory, in bytes + const ulong NEW_DIRECTORY_LOCATION = 0x400; + /// Location of old directory, in bytes + const ulong OLD_DIRECTORY_LOCATION = 0x200; + /// Size of old directory + const uint OLD_DIRECTORY_SIZE = 1280; + /// Size of new directory + const uint NEW_DIRECTORY_SIZE = 2048; + + /// New directory format magic number, "Nick" + const uint NEW_DIR_MAGIC = 0x6B63694E; + /// Old directory format magic number, "Hugo" + const uint OLD_DIR_MAGIC = 0x6F677548; + + const string FS_TYPE = "adfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/Acorn/Helpers.cs b/Aaru.Filesystems/Acorn/Helpers.cs new file mode 100644 index 000000000..11d4046c7 --- /dev/null +++ b/Aaru.Filesystems/Acorn/Helpers.cs @@ -0,0 +1,112 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Helpers.cs +// Author(s) : Natalia Portillo +// +// Component : Acorn filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Acorn's Advanced Data Filing System (ADFS) +public sealed partial class AcornADFS +{ + static byte AcornMapChecksum(byte[] data, int length) + { + var sum = 0; + var carry = 0; + + if(length > data.Length) length = data.Length; + + // ADC r0, r0, r1 + // MOVS r0, r0, LSL #24 + // MOV r0, r0, LSR #24 + for(int i = length - 1; i >= 0; i--) + { + sum += data[i] + carry; + + if(sum > 0xFF) + { + carry = 1; + sum &= 0xFF; + } + else + carry = 0; + } + + return (byte)(sum & 0xFF); + } + + static byte NewMapChecksum(byte[] mapBase) + { + uint rover; + uint sumVector0 = 0; + uint sumVector1 = 0; + uint sumVector2 = 0; + uint sumVector3 = 0; + + for(rover = (uint)(mapBase.Length - 4); rover > 0; rover -= 4) + { + sumVector0 += mapBase[rover + 0] + (sumVector3 >> 8); + sumVector3 &= 0xff; + sumVector1 += mapBase[rover + 1] + (sumVector0 >> 8); + sumVector0 &= 0xff; + sumVector2 += mapBase[rover + 2] + (sumVector1 >> 8); + sumVector1 &= 0xff; + sumVector3 += mapBase[rover + 3] + (sumVector2 >> 8); + sumVector2 &= 0xff; + } + + /* + Don't add the check byte when calculating its value + */ + sumVector0 += sumVector3 >> 8; + sumVector1 += mapBase[1] + (sumVector0 >> 8); + sumVector2 += mapBase[2] + (sumVector1 >> 8); + sumVector3 += mapBase[3] + (sumVector2 >> 8); + + return (byte)((sumVector0 ^ sumVector1 ^ sumVector2 ^ sumVector3) & 0xff); + } + + // TODO: This is not correct... + static byte AcornDirectoryChecksum(IList data, int length) + { + uint sum = 0; + + if(length > data.Count) length = data.Count; + + // EOR r0, r1, r0, ROR #13 + for(var i = 0; i < length; i++) + { + uint carry = sum & 0x1FFF; + sum >>= 13; + sum ^= data[i]; + sum += carry << 19; + } + + return (byte)((sum & 0xFF000000) >> 24 ^ (sum & 0xFF0000) >> 16 ^ (sum & 0xFF00) >> 8 ^ sum & 0xFF); + } +} \ No newline at end of file diff --git a/Aaru.Filesystems/Acorn/Info.cs b/Aaru.Filesystems/Acorn/Info.cs new file mode 100644 index 000000000..8bb1911f9 --- /dev/null +++ b/Aaru.Filesystems/Acorn/Info.cs @@ -0,0 +1,531 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Acorn filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Acorn's Advanced Data Filing System (ADFS) +public sealed partial class AcornADFS +{ +#region IFilesystem Members + + // TODO: BBC Master hard disks are untested... + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start >= partition.End) return false; + + ulong sbSector; + uint sectorsToRead; + + if(imagePlugin.Info.SectorSize < 256) return false; + + byte[] sector; + ErrorNumber errno; + + // ADFS-S, ADFS-M, ADFS-L, ADFS-D without partitions + if(partition.Start == 0) + { + errno = imagePlugin.ReadSector(0, out sector); + + if(errno != ErrorNumber.NoError) return false; + + byte oldChk0 = AcornMapChecksum(sector, 255); + OldMapSector0 oldMap0 = Marshal.ByteArrayToStructureLittleEndian(sector); + + errno = imagePlugin.ReadSector(1, out sector); + + if(errno != ErrorNumber.NoError) return false; + + byte oldChk1 = AcornMapChecksum(sector, 255); + OldMapSector1 oldMap1 = Marshal.ByteArrayToStructureLittleEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, "oldMap0.checksum = {0}", oldMap0.checksum); + AaruConsole.DebugWriteLine(MODULE_NAME, "oldChk0 = {0}", oldChk0); + + // According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400) + if(oldMap0.checksum == oldChk0 && oldMap1.checksum != oldChk1 && sector.Length >= 512) + { + errno = imagePlugin.ReadSector(0, out sector); + + if(errno != ErrorNumber.NoError) return false; + + var tmp = new byte[256]; + Array.Copy(sector, 256, tmp, 0, 256); + oldChk1 = AcornMapChecksum(tmp, 255); + oldMap1 = Marshal.ByteArrayToStructureLittleEndian(tmp); + } + + AaruConsole.DebugWriteLine(MODULE_NAME, "oldMap1.checksum = {0}", oldMap1.checksum); + AaruConsole.DebugWriteLine(MODULE_NAME, "oldChk1 = {0}", oldChk1); + + if(oldMap0.checksum == oldChk0 && + oldMap1.checksum == oldChk1 && + oldMap0.checksum != 0 && + oldMap1.checksum != 0) + { + sbSector = OLD_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize; + sectorsToRead = OLD_DIRECTORY_SIZE / imagePlugin.Info.SectorSize; + + if(OLD_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0) sectorsToRead++; + + errno = imagePlugin.ReadSectors(sbSector, sectorsToRead, out sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length > OLD_DIRECTORY_SIZE) + { + var tmp = new byte[OLD_DIRECTORY_SIZE]; + Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53); + Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53); + sector = tmp; + } + + OldDirectory oldRoot = Marshal.ByteArrayToStructureLittleEndian(sector); + byte dirChk = AcornDirectoryChecksum(sector, (int)OLD_DIRECTORY_SIZE - 1); + + AaruConsole.DebugWriteLine(MODULE_NAME, "oldRoot.header.magic at 0x200 = {0}", oldRoot.header.magic); + + AaruConsole.DebugWriteLine(MODULE_NAME, "oldRoot.tail.magic at 0x200 = {0}", oldRoot.tail.magic); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "oldRoot.tail.checkByte at 0x200 = {0}", + oldRoot.tail.checkByte); + + AaruConsole.DebugWriteLine(MODULE_NAME, "dirChk at 0x200 = {0}", dirChk); + + if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC || + oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC) + return true; + + // RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that... + sbSector = NEW_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize; + sectorsToRead = NEW_DIRECTORY_SIZE / imagePlugin.Info.SectorSize; + + if(NEW_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0) sectorsToRead++; + + errno = imagePlugin.ReadSectors(sbSector, sectorsToRead, out sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length > OLD_DIRECTORY_SIZE) + { + var tmp = new byte[OLD_DIRECTORY_SIZE]; + Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53); + Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53); + sector = tmp; + } + + oldRoot = Marshal.ByteArrayToStructureLittleEndian(sector); + dirChk = AcornDirectoryChecksum(sector, (int)OLD_DIRECTORY_SIZE - 1); + + AaruConsole.DebugWriteLine(MODULE_NAME, "oldRoot.header.magic at 0x400 = {0}", oldRoot.header.magic); + + AaruConsole.DebugWriteLine(MODULE_NAME, "oldRoot.tail.magic at 0x400 = {0}", oldRoot.tail.magic); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "oldRoot.tail.checkByte at 0x400 = {0}", + oldRoot.tail.checkByte); + + AaruConsole.DebugWriteLine(MODULE_NAME, "dirChk at 0x400 = {0}", dirChk); + + if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC || + oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC) + return true; + } + } + + // Partitioning or not, new formats follow: + DiscRecord drSb; + + errno = imagePlugin.ReadSector(partition.Start, out sector); + + if(errno != ErrorNumber.NoError) return false; + + byte newChk = NewMapChecksum(sector); + AaruConsole.DebugWriteLine(MODULE_NAME, "newChk = {0}", newChk); + AaruConsole.DebugWriteLine(MODULE_NAME, "map.zoneChecksum = {0}", sector[0]); + + sbSector = BOOT_BLOCK_LOCATION / imagePlugin.Info.SectorSize; + sectorsToRead = BOOT_BLOCK_SIZE / imagePlugin.Info.SectorSize; + + if(BOOT_BLOCK_SIZE % imagePlugin.Info.SectorSize > 0) sectorsToRead++; + + if(sbSector + partition.Start + sectorsToRead >= partition.End) return false; + + errno = imagePlugin.ReadSectors(sbSector + partition.Start, sectorsToRead, out byte[] bootSector); + + if(errno != ErrorNumber.NoError) return false; + + var bootChk = 0; + + if(bootSector.Length < 512) return false; + + for(var i = 0; i < 0x1FF; i++) bootChk = (bootChk & 0xFF) + (bootChk >> 8) + bootSector[i]; + + AaruConsole.DebugWriteLine(MODULE_NAME, "bootChk = {0}", bootChk); + AaruConsole.DebugWriteLine(MODULE_NAME, "bBlock.checksum = {0}", bootSector[0x1FF]); + + if(newChk == sector[0] && newChk != 0) + { + NewMap nmap = Marshal.ByteArrayToStructureLittleEndian(sector); + drSb = nmap.discRecord; + } + else if(bootChk == bootSector[0x1FF]) + { + BootBlock bBlock = Marshal.ByteArrayToStructureLittleEndian(bootSector); + drSb = bBlock.discRecord; + } + else + return false; + + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.log2secsize = {0}", drSb.log2secsize); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.idlen = {0}", drSb.idlen); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_size_high = {0}", drSb.disc_size_high); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_size = {0}", drSb.disc_size); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "IsNullOrEmpty(drSb.reserved) = {0}", + ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved)); + + if(drSb.log2secsize is < 8 or > 10) return false; + + if(drSb.idlen < drSb.log2secsize + 3 || drSb.idlen > 19) return false; + + if(drSb.disc_size_high >> drSb.log2secsize != 0) return false; + + if(!ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved)) return false; + + ulong bytes = drSb.disc_size_high; + bytes *= 0x100000000; + bytes += drSb.disc_size; + + return bytes <= imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize; + } + + // TODO: Find root directory on volumes with DiscRecord + // TODO: Support big directories (ADFS-G?) + // TODO: Find the real freemap on volumes with DiscRecord, as DiscRecord's discid may be empty but this one isn't + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-1"); + var sbInformation = new StringBuilder(); + metadata = new FileSystem(); + information = ""; + ErrorNumber errno; + + ulong sbSector; + byte[] sector; + uint sectorsToRead; + ulong bytes; + + // ADFS-S, ADFS-M, ADFS-L, ADFS-D without partitions + if(partition.Start == 0) + { + errno = imagePlugin.ReadSector(0, out sector); + + if(errno != ErrorNumber.NoError) return; + + byte oldChk0 = AcornMapChecksum(sector, 255); + OldMapSector0 oldMap0 = Marshal.ByteArrayToStructureLittleEndian(sector); + + errno = imagePlugin.ReadSector(1, out sector); + + if(errno != ErrorNumber.NoError) return; + + byte oldChk1 = AcornMapChecksum(sector, 255); + OldMapSector1 oldMap1 = Marshal.ByteArrayToStructureLittleEndian(sector); + + // According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400) + if(oldMap0.checksum == oldChk0 && oldMap1.checksum != oldChk1 && sector.Length >= 512) + { + errno = imagePlugin.ReadSector(0, out sector); + + if(errno != ErrorNumber.NoError) return; + + var tmp = new byte[256]; + Array.Copy(sector, 256, tmp, 0, 256); + oldChk1 = AcornMapChecksum(tmp, 255); + oldMap1 = Marshal.ByteArrayToStructureLittleEndian(tmp); + } + + if(oldMap0.checksum == oldChk0 && + oldMap1.checksum == oldChk1 && + oldMap0.checksum != 0 && + oldMap1.checksum != 0) + { + bytes = (ulong)((oldMap0.size[2] << 16) + (oldMap0.size[1] << 8) + oldMap0.size[0]) * 256; + var namebytes = new byte[10]; + + for(var i = 0; i < 5; i++) + { + namebytes[i * 2] = oldMap0.name[i]; + namebytes[i * 2 + 1] = oldMap1.name[i]; + } + + metadata = new FileSystem + { + Bootable = oldMap1.boot != 0, // Or not? + Clusters = bytes / imagePlugin.Info.SectorSize, + ClusterSize = imagePlugin.Info.SectorSize, + Type = FS_TYPE + }; + + if(ArrayHelpers.ArrayIsNullOrEmpty(namebytes)) + { + sbSector = OLD_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize; + sectorsToRead = OLD_DIRECTORY_SIZE / imagePlugin.Info.SectorSize; + + if(OLD_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0) sectorsToRead++; + + errno = imagePlugin.ReadSectors(sbSector, sectorsToRead, out sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length > OLD_DIRECTORY_SIZE) + { + var tmp = new byte[OLD_DIRECTORY_SIZE]; + Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53); + Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53); + sector = tmp; + } + + OldDirectory oldRoot = Marshal.ByteArrayToStructureLittleEndian(sector); + + if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC) + namebytes = oldRoot.tail.name; + else + { + // RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that... + sbSector = NEW_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize; + sectorsToRead = NEW_DIRECTORY_SIZE / imagePlugin.Info.SectorSize; + + if(NEW_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0) sectorsToRead++; + + errno = imagePlugin.ReadSectors(sbSector, sectorsToRead, out sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length > OLD_DIRECTORY_SIZE) + { + var tmp = new byte[OLD_DIRECTORY_SIZE]; + Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53); + + Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53); + + sector = tmp; + } + + oldRoot = Marshal.ByteArrayToStructureLittleEndian(sector); + + if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC) + namebytes = oldRoot.tail.name; + else + { + errno = imagePlugin.ReadSectors(sbSector, sectorsToRead, out sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length > NEW_DIRECTORY_SIZE) + { + var tmp = new byte[NEW_DIRECTORY_SIZE]; + Array.Copy(sector, 0, tmp, 0, NEW_DIRECTORY_SIZE - 41); + + Array.Copy(sector, sector.Length - 42, tmp, NEW_DIRECTORY_SIZE - 42, 41); + + sector = tmp; + } + + NewDirectory newRoot = Marshal.ByteArrayToStructureLittleEndian(sector); + + if(newRoot.header.magic == NEW_DIR_MAGIC && newRoot.tail.magic == NEW_DIR_MAGIC) + namebytes = newRoot.tail.title; + } + } + } + + sbInformation.AppendLine(Localization.Acorn_Advanced_Disc_Filing_System); + sbInformation.AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_per_sector, imagePlugin.Info.SectorSize).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_bytes, bytes).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(namebytes, encoding)) + .AppendLine(); + + if(oldMap1.discId > 0) + { + metadata.VolumeSerial = $"{oldMap1.discId:X4}"; + sbInformation.AppendFormat(Localization.Volume_ID_0_X4, oldMap1.discId).AppendLine(); + } + + if(!ArrayHelpers.ArrayIsNullOrEmpty(namebytes)) + metadata.VolumeName = StringHandlers.CToString(namebytes, encoding); + + information = sbInformation.ToString(); + + return; + } + } + + // Partitioning or not, new formats follow: + DiscRecord drSb; + + errno = imagePlugin.ReadSector(partition.Start, out sector); + + if(errno != ErrorNumber.NoError) return; + + byte newChk = NewMapChecksum(sector); + AaruConsole.DebugWriteLine(MODULE_NAME, "newChk = {0}", newChk); + AaruConsole.DebugWriteLine(MODULE_NAME, "map.zoneChecksum = {0}", sector[0]); + + sbSector = BOOT_BLOCK_LOCATION / imagePlugin.Info.SectorSize; + sectorsToRead = BOOT_BLOCK_SIZE / imagePlugin.Info.SectorSize; + + if(BOOT_BLOCK_SIZE % imagePlugin.Info.SectorSize > 0) sectorsToRead++; + + errno = imagePlugin.ReadSectors(sbSector + partition.Start, sectorsToRead, out byte[] bootSector); + + if(errno != ErrorNumber.NoError) return; + + var bootChk = 0; + + for(var i = 0; i < 0x1FF; i++) bootChk = (bootChk & 0xFF) + (bootChk >> 8) + bootSector[i]; + + AaruConsole.DebugWriteLine(MODULE_NAME, "bootChk = {0}", bootChk); + AaruConsole.DebugWriteLine(MODULE_NAME, "bBlock.checksum = {0}", bootSector[0x1FF]); + + if(newChk == sector[0] && newChk != 0) + { + NewMap nmap = Marshal.ByteArrayToStructureLittleEndian(sector); + drSb = nmap.discRecord; + } + else if(bootChk == bootSector[0x1FF]) + { + BootBlock bBlock = Marshal.ByteArrayToStructureLittleEndian(bootSector); + drSb = bBlock.discRecord; + } + else + return; + + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.log2secsize = {0}", drSb.log2secsize); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.spt = {0}", drSb.spt); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.heads = {0}", drSb.heads); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.density = {0}", drSb.density); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.idlen = {0}", drSb.idlen); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.log2bpmb = {0}", drSb.log2bpmb); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.skew = {0}", drSb.skew); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.bootoption = {0}", drSb.bootoption); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.lowsector = {0}", drSb.lowsector); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.nzones = {0}", drSb.nzones); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.zone_spare = {0}", drSb.zone_spare); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.root = {0}", drSb.root); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_size = {0}", drSb.disc_size); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_id = {0}", drSb.disc_id); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "drSb.disc_name = {0}", + StringHandlers.CToString(drSb.disc_name, encoding)); + + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_type = {0}", drSb.disc_type); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_size_high = {0}", drSb.disc_size_high); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.flags = {0}", drSb.flags); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.nzones_high = {0}", drSb.nzones_high); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.format_version = {0}", drSb.format_version); + AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.root_size = {0}", drSb.root_size); + + if(drSb.log2secsize is < 8 or > 10) return; + + if(drSb.idlen < drSb.log2secsize + 3 || drSb.idlen > 19) return; + + if(drSb.disc_size_high >> drSb.log2secsize != 0) return; + + if(!ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved)) return; + + bytes = drSb.disc_size_high; + bytes *= 0x100000000; + bytes += drSb.disc_size; + + ulong zones = drSb.nzones_high; + zones *= 0x100000000; + zones += drSb.nzones; + + if(bytes > imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize) return; + + metadata = new FileSystem(); + + sbInformation.AppendLine(Localization.Acorn_Advanced_Disc_Filing_System); + sbInformation.AppendLine(); + sbInformation.AppendFormat(Localization.Version_0, drSb.format_version).AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_per_sector, 1 << drSb.log2secsize).AppendLine(); + sbInformation.AppendFormat(Localization._0_sectors_per_track, drSb.spt).AppendLine(); + sbInformation.AppendFormat(Localization._0_heads, drSb.heads).AppendLine(); + sbInformation.AppendFormat(Localization.Density_code_0, drSb.density).AppendLine(); + sbInformation.AppendFormat(Localization.Skew_0, drSb.skew).AppendLine(); + sbInformation.AppendFormat(Localization.Boot_option_0, drSb.bootoption).AppendLine(); + + // TODO: What the hell is this field refering to? + sbInformation.AppendFormat(Localization.Root_starts_at_frag_0, drSb.root).AppendLine(); + + //sbInformation.AppendFormat("Root is {0} bytes long", drSb.root_size).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_bytes_in_1_zones, bytes, zones).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_flags_0_X4, drSb.flags).AppendLine(); + + if(drSb.disc_id > 0) + { + metadata.VolumeSerial = $"{drSb.disc_id:X4}"; + sbInformation.AppendFormat(Localization.Volume_ID_0_X4, drSb.disc_id).AppendLine(); + } + + if(!ArrayHelpers.ArrayIsNullOrEmpty(drSb.disc_name)) + { + string discname = StringHandlers.CToString(drSb.disc_name, encoding); + metadata.VolumeName = discname; + sbInformation.AppendFormat(Localization.Volume_name_0, discname).AppendLine(); + } + + information = sbInformation.ToString(); + + metadata.Bootable |= drSb.bootoption != 0; // Or not? + metadata.Clusters = bytes / (ulong)(1 << drSb.log2secsize); + metadata.ClusterSize = (uint)(1 << drSb.log2secsize); + metadata.Type = FS_TYPE; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Acorn/Structs.cs b/Aaru.Filesystems/Acorn/Structs.cs new file mode 100644 index 000000000..99056e0c8 --- /dev/null +++ b/Aaru.Filesystems/Acorn/Structs.cs @@ -0,0 +1,237 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Acorn filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Acorn's Advanced Data Filing System (ADFS) +public sealed partial class AcornADFS +{ +#region Nested type: BootBlock + + /// Boot block, used in hard disks and ADFS-F and higher. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct BootBlock + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1C0)] + public readonly byte[] spare; + public readonly DiscRecord discRecord; + public readonly byte flags; + public readonly ushort startCylinder; + public readonly byte checksum; + } + +#endregion + +#region Nested type: DirectoryEntry + + /// Directory header, common to "old" and "new" directories + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DirectoryEntry + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public readonly byte[] name; + public readonly uint load; + public readonly uint exec; + public readonly uint length; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] address; + public readonly byte atts; + } + +#endregion + +#region Nested type: DirectoryHeader + + /// Directory header, common to "old" and "new" directories + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DirectoryHeader + { + public readonly byte masterSequence; + public readonly uint magic; + } + +#endregion + +#region Nested type: DiscRecord + + /// Disc record, used in hard disks and ADFS-E and higher. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DiscRecord + { + public readonly byte log2secsize; + public readonly byte spt; + public readonly byte heads; + public readonly byte density; + public readonly byte idlen; + public readonly byte log2bpmb; + public readonly byte skew; + public readonly byte bootoption; + public readonly byte lowsector; + public readonly byte nzones; + public readonly ushort zone_spare; + public readonly uint root; + public readonly uint disc_size; + public readonly ushort disc_id; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public readonly byte[] disc_name; + public readonly uint disc_type; + public readonly uint disc_size_high; + public readonly byte flags; + public readonly byte nzones_high; + public readonly uint format_version; + public readonly uint root_size; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] reserved; + } + +#endregion + +#region Nested type: NewDirectory + + /// Directory, new format + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct NewDirectory + { + public readonly DirectoryHeader header; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 77)] + public readonly DirectoryEntry[] entries; + public readonly NewDirectoryTail tail; + } + +#endregion + +#region Nested type: NewDirectoryTail + + /// Directory tail, new format + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct NewDirectoryTail + { + public readonly byte lastMark; + public readonly ushort reserved; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] parent; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)] + public readonly byte[] title; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public readonly byte[] name; + public readonly byte endMasSeq; + public readonly uint magic; + public readonly byte checkByte; + } + +#endregion + +#region Nested type: NewMap + + /// Free block map, sector 0, used in ADFS-E + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct NewMap + { + public readonly byte zoneChecksum; + public readonly ushort freeLink; + public readonly byte crossChecksum; + public readonly DiscRecord discRecord; + } + +#endregion + +#region Nested type: OldDirectory + + /// Directory, old format + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct OldDirectory + { + public readonly DirectoryHeader header; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 47)] + public readonly DirectoryEntry[] entries; + public readonly OldDirectoryTail tail; + } + +#endregion + +#region Nested type: OldDirectoryTail + + /// Directory tail, old format + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct OldDirectoryTail + { + public readonly byte lastMark; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public readonly byte[] name; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] parent; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)] + public readonly byte[] title; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] + public readonly byte[] reserved; + public readonly byte endMasSeq; + public readonly uint magic; + public readonly byte checkByte; + } + +#endregion + +#region Nested type: OldMapSector0 + + /// Free block map, sector 0, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct OldMapSector0 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)] + public readonly byte[] freeStart; + public readonly byte reserved; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public readonly byte[] name; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] size; + public readonly byte checksum; + } + +#endregion + +#region Nested type: OldMapSector1 + + /// Free block map, sector 1, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct OldMapSector1 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)] + public readonly byte[] freeStart; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public readonly byte[] name; + public readonly ushort discId; + public readonly byte boot; + public readonly byte freeEnd; + public readonly byte checksum; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/AmigaDOS.cs b/Aaru.Filesystems/AmigaDOS.cs deleted file mode 100644 index 963243406..000000000 --- a/Aaru.Filesystems/AmigaDOS.cs +++ /dev/null @@ -1,525 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : AmigaDOS.cs -// Author(s) : Natalia Portillo -// -// Component : Amiga Fast File System plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Amiga Fast File System and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.Checksums; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of Amiga Fast File System (AFFS) -public sealed class AmigaDOSPlugin : IFilesystem -{ - const uint FFS_MASK = 0x444F5300; - const uint MUFS_MASK = 0x6D754600; - - const uint TYPE_HEADER = 2; - const uint SUBTYPE_ROOT = 1; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public string Name => "Amiga DOS filesystem"; - /// - public Guid Id => new("3c882400-208c-427d-a086-9119852a1bc7"); - /// - public Encoding Encoding { get; private set; } - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start + 4 >= partition.End) - return false; - - // Boot block is unless defined otherwise, 2 blocks - // Funny, you may need boot block to find root block if it's not in standard place just to know size of - // block size and then read the whole boot block. - // However while you can set a block size different from the sector size on formatting, the bootblock block - // size for floppies is the sector size, and for RDB is usually is the hard disk sector size, - // so this is not entirely wrong... - ErrorNumber errno = imagePlugin.ReadSectors(0 + partition.Start, 2, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - BootBlock bblk = Marshal.ByteArrayToStructureBigEndian(sector); - - // AROS boot floppies... - if(sector.Length >= 512 && - sector[510] == 0x55 && - sector[511] == 0xAA && - (bblk.diskType & FFS_MASK) != FFS_MASK && - (bblk.diskType & MUFS_MASK) != MUFS_MASK) - { - errno = imagePlugin.ReadSectors(1 + partition.Start, 2, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - bblk = Marshal.ByteArrayToStructureBigEndian(sector); - } - - // Not FFS or MuFS? - if((bblk.diskType & FFS_MASK) != FFS_MASK && - (bblk.diskType & MUFS_MASK) != MUFS_MASK) - return false; - - // Clear checksum on sector - sector[4] = sector[5] = sector[6] = sector[7] = 0; - uint bsum = AmigaBootChecksum(sector); - - AaruConsole.DebugWriteLine("AmigaDOS plugin", "bblk.checksum = 0x{0:X8}", bblk.checksum); - AaruConsole.DebugWriteLine("AmigaDOS plugin", "bsum = 0x{0:X8}", bsum); - - ulong bRootPtr = 0; - - // If bootblock is correct, let's take its rootblock pointer - if(bsum == bblk.checksum) - { - bRootPtr = bblk.root_ptr + partition.Start; - AaruConsole.DebugWriteLine("AmigaDOS plugin", "Bootblock points to {0} as Rootblock", bRootPtr); - } - - ulong[] rootPtrs = - { - bRootPtr + partition.Start, (partition.End - partition.Start + 1) / 2 + partition.Start - 2, - (partition.End - partition.Start + 1) / 2 + partition.Start - 1, - (partition.End - partition.Start + 1) / 2 + partition.Start, - (partition.End - partition.Start + 1) / 2 + partition.Start + 4 - }; - - var rblk = new RootBlock(); - - // So to handle even number of sectors - foreach(ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start)) - { - AaruConsole.DebugWriteLine("AmigaDOS plugin", "Searching for Rootblock in sector {0}", rootPtr); - - errno = imagePlugin.ReadSector(rootPtr, out sector); - - if(errno != ErrorNumber.NoError) - continue; - - rblk.type = BigEndianBitConverter.ToUInt32(sector, 0x00); - AaruConsole.DebugWriteLine("AmigaDOS plugin", "rblk.type = {0}", rblk.type); - - if(rblk.type != TYPE_HEADER) - continue; - - rblk.hashTableSize = BigEndianBitConverter.ToUInt32(sector, 0x0C); - - AaruConsole.DebugWriteLine("AmigaDOS plugin", "rblk.hashTableSize = {0}", rblk.hashTableSize); - - uint blockSize = (rblk.hashTableSize + 56) * 4; - var sectorsPerBlock = (uint)(blockSize / sector.Length); - - AaruConsole.DebugWriteLine("AmigaDOS plugin", "blockSize = {0}", blockSize); - AaruConsole.DebugWriteLine("AmigaDOS plugin", "sectorsPerBlock = {0}", sectorsPerBlock); - - if(blockSize % sector.Length > 0) - sectorsPerBlock++; - - if(rootPtr + sectorsPerBlock >= partition.End) - continue; - - errno = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock, out sector); - - if(errno != ErrorNumber.NoError) - continue; - - // Clear checksum on sector - rblk.checksum = BigEndianBitConverter.ToUInt32(sector, 20); - sector[20] = sector[21] = sector[22] = sector[23] = 0; - uint rsum = AmigaChecksum(sector); - - AaruConsole.DebugWriteLine("AmigaDOS plugin", "rblk.checksum = 0x{0:X8}", rblk.checksum); - AaruConsole.DebugWriteLine("AmigaDOS plugin", "rsum = 0x{0:X8}", rsum); - - rblk.sec_type = BigEndianBitConverter.ToUInt32(sector, sector.Length - 4); - AaruConsole.DebugWriteLine("AmigaDOS plugin", "rblk.sec_type = {0}", rblk.sec_type); - - if(rblk.sec_type == SUBTYPE_ROOT && - rblk.checksum == rsum) - return true; - } - - return false; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); - var sbInformation = new StringBuilder(); - XmlFsType = new FileSystemType(); - information = null; - ErrorNumber errno = imagePlugin.ReadSectors(0 + partition.Start, 2, out byte[] bootBlockSectors); - - if(errno != ErrorNumber.NoError) - return; - - BootBlock bootBlk = Marshal.ByteArrayToStructureBigEndian(bootBlockSectors); - bootBlk.bootCode = new byte[bootBlockSectors.Length - 12]; - Array.Copy(bootBlockSectors, 12, bootBlk.bootCode, 0, bootBlk.bootCode.Length); - bootBlockSectors[4] = bootBlockSectors[5] = bootBlockSectors[6] = bootBlockSectors[7] = 0; - uint bsum = AmigaBootChecksum(bootBlockSectors); - - ulong bRootPtr = 0; - - // If bootblock is correct, let's take its rootblock pointer - if(bsum == bootBlk.checksum) - { - bRootPtr = bootBlk.root_ptr + partition.Start; - AaruConsole.DebugWriteLine("AmigaDOS plugin", "Bootblock points to {0} as Rootblock", bRootPtr); - } - - ulong[] rootPtrs = - { - bRootPtr + partition.Start, (partition.End - partition.Start + 1) / 2 + partition.Start - 2, - (partition.End - partition.Start + 1) / 2 + partition.Start - 1, - (partition.End - partition.Start + 1) / 2 + partition.Start, - (partition.End - partition.Start + 1) / 2 + partition.Start + 4 - }; - - var rootBlk = new RootBlock(); - byte[] rootBlockSector = null; - - var rootFound = false; - uint blockSize = 0; - - // So to handle even number of sectors - foreach(ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start)) - { - AaruConsole.DebugWriteLine("AmigaDOS plugin", "Searching for Rootblock in sector {0}", rootPtr); - - errno = imagePlugin.ReadSector(rootPtr, out rootBlockSector); - - if(errno != ErrorNumber.NoError) - continue; - - rootBlk.type = BigEndianBitConverter.ToUInt32(rootBlockSector, 0x00); - AaruConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.type = {0}", rootBlk.type); - - if(rootBlk.type != TYPE_HEADER) - continue; - - rootBlk.hashTableSize = BigEndianBitConverter.ToUInt32(rootBlockSector, 0x0C); - - AaruConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.hashTableSize = {0}", rootBlk.hashTableSize); - - blockSize = (rootBlk.hashTableSize + 56) * 4; - var sectorsPerBlock = (uint)(blockSize / rootBlockSector.Length); - - AaruConsole.DebugWriteLine("AmigaDOS plugin", "blockSize = {0}", blockSize); - AaruConsole.DebugWriteLine("AmigaDOS plugin", "sectorsPerBlock = {0}", sectorsPerBlock); - - if(blockSize % rootBlockSector.Length > 0) - sectorsPerBlock++; - - if(rootPtr + sectorsPerBlock >= partition.End) - continue; - - errno = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock, out rootBlockSector); - - if(errno != ErrorNumber.NoError) - continue; - - // Clear checksum on sector - rootBlk.checksum = BigEndianBitConverter.ToUInt32(rootBlockSector, 20); - rootBlockSector[20] = rootBlockSector[21] = rootBlockSector[22] = rootBlockSector[23] = 0; - uint rsum = AmigaChecksum(rootBlockSector); - - AaruConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.checksum = 0x{0:X8}", rootBlk.checksum); - AaruConsole.DebugWriteLine("AmigaDOS plugin", "rsum = 0x{0:X8}", rsum); - - rootBlk.sec_type = BigEndianBitConverter.ToUInt32(rootBlockSector, rootBlockSector.Length - 4); - AaruConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.sec_type = {0}", rootBlk.sec_type); - - if(rootBlk.sec_type != SUBTYPE_ROOT || - rootBlk.checksum != rsum) - continue; - - errno = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock, out rootBlockSector); - - if(errno != ErrorNumber.NoError) - continue; - - rootFound = true; - - break; - } - - if(!rootFound) - return; - - rootBlk = MarshalRootBlock(rootBlockSector); - - string diskName = StringHandlers.PascalToString(rootBlk.diskName, Encoding); - - switch(bootBlk.diskType & 0xFF) - { - case 0: - sbInformation.Append("Amiga Original File System"); - XmlFsType.Type = "Amiga OFS"; - - break; - case 1: - sbInformation.Append("Amiga Fast File System"); - XmlFsType.Type = "Amiga FFS"; - - break; - case 2: - sbInformation.Append("Amiga Original File System with international characters"); - XmlFsType.Type = "Amiga OFS"; - - break; - case 3: - sbInformation.Append("Amiga Fast File System with international characters"); - XmlFsType.Type = "Amiga FFS"; - - break; - case 4: - sbInformation.Append("Amiga Original File System with directory cache"); - XmlFsType.Type = "Amiga OFS"; - - break; - case 5: - sbInformation.Append("Amiga Fast File System with directory cache"); - XmlFsType.Type = "Amiga FFS"; - - break; - case 6: - sbInformation.Append("Amiga Original File System with long filenames"); - XmlFsType.Type = "Amiga OFS2"; - - break; - case 7: - sbInformation.Append("Amiga Fast File System with long filenames"); - XmlFsType.Type = "Amiga FFS2"; - - break; - } - - if((bootBlk.diskType & 0x6D754600) == 0x6D754600) - sbInformation.Append(", with multi-user patches"); - - sbInformation.AppendLine(); - - sbInformation.AppendFormat("Volume name: {0}", diskName).AppendLine(); - - if(bootBlk.checksum == bsum) - { - var sha1Ctx = new Sha1Context(); - sha1Ctx.Update(bootBlk.bootCode); - sbInformation.AppendLine("Volume is bootable"); - sbInformation.AppendFormat("Boot code SHA1 is {0}", sha1Ctx.End()).AppendLine(); - } - - if(rootBlk.bitmapFlag == 0xFFFFFFFF) - sbInformation.AppendLine("Volume bitmap is valid"); - - if(rootBlk.bitmapExtensionBlock != 0x00000000 && - rootBlk.bitmapExtensionBlock != 0xFFFFFFFF) - sbInformation.AppendFormat("Bitmap extension at block {0}", rootBlk.bitmapExtensionBlock).AppendLine(); - - if((bootBlk.diskType & 0xFF) == 4 || - (bootBlk.diskType & 0xFF) == 5) - sbInformation.AppendFormat("Directory cache starts at block {0}", rootBlk.extension).AppendLine(); - - ulong blocks = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / blockSize; - - sbInformation.AppendFormat("Volume block size is {0} bytes", blockSize).AppendLine(); - sbInformation.AppendFormat("Volume has {0} blocks", blocks).AppendLine(); - - sbInformation.AppendFormat("Volume created on {0}", - DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks)). - AppendLine(); - - sbInformation.AppendFormat("Volume last modified on {0}", - DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks)). - AppendLine(); - - sbInformation.AppendFormat("Volume root directory last modified on on {0}", - DateHandlers.AmigaToDateTime(rootBlk.rDays, rootBlk.rMins, rootBlk.rTicks)). - AppendLine(); - - sbInformation.AppendFormat("Root block checksum is 0x{0:X8}", rootBlk.checksum).AppendLine(); - information = sbInformation.ToString(); - - XmlFsType.CreationDate = DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks); - - XmlFsType.CreationDateSpecified = true; - - XmlFsType.ModificationDate = DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks); - - XmlFsType.ModificationDateSpecified = true; - XmlFsType.Dirty = rootBlk.bitmapFlag != 0xFFFFFFFF; - XmlFsType.Clusters = blocks; - XmlFsType.ClusterSize = blockSize; - XmlFsType.VolumeName = diskName; - XmlFsType.Bootable = bsum == bootBlk.checksum; - - // Useful as a serial - XmlFsType.VolumeSerial = $"{rootBlk.checksum:X8}"; - } - - static RootBlock MarshalRootBlock(byte[] block) - { - var tmp = new byte[228]; - Array.Copy(block, 0, tmp, 0, 24); - Array.Copy(block, block.Length - 200, tmp, 28, 200); - RootBlock root = Marshal.ByteArrayToStructureBigEndian(tmp); - root.hashTable = new uint[(block.Length - 224) / 4]; - - for(var i = 0; i < root.hashTable.Length; i++) - root.hashTable[i] = BigEndianBitConverter.ToUInt32(block, 24 + i * 4); - - return root; - } - - static uint AmigaChecksum(byte[] data) - { - uint sum = 0; - - for(var i = 0; i < data.Length; i += 4) - sum += (uint)((data[i] << 24) + (data[i + 1] << 16) + (data[i + 2] << 8) + data[i + 3]); - - return (uint)-sum; - } - - static uint AmigaBootChecksum(byte[] data) - { - uint sum = 0; - - for(var i = 0; i < data.Length; i += 4) - { - uint psum = sum; - - if((sum += (uint)((data[i] << 24) + (data[i + 1] << 16) + (data[i + 2] << 8) + data[i + 3])) < psum) - sum++; - } - - return ~sum; - } - - /// Boot block, first 2 sectors - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BootBlock - { - /// Offset 0x00, "DOSx" disk type - public readonly uint diskType; - /// Offset 0x04, Checksum - public readonly uint checksum; - /// Offset 0x08, Pointer to root block, mostly invalid - public readonly uint root_ptr; - /// Offset 0x0C, Boot code, til completion. Size is intentionally incorrect to allow marshaling to work. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] - public byte[] bootCode; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct RootBlock - { - /// Offset 0x00, block type, value = T_HEADER (2) - public uint type; - /// Offset 0x04, unused - public readonly uint headerKey; - /// Offset 0x08, unused - public readonly uint highSeq; - /// Offset 0x0C, longs used by hash table - public uint hashTableSize; - /// Offset 0x10, unused - public readonly uint firstData; - /// Offset 0x14, Rootblock checksum - public uint checksum; - /// - /// Offset 0x18, Hashtable, size = (block size / 4) - 56 or size = hashTableSize. Size intentionally bad to allow - /// marshalling to work. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] - public uint[] hashTable; - /// Offset 0x18+hashTableSize*4+0, bitmap flag, 0xFFFFFFFF if valid - public readonly uint bitmapFlag; - /// Offset 0x18+hashTableSize*4+4, bitmap pages, 25 entries - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 25)] - public readonly uint[] bitmapPages; - /// Offset 0x18+hashTableSize*4+104, pointer to bitmap extension block - public readonly uint bitmapExtensionBlock; - /// Offset 0x18+hashTableSize*4+108, last root alteration days since 1978/01/01 - public readonly uint rDays; - /// Offset 0x18+hashTableSize*4+112, last root alteration minutes past midnight - public readonly uint rMins; - /// Offset 0x18+hashTableSize*4+116, last root alteration ticks (1/50 secs) - public readonly uint rTicks; - /// Offset 0x18+hashTableSize*4+120, disk name, pascal string, 31 bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)] - public readonly byte[] diskName; - /// Offset 0x18+hashTableSize*4+151, unused - public readonly byte padding; - /// Offset 0x18+hashTableSize*4+152, unused - public readonly uint reserved1; - /// Offset 0x18+hashTableSize*4+156, unused - public readonly uint reserved2; - /// Offset 0x18+hashTableSize*4+160, last disk alteration days since 1978/01/01 - public readonly uint vDays; - /// Offset 0x18+hashTableSize*4+164, last disk alteration minutes past midnight - public readonly uint vMins; - /// Offset 0x18+hashTableSize*4+168, last disk alteration ticks (1/50 secs) - public readonly uint vTicks; - /// Offset 0x18+hashTableSize*4+172, filesystem creation days since 1978/01/01 - public readonly uint cDays; - /// Offset 0x18+hashTableSize*4+176, filesystem creation minutes since 1978/01/01 - public readonly uint cMins; - /// Offset 0x18+hashTableSize*4+180, filesystem creation ticks since 1978/01/01 - public readonly uint cTicks; - /// Offset 0x18+hashTableSize*4+184, unused - public readonly uint nextHash; - /// Offset 0x18+hashTableSize*4+188, unused - public readonly uint parentDir; - /// Offset 0x18+hashTableSize*4+192, first directory cache block - public readonly uint extension; - /// Offset 0x18+hashTableSize*4+196, block secondary type = ST_ROOT (1) - public uint sec_type; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/AmigaDOS/AmigaDOS.cs b/Aaru.Filesystems/AmigaDOS/AmigaDOS.cs new file mode 100644 index 000000000..f2d52ca1c --- /dev/null +++ b/Aaru.Filesystems/AmigaDOS/AmigaDOS.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : AmigaDOS.cs +// Author(s) : Natalia Portillo +// +// Component : Amiga Fast File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Amiga Fast File System (AFFS) +public sealed partial class AmigaDOSPlugin : IFilesystem +{ + const string MODULE_NAME = "AmigaDOS plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.AmigaDOSPlugin_Name; + + /// + public Guid Id => new("3c882400-208c-427d-a086-9119852a1bc7"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/AmigaDOS/Consts.cs b/Aaru.Filesystems/AmigaDOS/Consts.cs new file mode 100644 index 000000000..7cda263e4 --- /dev/null +++ b/Aaru.Filesystems/AmigaDOS/Consts.cs @@ -0,0 +1,45 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Amiga Fast File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Amiga Fast File System (AFFS) +public sealed partial class AmigaDOSPlugin +{ + const uint FFS_MASK = 0x444F5300; + const uint MUFS_MASK = 0x6D754600; + + const uint TYPE_HEADER = 2; + const uint SUBTYPE_ROOT = 1; + + const string FS_TYPE_OFS = "aofs"; + const string FS_TYPE_FFS = "affs"; + const string FS_TYPE_OFS2 = "aofs2"; + const string FS_TYPE_FFS2 = "affs2"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/AmigaDOS/Helpers.cs b/Aaru.Filesystems/AmigaDOS/Helpers.cs new file mode 100644 index 000000000..39e5ecfb3 --- /dev/null +++ b/Aaru.Filesystems/AmigaDOS/Helpers.cs @@ -0,0 +1,75 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Helpers.cs +// Author(s) : Natalia Portillo +// +// Component : Amiga Fast File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.Helpers; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Amiga Fast File System (AFFS) +public sealed partial class AmigaDOSPlugin +{ + static RootBlock MarshalRootBlock(byte[] block) + { + var tmp = new byte[228]; + Array.Copy(block, 0, tmp, 0, 24); + Array.Copy(block, block.Length - 200, tmp, 28, 200); + RootBlock root = Marshal.ByteArrayToStructureBigEndian(tmp); + root.hashTable = new uint[(block.Length - 224) / 4]; + + for(var i = 0; i < root.hashTable.Length; i++) + root.hashTable[i] = BigEndianBitConverter.ToUInt32(block, 24 + i * 4); + + return root; + } + + static uint AmigaChecksum(byte[] data) + { + uint sum = 0; + + for(var i = 0; i < data.Length; i += 4) + sum += (uint)((data[i] << 24) + (data[i + 1] << 16) + (data[i + 2] << 8) + data[i + 3]); + + return (uint)-sum; + } + + static uint AmigaBootChecksum(byte[] data) + { + uint sum = 0; + + for(var i = 0; i < data.Length; i += 4) + { + uint psum = sum; + + if((sum += (uint)((data[i] << 24) + (data[i + 1] << 16) + (data[i + 2] << 8) + data[i + 3])) < psum) sum++; + } + + return ~sum; + } +} \ No newline at end of file diff --git a/Aaru.Filesystems/AmigaDOS/Info.cs b/Aaru.Filesystems/AmigaDOS/Info.cs new file mode 100644 index 000000000..ea79b1a04 --- /dev/null +++ b/Aaru.Filesystems/AmigaDOS/Info.cs @@ -0,0 +1,362 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Amiga Fast File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Linq; +using System.Text; +using Aaru.Checksums; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Amiga Fast File System (AFFS) +public sealed partial class AmigaDOSPlugin +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start + 4 >= partition.End) return false; + + // Boot block is unless defined otherwise, 2 blocks + // Funny, you may need boot block to find root block if it's not in standard place just to know size of + // block size and then read the whole boot block. + // However while you can set a block size different from the sector size on formatting, the bootblock block + // size for floppies is the sector size, and for RDB is usually is the hard disk sector size, + // so this is not entirely wrong... + ErrorNumber errno = imagePlugin.ReadSectors(0 + partition.Start, 2, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + BootBlock bblk = Marshal.ByteArrayToStructureBigEndian(sector); + + // AROS boot floppies... + if(sector.Length >= 512 && + sector[510] == 0x55 && + sector[511] == 0xAA && + (bblk.diskType & FFS_MASK) != FFS_MASK && + (bblk.diskType & MUFS_MASK) != MUFS_MASK) + { + errno = imagePlugin.ReadSectors(1 + partition.Start, 2, out sector); + + if(errno != ErrorNumber.NoError) return false; + + bblk = Marshal.ByteArrayToStructureBigEndian(sector); + } + + // Not FFS or MuFS? + if((bblk.diskType & FFS_MASK) != FFS_MASK && (bblk.diskType & MUFS_MASK) != MUFS_MASK) return false; + + // Clear checksum on sector + sector[4] = sector[5] = sector[6] = sector[7] = 0; + uint bsum = AmigaBootChecksum(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, "bblk.checksum = 0x{0:X8}", bblk.checksum); + AaruConsole.DebugWriteLine(MODULE_NAME, "bsum = 0x{0:X8}", bsum); + + ulong bRootPtr = 0; + + // If bootblock is correct, let's take its rootblock pointer + if(bsum == bblk.checksum) + { + bRootPtr = bblk.root_ptr + partition.Start; + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Bootblock_points_to_0_as_Rootblock, bRootPtr); + } + + ulong[] rootPtrs = + [ + bRootPtr + partition.Start, (partition.End - partition.Start + 1) / 2 + partition.Start - 2, + (partition.End - partition.Start + 1) / 2 + partition.Start - 1, + (partition.End - partition.Start + 1) / 2 + partition.Start, + (partition.End - partition.Start + 1) / 2 + partition.Start + 4 + ]; + + var rblk = new RootBlock(); + + // So to handle even number of sectors + foreach(ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Searching_for_Rootblock_in_sector_0, rootPtr); + + errno = imagePlugin.ReadSector(rootPtr, out sector); + + if(errno != ErrorNumber.NoError) continue; + + rblk.type = BigEndianBitConverter.ToUInt32(sector, 0x00); + AaruConsole.DebugWriteLine(MODULE_NAME, "rblk.type = {0}", rblk.type); + + if(rblk.type != TYPE_HEADER) continue; + + rblk.hashTableSize = BigEndianBitConverter.ToUInt32(sector, 0x0C); + + AaruConsole.DebugWriteLine(MODULE_NAME, "rblk.hashTableSize = {0}", rblk.hashTableSize); + + uint blockSize = (rblk.hashTableSize + 56) * 4; + var sectorsPerBlock = (uint)(blockSize / sector.Length); + + AaruConsole.DebugWriteLine(MODULE_NAME, "blockSize = {0}", blockSize); + AaruConsole.DebugWriteLine(MODULE_NAME, "sectorsPerBlock = {0}", sectorsPerBlock); + + if(blockSize % sector.Length > 0) sectorsPerBlock++; + + if(rootPtr + sectorsPerBlock >= partition.End) continue; + + errno = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock, out sector); + + if(errno != ErrorNumber.NoError) continue; + + // Clear checksum on sector + rblk.checksum = BigEndianBitConverter.ToUInt32(sector, 20); + sector[20] = sector[21] = sector[22] = sector[23] = 0; + uint rsum = AmigaChecksum(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, "rblk.checksum = 0x{0:X8}", rblk.checksum); + AaruConsole.DebugWriteLine(MODULE_NAME, "rsum = 0x{0:X8}", rsum); + + rblk.sec_type = BigEndianBitConverter.ToUInt32(sector, sector.Length - 4); + AaruConsole.DebugWriteLine(MODULE_NAME, "rblk.sec_type = {0}", rblk.sec_type); + + if(rblk.sec_type == SUBTYPE_ROOT && rblk.checksum == rsum) return true; + } + + return false; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-1"); + var sbInformation = new StringBuilder(); + metadata = new FileSystem(); + information = null; + ErrorNumber errno = imagePlugin.ReadSectors(0 + partition.Start, 2, out byte[] bootBlockSectors); + + if(errno != ErrorNumber.NoError) return; + + BootBlock bootBlk = Marshal.ByteArrayToStructureBigEndian(bootBlockSectors); + bootBlk.bootCode = new byte[bootBlockSectors.Length - 12]; + Array.Copy(bootBlockSectors, 12, bootBlk.bootCode, 0, bootBlk.bootCode.Length); + bootBlockSectors[4] = bootBlockSectors[5] = bootBlockSectors[6] = bootBlockSectors[7] = 0; + uint bsum = AmigaBootChecksum(bootBlockSectors); + + ulong bRootPtr = 0; + + // If bootblock is correct, let's take its rootblock pointer + if(bsum == bootBlk.checksum) + { + bRootPtr = bootBlk.root_ptr + partition.Start; + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Bootblock_points_to_0_as_Rootblock, bRootPtr); + } + + ulong[] rootPtrs = + [ + bRootPtr + partition.Start, (partition.End - partition.Start + 1) / 2 + partition.Start - 2, + (partition.End - partition.Start + 1) / 2 + partition.Start - 1, + (partition.End - partition.Start + 1) / 2 + partition.Start, + (partition.End - partition.Start + 1) / 2 + partition.Start + 4 + ]; + + var rootBlk = new RootBlock(); + byte[] rootBlockSector = null; + + var rootFound = false; + uint blockSize = 0; + + // So to handle even number of sectors + foreach(ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start)) + { + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Searching_for_Rootblock_in_sector_0, rootPtr); + + errno = imagePlugin.ReadSector(rootPtr, out rootBlockSector); + + if(errno != ErrorNumber.NoError) continue; + + rootBlk.type = BigEndianBitConverter.ToUInt32(rootBlockSector, 0x00); + AaruConsole.DebugWriteLine(MODULE_NAME, "rootBlk.type = {0}", rootBlk.type); + + if(rootBlk.type != TYPE_HEADER) continue; + + rootBlk.hashTableSize = BigEndianBitConverter.ToUInt32(rootBlockSector, 0x0C); + + AaruConsole.DebugWriteLine(MODULE_NAME, "rootBlk.hashTableSize = {0}", rootBlk.hashTableSize); + + blockSize = (rootBlk.hashTableSize + 56) * 4; + var sectorsPerBlock = (uint)(blockSize / rootBlockSector.Length); + + AaruConsole.DebugWriteLine(MODULE_NAME, "blockSize = {0}", blockSize); + AaruConsole.DebugWriteLine(MODULE_NAME, "sectorsPerBlock = {0}", sectorsPerBlock); + + if(blockSize % rootBlockSector.Length > 0) sectorsPerBlock++; + + if(rootPtr + sectorsPerBlock >= partition.End) continue; + + errno = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock, out rootBlockSector); + + if(errno != ErrorNumber.NoError) continue; + + // Clear checksum on sector + rootBlk.checksum = BigEndianBitConverter.ToUInt32(rootBlockSector, 20); + rootBlockSector[20] = rootBlockSector[21] = rootBlockSector[22] = rootBlockSector[23] = 0; + uint rsum = AmigaChecksum(rootBlockSector); + + AaruConsole.DebugWriteLine(MODULE_NAME, "rootBlk.checksum = 0x{0:X8}", rootBlk.checksum); + AaruConsole.DebugWriteLine(MODULE_NAME, "rsum = 0x{0:X8}", rsum); + + rootBlk.sec_type = BigEndianBitConverter.ToUInt32(rootBlockSector, rootBlockSector.Length - 4); + AaruConsole.DebugWriteLine(MODULE_NAME, "rootBlk.sec_type = {0}", rootBlk.sec_type); + + if(rootBlk.sec_type != SUBTYPE_ROOT || rootBlk.checksum != rsum) continue; + + errno = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock, out rootBlockSector); + + if(errno != ErrorNumber.NoError) continue; + + rootFound = true; + + break; + } + + if(!rootFound) return; + + rootBlk = MarshalRootBlock(rootBlockSector); + + string diskName = StringHandlers.PascalToString(rootBlk.diskName, encoding); + + switch(bootBlk.diskType & 0xFF) + { + case 0: + sbInformation.Append(Localization.Amiga_Original_File_System); + metadata.Type = FS_TYPE_OFS; + + break; + case 1: + sbInformation.Append(Localization.Amiga_Fast_File_System); + metadata.Type = FS_TYPE_FFS; + + break; + case 2: + sbInformation.Append(Localization.Amiga_Original_File_System_with_international_characters); + metadata.Type = FS_TYPE_OFS; + + break; + case 3: + sbInformation.Append(Localization.Amiga_Fast_File_System_with_international_characters); + metadata.Type = FS_TYPE_FFS; + + break; + case 4: + sbInformation.Append(Localization.Amiga_Original_File_System_with_directory_cache); + metadata.Type = FS_TYPE_OFS; + + break; + case 5: + sbInformation.Append(Localization.Amiga_Fast_File_System_with_directory_cache); + metadata.Type = FS_TYPE_FFS; + + break; + case 6: + sbInformation.Append(Localization.Amiga_Original_File_System_with_long_filenames); + metadata.Type = FS_TYPE_OFS2; + + break; + case 7: + sbInformation.Append(Localization.Amiga_Fast_File_System_with_long_filenames); + metadata.Type = FS_TYPE_FFS2; + + break; + } + + if((bootBlk.diskType & 0x6D754600) == 0x6D754600) sbInformation.Append(Localization.with_multi_user_patches); + + sbInformation.AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_name_0, diskName).AppendLine(); + + if(bootBlk.checksum == bsum) + { + var sha1Ctx = new Sha1Context(); + sha1Ctx.Update(bootBlk.bootCode); + sbInformation.AppendLine(Localization.Volume_is_bootable); + sbInformation.AppendFormat(Localization.Boot_code_SHA1_0, sha1Ctx.End()).AppendLine(); + } + + if(rootBlk.bitmapFlag == 0xFFFFFFFF) sbInformation.AppendLine(Localization.Volume_bitmap_is_valid); + + if(rootBlk.bitmapExtensionBlock != 0x00000000 && rootBlk.bitmapExtensionBlock != 0xFFFFFFFF) + { + sbInformation.AppendFormat(Localization.Bitmap_extension_at_block_0, rootBlk.bitmapExtensionBlock) + .AppendLine(); + } + + if((bootBlk.diskType & 0xFF) == 4 || (bootBlk.diskType & 0xFF) == 5) + sbInformation.AppendFormat(Localization.Directory_cache_starts_at_block_0, rootBlk.extension).AppendLine(); + + ulong blocks = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / blockSize; + + sbInformation.AppendFormat(Localization.Volume_block_size_is_0_bytes, blockSize).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_blocks, blocks).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_created_on_0, + DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_last_modified_on_0, + DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_root_directory_last_modified_on_0, + DateHandlers.AmigaToDateTime(rootBlk.rDays, rootBlk.rMins, rootBlk.rTicks)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Root_block_checksum_is_0, rootBlk.checksum).AppendLine(); + information = sbInformation.ToString(); + + metadata.CreationDate = DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks); + + metadata.ModificationDate = DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks); + + metadata.Dirty = rootBlk.bitmapFlag != 0xFFFFFFFF; + metadata.Clusters = blocks; + metadata.ClusterSize = blockSize; + metadata.VolumeName = diskName; + metadata.Bootable = bsum == bootBlk.checksum; + + // Useful as a serial + metadata.VolumeSerial = $"{rootBlk.checksum:X8}"; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/AmigaDOS/Structs.cs b/Aaru.Filesystems/AmigaDOS/Structs.cs new file mode 100644 index 000000000..2a4cce101 --- /dev/null +++ b/Aaru.Filesystems/AmigaDOS/Structs.cs @@ -0,0 +1,124 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Amiga Fast File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Amiga Fast File System (AFFS) +public sealed partial class AmigaDOSPlugin +{ +#region Nested type: BootBlock + + /// Boot block, first 2 sectors + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BootBlock + { + /// Offset 0x00, "DOSx" disk type + public readonly uint diskType; + /// Offset 0x04, Checksum + public readonly uint checksum; + /// Offset 0x08, Pointer to root block, mostly invalid + public readonly uint root_ptr; + /// Offset 0x0C, Boot code, til completion. Size is intentionally incorrect to allow marshaling to work. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public byte[] bootCode; + } + +#endregion + +#region Nested type: RootBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct RootBlock + { + /// Offset 0x00, block type, value = T_HEADER (2) + public uint type; + /// Offset 0x04, unused + public readonly uint headerKey; + /// Offset 0x08, unused + public readonly uint highSeq; + /// Offset 0x0C, longs used by hash table + public uint hashTableSize; + /// Offset 0x10, unused + public readonly uint firstData; + /// Offset 0x14, Rootblock checksum + public uint checksum; + /// + /// Offset 0x18, Hashtable, size = (block size / 4) - 56 or size = hashTableSize. Size intentionally bad to allow + /// marshalling to work. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public uint[] hashTable; + /// Offset 0x18+hashTableSize*4+0, bitmap flag, 0xFFFFFFFF if valid + public readonly uint bitmapFlag; + /// Offset 0x18+hashTableSize*4+4, bitmap pages, 25 entries + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 25)] + public readonly uint[] bitmapPages; + /// Offset 0x18+hashTableSize*4+104, pointer to bitmap extension block + public readonly uint bitmapExtensionBlock; + /// Offset 0x18+hashTableSize*4+108, last root alteration days since 1978/01/01 + public readonly uint rDays; + /// Offset 0x18+hashTableSize*4+112, last root alteration minutes past midnight + public readonly uint rMins; + /// Offset 0x18+hashTableSize*4+116, last root alteration ticks (1/50 secs) + public readonly uint rTicks; + /// Offset 0x18+hashTableSize*4+120, disk name, pascal string, 31 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)] + public readonly byte[] diskName; + /// Offset 0x18+hashTableSize*4+151, unused + public readonly byte padding; + /// Offset 0x18+hashTableSize*4+152, unused + public readonly uint reserved1; + /// Offset 0x18+hashTableSize*4+156, unused + public readonly uint reserved2; + /// Offset 0x18+hashTableSize*4+160, last disk alteration days since 1978/01/01 + public readonly uint vDays; + /// Offset 0x18+hashTableSize*4+164, last disk alteration minutes past midnight + public readonly uint vMins; + /// Offset 0x18+hashTableSize*4+168, last disk alteration ticks (1/50 secs) + public readonly uint vTicks; + /// Offset 0x18+hashTableSize*4+172, filesystem creation days since 1978/01/01 + public readonly uint cDays; + /// Offset 0x18+hashTableSize*4+176, filesystem creation minutes since 1978/01/01 + public readonly uint cMins; + /// Offset 0x18+hashTableSize*4+180, filesystem creation ticks since 1978/01/01 + public readonly uint cTicks; + /// Offset 0x18+hashTableSize*4+184, unused + public readonly uint nextHash; + /// Offset 0x18+hashTableSize*4+188, unused + public readonly uint parentDir; + /// Offset 0x18+hashTableSize*4+192, first directory cache block + public readonly uint extension; + /// Offset 0x18+hashTableSize*4+196, block secondary type = ST_ROOT (1) + public uint sec_type; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/AppleCommon/Consts.cs b/Aaru.Filesystems/AppleCommon/Consts.cs index 5a2c787f6..7962e3200 100644 --- a/Aaru.Filesystems/AppleCommon/Consts.cs +++ b/Aaru.Filesystems/AppleCommon/Consts.cs @@ -7,10 +7,6 @@ // // Component : Common Apple file systems. // -// --[ Description ] ---------------------------------------------------------- -// -// Common Apple file systems constants. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,7 +23,7 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ namespace Aaru.Filesystems; diff --git a/Aaru.Filesystems/AppleCommon/Enums.cs b/Aaru.Filesystems/AppleCommon/Enums.cs index ab1eecc55..b07dd4bb9 100644 --- a/Aaru.Filesystems/AppleCommon/Enums.cs +++ b/Aaru.Filesystems/AppleCommon/Enums.cs @@ -7,10 +7,6 @@ // // Component : Common Apple file systems. // -// --[ Description ] ---------------------------------------------------------- -// -// Common Apple file systems enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,42 +23,48 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable InconsistentNaming -namespace Aaru.Filesystems; - using System; +// ReSharper disable UnusedMember.Global + +namespace Aaru.Filesystems; + // Information from Inside Macintosh // https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf static partial class AppleCommon { +#region Nested type: ExtendedFinderFlags + [Flags] - internal enum VolumeAttributes : ushort + internal enum ExtendedFinderFlags : ushort { - HardwareLock = 0x80, - Unmounted = 0x100, - SparedBadBlocks = 0x200, - DoesNotNeedCache = 0x400, - BootInconsistent = 0x800, - ReusedIds = 0x1000, - Journaled = 0x2000, - Inconsistent = 0x4000, - SoftwareLock = 0x8000 + /// If set the other extended flags are ignored. + kExtendedFlagsAreInvalid = 0x8000, + /// Set if the file or folder has a badge resource. + kExtendedFlagHasCustomBadge = 0x0100, + /// Set if the object is marked as busy/incomplete. + kExtendedFlagObjectIsBusy = 0x0080, + /// Set if the file contains routing info resource. + kExtendedFlagHasRoutingInfo = 0x0004 } +#endregion + +#region Nested type: FinderFlags + [Flags] internal enum FinderFlags : ushort { /// Is on desktop. kIsOnDesk = 0x0001, /// Color mask. - kColor = 0x000E, kRequireSwitchLaunch = 0x0020, + kColor = 0x000E, + kRequireSwitchLaunch = 0x0020, /// If clear, the application needs to write to its resource fork, and therefore cannot be shared on a server. kIsShared = 0x0040, /// Extension or control panel with no INIT entries in resource fork. @@ -73,7 +75,8 @@ static partial class AppleCommon /// kHasBeenInited = 0x0100, /// PowerTalk - kAOCE = 0x200, kChanged = 0x0200, + kAOCE = 0x200, + kChanged = 0x0200, /// Has a custom icon in the resource fork. kHasCustomIcon = 0x0400, /// Is a stationery. @@ -88,6 +91,10 @@ static partial class AppleCommon kIsAlias = 0x8000 } +#endregion + +#region Nested type: FinderFolder + internal enum FinderFolder : short { fTrash = -3, @@ -95,16 +102,23 @@ static partial class AppleCommon fDisk = 0 } +#endregion + +#region Nested type: VolumeAttributes + [Flags] - internal enum ExtendedFinderFlags : ushort + internal enum VolumeAttributes : ushort { - /// If set the other extended flags are ignored. - kExtendedFlagsAreInvalid = 0x8000, - /// Set if the file or folder has a badge resource. - kExtendedFlagHasCustomBadge = 0x0100, - /// Set if the object is marked as busy/incomplete. - kExtendedFlagObjectIsBusy = 0x0080, - /// Set if the file contains routing info resource. - kExtendedFlagHasRoutingInfo = 0x0004 + HardwareLock = 0x80, + Unmounted = 0x100, + SparedBadBlocks = 0x200, + DoesNotNeedCache = 0x400, + BootInconsistent = 0x800, + ReusedIds = 0x1000, + Journaled = 0x2000, + Inconsistent = 0x4000, + SoftwareLock = 0x8000 } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleCommon/Info.cs b/Aaru.Filesystems/AppleCommon/Info.cs index 7732bd09e..fc1ae590b 100644 --- a/Aaru.Filesystems/AppleCommon/Info.cs +++ b/Aaru.Filesystems/AppleCommon/Info.cs @@ -7,10 +7,6 @@ // // Component : Common Apple file systems. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple Macintosh Boot Block information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,76 +23,89 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Text; using Aaru.Helpers; +namespace Aaru.Filesystems; + // Information from Inside Macintosh // https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf static partial class AppleCommon { internal static string GetBootBlockInformation(byte[] bbSector, Encoding encoding) { - if(bbSector is null || - bbSector.Length < 0x100) - return null; + if(bbSector is null || bbSector.Length < 0x100) return null; BootBlock bb = Marshal.ByteArrayToStructureBigEndian(bbSector); - if(bb.bbID != BB_MAGIC) - return null; + if(bb.bbID != BB_MAGIC) return null; var sb = new StringBuilder(); - sb.AppendLine("Boot Block:"); + sb.AppendLine(Localization.Boot_Block); if((bb.bbVersion & 0x8000) > 0) { - sb.AppendLine("Boot block is in new format."); + sb.AppendLine(Localization.Boot_block_is_in_new_format); if((bb.bbVersion & 0x4000) > 0) { - sb.AppendLine("Boot block should be executed."); + sb.AppendLine(Localization.Boot_block_should_be_executed); if((bb.bbVersion & 0x2000) > 0) - sb.AppendFormat("System heap will be extended by {0} bytes and a {1} fraction of the available RAM", - bb.bbSysHeapExtra, bb.bbSysHeapFract).AppendLine(); + { + sb.AppendFormat(Localization + .System_heap_will_be_extended_by_0_bytes_and_a_1_fraction_of_the_available_RAM, + bb.bbSysHeapExtra, + bb.bbSysHeapFract) + .AppendLine(); + } } } - else if((bb.bbVersion & 0xFF) == 0x0D) - sb.AppendLine("Boot block should be executed."); + else if((bb.bbVersion & 0xFF) == 0x0D) sb.AppendLine(Localization.Boot_block_should_be_executed); - if(bb.bbPageFlags > 0) - sb.AppendLine("Allocate secondary sound buffer at boot."); - else if(bb.bbPageFlags < 0) - sb.AppendLine("Allocate secondary sound and video buffers at boot."); + switch(bb.bbPageFlags) + { + case > 0: + sb.AppendLine(Localization.Allocate_secondary_sound_buffer_at_boot); - sb.AppendFormat("System filename: {0}", StringHandlers.PascalToString(bb.bbSysName, encoding)).AppendLine(); + break; + case < 0: + sb.AppendLine(Localization.Allocate_secondary_sound_and_video_buffers_at_boot); - sb.AppendFormat("Finder filename: {0}", StringHandlers.PascalToString(bb.bbShellName, encoding)).AppendLine(); + break; + } - sb.AppendFormat("Debugger filename: {0}", StringHandlers.PascalToString(bb.bbDbg1Name, encoding)).AppendLine(); + sb.AppendFormat(Localization.System_filename_0, StringHandlers.PascalToString(bb.bbSysName, encoding)) + .AppendLine(); - sb.AppendFormat("Disassembler filename: {0}", StringHandlers.PascalToString(bb.bbDbg2Name, encoding)). - AppendLine(); + sb.AppendFormat(Localization.Finder_filename_0, StringHandlers.PascalToString(bb.bbShellName, encoding)) + .AppendLine(); - sb.AppendFormat("Startup screen filename: {0}", StringHandlers.PascalToString(bb.bbScreenName, encoding)). - AppendLine(); + sb.AppendFormat(Localization.Debugger_filename_0, StringHandlers.PascalToString(bb.bbDbg1Name, encoding)) + .AppendLine(); - sb.AppendFormat("First program to execute at boot: {0}", - StringHandlers.PascalToString(bb.bbHelloName, encoding)).AppendLine(); + sb.AppendFormat(Localization.Disassembler_filename_0, StringHandlers.PascalToString(bb.bbDbg2Name, encoding)) + .AppendLine(); - sb.AppendFormat("Clipboard filename: {0}", StringHandlers.PascalToString(bb.bbScrapName, encoding)). - AppendLine(); + sb.AppendFormat(Localization.Startup_screen_filename_0, + StringHandlers.PascalToString(bb.bbScreenName, encoding)) + .AppendLine(); - sb.AppendFormat("Maximum opened files: {0}", bb.bbCntFCBs * 4).AppendLine(); - sb.AppendFormat("Event queue size: {0}", bb.bbCntEvts).AppendLine(); - sb.AppendFormat("Heap size with 128KiB of RAM: {0} bytes", bb.bb128KSHeap).AppendLine(); - sb.AppendFormat("Heap size with 256KiB of RAM: {0} bytes", bb.bb256KSHeap).AppendLine(); - sb.AppendFormat("Heap size with 512KiB of RAM or more: {0} bytes", bb.bbSysHeapSize).AppendLine(); + sb.AppendFormat(Localization.First_program_to_execute_at_boot_0, + StringHandlers.PascalToString(bb.bbHelloName, encoding)) + .AppendLine(); + + sb.AppendFormat(Localization.Clipboard_filename_0, StringHandlers.PascalToString(bb.bbScrapName, encoding)) + .AppendLine(); + + sb.AppendFormat(Localization.Maximum_opened_files_0, bb.bbCntFCBs * 4).AppendLine(); + sb.AppendFormat(Localization.Event_queue_size_0, bb.bbCntEvts).AppendLine(); + sb.AppendFormat(Localization.Heap_size_with_128KiB_of_RAM_0_bytes, bb.bb128KSHeap).AppendLine(); + sb.AppendFormat(Localization.Heap_size_with_256KiB_of_RAM_0_bytes, bb.bb256KSHeap).AppendLine(); + sb.AppendFormat(Localization.Heap_size_with_512KiB_of_RAM_or_more_0_bytes, bb.bbSysHeapSize).AppendLine(); return sb.ToString(); } diff --git a/Aaru.Filesystems/AppleCommon/Structs.cs b/Aaru.Filesystems/AppleCommon/Structs.cs index e56e7238f..daf2572fd 100644 --- a/Aaru.Filesystems/AppleCommon/Structs.cs +++ b/Aaru.Filesystems/AppleCommon/Structs.cs @@ -7,10 +7,6 @@ // // Component : Common Apple file systems. // -// --[ Description ] ---------------------------------------------------------- -// -// Common Apple file systems structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,21 +23,21 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable InconsistentNaming -namespace Aaru.Filesystems; - using System.Runtime.InteropServices; +namespace Aaru.Filesystems; + // Information from Inside Macintosh // https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf static partial class AppleCommon { +#region Nested type: BootBlock + /// Should be sectors 0 and 1 in volume, followed by boot code [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct BootBlock // Should be sectors 0 and 1 in volume @@ -93,20 +89,44 @@ static partial class AppleCommon public readonly uint bbSysHeapFract; } - internal struct Rect +#endregion + +#region Nested type: DInfo + + internal struct DInfo { - public ushort top; - public ushort left; - public ushort bottom; - public ushort right; + /// Position and dimensions of the folder's window. + public Rect frRect; + /// Flags. + public FinderFlags frFlags; + /// Folder's location in the parent folder. + public Point frLocation; + /// Finder view selected for folder. + public ushort frView; } - internal struct Point +#endregion + +#region Nested type: DXInfo + + internal struct DXInfo { - public ushort v; - public ushort h; + /// Scroll position for icon views. + public Point frScroll; + /// Directory ID chain of open folders. + public uint frOpenChain; + /// Extended flags. If high-bit is set, most significant byte is script code and least significant byte are flags. + public ExtendedFinderFlags frXFlags; + /// Resource fork ID of directory comment if high bit is clear. + public ushort frComment; + /// Put away folder ID. + public uint frPutAway; } +#endregion + +#region Nested type: FInfo + internal struct FInfo { /// The type of the file. @@ -121,6 +141,10 @@ static partial class AppleCommon public FinderFolder fdFldr; } +#endregion + +#region Nested type: FXInfo + internal struct FXInfo { /// Resource fork ID of file icon. @@ -135,29 +159,27 @@ static partial class AppleCommon public uint fdPutAway; } - internal struct DInfo +#endregion + +#region Nested type: Point + + internal struct Point { - /// Position and dimensions of the folder's window. - public Rect frRect; - /// Flags. - public FinderFlags frFlags; - /// Folder's location in the parent folder. - public Point frLocation; - /// Finder view selected for folder. - public ushort frView; + public ushort v; + public ushort h; } - internal struct DXInfo +#endregion + +#region Nested type: Rect + + internal struct Rect { - /// Scroll position for icon views. - public Point frScroll; - /// Directory ID chain of open folders. - public uint frOpenChain; - /// Extended flags. If high-bit is set, most significant byte is script code and least significant byte are flags. - public ExtendedFinderFlags frXFlags; - /// Resource fork ID of directory comment if high bit is clear. - public ushort frComment; - /// Put away folder ID. - public uint frPutAway; + public ushort top; + public ushort left; + public ushort bottom; + public ushort right; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleDOS/AppleDOS.cs b/Aaru.Filesystems/AppleDOS/AppleDOS.cs index 9f4c7a679..4c8040659 100644 --- a/Aaru.Filesystems/AppleDOS/AppleDOS.cs +++ b/Aaru.Filesystems/AppleDOS/AppleDOS.cs @@ -7,10 +7,6 @@ // // Component : Apple DOS filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Constructors and common variables for the Apple DOS filesystem plugin. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,42 +23,49 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Text; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Interfaces; -using Schemas; + +namespace Aaru.Filesystems; /// /// Implements the Apple DOS 3 filesystem public sealed partial class AppleDOS : IReadOnlyFilesystem { - bool _debug; - IMediaImage _device; - bool _mounted; - int _sectorsPerTrack; - ulong _start; - ulong _totalFileEntries; - bool _track1UsedByFiles; - bool _track2UsedByFiles; - uint _usedSectors; - Vtoc _vtoc; + // Do not translate + const string FS_TYPE = "appledos"; + const string MODULE_NAME = "Apple DOS plugin"; + bool _debug; + IMediaImage _device; + Encoding _encoding; + bool _mounted; + int _sectorsPerTrack; + ulong _start; + ulong _totalFileEntries; + bool _track1UsedByFiles; + bool _track2UsedByFiles; + uint _usedSectors; + Vtoc _vtoc; + +#region IReadOnlyFilesystem Members /// - public FileSystemType XmlFsType { get; private set; } + public FileSystem Metadata { get; private set; } + /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Apple DOS File System"; + public string Name => Localization.AppleDOS_Name; + /// public Guid Id => new("8658A1E9-B2E7-4BCC-9638-157A31B0A700\n"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public IEnumerable<(string name, Type type, string description)> SupportedOptions => @@ -71,6 +74,8 @@ public sealed partial class AppleDOS : IReadOnlyFilesystem /// public Dictionary Namespaces => null; +#endregion + static Dictionary GetDefaultOptions() => new() { { @@ -78,7 +83,8 @@ public sealed partial class AppleDOS : IReadOnlyFilesystem } }; - #region Caches +#region Caches + /// Caches track/sector lists Dictionary _extentCache; /// Caches files @@ -97,5 +103,6 @@ public sealed partial class AppleDOS : IReadOnlyFilesystem Dictionary _fileTypeCache; /// Caches locked files List _lockedFiles; - #endregion Caches + +#endregion Caches } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleDOS/Dir.cs b/Aaru.Filesystems/AppleDOS/Dir.cs index e14dd6851..dec465c62 100644 --- a/Aaru.Filesystems/AppleDOS/Dir.cs +++ b/Aaru.Filesystems/AppleDOS/Dir.cs @@ -27,20 +27,23 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.IO; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class AppleDOS { +#region IReadOnlyFilesystem Members + /// public ErrorNumber ReadLink(string path, out string dest) { @@ -50,18 +53,16 @@ public sealed partial class AppleDOS } /// - public ErrorNumber ReadDir(string path, out List contents) + public ErrorNumber OpenDir(string path, out IDirNode node) { - contents = null; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - if(!string.IsNullOrEmpty(path) && - string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) + if(!string.IsNullOrEmpty(path) && string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) return ErrorNumber.NotSupported; - contents = _catalogCache.Keys.ToList(); + var contents = _catalogCache.Keys.ToList(); if(_debug) { @@ -72,9 +73,47 @@ public sealed partial class AppleDOS contents.Sort(); + node = new AppleDosDirNode + { + Path = path, + Position = 0, + Contents = contents.ToArray() + }; + return ErrorNumber.NoError; } + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) + { + filename = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not AppleDosDirNode mynode) return ErrorNumber.InvalidArgument; + + if(mynode.Position < 0) return ErrorNumber.InvalidArgument; + + if(mynode.Position >= mynode.Contents.Length) return ErrorNumber.NoError; + + filename = mynode.Contents[mynode.Position++]; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not AppleDosDirNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Position = -1; + mynode.Contents = null; + + return ErrorNumber.NoError; + } + +#endregion + ErrorNumber ReadCatalog() { var catalogMs = new MemoryStream(); @@ -82,25 +121,20 @@ public sealed partial class AppleDOS _totalFileEntries = 0; _catalogCache = new Dictionary(); _fileTypeCache = new Dictionary(); - _fileSizeCache = new Dictionary(); - _lockedFiles = new List(); + _lockedFiles = []; - if(lba == 0 || - lba > _device.Info.Sectors) - return ErrorNumber.InvalidArgument; + if(lba == 0 || lba > _device.Info.Sectors) return ErrorNumber.InvalidArgument; while(lba != 0) { _usedSectors++; ErrorNumber errno = _device.ReadSector(lba, out byte[] catSectorB); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; _totalFileEntries += 7; - if(_debug) - catalogMs.Write(catSectorB, 0, catSectorB.Length); + if(_debug) catalogMs.Write(catSectorB, 0, catSectorB.Length); // Read the catalog sector CatalogSector catSector = Marshal.ByteArrayToStructureLittleEndian(catSectorB); @@ -111,36 +145,25 @@ public sealed partial class AppleDOS _track2UsedByFiles |= entry.extentTrack == 2; var filenameB = new byte[30]; - var ts = (ushort)((entry.extentTrack << 8) | entry.extentSector); + var ts = (ushort)(entry.extentTrack << 8 | entry.extentSector); // Apple DOS has high byte set over ASCII. - for(var i = 0; i < 30; i++) - filenameB[i] = (byte)(entry.filename[i] & 0x7F); + for(var i = 0; i < 30; i++) filenameB[i] = (byte)(entry.filename[i] & 0x7F); - string filename = StringHandlers.SpacePaddedToString(filenameB, Encoding); + string filename = StringHandlers.SpacePaddedToString(filenameB, _encoding); - if(!_catalogCache.ContainsKey(filename)) - _catalogCache.Add(filename, ts); + _catalogCache.TryAdd(filename, ts); + _fileTypeCache.TryAdd(filename, (byte)(entry.typeAndFlags & 0x7F)); - if(!_fileTypeCache.ContainsKey(filename)) - _fileTypeCache.Add(filename, (byte)(entry.typeAndFlags & 0x7F)); - - if(!_fileSizeCache.ContainsKey(filename)) - _fileSizeCache.Add(filename, entry.length * _vtoc.bytesPerSector); - - if((entry.typeAndFlags & 0x80) == 0x80 && - !_lockedFiles.Contains(filename)) - _lockedFiles.Add(filename); + if((entry.typeAndFlags & 0x80) == 0x80 && !_lockedFiles.Contains(filename)) _lockedFiles.Add(filename); } lba = (ulong)(catSector.trackOfNext * _sectorsPerTrack + catSector.sectorOfNext); - if(lba > _device.Info.Sectors) - break; + if(lba > _device.Info.Sectors) break; } - if(_debug) - _catalogBlocks = catalogMs.ToArray(); + if(_debug) _catalogBlocks = catalogMs.ToArray(); return ErrorNumber.NoError; } diff --git a/Aaru.Filesystems/AppleDOS/File.cs b/Aaru.Filesystems/AppleDOS/File.cs index 167d6b2e6..b97ea39a2 100644 --- a/Aaru.Filesystems/AppleDOS/File.cs +++ b/Aaru.Filesystems/AppleDOS/File.cs @@ -7,10 +7,6 @@ // // Component : Apple DOS filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle files. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,109 +23,142 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.IO; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Helpers; using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes; +namespace Aaru.Filesystems; + public sealed partial class AppleDOS { +#region IReadOnlyFilesystem Members + /// public ErrorNumber GetAttributes(string path, out FileAttributes attributes) { attributes = new FileAttributes(); - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; string filename = pathElements[0].ToUpperInvariant(); - if(!_fileCache.ContainsKey(filename)) - return ErrorNumber.NoSuchFile; + if(!_fileCache.ContainsKey(filename)) return ErrorNumber.NoSuchFile; attributes = FileAttributes.Extents; attributes |= FileAttributes.File; - if(_lockedFiles.Contains(filename)) - attributes |= FileAttributes.ReadOnly; + if(_lockedFiles.Contains(filename)) attributes |= FileAttributes.ReadOnly; - if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) + if(_debug && + (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) attributes |= FileAttributes.System; return ErrorNumber.NoError; } - /// - public ErrorNumber Read(string path, long offset, long size, ref byte[] buf) + public ErrorNumber OpenFile(string path, out IFileNode node) { - if(!_mounted) - return ErrorNumber.AccessDenied; + node = null; + + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; byte[] file; string filename = pathElements[0].ToUpperInvariant(); - if(filename.Length > 30) - return ErrorNumber.NameTooLong; + if(filename.Length > 30) return ErrorNumber.NameTooLong; - if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) + if(_debug && + (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) + { if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0) file = _catalogBlocks; else if(string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0) file = _vtocBlocks; else file = _bootBlocks; + } else { if(!_fileCache.TryGetValue(filename, out file)) { ErrorNumber error = CacheFile(filename); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; - if(!_fileCache.TryGetValue(filename, out file)) - return ErrorNumber.InvalidArgument; + if(!_fileCache.TryGetValue(filename, out file)) return ErrorNumber.InvalidArgument; } } - if(offset >= file.Length) - return ErrorNumber.InvalidArgument; + node = new AppleDosFileNode + { + Path = path, + Length = file.Length, + Offset = 0, + Cache = file + }; - if(size + offset >= file.Length) - size = file.Length - offset; + return ErrorNumber.NoError; + } - buf = new byte[size]; + /// + public ErrorNumber CloseFile(IFileNode node) + { + if(!_mounted) return ErrorNumber.AccessDenied; - Array.Copy(file, offset, buf, 0, size); + if(node is not AppleDosFileNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Cache = null; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(buffer is null || buffer.Length < length) return ErrorNumber.InvalidArgument; + + if(node is not AppleDosFileNode mynode) return ErrorNumber.InvalidArgument; + + read = length; + + if(length + mynode.Offset >= mynode.Length) read = mynode.Length - mynode.Offset; + + Array.Copy(mynode.Cache, mynode.Offset, buffer, 0, read); + + mynode.Offset += read; return ErrorNumber.NoError; } @@ -139,33 +168,31 @@ public sealed partial class AppleDOS { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; string filename = pathElements[0].ToUpperInvariant(); - if(filename.Length > 30) - return ErrorNumber.NameTooLong; + if(filename.Length > 30) return ErrorNumber.NameTooLong; - if(!_fileCache.ContainsKey(filename)) - return ErrorNumber.NoSuchFile; + if(!_fileCache.ContainsKey(filename)) return ErrorNumber.NoSuchFile; stat = new FileEntryInfo(); _fileSizeCache.TryGetValue(filename, out int fileSize); GetAttributes(path, out FileAttributes attrs); - if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) + if(_debug && + (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) { if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0) stat.Length = _catalogBlocks.Length; @@ -189,32 +216,23 @@ public sealed partial class AppleDOS return ErrorNumber.NoError; } - /// - public ErrorNumber MapBlock(string path, long fileBlock, out long deviceBlock) - { - deviceBlock = 0; - - // TODO: Not really important. - return !_mounted ? ErrorNumber.AccessDenied : ErrorNumber.NotImplemented; - } +#endregion ErrorNumber CacheFile(string path) { string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; string filename = pathElements[0].ToUpperInvariant(); - if(filename.Length > 30) - return ErrorNumber.NameTooLong; + if(filename.Length > 30) return ErrorNumber.NameTooLong; - if(!_catalogCache.TryGetValue(filename, out ushort ts)) - return ErrorNumber.NoSuchFile; + if(!_catalogCache.TryGetValue(filename, out ushort ts)) return ErrorNumber.NoSuchFile; var lba = (ulong)(((ts & 0xFF00) >> 8) * _sectorsPerTrack + (ts & 0xFF)); var fileMs = new MemoryStream(); @@ -226,11 +244,9 @@ public sealed partial class AppleDOS _usedSectors++; ErrorNumber errno = _device.ReadSector(lba, out byte[] tsSectorB); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - if(_debug) - tsListMs.Write(tsSectorB, 0, tsSectorB.Length); + if(_debug) tsListMs.Write(tsSectorB, 0, tsSectorB.Length); // Read the track/sector list sector TrackSectorList tsSector = Marshal.ByteArrayToStructureLittleEndian(tsSectorB); @@ -250,13 +266,11 @@ public sealed partial class AppleDOS var blockLba = (ulong)(entry.track * _sectorsPerTrack + entry.sector); - if(blockLba == 0) - break; + if(blockLba == 0) break; errno = _device.ReadSector(blockLba, out byte[] fileBlock); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; fileMs.Write(fileBlock, 0, fileBlock.Length); expectedBlock++; @@ -265,14 +279,15 @@ public sealed partial class AppleDOS lba = (ulong)(tsSector.nextListTrack * _sectorsPerTrack + tsSector.nextListSector); } - if(_fileCache.ContainsKey(filename)) - _fileCache.Remove(filename); + if(_fileCache.ContainsKey(filename)) _fileCache.Remove(filename); - if(_extentCache.ContainsKey(filename)) - _extentCache.Remove(filename); + if(_extentCache.ContainsKey(filename)) _extentCache.Remove(filename); + + if(_fileSizeCache.ContainsKey(filename)) _fileSizeCache.Remove(filename); _fileCache.Add(filename, fileMs.ToArray()); _extentCache.Add(filename, tsListMs.ToArray()); + _fileSizeCache.Add(filename, (int)fileMs.Length); return ErrorNumber.NoError; } @@ -287,16 +302,13 @@ public sealed partial class AppleDOS uint tracksOnBoot = 1; - if(!_track1UsedByFiles) - tracksOnBoot++; + if(!_track1UsedByFiles) tracksOnBoot++; - if(!_track2UsedByFiles) - tracksOnBoot++; + if(!_track2UsedByFiles) tracksOnBoot++; ErrorNumber errno = _device.ReadSectors(0, (uint)(tracksOnBoot * _sectorsPerTrack), out _bootBlocks); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; _usedSectors += (uint)(_bootBlocks.Length / _vtoc.bytesPerSector); diff --git a/Aaru.Filesystems/AppleDOS/Info.cs b/Aaru.Filesystems/AppleDOS/Info.cs index 6958df452..6efcf2a17 100644 --- a/Aaru.Filesystems/AppleDOS/Info.cs +++ b/Aaru.Filesystems/AppleDOS/Info.cs @@ -7,10 +7,6 @@ // // Component : Apple DOS filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Apple DOS filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,85 +23,86 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; -using Claunia.Encoding; -using Schemas; -using Encoding = System.Text.Encoding; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class AppleDOS { +#region IReadOnlyFilesystem Members + /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(imagePlugin.Info.Sectors != 455 && - imagePlugin.Info.Sectors != 560) - return false; + if(imagePlugin.Info.Sectors != 455 && imagePlugin.Info.Sectors != 560) return false; - if(partition.Start > 0 || - imagePlugin.Info.SectorSize != 256) - return false; + if(partition.Start > 0 || imagePlugin.Info.SectorSize != 256) return false; int spt = imagePlugin.Info.Sectors == 455 ? 13 : 16; ErrorNumber errno = imagePlugin.ReadSector((ulong)(17 * spt), out byte[] vtocB); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; _vtoc = Marshal.ByteArrayToStructureLittleEndian(vtocB); - return _vtoc.catalogSector < spt && _vtoc.maxTrackSectorPairsPerSector <= 122 && _vtoc.sectorsPerTrack == spt && - _vtoc.bytesPerSector == 256; + return _vtoc.catalogSector < spt && + _vtoc.maxTrackSectorPairsPerSector <= 122 && + _vtoc.sectorsPerTrack == spt && + _vtoc.bytesPerSector == 256; } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = encoding ?? new Apple2(); information = ""; var sb = new StringBuilder(); + metadata = new FileSystem(); int spt = imagePlugin.Info.Sectors == 455 ? 13 : 16; ErrorNumber errno = imagePlugin.ReadSector((ulong)(17 * spt), out byte[] vtocB); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; _vtoc = Marshal.ByteArrayToStructureLittleEndian(vtocB); - sb.AppendLine("Apple DOS File System"); + sb.AppendLine(Localization.AppleDOS_Name); sb.AppendLine(); - sb.AppendFormat("Catalog starts at sector {0} of track {1}", _vtoc.catalogSector, _vtoc.catalogTrack). - AppendLine(); + sb.AppendFormat(Localization.Catalog_starts_at_sector_0_of_track_1, _vtoc.catalogSector, _vtoc.catalogTrack) + .AppendLine(); - sb.AppendFormat("File system initialized by DOS release {0}", _vtoc.dosRelease).AppendLine(); - sb.AppendFormat("Disk volume number {0}", _vtoc.volumeNumber).AppendLine(); - sb.AppendFormat("Sectors allocated at most in track {0}", _vtoc.lastAllocatedSector).AppendLine(); - sb.AppendFormat("{0} tracks in volume", _vtoc.tracks).AppendLine(); - sb.AppendFormat("{0} sectors per track", _vtoc.sectorsPerTrack).AppendLine(); - sb.AppendFormat("{0} bytes per sector", _vtoc.bytesPerSector).AppendLine(); + sb.AppendFormat(Localization.File_system_initialized_by_DOS_release_0, _vtoc.dosRelease).AppendLine(); + sb.AppendFormat(Localization.Disk_volume_number_0, _vtoc.volumeNumber).AppendLine(); + sb.AppendFormat(Localization.Sectors_allocated_at_most_in_track_0, _vtoc.lastAllocatedSector).AppendLine(); + sb.AppendFormat(Localization._0_tracks_in_volume, _vtoc.tracks).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_track, _vtoc.sectorsPerTrack).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector, _vtoc.bytesPerSector).AppendLine(); - sb.AppendFormat("Track allocation is {0}", _vtoc.allocationDirection > 0 ? "forward" : "reverse").AppendLine(); + sb.AppendLine(_vtoc.allocationDirection > 0 + ? Localization.Track_allocation_is_forward + : Localization.Track_allocation_is_reverse); information = sb.ToString(); - XmlFsType = new FileSystemType + metadata = new FileSystem { Bootable = true, Clusters = imagePlugin.Info.Sectors, ClusterSize = imagePlugin.Info.SectorSize, - Type = "Apple DOS" + Type = FS_TYPE }; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleDOS/Structs.cs b/Aaru.Filesystems/AppleDOS/Structs.cs index 0ae3b4819..13e183299 100644 --- a/Aaru.Filesystems/AppleDOS/Structs.cs +++ b/Aaru.Filesystems/AppleDOS/Structs.cs @@ -7,10 +7,6 @@ // // Component : Apple DOS filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple DOS filesystem structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,15 +23,118 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System.Runtime.InteropServices; +using Aaru.CommonTypes.Interfaces; + namespace Aaru.Filesystems; -using System.Runtime.InteropServices; - public sealed partial class AppleDOS { +#region Nested type: AppleDosDirNode + + sealed class AppleDosDirNode : IDirNode + { + internal string[] Contents; + internal int Position; + +#region IDirNode Members + + /// + public string Path { get; init; } + +#endregion + } + +#endregion + +#region Nested type: AppleDosFileNode + + sealed class AppleDosFileNode : IFileNode + { + internal byte[] Cache; + +#region IFileNode Members + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + +#endregion + } + +#endregion + +#region Nested type: CatalogSector + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct CatalogSector + { + public readonly byte unused1; + public readonly byte trackOfNext; + public readonly byte sectorOfNext; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] unused2; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public readonly FileEntry[] entries; + } + +#endregion + +#region Nested type: FileEntry + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct FileEntry + { + public readonly byte extentTrack; + public readonly byte extentSector; + public readonly byte typeAndFlags; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)] + public readonly byte[] filename; + public readonly ushort length; + } + +#endregion + +#region Nested type: TrackSectorList + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct TrackSectorList + { + public readonly byte unused1; + public readonly byte nextListTrack; + public readonly byte nextListSector; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public readonly byte[] unused2; + public readonly ushort sectorOffset; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public readonly byte[] unused3; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 122)] + public readonly TrackSectorListEntry[] entries; + } + +#endregion + +#region Nested type: TrackSectorListEntry + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct TrackSectorListEntry + { + public readonly byte track; + public readonly byte sector; + } + +#endregion + +#region Nested type: Vtoc + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct Vtoc { @@ -62,48 +161,5 @@ public sealed partial class AppleDOS public readonly byte[] bitmap; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct CatalogSector - { - public readonly byte unused1; - public readonly byte trackOfNext; - public readonly byte sectorOfNext; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] unused2; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] - public readonly FileEntry[] entries; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct FileEntry - { - public readonly byte extentTrack; - public readonly byte extentSector; - public readonly byte typeAndFlags; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)] - public readonly byte[] filename; - public readonly ushort length; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct TrackSectorList - { - public readonly byte unused1; - public readonly byte nextListTrack; - public readonly byte nextListSector; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public readonly byte[] unused2; - public readonly ushort sectorOffset; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public readonly byte[] unused3; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 122)] - public readonly TrackSectorListEntry[] entries; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct TrackSectorListEntry - { - public readonly byte track; - public readonly byte sector; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleDOS/Super.cs b/Aaru.Filesystems/AppleDOS/Super.cs index 6c726b47c..181e2f041 100644 --- a/Aaru.Filesystems/AppleDOS/Super.cs +++ b/Aaru.Filesystems/AppleDOS/Super.cs @@ -7,10 +7,6 @@ // // Component : Apple DOS filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Handles mounting and umounting the Apple DOS filesystem. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,50 +23,51 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Collections.Generic; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Helpers; using Claunia.Encoding; -using Schemas; using Encoding = System.Text.Encoding; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class AppleDOS { - /// - public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, - Dictionary options, string @namespace) - { - _device = imagePlugin; - _start = partition.Start; - Encoding = encoding ?? new Apple2(); +#region IReadOnlyFilesystem Members - if(_device.Info.Sectors != 455 && - _device.Info.Sectors != 560) + /// + public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace) + { + _device = imagePlugin; + _start = partition.Start; + _encoding = encoding ?? new Apple2(); + + if(_device.Info.Sectors != 455 && _device.Info.Sectors != 560) { - AaruConsole.DebugWriteLine("Apple DOS plugin", "Incorrect device size."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Incorrect_device_size); return ErrorNumber.InOutError; } if(_start > 0) { - AaruConsole.DebugWriteLine("Apple DOS plugin", "Partitions are not supported."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Partitions_are_not_supported); return ErrorNumber.InOutError; } if(_device.Info.SectorSize != 256) { - AaruConsole.DebugWriteLine("Apple DOS plugin", "Incorrect sector size."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Incorrect_sector_size); return ErrorNumber.InOutError; } @@ -80,8 +77,7 @@ public sealed partial class AppleDOS // Read the VTOC ErrorNumber error = _device.ReadSector((ulong)(17 * _sectorsPerTrack), out _vtocBlocks); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; _vtoc = Marshal.ByteArrayToStructureLittleEndian(_vtocBlocks); @@ -93,38 +89,37 @@ public sealed partial class AppleDOS if(error != ErrorNumber.NoError) { - AaruConsole.DebugWriteLine("Apple DOS plugin", "Unable to read catalog."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Unable_to_read_catalog); return error; } + _fileSizeCache = new Dictionary(); + error = CacheAllFiles(); if(error != ErrorNumber.NoError) { - AaruConsole.DebugWriteLine("Apple DOS plugin", "Unable cache all files."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Unable_cache_all_files); return error; } // Create XML metadata for mounted filesystem - XmlFsType = new FileSystemType + Metadata = new FileSystem { - Bootable = true, - Clusters = _device.Info.Sectors, - ClusterSize = _vtoc.bytesPerSector, - Files = (ulong)_catalogCache.Count, - FilesSpecified = true, - FreeClustersSpecified = true, - Type = "Apple DOS" + Bootable = true, + Clusters = _device.Info.Sectors, + ClusterSize = _vtoc.bytesPerSector, + Files = (ulong)_catalogCache.Count, + Type = FS_TYPE }; - XmlFsType.FreeClusters = XmlFsType.Clusters - _usedSectors; + Metadata.FreeClusters = Metadata.Clusters - _usedSectors; options ??= GetDefaultOptions(); - if(options.TryGetValue("debug", out string debugString)) - bool.TryParse(debugString, out _debug); + if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out _debug); _mounted = true; @@ -152,7 +147,7 @@ public sealed partial class AppleDOS FilenameLength = 30, Files = (ulong)_catalogCache.Count, PluginId = Id, - Type = "Apple DOS" + Type = FS_TYPE }; stat.FreeFiles = _totalFileEntries - stat.Files; @@ -160,4 +155,6 @@ public sealed partial class AppleDOS return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleDOS/Xattr.cs b/Aaru.Filesystems/AppleDOS/Xattr.cs index 37ca90085..6a80951df 100644 --- a/Aaru.Filesystems/AppleDOS/Xattr.cs +++ b/Aaru.Filesystems/AppleDOS/Xattr.cs @@ -27,52 +27,51 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using Aaru.CommonTypes.Enums; +namespace Aaru.Filesystems; + public sealed partial class AppleDOS { +#region IReadOnlyFilesystem Members + /// public ErrorNumber ListXAttr(string path, out List xattrs) { xattrs = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; string filename = pathElements[0].ToUpperInvariant(); - if(filename.Length > 30) - return ErrorNumber.NameTooLong; + if(filename.Length > 30) return ErrorNumber.NameTooLong; - xattrs = new List(); + xattrs = []; - if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) {} + if(_debug && + (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) {} else { - if(!_catalogCache.ContainsKey(filename)) - return ErrorNumber.NoSuchFile; + if(!_catalogCache.ContainsKey(filename)) return ErrorNumber.NoSuchFile; xattrs.Add("com.apple.dos.type"); - if(_debug) - xattrs.Add("com.apple.dos.tracksectorlist"); + if(_debug) xattrs.Add("com.apple.dos.tracksectorlist"); } return ErrorNumber.NoError; @@ -81,34 +80,31 @@ public sealed partial class AppleDOS /// public ErrorNumber GetXattr(string path, string xattr, ref byte[] buf) { - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; string filename = pathElements[0].ToUpperInvariant(); - if(filename.Length > 30) - return ErrorNumber.NameTooLong; + if(filename.Length > 30) return ErrorNumber.NameTooLong; - if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) + if(_debug && + (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) return ErrorNumber.NoSuchExtendedAttribute; - if(!_catalogCache.ContainsKey(filename)) - return ErrorNumber.NoSuchFile; + if(!_catalogCache.ContainsKey(filename)) return ErrorNumber.NoSuchFile; if(string.Compare(xattr, "com.apple.dos.type", StringComparison.InvariantCulture) == 0) { - if(!_fileTypeCache.TryGetValue(filename, out byte type)) - return ErrorNumber.InvalidArgument; + if(!_fileTypeCache.TryGetValue(filename, out byte type)) return ErrorNumber.InvalidArgument; buf = new byte[1]; buf[0] = type; @@ -116,16 +112,16 @@ public sealed partial class AppleDOS return ErrorNumber.NoError; } - if(string.Compare(xattr, "com.apple.dos.tracksectorlist", StringComparison.InvariantCulture) != 0 || - !_debug) + if(string.Compare(xattr, "com.apple.dos.tracksectorlist", StringComparison.InvariantCulture) != 0 || !_debug) return ErrorNumber.NoSuchExtendedAttribute; - if(!_extentCache.TryGetValue(filename, out byte[] ts)) - return ErrorNumber.InvalidArgument; + if(!_extentCache.TryGetValue(filename, out byte[] ts)) return ErrorNumber.InvalidArgument; buf = new byte[ts.Length]; Array.Copy(ts, 0, buf, 0, buf.Length); return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleHFS/AppleHFS.cs b/Aaru.Filesystems/AppleHFS/AppleHFS.cs index b5a7250ec..f562de182 100644 --- a/Aaru.Filesystems/AppleHFS/AppleHFS.cs +++ b/Aaru.Filesystems/AppleHFS/AppleHFS.cs @@ -28,15 +28,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; -using System.Text; using Aaru.CommonTypes.Interfaces; -using Schemas; + +namespace Aaru.Filesystems; // Information from Inside Macintosh // https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf @@ -44,14 +42,16 @@ using Schemas; /// Implements detection of the Apple Hierarchical File System (HFS) public sealed partial class AppleHFS : IFilesystem { +#region IFilesystem Members + /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Apple Hierarchical File System"; + public string Name => Localization.Name_Apple_Hierarchical_File_System; + /// public Guid Id => new("36405F8D-0D26-6ECC-0BBB-1D5225FF404F"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleHFS/Consts.cs b/Aaru.Filesystems/AppleHFS/Consts.cs index 61f204a9c..ec82fa3c4 100644 --- a/Aaru.Filesystems/AppleHFS/Consts.cs +++ b/Aaru.Filesystems/AppleHFS/Consts.cs @@ -7,10 +7,6 @@ // // Component : Apple Hierarchical File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple Hierarchical File System constants. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,17 +23,15 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable InconsistentNaming -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; +namespace Aaru.Filesystems; + // Information from Inside Macintosh // https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf [SuppressMessage("ReSharper", "UnusedMember.Local")] @@ -53,4 +47,7 @@ public sealed partial class AppleHFS const uint kCatalogFileCnid = 4; /// File number of the bad allocation block file. const uint kBadBlocksFileCnid = 5; + + // Do not translate + const string FS_TYPE = "hfs"; } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleHFS/Enums.cs b/Aaru.Filesystems/AppleHFS/Enums.cs index f6f1bb038..04e554392 100644 --- a/Aaru.Filesystems/AppleHFS/Enums.cs +++ b/Aaru.Filesystems/AppleHFS/Enums.cs @@ -7,10 +7,6 @@ // // Component : Apple Hierarchical File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple Hierarchical File System enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,7 +23,7 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable InconsistentNaming @@ -38,17 +34,7 @@ namespace Aaru.Filesystems; public sealed partial class AppleHFS { - enum NodeType : sbyte - { - /// Index node - ndIndxNode = 0, - /// Header node - ndHdrNode = 1, - /// Map node - ndMapNode = 2, - /// Leaf node - ndLeafNode = -1 - } +#region Nested type: CatDataType enum CatDataType : sbyte { @@ -62,9 +48,31 @@ public sealed partial class AppleHFS cdrFThdRec = 4 } +#endregion + +#region Nested type: ForkType + enum ForkType : sbyte { Data = 0, Resource = -1 } + +#endregion + +#region Nested type: NodeType + + enum NodeType : sbyte + { + /// Index node + ndIndxNode = 0, + /// Header node + ndHdrNode = 1, + /// Map node + ndMapNode = 2, + /// Leaf node + ndLeafNode = -1 + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleHFS/Info.cs b/Aaru.Filesystems/AppleHFS/Info.cs index 2da9ed7ad..8e9f8824c 100644 --- a/Aaru.Filesystems/AppleHFS/Info.cs +++ b/Aaru.Filesystems/AppleHFS/Info.cs @@ -7,10 +7,6 @@ // // Component : Apple Hierarchical File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Apple Hierarchical File System and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,29 +23,30 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Linq; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; -using Schemas; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; // Information from Inside Macintosh // https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf public sealed partial class AppleHFS { +#region IFilesystem Members + /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(2 + partition.Start >= partition.End) - return false; + if(2 + partition.Start >= partition.End) return false; byte[] mdbSector; ushort drSigWord; @@ -59,8 +56,7 @@ public sealed partial class AppleHFS { errno = imagePlugin.ReadSectors(partition.Start, 2, out mdbSector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; foreach(int offset in new[] { @@ -69,8 +65,7 @@ public sealed partial class AppleHFS { drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, offset); - if(drSigWord != AppleCommon.HFS_MAGIC) - continue; + if(drSigWord != AppleCommon.HFS_MAGIC) continue; drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, offset + 0x7C); // Seek to embedded HFS+ signature @@ -81,16 +76,13 @@ public sealed partial class AppleHFS { errno = imagePlugin.ReadSector(2 + partition.Start, out mdbSector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; - if(mdbSector.Length < 0x7C + 2) - return false; + if(mdbSector.Length < 0x7C + 2) return false; drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0); - if(drSigWord != AppleCommon.HFS_MAGIC) - return false; + if(drSigWord != AppleCommon.HFS_MAGIC) return false; drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0x7C); // Seek to embedded HFS+ signature @@ -101,10 +93,12 @@ public sealed partial class AppleHFS } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = encoding ?? Encoding.GetEncoding("macintosh"); - information = ""; + encoding ??= Encoding.GetEncoding("macintosh"); + information = ""; + metadata = new FileSystem(); var sb = new StringBuilder(); @@ -119,8 +113,7 @@ public sealed partial class AppleHFS { errno = imagePlugin.ReadSectors(partition.Start, 2, out byte[] tmpSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; foreach(int offset in new[] { @@ -129,14 +122,12 @@ public sealed partial class AppleHFS { drSigWord = BigEndianBitConverter.ToUInt16(tmpSector, offset); - if(drSigWord != AppleCommon.HFS_MAGIC) - continue; + if(drSigWord != AppleCommon.HFS_MAGIC) continue; bbSector = new byte[1024]; mdbSector = new byte[512]; - if(offset >= 0x400) - Array.Copy(tmpSector, offset - 0x400, bbSector, 0, 1024); + if(offset >= 0x400) Array.Copy(tmpSector, offset - 0x400, bbSector, 0, 1024); Array.Copy(tmpSector, offset, mdbSector, 0, 512); apmFromHddOnCd = true; @@ -144,15 +135,13 @@ public sealed partial class AppleHFS break; } - if(!apmFromHddOnCd) - return; + if(!apmFromHddOnCd) return; } else { errno = imagePlugin.ReadSector(2 + partition.Start, out mdbSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0); @@ -160,8 +149,7 @@ public sealed partial class AppleHFS { errno = imagePlugin.ReadSector(partition.Start, out bbSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; } else return; @@ -169,151 +157,135 @@ public sealed partial class AppleHFS MasterDirectoryBlock mdb = Marshal.ByteArrayToStructureBigEndian(mdbSector); - sb.AppendLine("Apple Hierarchical File System"); + sb.AppendLine(Localization.Name_Apple_Hierarchical_File_System); sb.AppendLine(); if(apmFromHddOnCd) - sb.AppendLine("HFS uses 512 bytes/sector while device uses 2048 bytes/sector.").AppendLine(); + sb.AppendLine(Localization.HFS_uses_512_bytes_sector_while_device_uses_2048_bytes_sector).AppendLine(); - sb.AppendLine("Master Directory Block:"); - sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine(); - sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(mdb.drLsMod)).AppendLine(); + sb.AppendLine(Localization.Master_Directory_Block); + sb.AppendFormat(Localization.Creation_date_0, DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine(); + sb.AppendFormat(Localization.Last_modification_date_0, DateHandlers.MacToDateTime(mdb.drLsMod)).AppendLine(); if(mdb.drVolBkUp > 0) { - sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(mdb.drVolBkUp)).AppendLine(); - sb.AppendFormat("Backup sequence number: {0}", mdb.drVSeqNum).AppendLine(); + sb.AppendFormat(Localization.Last_backup_date_0, DateHandlers.MacToDateTime(mdb.drVolBkUp)).AppendLine(); + sb.AppendFormat(Localization.Backup_sequence_number_0, mdb.drVSeqNum).AppendLine(); } else - sb.AppendLine("Volume has never been backed up"); + sb.AppendLine(Localization.Volume_has_never_been_backed_up); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.HardwareLock)) - sb.AppendLine("Volume is locked by hardware."); + sb.AppendLine(Localization.Volume_is_locked_by_hardware); - sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted) ? "Volume was unmonted." - : "Volume is mounted."); + sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted) + ? Localization.Volume_was_unmonted + : Localization.Volume_is_mounted); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SparedBadBlocks)) - sb.AppendLine("Volume has spared bad blocks."); + sb.AppendLine(Localization.Volume_has_spared_bad_blocks); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.DoesNotNeedCache)) - sb.AppendLine("Volume does not need cache."); + sb.AppendLine(Localization.Volume_does_not_need_cache); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.BootInconsistent)) - sb.AppendLine("Boot volume is inconsistent."); + sb.AppendLine(Localization.Boot_volume_is_inconsistent); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.ReusedIds)) - sb.AppendLine("There are reused CNIDs."); + sb.AppendLine(Localization.There_are_reused_CNIDs); - if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Journaled)) - sb.AppendLine("Volume is journaled."); + if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Journaled)) sb.AppendLine(Localization.Volume_is_journaled); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Inconsistent)) - sb.AppendLine("Volume is seriously inconsistent."); + sb.AppendLine(Localization.Volume_is_seriously_inconsistent); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SoftwareLock)) - sb.AppendLine("Volume is locked by software."); + sb.AppendLine(Localization.Volume_is_locked_by_software); - sb.AppendFormat("{0} files on root directory", mdb.drNmFls).AppendLine(); - sb.AppendFormat("{0} directories on root directory", mdb.drNmRtDirs).AppendLine(); - sb.AppendFormat("{0} files on volume", mdb.drFilCnt).AppendLine(); - sb.AppendFormat("{0} directories on volume", mdb.drDirCnt).AppendLine(); - sb.AppendFormat("Volume write count: {0}", mdb.drWrCnt).AppendLine(); + sb.AppendFormat(Localization._0_files_in_root_directory, mdb.drNmFls).AppendLine(); + sb.AppendFormat(Localization._0_directories_in_root_directory, mdb.drNmRtDirs).AppendLine(); + sb.AppendFormat(Localization._0_files_in_volume, mdb.drFilCnt).AppendLine(); + sb.AppendFormat(Localization._0_directories_in_volume, mdb.drDirCnt).AppendLine(); + sb.AppendFormat(Localization.Volume_write_count_0, mdb.drWrCnt).AppendLine(); - sb.AppendFormat("Volume bitmap starting sector (in 512-bytes): {0}", mdb.drVBMSt).AppendLine(); - sb.AppendFormat("Next allocation block: {0}.", mdb.drAllocPtr).AppendLine(); - sb.AppendFormat("{0} volume allocation blocks.", mdb.drNmAlBlks).AppendLine(); - sb.AppendFormat("{0} bytes per allocation block.", mdb.drAlBlkSiz).AppendLine(); - sb.AppendFormat("{0} bytes to allocate when extending a file.", mdb.drClpSiz).AppendLine(); - sb.AppendFormat("{0} bytes to allocate when extending a Extents B-Tree.", mdb.drXTClpSiz).AppendLine(); - sb.AppendFormat("{0} bytes to allocate when extending a Catalog B-Tree.", mdb.drCTClpSiz).AppendLine(); - sb.AppendFormat("Sector of first allocation block: {0}", mdb.drAlBlSt).AppendLine(); - sb.AppendFormat("Next unused CNID: {0}", mdb.drNxtCNID).AppendLine(); - sb.AppendFormat("{0} unused allocation blocks.", mdb.drFreeBks).AppendLine(); + sb.AppendFormat(Localization.Volume_bitmap_starting_sector_in_512_bytes_0, mdb.drVBMSt).AppendLine(); + sb.AppendFormat(Localization.Next_allocation_block_0, mdb.drAllocPtr).AppendLine(); + sb.AppendFormat(Localization._0_volume_allocation_blocks, mdb.drNmAlBlks).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_allocation_block, mdb.drAlBlkSiz).AppendLine(); + sb.AppendFormat(Localization._0_bytes_to_allocate_when_extending_a_file, mdb.drClpSiz).AppendLine(); + sb.AppendFormat(Localization._0_bytes_to_allocate_when_extending_a_Extents_B_Tree, mdb.drXTClpSiz).AppendLine(); + sb.AppendFormat(Localization._0_bytes_to_allocate_when_extending_a_Catalog_B_Tree, mdb.drCTClpSiz).AppendLine(); + sb.AppendFormat(Localization.Sector_of_first_allocation_block_0, mdb.drAlBlSt).AppendLine(); + sb.AppendFormat(Localization.Next_unused_CNID_0, mdb.drNxtCNID).AppendLine(); + sb.AppendFormat(Localization._0_unused_allocation_blocks, mdb.drFreeBks).AppendLine(); - sb.AppendFormat("{0} bytes in the Extents B-Tree", mdb.drXTFlSize).AppendLine(); - sb.AppendFormat("{0} bytes in the Catalog B-Tree", mdb.drCTFlSize).AppendLine(); + sb.AppendFormat(Localization._0_bytes_in_the_Extents_B_Tree, mdb.drXTFlSize).AppendLine(); + sb.AppendFormat(Localization._0_bytes_in_the_Catalog_B_Tree, mdb.drCTFlSize).AppendLine(); - sb.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(mdb.drVN, Encoding)).AppendLine(); + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.PascalToString(mdb.drVN, encoding)).AppendLine(); - sb.AppendLine("Finder info:"); - sb.AppendFormat("CNID of bootable system's directory: {0}", mdb.drFndrInfo0).AppendLine(); - sb.AppendFormat("CNID of first-run application's directory: {0}", mdb.drFndrInfo1).AppendLine(); - sb.AppendFormat("CNID of previously opened directory: {0}", mdb.drFndrInfo2).AppendLine(); - sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", mdb.drFndrInfo3).AppendLine(); - sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", mdb.drFndrInfo5).AppendLine(); + sb.AppendLine(Localization.Finder_info); + sb.AppendFormat(Localization.CNID_of_bootable_system_directory_0, mdb.drFndrInfo0).AppendLine(); + sb.AppendFormat(Localization.CNID_of_first_run_application_directory_0, mdb.drFndrInfo1).AppendLine(); + sb.AppendFormat(Localization.CNID_of_previously_opened_directory_0, mdb.drFndrInfo2).AppendLine(); + sb.AppendFormat(Localization.CNID_of_bootable_Mac_OS_8_or_9_directory_0, mdb.drFndrInfo3).AppendLine(); + sb.AppendFormat(Localization.CNID_of_bootable_Mac_OS_X_directory_0, mdb.drFndrInfo5).AppendLine(); - if(mdb.drFndrInfo6 != 0 && - mdb.drFndrInfo7 != 0) - sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", mdb.drFndrInfo6, mdb.drFndrInfo7).AppendLine(); + if(mdb.drFndrInfo6 != 0 && mdb.drFndrInfo7 != 0) + sb.AppendFormat(Localization.Mac_OS_X_Volume_ID_0_1, mdb.drFndrInfo6, mdb.drFndrInfo7).AppendLine(); if(mdb.drEmbedSigWord == AppleCommon.HFSP_MAGIC) { - sb.AppendLine("Volume wraps a HFS+ volume."); - sb.AppendFormat("Starting block of the HFS+ volume: {0}", mdb.xdrStABNt).AppendLine(); - sb.AppendFormat("Allocations blocks of the HFS+ volume: {0}", mdb.xdrNumABlks).AppendLine(); + sb.AppendLine(Localization.Volume_wraps_a_HFS_Plus_volume); + sb.AppendFormat(Localization.Starting_block_of_the_HFS_Plus_volume_0, mdb.xdrStABNt).AppendLine(); + sb.AppendFormat(Localization.Allocations_blocks_of_the_HFS_Plus_volume_0, mdb.xdrNumABlks).AppendLine(); } else { - sb.AppendFormat("{0} blocks in volume cache", mdb.drVCSize).AppendLine(); - sb.AppendFormat("{0} blocks in volume bitmap cache", mdb.drVBMCSize).AppendLine(); - sb.AppendFormat("{0} blocks in volume common cache", mdb.drCtlCSize).AppendLine(); + sb.AppendFormat(Localization._0_blocks_in_volume_cache, mdb.drVCSize).AppendLine(); + sb.AppendFormat(Localization._0_blocks_in_volume_bitmap_cache, mdb.drVBMCSize).AppendLine(); + sb.AppendFormat(Localization._0_blocks_in_volume_common_cache, mdb.drCtlCSize).AppendLine(); } - string bootBlockInfo = AppleCommon.GetBootBlockInformation(bbSector, Encoding); + string bootBlockInfo = AppleCommon.GetBootBlockInformation(bbSector, encoding); if(bootBlockInfo != null) { - sb.AppendLine("Volume is bootable."); + sb.AppendLine(Localization.Volume_is_bootable); sb.AppendLine(); sb.AppendLine(bootBlockInfo); } - else if(mdb.drFndrInfo0 != 0 || - mdb.drFndrInfo3 != 0 || - mdb.drFndrInfo5 != 0) - sb.AppendLine("Volume is bootable."); + else if(mdb.drFndrInfo0 != 0 || mdb.drFndrInfo3 != 0 || mdb.drFndrInfo5 != 0) + sb.AppendLine(Localization.Volume_is_bootable); else - sb.AppendLine("Volume is not bootable."); + sb.AppendLine(Localization.Volume_is_not_bootable); information = sb.ToString(); - XmlFsType = new FileSystemType(); + metadata = new FileSystem(); - if(mdb.drVolBkUp > 0) - { - XmlFsType.BackupDate = DateHandlers.MacToDateTime(mdb.drVolBkUp); - XmlFsType.BackupDateSpecified = true; - } + if(mdb.drVolBkUp > 0) metadata.BackupDate = DateHandlers.MacToDateTime(mdb.drVolBkUp); - XmlFsType.Bootable = bootBlockInfo != null || mdb.drFndrInfo0 != 0 || mdb.drFndrInfo3 != 0 || - mdb.drFndrInfo5 != 0; + metadata.Bootable = + bootBlockInfo != null || mdb.drFndrInfo0 != 0 || mdb.drFndrInfo3 != 0 || mdb.drFndrInfo5 != 0; - XmlFsType.Clusters = mdb.drNmAlBlks; - XmlFsType.ClusterSize = mdb.drAlBlkSiz; + metadata.Clusters = mdb.drNmAlBlks; + metadata.ClusterSize = mdb.drAlBlkSiz; - if(mdb.drCrDate > 0) - { - XmlFsType.CreationDate = DateHandlers.MacToDateTime(mdb.drCrDate); - XmlFsType.CreationDateSpecified = true; - } + if(mdb.drCrDate > 0) metadata.CreationDate = DateHandlers.MacToDateTime(mdb.drCrDate); - XmlFsType.Dirty = !mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted); - XmlFsType.Files = mdb.drFilCnt; - XmlFsType.FilesSpecified = true; - XmlFsType.FreeClusters = mdb.drFreeBks; - XmlFsType.FreeClustersSpecified = true; + metadata.Dirty = !mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted); + metadata.Files = mdb.drFilCnt; + metadata.FreeClusters = mdb.drFreeBks; - if(mdb.drLsMod > 0) - { - XmlFsType.ModificationDate = DateHandlers.MacToDateTime(mdb.drLsMod); - XmlFsType.ModificationDateSpecified = true; - } + if(mdb.drLsMod > 0) metadata.ModificationDate = DateHandlers.MacToDateTime(mdb.drLsMod); - XmlFsType.Type = "HFS"; - XmlFsType.VolumeName = StringHandlers.PascalToString(mdb.drVN, Encoding); + metadata.Type = FS_TYPE; + metadata.VolumeName = StringHandlers.PascalToString(mdb.drVN, encoding); - if(mdb.drFndrInfo6 != 0 && - mdb.drFndrInfo7 != 0) - XmlFsType.VolumeSerial = $"{mdb.drFndrInfo6:X8}{mdb.drFndrInfo7:X8}"; + if(mdb.drFndrInfo6 != 0 && mdb.drFndrInfo7 != 0) + metadata.VolumeSerial = $"{mdb.drFndrInfo6:X8}{mdb.drFndrInfo7:X8}"; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleHFS/Structs.cs b/Aaru.Filesystems/AppleHFS/Structs.cs index e8e228f0e..b60530eb0 100644 --- a/Aaru.Filesystems/AppleHFS/Structs.cs +++ b/Aaru.Filesystems/AppleHFS/Structs.cs @@ -7,10 +7,6 @@ // // Component : Apple Hierarchical File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple Hierarchical File System structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,24 +23,245 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable UnusedType.Local // ReSharper disable IdentifierTypo // ReSharper disable MemberCanBePrivate.Local -namespace Aaru.Filesystems; - using System.Runtime.InteropServices; +namespace Aaru.Filesystems; + // Information from Inside Macintosh // https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf public sealed partial class AppleHFS { +#region Nested type: BTHdrRed + + /// B*-tree header + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct BTHdrRed + { + /// Current depth of tree. + public readonly ushort bthDepth; + /// Number of root node. + public readonly uint bthRoot; + /// Number of leaf records in tree. + public readonly uint bthNRecs; + /// Number of first leaf node. + public readonly uint bthFNode; + /// Number of last leaf node. + public readonly uint bthLNode; + /// Size of a node. + public readonly ushort bthNodeSize; + /// Maximum length of a key. + public readonly ushort bthKeyLen; + /// Total number of nodes in tree. + public readonly uint bthNNodes; + /// Number of free nodes. + public readonly uint bthFree; + /// Reserved + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 76)] + public readonly sbyte[] bthResv; + } + +#endregion + +#region Nested type: CatDataRec + + /// Catalog data record header + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct CatDataRec + { + public readonly CatDataType cdrType; + public readonly sbyte cdrResvr2; + } + +#endregion + +#region Nested type: CatKeyRec + + /// Catalog key record + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct CatKeyRec + { + /// Key length. + public readonly sbyte ckrKeyLen; + /// Reserved. + public readonly sbyte ckrResrv1; + /// Parent directory ID. + public readonly uint ckrParID; + /// Catalog node name. Full 32 bytes in index nodes but only the needed bytes, padded to word, in leaf nodes. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] ckrCName; + } + +#endregion + +#region Nested type: CdrDirRec + + /// Directory record + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct CdrDirRec + { + public readonly CatDataRec dirHdr; + /// Directory flags. + public readonly ushort dirFlags; + /// Directory valence. + public readonly ushort dirVal; + /// Directory ID. + public readonly uint dirDirID; + /// Date and time of creation. + public readonly uint dirCrDat; + /// Date and time of last modification. + public readonly uint dirMdDat; + /// Date and time of last backup. + public readonly uint dirBkDat; + /// Finder information. + public readonly AppleCommon.DInfo dirUsrInfo; + /// Additional Finder information. + public readonly AppleCommon.DXInfo dirFndrInfo; + /// Reserved + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly uint[] dirResrv; + } + +#endregion + +#region Nested type: CdrFilRec + + /// File record + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct CdrFilRec + { + public readonly CatDataRec filHdr; + /// File flags. + public readonly sbyte filFlags; + /// File type. + public readonly sbyte filType; + /// Finder information. + public readonly AppleCommon.FInfo filUsrWds; + /// File ID. + public readonly uint filFlNum; + /// First allocation block of data fork. + public readonly ushort filStBlk; + /// Logical EOF of data fork. + public readonly uint filLgLen; + /// Physical EOF of data fork. + public readonly uint filPyLen; + /// First allocation block of resource fork. + public readonly ushort filRStBlk; + /// Logical EOF of resource fork. + public readonly uint filRLgLen; + /// Physical EOF of resource fork. + public readonly uint filRPyLen; + /// Date and time of creation. + public readonly uint filCrDat; + /// Date and time of last modification. + public readonly uint filMdDat; + /// Date and time of last backup. + public readonly uint filBkDat; + /// Additional Finder information. + public readonly AppleCommon.FXInfo filFndrInfo; + /// File clump size. + public readonly ushort filClpSize; + /// First data fork extent record. + public readonly ExtDataRec filExtRec; + /// First resource fork extent record. + public readonly ExtDataRec filRExtRec; + /// Reserved + public readonly uint filResrv; + } + +#endregion + +#region Nested type: CdrFThdRec + + /// File thread record + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct CdrFThdRec + { + public readonly CatDataRec fthdHdr; + /// Reserved. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public readonly uint[] fthdResrv; + /// Parent ID for this file. + public readonly uint fthdParID; + /// Name of this file. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] fthdCName; + } + +#endregion + +#region Nested type: CdrThdRec + + /// Directory thread record + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct CdrThdRec + { + public readonly CatDataRec thdHdr; + /// Reserved. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public readonly uint[] thdResrv; + /// Parent ID for this directory. + public readonly uint thdParID; + /// Name of this directory. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] thdCName; + } + +#endregion + +#region Nested type: ExtDataRec + + /// Extent data record + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ExtDataRec + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly ExtDescriptor[] xdr; + } + +#endregion + +#region Nested type: ExtDescriptor + + /// Extent descriptor + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ExtDescriptor + { + /// First allocation block + public readonly ushort xdrStABN; + /// Number of allocation blocks + public readonly ushort xdrNumABlks; + } + +#endregion + +#region Nested type: ExtKeyRec + + /// Extent key record + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ExtKeyRec + { + /// Key length. + public readonly sbyte xkrKeyLen; + /// Fork type. + public readonly ForkType xkrFkType; + /// File number. + public readonly uint xkrFNum; + /// Starting file allocation block. + public readonly ushort xkrFABN; + } + +#endregion + +#region Nested type: MasterDirectoryBlock + /// Master Directory Block, should be sector 2 in volume [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct MasterDirectoryBlock // Should be sector 2 in volume @@ -134,6 +351,10 @@ public sealed partial class AppleHFS public readonly uint drCTFlSize; } +#endregion + +#region Nested type: NodeDescriptor + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct NodeDescriptor { @@ -151,184 +372,5 @@ public sealed partial class AppleHFS public readonly ushort ndResv2; } - /// B*-tree header - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct BTHdrRed - { - /// Current depth of tree. - public readonly ushort bthDepth; - /// Number of root node. - public readonly uint bthRoot; - /// Number of leaf records in tree. - public readonly uint bthNRecs; - /// Number of first leaf node. - public readonly uint bthFNode; - /// Number of last leaf node. - public readonly uint bthLNode; - /// Size of a node. - public readonly ushort bthNodeSize; - /// Maximum length of a key. - public readonly ushort bthKeyLen; - /// Total number of nodes in tree. - public readonly uint bthNNodes; - /// Number of free nodes. - public readonly uint bthFree; - /// Reserved - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 76)] - public readonly sbyte[] bthResv; - } - - /// Catalog key record - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct CatKeyRec - { - /// Key length. - public readonly sbyte ckrKeyLen; - /// Reserved. - public readonly sbyte ckrResrv1; - /// Parent directory ID. - public readonly uint ckrParID; - /// Catalog node name. Full 32 bytes in index nodes but only the needed bytes, padded to word, in leaf nodes. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] ckrCName; - } - - /// Catalog data record header - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct CatDataRec - { - public readonly CatDataType cdrType; - public readonly sbyte cdrResvr2; - } - - /// Directory record - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct CdrDirRec - { - public readonly CatDataRec dirHdr; - /// Directory flags. - public readonly ushort dirFlags; - /// Directory valence. - public readonly ushort dirVal; - /// Directory ID. - public readonly uint dirDirID; - /// Date and time of creation. - public readonly uint dirCrDat; - /// Date and time of last modification. - public readonly uint dirMdDat; - /// Date and time of last backup. - public readonly uint dirBkDat; - /// Finder information. - public readonly AppleCommon.DInfo dirUsrInfo; - /// Additional Finder information. - public readonly AppleCommon.DXInfo dirFndrInfo; - /// Reserved - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly uint[] dirResrv; - } - - /// File record - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct CdrFilRec - { - public readonly CatDataRec filHdr; - /// File flags. - public readonly sbyte filFlags; - /// File type. - public readonly sbyte filType; - /// Finder information. - public readonly AppleCommon.FInfo filUsrWds; - /// File ID. - public readonly uint filFlNum; - /// First allocation block of data fork. - public readonly ushort filStBlk; - /// Logical EOF of data fork. - public readonly uint filLgLen; - /// Physical EOF of data fork. - public readonly uint filPyLen; - /// First allocation block of resource fork. - public readonly ushort filRStBlk; - /// Logical EOF of resource fork. - public readonly uint filRLgLen; - /// Physical EOF of resource fork. - public readonly uint filRPyLen; - /// Date and time of creation. - public readonly uint filCrDat; - /// Date and time of last modification. - public readonly uint filMdDat; - /// Date and time of last backup. - public readonly uint filBkDat; - /// Additional Finder information. - public readonly AppleCommon.FXInfo filFndrInfo; - /// File clump size. - public readonly ushort filClpSize; - /// First data fork extent record. - public readonly ExtDataRec filExtRec; - /// First resource fork extent record. - public readonly ExtDataRec filRExtRec; - /// Reserved - public readonly uint filResrv; - } - - /// Directory thread record - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct CdrThdRec - { - public readonly CatDataRec thdHdr; - /// Reserved. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public readonly uint[] thdResrv; - /// Parent ID for this directory. - public readonly uint thdParID; - /// Name of this directory. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] thdCName; - } - - /// File thread record - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct CdrFThdRec - { - public readonly CatDataRec fthdHdr; - /// Reserved. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public readonly uint[] fthdResrv; - /// Parent ID for this file. - public readonly uint fthdParID; - /// Name of this file. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] fthdCName; - } - - /// Extent descriptor - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ExtDescriptor - { - /// First allocation block - public readonly ushort xdrStABN; - /// Number of allocation blocks - public readonly ushort xdrNumABlks; - } - - /// Extent data record - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ExtDataRec - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly ExtDescriptor[] xdr; - } - - /// Extent key record - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ExtKeyRec - { - /// Key length. - public readonly sbyte xkrKeyLen; - /// Fork type. - public readonly ForkType xkrFkType; - /// File number. - public readonly uint xkrFNum; - /// Starting file allocation block. - public readonly ushort xkrFABN; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleHFSPlus/AppleHFSPlus.cs b/Aaru.Filesystems/AppleHFSPlus/AppleHFSPlus.cs new file mode 100644 index 000000000..91dca170e --- /dev/null +++ b/Aaru.Filesystems/AppleHFSPlus/AppleHFSPlus.cs @@ -0,0 +1,51 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : AppleHFSPlus.cs +// Author(s) : Natalia Portillo +// +// Component : Apple Hierarchical File System Plus plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from Apple TechNote 1150: https://developer.apple.com/legacy/library/technotes/tn/tn1150.html +/// +/// Implements detection of Apple Hierarchical File System Plus (HFS+) +public sealed partial class AppleHFSPlus : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.AppleHFSPlus_Name; + + /// + public Guid Id => new("36405F8D-0D26-6EBE-436F-62F0586B4F08"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/AppleHFSPlus/Consts.cs b/Aaru.Filesystems/AppleHFSPlus/Consts.cs new file mode 100644 index 000000000..7010c9d19 --- /dev/null +++ b/Aaru.Filesystems/AppleHFSPlus/Consts.cs @@ -0,0 +1,38 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Apple Hierarchical File System Plus plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Information from Apple TechNote 1150: https://developer.apple.com/legacy/library/technotes/tn/tn1150.html +/// +/// Implements detection of Apple Hierarchical File System Plus (HFS+) +public sealed partial class AppleHFSPlus +{ + const string FS_TYPE_HFSP = "hfsplus"; + const string FS_TYPE_HFSX = "hfsx"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/AppleHFSPlus/Info.cs b/Aaru.Filesystems/AppleHFSPlus/Info.cs new file mode 100644 index 000000000..c7431e02f --- /dev/null +++ b/Aaru.Filesystems/AppleHFSPlus/Info.cs @@ -0,0 +1,290 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Apple Hierarchical File System Plus plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from Apple TechNote 1150: https://developer.apple.com/legacy/library/technotes/tn/tn1150.html +/// +/// Implements detection of Apple Hierarchical File System Plus (HFS+) +public sealed partial class AppleHFSPlus +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(2 + partition.Start >= partition.End) return false; + + ulong hfspOffset; + + uint sectorsToRead = 0x800 / imagePlugin.Info.SectorSize; + + if(0x800 % imagePlugin.Info.SectorSize > 0) sectorsToRead++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sectorsToRead, out byte[] vhSector); + + if(errno != ErrorNumber.NoError) return false; + + if(vhSector.Length < 0x800) return false; + + var drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400); + + if(drSigWord == AppleCommon.HFS_MAGIC) // "BD" + { + drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x47C); // Read embedded HFS+ signature + + if(drSigWord == AppleCommon.HFSP_MAGIC) // "H+" + { + // ReSharper disable once InconsistentNaming + var xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E); + + var drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414); + + var drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C); + + hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.Info.SectorSize); + } + else + hfspOffset = 0; + } + else + hfspOffset = 0; + + errno = imagePlugin.ReadSectors(partition.Start + hfspOffset, + sectorsToRead, + out vhSector); // Read volume header + + if(errno != ErrorNumber.NoError) return false; + + drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400); + + return drSigWord is AppleCommon.HFSP_MAGIC or AppleCommon.HFSX_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + + var vh = new VolumeHeader(); + + ulong hfspOffset; + bool wrapped; + + uint sectorsToRead = 0x800 / imagePlugin.Info.SectorSize; + + if(0x800 % imagePlugin.Info.SectorSize > 0) sectorsToRead++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sectorsToRead, out byte[] vhSector); + + if(errno != ErrorNumber.NoError) return; + + var drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400); + + if(drSigWord == AppleCommon.HFS_MAGIC) // "BD" + { + drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x47C); // Read embedded HFS+ signature + + if(drSigWord == AppleCommon.HFSP_MAGIC) // "H+" + { + // ReSharper disable once InconsistentNaming + var xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E); + + var drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414); + + var drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C); + + hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.Info.SectorSize); + wrapped = true; + } + else + { + hfspOffset = 0; + wrapped = false; + } + } + else + { + hfspOffset = 0; + wrapped = false; + } + + errno = imagePlugin.ReadSectors(partition.Start + hfspOffset, + sectorsToRead, + out vhSector); // Read volume header + + if(errno != ErrorNumber.NoError) return; + + vh.signature = BigEndianBitConverter.ToUInt16(vhSector, 0x400); + + if(vh.signature != AppleCommon.HFSP_MAGIC && vh.signature != AppleCommon.HFSX_MAGIC) return; + + var sb = new StringBuilder(); + + switch(vh.signature) + { + case 0x482B: + sb.AppendLine(Localization.HFS_filesystem); + + break; + case 0x4858: + sb.AppendLine(Localization.HFSX_filesystem); + + break; + } + + if(wrapped) sb.AppendLine(Localization.Volume_is_wrapped_inside_an_HFS_volume); + + var tmp = new byte[0x400]; + Array.Copy(vhSector, 0x400, tmp, 0, 0x400); + vhSector = tmp; + + vh = Marshal.ByteArrayToStructureBigEndian(vhSector); + + if(vh.version is 4 or 5) + { + sb.AppendFormat(Localization.Filesystem_version_is_0, vh.version).AppendLine(); + + if((vh.attributes & 0x80) == 0x80) sb.AppendLine(Localization.Volume_is_locked_by_hardware); + + if((vh.attributes & 0x100) == 0x100) sb.AppendLine(Localization.Volume_is_unmounted); + + if((vh.attributes & 0x200) == 0x200) sb.AppendLine(Localization.There_are_bad_blocks_in_the_extents_file); + + if((vh.attributes & 0x400) == 0x400) sb.AppendLine(Localization.Volume_does_not_need_cache); + + if((vh.attributes & 0x800) == 0x800) sb.AppendLine(Localization.Volume_state_is_inconsistent); + + if((vh.attributes & 0x1000) == 0x1000) sb.AppendLine(Localization.There_are_reused_CNIDs); + + if((vh.attributes & 0x2000) == 0x2000) sb.AppendLine(Localization.Volume_is_journaled); + + if((vh.attributes & 0x8000) == 0x8000) sb.AppendLine(Localization.Volume_is_locked_by_software); + + sb.AppendFormat(Localization.Implementation_that_last_mounted_the_volume_0, + Encoding.ASCII.GetString(vh.lastMountedVersion)) + .AppendLine(); + + if((vh.attributes & 0x2000) == 0x2000) + sb.AppendFormat(Localization.Journal_starts_at_allocation_block_0, vh.journalInfoBlock).AppendLine(); + + sb.AppendFormat(Localization.Creation_date_0, DateHandlers.MacToDateTime(vh.createDate)).AppendLine(); + + sb.AppendFormat(Localization.Last_modification_date_0, DateHandlers.MacToDateTime(vh.modifyDate)) + .AppendLine(); + + if(vh.backupDate > 0) + { + sb.AppendFormat(Localization.Last_backup_date_0, DateHandlers.MacToDateTime(vh.backupDate)) + .AppendLine(); + } + else + sb.AppendLine(Localization.Volume_has_never_been_backed_up); + + if(vh.backupDate > 0) + { + sb.AppendFormat(Localization.Last_check_date_0, DateHandlers.MacToDateTime(vh.checkedDate)) + .AppendLine(); + } + else + sb.AppendLine(Localization.Volume_has_never_been_checked_up); + + sb.AppendFormat(Localization._0_files_in_volume, vh.fileCount).AppendLine(); + sb.AppendFormat(Localization._0_directories_in_volume, vh.folderCount).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_allocation_block, vh.blockSize).AppendLine(); + sb.AppendFormat(Localization._0_allocation_blocks, vh.totalBlocks).AppendLine(); + sb.AppendFormat(Localization._0_free_blocks, vh.freeBlocks).AppendLine(); + sb.AppendFormat(Localization.Next_allocation_block_0, vh.nextAllocation).AppendLine(); + sb.AppendFormat(Localization.Resource_fork_clump_size_0_bytes, vh.rsrcClumpSize).AppendLine(); + sb.AppendFormat(Localization.Data_fork_clump_size_0_bytes, vh.dataClumpSize).AppendLine(); + sb.AppendFormat(Localization.Next_unused_CNID_0, vh.nextCatalogID).AppendLine(); + sb.AppendFormat(Localization.Volume_has_been_mounted_writable_0_times, vh.writeCount).AppendLine(); + sb.AppendFormat(Localization.Allocation_File_is_0_bytes, vh.allocationFile_logicalSize).AppendLine(); + sb.AppendFormat(Localization.Extents_File_is_0_bytes, vh.extentsFile_logicalSize).AppendLine(); + sb.AppendFormat(Localization.Catalog_File_is_0_bytes, vh.catalogFile_logicalSize).AppendLine(); + sb.AppendFormat(Localization.Attributes_File_is_0_bytes, vh.attributesFile_logicalSize).AppendLine(); + sb.AppendFormat(Localization.Startup_File_is_0_bytes, vh.startupFile_logicalSize).AppendLine(); + sb.AppendLine(Localization.Finder_info); + sb.AppendFormat(Localization.CNID_of_bootable_system_directory_0, vh.drFndrInfo0).AppendLine(); + sb.AppendFormat(Localization.CNID_of_first_run_application_directory_0, vh.drFndrInfo1).AppendLine(); + sb.AppendFormat(Localization.CNID_of_previously_opened_directory_0, vh.drFndrInfo2).AppendLine(); + sb.AppendFormat(Localization.CNID_of_bootable_Mac_OS_8_or_9_directory_0, vh.drFndrInfo3).AppendLine(); + sb.AppendFormat(Localization.CNID_of_bootable_Mac_OS_X_directory_0, vh.drFndrInfo5).AppendLine(); + + if(vh.drFndrInfo6 != 0 && vh.drFndrInfo7 != 0) + sb.AppendFormat(Localization.Mac_OS_X_Volume_ID_0_1, vh.drFndrInfo6, vh.drFndrInfo7).AppendLine(); + + metadata = new FileSystem(); + + if(vh.backupDate > 0) metadata.BackupDate = DateHandlers.MacToDateTime(vh.backupDate); + + metadata.Bootable |= vh.drFndrInfo0 != 0 || vh.drFndrInfo3 != 0 || vh.drFndrInfo5 != 0; + metadata.Clusters = vh.totalBlocks; + metadata.ClusterSize = vh.blockSize; + + if(vh.createDate > 0) metadata.CreationDate = DateHandlers.MacToDateTime(vh.createDate); + + metadata.Dirty = (vh.attributes & 0x100) != 0x100; + metadata.Files = vh.fileCount; + metadata.FreeClusters = vh.freeBlocks; + + if(vh.modifyDate > 0) metadata.ModificationDate = DateHandlers.MacToDateTime(vh.modifyDate); + + metadata.Type = vh.signature switch + { + 0x482B => FS_TYPE_HFSP, + 0x4858 => FS_TYPE_HFSX, + _ => metadata.Type + }; + + if(vh.drFndrInfo6 != 0 && vh.drFndrInfo7 != 0) + metadata.VolumeSerial = $"{vh.drFndrInfo6:X8}{vh.drFndrInfo7:X8}"; + + metadata.SystemIdentifier = Encoding.ASCII.GetString(vh.lastMountedVersion); + } + else + { + sb.AppendFormat(Localization.Filesystem_version_is_0, vh.version).AppendLine(); + sb.AppendLine(Localization.This_version_is_not_supported_yet); + } + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/AppleHFSPlus.cs b/Aaru.Filesystems/AppleHFSPlus/Structs.cs similarity index 56% rename from Aaru.Filesystems/AppleHFSPlus.cs rename to Aaru.Filesystems/AppleHFSPlus/Structs.cs index 8786fbc24..90d855e1d 100644 --- a/Aaru.Filesystems/AppleHFSPlus.cs +++ b/Aaru.Filesystems/AppleHFSPlus/Structs.cs @@ -2,15 +2,11 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : AppleHFSPlus.cs +// Filename : Structs.cs // Author(s) : Natalia Portillo // // Component : Apple Hierarchical File System Plus plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Apple Hierarchical File System Plus and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,295 +23,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - -using System; using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; + +namespace Aaru.Filesystems; // Information from Apple TechNote 1150: https://developer.apple.com/legacy/library/technotes/tn/tn1150.html /// /// Implements detection of Apple Hierarchical File System Plus (HFS+) -public sealed class AppleHFSPlus : IFilesystem +public sealed partial class AppleHFSPlus { - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Apple HFS+ filesystem"; - /// - public Guid Id => new("36405F8D-0D26-6EBE-436F-62F0586B4F08"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(2 + partition.Start >= partition.End) - return false; - - ulong hfspOffset; - - uint sectorsToRead = 0x800 / imagePlugin.Info.SectorSize; - - if(0x800 % imagePlugin.Info.SectorSize > 0) - sectorsToRead++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sectorsToRead, out byte[] vhSector); - - if(errno != ErrorNumber.NoError) - return false; - - if(vhSector.Length < 0x800) - return false; - - var drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400); - - if(drSigWord == AppleCommon.HFS_MAGIC) // "BD" - { - drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x47C); // Read embedded HFS+ signature - - if(drSigWord == AppleCommon.HFSP_MAGIC) // "H+" - { - // ReSharper disable once InconsistentNaming - var xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E); - - var drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414); - - var drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C); - - hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.Info.SectorSize); - } - else - hfspOffset = 0; - } - else - hfspOffset = 0; - - errno = imagePlugin.ReadSectors(partition.Start + hfspOffset, sectorsToRead, - out vhSector); // Read volume header - - if(errno != ErrorNumber.NoError) - return false; - - drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400); - - return drSigWord is AppleCommon.HFSP_MAGIC or AppleCommon.HFSX_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = Encoding.BigEndianUnicode; - information = ""; - - var vh = new VolumeHeader(); - - ulong hfspOffset; - bool wrapped; - - uint sectorsToRead = 0x800 / imagePlugin.Info.SectorSize; - - if(0x800 % imagePlugin.Info.SectorSize > 0) - sectorsToRead++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sectorsToRead, out byte[] vhSector); - - if(errno != ErrorNumber.NoError) - return; - - var drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400); - - if(drSigWord == AppleCommon.HFS_MAGIC) // "BD" - { - drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x47C); // Read embedded HFS+ signature - - if(drSigWord == AppleCommon.HFSP_MAGIC) // "H+" - { - // ReSharper disable once InconsistentNaming - var xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E); - - var drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414); - - var drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C); - - hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.Info.SectorSize); - wrapped = true; - } - else - { - hfspOffset = 0; - wrapped = false; - } - } - else - { - hfspOffset = 0; - wrapped = false; - } - - errno = imagePlugin.ReadSectors(partition.Start + hfspOffset, sectorsToRead, - out vhSector); // Read volume header - - if(errno != ErrorNumber.NoError) - return; - - vh.signature = BigEndianBitConverter.ToUInt16(vhSector, 0x400); - - if(vh.signature != AppleCommon.HFSP_MAGIC && - vh.signature != AppleCommon.HFSX_MAGIC) - return; - - var sb = new StringBuilder(); - - if(vh.signature == 0x482B) - sb.AppendLine("HFS+ filesystem."); - - if(vh.signature == 0x4858) - sb.AppendLine("HFSX filesystem."); - - if(wrapped) - sb.AppendLine("Volume is wrapped inside an HFS volume."); - - var tmp = new byte[0x400]; - Array.Copy(vhSector, 0x400, tmp, 0, 0x400); - vhSector = tmp; - - vh = Marshal.ByteArrayToStructureBigEndian(vhSector); - - if(vh.version is 4 or 5) - { - sb.AppendFormat("Filesystem version is {0}.", vh.version).AppendLine(); - - if((vh.attributes & 0x80) == 0x80) - sb.AppendLine("Volume is locked on hardware."); - - if((vh.attributes & 0x100) == 0x100) - sb.AppendLine("Volume is unmounted."); - - if((vh.attributes & 0x200) == 0x200) - sb.AppendLine("There are bad blocks in the extents file."); - - if((vh.attributes & 0x400) == 0x400) - sb.AppendLine("Volume does not require cache."); - - if((vh.attributes & 0x800) == 0x800) - sb.AppendLine("Volume state is inconsistent."); - - if((vh.attributes & 0x1000) == 0x1000) - sb.AppendLine("CNIDs are reused."); - - if((vh.attributes & 0x2000) == 0x2000) - sb.AppendLine("Volume is journaled."); - - if((vh.attributes & 0x8000) == 0x8000) - sb.AppendLine("Volume is locked on software."); - - sb.AppendFormat("Implementation that last mounted the volume: \"{0}\".", - Encoding.ASCII.GetString(vh.lastMountedVersion)).AppendLine(); - - if((vh.attributes & 0x2000) == 0x2000) - sb.AppendFormat("Journal starts at allocation block {0}.", vh.journalInfoBlock).AppendLine(); - - sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(vh.createDate)).AppendLine(); - sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(vh.modifyDate)).AppendLine(); - - if(vh.backupDate > 0) - sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(vh.backupDate)).AppendLine(); - else - sb.AppendLine("Volume has never been backed up"); - - if(vh.backupDate > 0) - sb.AppendFormat("Last check date: {0}", DateHandlers.MacToDateTime(vh.checkedDate)).AppendLine(); - else - sb.AppendLine("Volume has never been checked up"); - - sb.AppendFormat("{0} files on volume.", vh.fileCount).AppendLine(); - sb.AppendFormat("{0} folders on volume.", vh.folderCount).AppendLine(); - sb.AppendFormat("{0} bytes per allocation block.", vh.blockSize).AppendLine(); - sb.AppendFormat("{0} allocation blocks.", vh.totalBlocks).AppendLine(); - sb.AppendFormat("{0} free blocks.", vh.freeBlocks).AppendLine(); - sb.AppendFormat("Next allocation block: {0}.", vh.nextAllocation).AppendLine(); - sb.AppendFormat("Resource fork clump size: {0} bytes.", vh.rsrcClumpSize).AppendLine(); - sb.AppendFormat("Data fork clump size: {0} bytes.", vh.dataClumpSize).AppendLine(); - sb.AppendFormat("Next unused CNID: {0}.", vh.nextCatalogID).AppendLine(); - sb.AppendFormat("Volume has been mounted writable {0} times.", vh.writeCount).AppendLine(); - sb.AppendFormat("Allocation File is {0} bytes.", vh.allocationFile_logicalSize).AppendLine(); - sb.AppendFormat("Extents File is {0} bytes.", vh.extentsFile_logicalSize).AppendLine(); - sb.AppendFormat("Catalog File is {0} bytes.", vh.catalogFile_logicalSize).AppendLine(); - sb.AppendFormat("Attributes File is {0} bytes.", vh.attributesFile_logicalSize).AppendLine(); - sb.AppendFormat("Startup File is {0} bytes.", vh.startupFile_logicalSize).AppendLine(); - sb.AppendLine("Finder info:"); - sb.AppendFormat("CNID of bootable system's directory: {0}", vh.drFndrInfo0).AppendLine(); - sb.AppendFormat("CNID of first-run application's directory: {0}", vh.drFndrInfo1).AppendLine(); - sb.AppendFormat("CNID of previously opened directory: {0}", vh.drFndrInfo2).AppendLine(); - sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", vh.drFndrInfo3).AppendLine(); - sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", vh.drFndrInfo5).AppendLine(); - - if(vh.drFndrInfo6 != 0 && - vh.drFndrInfo7 != 0) - sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", vh.drFndrInfo6, vh.drFndrInfo7).AppendLine(); - - XmlFsType = new FileSystemType(); - - if(vh.backupDate > 0) - { - XmlFsType.BackupDate = DateHandlers.MacToDateTime(vh.backupDate); - XmlFsType.BackupDateSpecified = true; - } - - XmlFsType.Bootable |= vh.drFndrInfo0 != 0 || vh.drFndrInfo3 != 0 || vh.drFndrInfo5 != 0; - XmlFsType.Clusters = vh.totalBlocks; - XmlFsType.ClusterSize = vh.blockSize; - - if(vh.createDate > 0) - { - XmlFsType.CreationDate = DateHandlers.MacToDateTime(vh.createDate); - XmlFsType.CreationDateSpecified = true; - } - - XmlFsType.Dirty = (vh.attributes & 0x100) != 0x100; - XmlFsType.Files = vh.fileCount; - XmlFsType.FilesSpecified = true; - XmlFsType.FreeClusters = vh.freeBlocks; - XmlFsType.FreeClustersSpecified = true; - - if(vh.modifyDate > 0) - { - XmlFsType.ModificationDate = DateHandlers.MacToDateTime(vh.modifyDate); - XmlFsType.ModificationDateSpecified = true; - } - - if(vh.signature == 0x482B) - XmlFsType.Type = "HFS+"; - - if(vh.signature == 0x4858) - XmlFsType.Type = "HFSX"; - - if(vh.drFndrInfo6 != 0 && - vh.drFndrInfo7 != 0) - XmlFsType.VolumeSerial = $"{vh.drFndrInfo6:X8}{vh.drFndrInfo7:X8}"; - - XmlFsType.SystemIdentifier = Encoding.ASCII.GetString(vh.lastMountedVersion); - } - else - { - sb.AppendFormat("Filesystem version is {0}.", vh.version).AppendLine(); - sb.AppendLine("This version is not supported yet."); - } - - information = sb.ToString(); - } +#region Nested type: VolumeHeader /// HFS+ Volume Header, should be at offset 0x0400 bytes in volume with a size of 532 bytes [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -582,4 +302,6 @@ public sealed class AppleHFSPlus : IFilesystem /// 0x200 public readonly uint startupFile_extents_blockCount7; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleMFS/AppleMFS.cs b/Aaru.Filesystems/AppleMFS/AppleMFS.cs index 54cd97408..efa2e052f 100644 --- a/Aaru.Filesystems/AppleMFS/AppleMFS.cs +++ b/Aaru.Filesystems/AppleMFS/AppleMFS.cs @@ -7,10 +7,6 @@ // // Component : Apple Macintosh File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Constructors and common variables for the Apple Macintosh File System plugin. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,51 +23,56 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Text; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Interfaces; -using Schemas; + +namespace Aaru.Filesystems; // Information from Inside Macintosh Volume II /// /// Implements the Apple Macintosh File System public sealed partial class AppleMFS : IReadOnlyFilesystem { - bool _mounted; + const string MODULE_NAME = "Apple MFS plugin"; + byte[] _bitmapTags; + uint[] _blockMap; + byte[] _blockMapBytes; + byte[] _bootBlocks; + byte[] _bootTags; bool _debug; IMediaImage _device; - ulong _partitionStart; - Dictionary _idToFilename; - Dictionary _idToEntry; - Dictionary _filenameToId; - MasterDirectoryBlock _volMdb; - byte[] _bootBlocks; - byte[] _mdbBlocks; byte[] _directoryBlocks; - byte[] _blockMapBytes; - uint[] _blockMap; - int _sectorsPerBlock; - byte[] _bootTags; - byte[] _mdbTags; byte[] _directoryTags; - byte[] _bitmapTags; + Encoding _encoding; + Dictionary _filenameToId; + Dictionary _idToEntry; + Dictionary _idToFilename; + byte[] _mdbBlocks; + byte[] _mdbTags; + bool _mounted; + ulong _partitionStart; + int _sectorsPerBlock; + MasterDirectoryBlock _volMdb; + +#region IReadOnlyFilesystem Members /// - public FileSystemType XmlFsType { get; private set; } + public string Name => Localization.AppleMFS_Name; + /// - public string Name => "Apple Macintosh File System"; + public FileSystem Metadata { get; private set; } + /// public Guid Id => new("36405F8D-0D26-4066-6538-5DBF5D065C3A"); + /// - public Encoding Encoding { get; private set; } - /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; // TODO: Implement Finder namespace (requires decoding Desktop database) /// @@ -81,6 +82,8 @@ public sealed partial class AppleMFS : IReadOnlyFilesystem /// public Dictionary Namespaces => null; +#endregion + static Dictionary GetDefaultOptions() => new() { { diff --git a/Aaru.Filesystems/AppleMFS/Consts.cs b/Aaru.Filesystems/AppleMFS/Consts.cs index cd9951cc9..665dd1362 100644 --- a/Aaru.Filesystems/AppleMFS/Consts.cs +++ b/Aaru.Filesystems/AppleMFS/Consts.cs @@ -7,10 +7,6 @@ // // Component : Apple Macintosh File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple Macintosh File System constants. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,13 +23,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; +namespace Aaru.Filesystems; + // Information from Inside Macintosh Volume II [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed partial class AppleMFS @@ -48,4 +44,7 @@ public sealed partial class AppleMFS const int BMAP_FREE = 0; const int BMAP_LAST = 1; const int BMAP_DIR = 0xFFF; + + // Do not translate + const string FS_TYPE = "mfs"; } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleMFS/Dir.cs b/Aaru.Filesystems/AppleMFS/Dir.cs index 4c529ea9f..f7403a7e7 100644 --- a/Aaru.Filesystems/AppleMFS/Dir.cs +++ b/Aaru.Filesystems/AppleMFS/Dir.cs @@ -7,10 +7,6 @@ // // Component : Apple Macintosh File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle the Apple Macintosh File System directory. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,34 +23,35 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Helpers; +namespace Aaru.Filesystems; + // Information from Inside Macintosh Volume II public sealed partial class AppleMFS { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber ReadDir(string path, out List contents) + public ErrorNumber OpenDir(string path, out IDirNode node) { - contents = null; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - if(!string.IsNullOrEmpty(path) && - string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) + if(!string.IsNullOrEmpty(path) && string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) return ErrorNumber.NotSupported; - contents = _idToFilename.Select(kvp => kvp.Value).ToList(); + var contents = _idToFilename.Select(kvp => kvp.Value).ToList(); if(_debug) { @@ -62,15 +59,52 @@ public sealed partial class AppleMFS contents.Add("$Bitmap"); contents.Add("$MDB"); - if(_bootBlocks != null) - contents.Add("$Boot"); + if(_bootBlocks != null) contents.Add("$Boot"); } contents.Sort(); + node = new AppleMfsDirNode + { + Path = path, + _position = 0, + _contents = contents.ToArray() + }; + return ErrorNumber.NoError; } + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) + { + filename = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not AppleMfsDirNode mynode) return ErrorNumber.InvalidArgument; + + if(mynode._position < 0) return ErrorNumber.InvalidArgument; + + if(mynode._position >= mynode._contents.Length) return ErrorNumber.NoError; + + filename = mynode._contents[mynode._position++]; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not AppleMfsDirNode mynode) return ErrorNumber.InvalidArgument; + + mynode._position = -1; + mynode._contents = null; + + return ErrorNumber.NoError; + } + +#endregion + bool FillDirectory() { _idToFilename = new Dictionary(); @@ -86,8 +120,7 @@ public sealed partial class AppleMFS flFlags = (FileFlags)_directoryBlocks[offset + 0] }; - if(!entry.flFlags.HasFlag(FileFlags.Used)) - break; + if(!entry.flFlags.HasFlag(FileFlags.Used)) break; entry.flTyp = _directoryBlocks[offset + 1]; @@ -105,8 +138,9 @@ public sealed partial class AppleMFS entry.flNam = new byte[_directoryBlocks[offset + 50] + 1]; Array.Copy(_directoryBlocks, offset + 50, entry.flNam, 0, entry.flNam.Length); - string lowerFilename = StringHandlers.PascalToString(entry.flNam, Encoding).ToLowerInvariant(). - Replace('/', ':'); + string lowerFilename = StringHandlers.PascalToString(entry.flNam, _encoding) + .ToLowerInvariant() + .Replace('/', ':'); if(entry.flFlags.HasFlag(FileFlags.Used) && !_idToFilename.ContainsKey(entry.flFlNum) && @@ -117,35 +151,37 @@ public sealed partial class AppleMFS _idToEntry.Add(entry.flFlNum, entry); _idToFilename.Add(entry.flFlNum, - StringHandlers.PascalToString(entry.flNam, Encoding).Replace('/', ':')); + StringHandlers.PascalToString(entry.flNam, _encoding).Replace('/', ':')); _filenameToId.Add(lowerFilename, entry.flFlNum); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flFlags = {0}", entry.flFlags); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flTyp = {0}", entry.flTyp); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flFlNum = {0}", entry.flFlNum); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flStBlk = {0}", entry.flStBlk); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flLgLen = {0}", entry.flLgLen); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flPyLen = {0}", entry.flPyLen); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flRStBlk = {0}", entry.flRStBlk); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flRLgLen = {0}", entry.flRLgLen); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flRPyLen = {0}", entry.flRPyLen); + AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flFlags = {0}", entry.flFlags); + AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flTyp = {0}", entry.flTyp); + AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flFlNum = {0}", entry.flFlNum); + AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flStBlk = {0}", entry.flStBlk); + AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flLgLen = {0}", entry.flLgLen); + AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flPyLen = {0}", entry.flPyLen); + AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flRStBlk = {0}", entry.flRStBlk); + AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flRLgLen = {0}", entry.flRLgLen); + AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flRPyLen = {0}", entry.flRPyLen); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flCrDat = {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + "entry.flCrDat = {0}", DateHandlers.MacToDateTime(entry.flCrDat)); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flMdDat = {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + "entry.flMdDat = {0}", DateHandlers.MacToDateTime(entry.flMdDat)); - AaruConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flNam0 = {0}", - StringHandlers.PascalToString(entry.flNam, Encoding)); + AaruConsole.DebugWriteLine(MODULE_NAME, + "entry.flNam0 = {0}", + StringHandlers.PascalToString(entry.flNam, _encoding)); } offset += 50 + entry.flNam.Length; // "Entries are always an integral number of words" - if(offset % 2 != 0) - offset++; + if(offset % 2 != 0) offset++; // TODO: "Entries don't cross logical block boundaries" } diff --git a/Aaru.Filesystems/AppleMFS/File.cs b/Aaru.Filesystems/AppleMFS/File.cs index 14fd98332..ea72dac05 100644 --- a/Aaru.Filesystems/AppleMFS/File.cs +++ b/Aaru.Filesystems/AppleMFS/File.cs @@ -7,10 +7,6 @@ // // Component : Apple Macintosh File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle files. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,101 +23,49 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.IO; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Helpers; using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes; +namespace Aaru.Filesystems; + // Information from Inside Macintosh Volume II public sealed partial class AppleMFS { - /// - public ErrorNumber MapBlock(string path, long fileBlock, out long deviceBlock) - { - deviceBlock = new long(); - - if(!_mounted) - return ErrorNumber.AccessDenied; - - string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); - - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; - - path = pathElements[0]; - - if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) - return ErrorNumber.NoSuchFile; - - if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) - return ErrorNumber.NoSuchFile; - - if(fileBlock > entry.flPyLen / _volMdb.drAlBlkSiz) - return ErrorNumber.InvalidArgument; - - uint nextBlock = entry.flStBlk; - long relBlock = 0; - - while(true) - { - if(relBlock == fileBlock) - { - deviceBlock = (nextBlock - 2) * _sectorsPerBlock + _volMdb.drAlBlSt + (long)_partitionStart; - - return ErrorNumber.NoError; - } - - if(_blockMap[nextBlock] == BMAP_FREE || - _blockMap[nextBlock] == BMAP_LAST) - break; - - nextBlock = _blockMap[nextBlock]; - relBlock++; - } - - return ErrorNumber.InOutError; - } +#region IReadOnlyFilesystem Members /// public ErrorNumber GetAttributes(string path, out FileAttributes attributes) { attributes = new FileAttributes(); - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; path = pathElements[0]; - if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) - return ErrorNumber.NoSuchFile; + if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) return ErrorNumber.NoSuchFile; - if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) - return ErrorNumber.NoSuchFile; + if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) return ErrorNumber.NoSuchFile; - if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsAlias)) - attributes |= FileAttributes.Alias; + if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsAlias)) attributes |= FileAttributes.Alias; - if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasBundle)) - attributes |= FileAttributes.Bundle; + if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasBundle)) attributes |= FileAttributes.Bundle; if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasBeenInited)) attributes |= FileAttributes.HasBeenInited; @@ -129,20 +73,15 @@ public sealed partial class AppleMFS if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasCustomIcon)) attributes |= FileAttributes.HasCustomIcon; - if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasNoINITs)) - attributes |= FileAttributes.HasNoINITs; + if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasNoINITs)) attributes |= FileAttributes.HasNoINITs; - if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsInvisible)) - attributes |= FileAttributes.Hidden; + if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsInvisible)) attributes |= FileAttributes.Hidden; - if(entry.flFlags.HasFlag(FileFlags.Locked)) - attributes |= FileAttributes.Immutable; + if(entry.flFlags.HasFlag(FileFlags.Locked)) attributes |= FileAttributes.Immutable; - if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsOnDesk)) - attributes |= FileAttributes.IsOnDesk; + if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsOnDesk)) attributes |= FileAttributes.IsOnDesk; - if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsShared)) - attributes |= FileAttributes.Shared; + if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsShared)) attributes |= FileAttributes.Shared; if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsStationery)) attributes |= FileAttributes.Stationery; @@ -158,46 +97,82 @@ public sealed partial class AppleMFS } /// - public ErrorNumber Read(string path, long offset, long size, ref byte[] buf) + public ErrorNumber OpenFile(string path, out IFileNode node) { - if(!_mounted) - return ErrorNumber.AccessDenied; + node = null; + + if(!_mounted) return ErrorNumber.AccessDenied; byte[] file; ErrorNumber error = ErrorNumber.NoError; - if(_debug && string.Compare(path, "$", StringComparison.InvariantCulture) == 0) - file = _directoryBlocks; - else if(_debug && - string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 && - _bootBlocks != null) - file = _bootBlocks; - else if(_debug && string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0) - file = _blockMapBytes; - else if(_debug && string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0) - file = _mdbBlocks; - else - error = ReadFile(path, out file, false, false); - - if(error != ErrorNumber.NoError) - return error; - - if(size == 0) + switch(_debug) { - buf = Array.Empty(); + case true when string.Compare(path, "$", StringComparison.InvariantCulture) == 0: + file = _directoryBlocks; - return ErrorNumber.NoError; + break; + case true when string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 && _bootBlocks != null: + file = _bootBlocks; + + break; + case true when string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0: + file = _blockMapBytes; + + break; + case true when string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0: + file = _mdbBlocks; + + break; + default: + error = ReadFile(path, out file, false, false); + + break; } - if(offset >= file.Length) - return ErrorNumber.InvalidArgument; + if(error != ErrorNumber.NoError) return error; - if(size + offset >= file.Length) - size = file.Length - offset; + node = new AppleMfsFileNode + { + Path = path, + Length = file.Length, + Offset = 0, + _cache = file + }; - buf = new byte[size]; + return ErrorNumber.NoError; + } - Array.Copy(file, offset, buf, 0, size); + /// + public ErrorNumber CloseFile(IFileNode node) + { + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not AppleMfsFileNode mynode) return ErrorNumber.InvalidArgument; + + mynode._cache = null; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(buffer is null || buffer.Length < length) return ErrorNumber.InvalidArgument; + + if(node is not AppleMfsFileNode mynode) return ErrorNumber.InvalidArgument; + + read = length; + + if(length + mynode.Offset >= mynode.Length) read = mynode.Length - mynode.Offset; + + Array.Copy(mynode._cache, mynode.Offset, buffer, 0, read); + + mynode.Offset += read; return ErrorNumber.NoError; } @@ -207,24 +182,24 @@ public sealed partial class AppleMFS { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; path = pathElements[0]; if(_debug) - if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || + { + if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0) + string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0) { stat = new FileEntryInfo { @@ -246,8 +221,7 @@ public sealed partial class AppleMFS stat.Length = _blockMapBytes.Length; } - else if(string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 && - _bootBlocks != null) + else if(string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 && _bootBlocks != null) { stat.Blocks = _bootBlocks.Length / stat.BlockSize + _bootBlocks.Length % stat.BlockSize; stat.Length = _bootBlocks.Length; @@ -262,27 +236,25 @@ public sealed partial class AppleMFS return ErrorNumber.NoError; } + } - if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) - return ErrorNumber.NoSuchFile; + if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) return ErrorNumber.NoSuchFile; - if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) - return ErrorNumber.NoSuchFile; + if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) return ErrorNumber.NoSuchFile; ErrorNumber error = GetAttributes(path, out FileAttributes attr); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; stat = new FileEntryInfo { Attributes = attr, - Blocks = entry.flLgLen / _volMdb.drAlBlkSiz, + Blocks = entry.flPyLen / _volMdb.drAlBlkSiz, BlockSize = _volMdb.drAlBlkSiz, CreationTime = DateHandlers.MacToDateTime(entry.flCrDat), Inode = entry.flFlNum, LastWriteTime = DateHandlers.MacToDateTime(entry.flMdDat), - Length = entry.flPyLen, + Length = entry.flLgLen, Links = 1 }; @@ -297,28 +269,27 @@ public sealed partial class AppleMFS return ErrorNumber.NotImplemented; } +#endregion + ErrorNumber ReadFile(string path, out byte[] buf, bool resourceFork, bool tags) { buf = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; path = pathElements[0]; - if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) - return ErrorNumber.NoSuchFile; + if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) return ErrorNumber.NoSuchFile; - if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) - return ErrorNumber.NoSuchFile; + if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) return ErrorNumber.NoSuchFile; uint nextBlock; @@ -326,7 +297,7 @@ public sealed partial class AppleMFS { if(entry.flRPyLen == 0) { - buf = Array.Empty(); + buf = []; return ErrorNumber.NoError; } @@ -337,7 +308,7 @@ public sealed partial class AppleMFS { if(entry.flPyLen == 0) { - buf = Array.Empty(); + buf = []; return ErrorNumber.NoError; } @@ -349,26 +320,26 @@ public sealed partial class AppleMFS do { - byte[] sectors; - ErrorNumber errno; + ErrorNumber errno = tags + ? _device.ReadSectorsTag((ulong)((nextBlock - 2) * _sectorsPerBlock) + + _volMdb.drAlBlSt + + _partitionStart, + (uint)_sectorsPerBlock, + SectorTagType.AppleSectorTag, + out byte[] sectors) + : _device.ReadSectors((ulong)((nextBlock - 2) * _sectorsPerBlock) + + _volMdb.drAlBlSt + + _partitionStart, + (uint)_sectorsPerBlock, + out sectors); - errno = - tags - ? _device. - ReadSectorsTag((ulong)((nextBlock - 2) * _sectorsPerBlock) + _volMdb.drAlBlSt + _partitionStart, - (uint)_sectorsPerBlock, SectorTagType.AppleSectorTag, out sectors) - : _device. - ReadSectors((ulong)((nextBlock - 2) * _sectorsPerBlock) + _volMdb.drAlBlSt + _partitionStart, - (uint)_sectorsPerBlock, out sectors); - - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; ms.Write(sectors, 0, sectors.Length); if(_blockMap[nextBlock] == BMAP_FREE) { - AaruConsole.ErrorWriteLine("File truncated at block {0}", nextBlock); + AaruConsole.ErrorWriteLine(Localization.File_truncated_at_block_0, nextBlock); break; } @@ -381,6 +352,7 @@ public sealed partial class AppleMFS else { if(resourceFork) + { if(ms.Length < entry.flRLgLen) buf = ms.ToArray(); else @@ -388,6 +360,7 @@ public sealed partial class AppleMFS buf = new byte[entry.flRLgLen]; Array.Copy(ms.ToArray(), 0, buf, 0, buf.Length); } + } else { if(ms.Length < entry.flLgLen) diff --git a/Aaru.Filesystems/AppleMFS/Info.cs b/Aaru.Filesystems/AppleMFS/Info.cs index c155a4c53..3d59c75b1 100644 --- a/Aaru.Filesystems/AppleMFS/Info.cs +++ b/Aaru.Filesystems/AppleMFS/Info.cs @@ -7,10 +7,6 @@ // // Component : Apple Macintosh File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Apple Macintosh File System and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,34 +23,34 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; using Claunia.Encoding; -using Schemas; using Encoding = System.Text.Encoding; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; // Information from Inside Macintosh Volume II public sealed partial class AppleMFS { +#region IReadOnlyFilesystem Members + /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(2 + partition.Start >= partition.End) - return false; + if(2 + partition.Start >= partition.End) return false; ErrorNumber errno = imagePlugin.ReadSector(2 + partition.Start, out byte[] mdbSector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; var drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0x000); @@ -62,10 +58,12 @@ public sealed partial class AppleMFS } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = encoding ?? new MacRoman(); - information = ""; + encoding ??= new MacRoman(); + information = ""; + metadata = new FileSystem(); var sb = new StringBuilder(); @@ -73,18 +71,15 @@ public sealed partial class AppleMFS ErrorNumber errno = imagePlugin.ReadSector(2 + partition.Start, out byte[] mdbSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bbSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; mdb.drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0x000); - if(mdb.drSigWord != MFS_MAGIC) - return; + if(mdb.drSigWord != MFS_MAGIC) return; mdb.drCrDate = BigEndianBitConverter.ToUInt32(mdbSector, 0x002); mdb.drLsBkUp = BigEndianBitConverter.ToUInt32(mdbSector, 0x006); @@ -101,85 +96,78 @@ public sealed partial class AppleMFS mdb.drVNSiz = mdbSector[0x024]; var variableSize = new byte[mdb.drVNSiz + 1]; Array.Copy(mdbSector, 0x024, variableSize, 0, mdb.drVNSiz + 1); - mdb.drVN = StringHandlers.PascalToString(variableSize, Encoding); + mdb.drVN = StringHandlers.PascalToString(variableSize, encoding); - sb.AppendLine("Apple Macintosh File System"); + sb.AppendLine(Localization.AppleMFS_Name); sb.AppendLine(); - sb.AppendLine("Master Directory Block:"); - sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine(); - sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(mdb.drLsBkUp)).AppendLine(); + sb.AppendLine(Localization.Master_Directory_Block); + sb.AppendFormat(Localization.Creation_date_0, DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine(); + sb.AppendFormat(Localization.Last_backup_date_0, DateHandlers.MacToDateTime(mdb.drLsBkUp)).AppendLine(); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.HardwareLock)) - sb.AppendLine("Volume is locked by hardware."); + sb.AppendLine(Localization.Volume_is_locked_by_hardware); - sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted) ? "Volume was unmonted." - : "Volume is mounted."); + sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted) + ? Localization.Volume_was_unmonted + : Localization.Volume_is_mounted); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SparedBadBlocks)) - sb.AppendLine("Volume has spared bad blocks."); + sb.AppendLine(Localization.Volume_has_spared_bad_blocks); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.DoesNotNeedCache)) - sb.AppendLine("Volume does not need cache."); + sb.AppendLine(Localization.Volume_does_not_need_cache); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.BootInconsistent)) - sb.AppendLine("Boot volume is inconsistent."); + sb.AppendLine(Localization.Boot_volume_is_inconsistent); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.ReusedIds)) - sb.AppendLine("There are reused CNIDs."); + sb.AppendLine(Localization.There_are_reused_CNIDs); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Inconsistent)) - sb.AppendLine("Volume is seriously inconsistent."); + sb.AppendLine(Localization.Volume_is_seriously_inconsistent); if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SoftwareLock)) - sb.AppendLine("Volume is locked by software."); + sb.AppendLine(Localization.Volume_is_locked_by_software); - sb.AppendFormat("{0} files on volume", mdb.drNmFls).AppendLine(); - sb.AppendFormat("First directory sector: {0}", mdb.drDirSt).AppendLine(); - sb.AppendFormat("{0} sectors in directory.", mdb.drBlLen).AppendLine(); - sb.AppendFormat("{0} volume allocation blocks.", mdb.drNmAlBlks + 1).AppendLine(); - sb.AppendFormat("Size of allocation blocks: {0} bytes", mdb.drAlBlkSiz).AppendLine(); - sb.AppendFormat("{0} bytes to allocate.", mdb.drClpSiz).AppendLine(); - sb.AppendFormat("First allocation block (#2) starts in sector {0}.", mdb.drAlBlSt).AppendLine(); - sb.AppendFormat("Next unused file number: {0}", mdb.drNxtFNum).AppendLine(); - sb.AppendFormat("{0} unused allocation blocks.", mdb.drFreeBks).AppendLine(); - sb.AppendFormat("Volume name: {0}", mdb.drVN).AppendLine(); + sb.AppendFormat(Localization._0_files_in_volume, mdb.drNmFls).AppendLine(); + sb.AppendFormat(Localization.First_directory_sector_0, mdb.drDirSt).AppendLine(); + sb.AppendFormat(Localization._0_sectors_in_directory, mdb.drBlLen).AppendLine(); + sb.AppendFormat(Localization._0_volume_allocation_blocks, mdb.drNmAlBlks + 1).AppendLine(); + sb.AppendFormat(Localization.Size_of_allocation_blocks_0_bytes, mdb.drAlBlkSiz).AppendLine(); + sb.AppendFormat(Localization._0_bytes_to_allocate, mdb.drClpSiz).AppendLine(); + sb.AppendFormat(Localization.First_allocation_block_number_two_starts_in_sector_0, mdb.drAlBlSt).AppendLine(); + sb.AppendFormat(Localization.Next_unused_file_number_0, mdb.drNxtFNum).AppendLine(); + sb.AppendFormat(Localization._0_unused_allocation_blocks, mdb.drFreeBks).AppendLine(); + sb.AppendFormat(Localization.Volume_name_0, mdb.drVN).AppendLine(); - string bootBlockInfo = AppleCommon.GetBootBlockInformation(bbSector, Encoding); + string bootBlockInfo = AppleCommon.GetBootBlockInformation(bbSector, encoding); if(bootBlockInfo != null) { - sb.AppendLine("Volume is bootable."); + sb.AppendLine(Localization.Volume_is_bootable); sb.AppendLine(); sb.AppendLine(bootBlockInfo); } else - sb.AppendLine("Volume is not bootable."); + sb.AppendLine(Localization.Volume_is_not_bootable); information = sb.ToString(); - XmlFsType = new FileSystemType(); + metadata = new FileSystem(); - if(mdb.drLsBkUp > 0) - { - XmlFsType.BackupDate = DateHandlers.MacToDateTime(mdb.drLsBkUp); - XmlFsType.BackupDateSpecified = true; - } + if(mdb.drLsBkUp > 0) metadata.BackupDate = DateHandlers.MacToDateTime(mdb.drLsBkUp); - XmlFsType.Bootable = bootBlockInfo != null; - XmlFsType.Clusters = mdb.drNmAlBlks; - XmlFsType.ClusterSize = mdb.drAlBlkSiz; + metadata.Bootable = bootBlockInfo != null; + metadata.Clusters = mdb.drNmAlBlks; + metadata.ClusterSize = mdb.drAlBlkSiz; - if(mdb.drCrDate > 0) - { - XmlFsType.CreationDate = DateHandlers.MacToDateTime(mdb.drCrDate); - XmlFsType.CreationDateSpecified = true; - } + if(mdb.drCrDate > 0) metadata.CreationDate = DateHandlers.MacToDateTime(mdb.drCrDate); - XmlFsType.Files = mdb.drNmFls; - XmlFsType.FilesSpecified = true; - XmlFsType.FreeClusters = mdb.drFreeBks; - XmlFsType.FreeClustersSpecified = true; - XmlFsType.Type = "MFS"; - XmlFsType.VolumeName = mdb.drVN; + metadata.Files = mdb.drNmFls; + metadata.FreeClusters = mdb.drFreeBks; + metadata.Type = FS_TYPE; + metadata.VolumeName = mdb.drVN; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleMFS/Structs.cs b/Aaru.Filesystems/AppleMFS/Structs.cs index 6f05b7efd..0484fac7e 100644 --- a/Aaru.Filesystems/AppleMFS/Structs.cs +++ b/Aaru.Filesystems/AppleMFS/Structs.cs @@ -7,10 +7,6 @@ // // Component : Apple Macintosh File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple Macintosh File System structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,20 +23,108 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + #pragma warning disable 169 namespace Aaru.Filesystems; -using System; -using System.Diagnostics.CodeAnalysis; - // Information from Inside Macintosh Volume II -[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "NotAccessedField.Local")] +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "NotAccessedField.Local")] public sealed partial class AppleMFS { +#region Nested type: AppleMfsDirNode + + sealed class AppleMfsDirNode : IDirNode + { + internal string[] _contents; + internal int _position; + +#region IDirNode Members + + /// + public string Path { get; init; } + +#endregion + } + +#endregion + +#region Nested type: AppleMfsFileNode + + sealed class AppleMfsFileNode : IFileNode + { + internal byte[] _cache; + +#region IFileNode Members + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + +#endregion + } + +#endregion + +#region Nested type: FileEntry + + struct FileEntry + { + /// 0x00, Entry flags + public FileFlags flFlags; + /// 0x01, Version number + public byte flTyp; + /// 0x02, FinderInfo + public AppleCommon.FInfo flUsrWds; + /// 0x12, file ID + public uint flFlNum; + /// 0x16, first allocation block of data fork + public ushort flStBlk; + /// 0x18, logical end-of-file of data fork + public uint flLgLen; + /// 0x1C, physical end-of-file of data fork + public uint flPyLen; + /// 0x20, first allocation block of resource fork + public ushort flRStBlk; + /// 0x22, logical end-of-file of resource fork + public uint flRLgLen; + /// 0x26, physical end-of-file of resource fork + public uint flRPyLen; + /// 0x2A, date and time of creation + public uint flCrDat; + /// 0x2E, date and time of last modification + public uint flMdDat; + /// 0x32, file name prefixed with length + public byte[] flNam; + } + +#endregion + +#region Nested type: FileFlags + + [Flags] + enum FileFlags : byte + { + Locked = 0x01, + Used = 0x80 + } + +#endregion + +#region Nested type: MasterDirectoryBlock + /// Master Directory Block, should be at offset 0x0400 bytes in volume struct MasterDirectoryBlock { @@ -76,40 +160,5 @@ public sealed partial class AppleMFS public string drVN; } - [Flags] - enum FileFlags : byte - { - Locked = 0x01, - Used = 0x80 - } - - struct FileEntry - { - /// 0x00, Entry flags - public FileFlags flFlags; - /// 0x01, Version number - public byte flTyp; - /// 0x02, FinderInfo - public AppleCommon.FInfo flUsrWds; - /// 0x12, file ID - public uint flFlNum; - /// 0x16, first allocation block of data fork - public ushort flStBlk; - /// 0x18, logical end-of-file of data fork - public uint flLgLen; - /// 0x1C, physical end-of-file of data fork - public uint flPyLen; - /// 0x20, first allocation block of resource fork - public ushort flRStBlk; - /// 0x22, logical end-of-file of resource fork - public uint flRLgLen; - /// 0x26, physical end-of-file of resource fork - public uint flRPyLen; - /// 0x2A, date and time of creation - public uint flCrDat; - /// 0x2E, date and time of last modification - public uint flMdDat; - /// 0x32, file name prefixed with length - public byte[] flNam; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleMFS/Super.cs b/Aaru.Filesystems/AppleMFS/Super.cs index 22536da66..b44ebe6c3 100644 --- a/Aaru.Filesystems/AppleMFS/Super.cs +++ b/Aaru.Filesystems/AppleMFS/Super.cs @@ -7,10 +7,6 @@ // // Component : Apple Macintosh File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Handles mounting and umounting the Apple Macintosh File System. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,56 +23,53 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Helpers; -using Schemas; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; // Information from Inside Macintosh Volume II public sealed partial class AppleMFS { const int BYTES_BEFORE_BLOCK_MAP = 64; +#region IReadOnlyFilesystem Members + /// - public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, - Dictionary options, string @namespace) + public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace) { _device = imagePlugin; _partitionStart = partition.Start; - Encoding = encoding ?? Encoding.GetEncoding("macintosh"); - ErrorNumber errno; + _encoding = encoding ?? Encoding.GetEncoding("macintosh"); options ??= GetDefaultOptions(); - if(options.TryGetValue("debug", out string debugString)) - bool.TryParse(debugString, out _debug); + if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out _debug); _volMdb = new MasterDirectoryBlock(); - errno = _device.ReadSector(2 + _partitionStart, out _mdbBlocks); + ErrorNumber errno = _device.ReadSector(2 + _partitionStart, out _mdbBlocks); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; errno = _device.ReadSector(0 + _partitionStart, out _bootBlocks); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; _volMdb.drSigWord = BigEndianBitConverter.ToUInt16(_mdbBlocks, 0x000); - if(_volMdb.drSigWord != MFS_MAGIC) - return ErrorNumber.InvalidArgument; + if(_volMdb.drSigWord != MFS_MAGIC) return ErrorNumber.InvalidArgument; _volMdb.drCrDate = BigEndianBitConverter.ToUInt32(_mdbBlocks, 0x002); _volMdb.drLsBkUp = BigEndianBitConverter.ToUInt32(_mdbBlocks, 0x006); @@ -93,12 +86,11 @@ public sealed partial class AppleMFS _volMdb.drVNSiz = _mdbBlocks[0x024]; var variableSize = new byte[_volMdb.drVNSiz + 1]; Array.Copy(_mdbBlocks, 0x024, variableSize, 0, _volMdb.drVNSiz + 1); - _volMdb.drVN = StringHandlers.PascalToString(variableSize, Encoding); + _volMdb.drVN = StringHandlers.PascalToString(variableSize, _encoding); errno = _device.ReadSectors(_volMdb.drDirSt + _partitionStart, _volMdb.drBlLen, out _directoryBlocks); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; int bytesInBlockMap = _volMdb.drNmAlBlks * 12 / 8 + _volMdb.drNmAlBlks * 12 % 8; int bytesInWholeMdb = bytesInBlockMap + BYTES_BEFORE_BLOCK_MAP; @@ -108,8 +100,7 @@ public sealed partial class AppleMFS errno = _device.ReadSectors(_partitionStart + 2, (uint)sectorsInWholeMdb, out byte[] wholeMdb); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; _blockMapBytes = new byte[bytesInBlockMap]; Array.Copy(wholeMdb, BYTES_BEFORE_BLOCK_MAP, _blockMapBytes, 0, _blockMapBytes.Length); @@ -123,8 +114,7 @@ public sealed partial class AppleMFS uint tmp2 = 0; uint tmp3 = 0; - if(offset + 4 <= _blockMapBytes.Length) - tmp1 = BigEndianBitConverter.ToUInt32(_blockMapBytes, offset); + if(offset + 4 <= _blockMapBytes.Length) tmp1 = BigEndianBitConverter.ToUInt32(_blockMapBytes, offset); if(offset + 4 + 4 <= _blockMapBytes.Length) tmp2 = BigEndianBitConverter.ToUInt32(_blockMapBytes, offset + 4); @@ -132,29 +122,21 @@ public sealed partial class AppleMFS if(offset + 8 + 4 <= _blockMapBytes.Length) tmp3 = BigEndianBitConverter.ToUInt32(_blockMapBytes, offset + 8); - if(i < _blockMap.Length) - _blockMap[i] = (tmp1 & 0xFFF00000) >> 20; + if(i < _blockMap.Length) _blockMap[i] = (tmp1 & 0xFFF00000) >> 20; - if(i + 2 < _blockMap.Length) - _blockMap[i + 1] = (tmp1 & 0xFFF00) >> 8; + if(i + 2 < _blockMap.Length) _blockMap[i + 1] = (tmp1 & 0xFFF00) >> 8; - if(i + 3 < _blockMap.Length) - _blockMap[i + 2] = ((tmp1 & 0xFF) << 4) + ((tmp2 & 0xF0000000) >> 28); + if(i + 3 < _blockMap.Length) _blockMap[i + 2] = ((tmp1 & 0xFF) << 4) + ((tmp2 & 0xF0000000) >> 28); - if(i + 4 < _blockMap.Length) - _blockMap[i + 3] = (tmp2 & 0xFFF0000) >> 16; + if(i + 4 < _blockMap.Length) _blockMap[i + 3] = (tmp2 & 0xFFF0000) >> 16; - if(i + 5 < _blockMap.Length) - _blockMap[i + 4] = (tmp2 & 0xFFF0) >> 4; + if(i + 5 < _blockMap.Length) _blockMap[i + 4] = (tmp2 & 0xFFF0) >> 4; - if(i + 6 < _blockMap.Length) - _blockMap[i + 5] = ((tmp2 & 0xF) << 8) + ((tmp3 & 0xFF000000) >> 24); + if(i + 6 < _blockMap.Length) _blockMap[i + 5] = ((tmp2 & 0xF) << 8) + ((tmp3 & 0xFF000000) >> 24); - if(i + 7 < _blockMap.Length) - _blockMap[i + 6] = (tmp3 & 0xFFF000) >> 12; + if(i + 7 < _blockMap.Length) _blockMap[i + 6] = (tmp3 & 0xFFF000) >> 12; - if(i + 8 < _blockMap.Length) - _blockMap[i + 7] = tmp3 & 0xFFF; + if(i + 8 < _blockMap.Length) _blockMap[i + 7] = tmp3 & 0xFFF; offset += 12; } @@ -164,49 +146,41 @@ public sealed partial class AppleMFS _device.ReadSectorTag(2 + _partitionStart, SectorTagType.AppleSectorTag, out _mdbTags); _device.ReadSectorTag(0 + _partitionStart, SectorTagType.AppleSectorTag, out _bootTags); - _device.ReadSectorsTag(_volMdb.drDirSt + _partitionStart, _volMdb.drBlLen, SectorTagType.AppleSectorTag, + _device.ReadSectorsTag(_volMdb.drDirSt + _partitionStart, + _volMdb.drBlLen, + SectorTagType.AppleSectorTag, out _directoryTags); - _device.ReadSectorsTag(_partitionStart + 2, (uint)sectorsInWholeMdb, SectorTagType.AppleSectorTag, + _device.ReadSectorsTag(_partitionStart + 2, + (uint)sectorsInWholeMdb, + SectorTagType.AppleSectorTag, out _bitmapTags); } _sectorsPerBlock = (int)(_volMdb.drAlBlkSiz / _device.Info.SectorSize); - if(!FillDirectory()) - return ErrorNumber.InvalidArgument; + if(!FillDirectory()) return ErrorNumber.InvalidArgument; _mounted = true; var bbSig = BigEndianBitConverter.ToUInt16(_bootBlocks, 0x000); - if(bbSig != AppleCommon.BB_MAGIC) - _bootBlocks = null; + if(bbSig != AppleCommon.BB_MAGIC) _bootBlocks = null; - XmlFsType = new FileSystemType(); + Metadata = new FileSystem(); - if(_volMdb.drLsBkUp > 0) - { - XmlFsType.BackupDate = DateHandlers.MacToDateTime(_volMdb.drLsBkUp); - XmlFsType.BackupDateSpecified = true; - } + if(_volMdb.drLsBkUp > 0) Metadata.BackupDate = DateHandlers.MacToDateTime(_volMdb.drLsBkUp); - XmlFsType.Bootable = bbSig == AppleCommon.BB_MAGIC; - XmlFsType.Clusters = _volMdb.drNmAlBlks; - XmlFsType.ClusterSize = _volMdb.drAlBlkSiz; + Metadata.Bootable = bbSig == AppleCommon.BB_MAGIC; + Metadata.Clusters = _volMdb.drNmAlBlks; + Metadata.ClusterSize = _volMdb.drAlBlkSiz; - if(_volMdb.drCrDate > 0) - { - XmlFsType.CreationDate = DateHandlers.MacToDateTime(_volMdb.drCrDate); - XmlFsType.CreationDateSpecified = true; - } + if(_volMdb.drCrDate > 0) Metadata.CreationDate = DateHandlers.MacToDateTime(_volMdb.drCrDate); - XmlFsType.Files = _volMdb.drNmFls; - XmlFsType.FilesSpecified = true; - XmlFsType.FreeClusters = _volMdb.drFreeBks; - XmlFsType.FreeClustersSpecified = true; - XmlFsType.Type = "MFS"; - XmlFsType.VolumeName = _volMdb.drVN; + Metadata.Files = _volMdb.drNmFls; + Metadata.FreeClusters = _volMdb.drFreeBks; + Metadata.Type = FS_TYPE; + Metadata.VolumeName = _volMdb.drVN; return ErrorNumber.NoError; } @@ -233,11 +207,13 @@ public sealed partial class AppleMFS Files = _volMdb.drNmFls, FreeBlocks = _volMdb.drFreeBks, PluginId = Id, - Type = "Apple MFS" + Type = FS_TYPE }; stat.FreeFiles = uint.MaxValue - stat.Files; return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AppleMFS/Xattr.cs b/Aaru.Filesystems/AppleMFS/Xattr.cs index c87f5f986..3c61e0fac 100644 --- a/Aaru.Filesystems/AppleMFS/Xattr.cs +++ b/Aaru.Filesystems/AppleMFS/Xattr.cs @@ -28,56 +28,57 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using Aaru.CommonTypes.Enums; using Aaru.Helpers; +namespace Aaru.Filesystems; + // Information from Inside Macintosh Volume II public sealed partial class AppleMFS { +#region IReadOnlyFilesystem Members + /// public ErrorNumber ListXAttr(string path, out List xattrs) { xattrs = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; path = pathElements[0]; - xattrs = new List(); + xattrs = []; if(_debug) - if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || + { + if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0) + string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0) { if(_device.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag)) xattrs.Add("com.apple.macintosh.tags"); return ErrorNumber.NoError; } + } - if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) - return ErrorNumber.NoSuchFile; + if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) return ErrorNumber.NoSuchFile; - if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) - return ErrorNumber.NoSuchFile; + if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) return ErrorNumber.NoSuchFile; if(entry.flRLgLen > 0) { @@ -89,9 +90,7 @@ public sealed partial class AppleMFS xattrs.Add("com.apple.FinderInfo"); - if(_debug && - _device.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag) && - entry.flLgLen > 0) + if(_debug && _device.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag) && entry.flLgLen > 0) xattrs.Add("com.apple.macintosh.tags"); xattrs.Sort(); @@ -102,24 +101,25 @@ public sealed partial class AppleMFS /// public ErrorNumber GetXattr(string path, string xattr, ref byte[] buf) { - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; path = pathElements[0]; if(_debug) - if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || + { + if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0) + string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0) + { if(_device.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag) && string.Compare(xattr, "com.apple.macintosh.tags", StringComparison.InvariantCulture) == 0) { @@ -157,29 +157,25 @@ public sealed partial class AppleMFS } else return ErrorNumber.NoSuchExtendedAttribute; + } + } ErrorNumber error; - if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) - return ErrorNumber.NoSuchFile; + if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId)) return ErrorNumber.NoSuchFile; - if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) - return ErrorNumber.NoSuchFile; + if(!_idToEntry.TryGetValue(fileId, out FileEntry entry)) return ErrorNumber.NoSuchFile; - if(entry.flRLgLen > 0 && - string.Compare(xattr, "com.apple.ResourceFork", StringComparison.InvariantCulture) == 0) + switch(entry.flRLgLen) { - error = ReadFile(path, out buf, true, false); + case > 0 when string.Compare(xattr, "com.apple.ResourceFork", StringComparison.InvariantCulture) == 0: + error = ReadFile(path, out buf, true, false); - return error; - } + return error; + case > 0 when string.Compare(xattr, "com.apple.ResourceFork.tags", StringComparison.InvariantCulture) == 0: + error = ReadFile(path, out buf, true, true); - if(entry.flRLgLen > 0 && - string.Compare(xattr, "com.apple.ResourceFork.tags", StringComparison.InvariantCulture) == 0) - { - error = ReadFile(path, out buf, true, true); - - return error; + return error; } if(string.Compare(xattr, "com.apple.FinderInfo", StringComparison.InvariantCulture) == 0) @@ -198,4 +194,6 @@ public sealed partial class AppleMFS return error; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/AtheOS.cs b/Aaru.Filesystems/AtheOS.cs deleted file mode 100644 index b6f84d586..000000000 --- a/Aaru.Filesystems/AtheOS.cs +++ /dev/null @@ -1,252 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Atheos.cs -// Author(s) : Natalia Portillo -// -// Component : Atheos filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Atheos filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection for the AtheOS filesystem -[SuppressMessage("ReSharper", "UnusedMember.Local")] -public sealed class AtheOS : IFilesystem -{ - // Little endian constants (that is, as read by .NET :p) - const uint AFS_MAGIC1 = 0x41465331; - const uint AFS_MAGIC2 = 0xDD121031; - const uint AFS_MAGIC3 = 0x15B6830E; - - // Common constants - const uint AFS_SUPERBLOCK_SIZE = 1024; - const uint AFS_BOOTBLOCK_SIZE = AFS_SUPERBLOCK_SIZE; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "AtheOS Filesystem"; - /// - public Guid Id => new("AAB2C4F1-DC07-49EE-A948-576CC51B58C5"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - ulong sector = AFS_BOOTBLOCK_SIZE / imagePlugin.Info.SectorSize; - uint offset = AFS_BOOTBLOCK_SIZE % imagePlugin.Info.SectorSize; - uint run = 1; - - if(imagePlugin.Info.SectorSize < AFS_SUPERBLOCK_SIZE) - run = AFS_SUPERBLOCK_SIZE / imagePlugin.Info.SectorSize; - - if(sector + partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(sector + partition.Start, run, out byte[] tmp); - - if(errno != ErrorNumber.NoError) - return false; - - var sbSector = new byte[AFS_SUPERBLOCK_SIZE]; - - if(offset + AFS_SUPERBLOCK_SIZE > tmp.Length) - return false; - - Array.Copy(tmp, offset, sbSector, 0, AFS_SUPERBLOCK_SIZE); - - var magic = BitConverter.ToUInt32(sbSector, 0x20); - - return magic == AFS_MAGIC1; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - var sb = new StringBuilder(); - - ulong sector = AFS_BOOTBLOCK_SIZE / imagePlugin.Info.SectorSize; - uint offset = AFS_BOOTBLOCK_SIZE % imagePlugin.Info.SectorSize; - uint run = 1; - - if(imagePlugin.Info.SectorSize < AFS_SUPERBLOCK_SIZE) - run = AFS_SUPERBLOCK_SIZE / imagePlugin.Info.SectorSize; - - ErrorNumber errno = imagePlugin.ReadSectors(sector + partition.Start, run, out byte[] tmp); - - if(errno != ErrorNumber.NoError) - return; - - var sbSector = new byte[AFS_SUPERBLOCK_SIZE]; - Array.Copy(tmp, offset, sbSector, 0, AFS_SUPERBLOCK_SIZE); - - SuperBlock afsSb = Marshal.ByteArrayToStructureLittleEndian(sbSector); - - sb.AppendLine("Atheos filesystem"); - - if(afsSb.flags == 1) - sb.AppendLine("Filesystem is read-only"); - - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(afsSb.name, Encoding)).AppendLine(); - sb.AppendFormat("{0} bytes per block", afsSb.block_size).AppendLine(); - - sb.AppendFormat("{0} blocks in volume ({1} bytes)", afsSb.num_blocks, afsSb.num_blocks * afsSb.block_size). - AppendLine(); - - sb.AppendFormat("{0} used blocks ({1} bytes)", afsSb.used_blocks, afsSb.used_blocks * afsSb.block_size). - AppendLine(); - - sb.AppendFormat("{0} bytes per i-node", afsSb.inode_size).AppendLine(); - - sb.AppendFormat("{0} blocks per allocation group ({1} bytes)", afsSb.blocks_per_ag, - afsSb.blocks_per_ag * afsSb.block_size).AppendLine(); - - sb.AppendFormat("{0} allocation groups in volume", afsSb.num_ags).AppendLine(); - - sb.AppendFormat("Journal resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", - afsSb.log_blocks_start, afsSb.log_blocks_ag, afsSb.log_blocks_len, - afsSb.log_blocks_len * afsSb.block_size).AppendLine(); - - sb.AppendFormat("Journal starts in byte {0} and has {1} bytes in {2} blocks", afsSb.log_start, afsSb.log_size, - afsSb.log_valid_blocks).AppendLine(); - - sb. - AppendFormat("Root folder's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", - afsSb.root_dir_start, afsSb.root_dir_ag, afsSb.root_dir_len, - afsSb.root_dir_len * afsSb.block_size).AppendLine(); - - sb. - AppendFormat("Directory containing files scheduled for deletion's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", - afsSb.deleted_start, afsSb.deleted_ag, afsSb.deleted_len, - afsSb.deleted_len * afsSb.block_size).AppendLine(); - - sb. - AppendFormat("Indices' i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", - afsSb.indices_start, afsSb.indices_ag, afsSb.indices_len, - afsSb.indices_len * afsSb.block_size).AppendLine(); - - sb.AppendFormat("{0} blocks for bootloader ({1} bytes)", afsSb.boot_size, afsSb.boot_size * afsSb.block_size). - AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Clusters = (ulong)afsSb.num_blocks, - ClusterSize = afsSb.block_size, - Dirty = false, - FreeClusters = (ulong)(afsSb.num_blocks - afsSb.used_blocks), - FreeClustersSpecified = true, - Type = "AtheOS filesystem", - VolumeName = StringHandlers.CToString(afsSb.name, Encoding) - }; - } - - /// Be superblock - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SuperBlock - { - /// 0x000, Volume name, 32 bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] name; - /// 0x020, "AFS1", 0x41465331 - public readonly uint magic1; - /// 0x024, "BIGE", 0x42494745 - public readonly uint fs_byte_order; - /// 0x028, Bytes per block - public readonly uint block_size; - /// 0x02C, 1 << block_shift == block_size - public readonly uint block_shift; - /// 0x030, Blocks in volume - public readonly long num_blocks; - /// 0x038, Used blocks in volume - public readonly long used_blocks; - /// 0x040, Bytes per inode - public readonly int inode_size; - /// 0x044, 0xDD121031 - public readonly uint magic2; - /// 0x048, Blocks per allocation group - public readonly int blocks_per_ag; - /// 0x04C, 1 << ag_shift == blocks_per_ag - public readonly int ag_shift; - /// 0x050, Allocation groups in volume - public readonly int num_ags; - /// 0x054, 0x434c454e if clean, 0x44495254 if dirty - public readonly uint flags; - /// 0x058, Allocation group of journal - public readonly int log_blocks_ag; - /// 0x05C, Start block of journal, inside ag - public readonly ushort log_blocks_start; - /// 0x05E, Length in blocks of journal, inside ag - public readonly ushort log_blocks_len; - /// 0x060, Start of journal - public readonly long log_start; - /// 0x068, Valid block logs - public readonly int log_valid_blocks; - /// 0x06C, Log size - public readonly int log_size; - /// 0x070, 0x15B6830E - public readonly uint magic3; - /// 0x074, Allocation group where root folder's i-node resides - public readonly int root_dir_ag; - /// 0x078, Start in ag of root folder's i-node - public readonly ushort root_dir_start; - /// 0x07A, As this is part of inode_addr, this is 1 - public readonly ushort root_dir_len; - /// 0x07C, Allocation group where pending-delete-files' i-node resides - public readonly int deleted_ag; - /// 0x080, Start in ag of pending-delete-files' i-node - public readonly ushort deleted_start; - /// 0x082, As this is part of inode_addr, this is 1 - public readonly ushort deleted_len; - /// 0x084, Allocation group where indices' i-node resides - public readonly int indices_ag; - /// 0x088, Start in ag of indices' i-node - public readonly ushort indices_start; - /// 0x08A, As this is part of inode_addr, this is 1 - public readonly ushort indices_len; - /// 0x08C, Size of bootloader - public readonly int boot_size; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/AtheOS/AtheOS.cs b/Aaru.Filesystems/AtheOS/AtheOS.cs new file mode 100644 index 000000000..207f208f8 --- /dev/null +++ b/Aaru.Filesystems/AtheOS/AtheOS.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Atheos.cs +// Author(s) : Natalia Portillo +// +// Component : Atheos filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the AtheOS filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class AtheOS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.AtheOS_Name; + + /// + public Guid Id => new("AAB2C4F1-DC07-49EE-A948-576CC51B58C5"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/AtheOS/Consts.cs b/Aaru.Filesystems/AtheOS/Consts.cs new file mode 100644 index 000000000..f66df7bda --- /dev/null +++ b/Aaru.Filesystems/AtheOS/Consts.cs @@ -0,0 +1,48 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Atheos filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the AtheOS filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class AtheOS +{ + // Little endian constants (that is, as read by .NET :p) + const uint AFS_MAGIC1 = 0x41465331; + const uint AFS_MAGIC2 = 0xDD121031; + const uint AFS_MAGIC3 = 0x15B6830E; + + // Common constants + const uint AFS_SUPERBLOCK_SIZE = 1024; + const uint AFS_BOOTBLOCK_SIZE = AFS_SUPERBLOCK_SIZE; + + const string FS_TYPE = "atheos"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/AtheOS/Info.cs b/Aaru.Filesystems/AtheOS/Info.cs new file mode 100644 index 000000000..c292e5562 --- /dev/null +++ b/Aaru.Filesystems/AtheOS/Info.cs @@ -0,0 +1,176 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Atheos filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the AtheOS filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class AtheOS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + ulong sector = AFS_BOOTBLOCK_SIZE / imagePlugin.Info.SectorSize; + uint offset = AFS_BOOTBLOCK_SIZE % imagePlugin.Info.SectorSize; + uint run = 1; + + if(imagePlugin.Info.SectorSize < AFS_SUPERBLOCK_SIZE) run = AFS_SUPERBLOCK_SIZE / imagePlugin.Info.SectorSize; + + if(sector + partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(sector + partition.Start, run, out byte[] tmp); + + if(errno != ErrorNumber.NoError) return false; + + var sbSector = new byte[AFS_SUPERBLOCK_SIZE]; + + if(offset + AFS_SUPERBLOCK_SIZE > tmp.Length) return false; + + Array.Copy(tmp, offset, sbSector, 0, AFS_SUPERBLOCK_SIZE); + + var magic = BitConverter.ToUInt32(sbSector, 0x20); + + return magic == AFS_MAGIC1; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + ulong sector = AFS_BOOTBLOCK_SIZE / imagePlugin.Info.SectorSize; + uint offset = AFS_BOOTBLOCK_SIZE % imagePlugin.Info.SectorSize; + uint run = 1; + + if(imagePlugin.Info.SectorSize < AFS_SUPERBLOCK_SIZE) run = AFS_SUPERBLOCK_SIZE / imagePlugin.Info.SectorSize; + + ErrorNumber errno = imagePlugin.ReadSectors(sector + partition.Start, run, out byte[] tmp); + + if(errno != ErrorNumber.NoError) return; + + var sbSector = new byte[AFS_SUPERBLOCK_SIZE]; + Array.Copy(tmp, offset, sbSector, 0, AFS_SUPERBLOCK_SIZE); + + SuperBlock afsSb = Marshal.ByteArrayToStructureLittleEndian(sbSector); + + sb.AppendLine(Localization.Atheos_filesystem); + + if(afsSb.flags == 1) sb.AppendLine(Localization.Filesystem_is_read_only); + + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(afsSb.name, encoding)).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_block, afsSb.block_size).AppendLine(); + + sb.AppendFormat(Localization._0_blocks_in_volume_1_bytes, afsSb.num_blocks, afsSb.num_blocks * afsSb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization._0_used_blocks_1_bytes, afsSb.used_blocks, afsSb.used_blocks * afsSb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization._0_bytes_per_i_node, afsSb.inode_size).AppendLine(); + + sb.AppendFormat(Localization._0_blocks_per_allocation_group_1_bytes, + afsSb.blocks_per_ag, + afsSb.blocks_per_ag * afsSb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization._0_allocation_groups_in_volume, afsSb.num_ags).AppendLine(); + + sb.AppendFormat(Localization.Journal_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes, + afsSb.log_blocks_start, + afsSb.log_blocks_ag, + afsSb.log_blocks_len, + afsSb.log_blocks_len * afsSb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization.Journal_starts_in_byte_0_and_has_1_bytes_in_2_blocks, + afsSb.log_start, + afsSb.log_size, + afsSb.log_valid_blocks) + .AppendLine(); + + sb.AppendFormat(Localization + .Root_folder_s_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes, + afsSb.root_dir_start, + afsSb.root_dir_ag, + afsSb.root_dir_len, + afsSb.root_dir_len * afsSb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization + .Directory_containing_files_scheduled_for_deletion_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes, + afsSb.deleted_start, + afsSb.deleted_ag, + afsSb.deleted_len, + afsSb.deleted_len * afsSb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization + .Indices_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes, + afsSb.indices_start, + afsSb.indices_ag, + afsSb.indices_len, + afsSb.indices_len * afsSb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization._0_blocks_for_bootloader_1_bytes, + afsSb.boot_size, + afsSb.boot_size * afsSb.block_size) + .AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Clusters = (ulong)afsSb.num_blocks, + ClusterSize = afsSb.block_size, + Dirty = false, + FreeClusters = (ulong)(afsSb.num_blocks - afsSb.used_blocks), + Type = FS_TYPE, + VolumeName = StringHandlers.CToString(afsSb.name, encoding) + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/AtheOS/Structs.cs b/Aaru.Filesystems/AtheOS/Structs.cs new file mode 100644 index 000000000..9b55204f0 --- /dev/null +++ b/Aaru.Filesystems/AtheOS/Structs.cs @@ -0,0 +1,109 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Atheos filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the AtheOS filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class AtheOS +{ +#region Nested type: SuperBlock + + /// Be superblock + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SuperBlock + { + /// 0x000, Volume name, 32 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] name; + /// 0x020, "AFS1", 0x41465331 + public readonly uint magic1; + /// 0x024, "BIGE", 0x42494745 + public readonly uint fs_byte_order; + /// 0x028, Bytes per block + public readonly uint block_size; + /// 0x02C, 1 << block_shift == block_size + public readonly uint block_shift; + /// 0x030, Blocks in volume + public readonly long num_blocks; + /// 0x038, Used blocks in volume + public readonly long used_blocks; + /// 0x040, Bytes per inode + public readonly int inode_size; + /// 0x044, 0xDD121031 + public readonly uint magic2; + /// 0x048, Blocks per allocation group + public readonly int blocks_per_ag; + /// 0x04C, 1 << ag_shift == blocks_per_ag + public readonly int ag_shift; + /// 0x050, Allocation groups in volume + public readonly int num_ags; + /// 0x054, 0x434c454e if clean, 0x44495254 if dirty + public readonly uint flags; + /// 0x058, Allocation group of journal + public readonly int log_blocks_ag; + /// 0x05C, Start block of journal, inside ag + public readonly ushort log_blocks_start; + /// 0x05E, Length in blocks of journal, inside ag + public readonly ushort log_blocks_len; + /// 0x060, Start of journal + public readonly long log_start; + /// 0x068, Valid block logs + public readonly int log_valid_blocks; + /// 0x06C, Log size + public readonly int log_size; + /// 0x070, 0x15B6830E + public readonly uint magic3; + /// 0x074, Allocation group where root folder's i-node resides + public readonly int root_dir_ag; + /// 0x078, Start in ag of root folder's i-node + public readonly ushort root_dir_start; + /// 0x07A, As this is part of inode_addr, this is 1 + public readonly ushort root_dir_len; + /// 0x07C, Allocation group where pending-delete-files' i-node resides + public readonly int deleted_ag; + /// 0x080, Start in ag of pending-delete-files' i-node + public readonly ushort deleted_start; + /// 0x082, As this is part of inode_addr, this is 1 + public readonly ushort deleted_len; + /// 0x084, Allocation group where indices' i-node resides + public readonly int indices_ag; + /// 0x088, Start in ag of indices' i-node + public readonly ushort indices_start; + /// 0x08A, As this is part of inode_addr, this is 1 + public readonly ushort indices_len; + /// 0x08C, Size of bootloader + public readonly int boot_size; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Authors.cs b/Aaru.Filesystems/Authors.cs new file mode 100644 index 000000000..d076517b0 --- /dev/null +++ b/Aaru.Filesystems/Authors.cs @@ -0,0 +1,37 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Authors.cs +// Author(s) : Natalia Portillo +// +// Component : Aaru.Filesystems. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +static class Authors +{ + internal const string NataliaPortillo = "Natalia Portillo"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/BFS.cs b/Aaru.Filesystems/BFS.cs deleted file mode 100644 index 5847f4a94..000000000 --- a/Aaru.Filesystems/BFS.cs +++ /dev/null @@ -1,315 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : BFS.cs -// Author(s) : Natalia Portillo -// -// Component : BeOS filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the BeOS filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Information from Practical Filesystem Design, ISBN 1-55860-497-9 -/// -/// Implements detection of the Be (new) filesystem -[SuppressMessage("ReSharper", "UnusedMember.Local")] -public sealed class BeFS : IFilesystem -{ - // Little endian constants (that is, as read by .NET :p) - const uint BEFS_MAGIC1 = 0x42465331; - const uint BEFS_MAGIC2 = 0xDD121031; - const uint BEFS_MAGIC3 = 0x15B6830E; - const uint BEFS_ENDIAN = 0x42494745; - - // Big endian constants - const uint BEFS_CIGAM1 = 0x31534642; - const uint BEFS_NAIDNE = 0x45474942; - - // Common constants - const uint BEFS_CLEAN = 0x434C454E; - const uint BEFS_DIRTY = 0x44495254; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Be Filesystem"; - /// - public Guid Id => new("dc8572b3-b6ad-46e4-8de9-cbe123ff6672"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(2 + partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] sbSector); - - if(errno != ErrorNumber.NoError) - return false; - - var magic = BitConverter.ToUInt32(sbSector, 0x20); - var magicBe = BigEndianBitConverter.ToUInt32(sbSector, 0x20); - - if(magic == BEFS_MAGIC1 || - magicBe == BEFS_MAGIC1) - return true; - - if(sbSector.Length >= 0x400) - { - magic = BitConverter.ToUInt32(sbSector, 0x220); - magicBe = BigEndianBitConverter.ToUInt32(sbSector, 0x220); - } - - if(magic == BEFS_MAGIC1 || - magicBe == BEFS_MAGIC1) - return true; - - errno = imagePlugin.ReadSector(1 + partition.Start, out sbSector); - - if(errno != ErrorNumber.NoError) - return false; - - magic = BitConverter.ToUInt32(sbSector, 0x20); - magicBe = BigEndianBitConverter.ToUInt32(sbSector, 0x20); - - return magic == BEFS_MAGIC1 || magicBe == BEFS_MAGIC1; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - var sb = new StringBuilder(); - - var besb = new SuperBlock(); - - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] sbSector); - - if(errno != ErrorNumber.NoError) - return; - - bool littleEndian; - - besb.magic1 = BigEndianBitConverter.ToUInt32(sbSector, 0x20); - - if(besb.magic1 is BEFS_MAGIC1 or BEFS_CIGAM1) // Magic is at offset - littleEndian = besb.magic1 == BEFS_CIGAM1; - else - { - errno = imagePlugin.ReadSector(1 + partition.Start, out sbSector); - - if(errno != ErrorNumber.NoError) - return; - - besb.magic1 = BigEndianBitConverter.ToUInt32(sbSector, 0x20); - - if(besb.magic1 is BEFS_MAGIC1 or BEFS_CIGAM1) // There is a boot sector - littleEndian = besb.magic1 == BEFS_CIGAM1; - else if(sbSector.Length >= 0x400) - { - errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] temp); - - if(errno != ErrorNumber.NoError) - return; - - besb.magic1 = BigEndianBitConverter.ToUInt32(temp, 0x220); - - if(besb.magic1 is BEFS_MAGIC1 or BEFS_CIGAM1) // There is a boot sector - { - littleEndian = besb.magic1 == BEFS_CIGAM1; - sbSector = new byte[0x200]; - Array.Copy(temp, 0x200, sbSector, 0, 0x200); - } - else - return; - } - else - return; - } - - besb = littleEndian ? Marshal.ByteArrayToStructureLittleEndian(sbSector) - : Marshal.ByteArrayToStructureBigEndian(sbSector); - - sb.AppendLine(littleEndian ? "Little-endian BeFS" : "Big-endian BeFS"); - - if(besb.magic1 != BEFS_MAGIC1 || - besb.fs_byte_order != BEFS_ENDIAN || - besb.magic2 != BEFS_MAGIC2 || - besb.magic3 != BEFS_MAGIC3 || - besb.root_dir_len != 1 || - besb.indices_len != 1 || - 1 << (int)besb.block_shift != besb.block_size) - { - sb.AppendLine("Superblock seems corrupt, following information may be incorrect"); - sb.AppendFormat("Magic 1: 0x{0:X8} (Should be 0x42465331)", besb.magic1).AppendLine(); - sb.AppendFormat("Magic 2: 0x{0:X8} (Should be 0xDD121031)", besb.magic2).AppendLine(); - sb.AppendFormat("Magic 3: 0x{0:X8} (Should be 0x15B6830E)", besb.magic3).AppendLine(); - - sb.AppendFormat("Filesystem endianness: 0x{0:X8} (Should be 0x42494745)", besb.fs_byte_order).AppendLine(); - - sb.AppendFormat("Root folder's i-node size: {0} blocks (Should be 1)", besb.root_dir_len).AppendLine(); - sb.AppendFormat("Indices' i-node size: {0} blocks (Should be 1)", besb.indices_len).AppendLine(); - - sb.AppendFormat("1 << block_shift == block_size => 1 << {0} == {1} (Should be {2})", besb.block_shift, - 1 << (int)besb.block_shift, besb.block_size).AppendLine(); - } - - switch(besb.flags) - { - case BEFS_CLEAN: - sb.AppendLine(besb.log_start == besb.log_end ? "Filesystem is clean" : "Filesystem is dirty"); - - break; - case BEFS_DIRTY: - sb.AppendLine("Filesystem is dirty"); - - break; - default: - sb.AppendFormat("Unknown flags: {0:X8}", besb.flags).AppendLine(); - - break; - } - - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(besb.name, Encoding)).AppendLine(); - sb.AppendFormat("{0} bytes per block", besb.block_size).AppendLine(); - - sb.AppendFormat("{0} blocks in volume ({1} bytes)", besb.num_blocks, besb.num_blocks * besb.block_size). - AppendLine(); - - sb.AppendFormat("{0} used blocks ({1} bytes)", besb.used_blocks, besb.used_blocks * besb.block_size). - AppendLine(); - - sb.AppendFormat("{0} bytes per i-node", besb.inode_size).AppendLine(); - - sb.AppendFormat("{0} blocks per allocation group ({1} bytes)", besb.blocks_per_ag, - besb.blocks_per_ag * besb.block_size).AppendLine(); - - sb.AppendFormat("{0} allocation groups in volume", besb.num_ags).AppendLine(); - - sb.AppendFormat("Journal resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", - besb.log_blocks_start, besb.log_blocks_ag, besb.log_blocks_len, - besb.log_blocks_len * besb.block_size).AppendLine(); - - sb.AppendFormat("Journal starts in byte {0} and ends in byte {1}", besb.log_start, besb.log_end).AppendLine(); - - sb. - AppendFormat("Root folder's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", - besb.root_dir_start, besb.root_dir_ag, besb.root_dir_len, besb.root_dir_len * besb.block_size). - AppendLine(); - - sb. - AppendFormat("Indices' i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", - besb.indices_start, besb.indices_ag, besb.indices_len, besb.indices_len * besb.block_size). - AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Clusters = (ulong)besb.num_blocks, - ClusterSize = besb.block_size, - Dirty = besb.flags == BEFS_DIRTY, - FreeClusters = (ulong)(besb.num_blocks - besb.used_blocks), - FreeClustersSpecified = true, - Type = "BeFS", - VolumeName = StringHandlers.CToString(besb.name, Encoding) - }; - } - - /// Be superblock - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SuperBlock - { - /// 0x000, Volume name, 32 bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] name; - /// 0x020, "BFS1", 0x42465331 - public uint magic1; - /// 0x024, "BIGE", 0x42494745 - public readonly uint fs_byte_order; - /// 0x028, Bytes per block - public readonly uint block_size; - /// 0x02C, 1 << block_shift == block_size - public readonly uint block_shift; - /// 0x030, Blocks in volume - public readonly long num_blocks; - /// 0x038, Used blocks in volume - public readonly long used_blocks; - /// 0x040, Bytes per inode - public readonly int inode_size; - /// 0x044, 0xDD121031 - public readonly uint magic2; - /// 0x048, Blocks per allocation group - public readonly int blocks_per_ag; - /// 0x04C, 1 << ag_shift == blocks_per_ag - public readonly int ag_shift; - /// 0x050, Allocation groups in volume - public readonly int num_ags; - /// 0x054, 0x434c454e if clean, 0x44495254 if dirty - public readonly uint flags; - /// 0x058, Allocation group of journal - public readonly int log_blocks_ag; - /// 0x05C, Start block of journal, inside ag - public readonly ushort log_blocks_start; - /// 0x05E, Length in blocks of journal, inside ag - public readonly ushort log_blocks_len; - /// 0x060, Start of journal - public readonly long log_start; - /// 0x068, End of journal - public readonly long log_end; - /// 0x070, 0x15B6830E - public readonly uint magic3; - /// 0x074, Allocation group where root folder's i-node resides - public readonly int root_dir_ag; - /// 0x078, Start in ag of root folder's i-node - public readonly ushort root_dir_start; - /// 0x07A, As this is part of inode_addr, this is 1 - public readonly ushort root_dir_len; - /// 0x07C, Allocation group where indices' i-node resides - public readonly int indices_ag; - /// 0x080, Start in ag of indices' i-node - public readonly ushort indices_start; - /// 0x082, As this is part of inode_addr, this is 1 - public readonly ushort indices_len; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/BFS/BFS.cs b/Aaru.Filesystems/BFS/BFS.cs new file mode 100644 index 000000000..3e56871bf --- /dev/null +++ b/Aaru.Filesystems/BFS/BFS.cs @@ -0,0 +1,53 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : BFS.cs +// Author(s) : Natalia Portillo +// +// Component : BeOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from Practical Filesystem Design, ISBN 1-55860-497-9 +/// +/// Implements detection of the Be (new) filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class BeFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.BeFS_Name; + + /// + public Guid Id => new("dc8572b3-b6ad-46e4-8de9-cbe123ff6672"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/BFS/Consts.cs b/Aaru.Filesystems/BFS/Consts.cs new file mode 100644 index 000000000..99f2aa9b4 --- /dev/null +++ b/Aaru.Filesystems/BFS/Consts.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : BeOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Information from Practical Filesystem Design, ISBN 1-55860-497-9 +/// +/// Implements detection of the Be (new) filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class BeFS +{ + // Little endian constants (that is, as read by .NET :p) + const uint BEFS_MAGIC1 = 0x42465331; + const uint BEFS_MAGIC2 = 0xDD121031; + const uint BEFS_MAGIC3 = 0x15B6830E; + const uint BEFS_ENDIAN = 0x42494745; + + // Big endian constants + const uint BEFS_CIGAM1 = 0x31534642; + const uint BEFS_NAIDNE = 0x45474942; + + // Common constants + const uint BEFS_CLEAN = 0x434C454E; + const uint BEFS_DIRTY = 0x44495254; + + const string FS_TYPE = "befs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/BFS/Info.cs b/Aaru.Filesystems/BFS/Info.cs new file mode 100644 index 000000000..89e707164 --- /dev/null +++ b/Aaru.Filesystems/BFS/Info.cs @@ -0,0 +1,242 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : BeOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from Practical Filesystem Design, ISBN 1-55860-497-9 +/// +/// Implements detection of the Be (new) filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class BeFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(2 + partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] sbSector); + + if(errno != ErrorNumber.NoError) return false; + + var magic = BitConverter.ToUInt32(sbSector, 0x20); + var magicBe = BigEndianBitConverter.ToUInt32(sbSector, 0x20); + + if(magic == BEFS_MAGIC1 || magicBe == BEFS_MAGIC1) return true; + + if(sbSector.Length >= 0x400) + { + magic = BitConverter.ToUInt32(sbSector, 0x220); + magicBe = BigEndianBitConverter.ToUInt32(sbSector, 0x220); + } + + if(magic == BEFS_MAGIC1 || magicBe == BEFS_MAGIC1) return true; + + errno = imagePlugin.ReadSector(1 + partition.Start, out sbSector); + + if(errno != ErrorNumber.NoError) return false; + + magic = BitConverter.ToUInt32(sbSector, 0x20); + magicBe = BigEndianBitConverter.ToUInt32(sbSector, 0x20); + + return magic == BEFS_MAGIC1 || magicBe == BEFS_MAGIC1; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + var besb = new SuperBlock(); + + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] sbSector); + + if(errno != ErrorNumber.NoError) return; + + bool littleEndian; + + besb.magic1 = BigEndianBitConverter.ToUInt32(sbSector, 0x20); + + if(besb.magic1 is BEFS_MAGIC1 or BEFS_CIGAM1) // Magic is at offset + littleEndian = besb.magic1 == BEFS_CIGAM1; + else + { + errno = imagePlugin.ReadSector(1 + partition.Start, out sbSector); + + if(errno != ErrorNumber.NoError) return; + + besb.magic1 = BigEndianBitConverter.ToUInt32(sbSector, 0x20); + + if(besb.magic1 is BEFS_MAGIC1 or BEFS_CIGAM1) // There is a boot sector + littleEndian = besb.magic1 == BEFS_CIGAM1; + else if(sbSector.Length >= 0x400) + { + errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] temp); + + if(errno != ErrorNumber.NoError) return; + + besb.magic1 = BigEndianBitConverter.ToUInt32(temp, 0x220); + + if(besb.magic1 is BEFS_MAGIC1 or BEFS_CIGAM1) // There is a boot sector + { + littleEndian = besb.magic1 == BEFS_CIGAM1; + sbSector = new byte[0x200]; + Array.Copy(temp, 0x200, sbSector, 0, 0x200); + } + else + return; + } + else + return; + } + + besb = littleEndian + ? Marshal.ByteArrayToStructureLittleEndian(sbSector) + : Marshal.ByteArrayToStructureBigEndian(sbSector); + + sb.AppendLine(littleEndian ? Localization.Little_endian_BeFS : Localization.Big_endian_BeFS); + + if(besb.magic1 != BEFS_MAGIC1 || + besb.fs_byte_order != BEFS_ENDIAN || + besb.magic2 != BEFS_MAGIC2 || + besb.magic3 != BEFS_MAGIC3 || + besb.root_dir_len != 1 || + besb.indices_len != 1 || + 1 << (int)besb.block_shift != besb.block_size) + { + sb.AppendLine(Localization.Superblock_seems_corrupt_following_information_may_be_incorrect); + sb.AppendFormat(Localization.Magic_one_0_Should_be_0x42465331, besb.magic1).AppendLine(); + sb.AppendFormat(Localization.Magic_two_0_Should_be_0xDD121031, besb.magic2).AppendLine(); + sb.AppendFormat(Localization.Magic_three_0_Should_be_0x15B6830E, besb.magic3).AppendLine(); + + sb.AppendFormat(Localization.Filesystem_endianness_0_Should_be_0x42494745, besb.fs_byte_order).AppendLine(); + + sb.AppendFormat(Localization.Root_folder_i_node_size_0_blocks_Should_be_one, besb.root_dir_len) + .AppendLine(); + + sb.AppendFormat(Localization.Indices_i_node_size_0_blocks_Should_be_one, besb.indices_len).AppendLine(); + + sb.AppendFormat(Localization.blockshift_0_1_should_be_2, + besb.block_shift, + 1 << (int)besb.block_shift, + besb.block_size) + .AppendLine(); + } + + switch(besb.flags) + { + case BEFS_CLEAN: + sb.AppendLine(besb.log_start == besb.log_end + ? Localization.Filesystem_is_clean + : Localization.Filesystem_is_dirty); + + break; + case BEFS_DIRTY: + sb.AppendLine(Localization.Filesystem_is_dirty); + + break; + default: + sb.AppendFormat(Localization.Unknown_flags_0_X8, besb.flags).AppendLine(); + + break; + } + + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(besb.name, encoding)).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_block, besb.block_size).AppendLine(); + + sb.AppendFormat(Localization._0_blocks_in_volume_1_bytes, besb.num_blocks, besb.num_blocks * besb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization._0_used_blocks_1_bytes, besb.used_blocks, besb.used_blocks * besb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization._0_bytes_per_i_node, besb.inode_size).AppendLine(); + + sb.AppendFormat(Localization._0_blocks_per_allocation_group_1_bytes, + besb.blocks_per_ag, + besb.blocks_per_ag * besb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization._0_allocation_groups_in_volume, besb.num_ags).AppendLine(); + + sb.AppendFormat(Localization.Journal_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes, + besb.log_blocks_start, + besb.log_blocks_ag, + besb.log_blocks_len, + besb.log_blocks_len * besb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization.Journal_starts_in_byte_0_and_ends_in_byte_1, besb.log_start, besb.log_end) + .AppendLine(); + + sb.AppendFormat(Localization + .Root_folder_s_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes, + besb.root_dir_start, + besb.root_dir_ag, + besb.root_dir_len, + besb.root_dir_len * besb.block_size) + .AppendLine(); + + sb.AppendFormat(Localization + .Indices_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes, + besb.indices_start, + besb.indices_ag, + besb.indices_len, + besb.indices_len * besb.block_size) + .AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Clusters = (ulong)besb.num_blocks, + ClusterSize = besb.block_size, + Dirty = besb.flags == BEFS_DIRTY, + FreeClusters = (ulong)(besb.num_blocks - besb.used_blocks), + Type = FS_TYPE, + VolumeName = StringHandlers.CToString(besb.name, encoding) + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/BFS/Structs.cs b/Aaru.Filesystems/BFS/Structs.cs new file mode 100644 index 000000000..0bb8c7124 --- /dev/null +++ b/Aaru.Filesystems/BFS/Structs.cs @@ -0,0 +1,100 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : BeOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Information from Practical Filesystem Design, ISBN 1-55860-497-9 +/// +/// Implements detection of the Be (new) filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class BeFS +{ +#region Nested type: SuperBlock + + /// Be superblock + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SuperBlock + { + /// 0x000, Volume name, 32 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] name; + /// 0x020, "BFS1", 0x42465331 + public uint magic1; + /// 0x024, "BIGE", 0x42494745 + public readonly uint fs_byte_order; + /// 0x028, Bytes per block + public readonly uint block_size; + /// 0x02C, 1 << block_shift == block_size + public readonly uint block_shift; + /// 0x030, Blocks in volume + public readonly long num_blocks; + /// 0x038, Used blocks in volume + public readonly long used_blocks; + /// 0x040, Bytes per inode + public readonly int inode_size; + /// 0x044, 0xDD121031 + public readonly uint magic2; + /// 0x048, Blocks per allocation group + public readonly int blocks_per_ag; + /// 0x04C, 1 << ag_shift == blocks_per_ag + public readonly int ag_shift; + /// 0x050, Allocation groups in volume + public readonly int num_ags; + /// 0x054, 0x434c454e if clean, 0x44495254 if dirty + public readonly uint flags; + /// 0x058, Allocation group of journal + public readonly int log_blocks_ag; + /// 0x05C, Start block of journal, inside ag + public readonly ushort log_blocks_start; + /// 0x05E, Length in blocks of journal, inside ag + public readonly ushort log_blocks_len; + /// 0x060, Start of journal + public readonly long log_start; + /// 0x068, End of journal + public readonly long log_end; + /// 0x070, 0x15B6830E + public readonly uint magic3; + /// 0x074, Allocation group where root folder's i-node resides + public readonly int root_dir_ag; + /// 0x078, Start in ag of root folder's i-node + public readonly ushort root_dir_start; + /// 0x07A, As this is part of inode_addr, this is 1 + public readonly ushort root_dir_len; + /// 0x07C, Allocation group where indices' i-node resides + public readonly int indices_ag; + /// 0x080, Start in ag of indices' i-node + public readonly ushort indices_start; + /// 0x082, As this is part of inode_addr, this is 1 + public readonly ushort indices_len; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/BTRFS.cs b/Aaru.Filesystems/BTRFS.cs deleted file mode 100644 index b4180ea1a..000000000 --- a/Aaru.Filesystems/BTRFS.cs +++ /dev/null @@ -1,276 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : BTRFS.cs -// Author(s) : Natalia Portillo -// -// Component : B-tree file system plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the B-tree file system and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the b-tree filesystem (btrfs) -public sealed class BTRFS : IFilesystem -{ - /// BTRFS magic "_BHRfS_M" - const ulong BTRFS_MAGIC = 0x4D5F53665248425F; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "B-tree file system"; - /// - public Guid Id => new("C904CF15-5222-446B-B7DB-02EAC5D781B3"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start >= partition.End) - return false; - - ulong sbSectorOff = 0x10000 / imagePlugin.Info.SectorSize; - uint sbSectorSize = 0x1000 / imagePlugin.Info.SectorSize; - - if(sbSectorOff + partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(sbSectorOff + partition.Start, sbSectorSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - SuperBlock btrfsSb; - - try - { - btrfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); - } - catch - { - return false; - } - - AaruConsole.DebugWriteLine("BTRFS Plugin", "sbSectorOff = {0}", sbSectorOff); - AaruConsole.DebugWriteLine("BTRFS Plugin", "sbSectorSize = {0}", sbSectorSize); - AaruConsole.DebugWriteLine("BTRFS Plugin", "partition.PartitionStartSector = {0}", partition.Start); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.magic = 0x{0:X16}", btrfsSb.magic); - - return btrfsSb.magic == BTRFS_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - var sbInformation = new StringBuilder(); - XmlFsType = new FileSystemType(); - information = ""; - - ulong sbSectorOff = 0x10000 / imagePlugin.Info.SectorSize; - uint sbSectorSize = 0x1000 / imagePlugin.Info.SectorSize; - - ErrorNumber errno = imagePlugin.ReadSectors(sbSectorOff + partition.Start, sbSectorSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - SuperBlock btrfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.checksum = {0}", btrfsSb.checksum); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.uuid = {0}", btrfsSb.uuid); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.pba = {0}", btrfsSb.pba); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.flags = {0}", btrfsSb.flags); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.magic = {0}", btrfsSb.magic); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.generation = {0}", btrfsSb.generation); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.root_lba = {0}", btrfsSb.root_lba); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.chunk_lba = {0}", btrfsSb.chunk_lba); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.log_lba = {0}", btrfsSb.log_lba); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.log_root_transid = {0}", btrfsSb.log_root_transid); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.total_bytes = {0}", btrfsSb.total_bytes); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.bytes_used = {0}", btrfsSb.bytes_used); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.root_dir_objectid = {0}", btrfsSb.root_dir_objectid); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.num_devices = {0}", btrfsSb.num_devices); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.sectorsize = {0}", btrfsSb.sectorsize); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.nodesize = {0}", btrfsSb.nodesize); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.leafsize = {0}", btrfsSb.leafsize); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.stripesize = {0}", btrfsSb.stripesize); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.n = {0}", btrfsSb.n); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.chunk_root_generation = {0}", - btrfsSb.chunk_root_generation); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.compat_flags = 0x{0:X16}", btrfsSb.compat_flags); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.compat_ro_flags = 0x{0:X16}", btrfsSb.compat_ro_flags); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.incompat_flags = 0x{0:X16}", btrfsSb.incompat_flags); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.csum_type = {0}", btrfsSb.csum_type); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.root_level = {0}", btrfsSb.root_level); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.chunk_root_level = {0}", btrfsSb.chunk_root_level); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.log_root_level = {0}", btrfsSb.log_root_level); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.id = 0x{0:X16}", btrfsSb.dev_item.id); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.bytes = {0}", btrfsSb.dev_item.bytes); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.used = {0}", btrfsSb.dev_item.used); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.optimal_align = {0}", - btrfsSb.dev_item.optimal_align); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.optimal_width = {0}", - btrfsSb.dev_item.optimal_width); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.minimal_size = {0}", - btrfsSb.dev_item.minimal_size); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.type = {0}", btrfsSb.dev_item.type); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.generation = {0}", btrfsSb.dev_item.generation); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.start_offset = {0}", - btrfsSb.dev_item.start_offset); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.dev_group = {0}", btrfsSb.dev_item.dev_group); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.seek_speed = {0}", btrfsSb.dev_item.seek_speed); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.bandwitdh = {0}", btrfsSb.dev_item.bandwitdh); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.device_uuid = {0}", btrfsSb.dev_item.device_uuid); - - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.uuid = {0}", btrfsSb.dev_item.uuid); - AaruConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.label = {0}", btrfsSb.label); - - sbInformation.AppendLine("B-tree filesystem"); - sbInformation.AppendFormat("UUID: {0}", btrfsSb.uuid).AppendLine(); - sbInformation.AppendFormat("This superblock resides on physical block {0}", btrfsSb.pba).AppendLine(); - sbInformation.AppendFormat("Root tree starts at LBA {0}", btrfsSb.root_lba).AppendLine(); - sbInformation.AppendFormat("Chunk tree starts at LBA {0}", btrfsSb.chunk_lba).AppendLine(); - sbInformation.AppendFormat("Log tree starts at LBA {0}", btrfsSb.log_lba).AppendLine(); - - sbInformation.AppendFormat("Volume has {0} bytes spanned in {1} devices", btrfsSb.total_bytes, - btrfsSb.num_devices).AppendLine(); - - sbInformation.AppendFormat("Volume has {0} bytes used", btrfsSb.bytes_used).AppendLine(); - sbInformation.AppendFormat("{0} bytes/sector", btrfsSb.sectorsize).AppendLine(); - sbInformation.AppendFormat("{0} bytes/node", btrfsSb.nodesize).AppendLine(); - sbInformation.AppendFormat("{0} bytes/leaf", btrfsSb.leafsize).AppendLine(); - sbInformation.AppendFormat("{0} bytes/stripe", btrfsSb.stripesize).AppendLine(); - sbInformation.AppendFormat("Flags: 0x{0:X}", btrfsSb.flags).AppendLine(); - sbInformation.AppendFormat("Compatible flags: 0x{0:X}", btrfsSb.compat_flags).AppendLine(); - sbInformation.AppendFormat("Read-only compatible flags: 0x{0:X}", btrfsSb.compat_ro_flags).AppendLine(); - sbInformation.AppendFormat("Incompatible flags: 0x{0:X}", btrfsSb.incompat_flags).AppendLine(); - sbInformation.AppendFormat("Device's UUID: {0}", btrfsSb.dev_item.uuid).AppendLine(); - sbInformation.AppendFormat("Volume label: {0}", btrfsSb.label).AppendLine(); - - information = sbInformation.ToString(); - - XmlFsType = new FileSystemType - { - Clusters = btrfsSb.total_bytes / btrfsSb.sectorsize, - ClusterSize = btrfsSb.sectorsize, - FreeClustersSpecified = true, - VolumeName = btrfsSb.label, - VolumeSerial = $"{btrfsSb.uuid}", - VolumeSetIdentifier = $"{btrfsSb.dev_item.device_uuid}", - Type = Name - }; - - XmlFsType.FreeClusters = XmlFsType.Clusters - btrfsSb.bytes_used / btrfsSb.sectorsize; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SuperBlock - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] - public readonly byte[] checksum; - public readonly Guid uuid; - public readonly ulong pba; - public readonly ulong flags; - public readonly ulong magic; - public readonly ulong generation; - public readonly ulong root_lba; - public readonly ulong chunk_lba; - public readonly ulong log_lba; - public readonly ulong log_root_transid; - public readonly ulong total_bytes; - public readonly ulong bytes_used; - public readonly ulong root_dir_objectid; - public readonly ulong num_devices; - public readonly uint sectorsize; - public readonly uint nodesize; - public readonly uint leafsize; - public readonly uint stripesize; - public readonly uint n; - public readonly ulong chunk_root_generation; - public readonly ulong compat_flags; - public readonly ulong compat_ro_flags; - public readonly ulong incompat_flags; - public readonly ushort csum_type; - public readonly byte root_level; - public readonly byte chunk_root_level; - public readonly byte log_root_level; - public readonly DevItem dev_item; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x100)] - public readonly string label; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x100)] - public readonly byte[] reserved; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x800)] - public readonly byte[] chunkpairs; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4D5)] - public readonly byte[] unused; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DevItem - { - public readonly ulong id; - public readonly ulong bytes; - public readonly ulong used; - public readonly uint optimal_align; - public readonly uint optimal_width; - public readonly uint minimal_size; - public readonly ulong type; - public readonly ulong generation; - public readonly ulong start_offset; - public readonly uint dev_group; - public readonly byte seek_speed; - public readonly byte bandwitdh; - public readonly Guid device_uuid; - public readonly Guid uuid; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/BTRFS/BTRFS.cs b/Aaru.Filesystems/BTRFS/BTRFS.cs new file mode 100644 index 000000000..dd4a8c183 --- /dev/null +++ b/Aaru.Filesystems/BTRFS/BTRFS.cs @@ -0,0 +1,56 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : BTRFS.cs +// Author(s) : Natalia Portillo +// +// Component : B-tree file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the B-tree file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the b-tree filesystem (btrfs) +public sealed partial class BTRFS : IFilesystem +{ + const string MODULE_NAME = "BTRFS Plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.BTRFS_Name; + + /// + public Guid Id => new("C904CF15-5222-446B-B7DB-02EAC5D781B3"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/BTRFS/Consts.cs b/Aaru.Filesystems/BTRFS/Consts.cs new file mode 100644 index 000000000..45307c4cf --- /dev/null +++ b/Aaru.Filesystems/BTRFS/Consts.cs @@ -0,0 +1,43 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : B-tree file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the B-tree file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the b-tree filesystem (btrfs) +public sealed partial class BTRFS +{ + /// BTRFS magic "_BHRfS_M" + const ulong BTRFS_MAGIC = 0x4D5F53665248425F; + + const string FS_TYPE = "btrfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/BTRFS/Info.cs b/Aaru.Filesystems/BTRFS/Info.cs new file mode 100644 index 000000000..d5760d86f --- /dev/null +++ b/Aaru.Filesystems/BTRFS/Info.cs @@ -0,0 +1,195 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : B-tree file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the B-tree file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the b-tree filesystem (btrfs) +public sealed partial class BTRFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start >= partition.End) return false; + + ulong sbSectorOff = 0x10000 / imagePlugin.Info.SectorSize; + uint sbSectorSize = 0x1000 / imagePlugin.Info.SectorSize; + + if(sbSectorOff + partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(sbSectorOff + partition.Start, sbSectorSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + SuperBlock btrfsSb; + + try + { + btrfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); + } + catch + { + return false; + } + + AaruConsole.DebugWriteLine(MODULE_NAME, "sbSectorOff = {0}", sbSectorOff); + AaruConsole.DebugWriteLine(MODULE_NAME, "sbSectorSize = {0}", sbSectorSize); + AaruConsole.DebugWriteLine(MODULE_NAME, "partition.PartitionStartSector = {0}", partition.Start); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.magic = 0x{0:X16}", btrfsSb.magic); + + return btrfsSb.magic == BTRFS_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + var sbInformation = new StringBuilder(); + metadata = new FileSystem(); + information = ""; + + ulong sbSectorOff = 0x10000 / imagePlugin.Info.SectorSize; + uint sbSectorSize = 0x1000 / imagePlugin.Info.SectorSize; + + ErrorNumber errno = imagePlugin.ReadSectors(sbSectorOff + partition.Start, sbSectorSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + SuperBlock btrfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.checksum = {0}", btrfsSb.checksum); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.uuid = {0}", btrfsSb.uuid); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.pba = {0}", btrfsSb.pba); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.flags = {0}", btrfsSb.flags); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.magic = {0}", btrfsSb.magic); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.generation = {0}", btrfsSb.generation); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.root_lba = {0}", btrfsSb.root_lba); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.chunk_lba = {0}", btrfsSb.chunk_lba); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.log_lba = {0}", btrfsSb.log_lba); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.log_root_transid = {0}", btrfsSb.log_root_transid); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.total_bytes = {0}", btrfsSb.total_bytes); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.bytes_used = {0}", btrfsSb.bytes_used); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.root_dir_objectid = {0}", btrfsSb.root_dir_objectid); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.num_devices = {0}", btrfsSb.num_devices); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.sectorsize = {0}", btrfsSb.sectorsize); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.nodesize = {0}", btrfsSb.nodesize); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.leafsize = {0}", btrfsSb.leafsize); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.stripesize = {0}", btrfsSb.stripesize); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.n = {0}", btrfsSb.n); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.chunk_root_generation = {0}", btrfsSb.chunk_root_generation); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.compat_flags = 0x{0:X16}", btrfsSb.compat_flags); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.compat_ro_flags = 0x{0:X16}", btrfsSb.compat_ro_flags); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.incompat_flags = 0x{0:X16}", btrfsSb.incompat_flags); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.csum_type = {0}", btrfsSb.csum_type); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.root_level = {0}", btrfsSb.root_level); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.chunk_root_level = {0}", btrfsSb.chunk_root_level); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.log_root_level = {0}", btrfsSb.log_root_level); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.id = 0x{0:X16}", btrfsSb.dev_item.id); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.bytes = {0}", btrfsSb.dev_item.bytes); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.used = {0}", btrfsSb.dev_item.used); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.optimal_align = {0}", btrfsSb.dev_item.optimal_align); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.optimal_width = {0}", btrfsSb.dev_item.optimal_width); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.minimal_size = {0}", btrfsSb.dev_item.minimal_size); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.type = {0}", btrfsSb.dev_item.type); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.generation = {0}", btrfsSb.dev_item.generation); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.start_offset = {0}", btrfsSb.dev_item.start_offset); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.dev_group = {0}", btrfsSb.dev_item.dev_group); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.seek_speed = {0}", btrfsSb.dev_item.seek_speed); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.bandwidth = {0}", btrfsSb.dev_item.bandwidth); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.device_uuid = {0}", btrfsSb.dev_item.device_uuid); + + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.uuid = {0}", btrfsSb.dev_item.uuid); + AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.label = {0}", btrfsSb.label); + + sbInformation.AppendLine(Localization.B_tree_filesystem); + sbInformation.AppendFormat(Localization.UUID_0, btrfsSb.uuid).AppendLine(); + sbInformation.AppendFormat(Localization.This_superblock_resides_on_physical_block_0, btrfsSb.pba).AppendLine(); + sbInformation.AppendFormat(Localization.Root_tree_starts_at_LBA_0, btrfsSb.root_lba).AppendLine(); + sbInformation.AppendFormat(Localization.Chunk_tree_starts_at_LBA_0, btrfsSb.chunk_lba).AppendLine(); + sbInformation.AppendFormat(Localization.Log_tree_starts_at_LBA_0, btrfsSb.log_lba).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_has_0_bytes_spanned_in_1_devices, + btrfsSb.total_bytes, + btrfsSb.num_devices) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_has_0_bytes_used, btrfsSb.bytes_used).AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_sector, btrfsSb.sectorsize).AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_node, btrfsSb.nodesize).AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_leaf, btrfsSb.leafsize).AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_stripe, btrfsSb.stripesize).AppendLine(); + sbInformation.AppendFormat(Localization.Flags_0, btrfsSb.flags).AppendLine(); + sbInformation.AppendFormat(Localization.Compatible_flags_0, btrfsSb.compat_flags).AppendLine(); + sbInformation.AppendFormat(Localization.Read_only_compatible_flags_0, btrfsSb.compat_ro_flags).AppendLine(); + sbInformation.AppendFormat(Localization.Incompatible_flags_0, btrfsSb.incompat_flags).AppendLine(); + sbInformation.AppendFormat(Localization.Device_UUID_0, btrfsSb.dev_item.uuid).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_label_0, btrfsSb.label).AppendLine(); + + information = sbInformation.ToString(); + + metadata = new FileSystem + { + Clusters = btrfsSb.total_bytes / btrfsSb.sectorsize, + ClusterSize = btrfsSb.sectorsize, + VolumeName = btrfsSb.label, + VolumeSerial = $"{btrfsSb.uuid}", + VolumeSetIdentifier = $"{btrfsSb.dev_item.device_uuid}", + Type = FS_TYPE + }; + + metadata.FreeClusters = metadata.Clusters - btrfsSb.bytes_used / btrfsSb.sectorsize; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/BTRFS/Structs.cs b/Aaru.Filesystems/BTRFS/Structs.cs new file mode 100644 index 000000000..6535f921f --- /dev/null +++ b/Aaru.Filesystems/BTRFS/Structs.cs @@ -0,0 +1,110 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : B-tree file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the B-tree file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the b-tree filesystem (btrfs) +public sealed partial class BTRFS +{ +#region Nested type: DevItem + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DevItem + { + public readonly ulong id; + public readonly ulong bytes; + public readonly ulong used; + public readonly uint optimal_align; + public readonly uint optimal_width; + public readonly uint minimal_size; + public readonly ulong type; + public readonly ulong generation; + public readonly ulong start_offset; + public readonly uint dev_group; + public readonly byte seek_speed; + public readonly byte bandwidth; + public readonly Guid device_uuid; + public readonly Guid uuid; + } + +#endregion + +#region Nested type: SuperBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SuperBlock + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public readonly byte[] checksum; + public readonly Guid uuid; + public readonly ulong pba; + public readonly ulong flags; + public readonly ulong magic; + public readonly ulong generation; + public readonly ulong root_lba; + public readonly ulong chunk_lba; + public readonly ulong log_lba; + public readonly ulong log_root_transid; + public readonly ulong total_bytes; + public readonly ulong bytes_used; + public readonly ulong root_dir_objectid; + public readonly ulong num_devices; + public readonly uint sectorsize; + public readonly uint nodesize; + public readonly uint leafsize; + public readonly uint stripesize; + public readonly uint n; + public readonly ulong chunk_root_generation; + public readonly ulong compat_flags; + public readonly ulong compat_ro_flags; + public readonly ulong incompat_flags; + public readonly ushort csum_type; + public readonly byte root_level; + public readonly byte chunk_root_level; + public readonly byte log_root_level; + public readonly DevItem dev_item; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x100)] + public readonly string label; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x100)] + public readonly byte[] reserved; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x800)] + public readonly byte[] chunkpairs; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4D5)] + public readonly byte[] unused; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/CBM.cs b/Aaru.Filesystems/CBM.cs deleted file mode 100644 index 7c08cce76..000000000 --- a/Aaru.Filesystems/CBM.cs +++ /dev/null @@ -1,265 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : CBM.cs -// Author(s) : Natalia Portillo -// -// Component : Commodore file system plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Commodore file system and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Claunia.Encoding; -using Schemas; -using Encoding = System.Text.Encoding; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the filesystem used in 8-bit Commodore microcomputers -public sealed class CBM : IFilesystem -{ - /// - public FileSystemType XmlFsType { get; private set; } - /// - public string Name => "Commodore file system"; - /// - public Guid Id => new("D104744E-A376-450C-BAC0-1347C93F983B"); - /// - public Encoding Encoding { get; private set; } - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start > 0) - return false; - - if(imagePlugin.Info.SectorSize != 256) - return false; - - if(imagePlugin.Info.Sectors != 683 && - imagePlugin.Info.Sectors != 768 && - imagePlugin.Info.Sectors != 1366 && - imagePlugin.Info.Sectors != 3200) - return false; - - byte[] sector; - - if(imagePlugin.Info.Sectors == 3200) - { - ErrorNumber errno = imagePlugin.ReadSector(1560, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - Header cbmHdr = Marshal.ByteArrayToStructureLittleEndian
(sector); - - if(cbmHdr.diskDosVersion == 0x44 && - cbmHdr.dosVersion == 0x33 && - cbmHdr.diskVersion == 0x44) - return true; - } - else - { - ErrorNumber errno = imagePlugin.ReadSector(357, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - BAM cbmBam = Marshal.ByteArrayToStructureLittleEndian(sector); - - if(cbmBam.dosVersion == 0x41 && - cbmBam.doubleSided is 0x00 or 0x80 && - cbmBam.unused1 == 0x00 && - cbmBam.directoryTrack == 0x12) - return true; - } - - return false; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = new PETSCII(); - information = ""; - byte[] sector; - - var sbInformation = new StringBuilder(); - - sbInformation.AppendLine("Commodore file system"); - - XmlFsType = new FileSystemType - { - Type = "Commodore file system", - Clusters = imagePlugin.Info.Sectors, - ClusterSize = 256 - }; - - if(imagePlugin.Info.Sectors == 3200) - { - ErrorNumber errno = imagePlugin.ReadSector(1560, out sector); - - if(errno != ErrorNumber.NoError) - return; - - Header cbmHdr = Marshal.ByteArrayToStructureLittleEndian
(sector); - - sbInformation.AppendFormat("Directory starts at track {0} sector {1}", cbmHdr.directoryTrack, - cbmHdr.directorySector).AppendLine(); - - sbInformation.AppendFormat("Disk DOS Version: {0}", Encoding.ASCII.GetString(new[] - { - cbmHdr.diskDosVersion - })).AppendLine(); - - sbInformation.AppendFormat("DOS Version: {0}", Encoding.ASCII.GetString(new[] - { - cbmHdr.dosVersion - })).AppendLine(); - - sbInformation.AppendFormat("Disk Version: {0}", Encoding.ASCII.GetString(new[] - { - cbmHdr.diskVersion - })).AppendLine(); - - sbInformation.AppendFormat("Disk ID: {0}", cbmHdr.diskId).AppendLine(); - - sbInformation.AppendFormat("Disk name: {0}", StringHandlers.CToString(cbmHdr.name, Encoding)).AppendLine(); - - XmlFsType.VolumeName = StringHandlers.CToString(cbmHdr.name, Encoding); - XmlFsType.VolumeSerial = $"{cbmHdr.diskId}"; - } - else - { - ErrorNumber errno = imagePlugin.ReadSector(357, out sector); - - if(errno != ErrorNumber.NoError) - return; - - BAM cbmBam = Marshal.ByteArrayToStructureLittleEndian(sector); - - sbInformation.AppendFormat("Directory starts at track {0} sector {1}", cbmBam.directoryTrack, - cbmBam.directorySector).AppendLine(); - - sbInformation.AppendFormat("Disk DOS type: {0}", - Encoding.ASCII.GetString(BitConverter.GetBytes(cbmBam.dosType))).AppendLine(); - - sbInformation.AppendFormat("DOS Version: {0}", Encoding.ASCII.GetString(new[] - { - cbmBam.dosVersion - })).AppendLine(); - - sbInformation.AppendFormat("Disk ID: {0}", cbmBam.diskId).AppendLine(); - - sbInformation.AppendFormat("Disk name: {0}", StringHandlers.CToString(cbmBam.name, Encoding)).AppendLine(); - - XmlFsType.VolumeName = StringHandlers.CToString(cbmBam.name, Encoding); - XmlFsType.VolumeSerial = $"{cbmBam.diskId}"; - } - - information = sbInformation.ToString(); - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct BAM - { - /// Track where directory starts - public readonly byte directoryTrack; - /// Sector where directory starts - public readonly byte directorySector; - /// Disk DOS version, 0x41 - public readonly byte dosVersion; - /// Set to 0x80 if 1571, 0x00 if not - public readonly byte doubleSided; - /// Block allocation map - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 140)] - public readonly byte[] bam; - /// Disk name - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] name; - /// Filled with 0xA0 - public readonly ushort fill1; - /// Disk ID - public readonly ushort diskId; - /// Filled with 0xA0 - public readonly byte fill2; - /// DOS type - public readonly ushort dosType; - /// Filled with 0xA0 - public readonly uint fill3; - /// Unused - public readonly byte unused1; - /// Block allocation map for Dolphin DOS extended tracks - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public readonly byte[] dolphinBam; - /// Block allocation map for Speed DOS extended tracks - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public readonly byte[] speedBam; - /// Unused - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] - public readonly byte[] unused2; - /// Free sector count for second side in 1571 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] - public readonly byte[] freeCount; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Header - { - /// Track where directory starts - public readonly byte directoryTrack; - /// Sector where directory starts - public readonly byte directorySector; - /// Disk DOS version, 0x44 - public readonly byte diskDosVersion; - /// Unusued - public readonly byte unused1; - /// Disk name - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] name; - /// Filled with 0xA0 - public readonly ushort fill1; - /// Disk ID - public readonly ushort diskId; - /// Filled with 0xA0 - public readonly byte fill2; - /// DOS version ('3') - public readonly byte dosVersion; - /// Disk version ('D') - public readonly byte diskVersion; - /// Filled with 0xA0 - public readonly short fill3; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/CBM/CBM.cs b/Aaru.Filesystems/CBM/CBM.cs new file mode 100644 index 000000000..18b48a95f --- /dev/null +++ b/Aaru.Filesystems/CBM/CBM.cs @@ -0,0 +1,108 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CBM.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.CommonTypes.Structs; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used in 8-bit Commodore microcomputers +public sealed partial class CBM : IReadOnlyFilesystem +{ + byte[] _bam; + Dictionary _cache; + bool _debug; + byte[] _diskHeader; + bool _is1581; + bool _mounted; + byte[] _root; + FileSystemInfo _statfs; + +#region IReadOnlyFilesystem Members + + /// + public string Name => Localization.CBM_Name; + + /// + public Guid Id => new("D104744E-A376-450C-BAC0-1347C93F983B"); + + /// + public string Author => Authors.NataliaPortillo; + + /// + public ErrorNumber ListXAttr(string path, out List xattrs) + { + xattrs = null; + + return ErrorNumber.NotSupported; + } + + /// + public ErrorNumber GetXattr(string path, string xattr, ref byte[] buf) => ErrorNumber.NotSupported; + + /// + public ErrorNumber ReadLink(string path, out string dest) + { + dest = null; + + return ErrorNumber.NotSupported; + } + + /// + public FileSystem Metadata { get; private set; } + + /// + public IEnumerable<(string name, Type type, string description)> SupportedOptions => + Array.Empty<(string name, Type type, string description)>(); + + /// + public Dictionary Namespaces => null; + +#endregion + + static Dictionary GetDefaultOptions() => new() + { + { + "debug", false.ToString() + } + }; + + ulong CbmChsToLba(byte track, byte sector, bool is1581) + { + if(track is 0 or > 40) return 0; + + if(is1581) return (ulong)((track - 1) * 40 + sector - 1); + + return trackStartingLbas[track - 1] + sector; + } +} \ No newline at end of file diff --git a/Aaru.Filesystems/CBM/Consts.cs b/Aaru.Filesystems/CBM/Consts.cs new file mode 100644 index 000000000..ceb8f37d7 --- /dev/null +++ b/Aaru.Filesystems/CBM/Consts.cs @@ -0,0 +1,42 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used in 8-bit Commodore microcomputers +public sealed partial class CBM +{ + const string FS_TYPE = "cbmfs"; + + readonly ulong[] trackStartingLbas = + [ + 0, 21, 42, 63, 84, 105, 126, 147, 168, 189, 210, 231, 252, 273, 294, 315, 336, 357, 376, 395, 414, 433, 452, + 471, 490, 508, 526, 544, 562, 580, 598, 615, 632, 649, 666, 683, 700, 717, 734, 751 + ]; +} \ No newline at end of file diff --git a/Aaru.Filesystems/CBM/Dir.cs b/Aaru.Filesystems/CBM/Dir.cs new file mode 100644 index 000000000..d5da83ee0 --- /dev/null +++ b/Aaru.Filesystems/CBM/Dir.cs @@ -0,0 +1,96 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CBM.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Linq; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used in 8-bit Commodore microcomputers +public sealed partial class CBM +{ +#region IReadOnlyFilesystem Members + + /// + public ErrorNumber OpenDir(string path, out IDirNode node) + { + node = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(!string.IsNullOrEmpty(path) && string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) + return ErrorNumber.NotSupported; + + var contents = _cache.Keys.ToList(); + + contents.Sort(); + + node = new CbmDirNode + { + Path = path, + Position = 0, + Contents = contents.ToArray() + }; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not CbmDirNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Position = -1; + mynode.Contents = null; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) + { + filename = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not CbmDirNode mynode) return ErrorNumber.InvalidArgument; + + if(mynode.Position < 0) return ErrorNumber.InvalidArgument; + + if(mynode.Position >= mynode.Contents.Length) return ErrorNumber.NoError; + + filename = mynode.Contents[mynode.Position++]; + + return ErrorNumber.NoError; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/CBM/File.cs b/Aaru.Filesystems/CBM/File.cs new file mode 100644 index 000000000..803174118 --- /dev/null +++ b/Aaru.Filesystems/CBM/File.cs @@ -0,0 +1,167 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CBM.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.CommonTypes.Structs; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used in 8-bit Commodore microcomputers +public sealed partial class CBM +{ +#region IReadOnlyFilesystem Members + + /// + public ErrorNumber GetAttributes(string path, out FileAttributes attributes) + { + attributes = new FileAttributes(); + + if(!_mounted) return ErrorNumber.AccessDenied; + + string[] pathElements = path.Split(new[] + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); + + if(pathElements.Length != 1) return ErrorNumber.NotSupported; + + string filename = pathElements[0].ToUpperInvariant(); + + if(!_cache.TryGetValue(filename, out CachedFile file)) return ErrorNumber.NoSuchFile; + + attributes = file.attributes; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber Stat(string path, out FileEntryInfo stat) + { + stat = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + string[] pathElements = path.Split(new[] + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); + + if(pathElements.Length != 1) return ErrorNumber.NotSupported; + + string filename = pathElements[0].ToUpperInvariant(); + + if(filename.Length > 14) return ErrorNumber.NameTooLong; + + if(!_cache.TryGetValue(filename, out CachedFile file)) return ErrorNumber.NoSuchFile; + + stat = new FileEntryInfo + { + Attributes = file.attributes, + BlockSize = 256, + Length = (long)file.length, + Blocks = file.blocks, + Inode = file.id, + Links = 1 + }; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber OpenFile(string path, out IFileNode node) + { + node = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + string[] pathElements = path.Split(new[] + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); + + if(pathElements.Length != 1) return ErrorNumber.NotSupported; + + string filename = pathElements[0].ToUpperInvariant(); + + if(filename.Length > 14) return ErrorNumber.NameTooLong; + + if(!_cache.TryGetValue(filename, out CachedFile file)) return ErrorNumber.NoSuchFile; + + node = new CbmFileNode + { + Path = path, + Length = (long)file.length, + Offset = 0, + Cache = file.data + }; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseFile(IFileNode node) + { + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not CbmFileNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Cache = null; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(buffer is null || buffer.Length < length) return ErrorNumber.InvalidArgument; + + if(node is not CbmFileNode mynode) return ErrorNumber.InvalidArgument; + + read = length; + + if(length + mynode.Offset >= mynode.Length) read = mynode.Length - mynode.Offset; + + Array.Copy(mynode.Cache, mynode.Offset, buffer, 0, read); + + mynode.Offset += read; + + return ErrorNumber.NoError; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/CBM/Info.cs b/Aaru.Filesystems/CBM/Info.cs new file mode 100644 index 000000000..bb655e0da --- /dev/null +++ b/Aaru.Filesystems/CBM/Info.cs @@ -0,0 +1,185 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Claunia.Encoding; +using Encoding = System.Text.Encoding; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used in 8-bit Commodore microcomputers +public sealed partial class CBM +{ +#region IReadOnlyFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start > 0) return false; + + if(imagePlugin.Info.SectorSize != 256) return false; + + if(imagePlugin.Info.Sectors != 683 && + imagePlugin.Info.Sectors != 768 && + imagePlugin.Info.Sectors != 1366 && + imagePlugin.Info.Sectors != 3200) + return false; + + byte[] sector; + + if(imagePlugin.Info.Sectors == 3200) + { + ErrorNumber errno = imagePlugin.ReadSector(1560, out sector); + + if(errno != ErrorNumber.NoError) return false; + + Header cbmHdr = Marshal.ByteArrayToStructureLittleEndian
(sector); + + if(cbmHdr.diskDosVersion == 0x44 && cbmHdr is { dosVersion: 0x33, diskVersion: 0x44 }) return true; + } + else + { + ErrorNumber errno = imagePlugin.ReadSector(357, out sector); + + if(errno != ErrorNumber.NoError) return false; + + BAM cbmBam = Marshal.ByteArrayToStructureLittleEndian(sector); + + if(cbmBam is { dosVersion: 0x41, doubleSided: 0x00 or 0x80 } and { unused1: 0x00, directoryTrack: 0x12 }) + return true; + } + + return false; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding = new PETSCII(); + information = ""; + byte[] sector; + + var sbInformation = new StringBuilder(); + + sbInformation.AppendLine(Localization.Commodore_file_system); + + metadata = new FileSystem + { + Type = FS_TYPE, + Clusters = imagePlugin.Info.Sectors, + ClusterSize = 256 + }; + + if(imagePlugin.Info.Sectors == 3200) + { + ErrorNumber errno = imagePlugin.ReadSector(1560, out sector); + + if(errno != ErrorNumber.NoError) return; + + Header cbmHdr = Marshal.ByteArrayToStructureLittleEndian
(sector); + + sbInformation.AppendFormat(Localization.Directory_starts_at_track_0_sector_1, + cbmHdr.directoryTrack, + cbmHdr.directorySector) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Disk_DOS_Version_0, + Encoding.ASCII.GetString(new[] + { + cbmHdr.diskDosVersion + })) + .AppendLine(); + + sbInformation.AppendFormat(Localization.DOS_Version_0, + Encoding.ASCII.GetString(new[] + { + cbmHdr.dosVersion + })) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Disk_Version_0, + Encoding.ASCII.GetString(new[] + { + cbmHdr.diskVersion + })) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Disk_ID_0, cbmHdr.diskId).AppendLine(); + + sbInformation.AppendFormat(Localization.Disk_name_0, StringHandlers.CToString(cbmHdr.name, encoding)) + .AppendLine(); + + metadata.VolumeName = StringHandlers.CToString(cbmHdr.name, encoding); + metadata.VolumeSerial = $"{cbmHdr.diskId}"; + } + else + { + ErrorNumber errno = imagePlugin.ReadSector(357, out sector); + + if(errno != ErrorNumber.NoError) return; + + BAM cbmBam = Marshal.ByteArrayToStructureLittleEndian(sector); + + sbInformation.AppendFormat(Localization.Directory_starts_at_track_0_sector_1, + cbmBam.directoryTrack, + cbmBam.directorySector) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Disk_DOS_type_0, + Encoding.ASCII.GetString(BitConverter.GetBytes(cbmBam.dosType))) + .AppendLine(); + + sbInformation.AppendFormat(Localization.DOS_Version_0, + Encoding.ASCII.GetString(new[] + { + cbmBam.dosVersion + })) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Disk_ID_0, cbmBam.diskId).AppendLine(); + + sbInformation.AppendFormat(Localization.Disk_name_0, StringHandlers.CToString(cbmBam.name, encoding)) + .AppendLine(); + + metadata.VolumeName = StringHandlers.CToString(cbmBam.name, encoding); + metadata.VolumeSerial = $"{cbmBam.diskId}"; + } + + information = sbInformation.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/CBM/Structs.cs b/Aaru.Filesystems/CBM/Structs.cs new file mode 100644 index 000000000..120478f8e --- /dev/null +++ b/Aaru.Filesystems/CBM/Structs.cs @@ -0,0 +1,192 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; +using Aaru.CommonTypes.Interfaces; +using Aaru.CommonTypes.Structs; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used in 8-bit Commodore microcomputers +public sealed partial class CBM +{ +#region Nested type: BAM + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct BAM + { + /// Track where directory starts + public readonly byte directoryTrack; + /// Sector where directory starts + public readonly byte directorySector; + /// Disk DOS version, 0x41 + public readonly byte dosVersion; + /// Set to 0x80 if 1571, 0x00 if not + public readonly byte doubleSided; + /// Block allocation map + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 140)] + public readonly byte[] bam; + /// Disk name + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] name; + /// Filled with 0xA0 + public readonly ushort fill1; + /// Disk ID + public readonly ushort diskId; + /// Filled with 0xA0 + public readonly byte fill2; + /// DOS type + public readonly ushort dosType; + /// Filled with 0xA0 + public readonly uint fill3; + /// Unused + public readonly byte unused1; + /// Block allocation map for Dolphin DOS extended tracks + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public readonly byte[] dolphinBam; + /// Block allocation map for Speed DOS extended tracks + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public readonly byte[] speedBam; + /// Unused + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] + public readonly byte[] unused2; + /// Free sector count for second side in 1571 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] + public readonly byte[] freeCount; + } + +#endregion + +#region Nested type: CachedFile + + struct CachedFile + { + public byte[] data; + public ulong length; + public FileAttributes attributes; + public int blocks; + public ulong id; + } + +#endregion + +#region Nested type: CbmDirNode + + sealed class CbmDirNode : IDirNode + { + internal string[] Contents; + internal int Position; + +#region IDirNode Members + + /// + public string Path { get; init; } + +#endregion + } + +#endregion + +#region Nested type: CbmFileNode + + sealed class CbmFileNode : IFileNode + { + internal byte[] Cache; + +#region IFileNode Members + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + +#endregion + } + +#endregion + +#region Nested type: DirectoryEntry + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DirectoryEntry + { + public readonly byte nextDirBlockTrack; + public readonly byte nextDirBlockSector; + public readonly byte fileType; + public readonly byte firstFileBlockTrack; + public readonly byte firstFileBlockSector; + /// Filename + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] name; + public readonly byte firstSideBlockTrack; + public readonly byte firstSideBlockSector; + public readonly uint unused; + public readonly byte replacementTrack; + public readonly byte replacementSector; + public readonly short blocks; + } + +#endregion + +#region Nested type: Header + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Header + { + /// Track where directory starts + public readonly byte directoryTrack; + /// Sector where directory starts + public readonly byte directorySector; + /// Disk DOS version, 0x44 + public readonly byte diskDosVersion; + /// Unusued + public readonly byte unused1; + /// Disk name + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] name; + /// Filled with 0xA0 + public readonly ushort fill1; + /// Disk ID + public readonly ushort diskId; + /// Filled with 0xA0 + public readonly byte fill2; + /// DOS version ('3') + public readonly byte dosVersion; + /// Disk version ('D') + public readonly byte diskVersion; + /// Filled with 0xA0 + public readonly short fill3; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/CBM/Super.cs b/Aaru.Filesystems/CBM/Super.cs new file mode 100644 index 000000000..8f6179d79 --- /dev/null +++ b/Aaru.Filesystems/CBM/Super.cs @@ -0,0 +1,325 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : CBM.cs +// Author(s) : Natalia Portillo +// +// Component : Commodore file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.CommonTypes.Structs; +using Aaru.Console; +using Aaru.Helpers; +using Claunia.Encoding; +using Encoding = System.Text.Encoding; +using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes; +using FileSystemInfo = Aaru.CommonTypes.Structs.FileSystemInfo; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used in 8-bit Commodore microcomputers +public sealed partial class CBM +{ +#region IReadOnlyFilesystem Members + + /// + public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace) + { + if(partition.Start > 0) return ErrorNumber.InvalidArgument; + + if(imagePlugin.Info.SectorSize != 256) return ErrorNumber.InvalidArgument; + + if(imagePlugin.Info.Sectors != 683 && + imagePlugin.Info.Sectors != 768 && + imagePlugin.Info.Sectors != 1366 && + imagePlugin.Info.Sectors != 3200) + return ErrorNumber.InvalidArgument; + + options ??= GetDefaultOptions(); + + if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out _debug); + + encoding = new PETSCII(); + byte[] sector; + ulong rootLba; + string volumeName = null; + + Metadata = new FileSystem + { + Type = FS_TYPE, + Clusters = imagePlugin.Info.Sectors, + ClusterSize = 256 + }; + + uint serial; + + // Commodore 1581 + if(imagePlugin.Info.Sectors == 3200) + { + ErrorNumber errno = imagePlugin.ReadSector(1560, out _diskHeader); + + if(errno != ErrorNumber.NoError) return errno; + + Header cbmHdr = Marshal.ByteArrayToStructureBigEndian
(_diskHeader); + + if(cbmHdr.diskDosVersion != 0x44 || cbmHdr is not { dosVersion: 0x33, diskVersion: 0x44 }) + return ErrorNumber.InvalidArgument; + + _bam = new byte[512]; + + // Got to first BAM sector + errno = imagePlugin.ReadSector(1561, out sector); + + if(errno != ErrorNumber.NoError) return errno; + + Array.Copy(sector, 0, _bam, 0, 256); + + if(_bam[0] > 0) + { + // Got to next (and last) BAM sector + errno = imagePlugin.ReadSector((ulong)((_bam[0] - 1) * 40), out sector); + + if(errno != ErrorNumber.NoError) return errno; + + Array.Copy(sector, 0, _bam, 256, 256); + } + + if(cbmHdr.directoryTrack == 0) return ErrorNumber.InvalidArgument; + + rootLba = CbmChsToLba(cbmHdr.directoryTrack, cbmHdr.directorySector, true); + serial = cbmHdr.diskId; + Metadata.VolumeName = StringHandlers.CToString(cbmHdr.name, encoding); + Metadata.VolumeSerial = $"{cbmHdr.diskId}"; + _is1581 = true; + } + else + { + ErrorNumber errno = imagePlugin.ReadSector(357, out _bam); + + if(errno != ErrorNumber.NoError) return errno; + + BAM cbmBam = Marshal.ByteArrayToStructureBigEndian(_bam); + + if(cbmBam is not ({ dosVersion: 0x41, doubleSided : 0x00 or 0x80 } + and { unused1 : 0x00, directoryTrack: 0x12 })) + return ErrorNumber.InvalidArgument; + + rootLba = CbmChsToLba(cbmBam.directoryTrack, cbmBam.directorySector, false); + serial = cbmBam.diskId; + + Metadata.VolumeName = StringHandlers.CToString(cbmBam.name, encoding); + Metadata.VolumeSerial = $"{cbmBam.diskId}"; + } + + if(rootLba >= imagePlugin.Info.Sectors) return ErrorNumber.IllegalSeek; + + ulong nextLba = rootLba; + var rootMs = new MemoryStream(); + var relativeFileWarningShown = false; + + do + { + ErrorNumber errno = imagePlugin.ReadSector(nextLba, out sector); + + if(errno != ErrorNumber.NoError) return errno; + + rootMs.Write(sector, 0, 256); + + if(sector[0] == 0) break; + + nextLba = CbmChsToLba(sector[0], sector[1], _is1581); + } while(nextLba > 0); + + _root = rootMs.ToArray(); + + _statfs = new FileSystemInfo + { + Blocks = imagePlugin.Info.Sectors, + FilenameLength = 14, + Files = 0, + FreeBlocks = + imagePlugin.Info.Sectors - + (ulong)(_diskHeader?.Length ?? 0 / 256 - _bam.Length / 256 - _root.Length / 256), + FreeFiles = (ulong)(_root.Length / 32), + Id = new FileSystemId + { + Serial32 = serial, + IsInt = true + }, + PluginId = Id, + Type = "CBMFS" + }; + + // As this filesystem comes in (by nowadays standards) very small sizes, we can cache all files + _cache = new Dictionary(); + var offset = 0; + ulong fileId = 0; + + if(_debug) + { + // Root + _cache.Add("$", + new CachedFile + { + attributes = FileAttributes.Directory | FileAttributes.Hidden | FileAttributes.System, + length = (ulong)_root.Length, + data = _root, + blocks = _root.Length / 256, + id = fileId++ + }); + + // BAM + _cache.Add("$BAM", + new CachedFile + { + attributes = FileAttributes.File | FileAttributes.Hidden | FileAttributes.System, + length = (ulong)_bam.Length, + data = _bam, + blocks = _bam.Length / 256, + id = fileId++ + }); + + _statfs.Files += 2; + + // 1581 disk header + if(_diskHeader != null) + { + _cache.Add("$DISK_HEADER", + new CachedFile + { + attributes = FileAttributes.File | FileAttributes.Hidden | FileAttributes.System, + length = (ulong)_diskHeader.Length, + data = _diskHeader, + blocks = _diskHeader.Length / 256, + id = fileId++ + }); + + _statfs.Files++; + } + } + + while(offset < _root.Length) + { + DirectoryEntry dirEntry = Marshal.ByteArrayToStructureBigEndian(_root, offset, 32); + + if(dirEntry.fileType == 0) + { + offset += 32; + + continue; + } + + _statfs.Files++; + _statfs.FreeFiles--; + + for(var i = 0; i < dirEntry.name.Length; i++) + if(dirEntry.name[i] == 0xA0) + dirEntry.name[i] = 0; + + string name = StringHandlers.CToString(dirEntry.name, encoding); + + if((dirEntry.fileType & 0x07) == 4 && !relativeFileWarningShown) + { + AaruConsole.WriteLine(Localization.CBM_Mount_REL_file_warning); + relativeFileWarningShown = true; + } + + var data = new MemoryStream(); + + nextLba = CbmChsToLba(dirEntry.firstFileBlockTrack, dirEntry.firstFileBlockSector, _is1581); + + _statfs.FreeBlocks -= (ulong)dirEntry.blocks; + + while(dirEntry.blocks > 0) + { + if(dirEntry.firstFileBlockTrack == 0) break; + + ErrorNumber errno = imagePlugin.ReadSector(nextLba, out sector); + + if(errno != ErrorNumber.NoError) break; + + byte toRead = sector[0] == 0 ? sector[1] : (byte)254; + if(toRead == 255) toRead--; + + data.Write(sector, 2, toRead); + + if(sector[0] == 0) break; + + nextLba = CbmChsToLba(sector[0], sector[1], _is1581); + } + + FileAttributes attributes = FileAttributes.File; + + if((dirEntry.fileType & 0x80) != 0x80) attributes |= FileAttributes.Open; + if((dirEntry.fileType & 0x40) > 0) attributes |= FileAttributes.ReadOnly; + if((dirEntry.fileType & 7) == 2) attributes |= FileAttributes.Executable; + + _cache[name] = new CachedFile + { + attributes = attributes, + length = (ulong)data.Length, + data = data.ToArray(), + blocks = dirEntry.blocks, + id = fileId++ + }; + + offset += 32; + } + + _mounted = true; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber Unmount() + { + if(!_mounted) return ErrorNumber.AccessDenied; + + _mounted = false; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber StatFs(out FileSystemInfo stat) + { + stat = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + stat = _statfs.ShallowCopy(); + + return ErrorNumber.NoError; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/CPM/CPM.cs b/Aaru.Filesystems/CPM/CPM.cs index 88439ec7d..7bddd0497 100644 --- a/Aaru.Filesystems/CPM/CPM.cs +++ b/Aaru.Filesystems/CPM/CPM.cs @@ -27,22 +27,23 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Text; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; -using Schemas; + +namespace Aaru.Filesystems; /// /// Implements the CP/M filesystem public sealed partial class CPM : IReadOnlyFilesystem { + const string MODULE_NAME = "CP/M Plugin"; /// True if thinks this is a CP/M filesystem bool _cpmFound; @@ -59,6 +60,7 @@ public sealed partial class CPM : IReadOnlyFilesystem List _dirList; /// CP/M disc parameter block (on-memory) DiscParameterBlock _dpb; + Encoding _encoding; /// Cached file data Dictionary _fileCache; /// The volume label, if the CP/M filesystem contains one @@ -81,16 +83,19 @@ public sealed partial class CPM : IReadOnlyFilesystem /// If thinks this is a CP/M filesystem, this is the definition for it CpmDefinition _workingDefinition; +#region IReadOnlyFilesystem Members + /// - public FileSystemType XmlFsType { get; private set; } + public FileSystem Metadata { get; private set; } + /// - public Encoding Encoding { get; private set; } - /// - public string Name => "CP/M File System"; + public string Name => Localization.CPM_Name; + /// public Guid Id => new("AA2B8585-41DF-4E3B-8A35-D1A935E2F8A1"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public IEnumerable<(string name, Type type, string description)> SupportedOptions => @@ -98,4 +103,6 @@ public sealed partial class CPM : IReadOnlyFilesystem /// public Dictionary Namespaces => null; + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/CPM/Consts.cs b/Aaru.Filesystems/CPM/Consts.cs index a021bf068..bf336f203 100644 --- a/Aaru.Filesystems/CPM/Consts.cs +++ b/Aaru.Filesystems/CPM/Consts.cs @@ -27,7 +27,7 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // ReSharper disable InconsistentNaming @@ -36,6 +36,11 @@ namespace Aaru.Filesystems; public sealed partial class CPM { + // Do not translate + const string FS_TYPE = "cpmfs"; + +#region Nested type: FormatByte + /// Enumerates the format identification byte used by CP/M-86 enum FormatByte : byte { @@ -60,4 +65,6 @@ public sealed partial class CPM /// 3.5" double-density double-side 9 sectors/track k720Alt = 0x94 } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/CPM/Definitions.cs b/Aaru.Filesystems/CPM/Definitions.cs index 2793dcdee..19d62a974 100644 --- a/Aaru.Filesystems/CPM/Definitions.cs +++ b/Aaru.Filesystems/CPM/Definitions.cs @@ -27,37 +27,35 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; -using System.Xml; -using System.Xml.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Aaru.Filesystems; public sealed partial class CPM { - /// Loads all the known CP/M disk definitions from an XML stored as an embedded resource. + /// Loads all the known CP/M disk definitions from an JSON stored as an embedded resource. /// The definitions. bool LoadDefinitions() { try { - var defsReader = - XmlReader.Create(Assembly.GetExecutingAssembly(). - GetManifestResourceStream("Aaru.Filesystems.CPM.cpmdefs.xml") ?? - new MemoryStream()); + _definitions = + JsonSerializer.Deserialize(Assembly.GetExecutingAssembly() + .GetManifestResourceStream("Aaru.Filesystems.CPM.cpmdefs.json") ?? + new MemoryStream(), + typeof(CpmDefinitions), + CpmDefinitionsContext.Default) as CpmDefinitions; - var defsSerializer = new XmlSerializer(typeof(CpmDefinitions)); - _definitions = (CpmDefinitions)defsSerializer.Deserialize(defsReader); - - if(_definitions is null) - return false; + if(_definitions is null) return false; // Patch definitions foreach(CpmDefinition def in _definitions.definitions) @@ -70,13 +68,10 @@ public sealed partial class CPM sectorIds = new int[def.sectorsPerTrack] }; - for(var i = 0; i < def.sectorsPerTrack; i++) - def.side1.sectorIds[i] = i + 1; + for(var i = 0; i < def.sectorsPerTrack; i++) def.side1.sectorIds[i] = i + 1; } - if(def.sides != 2 || - def.side2 != null) - continue; + if(def.sides != 2 || def.side2 != null) continue; { def.side2 = new Side @@ -85,8 +80,7 @@ public sealed partial class CPM sectorIds = new int[def.sectorsPerTrack] }; - for(var i = 0; i < def.sectorsPerTrack; i++) - def.side2.sectorIds[i] = i + 1; + for(var i = 0; i < def.sectorsPerTrack; i++) def.side2.sectorIds[i] = i + 1; } } @@ -99,6 +93,14 @@ public sealed partial class CPM } } +[JsonSourceGenerationOptions(WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + IncludeFields = true)] +[JsonSerializable(typeof(CpmDefinitions))] + +// ReSharper disable once PartialTypeWithSinglePart +public partial class CpmDefinitionsContext : JsonSerializerContext; + /// CP/M disk definitions [SuppressMessage("ReSharper", "InconsistentNaming")] public sealed class CpmDefinitions diff --git a/Aaru.Filesystems/CPM/Dir.cs b/Aaru.Filesystems/CPM/Dir.cs index ef072e81e..acbe503c6 100644 --- a/Aaru.Filesystems/CPM/Dir.cs +++ b/Aaru.Filesystems/CPM/Dir.cs @@ -27,36 +27,72 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System; +using System.Text; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; + namespace Aaru.Filesystems; -using System; -using System.Collections.Generic; -using System.Text; -using Aaru.CommonTypes.Enums; -using Aaru.Helpers; - public sealed partial class CPM { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber ReadDir(string path, out List contents) + public ErrorNumber OpenDir(string path, out IDirNode node) { - contents = null; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - if(!string.IsNullOrEmpty(path) && - string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) + if(!string.IsNullOrEmpty(path) && string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) return ErrorNumber.NotSupported; - contents = new List(_dirList); + node = new CpmDirNode + { + Path = path, + Position = 0, + Contents = _dirList.ToArray() + }; return ErrorNumber.NoError; } + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) + { + filename = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not CpmDirNode mynode) return ErrorNumber.InvalidArgument; + + if(mynode.Position < 0) return ErrorNumber.InvalidArgument; + + if(mynode.Position >= mynode.Contents.Length) return ErrorNumber.NoError; + + filename = mynode.Contents[mynode.Position++]; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not CpmDirNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Position = -1; + mynode.Contents = null; + + return ErrorNumber.NoError; + } + +#endregion + /// /// Checks that the given directory blocks follow the CP/M filesystem directory specification Corrupted /// directories will fail. FAT directories will false positive if all files start with 0x05, and do not use full @@ -68,8 +104,7 @@ public sealed partial class CPM { try { - if(directory == null) - return false; + if(directory == null) return false; var fileCount = 0; @@ -80,41 +115,47 @@ public sealed partial class CPM if((entry.statusUser & 0x7F) < 0x20) { for(var f = 0; f < 8; f++) - if(entry.filename[f] < 0x20 && - entry.filename[f] != 0x00) + if(entry.filename[f] < 0x20 && entry.filename[f] != 0x00) return false; for(var e = 0; e < 3; e++) - if(entry.extension[e] < 0x20 && - entry.extension[e] != 0x00) + if(entry.extension[e] < 0x20 && entry.extension[e] != 0x00) return false; - if(!ArrayHelpers.ArrayIsNullOrWhiteSpace(entry.filename)) - fileCount++; + if(!ArrayHelpers.ArrayIsNullOrWhiteSpace(entry.filename)) fileCount++; } - else if(entry.statusUser == 0x20) + else { - for(var f = 0; f < 8; f++) - if(entry.filename[f] < 0x20 && - entry.filename[f] != 0x00) - return false; + switch(entry.statusUser) + { + case 0x20: + { + for(var f = 0; f < 8; f++) + if(entry.filename[f] < 0x20 && entry.filename[f] != 0x00) + return false; - for(var e = 0; e < 3; e++) - if(entry.extension[e] < 0x20 && - entry.extension[e] != 0x00) - return false; + for(var e = 0; e < 3; e++) + if(entry.extension[e] < 0x20 && entry.extension[e] != 0x00) + return false; - _label = Encoding.ASCII.GetString(directory, off + 1, 11).Trim(); - _labelCreationDate = new byte[4]; - _labelUpdateDate = new byte[4]; - Array.Copy(directory, off + 24, _labelCreationDate, 0, 4); - Array.Copy(directory, off + 28, _labelUpdateDate, 0, 4); + _label = Encoding.ASCII.GetString(directory, off + 1, 11).Trim(); + _labelCreationDate = new byte[4]; + _labelUpdateDate = new byte[4]; + Array.Copy(directory, off + 24, _labelCreationDate, 0, 4); + Array.Copy(directory, off + 28, _labelUpdateDate, 0, 4); + + break; + } + case 0x21 when directory[off + 1] == 0x00: + _thirdPartyTimestamps = true; + + break; + case 0x21: + _standardTimestamps |= directory[off + 21] == 0x00 && directory[off + 31] == 0x00; + + break; + } } - else if(entry.statusUser == 0x21) - if(directory[off + 1] == 0x00) - _thirdPartyTimestamps = true; - else - _standardTimestamps |= directory[off + 21] == 0x00 && directory[off + 31] == 0x00; } return fileCount > 0; diff --git a/Aaru.Filesystems/CPM/File.cs b/Aaru.Filesystems/CPM/File.cs index b858b4203..a769da4a5 100644 --- a/Aaru.Filesystems/CPM/File.cs +++ b/Aaru.Filesystems/CPM/File.cs @@ -7,10 +7,6 @@ // // Component : CP/M filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle files. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,33 +23,35 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class CPM { +#region IReadOnlyFilesystem Members + /// public ErrorNumber GetAttributes(string path, out FileAttributes attributes) { attributes = new FileAttributes(); - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; if(string.IsNullOrEmpty(pathElements[0]) || string.Compare(pathElements[0], "/", StringComparison.OrdinalIgnoreCase) == 0) @@ -72,50 +70,64 @@ public sealed partial class CPM return ErrorNumber.NoError; } - // TODO: Implementing this would require storing the interleaving /// - public ErrorNumber MapBlock(string path, long fileBlock, out long deviceBlock) + public ErrorNumber OpenFile(string path, out IFileNode node) { - deviceBlock = 0; + node = null; - return !_mounted ? ErrorNumber.AccessDenied : ErrorNumber.NotImplemented; + if(!_mounted) return ErrorNumber.AccessDenied; + + string[] pathElements = path.Split(new[] + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); + + if(pathElements.Length != 1) return ErrorNumber.NotSupported; + + if(!_fileCache.TryGetValue(pathElements[0].ToUpperInvariant(), out byte[] file)) return ErrorNumber.NoSuchFile; + + node = new CpmFileNode + { + Path = path, + Length = file.Length, + Offset = 0, + Cache = file + }; + + return ErrorNumber.NoError; } /// - public ErrorNumber Read(string path, long offset, long size, ref byte[] buf) + public ErrorNumber CloseFile(IFileNode node) { - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - if(size == 0) - { - buf = Array.Empty(); + if(node is not CpmFileNode mynode) return ErrorNumber.InvalidArgument; - return ErrorNumber.NoError; - } + mynode.Cache = null; - if(offset < 0) - return ErrorNumber.InvalidArgument; + return ErrorNumber.NoError; + } - string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(!_mounted) return ErrorNumber.AccessDenied; - if(!_fileCache.TryGetValue(pathElements[0].ToUpperInvariant(), out byte[] file)) - return ErrorNumber.NoSuchFile; + if(buffer is null || buffer.Length < length) return ErrorNumber.InvalidArgument; - if(offset >= file.Length) - return ErrorNumber.EINVAL; + if(node is not CpmFileNode mynode) return ErrorNumber.InvalidArgument; - if(size + offset >= file.Length) - size = file.Length - offset; + read = length; - buf = new byte[size]; - Array.Copy(file, offset, buf, 0, size); + if(length + mynode.Offset >= mynode.Length) read = mynode.Length - mynode.Offset; + + Array.Copy(mynode.Cache, mynode.Offset, buffer, 0, read); + + mynode.Offset += read; return ErrorNumber.NoError; } @@ -133,34 +145,35 @@ public sealed partial class CPM { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); + + if(pathElements.Length != 1) return ErrorNumber.NotSupported; + + if(!string.IsNullOrEmpty(path) && string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) { - '/' - }, StringSplitOptions.RemoveEmptyEntries); - - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; - - if(!string.IsNullOrEmpty(path) && - string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) - return _statCache.TryGetValue(pathElements[0].ToUpperInvariant(), out stat) ? ErrorNumber.NoError + return _statCache.TryGetValue(pathElements[0].ToUpperInvariant(), out stat) + ? ErrorNumber.NoError : ErrorNumber.NoSuchFile; + } stat = new FileEntryInfo { Attributes = FileAttributes.Directory, - BlockSize = XmlFsType.ClusterSize + BlockSize = Metadata.ClusterSize }; - if(_labelCreationDate != null) - stat.CreationTime = DateHandlers.CpmToDateTime(_labelCreationDate); + if(_labelCreationDate != null) stat.CreationTime = DateHandlers.CpmToDateTime(_labelCreationDate); - if(_labelUpdateDate != null) - stat.StatusChangeTime = DateHandlers.CpmToDateTime(_labelUpdateDate); + if(_labelUpdateDate != null) stat.StatusChangeTime = DateHandlers.CpmToDateTime(_labelUpdateDate); return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/CPM/Info.cs b/Aaru.Filesystems/CPM/Info.cs index b163b9475..893491989 100644 --- a/Aaru.Filesystems/CPM/Info.cs +++ b/Aaru.Filesystems/CPM/Info.cs @@ -27,29 +27,30 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.IO; using System.Linq; using System.Text; using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Helpers; -using Schemas; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class CPM { +#region IReadOnlyFilesystem Members + /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - ErrorNumber errno; - // This will only continue on devices with a chance to have ever been used by CP/M while failing on all others // It's ugly, but will stop a lot of false positives switch(imagePlugin.Info.MediaType) @@ -155,8 +156,10 @@ public sealed partial class CPM case MediaType.GENERIC_HDD: case MediaType.FlashDrive: case MediaType.MetaFloppy_Mod_I: - case MediaType.MetaFloppy_Mod_II: break; - default: return false; + case MediaType.MetaFloppy_Mod_II: + break; + default: + return false; } // This will try to identify a CP/M filesystem @@ -172,6 +175,8 @@ public sealed partial class CPM _label = null; // Try Amstrad superblock + ErrorNumber errno; + if(!_cpmFound) { // Read CHS = {0,0,1} @@ -186,10 +191,7 @@ public sealed partial class CPM var sig3 = BitConverter.ToUInt32(sector, 0x7C); // PCW16 extended boot record - if(sig1 == 0x4D2F5043 && - sig2 == 0x004B5344 && - sig3 == sig1) - amsSbOffset = 0x80; + if(sig1 == 0x4D2F5043 && sig2 == 0x004B5344 && sig3 == sig1) amsSbOffset = 0x80; // Read the superblock AmstradSuperBlock amsSb = @@ -206,8 +208,7 @@ public sealed partial class CPM sectorSize = (ulong)(128 << amsSb.psh); // Compare device limits from superblock to real limits - if(sectorSize == imagePlugin.Info.SectorSize && - sectorCount == imagePlugin.Info.Sectors) + if(sectorSize == imagePlugin.Info.SectorSize && sectorCount == imagePlugin.Info.Sectors) { _cpmFound = true; firstDirectorySector = (ulong)(amsSb.off * amsSb.spt); @@ -220,8 +221,7 @@ public sealed partial class CPM bsh = amsSb.bsh }; - for(var i = 0; i < _dpb.bsh; i++) - _dpb.blm += (byte)Math.Pow(2, i); + for(var i = 0; i < _dpb.bsh; i++) _dpb.blm += (byte)Math.Pow(2, i); if(sectorCount >= 1440) { @@ -239,13 +239,13 @@ public sealed partial class CPM _dpb.off = amsSb.off; _dpb.psh = amsSb.psh; - for(var i = 0; i < _dpb.psh; i++) - _dpb.phm += (byte)Math.Pow(2, i); + for(var i = 0; i < _dpb.psh; i++) _dpb.phm += (byte)Math.Pow(2, i); _dpb.spt = (ushort)(amsSb.spt * (sectorSize / 128)); var directoryLength = (uint)(((ulong)_dpb.drm + 1) * 32 / sectorSize); - imagePlugin.ReadSectors(firstDirectorySector + partition.Start, directoryLength, + imagePlugin.ReadSectors(firstDirectorySector + partition.Start, + directoryLength, out directory); // Build a CP/M disk definition @@ -274,26 +274,16 @@ public sealed partial class CPM } }; - for(var si = 0; si < amsSb.spt; si++) - _workingDefinition.side1.sectorIds[si] = si + 1; + for(var si = 0; si < amsSb.spt; si++) _workingDefinition.side1.sectorIds[si] = si + 1; if(amsSb.format == 2) { - switch(amsSb.sidedness & 0x02) - { - case 1: - _workingDefinition.order = "SIDES"; - - break; - case 2: - _workingDefinition.order = "CYLINDERS"; - - break; - default: - _workingDefinition.order = null; - - break; - } + _workingDefinition.order = (amsSb.sidedness & 0x02) switch + { + 1 => "SIDES", + 2 => "CYLINDERS", + _ => null + }; _workingDefinition.side2 = new Side { @@ -301,8 +291,7 @@ public sealed partial class CPM sectorIds = new int[amsSb.spt] }; - for(var si = 0; si < amsSb.spt; si++) - _workingDefinition.side2.sectorIds[si] = si + 1; + for(var si = 0; si < amsSb.spt; si++) _workingDefinition.side2.sectorIds[si] = si + 1; } else _workingDefinition.order = null; @@ -310,7 +299,7 @@ public sealed partial class CPM _workingDefinition.skew = 2; _workingDefinition.sofs = 0; - AaruConsole.DebugWriteLine("CP/M Plugin", "Found Amstrad superblock."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Found_Amstrad_superblock); } } } @@ -327,8 +316,7 @@ public sealed partial class CPM ushort sum = 0; // Sum of all 16-bit words that make this sector must be 0 - for(var i = 0; i < sector.Length; i += 2) - sum += BitConverter.ToUInt16(sector, i); + for(var i = 0; i < sector.Length; i += 2) sum += BitConverter.ToUInt16(sector, i); // It may happen that there is a corrupted superblock // Better to ignore corrupted than to false positive the rest @@ -375,10 +363,11 @@ public sealed partial class CPM var directoryLength = (uint)(((ulong)_dpb.drm + 1) * 32 / sectorSize); - imagePlugin.ReadSectors(firstDirectorySector + partition.Start, directoryLength, + imagePlugin.ReadSectors(firstDirectorySector + partition.Start, + directoryLength, out directory); - AaruConsole.DebugWriteLine("CP/M Plugin", "Found CP/M-86 hard disk superblock."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Found_CPM_86_hard_disk_superblock); // Build a CP/M disk definition _workingDefinition = new CpmDefinition @@ -417,8 +406,7 @@ public sealed partial class CPM for(var si = 0; si < hddSb.sectorsPerTrack; si++) _workingDefinition.side1.sectorIds[si] = si + 1; - for(var si = 0; si < hddSb.spt; si++) - _workingDefinition.side2.sectorIds[si] = si + 1; + for(var si = 0; si < hddSb.spt; si++) _workingDefinition.side2.sectorIds[si] = si + 1; } } } @@ -435,13 +423,13 @@ public sealed partial class CPM byte formatByte; // Check for alternate location of format ID - if(sector.Last() == 0x00 || - sector.Last() == 0xFF) - if(sector[0x40] == 0x94 || - sector[0x40] == 0x26) + if(sector.Last() == 0x00 || sector.Last() == 0xFF) + { + if(sector[0x40] == 0x94 || sector[0x40] == 0x26) formatByte = sector[0x40]; else formatByte = sector.Last(); + } else formatByte = sector.Last(); @@ -455,8 +443,7 @@ public sealed partial class CPM switch((FormatByte)formatByte) { case FormatByte.k160: - if(imagePlugin.Info.SectorSize == 512 && - imagePlugin.Info.Sectors == 320) + if(imagePlugin.Info is { SectorSize: 512, Sectors: 320 }) { _cpmFound = true; firstDirectorySector86 = 8; @@ -504,14 +491,12 @@ public sealed partial class CPM sofs = 0 }; - for(var si = 0; si < 8; si++) - _workingDefinition.side1.sectorIds[si] = si + 1; + for(var si = 0; si < 8; si++) _workingDefinition.side1.sectorIds[si] = si + 1; } break; case FormatByte.k320: - if(imagePlugin.Info.SectorSize == 512 && - imagePlugin.Info.Sectors == 640) + if(imagePlugin.Info is { SectorSize: 512, Sectors: 640 }) { _cpmFound = true; firstDirectorySector86 = 16; @@ -565,19 +550,16 @@ public sealed partial class CPM sofs = 0 }; - for(var si = 0; si < 8; si++) - _workingDefinition.side1.sectorIds[si] = si + 1; + for(var si = 0; si < 8; si++) _workingDefinition.side1.sectorIds[si] = si + 1; - for(var si = 0; si < 8; si++) - _workingDefinition.side2.sectorIds[si] = si + 1; + for(var si = 0; si < 8; si++) _workingDefinition.side2.sectorIds[si] = si + 1; } break; case FormatByte.k360: case FormatByte.k360Alt: case FormatByte.k360Alt2: - if(imagePlugin.Info.SectorSize == 512 && - imagePlugin.Info.Sectors == 720) + if(imagePlugin.Info is { SectorSize: 512, Sectors: 720 }) { _cpmFound = true; firstDirectorySector86 = 36; @@ -631,18 +613,15 @@ public sealed partial class CPM sofs = 0 }; - for(var si = 0; si < 9; si++) - _workingDefinition.side1.sectorIds[si] = si + 1; + for(var si = 0; si < 9; si++) _workingDefinition.side1.sectorIds[si] = si + 1; - for(var si = 0; si < 9; si++) - _workingDefinition.side2.sectorIds[si] = si + 1; + for(var si = 0; si < 9; si++) _workingDefinition.side2.sectorIds[si] = si + 1; } break; case FormatByte.k720: case FormatByte.k720Alt: - if(imagePlugin.Info.SectorSize == 512 && - imagePlugin.Info.Sectors == 1440) + if(imagePlugin.Info is { SectorSize: 512, Sectors: 1440 }) { _cpmFound = true; firstDirectorySector86 = 36; @@ -696,17 +675,14 @@ public sealed partial class CPM sofs = 0 }; - for(var si = 0; si < 9; si++) - _workingDefinition.side1.sectorIds[si] = si + 1; + for(var si = 0; si < 9; si++) _workingDefinition.side1.sectorIds[si] = si + 1; - for(var si = 0; si < 9; si++) - _workingDefinition.side2.sectorIds[si] = si + 1; + for(var si = 0; si < 9; si++) _workingDefinition.side2.sectorIds[si] = si + 1; } break; case FormatByte.f720: - if(imagePlugin.Info.SectorSize == 512 && - imagePlugin.Info.Sectors == 1440) + if(imagePlugin.Info is { SectorSize: 512, Sectors: 1440 }) { _cpmFound = true; firstDirectorySector86 = 18; @@ -760,17 +736,14 @@ public sealed partial class CPM sofs = 0 }; - for(var si = 0; si < 9; si++) - _workingDefinition.side1.sectorIds[si] = si + 1; + for(var si = 0; si < 9; si++) _workingDefinition.side1.sectorIds[si] = si + 1; - for(var si = 0; si < 9; si++) - _workingDefinition.side2.sectorIds[si] = si + 1; + for(var si = 0; si < 9; si++) _workingDefinition.side2.sectorIds[si] = si + 1; } break; case FormatByte.f1200: - if(imagePlugin.Info.SectorSize == 512 && - imagePlugin.Info.Sectors == 2400) + if(imagePlugin.Info is { SectorSize: 512, Sectors: 2400 }) { _cpmFound = true; firstDirectorySector86 = 30; @@ -824,17 +797,14 @@ public sealed partial class CPM sofs = 0 }; - for(var si = 0; si < 15; si++) - _workingDefinition.side1.sectorIds[si] = si + 1; + for(var si = 0; si < 15; si++) _workingDefinition.side1.sectorIds[si] = si + 1; - for(var si = 0; si < 15; si++) - _workingDefinition.side2.sectorIds[si] = si + 1; + for(var si = 0; si < 15; si++) _workingDefinition.side2.sectorIds[si] = si + 1; } break; case FormatByte.f1440: - if(imagePlugin.Info.SectorSize == 512 && - imagePlugin.Info.Sectors == 2880) + if(imagePlugin.Info is { SectorSize: 512, Sectors: 2880 }) { _cpmFound = true; firstDirectorySector86 = 36; @@ -888,11 +858,9 @@ public sealed partial class CPM sofs = 0 }; - for(var si = 0; si < 18; si++) - _workingDefinition.side1.sectorIds[si] = si + 1; + for(var si = 0; si < 18; si++) _workingDefinition.side1.sectorIds[si] = si + 1; - for(var si = 0; si < 18; si++) - _workingDefinition.side2.sectorIds[si] = si + 1; + for(var si = 0; si < 18; si++) _workingDefinition.side2.sectorIds[si] = si + 1; } break; @@ -902,10 +870,11 @@ public sealed partial class CPM { var directoryLength = (uint)(((ulong)_dpb.drm + 1) * 32 / imagePlugin.Info.SectorSize); - imagePlugin.ReadSectors(firstDirectorySector86 + partition.Start, directoryLength, + imagePlugin.ReadSectors(firstDirectorySector86 + partition.Start, + directoryLength, out directory); - AaruConsole.DebugWriteLine("CP/M Plugin", "Found CP/M-86 floppy identifier."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Found_CPM_86_floppy_identifier); } } } @@ -915,7 +884,7 @@ public sealed partial class CPM { if(CheckDir(directory)) { - AaruConsole.DebugWriteLine("CP/M Plugin", "First directory block seems correct."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.First_directory_block_seems_correct); return true; } @@ -927,21 +896,20 @@ public sealed partial class CPM if(!_cpmFound) { // Load all definitions - AaruConsole.DebugWriteLine("CP/M Plugin", "Trying to load definitions."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Trying_to_load_definitions); - if(LoadDefinitions() && - _definitions?.definitions != null && - _definitions.definitions.Count > 0) + if(LoadDefinitions() && _definitions?.definitions is { Count: > 0 }) { - AaruConsole.DebugWriteLine("CP/M Plugin", "Trying all known definitions."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Trying_all_known_definitions); - foreach(CpmDefinition def in from def in _definitions.definitions let sectors = - (ulong)(def.cylinders * def.sides * def.sectorsPerTrack) + foreach(CpmDefinition def in from def in _definitions.definitions + let sectors = (ulong)(def.cylinders * def.sides * def.sectorsPerTrack) where sectors == imagePlugin.Info.Sectors && - def.bytesPerSector == imagePlugin.Info.SectorSize select def) + def.bytesPerSector == imagePlugin.Info.SectorSize + select def) { // Definition seems to describe current disk, at least, same number of volume sectors and bytes per sector - AaruConsole.DebugWriteLine("CP/M Plugin", "Trying definition \"{0}\"", def.comment); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Trying_definition_0, def.comment); ulong offset; if(def.sofs != 0) @@ -970,30 +938,41 @@ public sealed partial class CPM // Skip first track (first side) for(var m = 0; m < def.side2.sectorIds.Length; m++) + { _sectorMask[m + def.side1.sectorIds.Length] = def.side2.sectorIds[m] - def.side2.sectorIds[0] + def.side1.sectorIds.Length; + } } // Head changes after whole side - else if(string.Compare(def.order, "CYLINDERS", - StringComparison.InvariantCultureIgnoreCase) == 0) + else if(string.Compare(def.order, + "CYLINDERS", + StringComparison.InvariantCultureIgnoreCase) == + 0) { for(var m = 0; m < def.side1.sectorIds.Length; m++) _sectorMask[m] = def.side1.sectorIds[m] - def.side1.sectorIds[0]; // Skip first track (first side) and first track (second side) for(var m = 0; m < def.side1.sectorIds.Length; m++) + { _sectorMask[m + def.side1.sectorIds.Length] = - def.side1.sectorIds[m] - def.side1.sectorIds[0] + def.side1.sectorIds.Length + + def.side1.sectorIds[m] - + def.side1.sectorIds[0] + + def.side1.sectorIds.Length + def.side2.sectorIds.Length; + } } // TODO: Implement COLUMBIA ordering - else if(string.Compare(def.order, "COLUMBIA", - StringComparison.InvariantCultureIgnoreCase) == 0) + else if(string.Compare(def.order, + "COLUMBIA", + StringComparison.InvariantCultureIgnoreCase) == + 0) { - AaruConsole.DebugWriteLine("CP/M Plugin", - "Don't know how to handle COLUMBIA ordering, not proceeding with this definition."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Dont_know_how_to_handle_COLUMBIA_ordering_not_proceeding_with_this_definition); continue; } @@ -1002,15 +981,17 @@ public sealed partial class CPM else if(string.Compare(def.order, "EAGLE", StringComparison.InvariantCultureIgnoreCase) == 0) { - AaruConsole.DebugWriteLine("CP/M Plugin", - "Don't know how to handle EAGLE ordering, not proceeding with this definition."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Don_know_how_to_handle_EAGLE_ordering_not_proceeding_with_this_definition); continue; } else { - AaruConsole.DebugWriteLine("CP/M Plugin", - "Unknown order type \"{0}\", not proceeding with this definition.", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Unknown_order_type_0_not_proceeding_with_this_definition, def.order); continue; @@ -1022,13 +1003,13 @@ public sealed partial class CPM for(var p = 0; p < dirLen; p++) { - errno = - imagePlugin. - ReadSector((ulong)((int)offset + (int)partition.Start + p / _sectorMask.Length * _sectorMask.Length + _sectorMask[p % _sectorMask.Length]), - out byte[] dirSector); + errno = imagePlugin.ReadSector((ulong)((int)offset + + (int)partition.Start + + p / _sectorMask.Length * _sectorMask.Length + + _sectorMask[p % _sectorMask.Length]), + out byte[] dirSector); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; ms.Write(dirSector, 0, dirSector.Length); } @@ -1036,8 +1017,11 @@ public sealed partial class CPM directory = ms.ToArray(); if(def.evenOdd) - AaruConsole.DebugWriteLine("CP/M Plugin", - "Definition contains EVEN-ODD field, with unknown meaning, detection may be wrong."); + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Definition_contains_EVEN_ODD_field_with_unknown_meaning_detection_may_be_wrong); + } // Complement of the directory bytes if needed if(def.complement) @@ -1047,7 +1031,8 @@ public sealed partial class CPM // Check the directory if(CheckDir(directory)) { - AaruConsole.DebugWriteLine("CP/M Plugin", "Definition \"{0}\" has a correct directory", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Definition_0_has_a_correct_directory, def.comment); // Build a Disc Parameter Block @@ -1149,45 +1134,47 @@ public sealed partial class CPM } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = encoding ?? Encoding.GetEncoding("IBM437"); information = ""; + metadata = new FileSystem(); // As the identification is so complex, just call Identify() and relay on its findings - if(!Identify(imagePlugin, partition) || - !_cpmFound || - _workingDefinition == null || - _dpb == null) - return; + if(!Identify(imagePlugin, partition) || !_cpmFound || _workingDefinition == null || _dpb == null) return; var sb = new StringBuilder(); - sb.AppendLine("CP/M filesystem"); + sb.AppendLine(Localization.CPM_filesystem); if(!string.IsNullOrEmpty(_workingDefinition.comment)) - sb.AppendFormat("Identified as {0}", _workingDefinition.comment).AppendLine(); + sb.AppendFormat(Localization.Identified_as_0, _workingDefinition.comment).AppendLine(); - sb.AppendFormat("Volume block is {0} bytes", 128 << _dpb.bsh).AppendLine(); + sb.AppendFormat(Localization.Volume_block_is_0_bytes, 128 << _dpb.bsh).AppendLine(); if(_dpb.dsm > 0) - sb.AppendFormat("Volume contains {0} blocks ({1} bytes)", _dpb.dsm, _dpb.dsm * (128 << _dpb.bsh)). - AppendLine(); + { + sb.AppendFormat(Localization.Volume_contains_0_blocks_1_bytes, _dpb.dsm, _dpb.dsm * (128 << _dpb.bsh)) + .AppendLine(); + } - sb.AppendFormat("Volume contains {0} directory entries", _dpb.drm + 1).AppendLine(); + sb.AppendFormat(Localization.Volume_contains_0_directory_entries, _dpb.drm + 1).AppendLine(); if(_workingDefinition.sofs > 0) - sb.AppendFormat("Volume reserves {0} sectors for system", _workingDefinition.sofs).AppendLine(); + sb.AppendFormat(Localization.Volume_reserves_0_sectors_for_system, _workingDefinition.sofs).AppendLine(); else - sb.AppendFormat("Volume reserves {1} tracks ({0} sectors) for system", - _workingDefinition.ofs * _workingDefinition.sectorsPerTrack, _workingDefinition.ofs). - AppendLine(); + { + sb.AppendFormat(Localization.Volume_reserves_1_tracks_0_sectors_for_system, + _workingDefinition.ofs * _workingDefinition.sectorsPerTrack, + _workingDefinition.ofs) + .AppendLine(); + } if(_workingDefinition.side1.sectorIds.Length >= 2) { int interleaveSide1 = _workingDefinition.side1.sectorIds[1] - _workingDefinition.side1.sectorIds[0]; if(interleaveSide1 > 1) - sb.AppendFormat("Side 0 uses {0}:1 software interleaving", interleaveSide1).AppendLine(); + sb.AppendFormat(Localization.Side_zero_uses_0_one_software_interleaving, interleaveSide1).AppendLine(); } if(_workingDefinition.sides == 2) @@ -1197,77 +1184,80 @@ public sealed partial class CPM int interleaveSide2 = _workingDefinition.side2.sectorIds[1] - _workingDefinition.side2.sectorIds[0]; if(interleaveSide2 > 1) - sb.AppendFormat("Side 1 uses {0}:1 software interleaving", interleaveSide2).AppendLine(); + { + sb.AppendFormat(Localization.Side_one_uses_0_one_software_interleaving, interleaveSide2) + .AppendLine(); + } } switch(_workingDefinition.order) { case "SIDES": - sb.AppendLine("Head changes after each whole track"); + sb.AppendLine(Localization.Head_changes_after_each_whole_track); break; case "CYLINDERS": - sb.AppendLine("Head changes after whole side"); + sb.AppendLine(Localization.Head_changes_after_whole_side); break; default: - sb.AppendFormat("Unknown how {0} side ordering works", _workingDefinition.order).AppendLine(); + sb.AppendFormat(Localization.Unknown_how_0_side_ordering_works, _workingDefinition.order) + .AppendLine(); break; } } if(_workingDefinition.skew > 0) - sb.AppendFormat("Device uses {0}:1 hardware interleaving", _workingDefinition.skew).AppendLine(); + sb.AppendFormat(Localization.Device_uses_0_one_hardware_interleaving, _workingDefinition.skew).AppendLine(); if(_workingDefinition.sofs > 0) - sb.AppendFormat("BSH {0} BLM {1} EXM {2} DSM {3} DRM {4} AL0 {5:X2}H AL1 {6:X2}H SOFS {7}", _dpb.bsh, - _dpb.blm, _dpb.exm, _dpb.dsm, _dpb.drm, _dpb.al0, _dpb.al1, _workingDefinition.sofs). - AppendLine(); + { + sb.AppendLine($"BSH {_dpb.bsh} BLM {_dpb.blm} EXM {_dpb.exm} DSM {_dpb.dsm} DRM {_dpb.drm} AL0 {_dpb.al0 + :X2}H AL1 {_dpb.al1:X2}H SOFS {_workingDefinition.sofs}"); + } else - sb.AppendFormat("BSH {0} BLM {1} EXM {2} DSM {3} DRM {4} AL0 {5:X2}H AL1 {6:X2}H OFS {7}", _dpb.bsh, - _dpb.blm, _dpb.exm, _dpb.dsm, _dpb.drm, _dpb.al0, _dpb.al1, _workingDefinition.ofs). - AppendLine(); + { + sb.AppendLine($"BSH {_dpb.bsh} BLM {_dpb.blm} EXM {_dpb.exm} DSM {_dpb.dsm} DRM {_dpb.drm} AL0 {_dpb.al0 + :X2}H AL1 {_dpb.al1:X2}H OFS {_workingDefinition.ofs}"); + } - if(_label != null) - sb.AppendFormat("Volume label {0}", _label).AppendLine(); + if(_label != null) sb.AppendFormat(Localization.Volume_label_0, _label).AppendLine(); - if(_standardTimestamps) - sb.AppendLine("Volume uses standard CP/M timestamps"); + if(_standardTimestamps) sb.AppendLine(Localization.Volume_uses_standard_CPM_timestamps); - if(_thirdPartyTimestamps) - sb.AppendLine("Volume uses third party timestamps"); + if(_thirdPartyTimestamps) sb.AppendLine(Localization.Volume_uses_third_party_timestamps); if(_labelCreationDate != null) - sb.AppendFormat("Volume created on {0}", DateHandlers.CpmToDateTime(_labelCreationDate)).AppendLine(); + { + sb.AppendFormat(Localization.Volume_created_on_0, DateHandlers.CpmToDateTime(_labelCreationDate)) + .AppendLine(); + } if(_labelUpdateDate != null) - sb.AppendFormat("Volume updated on {0}", DateHandlers.CpmToDateTime(_labelUpdateDate)).AppendLine(); + { + sb.AppendFormat(Localization.Volume_updated_on_0, DateHandlers.CpmToDateTime(_labelUpdateDate)) + .AppendLine(); + } - XmlFsType = new FileSystemType(); - XmlFsType.Bootable |= _workingDefinition.sofs > 0 || _workingDefinition.ofs > 0; - XmlFsType.ClusterSize = (uint)(128 << _dpb.bsh); + metadata = new FileSystem(); + metadata.Bootable |= _workingDefinition.sofs > 0 || _workingDefinition.ofs > 0; + metadata.ClusterSize = (uint)(128 << _dpb.bsh); if(_dpb.dsm > 0) - XmlFsType.Clusters = _dpb.dsm; + metadata.Clusters = _dpb.dsm; else - XmlFsType.Clusters = partition.End - partition.Start; + metadata.Clusters = partition.End - partition.Start; - if(_labelCreationDate != null) - { - XmlFsType.CreationDate = DateHandlers.CpmToDateTime(_labelCreationDate); - XmlFsType.CreationDateSpecified = true; - } + if(_labelCreationDate != null) metadata.CreationDate = DateHandlers.CpmToDateTime(_labelCreationDate); - if(_labelUpdateDate != null) - { - XmlFsType.ModificationDate = DateHandlers.CpmToDateTime(_labelUpdateDate); - XmlFsType.ModificationDateSpecified = true; - } + if(_labelUpdateDate != null) metadata.ModificationDate = DateHandlers.CpmToDateTime(_labelUpdateDate); - XmlFsType.Type = "CP/M"; - XmlFsType.VolumeName = _label; + metadata.Type = FS_TYPE; + metadata.VolumeName = _label; information = sb.ToString(); } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/CPM/Structs.cs b/Aaru.Filesystems/CPM/Structs.cs index 743ec2488..04968daa2 100644 --- a/Aaru.Filesystems/CPM/Structs.cs +++ b/Aaru.Filesystems/CPM/Structs.cs @@ -27,49 +27,20 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable NotAccessedField.Local -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; public sealed partial class CPM { - /// Most of the times this structure is hard wired or generated by CP/M, not stored on disk - [SuppressMessage("ReSharper", "InconsistentNaming")] - class DiscParameterBlock - { - /// First byte of allocation bitmap - public byte al0; - /// Second byte of allocation bitmap - public byte al1; - /// Block mask - public byte blm; - /// Block shift - public byte bsh; - /// Checksum vector size - public ushort cks; - /// Directory entries - 1 - public ushort drm; - /// Blocks on disk - 1 - public ushort dsm; - /// Extent mask - public byte exm; - /// Reserved tracks - public ushort off; - /// Physical sector mask - public byte phm; - /// Physical sector shift - public byte psh; - /// Sectors per track - public ushort spt; - } +#region Nested type: AmstradSuperBlock /// Amstrad superblock, for PCW [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -109,6 +80,186 @@ public sealed partial class CPM public readonly byte fiddle; } +#endregion + +#region Nested type: CpmDirNode + + sealed class CpmDirNode : IDirNode + { + internal string[] Contents; + internal int Position; + +#region IDirNode Members + + /// + public string Path { get; init; } + +#endregion + } + +#endregion + +#region Nested type: CpmFileNode + + sealed class CpmFileNode : IFileNode + { + internal byte[] Cache; + +#region IFileNode Members + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + +#endregion + } + +#endregion + +#region Nested type: DateEntry + + /// CP/M 3 timestamp entry + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DateEntry + { + /// Must be 0x21 + public readonly byte signature; + /// File 1 create/access timestamp + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] date1; + /// File 1 modification timestamp + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] date2; + /// File 1 password mode + public readonly byte mode1; + public readonly byte zero1; + /// File 2 create/access timestamp + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] date3; + /// File 2 modification timestamp + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] date4; + /// File 2 password mode + public readonly byte mode2; + public readonly byte zero2; + /// File 3 create/access timestamp + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] date5; + /// File 3 modification timestamp + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] date6; + /// File 3 password mode + public readonly byte mode3; + public readonly ushort zero3; + } + +#endregion + +#region Nested type: DirectoryEntry + + /// Directory entry for <256 allocation blocks + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DirectoryEntry + { + /// User number. Bit 7 set in CP/M 1 means hidden + public readonly byte statusUser; + /// Filename and bit 7 as flags + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] filename; + /// Extension and bit 7 as flags + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] extension; + /// Low byte of extent number + public readonly byte extentCounter; + /// + /// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how + /// many bytes are free. It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless. + /// + public readonly byte lastRecordBytes; + /// High byte of extent number + public readonly byte extentCounterHigh; + /// How many records are used in this entry. 0x80 if all are used. + public readonly byte records; + /// Allocation blocks + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] allocations; + } + +#endregion + +#region Nested type: DirectoryEntry16 + + /// Directory entry for >256 allocation blocks + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DirectoryEntry16 + { + /// User number. Bit 7 set in CP/M 1 means hidden + public readonly byte statusUser; + /// Filename and bit 7 as flags + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] filename; + /// Extension and bit 7 as flags + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] extension; + /// Low byte of extent number + public readonly byte extentCounter; + /// + /// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how + /// many bytes are free. It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless. + /// + public readonly byte lastRecordBytes; + /// High byte of extent number + public readonly byte extentCounterHigh; + /// How many records are used in this entry. 0x80 if all are used. + public readonly byte records; + /// Allocation blocks + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly ushort[] allocations; + } + +#endregion + +#region Nested type: DiscParameterBlock + + /// Most of the times this structure is hard wired or generated by CP/M, not stored on disk + [SuppressMessage("ReSharper", "InconsistentNaming")] + sealed class DiscParameterBlock + { + /// First byte of allocation bitmap + public byte al0; + /// Second byte of allocation bitmap + public byte al1; + /// Block mask + public byte blm; + /// Block shift + public byte bsh; + /// Checksum vector size + public ushort cks; + /// Directory entries - 1 + public ushort drm; + /// Blocks on disk - 1 + public ushort dsm; + /// Extent mask + public byte exm; + /// Reserved tracks + public ushort off; + /// Physical sector mask + public byte phm; + /// Physical sector shift + public byte psh; + /// Sectors per track + public ushort spt; + } + +#endregion + +#region Nested type: HardDiskSuperBlock + /// Superblock found on CP/M-86 hard disk volumes [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct HardDiskSuperBlock @@ -188,6 +339,10 @@ public sealed partial class CPM public readonly ushort firstSub; } +#endregion + +#region Nested type: LabelEntry + /// Volume label entry [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct LabelEntry @@ -217,40 +372,9 @@ public sealed partial class CPM public readonly byte[] mtime; } - /// CP/M 3 timestamp entry - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DateEntry - { - /// Must be 0x21 - public readonly byte signature; - /// File 1 create/access timestamp - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] date1; - /// File 1 modification timestamp - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] date2; - /// File 1 password mode - public readonly byte mode1; - public readonly byte zero1; - /// File 2 create/access timestamp - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] date3; - /// File 2 modification timestamp - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] date4; - /// File 2 password mode - public readonly byte mode2; - public readonly byte zero2; - /// File 3 create/access timestamp - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] date5; - /// File 3 modification timestamp - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] date6; - /// File 3 password mode - public readonly byte mode3; - public readonly ushort zero3; - } +#endregion + +#region Nested type: PasswordEntry /// Password entry [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -277,6 +401,10 @@ public sealed partial class CPM public readonly byte[] reserved2; } +#endregion + +#region Nested type: TrdPartyDateEntry + /// Timestamp for Z80DOS or DOS+ [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct TrdPartyDateEntry @@ -313,59 +441,5 @@ public sealed partial class CPM public readonly byte[] access3; } - /// Directory entry for <256 allocation blocks - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DirectoryEntry - { - /// User number. Bit 7 set in CP/M 1 means hidden - public readonly byte statusUser; - /// Filename and bit 7 as flags - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] filename; - /// Extension and bit 7 as flags - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] extension; - /// Low byte of extent number - public readonly byte extentCounter; - /// - /// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how - /// many bytes are free. It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless. - /// - public readonly byte lastRecordBytes; - /// High byte of extent number - public readonly byte extentCounterHigh; - /// How many records are used in this entry. 0x80 if all are used. - public readonly byte records; - /// Allocation blocks - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] allocations; - } - - /// Directory entry for >256 allocation blocks - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DirectoryEntry16 - { - /// User number. Bit 7 set in CP/M 1 means hidden - public readonly byte statusUser; - /// Filename and bit 7 as flags - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] filename; - /// Extension and bit 7 as flags - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] extension; - /// Low byte of extent number - public readonly byte extentCounter; - /// - /// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how - /// many bytes are free. It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless. - /// - public readonly byte lastRecordBytes; - /// High byte of extent number - public readonly byte extentCounterHigh; - /// How many records are used in this entry. 0x80 if all are used. - public readonly byte records; - /// Allocation blocks - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly ushort[] allocations; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/CPM/Super.cs b/Aaru.Filesystems/CPM/Super.cs index a3a7bb780..38129c1cb 100644 --- a/Aaru.Filesystems/CPM/Super.cs +++ b/Aaru.Filesystems/CPM/Super.cs @@ -29,40 +29,39 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Helpers; -using Schemas; using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes; using FileSystemInfo = Aaru.CommonTypes.Structs.FileSystemInfo; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class CPM { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, - Dictionary options, string @namespace) + public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace) { - _device = imagePlugin; - Encoding = encoding ?? Encoding.GetEncoding("IBM437"); + _device = imagePlugin; + _encoding = encoding ?? Encoding.GetEncoding("IBM437"); // As the identification is so complex, just call Identify() and relay on its findings - if(!Identify(_device, partition) || - !_cpmFound || - _workingDefinition == null || - _dpb == null) + if(!Identify(_device, partition) || !_cpmFound || _workingDefinition == null || _dpb == null) return ErrorNumber.InvalidArgument; // Build the software interleaving sector mask @@ -86,26 +85,35 @@ public sealed partial class CPM // Skip first track (first side) for(var m = 0; m < _workingDefinition.side2.sectorIds.Length; m++) + { _sectorMask[m + _workingDefinition.side1.sectorIds.Length] = - _workingDefinition.side2.sectorIds[m] - _workingDefinition.side2.sectorIds[0] + + _workingDefinition.side2.sectorIds[m] - + _workingDefinition.side2.sectorIds[0] + _workingDefinition.side1.sectorIds.Length; + } } // Head changes after whole side - else if(string.Compare(_workingDefinition.order, "CYLINDERS", - StringComparison.InvariantCultureIgnoreCase) == 0) + else if(string.Compare(_workingDefinition.order, + "CYLINDERS", + StringComparison.InvariantCultureIgnoreCase) == + 0) { for(var m = 0; m < _workingDefinition.side1.sectorIds.Length; m++) _sectorMask[m] = _workingDefinition.side1.sectorIds[m] - _workingDefinition.side1.sectorIds[0]; // Skip first track (first side) and first track (second side) for(var m = 0; m < _workingDefinition.side1.sectorIds.Length; m++) + { _sectorMask[m + _workingDefinition.side1.sectorIds.Length] = - _workingDefinition.side1.sectorIds[m] - _workingDefinition.side1.sectorIds[0] + - _workingDefinition.side1.sectorIds.Length + _workingDefinition.side2.sectorIds.Length; + _workingDefinition.side1.sectorIds[m] - + _workingDefinition.side1.sectorIds[0] + + _workingDefinition.side1.sectorIds.Length + + _workingDefinition.side2.sectorIds.Length; + } // TODO: Implement CYLINDERS ordering - AaruConsole.DebugWriteLine("CP/M Plugin", "CYLINDERS ordering not yet implemented."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.CYLINDERS_ordering_not_yet_implemented); return ErrorNumber.NotImplemented; } @@ -114,8 +122,9 @@ public sealed partial class CPM else if(string.Compare(_workingDefinition.order, "COLUMBIA", StringComparison.InvariantCultureIgnoreCase) == 0) { - AaruConsole.DebugWriteLine("CP/M Plugin", - "Don't know how to handle COLUMBIA ordering, not proceeding with this definition."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Dont_know_how_to_handle_COLUMBIA_ordering_not_proceeding_with_this_definition); return ErrorNumber.NotImplemented; } @@ -123,15 +132,16 @@ public sealed partial class CPM // TODO: Implement EAGLE ordering else if(string.Compare(_workingDefinition.order, "EAGLE", StringComparison.InvariantCultureIgnoreCase) == 0) { - AaruConsole.DebugWriteLine("CP/M Plugin", - "Don't know how to handle EAGLE ordering, not proceeding with this definition."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Don_know_how_to_handle_EAGLE_ordering_not_proceeding_with_this_definition); return ErrorNumber.NotImplemented; } else { - AaruConsole.DebugWriteLine("CP/M Plugin", - "Unknown order type \"{0}\", not proceeding with this definition.", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Unknown_order_type_0_not_proceeding_with_this_definition, _workingDefinition.order); return ErrorNumber.NotSupported; @@ -144,20 +154,22 @@ public sealed partial class CPM if(_workingDefinition.sides == 1 || string.Compare(_workingDefinition.order, "SIDES", StringComparison.InvariantCultureIgnoreCase) == 0) { - AaruConsole.DebugWriteLine("CP/M Plugin", "Deinterleaving whole volume."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Deinterleaving_whole_volume); for(var p = 0; p <= (int)(partition.End - partition.Start); p++) { ErrorNumber errno = - _device.ReadSector((ulong)((int)partition.Start + p / _sectorMask.Length * _sectorMask.Length + _sectorMask[p % _sectorMask.Length]), + _device.ReadSector((ulong)((int)partition.Start + + p / _sectorMask.Length * _sectorMask.Length + + _sectorMask[p % _sectorMask.Length]), out byte[] readSector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; if(_workingDefinition.complement) - for(var b = 0; b < readSector.Length; b++) - readSector[b] = (byte)(~readSector[b] & 0xFF); + { + for(var b = 0; b < readSector.Length; b++) readSector[b] = (byte)(~readSector[b] & 0xFF); + } deinterleavedSectors.Add((ulong)p, readSector); } @@ -169,7 +181,7 @@ public sealed partial class CPM var sectorsPerBlock = 0; Dictionary allocationBlocks = new(); - AaruConsole.DebugWriteLine("CP/M Plugin", "Creating allocation blocks."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Creating_allocation_blocks); // For each volume sector for(ulong a = 0; a < (ulong)deinterleavedSectors.Count; a++) @@ -178,12 +190,14 @@ public sealed partial class CPM // May it happen? Just in case, CP/M blocks are smaller than physical sectors if(sector.Length > blockSize) + { for(var i = 0; i < sector.Length / blockSize; i++) { var tmp = new byte[blockSize]; Array.Copy(sector, blockSize * i, tmp, 0, blockSize); allocationBlocks.Add(blockNo++, tmp); } + } // CP/M blocks are larger than physical sectors else if(sector.Length < blockSize) @@ -191,8 +205,7 @@ public sealed partial class CPM blockMs.Write(sector, 0, sector.Length); sectorsPerBlock++; - if(sectorsPerBlock != blockSize / sector.Length) - continue; + if(sectorsPerBlock != blockSize / sector.Length) continue; allocationBlocks.Add(blockNo++, blockMs.ToArray()); sectorsPerBlock = 0; @@ -204,7 +217,7 @@ public sealed partial class CPM allocationBlocks.Add(blockNo++, sector); } - AaruConsole.DebugWriteLine("CP/M Plugin", "Reading directory."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_directory); int dirOff; int dirSectors = (_dpb.drm + 1) * 32 / _workingDefinition.bytesPerSector; @@ -225,8 +238,7 @@ public sealed partial class CPM byte[] directory = dirMs.ToArray(); - if(directory == null) - return ErrorNumber.InvalidArgument; + if(directory == null) return ErrorNumber.InvalidArgument; var dirCnt = 0; string file1 = null; @@ -238,19 +250,21 @@ public sealed partial class CPM _statCache = new Dictionary(); _cpmStat = new FileSystemInfo(); var atime = false; - _dirList = new List(); + _dirList = []; _labelCreationDate = null; _labelUpdateDate = null; _passwordCache = new Dictionary(); - AaruConsole.DebugWriteLine("CP/M Plugin", "Traversing directory."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Traversing_directory); // For each directory entry for(var dOff = 0; dOff < directory.Length; dOff += 32) - // Describes a file (does not support PDOS entries with user >= 16, because they're identical to password entries - if((directory[dOff] & 0x7F) < 0x10) - if(allocationBlocks.Count > 256) + { + switch(directory[dOff] & 0x7F) + { + // Describes a file (does not support PDOS entries with user >= 16, because they're identical to password entries + case < 0x10 when allocationBlocks.Count > 256: { DirectoryEntry16 entry = Marshal.ByteArrayToStructureLittleEndian(directory, dOff, 32); @@ -276,18 +290,15 @@ public sealed partial class CPM validEntry &= entry.extension[i] >= 0x20; } - if(!validEntry) - continue; + if(!validEntry) continue; string filename = Encoding.ASCII.GetString(entry.filename).Trim(); string extension = Encoding.ASCII.GetString(entry.extension).Trim(); // If user is != 0, append user to name to have identical filenames - if(user > 0) - filename = $"{user:X1}:{filename}"; + if(user > 0) filename = $"{user:X1}:{filename}"; - if(!string.IsNullOrEmpty(extension)) - filename = filename + "." + extension; + if(!string.IsNullOrEmpty(extension)) filename = filename + "." + extension; filename = filename.Replace('/', '\u2215'); @@ -297,10 +308,12 @@ public sealed partial class CPM if(_statCache.TryGetValue(filename, out FileEntryInfo fInfo)) _statCache.Remove(filename); else + { fInfo = new FileEntryInfo { Attributes = new FileAttributes() }; + } // And any extent? if(fileExtents.TryGetValue(filename, out Dictionary> extentBlocks)) @@ -312,17 +325,14 @@ public sealed partial class CPM if(extentBlocks.TryGetValue(entryNo, out List blocks)) extentBlocks.Remove(entryNo); else - blocks = new List(); + blocks = []; // Attributes - if(hidden) - fInfo.Attributes |= FileAttributes.Hidden; + if(hidden) fInfo.Attributes |= FileAttributes.Hidden; - if(rdOnly) - fInfo.Attributes |= FileAttributes.ReadOnly; + if(rdOnly) fInfo.Attributes |= FileAttributes.ReadOnly; - if(system) - fInfo.Attributes |= FileAttributes.System; + if(system) fInfo.Attributes |= FileAttributes.System; // Supposedly there is a value in the directory entry telling how many blocks are designated in // this entry. However some implementations tend to do whatever they wish, but none will ever @@ -339,8 +349,7 @@ public sealed partial class CPM _statCache.Add(filename, fInfo); // Add the file to the directory listing - if(!_dirList.Contains(filename)) - _dirList.Add(filename); + if(!_dirList.Contains(filename)) _dirList.Add(filename); // Count entries 3 by 3 for timestamps switch(dirCnt % 3) @@ -360,8 +369,10 @@ public sealed partial class CPM } dirCnt++; + + break; } - else + case < 0x10: { DirectoryEntry entry = Marshal.ByteArrayToStructureLittleEndian(directory, dOff, 32); @@ -387,18 +398,15 @@ public sealed partial class CPM validEntry &= entry.extension[i] >= 0x20; } - if(!validEntry) - continue; + if(!validEntry) continue; string filename = Encoding.ASCII.GetString(entry.filename).Trim(); string extension = Encoding.ASCII.GetString(entry.extension).Trim(); // If user is != 0, append user to name to have identical filenames - if(user > 0) - filename = $"{user:X1}:{filename}"; + if(user > 0) filename = $"{user:X1}:{filename}"; - if(!string.IsNullOrEmpty(extension)) - filename = filename + "." + extension; + if(!string.IsNullOrEmpty(extension)) filename = filename + "." + extension; filename = filename.Replace('/', '\u2215'); @@ -408,10 +416,12 @@ public sealed partial class CPM if(_statCache.TryGetValue(filename, out FileEntryInfo fInfo)) _statCache.Remove(filename); else + { fInfo = new FileEntryInfo { Attributes = new FileAttributes() }; + } // And any extent? if(fileExtents.TryGetValue(filename, out Dictionary> extentBlocks)) @@ -423,17 +433,14 @@ public sealed partial class CPM if(extentBlocks.TryGetValue(entryNo, out List blocks)) extentBlocks.Remove(entryNo); else - blocks = new List(); + blocks = []; // Attributes - if(hidden) - fInfo.Attributes |= FileAttributes.Hidden; + if(hidden) fInfo.Attributes |= FileAttributes.Hidden; - if(rdOnly) - fInfo.Attributes |= FileAttributes.ReadOnly; + if(rdOnly) fInfo.Attributes |= FileAttributes.ReadOnly; - if(system) - fInfo.Attributes |= FileAttributes.System; + if(system) fInfo.Attributes |= FileAttributes.System; // Supposedly there is a value in the directory entry telling how many blocks are designated in // this entry. However some implementations tend to do whatever they wish, but none will ever @@ -450,8 +457,7 @@ public sealed partial class CPM _statCache.Add(filename, fInfo); // Add the file to the directory listing - if(!_dirList.Contains(filename)) - _dirList.Add(filename); + if(!_dirList.Contains(filename)) _dirList.Add(filename); // Count entries 3 by 3 for timestamps switch(dirCnt % 3) @@ -471,245 +477,247 @@ public sealed partial class CPM } dirCnt++; + + break; } - // A password entry (or a file entry in PDOS, but this does not handle that case) - else if((directory[dOff] & 0x7F) >= 0x10 && - (directory[dOff] & 0x7F) < 0x20) - { - PasswordEntry entry = Marshal.ByteArrayToStructureLittleEndian(directory, dOff, 32); - - int user = entry.userNumber & 0x0F; - - for(var i = 0; i < 8; i++) - entry.filename[i] &= 0x7F; - - for(var i = 0; i < 3; i++) - entry.extension[i] &= 0x7F; - - string filename = Encoding.ASCII.GetString(entry.filename).Trim(); - string extension = Encoding.ASCII.GetString(entry.extension).Trim(); - - // If user is != 0, append user to name to have identical filenames - if(user > 0) - filename = $"{user:X1}:{filename}"; - - if(!string.IsNullOrEmpty(extension)) - filename = filename + "." + extension; - - filename = filename.Replace('/', '\u2215'); - - // Do not repeat passwords - if(_passwordCache.ContainsKey(filename)) - _passwordCache.Remove(filename); - - // Copy whole password entry - var tmp = new byte[32]; - Array.Copy(directory, dOff, tmp, 0, 32); - _passwordCache.Add(filename, tmp); - - // Count entries 3 by 3 for timestamps - switch(dirCnt % 3) + // A password entry (or a file entry in PDOS, but this does not handle that case) + case >= 0x10 and < 0x20: { - case 0: - file1 = filename; + PasswordEntry entry = Marshal.ByteArrayToStructureLittleEndian(directory, dOff, 32); - break; - case 1: - file2 = filename; + int user = entry.userNumber & 0x0F; - break; - case 2: - file3 = filename; + for(var i = 0; i < 8; i++) entry.filename[i] &= 0x7F; - break; + for(var i = 0; i < 3; i++) entry.extension[i] &= 0x7F; + + string filename = Encoding.ASCII.GetString(entry.filename).Trim(); + string extension = Encoding.ASCII.GetString(entry.extension).Trim(); + + // If user is != 0, append user to name to have identical filenames + if(user > 0) filename = $"{user:X1}:{filename}"; + + if(!string.IsNullOrEmpty(extension)) filename = filename + "." + extension; + + filename = filename.Replace('/', '\u2215'); + + // Do not repeat passwords + if(_passwordCache.ContainsKey(filename)) _passwordCache.Remove(filename); + + // Copy whole password entry + var tmp = new byte[32]; + Array.Copy(directory, dOff, tmp, 0, 32); + _passwordCache.Add(filename, tmp); + + // Count entries 3 by 3 for timestamps + switch(dirCnt % 3) + { + case 0: + file1 = filename; + + break; + case 1: + file2 = filename; + + break; + case 2: + file3 = filename; + + break; + } + + dirCnt++; + + break; } - dirCnt++; + // Volume label and password entry. Volume password is ignored. + default: + switch(directory[dOff] & 0x7F) + { + case 0x20: + LabelEntry labelEntry = + Marshal.ByteArrayToStructureLittleEndian(directory, dOff, 32); + + // The volume label defines if one of the fields in CP/M 3 timestamp is a creation or an + // access time + atime |= (labelEntry.flags & 0x40) == 0x40; + + _label = Encoding.ASCII.GetString(directory, dOff + 1, 11).Trim(); + _labelCreationDate = new byte[4]; + _labelUpdateDate = new byte[4]; + Array.Copy(directory, dOff + 24, _labelCreationDate, 0, 4); + Array.Copy(directory, dOff + 28, _labelUpdateDate, 0, 4); + + // Count entries 3 by 3 for timestamps + switch(dirCnt % 3) + { + case 0: + file1 = null; + + break; + case 1: + file2 = null; + + break; + case 2: + file3 = null; + + break; + } + + dirCnt++; + + break; + case 0x21: + if(directory[dOff + 10] == 0x00 && + directory[dOff + 20] == 0x00 && + directory[dOff + 30] == 0x00 && + directory[dOff + 31] == 0x00) + { + DateEntry dateEntry = + Marshal.ByteArrayToStructureLittleEndian(directory, dOff, 32); + + FileEntryInfo fInfo; + + // Entry contains timestamps for last 3 entries, whatever the kind they are. + if(!string.IsNullOrEmpty(file1)) + { + if(_statCache.TryGetValue(file1, out fInfo)) + _statCache.Remove(file1); + else + fInfo = new FileEntryInfo(); + + if(atime) + fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date1); + else + fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date1); + + fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date2); + + _statCache.Add(file1, fInfo); + } + + if(!string.IsNullOrEmpty(file2)) + { + if(_statCache.TryGetValue(file2, out fInfo)) + _statCache.Remove(file2); + else + fInfo = new FileEntryInfo(); + + if(atime) + fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date3); + else + fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date3); + + fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date4); + + _statCache.Add(file2, fInfo); + } + + if(!string.IsNullOrEmpty(file3)) + { + if(_statCache.TryGetValue(file3, out fInfo)) + _statCache.Remove(file3); + else + fInfo = new FileEntryInfo(); + + if(atime) + fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date5); + else + fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date5); + + fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date6); + + _statCache.Add(file3, fInfo); + } + + file1 = null; + file2 = null; + file3 = null; + dirCnt = 0; + } + + // However, if this byte is 0, timestamp is in Z80DOS or DOS+ format + else if(directory[dOff + 1] == 0x00) + { + TrdPartyDateEntry trdPartyDateEntry = + Marshal.ByteArrayToStructureLittleEndian(directory, dOff, 32); + + FileEntryInfo fInfo; + + // Entry contains timestamps for last 3 entries, whatever the kind they are. + if(!string.IsNullOrEmpty(file1)) + { + if(_statCache.TryGetValue(file1, out fInfo)) + _statCache.Remove(file1); + else + fInfo = new FileEntryInfo(); + + var ctime = new byte[4]; + ctime[0] = trdPartyDateEntry.create1[0]; + ctime[1] = trdPartyDateEntry.create1[1]; + + fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access1); + fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime); + fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify1); + + _statCache.Add(file1, fInfo); + } + + if(!string.IsNullOrEmpty(file2)) + { + if(_statCache.TryGetValue(file2, out fInfo)) + _statCache.Remove(file2); + else + fInfo = new FileEntryInfo(); + + var ctime = new byte[4]; + ctime[0] = trdPartyDateEntry.create2[0]; + ctime[1] = trdPartyDateEntry.create2[1]; + + fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access2); + fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime); + fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify2); + + _statCache.Add(file2, fInfo); + } + + if(!string.IsNullOrEmpty(file3)) + { + if(_statCache.TryGetValue(file1, out fInfo)) + _statCache.Remove(file3); + else + fInfo = new FileEntryInfo(); + + var ctime = new byte[4]; + ctime[0] = trdPartyDateEntry.create3[0]; + ctime[1] = trdPartyDateEntry.create3[1]; + + fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access3); + fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime); + fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify3); + + _statCache.Add(file3, fInfo); + } + + file1 = null; + file2 = null; + file3 = null; + dirCnt = 0; + } + + break; + } + + break; } - - // Volume label and password entry. Volume password is ignored. - else - switch(directory[dOff] & 0x7F) - { - case 0x20: - LabelEntry labelEntry = - Marshal.ByteArrayToStructureLittleEndian(directory, dOff, 32); - - // The volume label defines if one of the fields in CP/M 3 timestamp is a creation or an - // access time - atime |= (labelEntry.flags & 0x40) == 0x40; - - _label = Encoding.ASCII.GetString(directory, dOff + 1, 11).Trim(); - _labelCreationDate = new byte[4]; - _labelUpdateDate = new byte[4]; - Array.Copy(directory, dOff + 24, _labelCreationDate, 0, 4); - Array.Copy(directory, dOff + 28, _labelUpdateDate, 0, 4); - - // Count entries 3 by 3 for timestamps - switch(dirCnt % 3) - { - case 0: - file1 = null; - - break; - case 1: - file2 = null; - - break; - case 2: - file3 = null; - - break; - } - - dirCnt++; - - break; - case 0x21: - if(directory[dOff + 10] == 0x00 && - directory[dOff + 20] == 0x00 && - directory[dOff + 30] == 0x00 && - directory[dOff + 31] == 0x00) - { - DateEntry dateEntry = - Marshal.ByteArrayToStructureLittleEndian(directory, dOff, 32); - - FileEntryInfo fInfo; - - // Entry contains timestamps for last 3 entries, whatever the kind they are. - if(!string.IsNullOrEmpty(file1)) - { - if(_statCache.TryGetValue(file1, out fInfo)) - _statCache.Remove(file1); - else - fInfo = new FileEntryInfo(); - - if(atime) - fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date1); - else - fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date1); - - fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date2); - - _statCache.Add(file1, fInfo); - } - - if(!string.IsNullOrEmpty(file2)) - { - if(_statCache.TryGetValue(file2, out fInfo)) - _statCache.Remove(file2); - else - fInfo = new FileEntryInfo(); - - if(atime) - fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date3); - else - fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date3); - - fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date4); - - _statCache.Add(file2, fInfo); - } - - if(!string.IsNullOrEmpty(file3)) - { - if(_statCache.TryGetValue(file3, out fInfo)) - _statCache.Remove(file3); - else - fInfo = new FileEntryInfo(); - - if(atime) - fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date5); - else - fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date5); - - fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date6); - - _statCache.Add(file3, fInfo); - } - - file1 = null; - file2 = null; - file3 = null; - dirCnt = 0; - } - - // However, if this byte is 0, timestamp is in Z80DOS or DOS+ format - else if(directory[dOff + 1] == 0x00) - { - TrdPartyDateEntry trdPartyDateEntry = - Marshal.ByteArrayToStructureLittleEndian(directory, dOff, 32); - - FileEntryInfo fInfo; - - // Entry contains timestamps for last 3 entries, whatever the kind they are. - if(!string.IsNullOrEmpty(file1)) - { - if(_statCache.TryGetValue(file1, out fInfo)) - _statCache.Remove(file1); - else - fInfo = new FileEntryInfo(); - - var ctime = new byte[4]; - ctime[0] = trdPartyDateEntry.create1[0]; - ctime[1] = trdPartyDateEntry.create1[1]; - - fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access1); - fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime); - fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify1); - - _statCache.Add(file1, fInfo); - } - - if(!string.IsNullOrEmpty(file2)) - { - if(_statCache.TryGetValue(file2, out fInfo)) - _statCache.Remove(file2); - else - fInfo = new FileEntryInfo(); - - var ctime = new byte[4]; - ctime[0] = trdPartyDateEntry.create2[0]; - ctime[1] = trdPartyDateEntry.create2[1]; - - fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access2); - fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime); - fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify2); - - _statCache.Add(file2, fInfo); - } - - if(!string.IsNullOrEmpty(file3)) - { - if(_statCache.TryGetValue(file1, out fInfo)) - _statCache.Remove(file3); - else - fInfo = new FileEntryInfo(); - - var ctime = new byte[4]; - ctime[0] = trdPartyDateEntry.create3[0]; - ctime[1] = trdPartyDateEntry.create3[1]; - - fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access3); - fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime); - fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify3); - - _statCache.Add(file3, fInfo); - } - - file1 = null; - file2 = null; - file3 = null; - dirCnt = 0; - } - - break; - } + } // Cache all files. As CP/M maximum volume size is 8 Mib // this should not be a problem - AaruConsole.DebugWriteLine("CP/M Plugin", "Reading files."); + AaruConsole.DebugWriteLine(MODULE_NAME, "Reading files."); long usedBlocks = 0; _fileCache = new Dictionary(); @@ -717,16 +725,15 @@ public sealed partial class CPM { var fileMs = new MemoryStream(); - if(_statCache.TryGetValue(filename, out FileEntryInfo fInfo)) - _statCache.Remove(filename); + if(_statCache.TryGetValue(filename, out FileEntryInfo fInfo)) _statCache.Remove(filename); fInfo.Blocks = 0; if(fileExtents.TryGetValue(filename, out Dictionary> extents)) + { for(var ex = 0; ex < extents.Count; ex++) { - if(!extents.TryGetValue(ex, out List alBlks)) - continue; + if(!extents.TryGetValue(ex, out List alBlks)) continue; foreach(ushort alBlk in alBlks) { @@ -735,6 +742,7 @@ public sealed partial class CPM fInfo.Blocks++; } } + } // If you insist to call CP/M "extent based" fInfo.Attributes |= FileAttributes.Extents; @@ -750,17 +758,15 @@ public sealed partial class CPM _decodedPasswordCache = new Dictionary(); // For each stored password, store a decoded version of it - if(_passwordCache.Count > 0) - foreach(KeyValuePair kvp in _passwordCache) - { - var tmp = new byte[8]; - Array.Copy(kvp.Value, 16, tmp, 0, 8); + foreach(KeyValuePair kvp in _passwordCache) + { + var tmp = new byte[8]; + Array.Copy(kvp.Value, 16, tmp, 0, 8); - for(var t = 0; t < 8; t++) - tmp[t] ^= kvp.Value[13]; + for(var t = 0; t < 8; t++) tmp[t] ^= kvp.Value[13]; - _decodedPasswordCache.Add(kvp.Key, tmp); - } + _decodedPasswordCache.Add(kvp.Key, tmp); + } // Generate statfs. _cpmStat.Blocks = (ulong)(_dpb.dsm + 1); @@ -768,34 +774,23 @@ public sealed partial class CPM _cpmStat.Files = (ulong)_fileCache.Count; _cpmStat.FreeBlocks = _cpmStat.Blocks - (ulong)usedBlocks; _cpmStat.PluginId = Id; - _cpmStat.Type = "CP/M filesystem"; + _cpmStat.Type = FS_TYPE; // Generate XML info - XmlFsType = new FileSystemType + Metadata = new FileSystem { - Clusters = _cpmStat.Blocks, - ClusterSize = (uint)blockSize, - Files = (ulong)_fileCache.Count, - FilesSpecified = true, - FreeClusters = _cpmStat.FreeBlocks, - FreeClustersSpecified = true, - Type = "CP/M filesystem" + Clusters = _cpmStat.Blocks, + ClusterSize = (uint)blockSize, + Files = (ulong)_fileCache.Count, + FreeClusters = _cpmStat.FreeBlocks, + Type = FS_TYPE }; - if(_labelCreationDate != null) - { - XmlFsType.CreationDate = DateHandlers.CpmToDateTime(_labelCreationDate); - XmlFsType.CreationDateSpecified = true; - } + if(_labelCreationDate != null) Metadata.CreationDate = DateHandlers.CpmToDateTime(_labelCreationDate); - if(_labelUpdateDate != null) - { - XmlFsType.ModificationDate = DateHandlers.CpmToDateTime(_labelUpdateDate); - XmlFsType.ModificationDateSpecified = true; - } + if(_labelUpdateDate != null) Metadata.ModificationDate = DateHandlers.CpmToDateTime(_labelUpdateDate); - if(!string.IsNullOrEmpty(_label)) - XmlFsType.VolumeName = _label; + if(!string.IsNullOrEmpty(_label)) Metadata.VolumeName = _label; _mounted = true; @@ -807,8 +802,7 @@ public sealed partial class CPM { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; stat = _cpmStat; @@ -832,4 +826,6 @@ public sealed partial class CPM return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/CPM/Xattr.cs b/Aaru.Filesystems/CPM/Xattr.cs index fb8942689..bbbe9d531 100644 --- a/Aaru.Filesystems/CPM/Xattr.cs +++ b/Aaru.Filesystems/CPM/Xattr.cs @@ -27,33 +27,33 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using Aaru.CommonTypes.Enums; +namespace Aaru.Filesystems; + public sealed partial class CPM { +#region IReadOnlyFilesystem Members + /// public ErrorNumber GetXattr(string path, string xattr, ref byte[] buf) { - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; - if(!_fileCache.ContainsKey(pathElements[0].ToUpperInvariant())) - return ErrorNumber.NoSuchFile; + if(!_fileCache.ContainsKey(pathElements[0].ToUpperInvariant())) return ErrorNumber.NoSuchFile; if(string.Compare(xattr, "com.caldera.cpm.password", StringComparison.InvariantCulture) == 0) if(!_passwordCache.TryGetValue(pathElements[0].ToUpperInvariant(), out buf)) @@ -62,7 +62,8 @@ public sealed partial class CPM if(string.Compare(xattr, "com.caldera.cpm.password.text", StringComparison.InvariantCulture) != 0) return ErrorNumber.NoSuchExtendedAttribute; - return !_passwordCache.TryGetValue(pathElements[0].ToUpperInvariant(), out buf) ? ErrorNumber.NoError + return !_passwordCache.TryGetValue(pathElements[0].ToUpperInvariant(), out buf) + ? ErrorNumber.NoError : ErrorNumber.NoSuchExtendedAttribute; } @@ -71,28 +72,27 @@ public sealed partial class CPM { xattrs = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; - if(!_fileCache.ContainsKey(pathElements[0].ToUpperInvariant())) - return ErrorNumber.NoSuchFile; + if(!_fileCache.ContainsKey(pathElements[0].ToUpperInvariant())) return ErrorNumber.NoSuchFile; - xattrs = new List(); + xattrs = []; - if(_passwordCache.ContainsKey(pathElements[0].ToUpperInvariant())) - xattrs.Add("com.caldera.cpm.password"); + if(_passwordCache.ContainsKey(pathElements[0].ToUpperInvariant())) xattrs.Add("com.caldera.cpm.password"); if(_decodedPasswordCache.ContainsKey(pathElements[0].ToUpperInvariant())) xattrs.Add("com.caldera.cpm.password.text"); return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/CPM/cpmdefs.json b/Aaru.Filesystems/CPM/cpmdefs.json new file mode 100644 index 000000000..1adaf0465 --- /dev/null +++ b/Aaru.Filesystems/CPM/cpmdefs.json @@ -0,0 +1,21847 @@ +{ + "creation": "2016-08-24T02:44:59.045767Z", + "definitions": [ + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 7, + "bsh": 3, + "bytesPerSector": 128, + "comment": "Generic CP/M - SSSD 8\u0022 - 128 x 26", + "complement": false, + "cylinders": 77, + "drm": 63, + "dsm": 242, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "A1", + "ofs": 2, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14, + 20, + 26, + 6, + 12, + 18, + 24, + 4, + 10, + 16, + 22 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "ABC-80 - SSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ABC1", + "ofs": 2, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 8, + 15, + 6, + 13, + 4, + 11, + 2, + 9, + 16, + 7, + 14, + 5, + 12, + 3, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 255, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "A. B. Dick Magna III - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 255, + "dsm": 255, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ABD1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Actrix (Access Matrix) - SSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ACT1", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Actrix (Access Matrix) - DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ACT2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 1 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Adler Textriter - SSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 31, + "dsm": 159, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ADL1", + "ofs": 0, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Advanced Digital Super 6 - SSDD 48 tpi 5.25\u0022 - 1024 x 4", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 77, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ADV1", + "ofs": 1, + "sectorsPerTrack": 4, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Advanced Digital Super 6 - DSDD 48 tpi 5.25\u0022 - 1024 x 4", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ADV2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 4, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Advanced Digital Super 6 - DSDD 96 tpi 5.25\u0022 - 1024 x 4", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 300, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ADV3", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 4, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Advanced Digital Super 8 - DSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 608, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ADV4", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Advanced Digital TurboDOS 312K - DSDD 48 tpi 5.25\u0022 - 1024 x 4", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ADV5", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 4, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Advanced Digital TurboDOS 366K - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 182, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ADV6", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Advanced Controls - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 385, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ADV7", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Allen-Bradley Advisor\u002B - DSDD 3.5\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 318, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ALL1", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 1 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Alspa - SSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 300, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ALS1", + "ofs": 2, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 7, + "bsh": 3, + "bytesPerSector": 128, + "comment": "Altos - SSSD 8\u0022 - 128 x 26", + "complement": false, + "cylinders": 77, + "drm": 63, + "dsm": 242, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "ALT1", + "ofs": 2, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 128, + "comment": "Altos - DSSD 8\u0022 - 128 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 122, + "encoding": "FM", + "evenOdd": false, + "exm": 3, + "label": "ALT2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14, + 20, + 26, + 6, + 12, + 18, + 24, + 4, + 10, + 16, + 22 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14, + 20, + 26, + 6, + 12, + 18, + 24, + 4, + 10, + 16, + 22 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Altos - SSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 139, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "ALT3", + "ofs": 2, + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Altos - DSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 284, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ALT4", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Altos Series 5 - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 176, + "dsm": 176, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "ALT5", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Amigo - SSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMI1", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Amigo - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 195, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMI2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Ampro - SSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 94, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "AMP1", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Ampro - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "AMP2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Ampro - SSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "AMP3", + "ofs": 2, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Ampro - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 394, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMP4", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 17, + 18, + 19, + 20, + 21 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 17, + 18, + 19, + 20, + 21 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Amstrad PCW 8256 - SSDD 48 tpi 3.00\u0022", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 175, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMS0", + "ofs": 1, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Amstrad PCW 8256 - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 356, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMS1", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Amstrad CPC464 - SSDD 48 tpi 5.25\u0022/3\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 171, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMS2", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Amstrad CPC464 - SSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 87, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "AMS3", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Amstrad PCW 8512 - DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 255, + "dsm": 356, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMS5", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Amstrad CPC 6128 - DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 175, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "AMS7", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Amstrad CPC 6128 - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 175, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "AMS8", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Amstrad CPC 6128 Side 1 - SSDD 3.5\u0022 / 3\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 180, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMS9", + "ofs": 0, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Amstrad CPC 6128 Side 2 - SSDD 3.5\u0022 / 3\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 180, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMSA", + "ofs": 80, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Amstrad PCW w/DU49, Moonstone XFORMAT - DSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 198, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "AMSB", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Amstrad CPC 6128 Vortex - DSDD 3.5\u0022/96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 178, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "AMSC", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Archive I - SSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ARC1", + "ofs": 2, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 248, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Archive II \u0026 III - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 319, + "dsm": 394, + "encoding": "MFM", + "evenOdd": true, + "exm": 0, + "label": "ARC2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Arisia - SSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 147, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ARI1", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Associate - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 195, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ASO1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Aster CT-80 - DSDD 96 tpi 5.25\u0022 - 1024 x 5, 3:1", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 394, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AST1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 1024, + "comment": "ATR-8000 - SSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ATR1", + "ofs": 2, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "ATR-8000 - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ATR2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "ATR-8000 - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ATR3", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "ATT-7700 - DSDD 3.5\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 316, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ATT1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 17, + 19, + 21, + 23, + 25, + 27, + 29, + 31, + 18, + 20, + 22, + 24, + 26, + 28, + 30, + 32 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Avatar - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 191, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "AVA1", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 3, + 7, + 2, + 6, + 10, + 4, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 3, + 7, + 2, + 6, + 10, + 4, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "Barudan - DSDD 3.5\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "BAR1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Beehive - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "BEE1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Beehive Microbee - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "BEE2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 2, + 5, + 8, + 1, + 4, + 7, + 10, + 3, + 6, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 2, + 5, + 8, + 1, + 4, + 7, + 10, + 3, + 6, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Beehive Microbee - SSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "BEE3", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 2, + 5, + 8, + 1, + 4, + 7, + 10, + 3, + 6, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Microbee Systems - DSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "BEE4", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 22, + 25, + 28, + 21, + 24, + 27, + 30, + 23, + 26, + 29 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 22, + 25, + 28, + 21, + 24, + 27, + 30, + 23, + 26, + 29 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Microbee Dreamdisk format - DSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 391, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "BEE5", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 2, + 5, + 8, + 1, + 4, + 7, + 10, + 3, + 6, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 2, + 5, + 8, + 1, + 4, + 7, + 10, + 3, + 6, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Computer Bell - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 192, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "BEL1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Big Board (512 bytes/sector) - SSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 280, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "BIG1", + "ofs": 2, + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Big Board (512 bytes/sector) - DSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 569, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "BIG2", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Big Board SWP 1024 bytes/sector - SSDD 8\u0022 - 1024 x 9", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 336, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "BIG4", + "ofs": 2, + "sectorsPerTrack": 9, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Bitelex - SSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 95, + "dsm": 131, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "BIT1", + "ofs": 2, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "BMC IF800 Model 20 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 191, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "BMC1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 5, + 11, + 17, + 3, + 9, + 15 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 5, + 11, + 17, + 3, + 9, + 15 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Bondwell 12 - SSDD 48 tpi 5.25\u0022 - 256 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 84, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "BON1", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Bondwell 14 - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "BON2", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Bondwell 2 - SSDD 3.5\u0022 - 256 x 18", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "BON3", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "BOSS TurboDOS - DSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 616, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "BOS1", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "BTI Systems - DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 175, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "BTI1", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Burr-Brown - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "BUR1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 10, + 2, + 11, + 3, + 12, + 4, + 13, + 5, + 14, + 6, + 15, + 7, + 16, + 8, + 17, + 9, + 18 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 10, + 2, + 11, + 3, + 12, + 4, + 13, + 5, + 14, + 6, + 15, + 7, + 16, + 8, + 17, + 9, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Cal-PC - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "CAL1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Cashcom 100 - DSDD 96 tpi 5.25\u0022 - 1024 x 4", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 303, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "CAS1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 4, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Commodore Business Machines 1581 drive - DSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 397, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "CBM1", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "CCS (256 bytes/sector) - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 165, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "CCS1", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 17, + 3, + 7, + 11, + 15, + 2, + 6, + 10, + 14, + 18, + 4, + 8, + 12, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 17, + 3, + 7, + 11, + 15, + 2, + 6, + 10, + 14, + 18, + 4, + 8, + 12, + 16 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "CCS (512 bytes/sector) - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 184, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "CCS2", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 3, + 6, + 9, + 2, + 5, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 3, + 6, + 9, + 2, + 5, + 8 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "CCS (1024 bytes/sector) - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 184, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "CCS3", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 63, + "bsh": 6, + "bytesPerSector": 1024, + "comment": "CCS 8 - DSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 149, + "encoding": "MFM", + "evenOdd": false, + "exm": 7, + "label": "CCS4", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "CCS 2442 - SSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 139, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "CCS5", + "ofs": 2, + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "CCS (1024 bytes alternate) - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 184, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "CCS6", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "CDC-110 Viking - DSDD 8\u0022 - 512 x 16", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 608, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "CDC1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 0, + 4, + 8, + 12, + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 4, + 8, + 12, + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "CDI-5000 - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "CDI1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "COLEX 850 - SSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "CLX1", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 3, + 7, + 2, + 6, + 10, + 4, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "COLEX 850 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 389, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "CLX2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 3, + 7, + 2, + 6, + 10, + 4, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 11, + 15, + 19, + 13, + 17, + 12, + 16, + 20, + 14, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "CMC Supersystem 2 - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 391, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "CMC1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Coin - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 392, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COI1", + "ofs": 3, + "order": "EAGLE", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Coleco ADAM, 40 track - SSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 146, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COL1", + "ofs": 0, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 6, + 3, + 8, + 5, + 2, + 7, + 4 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 26 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Coleco ADAM, 254K - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 255, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COL2", + "ofs": 0, + "order": "EAGLE", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 6, + 3, + 8, + 5, + 2, + 7, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 6, + 3, + 8, + 5, + 2, + 7, + 4 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 26 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Coleco ADAM, 320K - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 152, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "COL3", + "ofs": 0, + "order": "EAGLE", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 6, + 3, + 8, + 5, + 2, + 7, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 6, + 3, + 8, + 5, + 2, + 7, + 4 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 26 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Coleco ADAM, 720K - DSDD 3.5\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 354, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COL4", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 4, + 8, + 3, + 7, + 2, + 6 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 4, + 8, + 3, + 7, + 2, + 6 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 26 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Coleco ADAM, 360K - DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "COL5", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 4 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Coleco ADAM, E\u0026T PROM 720K - DSDD 3.5\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 354, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COL6", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 4, + 8, + 3, + 7, + 2, + 6 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 4, + 8, + 3, + 7, + 2, + 6 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 26 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Coleco ADAM, 720K - DSDD 3.5\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 358, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COL7", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 4, + 8, + 3, + 7, + 2, + 6 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 4, + 8, + 3, + 7, + 2, + 6 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 4 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Coleco ADAM, 1.44M - DSHD 3.5\u0022 - 512 x 18", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 712, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COL8", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 15, + 2, + 6, + 10, + 14, + 18, + 4, + 8, + 12, + 16, + 1, + 5, + 9, + 13, + 17, + 3, + 7, + 11 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 17, + 3, + 7, + 11, + 15, + 2, + 6, + 10, + 14, + 18, + 4, + 8, + 12, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Coleco Adam TDOS - DSDD 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 255, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COL9", + "ofs": 0, + "order": "EAGLE", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 6, + 3, + 8, + 5, + 2, + 7, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 6, + 3, + 8, + 5, + 2, + 7, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 26 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Columbia Commander 964 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 190, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "COLA", + "ofs": 2, + "order": "COLUMBIA", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Columbia 1600 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 197, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "COLB", + "ofs": 2, + "order": "COLUMBIA", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Columbia M64 - SSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 40, + "drm": 127, + "dsm": 190, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COLC", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Compis - DSDD 96 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 317, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COM1", + "ofs": 1, + "order": "CYLINDERS", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Compugraphic MCS-5 - SSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COM2", + "ofs": 1, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Compustar Model 30 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 35, + "drm": 63, + "dsm": 169, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "COM3", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Compupro (Viasyn) - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 389, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COM7", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Compupro (Viasyn) 8/16 - SSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 299, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COM8", + "ofs": 2, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Compupro (Viasyn) 8/16 - DSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 599, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COM9", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Compupro (Viasyn) - SSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 280, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COMA", + "ofs": 2, + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Compupro (Viasyn) - SSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 242, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COMB", + "ofs": 2, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 10, + 19, + 2, + 11, + 20, + 3, + 12, + 21, + 4, + 13, + 22, + 5, + 14, + 23, + 6 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Compupro (Viasyn) 256 bytes/sector - DSHD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 487, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "COME", + "ofs": 4, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 10, + 19, + 2, + 11, + 20, + 3, + 12, + 21, + 4, + 13, + 22, + 5, + 14, + 23, + 6 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 10, + 19, + 2, + 11, + 20, + 3, + 12, + 21, + 4, + 13, + 22, + 5, + 14, + 23, + 6 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "CPT Phoenix CP/M - DSDD 3.5\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 355, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "CPT1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 128, + "comment": "Cromemco CDOS - SSSD 48 tpi 5.25\u0022 - 128 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 82, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "CRO1", + "ofs": 3, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 6, + 11, + 16, + 3, + 8, + 13, + 18, + 5, + 10, + 15, + 2, + 7, + 12, + 17, + 4, + 9, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 18, + "comment": "Cromemco CDOS - DSSD 48 tpi 5.25\u0022 - 128 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 172, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "CRO2", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 128, + "side1": { + "sectorIds": [ + 1, + 6, + 11, + 16, + 3, + 8, + 13, + 18, + 5, + 10, + 15, + 2, + 7, + 12, + 17, + 4, + 9, + 14 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 6, + 11, + 16, + 3, + 8, + 13, + 18, + 5, + 10, + 15, + 2, + 7, + 12, + 17, + 4, + 9, + 14 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Cromemco CDOS - SSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "CRO3", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 3, + 7, + 2, + 6, + 10, + 4, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Cromemco CDOS - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "CRO4", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 3, + 7, + 2, + 6, + 10, + 4, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 3, + 7, + 2, + 6, + 10, + 4, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Cromemco CDOS - DSDD 8\u0022 - 512 x 16", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 608, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "CRO5", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 12, + 7, + 2, + 13, + 8, + 3, + 14, + 9, + 4, + 15, + 10, + 5, + 16, + 11, + 6 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 12, + 7, + 2, + 13, + 8, + 3, + 14, + 9, + 4, + 15, + 10, + 5, + 16, + 11, + 6 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Cromemco CP/M - SSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 94, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "CRO6", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 3, + 6, + 9, + 2, + 5, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Cromemco CP/M - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "CRO7", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 3, + 6, + 9, + 2, + 5, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 3, + 6, + 9, + 2, + 5, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Cykey - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 153, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "CYK1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Datavue DV80 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 94, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "DAT1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Datavue DV80 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "DAT2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Davidge - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 384, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DAV1", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "DEC DECMate II - SSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 195, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "DEC1", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "DEC VT-180 - SSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DEC3", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Dictaphone 6000 CP/M - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 352, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DIC1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 248, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Dictaphone 6000 CP/M - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 319, + "dsm": 345, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DIC2", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Digilog 2500 - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 35, + "drm": 63, + "dsm": 166, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "DIG1", + "ofs": 3, + "order": "EAGLE", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Digilog 1500 - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 392, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DIG2", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 248, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Digitech 500 series - SSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 319, + "dsm": 199, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "DIG3", + "ofs": 0, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 248, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Digitech 500 series - DSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 319, + "dsm": 398, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DIG4", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Digital Group, TVC-80 FDC - SSDD 8\u0022 - 1024 x 9", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 342, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DIG5", + "ofs": 1, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Dimension 68000 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 195, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "DIM1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Direct 1025 - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 152, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DIR1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Discovery - DSDD 96 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 313, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DIS1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Duet CP/M - DSDD 96tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 355, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DUE1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Eagle I, II - SSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 191, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "EAG1", + "ofs": 2, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Eagle III, IV, V - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 191, + "dsm": 394, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "EAG2", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Electroglas/Xynetics - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 158, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ELE1", + "ofs": 1, + "order": "EAGLE", + "sectorsPerTrack": 8, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Electroglas/Xynetics - DSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 397, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ELE2", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 10, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Epson QX-10 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "EPS1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Epson QX-10 (256 bytes/sector) - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 139, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "EPS2", + "ofs": 8, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Epson PX-10/8 - DSDD 3.5\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 139, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "EPS3", + "ofs": 8, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Epson QX-16 640K - DSDD 3.5\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 304, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "EPS4", + "ofs": 8, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 252, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Epson QX-16 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 389, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "EPS5", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "Ericsson DTC - SSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 77, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "ERI1", + "ofs": 2, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "Ericsson DTC - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 157, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "ERI2", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Ericsson Step One - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "ERI3", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Estimation Inc. EST101 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 394, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "EST1", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 63, + "bsh": 6, + "bytesPerSector": 1024, + "comment": "Everett/Charles Kryterion 165 - DSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "EVE1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Eureka A4 - DSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 399, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "EUR1", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 2, + 5, + 8, + 1, + 4, + 7, + 10, + 3, + 6, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 2, + 5, + 8, + 1, + 4, + 7, + 10, + 3, + 6, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Exidy Sorcerer - SSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 76, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "EXI1", + "ofs": 0, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 6, + 11, + 16, + 5, + 10, + 15, + 4, + 9, + 14, + 3, + 8, + 13, + 2, + 7, + 12 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 33 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "EXO - SSDD 8\u0022 - 512 x 16", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 149, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "EXO1", + "ofs": 2, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "EXO - DSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 303, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "EXO2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Florida Graphics - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 295, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "FLO1", + "ofs": 12, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Formula 1 - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 172, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "FOR1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 5, + 6, + 9, + 10, + 13, + 14, + 17, + 18, + 3, + 4, + 7, + 8, + 11, + 12, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 5, + 6, + 9, + 10, + 13, + 14, + 17, + 18, + 3, + 4, + 7, + 8, + 11, + 12, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Fujitsu Micro 8 - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "FUJ2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Future FX-20 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 95, + "dsm": 196, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "FUT1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 4 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Gemini Galaxy - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 196, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "GEM1", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Globe 101 - DSDD 96 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 319, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "GLO1", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 5, + "sofs": 13 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Gnat System 10 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 35, + "drm": 127, + "dsm": 169, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "GNA1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "Graco OM-5000 - DSHD 5.25\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 248, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "GRA1", + "ofs": 2, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Hagiwara HPU 801 CP/M 68K - DSDD 3.5\u0022 Special - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 486, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "HAG1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Hazeltine - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 379, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "HAZ1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "HCL System 2 - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 388, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "HCL1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Heath H89, Magnolia CP/M - SSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 95, + "dsm": 82, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "HEA1", + "ofs": 3, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 4, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Heath H89, Magnolia CP/M - DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 95, + "dsm": 172, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "HEA2", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Heath H89, Magnolia CP/M - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 176, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "HEA3", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Heurikon MLZ-91A - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 315, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "HEU1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 5, + 6, + 9, + 10, + 13, + 14, + 3, + 4, + 7, + 8, + 11, + 12, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 5, + 6, + 9, + 10, + 13, + 14, + 3, + 4, + 7, + 8, + 11, + 12, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Hewlett-Packard HP86/87/120/125 - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 251, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "HEW1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Hewlett Packard HP 125 - SSSD 8\u0022 - 256 x 16", + "complement": false, + "cylinders": 66, + "drm": 127, + "dsm": 251, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "HEW2", + "ofs": 3, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 6, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Hewlett Packard HP 125 - SSDD 3.5\u0022 - 256 x 16", + "complement": false, + "cylinders": 66, + "drm": 127, + "dsm": 251, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "HEW3", + "ofs": 3, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 6, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "Hitachi HPC-6000 CP/M 68K - DSHD 1.2M 3.5\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 242, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "HIT1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Hitachi R-1500 CP/M 68K - DSHD 1.2M 5.25\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 494, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "HIT2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Strippit Houdaille Fab/V - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "HOU1", + "ofs": 1, + "order": "CYLINDERS", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "IBM PC, CP/M-86 - SSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "IBM1", + "ofs": 1, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "IBM PC, CP/M-86 - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 157, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "IBM2", + "ofs": 1, + "order": "CYLINDERS", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "IBS Ultraframe Turbo DOS - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 397, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "IBS1", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "IBEX 7300 - DSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 246, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "IBX1", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "IBEX 7301 - DSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 242, + "encoding": "MFM", + "evenOdd": false, + "exm": 2, + "label": "IBX2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14, + 20, + 26, + 6, + 12, + 18, + 24, + 4, + 10, + 16, + 22 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14, + 20, + 26, + 6, + 12, + 18, + 24, + 4, + 10, + 16, + 22 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "ICL DRS 20 - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 158, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "ICL1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 6, + 11, + 16, + 5, + 10, + 15, + 4, + 9, + 14, + 3, + 8, + 13, + 2, + 7, + 12 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 6, + 11, + 16, + 5, + 10, + 15, + 4, + 9, + 14, + 3, + 8, + 13, + 2, + 7, + 12 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "ICL DRS 300 - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 350, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ICL2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "ICL Model 35/36 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 391, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ICL3", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 36 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "IMS 5000 - SSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 147, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "IMS1", + "ofs": 3, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 9, + 2, + 10, + 3, + 11, + 4, + 12, + 5, + 13, + 6, + 14, + 7, + 15, + 8, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "IMS 5000 TurboDOS - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 390, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "IMS2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "IMS 5000 TurboDOS - SSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 191, + "dsm": 308, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "IMS3", + "ofs": 0, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "IMS 5000 CP/M - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 395, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "IMS4", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Intel iPDS 100 - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 307, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "INT1", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 1024, + "comment": "Intuit - SSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 190, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "INT2", + "ofs": 2, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Insight Enterprises - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "INS1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Ithaca Intersystems - SSDD 96 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ITH1", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 5, + 6, + 9, + 10, + 13, + 14, + 17, + 18, + 3, + 4, + 7, + 8, + 11, + 12, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Ithaca Intersystems - SSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 191, + "dsm": 284, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ITH2", + "ofs": 1, + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Ithaca Intersystems - DSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 284, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ITH3", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "ITT 3030 - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 35, + "drm": 63, + "dsm": 247, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ITT1", + "ofs": 4, + "order": "CYLINDERS", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "ITT 3030 - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 70, + "drm": 127, + "dsm": 270, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ITT2", + "ofs": 4, + "order": "CYLINDERS", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Sel ITT 3030 - 70 Tracks 560 kB - 256 x 16", + "complement": false, + "cylinders": 70, + "drm": 127, + "dsm": 271, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ITT3030", + "ofs": 4, + "order": "EAGLE", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Jonos - SSDD 3.5\u0022 - 512 x 9", + "complement": false, + "cylinders": 70, + "drm": 63, + "dsm": 152, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "JON1", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Kaypro II/2 - SSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "KAY1", + "ofs": 1, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 4, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Kaypro 2X/4/10 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 196, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "KAY2", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Kaypro 2X/4/10 (Alternate) - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 196, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "KAY3", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Kaypro, Pro-8 ROM - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 95, + "dsm": 196, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "KAY4", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Kaypro Advent TurboROM - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 255, + "dsm": 195, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "KAY5", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 1024, + "comment": "Kaypro Advent TurboROM - SSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 31, + "dsm": 185, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "KAY6", + "ofs": 3, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Kaypro Advent TurboROM - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 395, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "KAY7", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 21, + 22, + 23, + 24, + 25 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Kontron - DSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 489, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "KON1", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22, + 25, + 3, + 6, + 9, + 12, + 15, + 18, + 21, + 24, + 2, + 5, + 8, + 11, + 14, + 17, + 20, + 23, + 26 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22, + 25, + 3, + 6, + 9, + 12, + 15, + 18, + 21, + 24, + 2, + 5, + 8, + 11, + 14, + 17, + 20, + 23, + 26 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 128, + "comment": "Kontron/Zeiss - DSDD 96 tpi 5.25\u0022 - 128 x 16", + "complement": false, + "cylinders": 35, + "drm": 63, + "dsm": 106, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "KON2", + "ofs": 17, + "order": "CYLINDERS", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Kontron Transient Recorder- DSDD 96 tpi 5.25\u0022/3.5\u0022 - 256 x 16", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 299, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "KON3", + "ofs": 4, + "order": "EAGLE", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Lanier LTD READ-ONLY - DSDD 96 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 318, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "LAN1", + "ofs": 1, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Lexoriter - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 159, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "LEX2", + "ofs": 0, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Lobo Max-80 - SSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 165, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "LOB1", + "ofs": 3, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Lobo Max-80 (256) - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 172, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "LOB2", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Lobo Max-80 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 191, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "LOB3", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Lobo Max-80 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 391, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "LOB4", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Lobo CP/M 2.2 - SSHD 8\u0022 - 256 x 30", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 280, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "LOB5", + "ofs": 2, + "sectorsPerTrack": 30, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "LNW 2 - SSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 82, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "LNW1", + "ofs": 3, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 6, + 11, + 16, + 3, + 8, + 13, + 18, + 5, + 10, + 15, + 2, + 7, + 12, + 17, + 4, + 9, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Lockheed-Martin Wire Harness Tester - DSDD 3.5\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 394, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "LOC1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Macsym 150 - SSDD 96 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MAC1", + "ofs": 2, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "MAI Basic Four - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 312, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "MAI1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Marconi Midata 510 - DSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 197, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "MAR1", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Memotech MaxBP - DSDD 3.5\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 191, + "dsm": 394, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "MEM1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Memotech FDX - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 156, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MEM2", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 26 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Micro Source M6000 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MIC6", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 3, + 7, + 2, + 6, + 10, + 4, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 11, + 15, + 19, + 13, + 17, + 12, + 16, + 20, + 14, + 18 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Michels and Kleberhoff CP/M 3 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 80, + "drm": 127, + "dsm": 394, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "MIC7", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Michels and Kleberhoff CP/M 3 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 35, + "drm": 63, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MIC8", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "MicroMint SB180 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 200, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MM7", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Molecular Series 9 - DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MOL1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 9, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Molecular/Durango Poppy 54 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 389, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "MOL2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Molecular - SSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 249, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MOL3", + "ofs": 0, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Monroe 8800 Series - SSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 153, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MON1", + "ofs": 3, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Monroe System 2000 - DSDD 96 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 315, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "MON2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Morrow MD2 - SSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 94, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MOR1", + "ofs": 2, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Morrow MD3, 5, 11, 16, 34 - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 191, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MOR2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Morrow TurboDOS - DSDD 48 tpi 5.25\u0022 - 1024 x 4", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "MOR6", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 4, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Morrow MD3...CP/M Plus - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MOR7", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Morrow 5/11/34 - SSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 92, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "MOR8", + "ofs": 3, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 4, + 2, + 5, + 3 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "MOS 80 - DSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 251, + "dsm": 244, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "MOS1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 10, + 19, + 2, + 11, + 20, + 3, + 12, + 21, + 4, + 13, + 22, + 5, + 14, + 23, + 6 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 10, + 19, + 2, + 11, + 20, + 3, + 12, + 21, + 4, + 13, + 22, + 5, + 14, + 23, + 6 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Multitech MIC-540 - DSDD 96 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 356, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "MUL1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "MUPD/MDISK, Side I - SSSD 96 tpi 5.25\u0022 - 256 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 96, + "encoding": "FM", + "evenOdd": false, + "exm": 1, + "label": "MUP1", + "ofs": 3, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 2, + 4, + 6, + 8, + 1, + 3, + 5, + 7, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "MUPD/MDISK, Side II - SSSD 96 tpi 5.25\u0022 - 256 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 96, + "encoding": "FM", + "evenOdd": false, + "exm": 1, + "label": "MUP2", + "ofs": 83, + "order": "EAGLE", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 2, + 4, + 6, + 8, + 1, + 3, + 5, + 7, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 2, + 4, + 6, + 8, + 1, + 3, + 5, + 7, + 9 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "MSD Systems PSC-1 POS - DSDD 96 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 158, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "MSD1", + "ofs": 1, + "order": "CYLINDERS", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 128, + "comment": "NCHQ System II - SSSD 48tpi 5.25\u0022 - 128 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 84, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "NCH1", + "ofs": 3, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 17, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "NCR Decision Mate V - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 153, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "NCR1", + "ofs": 3, + "order": "EAGLE", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "NCR FirstStep - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 275, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "NCR2", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 16, + 4, + 8, + 12, + 15, + 3, + 7, + 11, + 14, + 2, + 6, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 16, + 4, + 8, + 12, + 15, + 3, + 7, + 11, + 14, + 2, + 6, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "NEC PC-8801A - DSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 242, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "NEC2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 6, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "NEC PC-8801A - DSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 280, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "NEC3", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 6, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "NEC PC-8801A - DSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 599, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "NEC4", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "NEC PC-8001A - SSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "NEC5", + "ofs": 2, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "NEC PC-8001B - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "NEC6", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "NEC PC 8801A - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "NEC8", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "NEC PC 8801A - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "NEC9", + "ofs": 4, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "NEC PC 8500/8431A, Starlet - DSDD 3.5\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "NECA", + "ofs": 4, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "NEC APC CP/M-86 - DSHD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 494, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "NECC", + "ofs": 2, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22, + 25, + 2, + 5, + 8, + 11, + 14, + 17, + 20, + 23, + 26, + 3, + 6, + 9, + 12, + 15, + 18, + 21, + 24 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22, + 25, + 2, + 5, + 8, + 11, + 14, + 17, + 20, + 23, + 26, + 3, + 6, + 9, + 12, + 15, + 18, + 21, + 24 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "NEC APC TurboDOS - SSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 224, + "dsm": 308, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "NECD", + "ofs": 0, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "New Brain - SSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 97, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "NEW1", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "Niat - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 157, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "NIA1", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Nixdorf 8810/30 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 384, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "NIX1", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Norsonic 830/836 - DSDD 3.5\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 199, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "NOR1", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "Numeridex 7000 - DSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 248, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "NUM1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 28, + 34, + 40, + 46, + 52, + 32, + 38, + 44, + 50, + 30, + 36, + 42, + 48 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 1024, + "comment": "Octagon 8/16 - SSDD 8\u0022 - 1024 x 9", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 167, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "OCT1", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "OEM Screen Typist - SSDD 3.5\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 94, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "OEM1", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Olivetti ETV300 - SSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OLI1", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 17, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Olivetti M20 - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 255, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OLI2", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Olivetti 250, CWP1 - SSDD 3.5\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 157, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "OLI3", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Olivetti ETV 1010, CP/M 86 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 198, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "OLI5", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Olivetti ETV 112 - SSDD 3.5\u0022 - 256 x 18", + "complement": false, + "cylinders": 80, + "drm": 191, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OLI6", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 17, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Olympia EX-100 - DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "OLY1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Olympia ETX II - SSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OLY2", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Olympia Olytext 20 - DSDD 3.5\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 312, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OLY3", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Osborne 1 - SSSD 48 tpi 5.25\u0022 - 256 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 45, + "encoding": "FM", + "evenOdd": false, + "exm": 1, + "label": "OSB1", + "ofs": 3, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 1024, + "comment": "Osborne 1 - SSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 184, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OSB2", + "ofs": 3, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Osborne G2 System - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OSB4", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Osborne G2 System - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 389, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OSB5", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Osborne 1 \u002B Osmosis - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 384, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OSB6", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Osborne Nuevo - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "OSB7", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 6, + 8, + 10, + 7, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Osborne Vixen - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "OSB8", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 248, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Osborne Executive w/Z3 - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 395, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OSB9", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 248, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Osborne Executive Dig. Arts - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "OSBA", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Osborne Nuevo 2.1 - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 394, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OSBB", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "OSM Zeus 4 - DSDD 96 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 311, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OSM1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Otrona Attache - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 181, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "OTR1", + "ofs": 3, + "order": "EAGLE", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Otrona Attache - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 386, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "OTR2", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 128, + "comment": "Potter \u0026 Brumfield - SSSD 48 tpi 5.25\u0022 - 128 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 83, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "PB1", + "ofs": 3, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 17, + 3, + 7, + 11, + 15, + 2, + 6, + 10, + 14, + 18, + 4, + 8, + 12, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Pegasus Data Logger - DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PEG1", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 120, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "People\u0027s World Computer - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 398, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PEO1", + "ofs": 0, + "order": "CYLINDERS", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "People\u0027s World Computer Boot - SSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 397, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PEO2", + "ofs": 0, + "order": "CYLINDERS", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Pericom - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 395, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PER1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Philips PC-2010 - SSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PHI1", + "ofs": 2, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "Philips PC-2012 - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 157, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "PHI2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Philips PC-3000 - 3004 - SSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 147, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "PHI3", + "ofs": 3, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Physical Acoutstics - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 173, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "PHY1", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Pied Piper - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 391, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PIE1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Proglas 770K - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 388, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PRO1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Pulsar LBB - SSHD 8\u0022 - 512 x 17", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 317, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PUL1", + "ofs": 2, + "sectorsPerTrack": 17, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 2, + 5, + 8, + 11, + 14, + 17, + 3, + 6, + 9, + 12, + 15 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 128, + "comment": "Research Machines Limited 380Z - 128 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 74, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "RML1", + "ofs": 3, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Royal Alphatronic - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ROY1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Sage IV - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SAG1", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Sage IV - DSDD 96 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 315, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SAG2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Sanyo MBC-1000, MBC-1150 - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SAN1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Sanyo MBC-2000 - SSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 152, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SAN3", + "ofs": 4, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 6, + 11, + 16, + 5, + 10, + 15, + 4, + 9, + 14, + 3, + 8, + 13, + 2, + 7, + 12 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "Sanyo MBC-3000 - DSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 237, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "SAN4", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Sanco 8001 - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SAN5", + "ofs": 2, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Schneider CPC 6128 Side 1 - DSDD 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 180, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SCH1", + "ofs": 0, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Schneider CPC 6128 Side 2 - DSDD 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 180, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SCH2", + "ofs": 40, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "S.D. Systems 40 track - SSDD 3.5\u0022 - 256 x 18", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 84, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SDS1", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 256, + "comment": "S.D. Systems 80 track - DSDD 3.5\u0022 - 256 x 18", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 176, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SDS2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 18, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "S.D. Systems 80 track - SSDD 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 175, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SDS3", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "S.D. Systems - SSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 240, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SDS4", + "ofs": 3, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 17, + 21, + 25, + 3, + 7, + 11, + 15, + 19, + 23, + 2, + 6, + 10, + 14, + 18, + 22, + 26 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 1, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Seiko - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 315, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SEI1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "SemiDisk DT42 - DSHD 96 tpi 5.25\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 562, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SEM3", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 2, + 5, + 8, + 11, + 14, + 3, + 6, + 9, + 12, + 15 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 2, + 5, + 8, + 11, + 14, + 3, + 6, + 9, + 12, + 15 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Sharp MZ-80 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 40, + "drm": 127, + "dsm": 169, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SHA1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Sharp MZ-80B - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 40, + "drm": 127, + "dsm": 195, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SHA2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "sideId": 1 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Sharp 3500/5500 - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SHA3", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Sharp 5600 - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 312, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SHA4", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Sharp MZ 3541 - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SHA5", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Shelton SIG/NET 2 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 40, + "drm": 63, + "dsm": 195, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SHL2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Shelton SIG/NET 2 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 80, + "drm": 255, + "dsm": 395, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SHL3", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Siemens PG-685 DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 350, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SIE1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Siemens PG-675 DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SIE2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Silver-Reed WP System - DSDD 3.5\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SIL1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 2, + 4 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Smart Aleck - SSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SMA1", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 1024, + "comment": "Sorbus TurboDOS - 5.25\u0022 DSHD (or 8\u0022 DSDD) - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 308, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SOR1", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Sony SMC-70 - SSDD 3.5\u0022 - 256 x 16", + "complement": false, + "cylinders": 70, + "drm": 127, + "dsm": 135, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SON1", + "ofs": 2, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 3, + 6, + 9, + 12, + 15, + 2, + 5, + 8, + 11, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Spectravideo 318/328 - SSDD 48 tpi 5.25\u0022 - 256 x 17", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 156, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SPE1", + "ofs": 3, + "sectorsPerTrack": 17, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Spectravideo SV-328 - DSDD 48 tpi 5.25\u0022 - 256 x 17", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 162, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SPE2", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 17, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 1 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 252, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Sperry UTS 30, UTS 5000 - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 383, + "dsm": 354, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SPE2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Spectravideo - SSDD 48 tpi 5.25\u0022 - 256 x 17", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 157, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SPE3", + "ofs": 3, + "sectorsPerTrack": 17, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Spectravideo - DSDD 48 tpi 5.25\u0022 - 256 x 17", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 163, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SPE4", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 17, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Spectravideo - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 197, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SPE5", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Spectravideo - SSDD 3.5\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 163, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SPE6", + "ofs": 3, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Superbrain JR - SSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 35, + "drm": 63, + "dsm": 81, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SUP1", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Superbrain 40 track - SSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 40, + "drm": 63, + "dsm": 94, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SUP2", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Superbrain QD - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 35, + "drm": 63, + "dsm": 169, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SUP3", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Superbrain II - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": true, + "cylinders": 80, + "drm": 127, + "dsm": 196, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "SUP4", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 128, + "comment": "Superbrain - SSDD 48 tpi 5.25\u0022 - 128 x 30", + "complement": true, + "cylinders": 40, + "drm": 63, + "dsm": 142, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SUP5", + "ofs": 2, + "sectorsPerTrack": 30, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22, + 25, + 28, + 2, + 5, + 8, + 11, + 14, + 17, + 20, + 23, + 26, + 29 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 1024, + "comment": "System Group 2800 - DSDD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 303, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SYS1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Tarbell - DSDD 8\u0022 - 512 x 15", + "complement": false, + "cylinders": 77, + "drm": 169, + "dsm": 303, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TAR1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 15, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 12, + 13, + 14 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 12, + 13, + 14 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Tatung TPC2000 - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 354, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TAT1", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 248, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Techron TEF 10 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 319, + "dsm": 394, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TEC1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 3, + 6, + 9, + 2, + 5, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 3, + 6, + 9, + 2, + 5, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 255, + "al1": 240, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Techron TEF 12 - DSHD 96 tpi 5.25\u0022 - 512 x 17", + "complement": false, + "cylinders": 80, + "drm": 767, + "dsm": 670, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TEC2", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 17, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Tektronix 4170 - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 153, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TEK1", + "ofs": 1, + "order": "CYLINDERS", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Teletek - SSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 242, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TEL1", + "ofs": 2, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Teletek Systemaster - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 172, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TEL2", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 2, + 8, + 14, + 3, + 9, + 15, + 4, + 10, + 16, + 5, + 11, + 17, + 6, + 12, + 18 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 7, + 13, + 2, + 8, + 14, + 3, + 9, + 15, + 4, + 10, + 16, + 5, + 11, + 17, + 6, + 12, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Teletek Systemaster - DSDD 96 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 353, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TEL3", + "ofs": 3, + "order": "EAGLE", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 2, + 8, + 14, + 3, + 9, + 15, + 4, + 10, + 16, + 5, + 11, + 17, + 6, + 12, + 18 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 7, + 13, + 2, + 8, + 14, + 3, + 9, + 15, + 4, + 10, + 16, + 5, + 11, + 17, + 6, + 12, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "TeleVideo 8nn/TPC-1 CP/M - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TEL4", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 6, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "TeleVideo 1603 - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 354, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TEL5", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "TeleVideo 806 TurboDOS - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 200, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TEL6", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "TeleVideo 8nn TurboDOS - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TEL7", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 6, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Timex/Sinclair 2068\u002BAERCO FD-68 RP/M - DSDD 48 tpi 5.25\u0022 -1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TIM1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 63, + "bsh": 6, + "bytesPerSector": 1024, + "comment": "Tokyo Electron 80W - DSHD 3.5\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 160, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "TOK1", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Toshiba T100, T200 - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 255, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TOS1", + "ofs": 6, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 2, + 6, + 10, + 14, + 3, + 7, + 11, + 15, + 4, + 8, + 12, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Toshiba 300 - DSDD 96 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 318, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TOS2", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Toshiba T-250 - DSHD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 63, + "dsm": 487, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TOS3", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22, + 25, + 2, + 5, + 8, + 11, + 14, + 17, + 20, + 23, + 26, + 3, + 6, + 9, + 12, + 15, + 18, + 21, + 24 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 10, + 13, + 16, + 19, + 22, + 25, + 2, + 5, + 8, + 11, + 14, + 17, + 20, + 23, + 26, + 3, + 6, + 9, + 12, + 15, + 18, + 21, + 24 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Transtec - SSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TRA1", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 128, + "comment": "TRS-80 Model 1, Omikron CP/M - SSSD 48 tpi 5.25\u0022 - 128 x 18", + "complement": false, + "cylinders": 35, + "drm": 63, + "dsm": 71, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "TRS1", + "ofs": 3, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 13, + 17, + 3, + 7, + 11, + 15, + 2, + 6, + 10, + 14, + 18, + 4, + 8, + 12, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "TRS-80 Model 1, Bigmem CP/M - SSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 63, + "dsm": 243, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TRS2", + "ofs": 2, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 7, + 13, + 19, + 25, + 5, + 11, + 17, + 23, + 3, + 9, + 15, + 21, + 2, + 8, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "TRS-80 Model 1, ColorPower II - SSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TRS3", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "TRS-80, Pickles \u0026 Trout CP/M - SSDD 8\u0022 - 512 x 16", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 299, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TRS6", + "ofs": 2, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 4, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "TRS-80, Holmes CP/M - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 190, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TRS7", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "TRS-80, MM CP/M - SSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 94, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TRS8", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "TRS-80 Model 4, 4P; MT CP/M - SSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 84, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TRS9", + "ofs": 2, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 17, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "TRS-80 Model 4, 4P; MT CP/M - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TRSA", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 17, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 17, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "TRS-80 Model 4, 4P - SSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TRSB", + "ofs": 1, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 4, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "TRS-80 Model 4P-Montezuma800K - DSDD 96tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 399, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TRSD", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "TRS-80 II/12/16 Aton CP/M - DSHD 8\u0022 - 1024 x 8", + "complement": false, + "cylinders": 77, + "drm": 191, + "dsm": 608, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TRSF", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "TRS-80 II/12/16 Pickles \u0026 Trout - DSHD 8\u0022 - 512 x 16", + "complement": false, + "cylinders": 77, + "drm": 191, + "dsm": 608, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "TRSG", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 4, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "TRS-80 Model 4, Montezuma - DSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "TRSH", + "ofs": 2, + "order": "EAGLE", + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 17, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 11, + 13, + 15, + 17, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "U-Micro 1000 - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 395, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "UMI1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 96, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Varian Spectra AA/20, DS-15 - DSDD 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 317, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "VAR1", + "ofs": 0, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 2 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Vector 4 - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 356, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "VEC1", + "ofs": 1, + "order": "EAGLE", + "sectorsPerTrack": 9, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Visual 1050 - SSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "VIS1", + "ofs": 2, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Wangwriter - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "WAN1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 1024, + "comment": "Wave Mate Bullet - SSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 189, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "WAV1", + "ofs": 2, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Wave Mate Bullet - DSDD 96 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 394, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "WAV2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Wave Mate Bullet - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "WAV3", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Wave Mate Bullet - SSHD 8\u0022 - 1024 x 9", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 336, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "WAV4", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Xerox - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "XER1", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 128, + "comment": "Xerox 820 - SSSD 48 tpi 5.25\u0022 - 128 x 18", + "complement": false, + "cylinders": 40, + "drm": 31, + "dsm": 83, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "XER2", + "ofs": 3, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 6, + 11, + 16, + 3, + 8, + 13, + 18, + 5, + 10, + 15, + 2, + 7, + 12, + 17, + 4, + 9, + 14 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Xerox 820 II - SSDD 48 tpi 5.25\u0022 - 256 x 17", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 156, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "XER3", + "ofs": 3, + "sectorsPerTrack": 17, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Xerox 820-II, 16/8 - DSDD 48 tpi 5.25\u0022 - 256 x 17", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 162, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "XER4", + "ofs": 3, + "order": "EAGLE", + "sectorsPerTrack": 17, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Xerox 16/8 - SSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 242, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "XER5", + "ofs": 2, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "XEROX 16/8 - DSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 162, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "XER7", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 9, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Xerox 820, S/W Publishers DD - SSDD 48 tpi 5.25\u0022 - 256 x 18", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 166, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "XER8", + "ofs": 3, + "sectorsPerTrack": 18, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Xerox 3700 Laser Printer - DSDD 48 tpi 5.25\u0022 - 256 x 17", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 162, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "XER9", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 17, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Xerox 16/8, 820 II - SSDD 48 tpi 5.25\u0022", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 156, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "XERB", + "ofs": 3, + "sectorsPerTrack": 17, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Xerox 16/8 - SSDD 48 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "XERC", + "ofs": 2, + "sectorsPerTrack": 9, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Xerox 16/8 Special - SSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "XERD", + "ofs": 2, + "sectorsPerTrack": 8, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Xerox 16/8, 820-II - DSDD 48 tpi 5.25\u0022 - 256 x 17", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 162, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "XERE", + "ofs": 3, + "order": "EAGLE", + "sectorsPerTrack": 17, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Xerox 16/8 Special - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "XERF", + "ofs": 2, + "order": "CYLINDERS", + "sectorsPerTrack": 8, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Xerox 3700 Laser Printer - DSDD 48 tpi 5.25\u0022 - 256 x 17", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 162, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "XERG", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 17, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Xor 5 - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 191, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "XOR1", + "ofs": 3, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 6, + 2, + 7, + 3, + 8, + 4, + 9, + 5, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 6, + 2, + 7, + 3, + 8, + 4, + 9, + 5, + 10 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "XYZ - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "XYZ1", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 5, + 9, + 3, + 7, + 2, + 6, + 10, + 4, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 11, + 15, + 19, + 13, + 17, + 12, + 16, + 20, + 14, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Zeiss Video Analysis System - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 299, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZEI1", + "ofs": 4, + "order": "CYLINDERS", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Zenith Z-37 Disk - SSSD 48 tpi 5.25\u0022 - 256 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 91, + "encoding": "FM", + "evenOdd": false, + "exm": 0, + "label": "ZEN1", + "ofs": 3, + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Zenith Z-37 Disk - DSDD 96 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 315, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZEN2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Zenith Z89, Heath H89 - DSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 255, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZEN3", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Zenith Z90 - SSDD 48 tpi 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZEN5", + "ofs": 2, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Zenith Z-100 - SSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 151, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZEN7", + "ofs": 2, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Zenith Z-100 - DSDD 48 tpi 5.25\u0022 - 512 x 8", + "complement": false, + "cylinders": 40, + "drm": 255, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ZEN8", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Zenith Z-100 - SSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 127, + "dsm": 242, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ZENA", + "ofs": 2, + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 10, + 19, + 2, + 11, + 20, + 3, + 12, + 21, + 4, + 13, + 22, + 5, + 14, + 23, + 6 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Zenith Z-37 Disk - DSDD 96 (Half drive) 5.25\u0022 - 256 x 16", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZENB", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "Zenith/Heath H-89 Ext Density - DSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 255, + "dsm": 195, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZENC", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Zenith Z-100, Heath H-47 - DSDD 8\u0022 - 256 x 26", + "complement": false, + "cylinders": 77, + "drm": 255, + "dsm": 497, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZENE", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 26, + "side1": { + "sectorIds": [ + 1, + 10, + 19, + 2, + 11, + 20, + 3, + 12, + 21, + 4, + 13, + 22, + 5, + 14, + 23, + 6, + 15, + 24, + 7, + 16, + 25, + 8, + 17, + 26, + 9, + 18 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 10, + 19, + 2, + 11, + 20, + 3, + 12, + 21, + 4, + 13, + 22, + 5, + 14, + 23, + 6, + 15, + 24, + 7, + 16, + 25, + 8, + 17, + 26, + 9, + 18 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 1024, + "comment": "Zenith Z-37 - SSDD 48 tpi 5.25\u0022 - 1024 x 5", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 190, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZENF", + "ofs": 2, + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "HIGH", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Zenith/Heath H89/H90 Magnolia 7736 - SSHD 8\u0022 - 512 x 16", + "complement": false, + "cylinders": 77, + "drm": 191, + "dsm": 299, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZENH", + "ofs": 2, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Zorba - DSDD 48 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ZOR1", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Zorba - DSDD 96 tpi 5.25\u0022 - 512 x 10", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "ZOR2", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "PIC-DISK SSDD 96tpi 3.5\u0022", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 194, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "PIC1", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 3, + 5, + 7, + 9, + 2, + 4, + 6, + 8 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 1, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "SAM COUPE Pro-DOS - DSDD 160 tpi 3.5\u0022", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 356, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "A2", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Acorn CPM", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 200, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "ACPM", + "ofs": 3, + "order": "CYLINDERS", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "CPC 178K Data 40trk 9sct 64dir 1Kpb Side 2", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DA1B", + "ofs": 40, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 0 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "CPC 187K Data 42trk 9sct 64dir 1Kpb Side 2", + "complement": false, + "cylinders": 42, + "drm": 63, + "dsm": 188, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DA2B", + "ofs": 42, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 0 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "CPC-B360 358K Data 80trk 9sct 64dir 2Kpb Side 1", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "DA4A", + "ofs": 0, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 0 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "CPC-B360 358K Data 80trk 9sct 64dir 2Kpb Side 2", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "DA4B", + "ofs": 80, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 0 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "CPC 356K Data 40trk 9sct 128dir 2Kpb Two Sides", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "DAT5", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 0 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "DOBBERTIN 716K Data 80trk 9sct 128dir 4Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "DDOB", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 0 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 0 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "CPC-STD 169K System 40trk 9sct 64dir 1Kpb Side 1", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SY1A", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "CPC 169K System 40trk 9sct 64dir 1Kpb Side 2", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SY1B", + "ofs": 42, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "CPC 178K System 42trk 9sct 64dir 1Kpb Side 1", + "complement": false, + "cylinders": 42, + "drm": 63, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SY2A", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "CPC 178K System 42trk 9sct 64dir 1Kpb Side 2", + "complement": false, + "cylinders": 42, + "drm": 63, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SY2B", + "ofs": 44, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "CPC 253K System 60trk 9sct 64dir 1Kpb Side 1", + "complement": false, + "cylinders": 60, + "drm": 63, + "dsm": 254, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SY3A", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "CPC 253K System 60trk 9sct 64dir 1Kpb Side 2", + "complement": false, + "cylinders": 60, + "drm": 63, + "dsm": 254, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SY3B", + "ofs": 62, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "CPC-B360 348K System 80trk 9sct 64dir 2Kpb Side 1", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SY4A", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "CPC-B360 348K System 80trk 9sct 64dir 2Kpb Side 2", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SY4B", + "ofs": 82, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "CPC 346K System 40trk 9sct 128dir 2Kpb Two Sides", + "complement": false, + "cylinders": 40, + "drm": 127, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "SYS5", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 41 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "CPC 344K System 80trk 9sct 128dir 4Kpb Side 1", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 86, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "SY6A", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "CPC 344K System 80trk 9sct 128dir 4Kpb Side 2", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 86, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "SY6B", + "ofs": 82, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 5, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "DOBBERTIN 704K System 80trk 9sct 128dir 4Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 176, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "SDOB", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 41 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "ReadBIG 706K System 80trk 9sct 128dir 2Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 354, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "SBIG", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 41 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 41 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "CPC-STD 154K Ibm-Cpm86 40trk 8sct 64dir 1Kpb Side 1", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "IB1A", + "ofs": 1, + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "CPC 154K Ibm-Cpm86 40trk 8sct 64dir 1Kpb Side 2", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 155, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "IB1B", + "ofs": 41, + "order": "EAGLE", + "sectorsPerTrack": 8, + "side1": { + "sectorIds": [ + 1 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "PCW-STD 173K Format 40trk 9sct 64dir 1Kpb Side 1", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PC1A", + "ofs": 1, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "PCW 173K Format 40trk 9sct 64dir 1Kpb Side 2", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PC1B", + "ofs": 41, + "order": "EAGLE", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "PCW 346K Format 40trk 9sct 256dir 2Kpb Two Sides", + "complement": false, + "cylinders": 40, + "drm": 255, + "dsm": 176, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "PCW2", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "PCW 706K Format 80trk 9sct 256dir 2Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 356, + "evenOdd": false, + "exm": 0, + "label": "PCW3", + "ofs": 1, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "PCW 784K Format 80trk 10sct 256dir 4Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 197, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "DXT3", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "DiskPara3 796K Format 80trk 10sct 128dir 2Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 399, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DXT4", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "DiskPara 824K Format 83trk 10sct 192dir 2Kpb Two Sides", + "complement": false, + "cylinders": 83, + "drm": 191, + "dsm": 414, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "DXT5", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "sideId": 0 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "VORTEX 704K Format 80trk 9sct 128dir 4Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 176, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "VRTX", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "RAMDOS-D1 716K Format 80trk 9sct 128dir 2Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 359, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "RDD1", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "RAMDOS-D10 796K Format 80trk 10sct 128dir 2Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 399, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "RD10", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 11 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 11 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "RAMDOS-D2 712K Format 80trk 9sct 256dir 2Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 359, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "RDD2", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 21 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 21 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "RAMDOS-D20 792K Format 80trk 10sct 256dir 2Kpb Two Sides", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 399, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "RD20", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 31 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 31 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Amstrad ZX Spectrum \u002B3 - SSDD 64dir 1Kpb 180K - 173K user free", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZX0", + "ofs": 1, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Amstrad ZX Spectrum \u002B3 - DSDD 128dir 2Kpb 720K - 710K user free", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 356, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "ZX3", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 3, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Altos Series 5 - DSDD 96 tpi 5.25\u0022 - 512 x 9", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 176, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "ALT6", + "ofs": 64, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "PC1715 SCP (80*2* 5,1024 4 OFS 4k DIR) 5.25\u0022", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 389, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "A780", + "ofs": 4, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 224, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 1024, + "comment": "PC1715 CPA (80*2* 5,1024 0 OFS 6k DIR) 5.25\u0022", + "complement": false, + "cylinders": 80, + "drm": 191, + "dsm": 399, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "A800", + "ofs": 0, + "order": "SIDES", + "sectorsPerTrack": 5, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Amstrad PCW8256 - DSDD 48 tpi 5.25\u0022", + "complement": false, + "cylinders": 40, + "drm": 255, + "dsm": 356, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMS1", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Amstrad PCW8256 - SSDD 48 tpi 3\u0022 (JOYCE-SYSTEM)", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMS3", + "ofs": 1, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Amstrad CPC System - SSDD 48 tpi 3\u0022 or 5.25\u0022", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 170, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMS4", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Amstrad CPC-Data - SSDD 48 tpi 3\u0022 or 5.25\u0022", + "complement": false, + "cylinders": 40, + "drm": 63, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMS5", + "ofs": 0, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 5, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 512, + "comment": "Amstrad B360K - SSDD 96 tpi 5.25\u0022 SKEW 2", + "complement": false, + "cylinders": 80, + "drm": 63, + "dsm": 174, + "encoding": "MFM", + "evenOdd": false, + "exm": 1, + "label": "AMS6", + "ofs": 2, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Amstrad VORTEX - DSDD 96 tpi 5.25\u0022", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 176, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "AMS7", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Amstrad CPC System DSDD 96tpi 5.25\u0022 - DOBBERTIN -", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 176, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "AMS8", + "ofs": 2, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 128, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Amstrad DOBBERTIN DATA DSDD 96 tpi 5.25\u0022 Skew 5", + "complement": false, + "cylinders": 80, + "drm": 127, + "dsm": 179, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "AMS9", + "ofs": 0, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Amstrad PCW8256 - DSDD 96 tpi 5.25\u0022 10 x 512 788K", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 197, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "AMSA", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Amstrad PCW Joyce - SF2DD (824 kb - 256 entries)", + "complement": false, + "cylinders": 84, + "drm": 255, + "dsm": 208, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "SF2D", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 10, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 31, + "bsh": 5, + "bytesPerSector": 512, + "comment": "Amstrad PCW Joyce - 168 Track DD (740 kb - 256 entries)", + "complement": false, + "cylinders": 84, + "drm": 255, + "dsm": 187, + "encoding": "MFM", + "evenOdd": false, + "exm": 3, + "label": "168D", + "ofs": 1, + "order": "SIDES", + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 512, + "comment": "Extended CPC 3\u0022 43-track", + "complement": false, + "cylinders": 43, + "drm": 63, + "dsm": 193, + "encoding": "MFM", + "evenOdd": false, + "exm": 0, + "label": "AMS7", + "ofs": 0, + "sectorsPerTrack": 9, + "side1": { + "sectorIds": [ + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 2, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Apple // CPM card 13-sector", + "complement": false, + "cylinders": 35, + "drm": 47, + "dsm": 103, + "encoding": "GCR", + "evenOdd": false, + "exm": 0, + "label": "APL1", + "ofs": 3, + "sectorsPerTrack": 13, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 192, + "al1": 0, + "bitrate": "LOW", + "blm": 7, + "bsh": 3, + "bytesPerSector": 256, + "comment": "Apple // CPM card 16-sector", + "complement": false, + "cylinders": 35, + "drm": 63, + "dsm": 127, + "encoding": "GCR", + "evenOdd": false, + "exm": 0, + "label": "APL2", + "ofs": 3, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "sides": 1, + "skew": 0, + "sofs": 0 + }, + { + "al0": 240, + "al1": 0, + "bitrate": "LOW", + "blm": 15, + "bsh": 4, + "bytesPerSector": 256, + "comment": "Apple // CPM card special", + "complement": false, + "cylinders": 80, + "drm": 255, + "dsm": 313, + "encoding": "GCR", + "evenOdd": false, + "exm": 0, + "label": "APL3", + "ofs": 3, + "sectorsPerTrack": 16, + "side1": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 0 + }, + "side2": { + "sectorIds": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "sideId": 1 + }, + "sides": 2, + "skew": 0, + "sofs": 0 + } + ] +} \ No newline at end of file diff --git a/Aaru.Filesystems/CPM/cpmdefs.xml b/Aaru.Filesystems/CPM/cpmdefs.xml deleted file mode 100644 index 8652cb0c7..000000000 --- a/Aaru.Filesystems/CPM/cpmdefs.xml +++ /dev/null @@ -1,21849 +0,0 @@ - - - - - - Generic CP/M - SSSD 8" - 128 x 26 - FM - HIGH - 77 - 1 - 26 - 128 - 0 - - 0 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - 20 - 26 - 6 - 12 - 18 - 24 - 4 - 10 - 16 - 22 - - - - 3 - 7 - 0 - 242 - 63 - 192 - 0 - 2 - 0 - false - false - - - ABC-80 - SSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 1 - 16 - 256 - 0 - - 0 - - 1 - 8 - 15 - 6 - 13 - 4 - 11 - 2 - 9 - 16 - 7 - 14 - 5 - 12 - 3 - 10 - - - - 3 - 7 - 0 - 151 - 63 - 192 - 0 - 2 - 0 - false - false - - - A. B. Dick Magna III - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 0 - - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32 - - - SIDES - - 3 - 7 - 0 - 255 - 255 - 255 - 0 - 4 - 0 - false - false - - - Actrix (Access Matrix) - SSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 1 - 9 - 512 - 0 - - 0 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - - 3 - 7 - 0 - 170 - 63 - 192 - 0 - 2 - 0 - false - false - - - Actrix (Access Matrix) - DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 0 - - 1 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - - 1 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - SIDES - - 4 - 15 - 1 - 174 - 63 - 128 - 0 - 2 - 0 - false - false - - - Adler Textriter - SSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 1 - 16 - 256 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - - 3 - 7 - 0 - 159 - 31 - 128 - 0 - 0 - 0 - false - false - - - Advanced Digital Super 6 - SSDD 48 tpi 5.25" - 1024 x 4 - MFM - LOW - 40 - 1 - 4 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - - - - 4 - 15 - 0 - 77 - 63 - 128 - 0 - 1 - 0 - false - false - - - Advanced Digital Super 6 - DSDD 48 tpi 5.25" - 1024 x 4 - MFM - LOW - 40 - 2 - 4 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - - - - 0 - - 1 - 2 - 3 - 4 - - - SIDES - - 4 - 15 - 0 - 155 - 127 - 192 - 0 - 2 - 0 - false - false - - - Advanced Digital Super 6 - DSDD 96 tpi 5.25" - 1024 x 4 - MFM - LOW - 80 - 2 - 4 - 1024 - 2 - - 0 - - 1 - 2 - 3 - 4 - - - - 1 - - 1 - 2 - 3 - 4 - - - SIDES - - 4 - 15 - 0 - 300 - 127 - 192 - 0 - 2 - 0 - false - false - - - Advanced Digital Super 8 - DSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 2 - 8 - 1024 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 0 - 608 - 255 - 240 - 0 - 2 - 0 - false - false - - - Advanced Digital TurboDOS 312K - DSDD 48 tpi 5.25" - 1024 x 4 - MFM - LOW - 40 - 2 - 4 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - - - - 0 - - 1 - 2 - 3 - 4 - - - SIDES - - 4 - 15 - 1 - 155 - 127 - 192 - 0 - 2 - 0 - false - false - - - Advanced Digital TurboDOS 366K - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 1 - 182 - 127 - 192 - 0 - 6 - 0 - false - false - - - Advanced Controls - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 1 - 3 - 5 - 2 - 4 - - - SIDES - - 4 - 15 - 0 - 385 - 127 - 192 - 0 - 6 - 0 - false - false - - - Allen-Bradley Advisor+ - DSDD 3.5" - 512 x 8 - MFM - LOW - 80 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 0 - 318 - 127 - 192 - 0 - 0 - 1 - false - false - - - Alspa - SSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 1 - 8 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 4 - 15 - 0 - 300 - 127 - 192 - 0 - 2 - 0 - false - false - - - Altos - SSSD 8" - 128 x 26 - FM - HIGH - 77 - 1 - 26 - 128 - 0 - - 0 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - - - - 3 - 7 - 0 - 242 - 63 - 192 - 0 - 2 - 0 - false - false - - - Altos - DSSD 8" - 128 x 26 - FM - HIGH - 77 - 2 - 26 - 128 - 0 - - 0 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - 20 - 26 - 6 - 12 - 18 - 24 - 4 - 10 - 16 - 22 - - - - 1 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - 20 - 26 - 6 - 12 - 18 - 24 - 4 - 10 - 16 - 22 - - - SIDES - - 5 - 31 - 3 - 122 - 127 - 128 - 0 - 2 - 0 - false - false - - - Altos - SSDD 8" - 512 x 15 - MFM - HIGH - 77 - 1 - 15 - 512 - 5 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - - 5 - 31 - 3 - 139 - 127 - 128 - 0 - 2 - 0 - false - false - - - Altos - DSDD 8" - 512 x 15 - MFM - HIGH - 77 - 2 - 15 - 512 - 5 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - SIDES - - 5 - 31 - 1 - 284 - 255 - 192 - 0 - 2 - 0 - false - false - - - Altos Series 5 - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 5 - 31 - 3 - 176 - 176 - 192 - 0 - 2 - 0 - false - false - - - Amigo - SSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 1 - 10 - 512 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 3 - 7 - 0 - 189 - 63 - 192 - 0 - 2 - 0 - false - false - - - Amigo - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 0 - 195 - 63 - 128 - 0 - 2 - 0 - false - false - - - Ampro - SSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 1 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 4 - 15 - 1 - 94 - 63 - 128 - 0 - 2 - 0 - false - false - - - Ampro - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 2 - - 0 - - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - - - - 1 - - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - - - SIDES - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Ampro - SSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 1 - 5 - 1024 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Ampro - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 2 - - 0 - - 17 - 18 - 19 - 20 - 21 - - - - 1 - - 17 - 18 - 19 - 20 - 21 - - - SIDES - - 4 - 15 - 0 - 394 - 255 - 240 - 0 - 2 - 0 - false - false - - - Amstrad PCW 8256 - SSDD 48 tpi 3.00" - MFM - LOW - 40 - 1 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 3 - 7 - 0 - 175 - 63 - 192 - 0 - 1 - 0 - false - false - - - Amstrad PCW 8256 - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 356 - 255 - 240 - 0 - 1 - 0 - false - false - - - Amstrad CPC464 - SSDD 48 tpi 5.25"/3" - 512 x 9 - MFM - LOW - 40 - 1 - 9 - 512 - 5 - - 0 - - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - - - - 3 - 7 - 0 - 171 - 63 - 192 - 0 - 2 - 0 - false - false - - - Amstrad CPC464 - SSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 1 - 9 - 512 - 5 - - 0 - - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - - - - 5 - 31 - 3 - 87 - 127 - 128 - 0 - 2 - 0 - false - false - - - Amstrad PCW 8512 - DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 356 - 255 - 240 - 0 - 1 - 0 - false - false - - - Amstrad CPC 6128 - DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 0 - - 0 - - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - - - - 1 - - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - - - SIDES - - 4 - 15 - 1 - 175 - 127 - 192 - 0 - 2 - 0 - false - false - - - Amstrad CPC 6128 - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - - - - 1 - - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - - - SIDES - - 5 - 31 - 3 - 175 - 127 - 128 - 0 - 2 - 0 - false - false - - - Amstrad CPC 6128 Side 1 - SSDD 3.5" / 3" - 512 x 9 - MFM - LOW - 80 - 1 - 9 - 512 - 0 - - 0 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - - - - 3 - 7 - 0 - 180 - 63 - 192 - 0 - 0 - 0 - false - false - - - Amstrad CPC 6128 Side 2 - SSDD 3.5" / 3" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - - - - 0 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - - - - 3 - 7 - 0 - 180 - 63 - 192 - 0 - 80 - 0 - false - false - - - Amstrad PCW w/DU49, Moonstone XFORMAT - DSDD 3.5" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 5 - 31 - 3 - 198 - 255 - 192 - 0 - 1 - 0 - false - false - - - Amstrad CPC 6128 Vortex - DSDD 3.5"/96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 5 - 31 - 3 - 178 - 127 - 128 - 0 - 2 - 0 - false - false - - - Archive I - SSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 1 - 5 - 1024 - 0 - - 0 - - 1 - 4 - 2 - 5 - 3 - - - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Archive II & III - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 4 - 2 - 5 - 3 - - - - 1 - - 1 - 4 - 2 - 5 - 3 - - - SIDES - - 4 - 15 - 0 - 394 - 319 - 248 - 0 - 2 - 0 - false - true - - - Arisia - SSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 1 - 18 - 256 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - - 3 - 7 - 0 - 147 - 127 - 240 - 0 - 2 - 0 - false - false - - - Associate - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - - - SIDES - - 4 - 15 - 1 - 195 - 127 - 192 - 0 - 2 - 0 - false - false - - - Aster CT-80 - DSDD 96 tpi 5.25" - 1024 x 5, 3:1 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 0 - 1 - 2 - 3 - 4 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - - - SIDES - - 4 - 15 - 0 - 394 - 127 - 192 - 0 - 4 - 0 - false - false - - - ATR-8000 - SSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 1 - 5 - 1024 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 3 - 7 - 0 - 189 - 63 - 192 - 0 - 2 - 0 - false - false - - - ATR-8000 - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 0 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 1 - 189 - 127 - 192 - 0 - 4 - 0 - false - false - - - ATR-8000 - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - EAGLE - - 4 - 15 - 1 - 189 - 127 - 192 - 0 - 2 - 0 - false - false - - - ATT-7700 - DSDD 3.5" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - - 1 - - 17 - 19 - 21 - 23 - 25 - 27 - 29 - 31 - 18 - 20 - 22 - 24 - 26 - 28 - 30 - 32 - - - SIDES - - 4 - 15 - 0 - 316 - 127 - 192 - 0 - 2 - 0 - false - false - - - Avatar - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 5 - 9 - 3 - 7 - 2 - 6 - 10 - 4 - 8 - - - - 1 - - 1 - 5 - 9 - 3 - 7 - 2 - 6 - 10 - 4 - 8 - - - CYLINDERS - - 4 - 15 - 1 - 191 - 127 - 192 - 0 - 3 - 0 - false - false - - - Barudan - DSDD 3.5" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - - 1 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - SIDES - - 5 - 31 - 3 - 155 - 127 - 128 - 0 - 4 - 0 - false - false - - - Beehive - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Beehive Microbee - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 2 - 5 - 8 - 1 - 4 - 7 - 10 - 3 - 6 - 9 - - - - 1 - - 2 - 5 - 8 - 1 - 4 - 7 - 10 - 3 - 6 - 9 - - - SIDES - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Beehive Microbee - SSDD 3.5" - 512 x 10 - MFM - LOW - 80 - 1 - 10 - 512 - 0 - - 0 - - 2 - 5 - 8 - 1 - 4 - 7 - 10 - 3 - 6 - 9 - - - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Microbee Systems - DSDD 3.5" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 22 - 25 - 28 - 21 - 24 - 27 - 30 - 23 - 26 - 29 - - - - 0 - - 22 - 25 - 28 - 21 - 24 - 27 - 30 - 23 - 26 - 29 - - - SIDES - - 5 - 31 - 3 - 194 - 127 - 128 - 0 - 4 - 0 - false - false - - - Microbee Dreamdisk format - DSDD 3.5" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 2 - 5 - 8 - 1 - 4 - 7 - 10 - 3 - 6 - 9 - - - - 1 - - 2 - 5 - 8 - 1 - 4 - 7 - 10 - 3 - 6 - 9 - - - SIDES - - 4 - 15 - 0 - 391 - 255 - 240 - 0 - 2 - 0 - false - false - - - Computer Bell - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 1 - 192 - 127 - 192 - 0 - 3 - 0 - false - false - - - Big Board (512 bytes/sector) - SSDD 8" - 512 x 15 - MFM - HIGH - 77 - 1 - 15 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - - 4 - 15 - 0 - 280 - 127 - 192 - 0 - 2 - 0 - false - false - - - Big Board (512 bytes/sector) - DSDD 8" - 512 x 15 - MFM - HIGH - 77 - 2 - 15 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - CYLINDERS - - 4 - 15 - 0 - 569 - 127 - 192 - 0 - 2 - 0 - false - false - - - Big Board SWP 1024 bytes/sector - SSDD 8" - 1024 x 9 - MFM - HIGH - 77 - 1 - 9 - 1024 - 0 - - 4 - 15 - 0 - 336 - 127 - 192 - 0 - 2 - 0 - false - false - - - Bitelex - SSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 1 - 16 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - - 3 - 7 - 0 - 131 - 95 - 224 - 0 - 2 - 0 - false - false - - - BMC IF800 Model 20 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 7 - 13 - 19 - 5 - 11 - 17 - 3 - 9 - 15 - - - - 1 - - 1 - 7 - 13 - 19 - 5 - 11 - 17 - 3 - 9 - 15 - - - SIDES - - 4 - 15 - 0 - 191 - 127 - 192 - 0 - 3 - 0 - false - false - - - Bondwell 12 - SSDD 48 tpi 5.25" - 256 x 10 - MFM - LOW - 40 - 1 - 18 - 256 - 2 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 4 - 15 - 1 - 84 - 127 - 192 - 0 - 2 - 0 - false - false - - - Bondwell 14 - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 2 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - EAGLE - - 4 - 15 - 1 - 174 - 127 - 192 - 0 - 2 - 0 - false - false - - - Bondwell 2 - SSDD 3.5" - 256 x 18 - MFM - LOW - 80 - 1 - 18 - 256 - 2 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 4 - 15 - 1 - 174 - 127 - 192 - 0 - 2 - 0 - false - false - - - BOSS TurboDOS - DSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 2 - 8 - 1024 - 4 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 0 - 616 - 255 - 240 - 0 - 0 - 0 - false - false - - - BTI Systems - DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 2 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - EAGLE - - 4 - 15 - 1 - 175 - 127 - 192 - 0 - 2 - 0 - false - false - - - Burr-Brown - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 0 - - 0 - - 1 - 10 - 2 - 11 - 3 - 12 - 4 - 13 - 5 - 14 - 6 - 15 - 7 - 16 - 8 - 17 - 9 - 18 - - - - 1 - - 1 - 10 - 2 - 11 - 3 - 12 - 4 - 13 - 5 - 14 - 6 - 15 - 7 - 16 - 8 - 17 - 9 - 18 - - - SIDES - - 4 - 15 - 1 - 170 - 63 - 128 - 0 - 4 - 0 - false - false - - - Cal-PC - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Cashcom 100 - DSDD 96 tpi 5.25" - 1024 x 4 - MFM - LOW - 80 - 2 - 4 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - - - - 1 - - 1 - 2 - 3 - 4 - - - SIDES - - 4 - 15 - 0 - 303 - 127 - 192 - 0 - 2 - 0 - false - false - - - Commodore Business Machines 1581 drive - DSDD 3.5" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 0 - 397 - 127 - 192 - 0 - 0 - 0 - false - false - - - CCS (256 bytes/sector) - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 0 - - 0 - - 1 - 5 - 9 - 13 - 17 - 3 - 7 - 11 - 15 - 2 - 6 - 10 - 14 - 18 - 4 - 8 - 12 - 16 - - - - 0 - - 1 - 5 - 9 - 13 - 17 - 3 - 7 - 11 - 15 - 2 - 6 - 10 - 14 - 18 - 4 - 8 - 12 - 16 - - - SIDES - - 4 - 15 - 1 - 165 - 63 - 128 - 0 - 6 - 0 - false - false - - - CCS (512 bytes/sector) - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 4 - 7 - 10 - 3 - 6 - 9 - 2 - 5 - 8 - - - - 0 - - 1 - 4 - 7 - 10 - 3 - 6 - 9 - 2 - 5 - 8 - - - SIDES - - 4 - 15 - 1 - 184 - 63 - 128 - 0 - 6 - 0 - false - false - - - CCS (1024 bytes/sector) - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 0 - - 1 - 3 - 5 - 2 - 4 - - - SIDES - - 4 - 15 - 1 - 184 - 63 - 128 - 0 - 6 - 0 - false - false - - - CCS 8 - DSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 2 - 8 - 1024 - 0 - - 0 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - - - - 1 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - - - SIDES - - 6 - 63 - 7 - 149 - 127 - 128 - 0 - 4 - 0 - false - false - - - CCS 2442 - SSDD 8" - 512 x 15 - MFM - HIGH - 77 - 1 - 15 - 512 - 0 - - 0 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - - - - 5 - 31 - 3 - 139 - 127 - 128 - 0 - 2 - 0 - false - false - - - CCS (1024 bytes alternate) - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 1 - 3 - 5 - 2 - 4 - - - SIDES - - 4 - 15 - 1 - 184 - 63 - 128 - 0 - 6 - 0 - false - false - - - CDC-110 Viking - DSDD 8" - 512 x 16 - MFM - HIGH - 77 - 2 - 16 - 512 - 0 - - 0 - - 0 - 4 - 8 - 12 - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - - - - 1 - - 0 - 4 - 8 - 12 - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - - - SIDES - - 4 - 15 - 0 - 608 - 255 - 240 - 0 - 2 - 0 - false - false - - - CDI-5000 - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 4 - 2 - 5 - 3 - - - - 1 - - 1 - 4 - 2 - 5 - 3 - - - SIDES - - 4 - 15 - 1 - 194 - 63 - 128 - 0 - 2 - 0 - false - false - - - COLEX 850 - SSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 1 - 10 - 512 - 0 - - 0 - - 1 - 5 - 9 - 3 - 7 - 2 - 6 - 10 - 4 - 8 - - - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - COLEX 850 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 5 - 9 - 3 - 7 - 2 - 6 - 10 - 4 - 8 - - - - 1 - - 11 - 15 - 19 - 13 - 17 - 12 - 16 - 20 - 14 - 18 - - - SIDES - - 4 - 15 - 0 - 389 - 127 - 192 - 0 - 4 - 0 - false - false - - - CMC Supersystem 2 - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 391 - 127 - 192 - 0 - 3 - 0 - false - false - - - Coin - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 0 - - 1 - 2 - 3 - 4 - 5 - - - EAGLE - - 4 - 15 - 0 - 392 - 127 - 192 - 0 - 3 - 0 - false - false - - - Coleco ADAM, 40 track - SSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 1 - 8 - 512 - 0 - - 0 - - 1 - 6 - 3 - 8 - 5 - 2 - 7 - 4 - - - - 3 - 7 - 0 - 146 - 63 - 192 - 0 - 0 - 26 - false - false - - - Coleco ADAM, 254K - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 0 - - 0 - - 1 - 6 - 3 - 8 - 5 - 2 - 7 - 4 - - - - 0 - - 1 - 6 - 3 - 8 - 5 - 2 - 7 - 4 - - - EAGLE - - 3 - 7 - 0 - 255 - 63 - 192 - 0 - 0 - 26 - false - false - - - Coleco ADAM, 320K - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 0 - - 0 - - 1 - 6 - 3 - 8 - 5 - 2 - 7 - 4 - - - - 0 - - 1 - 6 - 3 - 8 - 5 - 2 - 7 - 4 - - - EAGLE - - 4 - 15 - 1 - 152 - 63 - 128 - 0 - 0 - 26 - false - false - - - Coleco ADAM, 720K - DSDD 3.5" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 5 - 9 - 4 - 8 - 3 - 7 - 2 - 6 - - - - 0 - - 1 - 5 - 9 - 4 - 8 - 3 - 7 - 2 - 6 - - - SIDES - - 4 - 15 - 0 - 354 - 127 - 192 - 0 - 0 - 26 - false - false - - - Coleco ADAM, 360K - DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 0 - - 0 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - - 1 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - SIDES - - 4 - 15 - 1 - 179 - 63 - 128 - 0 - 0 - 4 - false - false - - - Coleco ADAM, E&T PROM 720K - DSDD 3.5" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 5 - 9 - 4 - 8 - 3 - 7 - 2 - 6 - - - - 1 - - 1 - 5 - 9 - 4 - 8 - 3 - 7 - 2 - 6 - - - SIDES - - 4 - 15 - 0 - 354 - 127 - 192 - 0 - 0 - 26 - false - false - - - Coleco ADAM, 720K - DSDD 3.5" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 5 - 9 - 4 - 8 - 3 - 7 - 2 - 6 - - - - 0 - - 1 - 5 - 9 - 4 - 8 - 3 - 7 - 2 - 6 - - - SIDES - - 4 - 15 - 0 - 358 - 127 - 192 - 0 - 0 - 4 - false - false - - - Coleco ADAM, 1.44M - DSHD 3.5" - 512 x 18 - MFM - HIGH - 80 - 2 - 18 - 512 - 0 - - 0 - - 15 - 2 - 6 - 10 - 14 - 18 - 4 - 8 - 12 - 16 - 1 - 5 - 9 - 13 - 17 - 3 - 7 - 11 - - - - 1 - - 1 - 5 - 9 - 13 - 17 - 3 - 7 - 11 - 15 - 2 - 6 - 10 - 14 - 18 - 4 - 8 - 12 - 16 - - - SIDES - - 4 - 15 - 0 - 712 - 255 - 240 - 0 - 2 - 0 - false - false - - - Coleco Adam TDOS - DSDD 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 0 - - 0 - - 1 - 6 - 3 - 8 - 5 - 2 - 7 - 4 - - - - 1 - - 1 - 6 - 3 - 8 - 5 - 2 - 7 - 4 - - - EAGLE - - 3 - 7 - 0 - 255 - 63 - 192 - 0 - 0 - 26 - false - false - - - Columbia Commander 964 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - COLUMBIA - - 4 - 15 - 1 - 190 - 63 - 128 - 0 - 2 - 0 - false - false - - - Columbia 1600 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - COLUMBIA - - 5 - 31 - 3 - 197 - 255 - 192 - 0 - 2 - 0 - false - false - - - Columbia M64 - SSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 1 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 3 - 7 - 0 - 190 - 127 - 240 - 0 - 2 - 0 - true - false - - - Compis - DSDD 96 tpi 5.25" - 512 x 8 - MFM - LOW - 80 - 2 - 8 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - CYLINDERS - - 4 - 15 - 0 - 317 - 127 - 192 - 0 - 1 - 0 - false - false - - - Compugraphic MCS-5 - SSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 1 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 3 - 7 - 0 - 155 - 63 - 192 - 0 - 1 - 0 - false - false - - - Compustar Model 30 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 35 - 2 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - EAGLE - - 4 - 15 - 1 - 169 - 63 - 128 - 0 - 2 - 0 - true - false - - - Compupro (Viasyn) - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 1 - 3 - 5 - 2 - 4 - - - SIDES - - 4 - 15 - 0 - 389 - 255 - 240 - 0 - 4 - 0 - false - false - - - Compupro (Viasyn) 8/16 - SSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 1 - 8 - 1024 - 0 - - 0 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - - - - 4 - 15 - 0 - 299 - 127 - 192 - 0 - 2 - 0 - false - false - - - Compupro (Viasyn) 8/16 - DSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 2 - 8 - 1024 - 0 - - 0 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - - - - 1 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - - - SIDES - - 4 - 15 - 0 - 599 - 255 - 240 - 0 - 4 - 0 - false - false - - - Compupro (Viasyn) - SSDD 8" - 512 x 15 - MFM - HIGH - 77 - 1 - 15 - 512 - 0 - - 0 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - - - - 4 - 15 - 0 - 280 - 127 - 192 - 0 - 2 - 0 - false - false - - - Compupro (Viasyn) - SSDD 8" - 256 x 26 - MFM - HIGH - 77 - 1 - 26 - 256 - 0 - - 0 - - 1 - 10 - 19 - 2 - 11 - 20 - 3 - 12 - 21 - 4 - 13 - 22 - 5 - 14 - 23 - 6 - - - - 4 - 15 - 0 - 242 - 127 - 192 - 0 - 2 - 0 - false - false - - - Compupro (Viasyn) 256 bytes/sector - DSHD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 10 - 19 - 2 - 11 - 20 - 3 - 12 - 21 - 4 - 13 - 22 - 5 - 14 - 23 - 6 - - - - 1 - - 1 - 10 - 19 - 2 - 11 - 20 - 3 - 12 - 21 - 4 - 13 - 22 - 5 - 14 - 23 - 6 - - - - 4 - 15 - 0 - 487 - 255 - 240 - 0 - 4 - 0 - false - false - - - CPT Phoenix CP/M - DSDD 3.5" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - - 1 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - SIDES - - 4 - 15 - 0 - 355 - 255 - 240 - 0 - 2 - 0 - false - false - - - Cromemco CDOS - SSSD 48 tpi 5.25" - 128 x 18 - FM - LOW - 40 - 1 - 18 - 128 - 0 - - 0 - - 1 - 6 - 11 - 16 - 3 - 8 - 13 - 18 - 5 - 10 - 15 - 2 - 7 - 12 - 17 - 4 - 9 - 14 - - - - 3 - 7 - 0 - 82 - 63 - 192 - 0 - 3 - 0 - false - false - - - Cromemco CDOS - DSSD 48 tpi 5.25" - 128 x 18 - FM - LOW - 40 - 2 - 128 - 18 - 0 - - 0 - - 1 - 6 - 11 - 16 - 3 - 8 - 13 - 18 - 5 - 10 - 15 - 2 - 7 - 12 - 17 - 4 - 9 - 14 - - - - 1 - - 1 - 6 - 11 - 16 - 3 - 8 - 13 - 18 - 5 - 10 - 15 - 2 - 7 - 12 - 17 - 4 - 9 - 14 - - - SIDES - - 3 - 7 - 0 - 172 - 63 - 192 - 0 - 3 - 0 - false - false - - - Cromemco CDOS - SSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 1 - 10 - 512 - 0 - - 0 - - 1 - 5 - 9 - 3 - 7 - 2 - 6 - 10 - 4 - 8 - - - - 3 - 7 - 0 - 189 - 63 - 192 - 0 - 2 - 0 - false - false - - - Cromemco CDOS - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 5 - 9 - 3 - 7 - 2 - 6 - 10 - 4 - 8 - - - - 1 - - 1 - 5 - 9 - 3 - 7 - 2 - 6 - 10 - 4 - 8 - - - SIDES - - 4 - 15 - 0 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Cromemco CDOS - DSDD 8" - 512 x 16 - MFM - HIGH - 77 - 2 - 16 - 512 - 0 - - 0 - - 1 - 12 - 7 - 2 - 13 - 8 - 3 - 14 - 9 - 4 - 15 - 10 - 5 - 16 - 11 - 6 - - - - 1 - - 1 - 12 - 7 - 2 - 13 - 8 - 3 - 14 - 9 - 4 - 15 - 10 - 5 - 16 - 11 - 6 - - - SIDES - - 4 - 15 - 0 - 608 - 255 - 240 - 0 - 2 - 0 - false - false - - - Cromemco CP/M - SSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 1 - 10 - 512 - 0 - - 0 - - 1 - 4 - 7 - 10 - 3 - 6 - 9 - 2 - 5 - 8 - - - - 4 - 15 - 1 - 94 - 127 - 192 - 0 - 2 - 0 - false - false - - - Cromemco CP/M - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 4 - 7 - 10 - 3 - 6 - 9 - 2 - 5 - 8 - - - - 1 - - 1 - 4 - 7 - 10 - 3 - 6 - 9 - 2 - 5 - 8 - - - SIDES - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Cykey - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 0 - - 0 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - 16 - - - - 1 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - 16 - - - SIDES - - 4 - 15 - 1 - 153 - 63 - 192 - 0 - 3 - 0 - false - false - - - Datavue DV80 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 3 - - 0 - - 129 - 130 - 131 - 132 - 133 - 134 - 135 - 136 - 137 - 138 - - - - 1 - - 129 - 130 - 131 - 132 - 133 - 134 - 135 - 136 - 137 - 138 - - - SIDES - - 5 - 31 - 3 - 94 - 127 - 128 - 0 - 4 - 0 - false - false - - - Datavue DV80 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 3 - - 0 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - 202 - - - - 1 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - 202 - - - SIDES - - 5 - 31 - 3 - 194 - 127 - 128 - 0 - 4 - 0 - false - false - - - Davidge - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 1 - 3 - 5 - 2 - 4 - - - SIDES - - 4 - 15 - 0 - 384 - 127 - 192 - 0 - 6 - 0 - false - false - - - DEC DECMate II - SSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 1 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 4 - 15 - 1 - 195 - 127 - 192 - 0 - 2 - 0 - false - false - - - DEC VT-180 - SSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 1 - 9 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - - - - 3 - 7 - 0 - 170 - 63 - 192 - 0 - 2 - 0 - false - false - - - Dictaphone 6000 CP/M - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - - - SIDES - - 4 - 15 - 0 - 352 - 127 - 192 - 0 - 3 - 0 - false - false - - - Dictaphone 6000 CP/M - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - - 1 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - SIDES - - 4 - 15 - 0 - 345 - 319 - 248 - 0 - 6 - 0 - false - false - - - Digilog 2500 - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 35 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 0 - - 1 - 2 - 3 - 4 - 5 - - - EAGLE - - 4 - 15 - 1 - 166 - 63 - 128 - 0 - 3 - 0 - false - false - - - Digilog 1500 - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - CYLINDERS - - 4 - 15 - 0 - 392 - 127 - 192 - 0 - 3 - 0 - false - false - - - Digitech 500 series - SSDD 3.5" - 512 x 10 - MFM - LOW - 80 - 1 - 10 - 512 - 0 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 4 - 15 - 1 - 199 - 319 - 248 - 0 - 0 - 0 - false - false - - - Digitech 500 series - DSDD 3.5" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 398 - 319 - 248 - 0 - 0 - 0 - false - false - - - Digital Group, TVC-80 FDC - SSDD 8" - 1024 x 9 - MFM - HIGH - 77 - 1 - 9 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 4 - 15 - 0 - 342 - 127 - 192 - 0 - 1 - 0 - false - false - - - Dimension 68000 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 2 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 1 - 195 - 63 - 128 - 0 - 2 - 0 - false - false - - - Direct 1025 - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 0 - 152 - 127 - 192 - 0 - 3 - 0 - false - false - - - Discovery - DSDD 96 tpi 5.25" - 512 x 8 - MFM - LOW - 80 - 2 - 8 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 0 - 313 - 127 - 192 - 0 - 3 - 0 - false - false - - - Duet CP/M - DSDD 96tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - - - SIDES - - 4 - 15 - 0 - 355 - 255 - 240 - 0 - 2 - 0 - false - false - - - Eagle I, II - SSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 1 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 4 - 15 - 1 - 194 - 191 - 224 - 0 - 2 - 0 - false - false - - - Eagle III, IV, V - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 1 - 3 - 5 - 2 - 4 - - - EAGLE - - 4 - 15 - 0 - 394 - 191 - 224 - 0 - 2 - 0 - false - false - - - Electroglas/Xynetics - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 3 - EAGLE - - 4 - 15 - 1 - 158 - 63 - 128 - 0 - 1 - 0 - false - false - - - Electroglas/Xynetics - DSDD 3.5" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 3 - SIDES - - 4 - 15 - 0 - 397 - 255 - 240 - 0 - 1 - 0 - false - false - - - Epson QX-10 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 5 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 1 - 189 - 127 - 192 - 0 - 4 - 0 - false - false - - - Epson QX-10 (256 bytes/sector) - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 1 - 139 - 63 - 128 - 0 - 8 - 0 - false - false - - - Epson PX-10/8 - DSDD 3.5" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 1 - 139 - 63 - 128 - 0 - 8 - 0 - false - false - - - Epson QX-16 640K - DSDD 3.5" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 0 - 304 - 127 - 192 - 0 - 8 - 0 - false - false - - - Epson QX-16 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 0 - 389 - 255 - 252 - 0 - 4 - 0 - false - false - - - Ericsson DTC - SSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 1 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 5 - 31 - 3 - 77 - 127 - 128 - 0 - 2 - 0 - false - false - - - Ericsson DTC - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - CYLINDERS - - 5 - 31 - 3 - 157 - 127 - 128 - 0 - 2 - 0 - false - false - - - Ericsson Step One - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 5 - 31 - 3 - 174 - 127 - 128 - 0 - 4 - 0 - false - false - - - Estimation Inc. EST101 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - EAGLE - - 4 - 15 - 0 - 394 - 255 - 240 - 0 - 2 - 0 - false - false - - - Everett/Charles Kryterion 165 - DSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 2 - 8 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 6 - 63 - 3 - 151 - 255 - 192 - 0 - 2 - 0 - false - false - - - Eureka A4 - DSDD 3.5" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 2 - 5 - 8 - 1 - 4 - 7 - 10 - 3 - 6 - 9 - - - - 1 - - 2 - 5 - 8 - 1 - 4 - 7 - 10 - 3 - 6 - 9 - - - SIDES - - 4 - 15 - 0 - 399 - 255 - 240 - 0 - 0 - 0 - false - false - - - Exidy Sorcerer - SSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 1 - 16 - 256 - 0 - - 0 - - 1 - 6 - 11 - 16 - 5 - 10 - 15 - 4 - 9 - 14 - 3 - 8 - 13 - 2 - 7 - 12 - - - - 4 - 15 - 0 - 76 - 63 - 192 - 0 - 0 - 33 - false - false - - - EXO - SSDD 8" - 512 x 16 - MFM - HIGH - 77 - 1 - 16 - 512 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 5 - 31 - 3 - 149 - 127 - 128 - 0 - 2 - 0 - false - false - - - EXO - DSDD 8" - 512 x 15 - MFM - HIGH - 77 - 2 - 15 - 512 - 5 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - SIDES - - 5 - 31 - 1 - 303 - 127 - 128 - 0 - 2 - 0 - false - false - - - Florida Graphics - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 2 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - SIDES - - 4 - 15 - 0 - 295 - 127 - 192 - 0 - 12 - 0 - false - false - - - Formula 1 - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 0 - - 0 - - 1 - 2 - 5 - 6 - 9 - 10 - 13 - 14 - 17 - 18 - 3 - 4 - 7 - 8 - 11 - 12 - 15 - 16 - - - - 1 - - 1 - 2 - 5 - 6 - 9 - 10 - 13 - 14 - 17 - 18 - 3 - 4 - 7 - 8 - 11 - 12 - 15 - 16 - - - SIDES - - 4 - 15 - 1 - 172 - 127 - 192 - 0 - 3 - 0 - false - false - - - Fujitsu Micro 8 - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 1 - 151 - 127 - 192 - 0 - 4 - 0 - false - false - - - Future FX-20 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 4 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 5 - 31 - 3 - 196 - 95 - 128 - 0 - 2 - 0 - false - false - - - Gemini Galaxy - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - EAGLE - - 5 - 31 - 3 - 196 - 127 - 128 - 0 - 2 - 0 - false - false - - - Globe 101 - DSDD 96 tpi 5.25" - 512 x 8 - MFM - LOW - 80 - 2 - 8 - 512 - 5 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 0 - 319 - 127 - 192 - 0 - 0 - 13 - false - false - - - Gnat System 10 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 35 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - - - SIDES - - 4 - 15 - 0 - 169 - 127 - 192 - 0 - 2 - 0 - false - false - - - Graco OM-5000 - DSHD 5.25" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 5 - 31 - 3 - 248 - 127 - 128 - 0 - 2 - 0 - false - false - - - Hagiwara HPU 801 CP/M 68K - DSDD 3.5" Special - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - - - SIDES - - 4 - 15 - 0 - 486 - 127 - 192 - 0 - 4 - 0 - false - false - - - Hazeltine - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 77 - 2 - 10 - 512 - 5 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 0 - 379 - 255 - 240 - 0 - 2 - 0 - false - false - - - HCL System 2 - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 388 - 255 - 240 - 0 - 4 - 0 - false - false - - - Heath H89, Magnolia CP/M - SSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 1 - 9 - 512 - 4 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 4 - 15 - 1 - 82 - 95 - 192 - 0 - 3 - 0 - false - false - - - Heath H89, Magnolia CP/M - DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 4 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - CYLINDERS - - 4 - 15 - 1 - 172 - 95 - 192 - 0 - 3 - 0 - false - false - - - Heath H89, Magnolia CP/M - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 4 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - CYLINDERS - - 5 - 31 - 3 - 176 - 127 - 128 - 0 - 3 - 0 - false - false - - - Heurikon MLZ-91A - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 5 - 6 - 9 - 10 - 13 - 14 - 3 - 4 - 7 - 8 - 11 - 12 - 15 - 16 - - - - 1 - - 1 - 2 - 5 - 6 - 9 - 10 - 13 - 14 - 3 - 4 - 7 - 8 - 11 - 12 - 15 - 16 - - - SIDES - - 4 - 15 - 0 - 315 - 127 - 192 - 0 - 2 - 0 - false - false - - - Hewlett-Packard HP86/87/120/125 - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 4 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - SIDES - - 3 - 7 - 0 - 251 - 127 - 240 - 0 - 3 - 0 - false - false - - - Hewlett Packard HP 125 - SSSD 8" - 256 x 16 - FM - HIGH - 66 - 1 - 16 - 256 - 6 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - - 3 - 7 - 0 - 251 - 127 - 240 - 0 - 3 - 0 - false - false - - - Hewlett Packard HP 125 - SSDD 3.5" - 256 x 16 - MFM - LOW - 66 - 1 - 16 - 256 - 6 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - - 3 - 7 - 0 - 251 - 127 - 240 - 0 - 3 - 0 - false - false - - - Hitachi HPC-6000 CP/M 68K - DSHD 1.2M 3.5" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - - - SIDES - - 5 - 31 - 3 - 242 - 127 - 128 - 0 - 4 - 0 - false - false - - - Hitachi R-1500 CP/M 68K - DSHD 1.2M 5.25" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - - - SIDES - - 4 - 15 - 0 - 494 - 127 - 192 - 0 - 2 - 0 - false - false - - - Strippit Houdaille Fab/V - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - CYLINDERS - - 4 - 15 - 0 - 174 - 63 - 128 - 0 - 1 - 0 - false - false - - - IBM PC, CP/M-86 - SSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 1 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 3 - 7 - 0 - 155 - 63 - 192 - 0 - 1 - 0 - false - false - - - IBM PC, CP/M-86 - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - CYLINDERS - - 4 - 15 - 1 - 157 - 63 - 128 - 0 - 1 - 0 - false - false - - - IBS Ultraframe Turbo DOS - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 397 - 255 - 240 - 0 - 0 - 0 - false - false - - - IBEX 7300 - DSDD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 5 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - CYLINDERS - - 5 - 31 - 3 - 246 - 127 - 128 - 0 - 2 - 0 - false - false - - - IBEX 7301 - DSDD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - 20 - 26 - 6 - 12 - 18 - 24 - 4 - 10 - 16 - 22 - - - - 1 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - 20 - 26 - 6 - 12 - 18 - 24 - 4 - 10 - 16 - 22 - - - SIDES - - 5 - 31 - 2 - 242 - 127 - 128 - 0 - 4 - 0 - false - false - - - ICL DRS 20 - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 6 - 11 - 16 - 5 - 10 - 15 - 4 - 9 - 14 - 3 - 8 - 13 - 2 - 7 - 12 - - - - 1 - - 1 - 6 - 11 - 16 - 5 - 10 - 15 - 4 - 9 - 14 - 3 - 8 - 13 - 2 - 7 - 12 - - - SIDES - - 5 - 31 - 3 - 158 - 255 - 192 - 0 - 2 - 0 - false - false - - - ICL DRS 300 - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 350 - 127 - 192 - 0 - 4 - 0 - false - false - - - ICL Model 35/36 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 0 - 391 - 127 - 192 - 0 - 0 - 36 - false - false - - - IMS 5000 - SSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 1 - 16 - 256 - 0 - - 0 - - 1 - 9 - 2 - 10 - 3 - 11 - 4 - 12 - 5 - 13 - 6 - 14 - 7 - 15 - 8 - 16 - - - - 3 - 7 - 0 - 147 - 63 - 192 - 0 - 3 - 0 - false - false - - - IMS 5000 TurboDOS - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 390 - 127 - 192 - 0 - 4 - 0 - false - false - - - IMS 5000 TurboDOS - SSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 1 - 8 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 4 - 15 - 0 - 308 - 191 - 224 - 0 - 0 - 0 - false - false - - - IMS 5000 CP/M - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 0 - - 1 - 2 - 3 - 4 - 5 - - - CYLINDERS - - 4 - 15 - 0 - 395 - 255 - 240 - 0 - 2 - 0 - false - false - - - Intel iPDS 100 - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 4 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 0 - 307 - 255 - 240 - 0 - 6 - 0 - false - false - - - Intuit - SSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 1 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 3 - 7 - 0 - 190 - 127 - 240 - 0 - 2 - 0 - false - false - - - Insight Enterprises - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 1 - 155 - 63 - 128 - 0 - 2 - 0 - false - false - - - Ithaca Intersystems - SSDD 96 tpi 5.25" - 256 x 18 - MFM - LOW - 80 - 1 - 18 - 256 - 2 - - 0 - - 1 - 2 - 5 - 6 - 9 - 10 - 13 - 14 - 17 - 18 - 3 - 4 - 7 - 8 - 11 - 12 - 15 - 16 - - - - 4 - 15 - 1 - 174 - 127 - 192 - 0 - 2 - 0 - false - false - - - Ithaca Intersystems - SSDD 8" - 512 x 15 - MFM - HIGH - 77 - 1 - 15 - 512 - 0 - - 0 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - - - - 4 - 15 - 0 - 284 - 191 - 224 - 0 - 1 - 0 - false - false - - - Ithaca Intersystems - DSDD 8" - 512 x 15 - MFM - HIGH - 77 - 2 - 15 - 512 - 0 - - 0 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - - - - 1 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - - - SIDES - - 5 - 31 - 1 - 284 - 255 - 192 - 0 - 1 - 0 - false - false - - - ITT 3030 - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 35 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - CYLINDERS - - 3 - 7 - 0 - 247 - 63 - 192 - 0 - 4 - 0 - false - false - - - ITT 3030 - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 70 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - CYLINDERS - - 4 - 15 - 0 - 270 - 127 - 192 - 0 - 4 - 0 - false - false - - - Sel ITT 3030 - 70 Tracks 560 kB - 256 x 16 - MFM - LOW - 70 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - EAGLE - - 4 - 15 - 0 - 271 - 127 - 192 - 0 - 4 - 0 - false - false - - - Jonos - SSDD 3.5" - 512 x 9 - MFM - LOW - 70 - 1 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 4 - 15 - 1 - 152 - 63 - 128 - 0 - 2 - 0 - false - false - - - Kaypro II/2 - SSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 1 - 10 - 512 - 4 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 3 - 7 - 0 - 194 - 63 - 240 - 0 - 1 - 0 - false - false - - - Kaypro 2X/4/10 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 4 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 0 - - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - - - SIDES - - 4 - 15 - 1 - 196 - 63 - 192 - 0 - 1 - 0 - false - false - - - Kaypro 2X/4/10 (Alternate) - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 4 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - - - SIDES - - 4 - 15 - 1 - 196 - 63 - 192 - 0 - 1 - 0 - false - false - - - Kaypro, Pro-8 ROM - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 4 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 0 - - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - - - SIDES - - 5 - 31 - 3 - 196 - 95 - 128 - 0 - 2 - 0 - false - false - - - Kaypro Advent TurboROM - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 11 - 12 - 13 - 14 - 15 - - - SIDES - - 4 - 15 - 1 - 195 - 255 - 240 - 0 - 2 - 0 - false - false - - - Kaypro Advent TurboROM - SSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 1 - 5 - 1024 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 3 - 7 - 0 - 185 - 31 - 192 - 0 - 3 - 0 - false - false - - - Kaypro Advent TurboROM - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 21 - 22 - 23 - 24 - 25 - - - SIDES - - 4 - 15 - 0 - 395 - 255 - 240 - 0 - 2 - 0 - false - false - - - Kontron - DSDD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 19 - 22 - 25 - 3 - 6 - 9 - 12 - 15 - 18 - 21 - 24 - 2 - 5 - 8 - 11 - 14 - 17 - 20 - 23 - 26 - - - - 1 - - 1 - 4 - 7 - 10 - 13 - 16 - 19 - 22 - 25 - 3 - 6 - 9 - 12 - 15 - 18 - 21 - 24 - 2 - 5 - 8 - 11 - 14 - 17 - 20 - 23 - 26 - - - CYLINDERS - - 4 - 15 - 0 - 489 - 255 - 240 - 0 - 3 - 0 - false - false - - - Kontron/Zeiss - DSDD 96 tpi 5.25" - 128 x 16 - FM - LOW - 35 - 2 - 16 - 128 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - CYLINDERS - - 3 - 7 - 0 - 106 - 63 - 192 - 0 - 17 - 0 - false - false - - - Kontron Transient Recorder- DSDD 96 tpi 5.25"/3.5" - 256 x 16 - MFM - LOW - 77 - 2 - 16 - 256 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - - 1 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - EAGLE - - 4 - 15 - 0 - 299 - 255 - 240 - 0 - 4 - 0 - false - false - - - Lanier LTD READ-ONLY - DSDD 96 tpi 5.25" - 512 x 8 - MFM - LOW - 80 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 4 - 15 - 0 - 318 - 127 - 192 - 0 - 1 - 0 - false - false - - - Lexoriter - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - - 1 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - - 4 - 15 - 1 - 159 - 127 - 192 - 0 - 0 - 0 - false - false - - - Lobo Max-80 - SSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 1 - 18 - 256 - 2 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 3 - 7 - 0 - 165 - 63 - 192 - 0 - 3 - 0 - false - false - - - Lobo Max-80 (256) - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 2 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - SIDES - - 4 - 15 - 0 - 172 - 127 - 192 - 0 - 3 - 0 - false - false - - - Lobo Max-80 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 2 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 191 - 127 - 192 - 0 - 3 - 0 - false - false - - - Lobo Max-80 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 2 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 391 - 255 - 240 - 0 - 3 - 0 - false - false - - - Lobo CP/M 2.2 - SSHD 8" - 256 x 30 - MFM - HIGH - 77 - 1 - 30 - 256 - 3 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - - - - 4 - 15 - 0 - 280 - 127 - 192 - 0 - 2 - 0 - false - false - - - LNW 2 - SSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 1 - 18 - 256 - 0 - - 0 - - 1 - 6 - 11 - 16 - 3 - 8 - 13 - 18 - 5 - 10 - 15 - 2 - 7 - 12 - 17 - 4 - 9 - 14 - - - - 4 - 15 - 1 - 82 - 63 - 128 - 0 - 3 - 0 - false - false - - - Lockheed-Martin Wire Harness Tester - DSDD 3.5" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 4 - 2 - 5 - 3 - - - - 1 - - 1 - 4 - 2 - 5 - 3 - - - SIDES - - 4 - 15 - 0 - 394 - 127 - 192 - 0 - 2 - 0 - false - false - - - Macsym 150 - SSDD 96 tpi 5.25" - 512 x 8 - MFM - LOW - 80 - 1 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 4 - 15 - 1 - 155 - 127 - 192 - 0 - 2 - 0 - false - false - - - MAI Basic Four - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 0 - 312 - 127 - 192 - 0 - 3 - 0 - false - false - - - Marconi Midata 510 - DSDD 3.5" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 3 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - EAGLE - - 5 - 31 - 3 - 197 - 127 - 128 - 0 - 2 - 0 - false - false - - - Memotech MaxBP - DSDD 3.5" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 394 - 191 - 224 - 0 - 2 - 0 - false - false - - - Memotech FDX - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 1 - 156 - 63 - 128 - 0 - 0 - 26 - false - false - - - Micro Source M6000 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 5 - 9 - 3 - 7 - 2 - 6 - 10 - 4 - 8 - - - - 0 - - 11 - 15 - 19 - 13 - 17 - 12 - 16 - 20 - 14 - 18 - - - SIDES - - 4 - 15 - 1 - 189 - 127 - 192 - 0 - 4 - 0 - false - false - - - Michels and Kleberhoff CP/M 3 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - EAGLE - - 4 - 15 - 0 - 394 - 127 - 192 - 0 - 2 - 0 - true - false - - - Michels and Kleberhoff CP/M 3 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 35 - 2 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - CYLINDERS - - 4 - 15 - 1 - 194 - 63 - 128 - 0 - 2 - 0 - true - false - - - MicroMint SB180 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - - - - 1 - - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - - - SIDES - - 4 - 15 - 1 - 200 - 127 - 192 - 0 - 0 - 0 - false - false - - - Molecular Series 9 - DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 2 - SIDES - - 4 - 15 - 1 - 179 - 127 - 192 - 0 - 4 - 0 - false - false - - - Molecular/Durango Poppy 54 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 3 - - 0 - - 128 - 129 - 130 - 131 - 132 - 133 - 134 - 135 - 136 - 137 - - - - 1 - - 138 - 139 - 140 - 141 - 142 - 143 - 144 - 145 - 146 - 147 - - - SIDES - - 4 - 15 - 0 - 389 - 127 - 192 - 0 - 4 - 0 - false - false - - - Molecular - SSDD 8" - 256 x 26 - MFM - HIGH - 77 - 1 - 26 - 256 - 0 - - 0 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - - - - 4 - 15 - 1 - 249 - 127 - 192 - 0 - 0 - 0 - false - false - - - Monroe 8800 Series - SSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 1 - 16 - 256 - 0 - - 0 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - 16 - - - - 4 - 15 - 1 - 153 - 63 - 128 - 0 - 3 - 0 - false - false - - - Monroe System 2000 - DSDD 96 tpi 5.25" - 512 x 8 - MFM - LOW - 80 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 0 - 315 - 127 - 192 - 0 - 2 - 0 - false - false - - - Morrow MD2 - SSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 1 - 5 - 1024 - 0 - - 0 - - 1 - 4 - 2 - 5 - 3 - - - - 4 - 15 - 1 - 94 - 127 - 192 - 0 - 2 - 0 - false - false - - - Morrow MD3, 5, 11, 16, 34 - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 4 - 2 - 5 - 3 - - - - 1 - - 1 - 4 - 2 - 5 - 3 - - - SIDES - - 4 - 15 - 1 - 194 - 191 - 224 - 0 - 2 - 0 - false - false - - - Morrow TurboDOS - DSDD 48 tpi 5.25" - 1024 x 4 - MFM - LOW - 40 - 2 - 4 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - - - - 1 - - 1 - 2 - 3 - 4 - - - SIDES - - 4 - 15 - 0 - 155 - 127 - 192 - 0 - 2 - 0 - false - false - - - Morrow MD3...CP/M Plus - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 4 - 2 - 5 - 3 - - - - 1 - - 1 - 4 - 2 - 5 - 3 - - - SIDES - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Morrow 5/11/34 - SSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 1 - 5 - 1024 - 0 - - 0 - - 1 - 4 - 2 - 5 - 3 - - - - 4 - 15 - 1 - 92 - 127 - 192 - 0 - 3 - 0 - false - false - - - MOS 80 - DSDD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 10 - 19 - 2 - 11 - 20 - 3 - 12 - 21 - 4 - 13 - 22 - 5 - 14 - 23 - 6 - - - - 1 - - 1 - 10 - 19 - 2 - 11 - 20 - 3 - 12 - 21 - 4 - 13 - 22 - 5 - 14 - 23 - 6 - - - SIDES - - 5 - 31 - 0 - 244 - 251 - 192 - 0 - 3 - 0 - false - false - - - Multitech MIC-540 - DSDD 96 tpi 5.25" - 256 x 18 - MFM - LOW - 80 - 2 - 18 - 256 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - SIDES - - 4 - 15 - 0 - 356 - 127 - 192 - 0 - 4 - 0 - false - false - - - MUPD/MDISK, Side I - SSSD 96 tpi 5.25" - 256 x 10 - FM - LOW - 80 - 1 - 10 - 256 - 0 - - 0 - - 0 - 2 - 4 - 6 - 8 - 1 - 3 - 5 - 7 - 9 - - - - 4 - 15 - 1 - 96 - 127 - 192 - 0 - 3 - 0 - false - false - - - MUPD/MDISK, Side II - SSSD 96 tpi 5.25" - 256 x 10 - FM - LOW - 80 - 2 - 10 - 256 - 0 - - 0 - - 0 - 2 - 4 - 6 - 8 - 1 - 3 - 5 - 7 - 9 - - - - 0 - - 0 - 2 - 4 - 6 - 8 - 1 - 3 - 5 - 7 - 9 - - - EAGLE - - 4 - 15 - 1 - 96 - 127 - 192 - 0 - 83 - 0 - false - false - - - MSD Systems PSC-1 POS - DSDD 96 tpi 5.25" - 512 x 8 - MFM - LOW - 80 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - CYLINDERS - - 5 - 31 - 3 - 158 - 127 - 128 - 0 - 1 - 0 - false - false - - - NCHQ System II - SSSD 48tpi 5.25" - 128 x 18 - FM - LOW - 40 - 1 - 18 - 128 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 17 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - 18 - - - - 3 - 7 - 0 - 84 - 63 - 192 - 0 - 3 - 0 - false - false - - - NCR Decision Mate V - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - EAGLE - - 4 - 15 - 1 - 153 - 127 - 192 - 0 - 3 - 0 - false - false - - - NCR FirstStep - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 5 - 9 - 13 - 16 - 4 - 8 - 12 - 15 - 3 - 7 - 11 - 14 - 2 - 6 - 10 - - - - 1 - - 1 - 5 - 9 - 13 - 16 - 4 - 8 - 12 - 15 - 3 - 7 - 11 - 14 - 2 - 6 - 10 - - - SIDES - - 4 - 15 - 0 - 275 - 255 - 240 - 0 - 6 - 0 - false - false - - - NEC PC-8801A - DSDD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 6 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - - - SIDES - - 5 - 31 - 3 - 242 - 127 - 128 - 0 - 4 - 0 - false - false - - - NEC PC-8801A - DSDD 8" - 512 x 15 - MFM - HIGH - 77 - 2 - 15 - 512 - 6 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - - - SIDES - - 5 - 31 - 1 - 280 - 127 - 128 - 0 - 4 - 0 - false - false - - - NEC PC-8801A - DSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 2 - 8 - 1024 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 0 - 599 - 255 - 240 - 0 - 4 - 0 - false - false - - - NEC PC-8001A - SSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 1 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 3 - 7 - 0 - 151 - 63 - 192 - 0 - 2 - 0 - false - false - - - NEC PC-8001B - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 1 - 151 - 63 - 128 - 0 - 2 - 0 - false - false - - - NEC PC 8801A - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 1 - 151 - 127 - 192 - 0 - 4 - 0 - false - false - - - NEC PC 8801A - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - - 4 - 15 - 1 - 189 - 127 - 192 - 0 - 4 - 0 - false - false - - - NEC PC 8500/8431A, Starlet - DSDD 3.5" - 256 x 16 - MFM - LOW - 80 - 1 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 4 - 15 - 1 - 151 - 127 - 192 - 0 - 4 - 0 - false - false - - - NEC APC CP/M-86 - DSHD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 19 - 22 - 25 - 2 - 5 - 8 - 11 - 14 - 17 - 20 - 23 - 26 - 3 - 6 - 9 - 12 - 15 - 18 - 21 - 24 - - - - 1 - - 1 - 4 - 7 - 10 - 13 - 16 - 19 - 22 - 25 - 2 - 5 - 8 - 11 - 14 - 17 - 20 - 23 - 26 - 3 - 6 - 9 - 12 - 15 - 18 - 21 - 24 - - - - 4 - 15 - 0 - 494 - 255 - 240 - 0 - 2 - 0 - false - false - - - NEC APC TurboDOS - SSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 1 - 8 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 4 - 15 - 0 - 308 - 224 - 224 - 0 - 0 - 0 - false - false - - - New Brain - SSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 1 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 5 - 31 - 3 - 97 - 127 - 128 - 0 - 2 - 0 - false - false - - - Niat - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - 16 - - - - 1 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - 16 - - - CYLINDERS - - 5 - 31 - 3 - 157 - 127 - 128 - 0 - 2 - 0 - false - false - - - Nixdorf 8810/30 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 0 - 384 - 127 - 192 - 0 - 6 - 0 - false - false - - - Norsonic 830/836 - DSDD 3.5" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 199 - 127 - 192 - 0 - 0 - 0 - false - false - - - Numeridex 7000 - DSDD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - - - - 1 - - 28 - 34 - 40 - 46 - 52 - 32 - 38 - 44 - 50 - 30 - 36 - 42 - 48 - - - SIDES - - 5 - 31 - 3 - 248 - 127 - 128 - 0 - 2 - 0 - false - false - - - Octagon 8/16 - SSDD 8" - 1024 x 9 - MFM - HIGH - 77 - 1 - 9 - 1024 - 3 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 5 - 31 - 1 - 167 - 127 - 128 - 0 - 2 - 0 - false - false - - - OEM Screen Typist - SSDD 3.5" - 512 x 10 - MFM - LOW - 40 - 1 - 10 - 512 - 0 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 4 - 15 - 1 - 94 - 63 - 128 - 0 - 2 - 0 - false - false - - - Olivetti ETV300 - SSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 1 - 18 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 17 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - 18 - - - - 3 - 7 - 0 - 170 - 63 - 192 - 0 - 2 - 0 - false - false - - - Olivetti M20 - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 3 - 7 - 0 - 255 - 63 - 192 - 0 - 3 - 0 - false - false - - - Olivetti 250, CWP1 - SSDD 3.5" - 256 x 16 - MFM - LOW - 80 - 1 - 16 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - SIDES - - 4 - 15 - 1 - 157 - 63 - 128 - 0 - 1 - 0 - false - false - - - Olivetti ETV 1010, CP/M 86 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 1 - 198 - 127 - 192 - 0 - 1 - 0 - false - false - - - Olivetti ETV 112 - SSDD 3.5" - 256 x 18 - MFM - LOW - 80 - 1 - 18 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 17 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - 18 - - - - 4 - 15 - 0 - 174 - 191 - 224 - 0 - 2 - 0 - false - false - - - Olympia EX-100 - DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 1 - 174 - 127 - 192 - 0 - 2 - 0 - false - false - - - Olympia ETX II - SSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 1 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 3 - 7 - 0 - 170 - 127 - 240 - 0 - 2 - 0 - false - false - - - Olympia Olytext 20 - DSDD 3.5" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 0 - 312 - 127 - 192 - 0 - 4 - 0 - false - false - - - Osborne 1 - SSSD 48 tpi 5.25" - 256 x 10 - FM - LOW - 40 - 1 - 10 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 4 - 15 - 1 - 45 - 63 - 128 - 0 - 3 - 0 - false - false - - - Osborne 1 - SSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 1 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 3 - 7 - 0 - 184 - 63 - 192 - 0 - 3 - 0 - false - false - - - Osborne G2 System - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 0 - 189 - 127 - 192 - 0 - 4 - 0 - false - false - - - Osborne G2 System - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 0 - 389 - 255 - 240 - 0 - 4 - 0 - false - false - - - Osborne 1 + Osmosis - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - SIDES - - 4 - 15 - 0 - 384 - 127 - 192 - 0 - 6 - 0 - false - false - - - Osborne Nuevo - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 6 - 8 - 10 - 7 - 9 - - - SIDES - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Osborne Vixen - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 1 - 3 - 5 - 2 - 4 - - - SIDES - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Osborne Executive w/Z3 - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 1 - 3 - 5 - 2 - 4 - - - SIDES - - 4 - 15 - 0 - 395 - 127 - 248 - 0 - 2 - 0 - false - false - - - Osborne Executive Dig. Arts - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 1 - 3 - 5 - 2 - 4 - - - SIDES - - 4 - 15 - 1 - 194 - 127 - 248 - 0 - 2 - 0 - false - false - - - Osborne Nuevo 2.1 - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 394 - 255 - 240 - 0 - 2 - 0 - false - false - - - OSM Zeus 4 - DSDD 96 tpi 5.25" - 512 x 8 - MFM - LOW - 80 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 0 - 311 - 127 - 192 - 0 - 4 - 0 - false - false - - - Otrona Attache - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - EAGLE - - 4 - 15 - 1 - 181 - 127 - 192 - 0 - 3 - 0 - false - false - - - Otrona Attache - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - CYLINDERS - - 4 - 15 - 0 - 386 - 127 - 192 - 0 - 3 - 0 - false - false - - - Potter & Brumfield - SSSD 48 tpi 5.25" - 128 x 18 - FM - LOW - 40 - 1 - 18 - 128 - 0 - - 0 - - 1 - 5 - 9 - 13 - 17 - 3 - 7 - 11 - 15 - 2 - 6 - 10 - 14 - 18 - 4 - 8 - 12 - 16 - - - - 3 - 7 - 0 - 83 - 63 - 192 - 0 - 3 - 0 - false - false - - - Pegasus Data Logger - DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 0 - - 0 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - - 1 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - 9 - - - SIDES - - 4 - 15 - 0 - 170 - 63 - 128 - 0 - 6 - 0 - false - false - - - People's World Computer - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - CYLINDERS - - 4 - 15 - 0 - 398 - 127 - 120 - 0 - 0 - 0 - false - false - - - People's World Computer Boot - SSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - CYLINDERS - - 4 - 15 - 0 - 397 - 127 - 240 - 0 - 0 - 0 - false - false - - - Pericom - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 0 - - 1 - 3 - 5 - 2 - 4 - - - SIDES - - 4 - 15 - 0 - 395 - 127 - 192 - 0 - 2 - 0 - false - false - - - Philips PC-2010 - SSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 1 - 16 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - - 3 - 7 - 0 - 151 - 63 - 192 - 0 - 2 - 0 - false - false - - - Philips PC-2012 - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - SIDES - - 5 - 31 - 3 - 157 - 127 - 128 - 0 - 2 - 0 - false - false - - - Philips PC-3000 - 3004 - SSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 1 - 16 - 256 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - - 4 - 15 - 1 - 147 - 63 - 192 - 0 - 3 - 0 - false - false - - - Physical Acoutstics - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 3 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - CYLINDERS - - 4 - 15 - 1 - 173 - 127 - 192 - 0 - 3 - 0 - false - false - - - Pied Piper - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - SIDES - - 4 - 15 - 0 - 391 - 255 - 240 - 0 - 3 - 0 - false - false - - - Proglas 770K - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 0 - 388 - 255 - 240 - 0 - 2 - 0 - false - false - - - Pulsar LBB - SSHD 8" - 512 x 17 - MFM - HIGH - 77 - 1 - 17 - 512 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 2 - 5 - 8 - 11 - 14 - 17 - 3 - 6 - 9 - 12 - 15 - - - - 4 - 15 - 0 - 317 - 127 - 192 - 0 - 2 - 0 - false - false - - - Research Machines Limited 380Z - 128 x 16 - FM - LOW - 40 - 1 - 16 - 128 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - - 3 - 7 - 0 - 74 - 63 - 192 - 0 - 3 - 0 - false - false - - - Royal Alphatronic - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 1 - 151 - 127 - 192 - 0 - 4 - 0 - false - false - - - Sage IV - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - CYLINDERS - - 4 - 15 - 1 - 155 - 63 - 128 - 0 - 2 - 0 - false - false - - - Sage IV - DSDD 96 tpi 5.25" - 512 x 8 - MFM - LOW - 80 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 0 - 315 - 63 - 128 - 0 - 2 - 0 - false - false - - - Sanyo MBC-1000, MBC-1150 - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - - 1 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - SIDES - - 4 - 15 - 1 - 155 - 63 - 128 - 0 - 2 - 0 - false - false - - - Sanyo MBC-2000 - SSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 1 - 16 - 256 - 0 - - 0 - - 1 - 6 - 11 - 16 - 5 - 10 - 15 - 4 - 9 - 14 - 3 - 8 - 13 - 2 - 7 - 12 - - - - 4 - 15 - 1 - 152 - 63 - 128 - 0 - 4 - 0 - false - false - - - Sanyo MBC-3000 - DSDD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - - - - 1 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - - - SIDES - - 5 - 31 - 3 - 237 - 127 - 128 - 0 - 4 - 0 - false - false - - - Sanco 8001 - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 1 - 3 - 5 - 2 - 4 - - - - 4 - 15 - 0 - 194 - 63 - 128 - 0 - 2 - 0 - false - false - - - Schneider CPC 6128 Side 1 - DSDD 5.25" - 512 x 9 - MFM - LOW - 40 - 1 - 9 - 512 - 2 - - 0 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - - - - 3 - 7 - 0 - 180 - 63 - 192 - 0 - 0 - 0 - false - false - - - Schneider CPC 6128 Side 2 - DSDD 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 0 - - 0 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - - - - 0 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - - - - 3 - 7 - 0 - 180 - 63 - 192 - 0 - 40 - 0 - false - false - - - S.D. Systems 40 track - SSDD 3.5" - 256 x 18 - MFM - LOW - 80 - 1 - 18 - 256 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - - 4 - 15 - 0 - 84 - 127 - 192 - 0 - 2 - 0 - false - false - - - S.D. Systems 80 track - DSDD 3.5" - 256 x 18 - MFM - LOW - 80 - 2 - 18 - 256 - 0 - SIDES - - 5 - 31 - 0 - 176 - 127 - 128 - 0 - 2 - 0 - false - false - - - S.D. Systems 80 track - SSDD 5.25" - 256 x 18 - MFM - LOW - 80 - 1 - 18 - 256 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - - 4 - 15 - 0 - 175 - 127 - 192 - 0 - 2 - 0 - false - false - - - S.D. Systems - SSDD 8" - 256 x 26 - MFM - HIGH - 77 - 1 - 26 - 256 - 1 - - 0 - - 1 - 5 - 9 - 13 - 17 - 21 - 25 - 3 - 7 - 11 - 15 - 19 - 23 - 2 - 6 - 10 - 14 - 18 - 22 - 26 - - - - 4 - 15 - 1 - 240 - 127 - 192 - 0 - 3 - 0 - false - false - - - Seiko - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 0 - 315 - 127 - 192 - 0 - 2 - 0 - false - false - - - SemiDisk DT42 - DSHD 96 tpi 5.25" - 512 x 15 - MFM - HIGH - 77 - 2 - 15 - 512 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 2 - 5 - 8 - 11 - 14 - 3 - 6 - 9 - 12 - 15 - - - - 1 - - 1 - 4 - 7 - 10 - 13 - 2 - 5 - 8 - 11 - 14 - 3 - 6 - 9 - 12 - 15 - - - SIDES - - 4 - 15 - 0 - 562 - 255 - 240 - 0 - 4 - 0 - false - false - - - Sharp MZ-80 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 2 - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 1 - 169 - 127 - 192 - 0 - 2 - 0 - true - false - - - Sharp MZ-80B - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 2 - - 1 - - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - - - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 1 - 195 - 127 - 192 - 0 - 2 - 0 - true - false - - - Sharp 3500/5500 - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - SIDES - - 4 - 15 - 1 - 151 - 127 - 192 - 0 - 4 - 0 - false - false - - - Sharp 5600 - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - - - SIDES - - 4 - 15 - 0 - 312 - 127 - 192 - 0 - 4 - 0 - false - false - - - Sharp MZ 3541 - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - SIDES - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Shelton SIG/NET 2 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - SIDES - - 4 - 15 - 1 - 195 - 63 - 128 - 0 - 2 - 0 - true - false - - - Shelton SIG/NET 2 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - SIDES - - 4 - 15 - 0 - 395 - 255 - 240 - 0 - 2 - 0 - true - false - - - Siemens PG-685 DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 350 - 255 - 240 - 0 - 4 - 0 - false - false - - - Siemens PG-675 DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 1 - 170 - 63 - 128 - 0 - 4 - 0 - false - false - - - Silver-Reed WP System - DSDD 3.5" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 3 - 5 - 2 - 4 - - - - 1 - - 1 - 3 - 5 - 2 - 4 - - - SIDES - - 4 - 15 - 1 - 189 - 127 - 192 - 0 - 4 - 0 - false - false - - - Smart Aleck - SSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 1 - 18 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - - 3 - 7 - 0 - 170 - 63 - 192 - 0 - 2 - 0 - false - false - - - Sorbus TurboDOS - 5.25" DSHD (or 8" DSDD) - 1024 x 8 - MFM - HIGH - 77 - 2 - 8 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 5 - 31 - 1 - 308 - 255 - 192 - 0 - 0 - 0 - false - false - - - Sony SMC-70 - SSDD 3.5" - 256 x 16 - MFM - LOW - 70 - 1 - 16 - 256 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 3 - 6 - 9 - 12 - 15 - 2 - 5 - 8 - 11 - 14 - - - - 4 - 15 - 1 - 135 - 127 - 192 - 0 - 2 - 0 - false - false - - - Spectravideo 318/328 - SSDD 48 tpi 5.25" - 256 x 17 - MFM - LOW - 40 - 1 - 17 - 256 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 3 - 7 - 0 - 156 - 63 - 192 - 0 - 3 - 0 - false - false - - - Spectravideo SV-328 - DSDD 48 tpi 5.25" - 256 x 17 - MFM - LOW - 40 - 2 - 17 - 256 - 2 - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - CYLINDERS - - 4 - 15 - 1 - 162 - 63 - 128 - 0 - 3 - 0 - false - false - - - Sperry UTS 30, UTS 5000 - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 354 - 383 - 252 - 0 - 2 - 0 - false - false - - - Spectravideo - SSDD 48 tpi 5.25" - 256 x 17 - MFM - LOW - 40 - 1 - 17 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 3 - 7 - 0 - 157 - 63 - 192 - 0 - 3 - 0 - false - false - - - Spectravideo - DSDD 48 tpi 5.25" - 256 x 17 - MFM - LOW - 40 - 2 - 17 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - CYLINDERS - - 4 - 15 - 1 - 163 - 63 - 128 - 0 - 3 - 0 - false - false - - - Spectravideo - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 1 - 197 - 63 - 128 - 0 - 1 - 0 - false - false - - - Spectravideo - SSDD 3.5" - 512 x 9 - MFM - LOW - 80 - 1 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 4 - 15 - 1 - 163 - 63 - 128 - 0 - 3 - 0 - false - false - - - Superbrain JR - SSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 35 - 1 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 4 - 15 - 1 - 81 - 63 - 128 - 0 - 2 - 0 - true - false - - - Superbrain 40 track - SSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 1 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 4 - 15 - 1 - 94 - 63 - 128 - 0 - 2 - 0 - true - false - - - Superbrain QD - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 35 - 2 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - CYLINDERS - - 4 - 15 - 1 - 169 - 63 - 128 - 0 - 2 - 0 - true - false - - - Superbrain II - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - CYLINDERS - - 5 - 31 - 3 - 196 - 127 - 192 - 0 - 3 - 0 - true - false - - - Superbrain - SSDD 48 tpi 5.25" - 128 x 30 - MFM - LOW - 40 - 1 - 30 - 128 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 19 - 22 - 25 - 28 - 2 - 5 - 8 - 11 - 14 - 17 - 20 - 23 - 26 - 29 - - - - 3 - 7 - 0 - 142 - 63 - 192 - 0 - 2 - 0 - true - false - - - System Group 2800 - DSDD 8" - 1024 x 8 - MFM - HIGH - 77 - 2 - 8 - 1024 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 5 - 31 - 1 - 303 - 255 - 192 - 0 - 2 - 0 - false - false - - - Tarbell - DSDD 8" - 512 x 15 - MFM - HIGH - 77 - 2 - 15 - 512 - 4 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 12 - 13 - 14 - - - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 12 - 13 - 14 - - - SIDES - - 5 - 31 - 0 - 303 - 169 - 192 - 0 - 2 - 0 - false - false - - - Tatung TPC2000 - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 3 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - EAGLE - - 4 - 15 - 0 - 354 - 127 - 192 - 0 - 2 - 0 - false - false - - - Techron TEF 10 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 4 - 7 - 10 - 3 - 6 - 9 - 2 - 5 - 8 - - - - 1 - - 1 - 4 - 7 - 10 - 3 - 6 - 9 - 2 - 5 - 8 - - - SIDES - - 4 - 15 - 0 - 394 - 319 - 248 - 0 - 2 - 0 - false - false - - - Techron TEF 12 - DSHD 96 tpi 5.25" - 512 x 17 - MFM - HIGH - 80 - 2 - 17 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - SIDES - - 4 - 15 - 0 - 670 - 767 - 255 - 240 - 4 - 0 - false - false - - - Tektronix 4170 - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - CYLINDERS - - 4 - 15 - 0 - 153 - 63 - 128 - 0 - 1 - 0 - false - false - - - Teletek - SSDD 8" - 256 x 26 - MFM - HIGH - 77 - 1 - 26 - 256 - 0 - - 0 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - - - - 4 - 15 - 1 - 242 - 127 - 192 - 0 - 2 - 0 - false - false - - - Teletek Systemaster - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 0 - - 0 - - 1 - 7 - 13 - 2 - 8 - 14 - 3 - 9 - 15 - 4 - 10 - 16 - 5 - 11 - 17 - 6 - 12 - 18 - - - - 1 - - 1 - 7 - 13 - 2 - 8 - 14 - 3 - 9 - 15 - 4 - 10 - 16 - 5 - 11 - 17 - 6 - 12 - 18 - - - CYLINDERS - - 4 - 15 - 1 - 172 - 127 - 192 - 0 - 3 - 0 - false - false - - - Teletek Systemaster - DSDD 96 tpi 5.25" - 256 x 18 - MFM - LOW - 80 - 2 - 18 - 256 - 0 - - 0 - - 1 - 7 - 13 - 2 - 8 - 14 - 3 - 9 - 15 - 4 - 10 - 16 - 5 - 11 - 17 - 6 - 12 - 18 - - - - 1 - - 1 - 7 - 13 - 2 - 8 - 14 - 3 - 9 - 15 - 4 - 10 - 16 - 5 - 11 - 17 - 6 - 12 - 18 - - - EAGLE - - 4 - 15 - 0 - 353 - 127 - 192 - 0 - 3 - 0 - false - false - - - TeleVideo 8nn/TPC-1 CP/M - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 6 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - SIDES - - 4 - 15 - 0 - 170 - 63 - 128 - 0 - 4 - 0 - false - false - - - TeleVideo 1603 - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 354 - 127 - 192 - 0 - 2 - 0 - false - false - - - TeleVideo 806 TurboDOS - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 1 - 200 - 127 - 192 - 0 - 0 - 0 - false - false - - - TeleVideo 8nn TurboDOS - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 6 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - SIDES - - 4 - 15 - 1 - 170 - 63 - 128 - 0 - 4 - 0 - false - false - - - Timex/Sinclair 2068+AERCO FD-68 RP/M - DSDD 48 tpi 5.25" -1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 1 - 189 - 127 - 192 - 0 - 4 - 0 - false - false - - - Tokyo Electron 80W - DSHD 3.5" - 1024 x 8 - MFM - HIGH - 77 - 2 - 8 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 6 - 63 - 3 - 160 - 255 - 128 - 0 - 0 - 0 - false - false - - - Toshiba T100, T200 - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 0 - - 0 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - 16 - - - - 1 - - 1 - 5 - 9 - 13 - 2 - 6 - 10 - 14 - 3 - 7 - 11 - 15 - 4 - 8 - 12 - 16 - - - SIDES - - 3 - 7 - 0 - 255 - 63 - 192 - 0 - 6 - 0 - false - false - - - Toshiba 300 - DSDD 96 tpi 5.25" - 512 x 8 - MFM - LOW - 80 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 0 - 318 - 127 - 192 - 0 - 1 - 0 - false - false - - - Toshiba T-250 - DSHD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 4 - 7 - 10 - 13 - 16 - 19 - 22 - 25 - 2 - 5 - 8 - 11 - 14 - 17 - 20 - 23 - 26 - 3 - 6 - 9 - 12 - 15 - 18 - 21 - 24 - - - - 1 - - 1 - 4 - 7 - 10 - 13 - 16 - 19 - 22 - 25 - 2 - 5 - 8 - 11 - 14 - 17 - 20 - 23 - 26 - 3 - 6 - 9 - 12 - 15 - 18 - 21 - 24 - - - SIDES - - 4 - 15 - 0 - 487 - 63 - 128 - 0 - 4 - 0 - false - false - - - Transtec - SSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 1 - 10 - 512 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 4 - 15 - 1 - 194 - 63 - 128 - 0 - 2 - 0 - false - false - - - TRS-80 Model 1, Omikron CP/M - SSSD 48 tpi 5.25" - 128 x 18 - FM - LOW - 35 - 1 - 18 - 128 - 0 - - 0 - - 1 - 5 - 9 - 13 - 17 - 3 - 7 - 11 - 15 - 2 - 6 - 10 - 14 - 18 - 4 - 8 - 12 - 16 - - - - 3 - 7 - 0 - 71 - 63 - 192 - 0 - 3 - 0 - false - false - - - TRS-80 Model 1, Bigmem CP/M - SSDD 8" - 256 x 26 - MFM - HIGH - 77 - 1 - 26 - 256 - 0 - - 0 - - 1 - 7 - 13 - 19 - 25 - 5 - 11 - 17 - 23 - 3 - 9 - 15 - 21 - 2 - 8 - 14 - - - - 4 - 15 - 1 - 243 - 63 - 128 - 0 - 2 - 0 - false - false - - - TRS-80 Model 1, ColorPower II - SSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 1 - 18 - 256 - 5 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - - 3 - 7 - 0 - 170 - 63 - 192 - 0 - 2 - 0 - false - false - - - TRS-80, Pickles & Trout CP/M - SSDD 8" - 512 x 16 - MFM - HIGH - 77 - 1 - 16 - 512 - 4 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 4 - 15 - 0 - 299 - 127 - 192 - 0 - 2 - 0 - false - false - - - TRS-80, Holmes CP/M - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 4 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - - - SIDES - - 4 - 15 - 1 - 190 - 63 - 240 - 0 - 2 - 0 - false - false - - - TRS-80, MM CP/M - SSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 1 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 4 - 15 - 1 - 94 - 127 - 192 - 0 - 2 - 0 - false - false - - - TRS-80 Model 4, 4P; MT CP/M - SSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 1 - 18 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 17 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - 18 - - - - 4 - 15 - 1 - 84 - 127 - 192 - 0 - 2 - 0 - false - false - - - TRS-80 Model 4, 4P; MT CP/M - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 17 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - 18 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 17 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - 18 - - - SIDES - - 4 - 15 - 1 - 174 - 127 - 192 - 0 - 2 - 0 - false - false - - - TRS-80 Model 4, 4P - SSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 1 - 8 - 512 - 4 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 3 - 7 - 0 - 155 - 63 - 192 - 0 - 1 - 0 - false - false - - - TRS-80 Model 4P-Montezuma800K - DSDD 96tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - 10 - - - SIDES - - 4 - 15 - 0 - 399 - 127 - 192 - 0 - 0 - 0 - false - false - - - TRS-80 II/12/16 Aton CP/M - DSHD 8" - 1024 x 8 - MFM - HIGH - 77 - 2 - 8 - 1024 - 3 - - 0 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - - - - 1 - - 1 - 4 - 7 - 2 - 5 - 8 - 3 - 6 - - - SIDES - - 4 - 15 - 0 - 608 - 191 - 224 - 0 - 2 - 0 - false - false - - - TRS-80 II/12/16 Pickles & Trout - DSHD 8" - 512 x 16 - MFM - HIGH - 77 - 2 - 16 - 512 - 4 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - CYLINDERS - - 4 - 15 - 0 - 608 - 191 - 224 - 0 - 2 - 0 - false - false - - - TRS-80 Model 4, Montezuma - DSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 2 - 18 - 256 - 0 - - 0 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 17 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - 18 - - - - 1 - - 1 - 3 - 5 - 7 - 9 - 11 - 13 - 15 - 17 - 2 - 4 - 6 - 8 - 10 - 12 - 14 - 16 - 18 - - - EAGLE - - 4 - 15 - 1 - 174 - 127 - 192 - 0 - 2 - 0 - false - false - - - U-Micro 1000 - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 4 - 15 - 0 - 395 - 127 - 192 - 0 - 2 - 0 - false - false - - - Varian Spectra AA/20, DS-15 - DSDD 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - EAGLE - - 3 - 7 - 0 - 317 - 63 - 96 - 0 - 0 - 2 - false - false - - - Vector 4 - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 2 - EAGLE - - 4 - 15 - 0 - 356 - 127 - 192 - 0 - 1 - 0 - false - false - - - Visual 1050 - SSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 1 - 10 - 512 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 2 - 0 - false - false - - - Wangwriter - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 1 - 155 - 127 - 192 - 0 - 2 - 0 - false - false - - - Wave Mate Bullet - SSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 1 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 3 - 7 - 0 - 189 - 63 - 192 - 0 - 2 - 0 - false - false - - - Wave Mate Bullet - DSDD 96 tpi 5.25" - 1024 x 5 - MFM - LOW - 80 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 394 - 127 - 192 - 0 - 2 - 0 - false - false - - - Wave Mate Bullet - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 1 - 194 - 63 - 128 - 0 - 2 - 0 - false - false - - - Wave Mate Bullet - SSHD 8" - 1024 x 9 - MFM - HIGH - 77 - 1 - 9 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 4 - 15 - 0 - 336 - 127 - 192 - 0 - 2 - 0 - false - false - - - Xerox - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - CYLINDERS - - 4 - 15 - 1 - 170 - 127 - 192 - 0 - 2 - 0 - false - false - - - Xerox 820 - SSSD 48 tpi 5.25" - 128 x 18 - FM - LOW - 40 - 1 - 18 - 128 - 0 - - 0 - - 1 - 6 - 11 - 16 - 3 - 8 - 13 - 18 - 5 - 10 - 15 - 2 - 7 - 12 - 17 - 4 - 9 - 14 - - - - 3 - 7 - 0 - 83 - 31 - 128 - 0 - 3 - 0 - false - false - - - Xerox 820 II - SSDD 48 tpi 5.25" - 256 x 17 - MFM - LOW - 40 - 1 - 17 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 3 - 7 - 0 - 156 - 63 - 192 - 0 - 3 - 0 - false - false - - - Xerox 820-II, 16/8 - DSDD 48 tpi 5.25" - 256 x 17 - MFM - LOW - 40 - 2 - 17 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - EAGLE - - 4 - 15 - 1 - 162 - 63 - 128 - 0 - 3 - 0 - false - false - - - Xerox 16/8 - SSDD 8" - 256 x 26 - MFM - HIGH - 77 - 1 - 26 - 256 - 5 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 4 - 15 - 1 - 242 - 127 - 192 - 0 - 2 - 0 - false - false - - - XEROX 16/8 - DSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 2 - 9 - 512 - 2 - CYLINDERS - - 4 - 15 - 1 - 162 - 63 - 128 - 0 - 2 - 0 - false - false - - - Xerox 820, S/W Publishers DD - SSDD 48 tpi 5.25" - 256 x 18 - MFM - LOW - 40 - 1 - 18 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - - - - 3 - 7 - 0 - 166 - 63 - 192 - 0 - 3 - 0 - false - false - - - Xerox 3700 Laser Printer - DSDD 48 tpi 5.25" - 256 x 17 - MFM - LOW - 40 - 2 - 17 - 256 - 3 - CYLINDERS - - 4 - 15 - 1 - 162 - 63 - 192 - 0 - 3 - 0 - false - false - - - Xerox 16/8, 820 II - SSDD 48 tpi 5.25" - MFM - LOW - 40 - 1 - 17 - 256 - 3 - - 3 - 7 - 0 - 156 - 63 - 192 - 0 - 3 - 0 - false - false - - - Xerox 16/8 - SSDD 48 tpi 5.25" - 512 x 9 - MFM - LOW - 40 - 1 - 9 - 512 - 3 - - 3 - 7 - 0 - 170 - 63 - 192 - 0 - 2 - 0 - false - false - - - Xerox 16/8 Special - SSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 1 - 8 - 512 - 3 - - 3 - 7 - 0 - 151 - 63 - 192 - 0 - 2 - 0 - false - false - - - Xerox 16/8, 820-II - DSDD 48 tpi 5.25" - 256 x 17 - MFM - LOW - 40 - 2 - 17 - 256 - 3 - EAGLE - - 4 - 15 - 1 - 162 - 63 - 128 - 0 - 3 - 0 - false - false - - - Xerox 16/8 Special - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 3 - CYLINDERS - - 4 - 15 - 1 - 155 - 63 - 128 - 0 - 2 - 0 - false - false - - - Xerox 3700 Laser Printer - DSDD 48 tpi 5.25" - 256 x 17 - MFM - LOW - 40 - 2 - 17 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - - - CYLINDERS - - 4 - 15 - 1 - 162 - 63 - 192 - 0 - 3 - 0 - false - false - - - Xor 5 - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 6 - 2 - 7 - 3 - 8 - 4 - 9 - 5 - 10 - - - - 0 - - 1 - 6 - 2 - 7 - 3 - 8 - 4 - 9 - 5 - 10 - - - SIDES - - 4 - 15 - 1 - 191 - 127 - 192 - 0 - 3 - 0 - false - false - - - XYZ - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 0 - - 0 - - 1 - 5 - 9 - 3 - 7 - 2 - 6 - 10 - 4 - 8 - - - - 1 - - 11 - 15 - 19 - 13 - 17 - 12 - 16 - 20 - 14 - 18 - - - SIDES - - 4 - 15 - 1 - 194 - 127 - 192 - 0 - 4 - 0 - false - false - - - Zeiss Video Analysis System - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - CYLINDERS - - 4 - 15 - 0 - 299 - 255 - 240 - 0 - 4 - 0 - false - false - - - Zenith Z-37 Disk - SSSD 48 tpi 5.25" - 256 x 10 - FM - LOW - 40 - 1 - 10 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 3 - 7 - 0 - 91 - 63 - 192 - 0 - 3 - 0 - false - false - - - Zenith Z-37 Disk - DSDD 96 tpi 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 0 - 315 - 255 - 240 - 0 - 2 - 0 - false - false - - - Zenith Z89, Heath H89 - DSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 2 - 16 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 0 - 155 - 255 - 240 - 0 - 2 - 0 - false - false - - - Zenith Z90 - SSDD 48 tpi 5.25" - 256 x 16 - MFM - LOW - 40 - 1 - 16 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 3 - 7 - 0 - 151 - 127 - 240 - 0 - 2 - 0 - false - false - - - Zenith Z-100 - SSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 1 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 3 - 7 - 0 - 151 - 127 - 240 - 0 - 2 - 0 - false - false - - - Zenith Z-100 - DSDD 48 tpi 5.25" - 512 x 8 - MFM - LOW - 40 - 2 - 8 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - - - SIDES - - 4 - 15 - 1 - 155 - 255 - 240 - 0 - 2 - 0 - false - false - - - Zenith Z-100 - SSDD 8" - 256 x 26 - MFM - HIGH - 77 - 1 - 26 - 256 - 0 - - 0 - - 1 - 10 - 19 - 2 - 11 - 20 - 3 - 12 - 21 - 4 - 13 - 22 - 5 - 14 - 23 - 6 - - - - 4 - 15 - 1 - 242 - 127 - 192 - 0 - 2 - 0 - false - false - - - Zenith Z-37 Disk - DSDD 96 (Half drive) 5.25" - 256 x 16 - MFM - LOW - 80 - 2 - 16 - 256 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - SIDES - - 4 - 15 - 0 - 155 - 255 - 240 - 0 - 2 - 0 - false - false - - - Zenith/Heath H-89 Ext Density - DSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 2 - 5 - 1024 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 195 - 255 - 240 - 0 - 2 - 0 - false - false - - - Zenith Z-100, Heath H-47 - DSDD 8" - 256 x 26 - MFM - HIGH - 77 - 2 - 26 - 256 - 0 - - 0 - - 1 - 10 - 19 - 2 - 11 - 20 - 3 - 12 - 21 - 4 - 13 - 22 - 5 - 14 - 23 - 6 - 15 - 24 - 7 - 16 - 25 - 8 - 17 - 26 - 9 - 18 - - - - 1 - - 1 - 10 - 19 - 2 - 11 - 20 - 3 - 12 - 21 - 4 - 13 - 22 - 5 - 14 - 23 - 6 - 15 - 24 - 7 - 16 - 25 - 8 - 17 - 26 - 9 - 18 - - - SIDES - - 4 - 15 - 0 - 497 - 255 - 240 - 0 - 2 - 0 - false - false - - - Zenith Z-37 - SSDD 48 tpi 5.25" - 1024 x 5 - MFM - LOW - 40 - 1 - 5 - 1024 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 3 - 7 - 0 - 190 - 127 - 240 - 0 - 2 - 0 - false - false - - - Zenith/Heath H89/H90 Magnolia 7736 - SSHD 8" - 512 x 16 - MFM - HIGH - 77 - 1 - 16 - 512 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 4 - 15 - 0 - 299 - 191 - 224 - 0 - 2 - 0 - false - false - - - Zorba - DSDD 48 tpi 5.25" - 512 x 10 - MFM - LOW - 40 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 0 - - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - - - SIDES - - 4 - 15 - 1 - 194 - 63 - 128 - 0 - 2 - 0 - false - false - - - Zorba - DSDD 96 tpi 5.25" - 512 x 10 - MFM - LOW - 80 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 0 - - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - - - SIDES - - 5 - 31 - 3 - 194 - 127 - 128 - 0 - 2 - 0 - false - false - - - PIC-DISK SSDD 96tpi 3.5" - MFM - LOW - 80 - 1 - 9 - 512 - 1 - - 0 - - 1 - 3 - 5 - 7 - 9 - 2 - 4 - 6 - 8 - - - - 4 - 15 - 1 - 194 - 63 - 128 - 0 - 2 - 0 - false - false - - - SAM COUPE Pro-DOS - DSDD 160 tpi 3.5" - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 356 - 255 - 240 - 0 - 1 - 0 - false - false - - - Acorn CPM - MFM - LOW - 80 - 2 - 10 - 256 - 5 - - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - CYLINDERS - - 4 - 15 - 1 - 200 - 127 - 192 - 0 - 3 - 0 - false - false - - - CPC 178K Data 40trk 9sct 64dir 1Kpb Side 2 - MFM - LOW - 40 - 2 - 9 - 512 - 5 - - 0 - - 0 - - - - 0 - - 0 - - - EAGLE - - 3 - 7 - 0 - 179 - 63 - 192 - 0 - 40 - 0 - false - false - - - CPC 187K Data 42trk 9sct 64dir 1Kpb Side 2 - MFM - LOW - 42 - 2 - 9 - 512 - 5 - - 0 - - 0 - - - - 0 - - 0 - - - EAGLE - - 3 - 7 - 0 - 188 - 63 - 192 - 0 - 42 - 0 - false - false - - - CPC-B360 358K Data 80trk 9sct 64dir 2Kpb Side 1 - MFM - LOW - 80 - 1 - 9 - 512 - 2 - - 0 - - 0 - - - - 4 - 15 - 1 - 179 - 63 - 128 - 0 - 0 - 0 - false - false - - - CPC-B360 358K Data 80trk 9sct 64dir 2Kpb Side 2 - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 0 - - - - 0 - - 0 - - - EAGLE - - 4 - 15 - 1 - 179 - 63 - 128 - 0 - 80 - 0 - false - false - - - CPC 356K Data 40trk 9sct 128dir 2Kpb Two Sides - MFM - LOW - 40 - 2 - 9 - 512 - 2 - - 0 - - 0 - - - - 1 - - 0 - - - SIDES - - 4 - 15 - 1 - 179 - 127 - 192 - 0 - 0 - 0 - false - false - - - DOBBERTIN 716K Data 80trk 9sct 128dir 4Kpb Two Sides - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 0 - - - - 1 - - 0 - - - SIDES - - 5 - 31 - 3 - 179 - 127 - 128 - 0 - 0 - 0 - false - false - - - CPC-STD 169K System 40trk 9sct 64dir 1Kpb Side 1 - MFM - LOW - 40 - 1 - 9 - 512 - 5 - - 0 - - 41 - - - - 3 - 7 - 0 - 170 - 63 - 192 - 0 - 2 - 0 - false - false - - - CPC 169K System 40trk 9sct 64dir 1Kpb Side 2 - MFM - LOW - 40 - 2 - 9 - 512 - 5 - - 0 - - 41 - - - - 0 - - 41 - - - EAGLE - - 3 - 7 - 0 - 170 - 63 - 192 - 0 - 42 - 0 - false - false - - - CPC 178K System 42trk 9sct 64dir 1Kpb Side 1 - MFM - LOW - 42 - 1 - 9 - 512 - 5 - - 0 - - 41 - - - - 3 - 7 - 0 - 179 - 63 - 192 - 0 - 2 - 0 - false - false - - - CPC 178K System 42trk 9sct 64dir 1Kpb Side 2 - MFM - LOW - 42 - 2 - 9 - 512 - 5 - - 0 - - 41 - - - - 0 - - 41 - - - EAGLE - - 3 - 7 - 0 - 179 - 63 - 192 - 0 - 44 - 0 - false - false - - - CPC 253K System 60trk 9sct 64dir 1Kpb Side 1 - MFM - LOW - 60 - 1 - 9 - 512 - 5 - - 0 - - 41 - - - - 3 - 7 - 0 - 254 - 63 - 192 - 0 - 2 - 0 - false - false - - - CPC 253K System 60trk 9sct 64dir 1Kpb Side 2 - MFM - LOW - 60 - 2 - 9 - 512 - 5 - - 0 - - 41 - - - - 0 - - 41 - - - EAGLE - - 3 - 7 - 0 - 254 - 63 - 192 - 0 - 62 - 0 - false - false - - - CPC-B360 348K System 80trk 9sct 64dir 2Kpb Side 1 - MFM - LOW - 80 - 1 - 9 - 512 - 2 - - 0 - - 41 - - - - 4 - 15 - 1 - 174 - 63 - 128 - 0 - 2 - 0 - false - false - - - CPC-B360 348K System 80trk 9sct 64dir 2Kpb Side 2 - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 41 - - - - 0 - - 41 - - - EAGLE - - 4 - 15 - 1 - 174 - 63 - 128 - 0 - 82 - 0 - false - false - - - CPC 346K System 40trk 9sct 128dir 2Kpb Two Sides - MFM - LOW - 40 - 2 - 9 - 512 - 2 - - 0 - - 41 - - - - 1 - - 41 - - - SIDES - - 4 - 15 - 1 - 174 - 127 - 192 - 0 - 2 - 0 - false - false - - - CPC 344K System 80trk 9sct 128dir 4Kpb Side 1 - MFM - LOW - 80 - 1 - 9 - 512 - 5 - - 0 - - 41 - - - - 5 - 31 - 3 - 86 - 127 - 128 - 0 - 2 - 0 - false - false - - - CPC 344K System 80trk 9sct 128dir 4Kpb Side 2 - MFM - LOW - 80 - 2 - 9 - 512 - 5 - - 0 - - 41 - - - - 0 - - 41 - - - EAGLE - - 5 - 31 - 3 - 86 - 127 - 128 - 0 - 82 - 0 - false - false - - - DOBBERTIN 704K System 80trk 9sct 128dir 4Kpb Two Sides - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 41 - - - - 1 - - 41 - - - SIDES - - 5 - 31 - 3 - 176 - 127 - 128 - 0 - 2 - 0 - false - false - - - ReadBIG 706K System 80trk 9sct 128dir 2Kpb Two Sides - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 41 - - - - 1 - - 41 - - - SIDES - - 4 - 15 - 0 - 354 - 127 - 192 - 0 - 2 - 0 - false - false - - - CPC-STD 154K Ibm-Cpm86 40trk 8sct 64dir 1Kpb Side 1 - MFM - LOW - 40 - 1 - 8 - 512 - 2 - - 0 - - 1 - - - - 3 - 7 - 0 - 155 - 63 - 192 - 0 - 1 - 0 - false - false - - - CPC 154K Ibm-Cpm86 40trk 8sct 64dir 1Kpb Side 2 - MFM - LOW - 40 - 2 - 8 - 512 - 2 - - 0 - - 1 - - - - 0 - - 1 - - - EAGLE - - 3 - 7 - 0 - 155 - 63 - 192 - 0 - 41 - 0 - false - false - - - PCW-STD 173K Format 40trk 9sct 64dir 1Kpb Side 1 - MFM - LOW - 40 - 1 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 3 - 7 - 0 - 174 - 63 - 192 - 0 - 1 - 0 - false - false - - - PCW 173K Format 40trk 9sct 64dir 1Kpb Side 2 - MFM - LOW - 40 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - EAGLE - - 3 - 7 - 0 - 174 - 63 - 192 - 0 - 41 - 0 - false - false - - - PCW 346K Format 40trk 9sct 256dir 2Kpb Two Sides - MFM - LOW - 40 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 176 - 255 - 240 - 0 - 1 - 0 - false - false - - - PCW 706K Format 80trk 9sct 256dir 2Kpb Two Sides - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 4 - 15 - 0 - 356 - 255 - 240 - 0 - 1 - 0 - false - false - - - PCW 784K Format 80trk 10sct 256dir 4Kpb Two Sides - MFM - LOW - 80 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 5 - 31 - 3 - 197 - 255 - 192 - 0 - 1 - 0 - false - false - - - DiskPara3 796K Format 80trk 10sct 128dir 2Kpb Two Sides - MFM - LOW - 80 - 2 - 10 - 512 - 2 - - 0 - - 1 - - - - 1 - - 1 - - - SIDES - - 4 - 15 - 0 - 399 - 127 - 192 - 0 - 0 - 0 - false - false - - - DiskPara 824K Format 83trk 10sct 192dir 2Kpb Two Sides - MFM - LOW - 83 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 0 - - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - - - SIDES - - 4 - 15 - 0 - 414 - 191 - 224 - 0 - 0 - 0 - false - false - - - VORTEX 704K Format 80trk 9sct 128dir 4Kpb Two Sides - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 1 - - - - 1 - - 1 - - - SIDES - - 5 - 31 - 3 - 176 - 127 - 128 - 0 - 2 - 0 - false - false - - - RAMDOS-D1 716K Format 80trk 9sct 128dir 2Kpb Two Sides - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 1 - - - - 1 - - 1 - - - SIDES - - 4 - 15 - 0 - 359 - 127 - 192 - 0 - 0 - 0 - false - false - - - RAMDOS-D10 796K Format 80trk 10sct 128dir 2Kpb Two Sides - MFM - LOW - 80 - 2 - 10 - 512 - 2 - - 0 - - 11 - - - - 1 - - 11 - - - SIDES - - 4 - 15 - 0 - 399 - 127 - 192 - 0 - 0 - 0 - false - false - - - RAMDOS-D2 712K Format 80trk 9sct 256dir 2Kpb Two Sides - MFM - LOW - 80 - 2 - 9 - 512 - 0 - - 0 - - 21 - - - - 1 - - 21 - - - SIDES - - 4 - 15 - 0 - 359 - 255 - 240 - 0 - 0 - 0 - false - false - - - RAMDOS-D20 792K Format 80trk 10sct 256dir 2Kpb Two Sides - MFM - LOW - 80 - 2 - 10 - 512 - 2 - - 0 - - 31 - - - - 1 - - 31 - - - SIDES - - 4 - 15 - 0 - 399 - 255 - 240 - 0 - 0 - 0 - false - false - - - Amstrad ZX Spectrum +3 - SSDD 64dir 1Kpb 180K - 173K user free - MFM - LOW - 40 - 1 - 9 - 512 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 3 - 7 - 0 - 174 - 63 - 192 - 0 - 1 - 0 - false - false - - - Amstrad ZX Spectrum +3 - DSDD 128dir 2Kpb 720K - 710K user free - MFM - LOW - 80 - 2 - 9 - 512 - 3 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 356 - 127 - 192 - 0 - 1 - 0 - false - false - - - Altos Series 5 - DSDD 96 tpi 5.25" - 512 x 9 - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 5 - 31 - 3 - 176 - 255 - 192 - 0 - 64 - 0 - false - false - - - PC1715 SCP (80*2* 5,1024 4 OFS 4k DIR) 5.25" - MFM - LOW - 80 - 2 - 5 - 1024 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 389 - 127 - 192 - 0 - 4 - 0 - false - false - - - PC1715 CPA (80*2* 5,1024 0 OFS 6k DIR) 5.25" - MFM - LOW - 80 - 2 - 5 - 1024 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - - - SIDES - - 4 - 15 - 0 - 399 - 191 - 224 - 0 - 0 - 0 - false - false - - - Amstrad PCW8256 - DSDD 48 tpi 5.25" - MFM - LOW - 40 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 4 - 15 - 0 - 356 - 255 - 240 - 0 - 1 - 0 - false - false - - - Amstrad PCW8256 - SSDD 48 tpi 3" (JOYCE-SYSTEM) - MFM - LOW - 40 - 1 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 3 - 7 - 0 - 174 - 63 - 192 - 0 - 1 - 0 - false - false - - - Amstrad CPC System - SSDD 48 tpi 3" or 5.25" - MFM - LOW - 40 - 1 - 9 - 512 - 5 - - 0 - - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - - - - 3 - 7 - 0 - 170 - 63 - 192 - 0 - 2 - 0 - false - false - - - Amstrad CPC-Data - SSDD 48 tpi 3" or 5.25" - MFM - LOW - 40 - 1 - 9 - 512 - 5 - - 0 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - - - - 3 - 7 - 0 - 179 - 63 - 192 - 0 - 0 - 0 - false - false - - - Amstrad B360K - SSDD 96 tpi 5.25" SKEW 2 - MFM - LOW - 80 - 1 - 9 - 512 - 2 - - 0 - - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - - - - 4 - 15 - 1 - 174 - 63 - 128 - 0 - 2 - 0 - false - false - - - Amstrad VORTEX - DSDD 96 tpi 5.25" - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 5 - 31 - 3 - 176 - 127 - 128 - 0 - 2 - 0 - false - false - - - Amstrad CPC System DSDD 96tpi 5.25" - DOBBERTIN - - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - - - - 1 - - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - - - SIDES - - 5 - 31 - 3 - 176 - 127 - 128 - 0 - 2 - 0 - false - false - - - Amstrad DOBBERTIN DATA DSDD 96 tpi 5.25" Skew 5 - MFM - LOW - 80 - 2 - 9 - 512 - 2 - - 0 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - - - - 1 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - - - - 5 - 31 - 3 - 179 - 127 - 128 - 0 - 0 - 0 - false - false - - - Amstrad PCW8256 - DSDD 96 tpi 5.25" 10 x 512 788K - MFM - LOW - 80 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 5 - 31 - 3 - 197 - 255 - 192 - 0 - 1 - 0 - false - false - - - Amstrad PCW Joyce - SF2DD (824 kb - 256 entries) - MFM - LOW - 84 - 2 - 10 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - SIDES - - 5 - 31 - 3 - 208 - 255 - 192 - 0 - 1 - 0 - false - false - - - Amstrad PCW Joyce - 168 Track DD (740 kb - 256 entries) - MFM - LOW - 84 - 2 - 9 - 512 - 2 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - SIDES - - 5 - 31 - 3 - 187 - 255 - 192 - 0 - 1 - 0 - false - false - - - Extended CPC 3" 43-track - MFM - LOW - 43 - 1 - 9 - 512 - 2 - - 0 - - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - - - - 3 - 7 - 0 - 193 - 63 - 192 - 0 - 0 - 0 - false - false - - - Apple // CPM card 13-sector - GCR - LOW - 35 - 1 - 13 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - - - - 3 - 7 - 0 - 103 - 47 - 192 - 0 - 3 - 0 - false - false - - - Apple // CPM card 16-sector - GCR - LOW - 35 - 1 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 3 - 7 - 0 - 127 - 63 - 192 - 0 - 3 - 0 - false - false - - - Apple // CPM card special - GCR - LOW - 80 - 2 - 16 - 256 - 0 - - 0 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 1 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - - - - 4 - 15 - 0 - 313 - 255 - 240 - 0 - 3 - 0 - false - false - - - 2016-08-24T02:44:59.045767Z - \ No newline at end of file diff --git a/Aaru.Filesystems/Cram.cs b/Aaru.Filesystems/Cram.cs deleted file mode 100644 index 36e054853..000000000 --- a/Aaru.Filesystems/Cram.cs +++ /dev/null @@ -1,161 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Cram.cs -// Author(s) : Natalia Portillo -// -// Component : Cram file system plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Cram file system and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -// ReSharper disable UnusedMember.Local - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the CRAM filesystem -[SuppressMessage("ReSharper", "UnusedType.Local")] -public sealed class Cram : IFilesystem -{ - /// Identifier for Cram - const uint CRAM_MAGIC = 0x28CD3D45; - const uint CRAM_CIGAM = 0x453DCD28; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Cram filesystem"; - /// - public Guid Id => new("F8F6E46F-7A2A-48E3-9C0A-46AF4DC29E09"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - var magic = BitConverter.ToUInt32(sector, 0x00); - - return magic is CRAM_MAGIC or CRAM_CIGAM; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - var magic = BitConverter.ToUInt32(sector, 0x00); - - var crSb = new SuperBlock(); - var littleEndian = true; - - switch(magic) - { - case CRAM_MAGIC: - crSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - break; - case CRAM_CIGAM: - crSb = Marshal.ByteArrayToStructureBigEndian(sector); - littleEndian = false; - - break; - } - - var sbInformation = new StringBuilder(); - - sbInformation.AppendLine("Cram file system"); - sbInformation.AppendLine(littleEndian ? "Little-endian" : "Big-endian"); - sbInformation.AppendFormat("Volume edition {0}", crSb.edition).AppendLine(); - sbInformation.AppendFormat("Volume name: {0}", StringHandlers.CToString(crSb.name, Encoding)).AppendLine(); - sbInformation.AppendFormat("Volume has {0} bytes", crSb.size).AppendLine(); - sbInformation.AppendFormat("Volume has {0} blocks", crSb.blocks).AppendLine(); - sbInformation.AppendFormat("Volume has {0} files", crSb.files).AppendLine(); - - information = sbInformation.ToString(); - - XmlFsType = new FileSystemType - { - VolumeName = StringHandlers.CToString(crSb.name, Encoding), - Type = "Cram file system", - Clusters = crSb.blocks, - Files = crSb.files, - FilesSpecified = true, - FreeClusters = 0, - FreeClustersSpecified = true - }; - } - - enum CramCompression : ushort - { - Zlib = 1, - Lzma = 2, - Lzo = 3, - Xz = 4, - Lz4 = 5 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SuperBlock - { - public readonly uint magic; - public readonly uint size; - public readonly uint flags; - public readonly uint future; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] signature; - public readonly uint crc; - public readonly uint edition; - public readonly uint blocks; - public readonly uint files; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] name; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/Cram/Consts.cs b/Aaru.Filesystems/Cram/Consts.cs new file mode 100644 index 000000000..ad5dce9a6 --- /dev/null +++ b/Aaru.Filesystems/Cram/Consts.cs @@ -0,0 +1,45 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Cram file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the CRAM filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class Cram +{ + /// Identifier for Cram + const uint CRAM_MAGIC = 0x28CD3D45; + const uint CRAM_CIGAM = 0x453DCD28; + + const string FS_TYPE = "cramfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/Cram/Cram.cs b/Aaru.Filesystems/Cram/Cram.cs new file mode 100644 index 000000000..e68d4a009 --- /dev/null +++ b/Aaru.Filesystems/Cram/Cram.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Cram.cs +// Author(s) : Natalia Portillo +// +// Component : Cram file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the CRAM filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class Cram : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.Cram_Name; + + /// + public Guid Id => new("F8F6E46F-7A2A-48E3-9C0A-46AF4DC29E09"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Cram/Enums.cs b/Aaru.Filesystems/Cram/Enums.cs new file mode 100644 index 000000000..53fa470a8 --- /dev/null +++ b/Aaru.Filesystems/Cram/Enums.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Cram file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the CRAM filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class Cram +{ +#region Nested type: CramCompression + + enum CramCompression : ushort + { + Zlib = 1, + Lzma = 2, + Lzo = 3, + Xz = 4, + Lz4 = 5 + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Cram/Info.cs b/Aaru.Filesystems/Cram/Info.cs new file mode 100644 index 000000000..a10c14e4e --- /dev/null +++ b/Aaru.Filesystems/Cram/Info.cs @@ -0,0 +1,118 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Cram file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the CRAM filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class Cram +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + var magic = BitConverter.ToUInt32(sector, 0x00); + + return magic is CRAM_MAGIC or CRAM_CIGAM; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); + metadata = new FileSystem(); + + if(errno != ErrorNumber.NoError) return; + + var magic = BitConverter.ToUInt32(sector, 0x00); + + var crSb = new SuperBlock(); + var littleEndian = true; + + switch(magic) + { + case CRAM_MAGIC: + crSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + break; + case CRAM_CIGAM: + crSb = Marshal.ByteArrayToStructureBigEndian(sector); + littleEndian = false; + + break; + } + + var sbInformation = new StringBuilder(); + + sbInformation.AppendLine(Localization.Cram_file_system); + sbInformation.AppendLine(littleEndian ? Localization.Little_endian : Localization.Big_endian); + sbInformation.AppendFormat(Localization.Volume_edition_0, crSb.edition).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(crSb.name, encoding)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_has_0_bytes, crSb.size).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_blocks, crSb.blocks).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_files, crSb.files).AppendLine(); + + information = sbInformation.ToString(); + + metadata = new FileSystem + { + VolumeName = StringHandlers.CToString(crSb.name, encoding), + Type = FS_TYPE, + Clusters = crSb.blocks, + Files = crSb.files, + FreeClusters = 0 + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Cram/Structs.cs b/Aaru.Filesystems/Cram/Structs.cs new file mode 100644 index 000000000..bdc06933f --- /dev/null +++ b/Aaru.Filesystems/Cram/Structs.cs @@ -0,0 +1,61 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Cram file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the CRAM filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class Cram +{ +#region Nested type: SuperBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SuperBlock + { + public readonly uint magic; + public readonly uint size; + public readonly uint flags; + public readonly uint future; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] signature; + public readonly uint crc; + public readonly uint edition; + public readonly uint blocks; + public readonly uint files; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] name; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ECMA67/Consts.cs b/Aaru.Filesystems/ECMA67/Consts.cs new file mode 100644 index 000000000..1f5ff0bac --- /dev/null +++ b/Aaru.Filesystems/ECMA67/Consts.cs @@ -0,0 +1,41 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : ECMA-67 plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the ECMA-67 file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem described in ECMA-67 +public sealed partial class ECMA67 +{ + const string FS_TYPE = "ecma67"; + readonly byte[] _magic = "VOL"u8.ToArray(); +} \ No newline at end of file diff --git a/Aaru.Filesystems/ECMA67/ECMA67.cs b/Aaru.Filesystems/ECMA67/ECMA67.cs new file mode 100644 index 000000000..b2844a4af --- /dev/null +++ b/Aaru.Filesystems/ECMA67/ECMA67.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ECMA67.cs +// Author(s) : Natalia Portillo +// +// Component : ECMA-67 plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the ECMA-67 file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem described in ECMA-67 +public sealed partial class ECMA67 : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.ECMA67_Name; + + /// + public Guid Id => new("62A2D44A-CBC1-4377-B4B6-28C5C92034A1"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ECMA67/Info.cs b/Aaru.Filesystems/ECMA67/Info.cs new file mode 100644 index 000000000..5fa4e3efb --- /dev/null +++ b/Aaru.Filesystems/ECMA67/Info.cs @@ -0,0 +1,100 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : ECMA-67 plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the ECMA-67 file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Linq; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem described in ECMA-67 +public sealed partial class ECMA67 +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start > 0) return false; + + if(partition.End < 8) return false; + + ErrorNumber errno = imagePlugin.ReadSector(6, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length != 128) return false; + + VolumeLabel vol = Marshal.ByteArrayToStructureLittleEndian(sector); + + return _magic.SequenceEqual(vol.labelIdentifier) && vol is { labelNumber: 1, recordLength: 0x31 }; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + ErrorNumber errno = imagePlugin.ReadSector(6, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + var sbInformation = new StringBuilder(); + + VolumeLabel vol = Marshal.ByteArrayToStructureLittleEndian(sector); + + sbInformation.AppendLine(Localization.ECMA_67); + + sbInformation.AppendFormat(Localization.Volume_name_0, Encoding.ASCII.GetString(vol.volumeIdentifier)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_owner_0, Encoding.ASCII.GetString(vol.owner)).AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = 256, + Clusters = partition.End - partition.Start + 1, + VolumeName = Encoding.ASCII.GetString(vol.volumeIdentifier) + }; + + information = sbInformation.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ECMA67.cs b/Aaru.Filesystems/ECMA67/Structs.cs similarity index 52% rename from Aaru.Filesystems/ECMA67.cs rename to Aaru.Filesystems/ECMA67/Structs.cs index df954cdcc..664a43980 100644 --- a/Aaru.Filesystems/ECMA67.cs +++ b/Aaru.Filesystems/ECMA67/Structs.cs @@ -2,7 +2,7 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : ECMA67.cs +// Filename : Structs.cs // Author(s) : Natalia Portillo // // Component : ECMA-67 plugin. @@ -27,92 +27,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System.Runtime.InteropServices; + namespace Aaru.Filesystems; -using System; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - /// /// Implements detection of the filesystem described in ECMA-67 -public sealed class ECMA67 : IFilesystem +public sealed partial class ECMA67 { - readonly byte[] _magic = - { - 0x56, 0x4F, 0x4C - }; - - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "ECMA-67"; - /// - public Guid Id => new("62A2D44A-CBC1-4377-B4B6-28C5C92034A1"); - /// - public FileSystemType XmlFsType { get; private set; } - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start > 0) - return false; - - if(partition.End < 8) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(6, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length != 128) - return false; - - VolumeLabel vol = Marshal.ByteArrayToStructureLittleEndian(sector); - - return _magic.SequenceEqual(vol.labelIdentifier) && vol.labelNumber == 1 && vol.recordLength == 0x31; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); - information = ""; - ErrorNumber errno = imagePlugin.ReadSector(6, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - var sbInformation = new StringBuilder(); - - VolumeLabel vol = Marshal.ByteArrayToStructureLittleEndian(sector); - - sbInformation.AppendLine("ECMA-67"); - - sbInformation.AppendFormat("Volume name: {0}", Encoding.ASCII.GetString(vol.volumeIdentifier)).AppendLine(); - sbInformation.AppendFormat("Volume owner: {0}", Encoding.ASCII.GetString(vol.owner)).AppendLine(); - - XmlFsType = new FileSystemType - { - Type = "ECMA-67", - ClusterSize = 256, - Clusters = partition.End - partition.Start + 1, - VolumeName = Encoding.ASCII.GetString(vol.volumeIdentifier) - }; - - information = sbInformation.ToString(); - } +#region Nested type: VolumeLabel [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct VolumeLabel @@ -140,4 +66,6 @@ public sealed class ECMA67 : IFilesystem [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] public readonly byte[] reserved5; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/EFS.cs b/Aaru.Filesystems/EFS.cs deleted file mode 100644 index 5744f1f92..000000000 --- a/Aaru.Filesystems/EFS.cs +++ /dev/null @@ -1,288 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : EFS.cs -// Author(s) : Natalia Portillo -// -// Component : Extent File System plugin -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Extent File System and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements identification for the SGI Extent FileSystem -public sealed class EFS : IFilesystem -{ - const uint EFS_MAGIC = 0x00072959; - const uint EFS_MAGIC_NEW = 0x0007295A; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Extent File System Plugin"; - /// - public Guid Id => new("52A43F90-9AF3-4391-ADFE-65598DEEABAB"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 512) - return false; - - // Misaligned - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) - { - var sbSize = (uint)((Marshal.SizeOf() + 0x200) / imagePlugin.Info.SectorSize); - - if((Marshal.SizeOf() + 0x200) % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - var sbpiece = new byte[Marshal.SizeOf()]; - - Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf()); - - Superblock sb = Marshal.ByteArrayToStructureBigEndian(sbpiece); - - AaruConsole.DebugWriteLine("EFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})", - 0x200, sb.sb_magic, EFS_MAGIC, EFS_MAGIC_NEW); - - if(sb.sb_magic is EFS_MAGIC or EFS_MAGIC_NEW) - return true; - } - else - { - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + 1, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - Superblock sb = Marshal.ByteArrayToStructureBigEndian(sector); - - AaruConsole.DebugWriteLine("EFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})", 1, - sb.sb_magic, EFS_MAGIC, EFS_MAGIC_NEW); - - if(sb.sb_magic is EFS_MAGIC or EFS_MAGIC_NEW) - return true; - } - - return false; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - if(imagePlugin.Info.SectorSize < 512) - return; - - Superblock efsSb; - - // Misaligned - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) - { - var sbSize = (uint)((Marshal.SizeOf() + 0x400) / imagePlugin.Info.SectorSize); - - if((Marshal.SizeOf() + 0x400) % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < Marshal.SizeOf()) - return; - - var sbpiece = new byte[Marshal.SizeOf()]; - - Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf()); - - efsSb = Marshal.ByteArrayToStructureBigEndian(sbpiece); - - AaruConsole.DebugWriteLine("EFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})", - 0x200, efsSb.sb_magic, EFS_MAGIC, EFS_MAGIC_NEW); - } - else - { - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + 1, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < Marshal.SizeOf()) - return; - - efsSb = Marshal.ByteArrayToStructureBigEndian(sector); - - AaruConsole.DebugWriteLine("EFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})", 1, - efsSb.sb_magic, EFS_MAGIC, EFS_MAGIC_NEW); - } - - if(efsSb.sb_magic != EFS_MAGIC && - efsSb.sb_magic != EFS_MAGIC_NEW) - return; - - var sb = new StringBuilder(); - - sb.AppendLine("SGI extent filesystem"); - - if(efsSb.sb_magic == EFS_MAGIC_NEW) - sb.AppendLine("New version"); - - sb.AppendFormat("Filesystem size: {0} basic blocks", efsSb.sb_size).AppendLine(); - sb.AppendFormat("First cylinder group starts at block {0}", efsSb.sb_firstcg).AppendLine(); - sb.AppendFormat("Cylinder group size: {0} basic blocks", efsSb.sb_cgfsize).AppendLine(); - sb.AppendFormat("{0} inodes per cylinder group", efsSb.sb_cgisize).AppendLine(); - sb.AppendFormat("{0} sectors per track", efsSb.sb_sectors).AppendLine(); - sb.AppendFormat("{0} heads per cylinder", efsSb.sb_heads).AppendLine(); - sb.AppendFormat("{0} cylinder groups", efsSb.sb_ncg).AppendLine(); - sb.AppendFormat("Volume created on {0}", DateHandlers.UnixToDateTime(efsSb.sb_time)).AppendLine(); - sb.AppendFormat("{0} bytes on bitmap", efsSb.sb_bmsize).AppendLine(); - sb.AppendFormat("{0} free blocks", efsSb.sb_tfree).AppendLine(); - sb.AppendFormat("{0} free inodes", efsSb.sb_tinode).AppendLine(); - - if(efsSb.sb_bmblock > 0) - sb.AppendFormat("Bitmap resides at block {0}", efsSb.sb_bmblock).AppendLine(); - - if(efsSb.sb_replsb > 0) - sb.AppendFormat("Replacement superblock resides at block {0}", efsSb.sb_replsb).AppendLine(); - - if(efsSb.sb_lastinode > 0) - sb.AppendFormat("Last inode allocated: {0}", efsSb.sb_lastinode).AppendLine(); - - if(efsSb.sb_dirty > 0) - sb.AppendLine("Volume is dirty"); - - sb.AppendFormat("Checksum: 0x{0:X8}", efsSb.sb_checksum).AppendLine(); - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(efsSb.sb_fname, Encoding)).AppendLine(); - sb.AppendFormat("Volume pack: {0}", StringHandlers.CToString(efsSb.sb_fpack, Encoding)).AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Type = "Extent File System", - ClusterSize = 512, - Clusters = (ulong)efsSb.sb_size, - FreeClusters = (ulong)efsSb.sb_tfree, - FreeClustersSpecified = true, - Dirty = efsSb.sb_dirty > 0, - VolumeName = StringHandlers.CToString(efsSb.sb_fname, Encoding), - VolumeSerial = $"{efsSb.sb_checksum:X8}", - CreationDate = DateHandlers.UnixToDateTime(efsSb.sb_time), - CreationDateSpecified = true - }; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "InconsistentNaming")] - readonly struct Superblock - { - /* 0: fs size incl. bb 0 (in bb) */ - public readonly int sb_size; - /* 4: first cg offset (in bb) */ - public readonly int sb_firstcg; - /* 8: cg size (in bb) */ - public readonly int sb_cgfsize; - /* 12: inodes/cg (in bb) */ - public readonly short sb_cgisize; - /* 14: geom: sectors/track */ - public readonly short sb_sectors; - /* 16: geom: heads/cylinder (unused) */ - public readonly short sb_heads; - /* 18: num of cg's in the filesystem */ - public readonly short sb_ncg; - /* 20: non-0 indicates fsck required */ - public readonly short sb_dirty; - /* 22: */ - public readonly short sb_pad0; - /* 24: superblock ctime */ - public readonly int sb_time; - /* 28: magic [0] */ - public readonly uint sb_magic; - /* 32: name of filesystem */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public readonly byte[] sb_fname; - /* 38: name of filesystem pack */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public readonly byte[] sb_fpack; - /* 44: bitmap size (in bytes) */ - public readonly int sb_bmsize; - /* 48: total free data blocks */ - public readonly int sb_tfree; - /* 52: total free inodes */ - public readonly int sb_tinode; - /* 56: bitmap offset (grown fs) */ - public readonly int sb_bmblock; - /* 62: repl. superblock offset */ - public readonly int sb_replsb; - /* 64: last allocated inode */ - public readonly int sb_lastinode; - /* 68: unused */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public readonly byte[] sb_spare; - /* 88: checksum (all above) */ - public readonly uint sb_checksum; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/EFS/Consts.cs b/Aaru.Filesystems/EFS/Consts.cs new file mode 100644 index 000000000..9f575d8bf --- /dev/null +++ b/Aaru.Filesystems/EFS/Consts.cs @@ -0,0 +1,39 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Extent File System plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements identification for the SGI Extent FileSystem +public sealed partial class EFS +{ + const uint EFS_MAGIC = 0x00072959; + const uint EFS_MAGIC_NEW = 0x0007295A; + + const string FS_TYPE = "efs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/EFS/EFS.cs b/Aaru.Filesystems/EFS/EFS.cs new file mode 100644 index 000000000..84c66d187 --- /dev/null +++ b/Aaru.Filesystems/EFS/EFS.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : EFS.cs +// Author(s) : Natalia Portillo +// +// Component : Extent File System plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements identification for the SGI Extent FileSystem +public sealed partial class EFS : IFilesystem +{ + const string MODULE_NAME = "EFS plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.EFS_Name; + + /// + public Guid Id => new("52A43F90-9AF3-4391-ADFE-65598DEEABAB"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/EFS/Info.cs b/Aaru.Filesystems/EFS/Info.cs new file mode 100644 index 000000000..48e6ae90a --- /dev/null +++ b/Aaru.Filesystems/EFS/Info.cs @@ -0,0 +1,216 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Extent File System plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements identification for the SGI Extent FileSystem +public sealed partial class EFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 512) return false; + + // Misaligned + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) + { + var sbSize = (uint)((Marshal.SizeOf() + 0x200) / imagePlugin.Info.SectorSize); + + if((Marshal.SizeOf() + 0x200) % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + var sbpiece = new byte[Marshal.SizeOf()]; + + Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf()); + + Superblock sb = Marshal.ByteArrayToStructureBigEndian(sbpiece); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.magic_at_0_equals_1_expected_2_or_3, + 0x200, + sb.sb_magic, + EFS_MAGIC, + EFS_MAGIC_NEW); + + if(sb.sb_magic is EFS_MAGIC or EFS_MAGIC_NEW) return true; + } + else + { + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + 1, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + Superblock sb = Marshal.ByteArrayToStructureBigEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.magic_at_0_equals_1_expected_2_or_3, + 1, + sb.sb_magic, + EFS_MAGIC, + EFS_MAGIC_NEW); + + if(sb.sb_magic is EFS_MAGIC or EFS_MAGIC_NEW) return true; + } + + return false; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize < 512) return; + + Superblock efsSb; + + // Misaligned + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) + { + var sbSize = (uint)((Marshal.SizeOf() + 0x400) / imagePlugin.Info.SectorSize); + + if((Marshal.SizeOf() + 0x400) % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < Marshal.SizeOf()) return; + + var sbpiece = new byte[Marshal.SizeOf()]; + + Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf()); + + efsSb = Marshal.ByteArrayToStructureBigEndian(sbpiece); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.magic_at_0_X3_equals_1_expected_2_or_3, + 0x200, + efsSb.sb_magic, + EFS_MAGIC, + EFS_MAGIC_NEW); + } + else + { + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + 1, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < Marshal.SizeOf()) return; + + efsSb = Marshal.ByteArrayToStructureBigEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.magic_at_0_equals_1_expected_2_or_3, + 1, + efsSb.sb_magic, + EFS_MAGIC, + EFS_MAGIC_NEW); + } + + if(efsSb.sb_magic != EFS_MAGIC && efsSb.sb_magic != EFS_MAGIC_NEW) return; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.SGI_extent_filesystem); + + if(efsSb.sb_magic == EFS_MAGIC_NEW) sb.AppendLine(Localization.New_version); + + sb.AppendFormat(Localization.Filesystem_size_0_basic_blocks, efsSb.sb_size).AppendLine(); + sb.AppendFormat(Localization.First_cylinder_group_starts_at_block_0, efsSb.sb_firstcg).AppendLine(); + sb.AppendFormat(Localization.Cylinder_group_size_0_basic_blocks, efsSb.sb_cgfsize).AppendLine(); + sb.AppendFormat(Localization._0_inodes_per_cylinder_group, efsSb.sb_cgisize).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_track, efsSb.sb_sectors).AppendLine(); + sb.AppendFormat(Localization._0_heads_per_cylinder, efsSb.sb_heads).AppendLine(); + sb.AppendFormat(Localization._0_cylinder_groups, efsSb.sb_ncg).AppendLine(); + sb.AppendFormat(Localization.Volume_created_on_0, DateHandlers.UnixToDateTime(efsSb.sb_time)).AppendLine(); + sb.AppendFormat(Localization._0_bytes_on_bitmap, efsSb.sb_bmsize).AppendLine(); + sb.AppendFormat(Localization._0_free_blocks, efsSb.sb_tfree).AppendLine(); + sb.AppendFormat(Localization._0_free_inodes, efsSb.sb_tinode).AppendLine(); + + if(efsSb.sb_bmblock > 0) sb.AppendFormat(Localization.Bitmap_resides_at_block_0, efsSb.sb_bmblock).AppendLine(); + + if(efsSb.sb_replsb > 0) + sb.AppendFormat(Localization.Replacement_superblock_resides_at_block_0, efsSb.sb_replsb).AppendLine(); + + if(efsSb.sb_lastinode > 0) + sb.AppendFormat(Localization.Last_inode_allocated_0, efsSb.sb_lastinode).AppendLine(); + + if(efsSb.sb_dirty > 0) sb.AppendLine(Localization.Volume_is_dirty); + + sb.AppendFormat(Localization.Checksum_0_X8, efsSb.sb_checksum).AppendLine(); + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(efsSb.sb_fname, encoding)).AppendLine(); + sb.AppendFormat(Localization.Volume_pack_0, StringHandlers.CToString(efsSb.sb_fpack, encoding)).AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = 512, + Clusters = (ulong)efsSb.sb_size, + FreeClusters = (ulong)efsSb.sb_tfree, + Dirty = efsSb.sb_dirty > 0, + VolumeName = StringHandlers.CToString(efsSb.sb_fname, encoding), + VolumeSerial = $"{efsSb.sb_checksum:X8}", + CreationDate = DateHandlers.UnixToDateTime(efsSb.sb_time) + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/EFS/Structs.cs b/Aaru.Filesystems/EFS/Structs.cs new file mode 100644 index 000000000..9987a16ab --- /dev/null +++ b/Aaru.Filesystems/EFS/Structs.cs @@ -0,0 +1,92 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Extent File System plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements identification for the SGI Extent FileSystem +public sealed partial class EFS +{ +#region Nested type: Superblock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [SuppressMessage("ReSharper", "InconsistentNaming")] + readonly struct Superblock + { + /* 0: fs size incl. bb 0 (in bb) */ + public readonly int sb_size; + /* 4: first cg offset (in bb) */ + public readonly int sb_firstcg; + /* 8: cg size (in bb) */ + public readonly int sb_cgfsize; + /* 12: inodes/cg (in bb) */ + public readonly short sb_cgisize; + /* 14: geom: sectors/track */ + public readonly short sb_sectors; + /* 16: geom: heads/cylinder (unused) */ + public readonly short sb_heads; + /* 18: num of cg's in the filesystem */ + public readonly short sb_ncg; + /* 20: non-0 indicates fsck required */ + public readonly short sb_dirty; + /* 22: */ + public readonly short sb_pad0; + /* 24: superblock ctime */ + public readonly int sb_time; + /* 28: magic [0] */ + public readonly uint sb_magic; + /* 32: name of filesystem */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public readonly byte[] sb_fname; + /* 38: name of filesystem pack */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public readonly byte[] sb_fpack; + /* 44: bitmap size (in bytes) */ + public readonly int sb_bmsize; + /* 48: total free data blocks */ + public readonly int sb_tfree; + /* 52: total free inodes */ + public readonly int sb_tinode; + /* 56: bitmap offset (grown fs) */ + public readonly int sb_bmblock; + /* 62: repl. superblock offset */ + public readonly int sb_replsb; + /* 64: last allocated inode */ + public readonly int sb_lastinode; + /* 68: unused */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public readonly byte[] sb_spare; + /* 88: checksum (all above) */ + public readonly uint sb_checksum; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/F2FS.cs b/Aaru.Filesystems/F2FS.cs deleted file mode 100644 index d2e9c413b..000000000 --- a/Aaru.Filesystems/F2FS.cs +++ /dev/null @@ -1,239 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : F2FS.cs -// Author(s) : Natalia Portillo -// -// Component : F2FS filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the F2FS filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the Flash-Friendly File System (F2FS) -[SuppressMessage("ReSharper", "UnusedMember.Local")] -public sealed class F2FS : IFilesystem -{ - // ReSharper disable InconsistentNaming - const uint F2FS_MAGIC = 0xF2F52010; - const uint F2FS_SUPER_OFFSET = 1024; - const uint F2FS_MIN_SECTOR = 512; - const uint F2FS_MAX_SECTOR = 4096; - const uint F2FS_BLOCK_SIZE = 4096; - - // ReSharper restore InconsistentNaming - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "F2FS Plugin"; - /// - public Guid Id => new("82B0920F-5F0D-4063-9F57-ADE0AE02ECE5"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize is < F2FS_MIN_SECTOR or > F2FS_MAX_SECTOR) - return false; - - uint sbAddr = F2FS_SUPER_OFFSET / imagePlugin.Info.SectorSize; - - if(sbAddr == 0) - sbAddr = 1; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - if(partition.Start + sbAddr + sbSize >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - Superblock sb = Marshal.ByteArrayToStructureLittleEndian(sector); - - return sb.magic == F2FS_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = Encoding.Unicode; - information = ""; - - if(imagePlugin.Info.SectorSize is < F2FS_MIN_SECTOR or > F2FS_MAX_SECTOR) - return; - - uint sbAddr = F2FS_SUPER_OFFSET / imagePlugin.Info.SectorSize; - - if(sbAddr == 0) - sbAddr = 1; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < Marshal.SizeOf()) - return; - - // ReSharper disable once InconsistentNaming - Superblock f2fsSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - if(f2fsSb.magic != F2FS_MAGIC) - return; - - var sb = new StringBuilder(); - - sb.AppendLine("F2FS filesystem"); - sb.AppendFormat("Version {0}.{1}", f2fsSb.major_ver, f2fsSb.minor_ver).AppendLine(); - sb.AppendFormat("{0} bytes per sector", 1 << (int)f2fsSb.log_sectorsize).AppendLine(); - - sb.AppendFormat("{0} sectors ({1} bytes) per block", 1 << (int)f2fsSb.log_sectors_per_block, - 1 << (int)f2fsSb.log_blocksize).AppendLine(); - - sb.AppendFormat("{0} blocks per segment", f2fsSb.log_blocks_per_seg).AppendLine(); - sb.AppendFormat("{0} blocks in volume", f2fsSb.block_count).AppendLine(); - sb.AppendFormat("{0} segments per section", f2fsSb.segs_per_sec).AppendLine(); - sb.AppendFormat("{0} sections per zone", f2fsSb.secs_per_zone).AppendLine(); - sb.AppendFormat("{0} sections", f2fsSb.section_count).AppendLine(); - sb.AppendFormat("{0} segments", f2fsSb.segment_count).AppendLine(); - sb.AppendFormat("Root directory resides on inode {0}", f2fsSb.root_ino).AppendLine(); - sb.AppendFormat("Volume UUID: {0}", f2fsSb.uuid).AppendLine(); - - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(f2fsSb.volume_name, Encoding.Unicode, true)). - AppendLine(); - - sb.AppendFormat("Volume last mounted on kernel version: {0}", StringHandlers.CToString(f2fsSb.version)). - AppendLine(); - - sb.AppendFormat("Volume created on kernel version: {0}", StringHandlers.CToString(f2fsSb.init_version)). - AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Type = "F2FS filesystem", - SystemIdentifier = Encoding.ASCII.GetString(f2fsSb.version), - Clusters = f2fsSb.block_count, - ClusterSize = (uint)(1 << (int)f2fsSb.log_blocksize), - DataPreparerIdentifier = Encoding.ASCII.GetString(f2fsSb.init_version), - VolumeName = StringHandlers.CToString(f2fsSb.volume_name, Encoding.Unicode, true), - VolumeSerial = f2fsSb.uuid.ToString() - }; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "InconsistentNaming")] - readonly struct Superblock - { - public readonly uint magic; - public readonly ushort major_ver; - public readonly ushort minor_ver; - public readonly uint log_sectorsize; - public readonly uint log_sectors_per_block; - public readonly uint log_blocksize; - public readonly uint log_blocks_per_seg; - public readonly uint segs_per_sec; - public readonly uint secs_per_zone; - public readonly uint checksum_offset; - public readonly ulong block_count; - public readonly uint section_count; - public readonly uint segment_count; - public readonly uint segment_count_ckpt; - public readonly uint segment_count_sit; - public readonly uint segment_count_nat; - public readonly uint segment_count_ssa; - public readonly uint segment_count_main; - public readonly uint segment0_blkaddr; - public readonly uint cp_blkaddr; - public readonly uint sit_blkaddr; - public readonly uint nat_blkaddr; - public readonly uint ssa_blkaddr; - public readonly uint main_blkaddr; - public readonly uint root_ino; - public readonly uint node_ino; - public readonly uint meta_ino; - public readonly Guid uuid; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] - public readonly byte[] volume_name; - public readonly uint extension_count; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] extension_list1; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] extension_list2; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] extension_list3; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] extension_list4; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] extension_list5; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] extension_list6; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] extension_list7; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] extension_list8; - public readonly uint cp_payload; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] - public readonly byte[] version; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] - public readonly byte[] init_version; - public readonly uint feature; - public readonly byte encryption_level; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] encrypt_pw_salt; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 871)] - public readonly byte[] reserved; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/F2FS/Consts.cs b/Aaru.Filesystems/F2FS/Consts.cs new file mode 100644 index 000000000..acde7769c --- /dev/null +++ b/Aaru.Filesystems/F2FS/Consts.cs @@ -0,0 +1,48 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : F2FS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Flash-Friendly File System (F2FS) +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class F2FS +{ + const string FS_TYPE = "f2fs"; + + // ReSharper disable InconsistentNaming + const uint F2FS_MAGIC = 0xF2F52010; + const uint F2FS_SUPER_OFFSET = 1024; + const uint F2FS_MIN_SECTOR = 512; + const uint F2FS_MAX_SECTOR = 4096; + const uint F2FS_BLOCK_SIZE = 4096; + + // ReSharper restore InconsistentNaming +} \ No newline at end of file diff --git a/Aaru.Filesystems/F2FS/F2FS.cs b/Aaru.Filesystems/F2FS/F2FS.cs new file mode 100644 index 000000000..64c25efe4 --- /dev/null +++ b/Aaru.Filesystems/F2FS/F2FS.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : F2FS.cs +// Author(s) : Natalia Portillo +// +// Component : F2FS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Flash-Friendly File System (F2FS) +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class F2FS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.F2FS_Name; + + /// + public Guid Id => new("82B0920F-5F0D-4063-9F57-ADE0AE02ECE5"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/F2FS/Info.cs b/Aaru.Filesystems/F2FS/Info.cs new file mode 100644 index 000000000..1ce6b90d3 --- /dev/null +++ b/Aaru.Filesystems/F2FS/Info.cs @@ -0,0 +1,145 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : F2FS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Flash-Friendly File System (F2FS) +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class F2FS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize is < F2FS_MIN_SECTOR or > F2FS_MAX_SECTOR) return false; + + uint sbAddr = F2FS_SUPER_OFFSET / imagePlugin.Info.SectorSize; + + if(sbAddr == 0) sbAddr = 1; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + if(partition.Start + sbAddr + sbSize >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + Superblock sb = Marshal.ByteArrayToStructureLittleEndian(sector); + + return sb.magic == F2FS_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize is < F2FS_MIN_SECTOR or > F2FS_MAX_SECTOR) return; + + uint sbAddr = F2FS_SUPER_OFFSET / imagePlugin.Info.SectorSize; + + if(sbAddr == 0) sbAddr = 1; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < Marshal.SizeOf()) return; + + // ReSharper disable once InconsistentNaming + Superblock f2fsSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + if(f2fsSb.magic != F2FS_MAGIC) return; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.F2FS_filesystem); + sb.AppendFormat(Localization.Version_0_1, f2fsSb.major_ver, f2fsSb.minor_ver).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector, 1 << (int)f2fsSb.log_sectorsize).AppendLine(); + + sb.AppendFormat(Localization._0_sectors_1_bytes_per_block, + 1 << (int)f2fsSb.log_sectors_per_block, + 1 << (int)f2fsSb.log_blocksize) + .AppendLine(); + + sb.AppendFormat(Localization._0_blocks_per_segment, f2fsSb.log_blocks_per_seg).AppendLine(); + sb.AppendFormat(Localization._0_blocks_in_volume, f2fsSb.block_count).AppendLine(); + sb.AppendFormat(Localization._0_segments_per_section, f2fsSb.segs_per_sec).AppendLine(); + sb.AppendFormat(Localization._0_sections_per_zone, f2fsSb.secs_per_zone).AppendLine(); + sb.AppendFormat(Localization._0_sections, f2fsSb.section_count).AppendLine(); + sb.AppendFormat(Localization._0_segments, f2fsSb.segment_count).AppendLine(); + sb.AppendFormat(Localization.Root_directory_resides_on_inode_0, f2fsSb.root_ino).AppendLine(); + sb.AppendFormat(Localization.Volume_UUID_0, f2fsSb.uuid).AppendLine(); + + sb.AppendFormat(Localization.Volume_name_0, + StringHandlers.CToString(f2fsSb.volume_name, Encoding.Unicode, true)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_last_mounted_on_kernel_version_0, StringHandlers.CToString(f2fsSb.version)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_created_on_kernel_version_0, StringHandlers.CToString(f2fsSb.init_version)) + .AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + SystemIdentifier = Encoding.ASCII.GetString(f2fsSb.version), + Clusters = f2fsSb.block_count, + ClusterSize = (uint)(1 << (int)f2fsSb.log_blocksize), + DataPreparerIdentifier = Encoding.ASCII.GetString(f2fsSb.init_version), + VolumeName = StringHandlers.CToString(f2fsSb.volume_name, Encoding.Unicode, true), + VolumeSerial = f2fsSb.uuid.ToString() + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/F2FS/Structs.cs b/Aaru.Filesystems/F2FS/Structs.cs new file mode 100644 index 000000000..8ec302bfd --- /dev/null +++ b/Aaru.Filesystems/F2FS/Structs.cs @@ -0,0 +1,107 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : F2FS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Flash-Friendly File System (F2FS) +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class F2FS +{ +#region Nested type: Superblock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [SuppressMessage("ReSharper", "InconsistentNaming")] + readonly struct Superblock + { + public readonly uint magic; + public readonly ushort major_ver; + public readonly ushort minor_ver; + public readonly uint log_sectorsize; + public readonly uint log_sectors_per_block; + public readonly uint log_blocksize; + public readonly uint log_blocks_per_seg; + public readonly uint segs_per_sec; + public readonly uint secs_per_zone; + public readonly uint checksum_offset; + public readonly ulong block_count; + public readonly uint section_count; + public readonly uint segment_count; + public readonly uint segment_count_ckpt; + public readonly uint segment_count_sit; + public readonly uint segment_count_nat; + public readonly uint segment_count_ssa; + public readonly uint segment_count_main; + public readonly uint segment0_blkaddr; + public readonly uint cp_blkaddr; + public readonly uint sit_blkaddr; + public readonly uint nat_blkaddr; + public readonly uint ssa_blkaddr; + public readonly uint main_blkaddr; + public readonly uint root_ino; + public readonly uint node_ino; + public readonly uint meta_ino; + public readonly Guid uuid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] + public readonly byte[] volume_name; + public readonly uint extension_count; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] extension_list1; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] extension_list2; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] extension_list3; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] extension_list4; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] extension_list5; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] extension_list6; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] extension_list7; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] extension_list8; + public readonly uint cp_payload; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + public readonly byte[] version; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + public readonly byte[] init_version; + public readonly uint feature; + public readonly byte encryption_level; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] encrypt_pw_salt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 871)] + public readonly byte[] reserved; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/FAT/BPB.cs b/Aaru.Filesystems/FAT/BPB.cs index ee05ffca8..27a5a8073 100644 --- a/Aaru.Filesystems/FAT/BPB.cs +++ b/Aaru.Filesystems/FAT/BPB.cs @@ -7,10 +7,6 @@ // // Component : Microsoft FAT filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Microsoft FAT Boot Parameter Block variant. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,11 +23,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.IO; using System.Text; @@ -41,6 +35,8 @@ using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class FAT { static BpbKind DetectBpbKind(byte[] bpbSector, IMediaImage imagePlugin, Partition partition, @@ -59,30 +55,41 @@ public sealed partial class FAT ulong expectedClusters = humanBpb.bpc > 0 ? partition.Size / humanBpb.bpc : 0; // Check clusters for Human68k are correct - bool humanClustersCorrect = humanBpb.clusters == 0 ? humanBpb.big_clusters == expectedClusters - : humanBpb.clusters == expectedClusters; + bool humanClustersCorrect = humanBpb.clusters == 0 + ? humanBpb.big_clusters == expectedClusters + : humanBpb.clusters == expectedClusters; // Check OEM for Human68k is correct - bool humanOemCorrect = bpbSector[2] >= 0x20 && bpbSector[3] >= 0x20 && bpbSector[4] >= 0x20 && - bpbSector[5] >= 0x20 && bpbSector[6] >= 0x20 && bpbSector[7] >= 0x20 && - bpbSector[8] >= 0x20 && bpbSector[9] >= 0x20 && bpbSector[10] >= 0x20 && - bpbSector[11] >= 0x20 && bpbSector[12] >= 0x20 && bpbSector[13] >= 0x20 && - bpbSector[14] >= 0x20 && bpbSector[15] >= 0x20 && bpbSector[16] >= 0x20 && + bool humanOemCorrect = bpbSector[2] >= 0x20 && + bpbSector[3] >= 0x20 && + bpbSector[4] >= 0x20 && + bpbSector[5] >= 0x20 && + bpbSector[6] >= 0x20 && + bpbSector[7] >= 0x20 && + bpbSector[8] >= 0x20 && + bpbSector[9] >= 0x20 && + bpbSector[10] >= 0x20 && + bpbSector[11] >= 0x20 && + bpbSector[12] >= 0x20 && + bpbSector[13] >= 0x20 && + bpbSector[14] >= 0x20 && + bpbSector[15] >= 0x20 && + bpbSector[16] >= 0x20 && bpbSector[17] >= 0x20; // Check correct branch for Human68k bool humanBranchCorrect = bpbSector[0] == 0x60 && bpbSector[1] >= 0x1C && bpbSector[1] < 0xFE; - AaruConsole.DebugWriteLine("FAT plugin", "humanClustersCorrect = {0}", humanClustersCorrect); - AaruConsole.DebugWriteLine("FAT plugin", "humanOemCorrect = {0}", humanOemCorrect); - AaruConsole.DebugWriteLine("FAT plugin", "humanBranchCorrect = {0}", humanBranchCorrect); + AaruConsole.DebugWriteLine(MODULE_NAME, "humanClustersCorrect = {0}", humanClustersCorrect); + AaruConsole.DebugWriteLine(MODULE_NAME, "humanOemCorrect = {0}", humanOemCorrect); + AaruConsole.DebugWriteLine(MODULE_NAME, "humanBranchCorrect = {0}", humanBranchCorrect); // If all Human68k checks are correct, it is a Human68k FAT16 bool useHumanBpb = humanClustersCorrect && humanOemCorrect && humanBranchCorrect && expectedClusters > 0; if(useHumanBpb) { - AaruConsole.DebugWriteLine("FAT plugin", "Using Human68k BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_Human68k_BPB); fakeBpb.jump = humanBpb.jump; fakeBpb.oem_name = humanBpb.oem_name; @@ -117,10 +124,7 @@ public sealed partial class FAT var useDos33Bpb = false; var userShortExtendedBpb = false; var useExtendedBpb = false; - var useShortFat32 = false; - var useLongFat32 = false; var useApricotBpb = false; - var useDecRainbowBpb = false; if(imagePlugin.Info.SectorSize >= 256) { @@ -158,7 +162,7 @@ public sealed partial class FAT bool correctSpcApricot = apricotBpb.mainBPB.spc is 1 or 2 or 4 or 8 or 16 or 32 or 64; // This is to support FAT partitions on hybrid ISO/USB images - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) { atariBpb.sectors /= 4; msxBpb.sectors /= 4; @@ -179,32 +183,32 @@ public sealed partial class FAT apricotBpb.mainBPB.sectors /= 4; } - andosOemCorrect = dos33Bpb.oem_name[0] < 0x20 && dos33Bpb.oem_name[1] >= 0x20 && - dos33Bpb.oem_name[2] >= 0x20 && dos33Bpb.oem_name[3] >= 0x20 && - dos33Bpb.oem_name[4] >= 0x20 && dos33Bpb.oem_name[5] >= 0x20 && - dos33Bpb.oem_name[6] >= 0x20 && dos33Bpb.oem_name[7] >= 0x20; + andosOemCorrect = dos33Bpb.oem_name[0] < 0x20 && + dos33Bpb.oem_name[1] >= 0x20 && + dos33Bpb.oem_name[2] >= 0x20 && + dos33Bpb.oem_name[3] >= 0x20 && + dos33Bpb.oem_name[4] >= 0x20 && + dos33Bpb.oem_name[5] >= 0x20 && + dos33Bpb.oem_name[6] >= 0x20 && + dos33Bpb.oem_name[7] >= 0x20; - if(bitsInBpsFat32 == 1 && - correctSpcFat32 && - fat32Bpb.fats_no <= 2 && - fat32Bpb.spfat == 0 && - fat32Bpb.signature == 0x29 && + if(bitsInBpsFat32 == 1 && + correctSpcFat32 && + fat32Bpb.fats_no <= 2 && + fat32Bpb is { spfat: 0, signature: 0x29 } && Encoding.ASCII.GetString(fat32Bpb.fs_type) == "FAT32 ") { - AaruConsole.DebugWriteLine("FAT plugin", "Using FAT32 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_FAT32_BPB); minBootNearJump = 0x58; return BpbKind.LongFat32; } - if(bitsInBpsFat32Short == 1 && - correctSpcFat32Short && - shortFat32Bpb.fats_no <= 2 && - shortFat32Bpb.sectors == 0 && - shortFat32Bpb.spfat == 0 && - shortFat32Bpb.signature == 0x28) + if(bitsInBpsFat32Short == 1 && + correctSpcFat32Short && + shortFat32Bpb is { fats_no: <= 2, sectors: 0 } and { spfat: 0, signature: 0x28 }) { - AaruConsole.DebugWriteLine("FAT plugin", "Using short FAT32 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_short_FAT32_BPB); minBootNearJump = 0x57; @@ -213,75 +217,76 @@ public sealed partial class FAT if(bitsInBpsMsx == 1 && correctSpcMsx && - msxBpb.fats_no <= 2 && - msxBpb.root_ent > 0 && + msxBpb is { fats_no: <= 2, root_ent: > 0 } && msxBpb.sectors <= partition.End - partition.Start + 1 && msxBpb.spfat > 0 && Encoding.ASCII.GetString(msxBpb.vol_id) == "VOL_ID") { - AaruConsole.DebugWriteLine("FAT plugin", "Using MSX BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_MSX_BPB); useMsxBpb = true; } - else if(bitsInBpsApricot == 1 && - correctSpcApricot && - apricotBpb.mainBPB.fats_no <= 2 && - apricotBpb.mainBPB.root_ent > 0 && - apricotBpb.mainBPB.sectors <= partition.End - partition.Start + 1 && - apricotBpb.mainBPB.spfat > 0 && - apricotBpb.partitionCount == 0) + else if(bitsInBpsApricot == 1 && + correctSpcApricot && + apricotBpb.mainBPB is { fats_no: <= 2, root_ent: > 0 } && + apricotBpb.mainBPB.sectors <= partition.End - partition.Start + 1 && + apricotBpb.mainBPB.spfat > 0 && + apricotBpb.partitionCount == 0) { - AaruConsole.DebugWriteLine("FAT plugin", "Using Apricot BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_Apricot_BPB); useApricotBpb = true; } - else if(bitsInBpsDos40 == 1 && - correctSpcDos40 && - ebpb.fats_no <= 2 && - ebpb.root_ent > 0 && - ebpb.spfat > 0 && + else if(bitsInBpsDos40 == 1 && + correctSpcDos40 && + ebpb.fats_no <= 2 && + ebpb is { root_ent: > 0, spfat: > 0 } && (ebpb.signature is 0x28 or 0x29 || andosOemCorrect)) { if(ebpb.sectors == 0) { if(ebpb.big_sectors <= partition.End - partition.Start + 1) + { if(ebpb.signature == 0x29 || andosOemCorrect) { - AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 4.0 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_4_0_BPB); useExtendedBpb = true; minBootNearJump = 0x3C; } else { - AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.4 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_3_4_BPB); userShortExtendedBpb = true; minBootNearJump = 0x29; } + } } else if(ebpb.sectors <= partition.End - partition.Start + 1) + { if(ebpb.signature == 0x29 || andosOemCorrect) { - AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 4.0 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_4_0_BPB); useExtendedBpb = true; minBootNearJump = 0x3C; } else { - AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.4 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_3_4_BPB); userShortExtendedBpb = true; minBootNearJump = 0x29; } + } } else if(bitsInBpsDos33 == 1 && correctSpcDos33 && dos33Bpb.rsectors < partition.End - partition.Start && dos33Bpb.fats_no <= 2 && - dos33Bpb.root_ent > 0 && - dos33Bpb.spfat > 0) + dos33Bpb is { root_ent: > 0, spfat: > 0 }) + { if(dos33Bpb.sectors == 0 && dos33Bpb.hsectors <= partition.Start && dos33Bpb.big_sectors > 0 && dos33Bpb.big_sectors <= partition.End - partition.Start + 1) { - AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.3 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_3_3_BPB); useDos33Bpb = true; minBootNearJump = 0x22; } @@ -289,78 +294,80 @@ public sealed partial class FAT dos33Bpb.hsectors <= partition.Start && dos33Bpb.sectors > 0 && dos33Bpb.sectors <= partition.End - partition.Start + 1) + { if(atariBpb.jump[0] == 0x60 || - atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 && + atariBpb.jump[0] == 0xE9 && + atariBpb.jump[1] == 0x00 && Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT " || partition.Type is "GEM" or "BGM") { - AaruConsole.DebugWriteLine("FAT plugin", "Using Atari BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_Atari_BPB); useAtariBpb = true; } else { - AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.3 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_3_3_BPB); useDos33Bpb = true; minBootNearJump = 0x22; } + } else { if(dos32Bpb.hsectors <= partition.Start && dos32Bpb.hsectors + dos32Bpb.sectors == dos32Bpb.total_sectors) { - AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.2 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_3_2_BPB); useDos32Bpb = true; minBootNearJump = 0x1E; } - else if(dos30Bpb.sptrk > 0 && - dos30Bpb.sptrk < 64 && - dos30Bpb.heads > 0 && - dos30Bpb.heads < 256) + else if(dos30Bpb.sptrk is > 0 and < 64 && dos30Bpb.heads is > 0 and < 256) + { if(atariBpb.jump[0] == 0x60 || - atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 && + atariBpb.jump[0] == 0xE9 && + atariBpb.jump[1] == 0x00 && Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT ") { - AaruConsole.DebugWriteLine("FAT plugin", "Using Atari BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_Atari_BPB); useAtariBpb = true; } else { - AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 3.0 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_3_0_BPB); useDos3Bpb = true; minBootNearJump = 0x1C; } + } else { if(atariBpb.jump[0] == 0x60 || - atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 && + atariBpb.jump[0] == 0xE9 && + atariBpb.jump[1] == 0x00 && Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT ") { - AaruConsole.DebugWriteLine("FAT plugin", "Using Atari BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_Atari_BPB); useAtariBpb = true; } else { - AaruConsole.DebugWriteLine("FAT plugin", "Using DOS 2.0 BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_2_0_BPB); useDos2Bpb = true; minBootNearJump = 0x16; } } } + } } // DEC Rainbow, lacks a BPB but has a very concrete structure... - if(imagePlugin.Info.Sectors == 800 && - imagePlugin.Info.SectorSize == 512 && - !useAtariBpb && - !useMsxBpb && - !useDos2Bpb && - !useDos3Bpb && - !useDos32Bpb && - !useDos33Bpb && - !userShortExtendedBpb && - !useExtendedBpb && - !useShortFat32 && - !useLongFat32 && + if(imagePlugin.Info is { Sectors: 800, SectorSize: 512 } && + !useAtariBpb && + !useMsxBpb && + !useDos2Bpb && + !useDos3Bpb && + !useDos32Bpb && + !useDos33Bpb && + !userShortExtendedBpb && + !useExtendedBpb && !useApricotBpb) { // DEC Rainbow boots up with a Z80, first byte should be DI (disable interrupts) @@ -392,17 +399,18 @@ public sealed partial class FAT for(var e = 0; e < 96 * 32; e += 32) { for(var c = 0; c < 11; c++) - if(rootDir[c + e] < 0x20 && rootDir[c + e] != 0x00 && rootDir[c + e] != 0x05 || - rootDir[c + e] == 0xFF || - rootDir[c + e] == 0x2E) - { - validRootDir = false; + { + if((rootDir[c + e] >= 0x20 || rootDir[c + e] == 0x00 || rootDir[c + e] == 0x05) && + rootDir[c + e] != 0xFF && + rootDir[c + e] != 0x2E) + continue; - break; - } + validRootDir = false; - if(!validRootDir) break; + } + + if(!validRootDir) break; } if(z80Di == 0xF3 && @@ -411,7 +419,7 @@ public sealed partial class FAT fat1Sector0[1] == 0xFF && validRootDir) { - AaruConsole.DebugWriteLine("FAT plugin", "Using DEC Rainbow hardcoded BPB."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DEC_Rainbow_hardcoded_BPB); fakeBpb.bps = 512; fakeBpb.spc = 1; fakeBpb.rsectors = 20; @@ -439,20 +447,16 @@ public sealed partial class FAT !useHumanBpb && !userShortExtendedBpb && !useExtendedBpb && - !useShortFat32 && - !useLongFat32 && - !useApricotBpb && - !useDecRainbowBpb) + !useApricotBpb) { imagePlugin.ReadSector(1 + partition.Start, out byte[] fatSector); switch(fatSector[0]) { case 0xE5: - if(imagePlugin.Info.Sectors == 2002 && - imagePlugin.Info.SectorSize == 128) + if(imagePlugin.Info is { Sectors: 2002, SectorSize: 128 }) { - AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_hardcoded_BPB); fakeBpb.bps = 128; fakeBpb.spc = 4; fakeBpb.rsectors = 1; @@ -468,37 +472,38 @@ public sealed partial class FAT break; case 0xFD: - if(imagePlugin.Info.Sectors == 4004 && - imagePlugin.Info.SectorSize == 128) + switch(imagePlugin.Info.Sectors) { - AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); - fakeBpb.bps = 128; - fakeBpb.spc = 4; - fakeBpb.rsectors = 4; - fakeBpb.fats_no = 2; - fakeBpb.root_ent = 68; - fakeBpb.sectors = 4004; - fakeBpb.media = 0xFD; - fakeBpb.sptrk = 26; - fakeBpb.heads = 2; - fakeBpb.hsectors = 0; - fakeBpb.spfat = 6; - } - else if(imagePlugin.Info.Sectors == 2002 && - imagePlugin.Info.SectorSize == 128) - { - AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); - fakeBpb.bps = 128; - fakeBpb.spc = 4; - fakeBpb.rsectors = 4; - fakeBpb.fats_no = 2; - fakeBpb.root_ent = 68; - fakeBpb.sectors = 2002; - fakeBpb.media = 0xFD; - fakeBpb.sptrk = 26; - fakeBpb.heads = 1; - fakeBpb.hsectors = 0; - fakeBpb.spfat = 6; + case 4004 when imagePlugin.Info.SectorSize == 128: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_hardcoded_BPB); + fakeBpb.bps = 128; + fakeBpb.spc = 4; + fakeBpb.rsectors = 4; + fakeBpb.fats_no = 2; + fakeBpb.root_ent = 68; + fakeBpb.sectors = 4004; + fakeBpb.media = 0xFD; + fakeBpb.sptrk = 26; + fakeBpb.heads = 2; + fakeBpb.hsectors = 0; + fakeBpb.spfat = 6; + + break; + case 2002 when imagePlugin.Info.SectorSize == 128: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_hardcoded_BPB); + fakeBpb.bps = 128; + fakeBpb.spc = 4; + fakeBpb.rsectors = 4; + fakeBpb.fats_no = 2; + fakeBpb.root_ent = 68; + fakeBpb.sectors = 2002; + fakeBpb.media = 0xFD; + fakeBpb.sptrk = 26; + fakeBpb.heads = 1; + fakeBpb.hsectors = 0; + fakeBpb.spfat = 6; + + break; } break; @@ -506,7 +511,7 @@ public sealed partial class FAT switch(imagePlugin.Info.Sectors) { case 320 when imagePlugin.Info.SectorSize == 512: - AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB for 5.25\" SSDD."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_hardcoded_BPB_for_5_25_SSDD); fakeBpb.bps = 512; fakeBpb.spc = 1; fakeBpb.rsectors = 1; @@ -521,7 +526,7 @@ public sealed partial class FAT break; case 2002 when imagePlugin.Info.SectorSize == 128: - AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_hardcoded_BPB); fakeBpb.bps = 128; fakeBpb.spc = 4; fakeBpb.rsectors = 1; @@ -536,7 +541,7 @@ public sealed partial class FAT break; case 1232 when imagePlugin.Info.SectorSize == 1024: - AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_hardcoded_BPB); fakeBpb.bps = 1024; fakeBpb.spc = 1; fakeBpb.rsectors = 1; @@ -551,7 +556,7 @@ public sealed partial class FAT break; case 616 when imagePlugin.Info.SectorSize == 1024: - AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_hardcoded_BPB); fakeBpb.bps = 1024; fakeBpb.spc = 1; fakeBpb.rsectors = 1; @@ -565,7 +570,7 @@ public sealed partial class FAT break; case 720 when imagePlugin.Info.SectorSize == 128: - AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_hardcoded_BPB); fakeBpb.bps = 128; fakeBpb.spc = 2; fakeBpb.rsectors = 54; @@ -580,7 +585,7 @@ public sealed partial class FAT break; case 640 when imagePlugin.Info.SectorSize == 512: - AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB for 5.25\" DSDD."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_hardcoded_BPB_for_5_25_DSDD); fakeBpb.bps = 512; fakeBpb.spc = 2; fakeBpb.rsectors = 1; @@ -598,10 +603,9 @@ public sealed partial class FAT break; case 0xFF: - if(imagePlugin.Info.Sectors == 640 && - imagePlugin.Info.SectorSize == 512) + if(imagePlugin.Info is { Sectors: 640, SectorSize: 512 }) { - AaruConsole.DebugWriteLine("FAT plugin", "Using hardcoded BPB for 5.25\" DSDD."); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_hardcoded_BPB_for_5_25_DSDD); fakeBpb.bps = 512; fakeBpb.spc = 2; fakeBpb.rsectors = 1; @@ -619,8 +623,9 @@ public sealed partial class FAT } // This assumes a bootable sector will jump somewhere or disable interrupts in x86 code - bootable |= bpbSector[0] == 0xFA || bpbSector[0] == 0xEB && bpbSector[1] <= 0x7F || - bpbSector[0] == 0xE9 && BitConverter.ToUInt16(bpbSector, 1) <= 0x1FC; + bootable |= bpbSector[0] == 0xFA || + bpbSector[0] == 0xEB && bpbSector[1] <= 0x7F || + bpbSector[0] == 0xE9 && BitConverter.ToUInt16(bpbSector, 1) <= 0x1FC; fakeBpb.boot_code = bpbSector; @@ -786,28 +791,26 @@ public sealed partial class FAT return BpbKind.Atari; } - if(useApricotBpb) + if(!useApricotBpb) return BpbKind.None; + + fakeBpb.bps = apricotBpb.mainBPB.bps; + fakeBpb.spc = apricotBpb.mainBPB.spc; + fakeBpb.rsectors = apricotBpb.mainBPB.rsectors; + fakeBpb.fats_no = apricotBpb.mainBPB.fats_no; + fakeBpb.root_ent = apricotBpb.mainBPB.root_ent; + fakeBpb.sectors = apricotBpb.mainBPB.sectors; + fakeBpb.media = apricotBpb.mainBPB.media; + fakeBpb.spfat = apricotBpb.mainBPB.spfat; + fakeBpb.sptrk = apricotBpb.spt; + bootable = apricotBpb.bootType > 0; + + if(apricotBpb.bootLocation > 0 && apricotBpb.bootLocation + apricotBpb.bootSize < imagePlugin.Info.Sectors) { - fakeBpb.bps = apricotBpb.mainBPB.bps; - fakeBpb.spc = apricotBpb.mainBPB.spc; - fakeBpb.rsectors = apricotBpb.mainBPB.rsectors; - fakeBpb.fats_no = apricotBpb.mainBPB.fats_no; - fakeBpb.root_ent = apricotBpb.mainBPB.root_ent; - fakeBpb.sectors = apricotBpb.mainBPB.sectors; - fakeBpb.media = apricotBpb.mainBPB.media; - fakeBpb.spfat = apricotBpb.mainBPB.spfat; - fakeBpb.sptrk = apricotBpb.spt; - bootable = apricotBpb.bootType > 0; - - if(apricotBpb.bootLocation > 0 && - apricotBpb.bootLocation + apricotBpb.bootSize < imagePlugin.Info.Sectors) - imagePlugin.ReadSectors(apricotBpb.bootLocation, - (uint)(apricotBpb.sectorSize * apricotBpb.bootSize) / - imagePlugin.Info.SectorSize, out fakeBpb.boot_code); - - return BpbKind.Apricot; + imagePlugin.ReadSectors(apricotBpb.bootLocation, + (uint)(apricotBpb.sectorSize * apricotBpb.bootSize) / imagePlugin.Info.SectorSize, + out fakeBpb.boot_code); } - return BpbKind.None; + return BpbKind.Apricot; } } \ No newline at end of file diff --git a/Aaru.Filesystems/FAT/Consts.cs b/Aaru.Filesystems/FAT/Consts.cs index 3e58c6d2b..750d5803e 100644 --- a/Aaru.Filesystems/FAT/Consts.cs +++ b/Aaru.Filesystems/FAT/Consts.cs @@ -7,10 +7,6 @@ // // Component : Microsoft FAT filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Microsoft FAT filesystem constants. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,17 +23,15 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable UnusedMember.Local -namespace Aaru.Filesystems; - using System; +namespace Aaru.Filesystems; + public sealed partial class FAT { const uint FSINFO_SIGNATURE1 = 0x41615252; @@ -83,8 +77,13 @@ public sealed partial class FAT const ushort EAT_ASN1 = 0xFFDD; const string FAT32_EA_TAIL = " EA. SF"; + const string FS_TYPE_FAT_PLUS = "fatplus"; + const string FS_TYPE_FAT32 = "fat32"; + const string FS_TYPE_FAT16 = "fat16"; + const string FS_TYPE_FAT12 = "fat12"; + readonly (string hash, string name)[] _knownBootHashes = - { + [ ("b639b4d5b25f63560e3b34a3a0feb732aa65486f", "Amstrad MS-DOS 3.20 (8-sector floppy)"), ("9311151f13f7611b1431593da05ddd3153370574", "Amstrad MS-DOS 3.20 (Spanish)"), ("55eda6a9b955f5199020e6b56a6954fa6fcb7dc6", "AT&T MS-DOS 2.11"), @@ -174,21 +173,9 @@ public sealed partial class FAT ("8524587ee91494cc51cc2c9d07453e84be0cdc33", "Hero Soft v1.10"), ("681a0d9d662ba368e6acb0d0bf602e1f56411144", "Human68k 2.00"), ("91e2b47c3cb46611249e4daa283a68ba21ba596a", "Human68k 2.00") - }; + ]; - [Flags] - enum FatAttributes : byte - { - ReadOnly = 0x01, - Hidden = 0x02, - System = 0x04, - VolumeLabel = 0x08, - Subdirectory = 0x10, - Archive = 0x20, - Device = 0x40, - Reserved = 0x80, - LFN = 0x0F - } +#region Nested type: BpbKind enum BpbKind { @@ -210,6 +197,61 @@ public sealed partial class FAT Human } +#endregion + +#region Nested type: CaseInfo + + [Flags] + enum CaseInfo : byte + { + /// FASTFAT.SYS indicator that basename is lowercase + LowerCaseBasename = 0x08, + /// FASTFAT.SYS indicator that extension is lowercase + LowerCaseExtension = 0x10, + AllLowerCase = 0x18, + /// FAT32.IFS < 0.97 indicator for normal EAs present + NormalEaOld = 0xEA, + /// FAT32.IFS < 0.97 indicator for critical EAs present + CriticalEaOld = 0xEC, + /// FAT32.IFS >= 0.97 indicator for normal EAs present + NormalEa = 0x40, + /// FAT32.IFS >= 0.97 indicator for critical EAs present + CriticalEa = 0x80 + } + +#endregion + +#region Nested type: EaFlags + + [Flags] + enum EaFlags : uint + { + Normal = 0, + Critical = 1 + } + +#endregion + +#region Nested type: FatAttributes + + [Flags] + enum FatAttributes : byte + { + ReadOnly = 0x01, + Hidden = 0x02, + System = 0x04, + VolumeLabel = 0x08, + Subdirectory = 0x10, + Archive = 0x20, + Device = 0x40, + Reserved = 0x80, + LFN = 0x0F + } + +#endregion + +#region Nested type: Namespace + enum Namespace { Dos, @@ -220,27 +262,5 @@ public sealed partial class FAT Human } - [Flags] - enum EaFlags : uint - { - Normal = 0, - Critical = 1 - } - - [Flags] - enum CaseInfo : byte - { - /// FASTFAT.SYS indicator that basename is lowercase - LowerCaseBasename = 0x08, - /// FASTFAT.SYS indicator that extension is lowercase - LowerCaseExtension = 0x10, AllLowerCase = 0x18, - /// FAT32.IFS < 0.97 indicator for normal EAs present - NormalEaOld = 0xEA, - /// FAT32.IFS < 0.97 indicator for critical EAs present - CriticalEaOld = 0xEC, - /// FAT32.IFS >= 0.97 indicator for normal EAs present - NormalEa = 0x40, - /// FAT32.IFS >= 0.97 indicator for critical EAs present - CriticalEa = 0x80 - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/FAT/Dir.cs b/Aaru.Filesystems/FAT/Dir.cs index 14599604e..891c5ac43 100644 --- a/Aaru.Filesystems/FAT/Dir.cs +++ b/Aaru.Filesystems/FAT/Dir.cs @@ -7,10 +7,6 @@ // // Component : Microsoft FAT filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle Microsoft FAT filesystem directories. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,22 +23,25 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class FAT { +#region IReadOnlyFilesystem Members + /// /// Solves a symbolic link. /// Link path. @@ -55,48 +54,52 @@ public sealed partial class FAT } /// - /// Lists contents from a directory. - /// Directory path. - /// Directory contents. - public ErrorNumber ReadDir(string path, out List contents) + public ErrorNumber OpenDir(string path, out IDirNode node) { - contents = null; - ErrorNumber errno; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - if(string.IsNullOrWhiteSpace(path) || - path == "/") + if(string.IsNullOrWhiteSpace(path) || path == "/") { - contents = _rootDirectoryCache.Keys.ToList(); + node = new FatDirNode + { + Path = path, + Position = 0, + Entries = _rootDirectoryCache.Values.ToArray() + }; return ErrorNumber.NoError; } - string cutPath = path.StartsWith("/", StringComparison.Ordinal) ? path.Substring(1).ToLower(_cultureInfo) + string cutPath = path.StartsWith("/", StringComparison.Ordinal) + ? path[1..].ToLower(_cultureInfo) : path.ToLower(_cultureInfo); if(_directoryCache.TryGetValue(cutPath, out Dictionary currentDirectory)) { - contents = currentDirectory.Keys.ToList(); + node = new FatDirNode + { + Path = path, + Position = 0, + Entries = currentDirectory.Values.ToArray() + }; return ErrorNumber.NoError; } string[] pieces = cutPath.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); KeyValuePair entry = _rootDirectoryCache.FirstOrDefault(t => t.Key.ToLower(_cultureInfo) == pieces[0]); - if(string.IsNullOrEmpty(entry.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(entry.Key)) return ErrorNumber.NoSuchFile; - if(!entry.Value.Dirent.attributes.HasFlag(FatAttributes.Subdirectory)) - return ErrorNumber.NotDirectory; + if(!entry.Value.Dirent.attributes.HasFlag(FatAttributes.Subdirectory)) return ErrorNumber.NotDirectory; string currentPath = pieces[0]; @@ -106,44 +109,45 @@ public sealed partial class FAT { entry = currentDirectory.FirstOrDefault(t => t.Key.ToLower(_cultureInfo) == pieces[p]); - if(string.IsNullOrEmpty(entry.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(entry.Key)) return ErrorNumber.NoSuchFile; - if(!entry.Value.Dirent.attributes.HasFlag(FatAttributes.Subdirectory)) - return ErrorNumber.NotDirectory; + if(!entry.Value.Dirent.attributes.HasFlag(FatAttributes.Subdirectory)) return ErrorNumber.NotDirectory; currentPath = p == 0 ? pieces[0] : $"{currentPath}/{pieces[p]}"; uint currentCluster = entry.Value.Dirent.start_cluster; - if(_fat32) - currentCluster += (uint)(entry.Value.Dirent.ea_handle << 16); + if(_fat32) currentCluster += (uint)(entry.Value.Dirent.ea_handle << 16); - if(_directoryCache.TryGetValue(currentPath, out currentDirectory)) - continue; + if(_directoryCache.TryGetValue(currentPath, out currentDirectory)) continue; // Reserved unallocated directory, seen in Atari ST if(currentCluster == 0) { _directoryCache[currentPath] = new Dictionary(); - contents = new List(); + + node = new FatDirNode + { + Path = path, + Position = 0, + Entries = [] + }; return ErrorNumber.NoError; } uint[] clusters = GetClusters(currentCluster); - if(clusters is null) - return ErrorNumber.InvalidArgument; + if(clusters is null) return ErrorNumber.InvalidArgument; var directoryBuffer = new byte[_bytesPerCluster * clusters.Length]; for(var i = 0; i < clusters.Length; i++) { - errno = _image.ReadSectors(_firstClusterSector + clusters[i] * _sectorsPerCluster, _sectorsPerCluster, - out byte[] buffer); + ErrorNumber errno = _image.ReadSectors(_firstClusterSector + clusters[i] * _sectorsPerCluster, + _sectorsPerCluster, + out byte[] buffer); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; Array.Copy(buffer, 0, directoryBuffer, i * _bytesPerCluster, _bytesPerCluster); } @@ -155,26 +159,24 @@ public sealed partial class FAT for(var pos = 0; pos < directoryBuffer.Length; pos += Marshal.SizeOf()) { DirectoryEntry dirent = - Marshal.ByteArrayToStructureLittleEndian(directoryBuffer, pos, + Marshal.ByteArrayToStructureLittleEndian(directoryBuffer, + pos, Marshal.SizeOf()); - if(dirent.filename[0] == DIRENT_FINISHED) - break; + if(dirent.filename[0] == DIRENT_FINISHED) break; if(dirent.attributes.HasFlag(FatAttributes.LFN)) { - if(_namespace != Namespace.Lfn && - _namespace != Namespace.Ecs) - continue; + if(_namespace != Namespace.Lfn && _namespace != Namespace.Ecs) continue; LfnEntry lfnEntry = - Marshal.ByteArrayToStructureLittleEndian(directoryBuffer, pos, + Marshal.ByteArrayToStructureLittleEndian(directoryBuffer, + pos, Marshal.SizeOf()); int lfnSequence = lfnEntry.sequence & LFN_MASK; - if((lfnEntry.sequence & LFN_ERASED) > 0) - continue; + if((lfnEntry.sequence & LFN_ERASED) > 0) continue; if((lfnEntry.sequence & LFN_LAST) > 0) { @@ -182,15 +184,13 @@ public sealed partial class FAT lastLfnChecksum = lfnEntry.checksum; } - if(lastLfnName is null) - continue; + if(lastLfnName is null) continue; - if(lfnEntry.checksum != lastLfnChecksum) - continue; + if(lfnEntry.checksum != lastLfnChecksum) continue; lfnSequence--; - Array.Copy(lfnEntry.name1, 0, lastLfnName, lfnSequence * 26, 10); + Array.Copy(lfnEntry.name1, 0, lastLfnName, lfnSequence * 26, 10); Array.Copy(lfnEntry.name2, 0, lastLfnName, lfnSequence * 26 + 10, 12); Array.Copy(lfnEntry.name3, 0, lastLfnName, lfnSequence * 26 + 22, 4); @@ -198,34 +198,27 @@ public sealed partial class FAT } // Not a correct entry - if(dirent.filename[0] < DIRENT_MIN && - dirent.filename[0] != DIRENT_E5) - continue; + if(dirent.filename[0] < DIRENT_MIN && dirent.filename[0] != DIRENT_E5) continue; // Self - if(Encoding.GetString(dirent.filename).TrimEnd() == ".") - continue; + if(_encoding.GetString(dirent.filename).TrimEnd() == ".") continue; // Parent - if(Encoding.GetString(dirent.filename).TrimEnd() == "..") - continue; + if(_encoding.GetString(dirent.filename).TrimEnd() == "..") continue; // Deleted - if(dirent.filename[0] == DIRENT_DELETED) - continue; + if(dirent.filename[0] == DIRENT_DELETED) continue; string filename; - if(dirent.attributes.HasFlag(FatAttributes.VolumeLabel)) - continue; + if(dirent.attributes.HasFlag(FatAttributes.VolumeLabel)) continue; var completeEntry = new CompleteDirectoryEntry { Dirent = dirent }; - if(_namespace is Namespace.Lfn or Namespace.Ecs && - lastLfnName != null) + if(_namespace is Namespace.Lfn or Namespace.Ecs && lastLfnName != null) { byte calculatedLfnChecksum = LfnChecksum(dirent.filename, dirent.extension); @@ -239,20 +232,16 @@ public sealed partial class FAT } } - if(dirent.filename[0] == DIRENT_E5) - dirent.filename[0] = DIRENT_DELETED; + if(dirent.filename[0] == DIRENT_E5) dirent.filename[0] = DIRENT_DELETED; - string name = Encoding.GetString(dirent.filename).TrimEnd(); - string extension = Encoding.GetString(dirent.extension).TrimEnd(); + string name = _encoding.GetString(dirent.filename).TrimEnd(); + string extension = _encoding.GetString(dirent.extension).TrimEnd(); - if(name == "" && - extension == "") + if(name == "" && extension == "") { - AaruConsole.DebugWriteLine("FAT filesystem", "Found empty filename in {0}", path); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Found_empty_filename_in_0, path); - if(!_debug || - dirent.size > 0 && dirent.start_cluster == 0) - continue; // Skip invalid name + if(!_debug || dirent is { size: > 0, start_cluster: 0 }) continue; // Skip invalid name // If debug, add it name = ":{EMPTYNAME}:"; @@ -262,13 +251,11 @@ public sealed partial class FAT { extension = $"{uniq:D03}"; - if(!currentDirectory.ContainsKey($"{name}.{extension}")) - break; + if(!currentDirectory.ContainsKey($"{name}.{extension}")) break; } // If we couldn't find it, just skip over - if(currentDirectory.ContainsKey($"{name}.{extension}")) - continue; + if(currentDirectory.ContainsKey($"{name}.{extension}")) continue; } if(_namespace == Namespace.Nt) @@ -288,14 +275,15 @@ public sealed partial class FAT if(_namespace == Namespace.Human) { HumanDirectoryEntry humanEntry = - Marshal.ByteArrayToStructureLittleEndian(directoryBuffer, pos, + Marshal.ByteArrayToStructureLittleEndian(directoryBuffer, + pos, Marshal.SizeOf()); completeEntry.HumanDirent = humanEntry; - name = StringHandlers.CToString(humanEntry.name1, Encoding).TrimEnd(); - extension = StringHandlers.CToString(humanEntry.extension, Encoding).TrimEnd(); - string name2 = StringHandlers.CToString(humanEntry.name2, Encoding).TrimEnd(); + name = StringHandlers.CToString(humanEntry.name1, _encoding).TrimEnd(); + extension = StringHandlers.CToString(humanEntry.extension, _encoding).TrimEnd(); + string name2 = StringHandlers.CToString(humanEntry.name2, _encoding).TrimEnd(); if(extension != "") filename = name + name2 + "." + extension; @@ -316,9 +304,7 @@ public sealed partial class FAT } // Check OS/2 .LONGNAME - if(_eaCache != null && - _namespace is Namespace.Os2 or Namespace.Ecs && - !_fat32) + if(_eaCache != null && _namespace is Namespace.Os2 or Namespace.Ecs && !_fat32) { var filesWithEas = currentDirectory.Where(t => t.Value.Dirent.ea_handle != 0).ToList(); @@ -326,28 +312,23 @@ public sealed partial class FAT { Dictionary eas = GetEas(fileWithEa.Value.Dirent.ea_handle); - if(eas is null) - continue; + if(eas is null) continue; - if(!eas.TryGetValue("com.microsoft.os2.longname", out byte[] longnameEa)) - continue; + if(!eas.TryGetValue("com.microsoft.os2.longname", out byte[] longnameEa)) continue; - if(BitConverter.ToUInt16(longnameEa, 0) != EAT_ASCII) - continue; + if(BitConverter.ToUInt16(longnameEa, 0) != EAT_ASCII) continue; var longnameSize = BitConverter.ToUInt16(longnameEa, 2); - if(longnameSize + 4 > longnameEa.Length) - continue; + if(longnameSize + 4 > longnameEa.Length) continue; var longnameBytes = new byte[longnameSize]; Array.Copy(longnameEa, 4, longnameBytes, 0, longnameSize); - string longname = StringHandlers.CToString(longnameBytes, Encoding); + string longname = StringHandlers.CToString(longnameBytes, _encoding); - if(string.IsNullOrWhiteSpace(longname)) - continue; + if(string.IsNullOrWhiteSpace(longname)) continue; // Forward slash is allowed in .LONGNAME, so change it to visually similar division slash longname = longname.Replace('/', '\u2215'); @@ -361,37 +342,87 @@ public sealed partial class FAT // Check FAT32.IFS EAs if(_fat32 || _debug) { - var fat32EaSidecars = currentDirectory.Where(t => t.Key.EndsWith(FAT32_EA_TAIL, true, _cultureInfo)). - ToList(); + var fat32EaSidecars = currentDirectory.Where(t => t.Key.EndsWith(FAT32_EA_TAIL, true, _cultureInfo)) + .ToList(); foreach(KeyValuePair sidecar in fat32EaSidecars) { // No real file this sidecar accompanies - if(!currentDirectory. - TryGetValue(sidecar.Key.Substring(0, sidecar.Key.Length - FAT32_EA_TAIL.Length), - out CompleteDirectoryEntry fileWithEa)) + if(!currentDirectory.TryGetValue(sidecar.Key[..^FAT32_EA_TAIL.Length], + out CompleteDirectoryEntry fileWithEa)) continue; // If not in debug mode we will consider the lack of EA bitflags to mean the EAs are corrupted or not real if(!_debug) + { if(!fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.NormalEaOld) && !fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.CriticalEa) && !fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.NormalEa) && !fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.CriticalEa)) continue; + } fileWithEa.Fat32Ea = sidecar.Value.Dirent; - if(!_debug) - currentDirectory.Remove(sidecar.Key); + if(!_debug) currentDirectory.Remove(sidecar.Key); } } _directoryCache.Add(currentPath, currentDirectory); } - contents = currentDirectory?.Keys.ToList(); + if(currentDirectory is null) return ErrorNumber.NoSuchFile; + + node = new FatDirNode + { + Path = path, + Position = 0, + Entries = currentDirectory.Values.ToArray() + }; return ErrorNumber.NoError; } + + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) + { + filename = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not FatDirNode mynode) return ErrorNumber.InvalidArgument; + + if(mynode.Position < 0) return ErrorNumber.InvalidArgument; + + if(mynode.Position >= mynode.Entries.Length) return ErrorNumber.NoError; + + CompleteDirectoryEntry entry = mynode.Entries[mynode.Position]; + + filename = _namespace switch + { + Namespace.Ecs when entry.Longname is not null => entry.Longname, + Namespace.Ecs when entry.Longname is null && entry.Lfn is not null => entry.Lfn, + Namespace.Lfn when entry.Lfn is not null => entry.Lfn, + Namespace.Human when entry.HumanName is not null => entry.HumanName, + Namespace.Os2 when entry.Longname is not null => entry.Longname, + _ => entry.Shortname + }; + + mynode.Position++; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not FatDirNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Position = -1; + mynode.Entries = null; + + return ErrorNumber.NoError; + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/FAT/FAT.cs b/Aaru.Filesystems/FAT/FAT.cs index 29944c05b..13869088e 100644 --- a/Aaru.Filesystems/FAT/FAT.cs +++ b/Aaru.Filesystems/FAT/FAT.cs @@ -7,10 +7,6 @@ // // Component : Microsoft FAT filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Microsoft FAT filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,18 +23,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Globalization; using System.Text; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; -using Schemas; + +namespace Aaru.Filesystems; // TODO: Differentiate between Atari and X68k FAT, as this one uses a standard BPB. // X68K uses cdate/adate from direntry for extending filename @@ -46,18 +42,22 @@ using Schemas; /// Implements the File Allocation Table, aka FAT, filesystem (FAT12, FAT16 and FAT32 variants). public sealed partial class FAT : IReadOnlyFilesystem { + const string MODULE_NAME = "FAT plugin"; uint _bytesPerCluster; byte[] _cachedEaData; CultureInfo _cultureInfo; bool _debug; Dictionary> _directoryCache; DirectoryEntry _eaDirEntry; + Encoding _encoding; bool _fat12; bool _fat16; bool _fat32; ushort[] _fatEntries; + uint _fatEntriesPerSector; ulong _fatFirstSector; ulong _firstClusterSector; + IMediaImage _image; bool _mounted; Namespace _namespace; uint _reservedSectors; @@ -67,16 +67,19 @@ public sealed partial class FAT : IReadOnlyFilesystem FileSystemInfo _statfs; bool _useFirstFat; +#region IReadOnlyFilesystem Members + /// - public FileSystemType XmlFsType { get; private set; } + public FileSystem Metadata { get; private set; } + /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Microsoft File Allocation Table"; + public string Name => Localization.FAT_Name; + /// public Guid Id => new("33513B2C-0D26-0D2D-32C3-79D8611158E0"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public IEnumerable<(string name, Type type, string description)> SupportedOptions => @@ -86,22 +89,24 @@ public sealed partial class FAT : IReadOnlyFilesystem public Dictionary Namespaces => new() { { - "dos", "DOS (8.3 all uppercase)" + "dos", Localization.DOS_8_3_all_uppercase }, { - "nt", "Windows NT (8.3 mixed case)" + "nt", Localization.Windows_NT_8_3_mixed_case }, { - "os2", "OS/2 .LONGNAME extended attribute" + "os2", Localization.OS2_LONGNAME_extended_attribute }, { - "ecs", "Use LFN when available with fallback to .LONGNAME (default)" + "ecs", Localization.Use_LFN_when_available_with_fallback_to_LONGNAME_default }, { - "lfn", "Long file names" + "lfn", Localization.Long_file_names } }; +#endregion + static Dictionary GetDefaultOptions() => new() { { diff --git a/Aaru.Filesystems/FAT/File.cs b/Aaru.Filesystems/FAT/File.cs index 2ffa8acbf..b5a1ccf2b 100644 --- a/Aaru.Filesystems/FAT/File.cs +++ b/Aaru.Filesystems/FAT/File.cs @@ -7,10 +7,6 @@ // // Component : Microsoft FAT filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle files. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,61 +23,35 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.IO; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Helpers; using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes; +namespace Aaru.Filesystems; + public sealed partial class FAT { - /// - public ErrorNumber MapBlock(string path, long fileBlock, out long deviceBlock) - { - deviceBlock = 0; - - if(!_mounted) - return ErrorNumber.AccessDenied; - - ErrorNumber err = Stat(path, out FileEntryInfo stat); - - if(err != ErrorNumber.NoError) - return err; - - if(stat.Attributes.HasFlag(FileAttributes.Directory) && - !_debug) - return ErrorNumber.IsDirectory; - - uint[] clusters = GetClusters((uint)stat.Inode); - - if(fileBlock >= clusters.Length) - return ErrorNumber.InvalidArgument; - - deviceBlock = (long)(_firstClusterSector + clusters[fileBlock] * _sectorsPerCluster); - - return ErrorNumber.NoError; - } +#region IReadOnlyFilesystem Members /// public ErrorNumber GetAttributes(string path, out FileAttributes attributes) { attributes = new FileAttributes(); - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = Stat(path, out FileEntryInfo stat); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; attributes = stat.Attributes; @@ -89,66 +59,85 @@ public sealed partial class FAT } /// - public ErrorNumber Read(string path, long offset, long size, ref byte[] buf) + public ErrorNumber OpenFile(string path, out IFileNode node) { - ErrorNumber errno; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = Stat(path, out FileEntryInfo stat); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; - if(stat.Attributes.HasFlag(FileAttributes.Directory) && - !_debug) - return ErrorNumber.IsDirectory; - - if(size == 0) - { - buf = Array.Empty(); - - return ErrorNumber.NoError; - } - - if(offset >= stat.Length) - return ErrorNumber.InvalidArgument; - - if(size + offset >= stat.Length) - size = stat.Length - offset; + if(stat.Attributes.HasFlag(FileAttributes.Directory) && !_debug) return ErrorNumber.IsDirectory; uint[] clusters = GetClusters((uint)stat.Inode); - if(clusters is null) - return ErrorNumber.InvalidArgument; + if(clusters is null) return ErrorNumber.InvalidArgument; - long firstCluster = offset / _bytesPerCluster; - long offsetInCluster = offset % _bytesPerCluster; - long sizeInClusters = (size + offsetInCluster) / _bytesPerCluster; + node = new FatFileNode + { + Path = path, + Length = stat.Length, + Offset = 0, + Clusters = clusters + }; - if((size + offsetInCluster) % _bytesPerCluster > 0) - sizeInClusters++; + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseFile(IFileNode node) + { + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not FatFileNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Clusters = null; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(buffer is null || buffer.Length < length) return ErrorNumber.InvalidArgument; + + if(node is not FatFileNode mynode) return ErrorNumber.InvalidArgument; + + read = length; + + if(length + mynode.Offset >= mynode.Length) read = mynode.Length - mynode.Offset; + + long firstCluster = mynode.Offset / _bytesPerCluster; + long offsetInCluster = mynode.Offset % _bytesPerCluster; + long sizeInClusters = (read + offsetInCluster) / _bytesPerCluster; + + if((read + offsetInCluster) % _bytesPerCluster > 0) sizeInClusters++; var ms = new MemoryStream(); for(var i = 0; i < sizeInClusters; i++) { - if(i + firstCluster >= clusters.Length) - return ErrorNumber.InvalidArgument; + if(i + firstCluster >= mynode.Clusters.Length) return ErrorNumber.InvalidArgument; - errno = _image.ReadSectors(_firstClusterSector + clusters[i + firstCluster] * _sectorsPerCluster, - _sectorsPerCluster, out byte[] buffer); + ErrorNumber errno = + _image.ReadSectors(_firstClusterSector + mynode.Clusters[i + firstCluster] * _sectorsPerCluster, + _sectorsPerCluster, + out byte[] buf); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - ms.Write(buffer, 0, buffer.Length); + ms.Write(buf, 0, buf.Length); } ms.Position = offsetInCluster; - buf = new byte[size]; - ms.Read(buf, 0, (int)size); + ms.EnsureRead(buffer, 0, (int)read); + mynode.Offset += read; return ErrorNumber.NoError; } @@ -158,13 +147,11 @@ public sealed partial class FAT { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = GetFileEntry(path, out CompleteDirectoryEntry completeEntry); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; DirectoryEntry entry = completeEntry.Dirent; @@ -178,62 +165,54 @@ public sealed partial class FAT Links = 1 }; - if(entry.cdate > 0 || - entry.ctime > 0) - stat.CreationTime = DateHandlers.DosToDateTime(entry.cdate, entry.ctime); + if(entry.cdate > 0 || entry.ctime > 0) stat.CreationTime = DateHandlers.DosToDateTime(entry.cdate, entry.ctime); if(_namespace != Namespace.Human) { - if(entry.mdate > 0 || - entry.mtime > 0) + if(entry.mdate > 0 || entry.mtime > 0) stat.LastWriteTime = DateHandlers.DosToDateTime(entry.mdate, entry.mtime); - if(entry.ctime_ms > 0) - stat.CreationTime = stat.CreationTime?.AddMilliseconds(entry.ctime_ms * 10); + if(entry.ctime_ms > 0) stat.CreationTime = stat.CreationTime?.AddMilliseconds(entry.ctime_ms * 10); } - if(entry.size % _bytesPerCluster > 0) - stat.Blocks++; + if(entry.size % _bytesPerCluster > 0) stat.Blocks++; if(entry.attributes.HasFlag(FatAttributes.Subdirectory)) { stat.Attributes |= FileAttributes.Directory; - if(_fat32 && entry.ea_handle << 16 > 0 || - entry.start_cluster > 0) - stat.Blocks = _fat32 ? GetClusters((uint)((entry.ea_handle << 16) + entry.start_cluster))?.Length ?? 0 - : GetClusters(entry.start_cluster)?.Length ?? 0; + if(_fat32 && entry.ea_handle << 16 > 0 || entry.start_cluster > 0) + { + stat.Blocks = _fat32 + ? GetClusters((uint)((entry.ea_handle << 16) + entry.start_cluster))?.Length ?? 0 + : GetClusters(entry.start_cluster)?.Length ?? 0; + } stat.Length = stat.Blocks * stat.BlockSize; } - if(entry.attributes.HasFlag(FatAttributes.ReadOnly)) - stat.Attributes |= FileAttributes.ReadOnly; + if(entry.attributes.HasFlag(FatAttributes.ReadOnly)) stat.Attributes |= FileAttributes.ReadOnly; - if(entry.attributes.HasFlag(FatAttributes.Hidden)) - stat.Attributes |= FileAttributes.Hidden; + if(entry.attributes.HasFlag(FatAttributes.Hidden)) stat.Attributes |= FileAttributes.Hidden; - if(entry.attributes.HasFlag(FatAttributes.System)) - stat.Attributes |= FileAttributes.System; + if(entry.attributes.HasFlag(FatAttributes.System)) stat.Attributes |= FileAttributes.System; - if(entry.attributes.HasFlag(FatAttributes.Archive)) - stat.Attributes |= FileAttributes.Archive; + if(entry.attributes.HasFlag(FatAttributes.Archive)) stat.Attributes |= FileAttributes.Archive; - if(entry.attributes.HasFlag(FatAttributes.Device)) - stat.Attributes |= FileAttributes.Device; + if(entry.attributes.HasFlag(FatAttributes.Device)) stat.Attributes |= FileAttributes.Device; return ErrorNumber.NoError; } +#endregion + uint[] GetClusters(uint startCluster) { - if(startCluster == 0) - return Array.Empty(); + if(startCluster == 0) return []; - if(startCluster >= XmlFsType.Clusters) - return null; + if(startCluster >= Metadata.Clusters) return null; - List clusters = new(); + List clusters = []; uint nextCluster = startCluster; @@ -244,12 +223,11 @@ public sealed partial class FAT ulong currentSector = nextSector; ErrorNumber errno = _image.ReadSector(currentSector, out byte[] fatData); - if(errno != ErrorNumber.NoError) - return null; + if(errno != ErrorNumber.NoError) return null; if(_fat32) - while((nextCluster & FAT32_MASK) > 0 && - (nextCluster & FAT32_MASK) <= FAT32_RESERVED) + { + while((nextCluster & FAT32_MASK) > 0 && (nextCluster & FAT32_MASK) <= FAT32_RESERVED) { clusters.Add(nextCluster); @@ -257,8 +235,7 @@ public sealed partial class FAT { errno = _image.ReadSector(nextSector, out fatData); - if(errno != ErrorNumber.NoError) - return null; + if(errno != ErrorNumber.NoError) return null; currentSector = nextSector; } @@ -269,26 +246,27 @@ public sealed partial class FAT nextEntry = (int)(nextCluster % _fatEntriesPerSector); } + } else if(_fat16) - while(nextCluster > 0 && - nextCluster <= FAT16_RESERVED) + { + while(nextCluster is > 0 and <= FAT16_RESERVED) { - if(nextCluster > _fatEntries.Length) - return null; + if(nextCluster >= _fatEntries.Length) break; clusters.Add(nextCluster); nextCluster = _fatEntries[nextCluster]; } + } else - while(nextCluster > 0 && - nextCluster <= FAT12_RESERVED) + { + while(nextCluster is > 0 and <= FAT12_RESERVED) { - if(nextCluster > _fatEntries.Length) - return null; + if(nextCluster >= _fatEntries.Length) break; clusters.Add(nextCluster); nextCluster = _fatEntries[nextCluster]; } + } return clusters.ToArray(); } @@ -297,53 +275,50 @@ public sealed partial class FAT { entry = null; - string cutPath = path.StartsWith('/') ? path.Substring(1).ToLower(_cultureInfo) : path.ToLower(_cultureInfo); + string cutPath = path.StartsWith('/') ? path[1..].ToLower(_cultureInfo) : path.ToLower(_cultureInfo); string[] pieces = cutPath.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pieces.Length == 0) - return ErrorNumber.InvalidArgument; + if(pieces.Length == 0) return ErrorNumber.InvalidArgument; var parentPath = string.Join("/", pieces, 0, pieces.Length - 1); if(!_directoryCache.TryGetValue(parentPath, out _)) { - ErrorNumber err = ReadDir(parentPath, out _); + ErrorNumber err = OpenDir(parentPath, out IDirNode node); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; + + CloseDir(node); } Dictionary parent; if(pieces.Length == 1) parent = _rootDirectoryCache; - else if(!_directoryCache.TryGetValue(parentPath, out parent)) - return ErrorNumber.InvalidArgument; + else if(!_directoryCache.TryGetValue(parentPath, out parent)) return ErrorNumber.InvalidArgument; KeyValuePair dirent = parent.FirstOrDefault(t => t.Key.ToLower(_cultureInfo) == pieces[^1]); - if(string.IsNullOrEmpty(dirent.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(dirent.Key)) return ErrorNumber.NoSuchFile; entry = dirent.Value; return ErrorNumber.NoError; } - byte LfnChecksum(byte[] name, byte[] extension) + static byte LfnChecksum(byte[] name, byte[] extension) { byte sum = 0; - for(var i = 0; i < 8; i++) - sum = (byte)(((sum & 1) << 7) + (sum >> 1) + name[i]); + for(var i = 0; i < 8; i++) sum = (byte)(((sum & 1) << 7) + (sum >> 1) + name[i]); - for(var i = 0; i < 3; i++) - sum = (byte)(((sum & 1) << 7) + (sum >> 1) + extension[i]); + for(var i = 0; i < 3; i++) sum = (byte)(((sum & 1) << 7) + (sum >> 1) + extension[i]); return sum; } diff --git a/Aaru.Filesystems/FAT/Info.cs b/Aaru.Filesystems/FAT/Info.cs index ed37466e4..9e4744f78 100644 --- a/Aaru.Filesystems/FAT/Info.cs +++ b/Aaru.Filesystems/FAT/Info.cs @@ -7,10 +7,6 @@ // // Component : Microsoft FAT filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Microsoft FAT filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,11 +23,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Diagnostics.CodeAnalysis; using System.IO; @@ -39,22 +33,25 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; using Aaru.Checksums; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Helpers; -using Schemas; using Marshal = Aaru.Helpers.Marshal; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class FAT { +#region IReadOnlyFilesystem Members + /// [SuppressMessage("ReSharper", "JoinDeclarationAndInitializer")] public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(2 + partition.Start >= partition.End) - return false; + if(2 + partition.Start >= partition.End) return false; ushort bps; byte spc; @@ -79,51 +76,56 @@ public sealed partial class FAT ErrorNumber errno = imagePlugin.ReadSectors(0 + partition.Start, sectorsPerBpb, out byte[] bpbSector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; errno = imagePlugin.ReadSector(sectorsPerBpb + partition.Start, out byte[] fatSector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; HumanParameterBlock humanBpb = Marshal.ByteArrayToStructureBigEndian(bpbSector); ulong expectedClusters = humanBpb.bpc > 0 ? partition.Size / humanBpb.bpc : 0; - AaruConsole.DebugWriteLine("FAT plugin", "Human bpc = {0}", humanBpb.bpc); - AaruConsole.DebugWriteLine("FAT plugin", "Human clusters = {0}", humanBpb.clusters); - AaruConsole.DebugWriteLine("FAT plugin", "Human big_clusters = {0}", humanBpb.big_clusters); - AaruConsole.DebugWriteLine("FAT plugin", "Human expected clusters = {0}", expectedClusters); + AaruConsole.DebugWriteLine(MODULE_NAME, "Human bpc = {0}", humanBpb.bpc); + AaruConsole.DebugWriteLine(MODULE_NAME, "Human clusters = {0}", humanBpb.clusters); + AaruConsole.DebugWriteLine(MODULE_NAME, "Human big_clusters = {0}", humanBpb.big_clusters); + AaruConsole.DebugWriteLine(MODULE_NAME, "Human expected clusters = {0}", expectedClusters); // Check clusters for Human68k are correct - bool humanClustersCorrect = humanBpb.clusters == 0 ? humanBpb.big_clusters == expectedClusters - : humanBpb.clusters == expectedClusters; + bool humanClustersCorrect = humanBpb.clusters == 0 + ? humanBpb.big_clusters == expectedClusters + : humanBpb.clusters == expectedClusters; // Check OEM for Human68k is correct - bool humanOemCorrect = bpbSector[2] >= 0x20 && bpbSector[3] >= 0x20 && bpbSector[4] >= 0x20 && - bpbSector[5] >= 0x20 && bpbSector[6] >= 0x20 && bpbSector[7] >= 0x20 && - bpbSector[8] >= 0x20 && bpbSector[9] >= 0x20 && bpbSector[10] >= 0x20 && - bpbSector[11] >= 0x20 && bpbSector[12] >= 0x20 && bpbSector[13] >= 0x20 && - bpbSector[14] >= 0x20 && bpbSector[15] >= 0x20 && bpbSector[16] >= 0x20 && + bool humanOemCorrect = bpbSector[2] >= 0x20 && + bpbSector[3] >= 0x20 && + bpbSector[4] >= 0x20 && + bpbSector[5] >= 0x20 && + bpbSector[6] >= 0x20 && + bpbSector[7] >= 0x20 && + bpbSector[8] >= 0x20 && + bpbSector[9] >= 0x20 && + bpbSector[10] >= 0x20 && + bpbSector[11] >= 0x20 && + bpbSector[12] >= 0x20 && + bpbSector[13] >= 0x20 && + bpbSector[14] >= 0x20 && + bpbSector[15] >= 0x20 && + bpbSector[16] >= 0x20 && bpbSector[17] >= 0x20; // Check correct branch for Human68k bool humanBranchCorrect = bpbSector[0] == 0x60 && bpbSector[1] >= 0x20 && bpbSector[1] < 0xFE; - AaruConsole.DebugWriteLine("FAT plugin", "humanClustersCorrect = {0}", humanClustersCorrect); - AaruConsole.DebugWriteLine("FAT plugin", "humanOemCorrect = {0}", humanOemCorrect); - AaruConsole.DebugWriteLine("FAT plugin", "humanBranchCorrect = {0}", humanBranchCorrect); + AaruConsole.DebugWriteLine(MODULE_NAME, "humanClustersCorrect = {0}", humanClustersCorrect); + AaruConsole.DebugWriteLine(MODULE_NAME, "humanOemCorrect = {0}", humanOemCorrect); + AaruConsole.DebugWriteLine(MODULE_NAME, "humanBranchCorrect = {0}", humanBranchCorrect); // If all Human68k checks are correct, it is a Human68k FAT16 - if(humanClustersCorrect && - humanOemCorrect && - humanBranchCorrect && - expectedClusters > 0) - return true; + if(humanClustersCorrect && humanOemCorrect && humanBranchCorrect && expectedClusters > 0) return true; Array.Copy(bpbSector, 0x02, atariOem, 0, 6); - Array.Copy(bpbSector, 0x03, dosOem, 0, 8); + Array.Copy(bpbSector, 0x03, dosOem, 0, 8); bps = BitConverter.ToUInt16(bpbSector, 0x00B); spc = bpbSector[0x00D]; reservedSecs = BitConverter.ToUInt16(bpbSector, 0x00E); @@ -141,40 +143,49 @@ public sealed partial class FAT fatId = fatSector[0]; int bitsInBps = CountBits.Count(bps); - if(imagePlugin.Info.SectorSize >= 512) - bootable = BitConverter.ToUInt16(bpbSector, 0x1FE); + if(imagePlugin.Info.SectorSize >= 512) bootable = BitConverter.ToUInt16(bpbSector, 0x1FE); bool correctSpc = spc is 1 or 2 or 4 or 8 or 16 or 32 or 64; string msxString = Encoding.ASCII.GetString(msxId); string fat32String = Encoding.ASCII.GetString(fat32Id); - bool atariOemCorrect = atariOem[0] >= 0x20 && atariOem[1] >= 0x20 && atariOem[2] >= 0x20 && - atariOem[3] >= 0x20 && atariOem[4] >= 0x20 && atariOem[5] >= 0x20; + bool atariOemCorrect = atariOem[0] >= 0x20 && + atariOem[1] >= 0x20 && + atariOem[2] >= 0x20 && + atariOem[3] >= 0x20 && + atariOem[4] >= 0x20 && + atariOem[5] >= 0x20; - bool dosOemCorrect = dosOem[0] >= 0x20 && dosOem[1] >= 0x20 && dosOem[2] >= 0x20 && dosOem[3] >= 0x20 && - dosOem[4] >= 0x20 && dosOem[5] >= 0x20 && dosOem[6] >= 0x20 && dosOem[7] >= 0x20; + bool dosOemCorrect = dosOem[0] >= 0x20 && + dosOem[1] >= 0x20 && + dosOem[2] >= 0x20 && + dosOem[3] >= 0x20 && + dosOem[4] >= 0x20 && + dosOem[5] >= 0x20 && + dosOem[6] >= 0x20 && + dosOem[7] >= 0x20; string oemString = Encoding.ASCII.GetString(dosOem); - AaruConsole.DebugWriteLine("FAT plugin", "atari_oem_correct = {0}", atariOemCorrect); - AaruConsole.DebugWriteLine("FAT plugin", "dos_oem_correct = {0}", dosOemCorrect); - AaruConsole.DebugWriteLine("FAT plugin", "bps = {0}", bps); - AaruConsole.DebugWriteLine("FAT plugin", "bits in bps = {0}", bitsInBps); - AaruConsole.DebugWriteLine("FAT plugin", "spc = {0}", spc); - AaruConsole.DebugWriteLine("FAT plugin", "correct_spc = {0}", correctSpc); - AaruConsole.DebugWriteLine("FAT plugin", "reserved_secs = {0}", reservedSecs); - AaruConsole.DebugWriteLine("FAT plugin", "fats_no = {0}", numberOfFats); - AaruConsole.DebugWriteLine("FAT plugin", "root_entries = {0}", rootEntries); - AaruConsole.DebugWriteLine("FAT plugin", "sectors = {0}", sectors); - AaruConsole.DebugWriteLine("FAT plugin", "media_descriptor = 0x{0:X2}", mediaDescriptor); - AaruConsole.DebugWriteLine("FAT plugin", "fat_sectors = {0}", fatSectors); - AaruConsole.DebugWriteLine("FAT plugin", "msx_id = \"{0}\"", msxString); - AaruConsole.DebugWriteLine("FAT plugin", "big_sectors = {0}", bigSectors); - AaruConsole.DebugWriteLine("FAT plugin", "bpb_signature = 0x{0:X2}", bpbSignature); - AaruConsole.DebugWriteLine("FAT plugin", "fat32_signature = 0x{0:X2}", fat32Signature); - AaruConsole.DebugWriteLine("FAT plugin", "fat32_id = \"{0}\"", fat32String); - AaruConsole.DebugWriteLine("FAT plugin", "huge_sectors = {0}", hugeSectors); - AaruConsole.DebugWriteLine("FAT plugin", "fat_id = 0x{0:X2}", fatId); + AaruConsole.DebugWriteLine(MODULE_NAME, "atari_oem_correct = {0}", atariOemCorrect); + AaruConsole.DebugWriteLine(MODULE_NAME, "dos_oem_correct = {0}", dosOemCorrect); + AaruConsole.DebugWriteLine(MODULE_NAME, "bps = {0}", bps); + AaruConsole.DebugWriteLine(MODULE_NAME, "bits in bps = {0}", bitsInBps); + AaruConsole.DebugWriteLine(MODULE_NAME, "spc = {0}", spc); + AaruConsole.DebugWriteLine(MODULE_NAME, "correct_spc = {0}", correctSpc); + AaruConsole.DebugWriteLine(MODULE_NAME, "reserved_secs = {0}", reservedSecs); + AaruConsole.DebugWriteLine(MODULE_NAME, "fats_no = {0}", numberOfFats); + AaruConsole.DebugWriteLine(MODULE_NAME, "root_entries = {0}", rootEntries); + AaruConsole.DebugWriteLine(MODULE_NAME, "sectors = {0}", sectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "media_descriptor = 0x{0:X2}", mediaDescriptor); + AaruConsole.DebugWriteLine(MODULE_NAME, "fat_sectors = {0}", fatSectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "msx_id = \"{0}\"", msxString); + AaruConsole.DebugWriteLine(MODULE_NAME, "big_sectors = {0}", bigSectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb_signature = 0x{0:X2}", bpbSignature); + AaruConsole.DebugWriteLine(MODULE_NAME, "fat32_signature = 0x{0:X2}", fat32Signature); + AaruConsole.DebugWriteLine(MODULE_NAME, "fat32_id = \"{0}\"", fat32String); + AaruConsole.DebugWriteLine(MODULE_NAME, "huge_sectors = {0}", hugeSectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "fat_id = 0x{0:X2}", fatId); var apricotBps = BitConverter.ToUInt16(bpbSector, 0x50); byte apricotSpc = bpbSector[0x52]; @@ -190,18 +201,18 @@ public sealed partial class FAT int bitsInApricotBps = CountBits.Count(apricotBps); byte apricotPartitions = bpbSector[0x0C]; - AaruConsole.DebugWriteLine("FAT plugin", "apricot_bps = {0}", apricotBps); - AaruConsole.DebugWriteLine("FAT plugin", "apricot_spc = {0}", apricotSpc); - AaruConsole.DebugWriteLine("FAT plugin", "apricot_correct_spc = {0}", apricotCorrectSpc); - AaruConsole.DebugWriteLine("FAT plugin", "apricot_reserved_secs = {0}", apricotReservedSecs); - AaruConsole.DebugWriteLine("FAT plugin", "apricot_fats_no = {0}", apricotFatsNo); - AaruConsole.DebugWriteLine("FAT plugin", "apricot_root_entries = {0}", apricotRootEntries); - AaruConsole.DebugWriteLine("FAT plugin", "apricot_sectors = {0}", apricotSectors); - AaruConsole.DebugWriteLine("FAT plugin", "apricot_media_descriptor = 0x{0:X2}", apricotMediaDescriptor); - AaruConsole.DebugWriteLine("FAT plugin", "apricot_fat_sectors = {0}", apricotFatSectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_bps = {0}", apricotBps); + AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_spc = {0}", apricotSpc); + AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_correct_spc = {0}", apricotCorrectSpc); + AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_reserved_secs = {0}", apricotReservedSecs); + AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_fats_no = {0}", apricotFatsNo); + AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_root_entries = {0}", apricotRootEntries); + AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_sectors = {0}", apricotSectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_media_descriptor = 0x{0:X2}", apricotMediaDescriptor); + AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_fat_sectors = {0}", apricotFatSectors); // This is to support FAT partitions on hybrid ISO/USB images - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) { sectors /= 4; bigSectors /= 4; @@ -211,13 +222,16 @@ public sealed partial class FAT switch(oemString) { // exFAT - case "EXFAT ": return false; + case "EXFAT ": + return false; // NTFS - case "NTFS " when bootable == 0xAA55 && numberOfFats == 0 && fatSectors == 0: return false; + case "NTFS " when bootable == 0xAA55 && numberOfFats == 0 && fatSectors == 0: + return false; // QNX4 - case "FQNX4FS ": return false; + case "FQNX4FS ": + return false; } // HPFS @@ -226,46 +240,60 @@ public sealed partial class FAT errno = imagePlugin.ReadSector(16 + partition.Start, out byte[] hpfsSbSector); // Seek to superblock, on logical sector 16 - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; var hpfsMagic1 = BitConverter.ToUInt32(hpfsSbSector, 0x000); var hpfsMagic2 = BitConverter.ToUInt32(hpfsSbSector, 0x004); - if(hpfsMagic1 == 0xF995E849 && - hpfsMagic2 == 0xFA53E9C5) - return false; + if(hpfsMagic1 == 0xF995E849 && hpfsMagic2 == 0xFA53E9C5) return false; } switch(bitsInBps) { // FAT32 for sure - case 1 when correctSpc && numberOfFats <= 2 && fatSectors == 0 && fat32Signature == 0x29 && - fat32String == "FAT32 ": return true; + case 1 when correctSpc && + numberOfFats <= 2 && + fatSectors == 0 && + fat32Signature == 0x29 && + fat32String == "FAT32 ": + return true; // short FAT32 case 1 when correctSpc && numberOfFats <= 2 && fatSectors == 0 && fat32Signature == 0x28: - return sectors == 0 ? bigSectors == 0 - ? hugeSectors <= partition.End - partition.Start + 1 - : bigSectors <= partition.End - partition.Start + 1 + return sectors == 0 + ? bigSectors == 0 + ? hugeSectors <= partition.End - partition.Start + 1 + : bigSectors <= partition.End - partition.Start + 1 : sectors <= partition.End - partition.Start + 1; // MSX-DOS FAT12 - case 1 when correctSpc && numberOfFats <= 2 && rootEntries > 0 && - sectors <= partition.End - partition.Start + 1 && fatSectors > 0 && - msxString == "VOL_ID": return true; + case 1 when correctSpc && + numberOfFats <= 2 && + rootEntries > 0 && + sectors <= partition.End - partition.Start + 1 && + fatSectors > 0 && + msxString == "VOL_ID": + return true; // EBPB - case 1 when correctSpc && numberOfFats <= 2 && rootEntries > 0 && fatSectors > 0 && + case 1 when correctSpc && + numberOfFats <= 2 && + rootEntries > 0 && + fatSectors > 0 && bpbSignature is 0x28 or 0x29: - return sectors == 0 ? bigSectors <= partition.End - partition.Start + 1 - : sectors <= partition.End - partition.Start + 1; + return sectors == 0 + ? bigSectors <= partition.End - partition.Start + 1 + : sectors <= partition.End - partition.Start + 1; // BPB - case 1 when correctSpc && reservedSecs < partition.End - partition.Start && numberOfFats <= 2 && - rootEntries > 0 && fatSectors > 0: - return sectors == 0 ? bigSectors <= partition.End - partition.Start + 1 - : sectors <= partition.End - partition.Start + 1; + case 1 when correctSpc && + reservedSecs < partition.End - partition.Start && + numberOfFats <= 2 && + rootEntries > 0 && + fatSectors > 0: + return sectors == 0 + ? bigSectors <= partition.End - partition.Start + 1 + : sectors <= partition.End - partition.Start + 1; } // Apricot BPB @@ -280,12 +308,10 @@ public sealed partial class FAT return true; // All FAT12 without BPB can only be used on floppies, without partitions. - if(partition.Start != 0) - return false; + if(partition.Start != 0) return false; // DEC Rainbow, lacks a BPB but has a very concrete structure... - if(imagePlugin.Info.Sectors == 800 && - imagePlugin.Info.SectorSize == 512) + if(imagePlugin.Info is { Sectors: 800, SectorSize: 512 }) { // DEC Rainbow boots up with a Z80, first byte should be DI (disable interrupts) byte z80Di = bpbSector[0]; @@ -293,14 +319,12 @@ public sealed partial class FAT // First FAT1 sector resides at LBA 0x14 errno = imagePlugin.ReadSector(0x14, out byte[] fat1Sector0); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; // First FAT2 sector resides at LBA 0x1A errno = imagePlugin.ReadSector(0x1A, out byte[] fat2Sector0); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; bool equalFatIds = fat1Sector0[0] == fat2Sector0[0] && fat1Sector0[1] == fat2Sector0[1]; @@ -314,8 +338,7 @@ public sealed partial class FAT { errno = imagePlugin.ReadSector(rootSector, out byte[] tmp); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; rootMs.Write(tmp, 0, tmp.Length); } @@ -327,17 +350,18 @@ public sealed partial class FAT for(var e = 0; e < 96 * 32; e += 32) { for(var c = 0; c < 11; c++) - if(rootDir[c + e] < 0x20 && rootDir[c + e] != 0x00 && rootDir[c + e] != 0x05 || - rootDir[c + e] == 0xFF || - rootDir[c + e] == 0x2E) - { - validRootDir = false; + { + if((rootDir[c + e] >= 0x20 || rootDir[c + e] == 0x00 || rootDir[c + e] == 0x05) && + rootDir[c + e] != 0xFF && + rootDir[c + e] != 0x2E) + continue; - break; - } + validRootDir = false; - if(!validRootDir) break; + } + + if(!validRootDir) break; } if(z80Di == 0xF3 && @@ -350,109 +374,98 @@ public sealed partial class FAT byte fat2 = fatSector[1]; byte fat3 = fatSector[2]; - var fatCluster2 = (ushort)(((fat2 << 8) + fat3) & 0xFFF); + var fatCluster2 = (ushort)((fat2 << 8) + fat3 & 0xFFF); - AaruConsole.DebugWriteLine("FAT plugin", "1st fat cluster 1 = {0:X3}", fatCluster2); + AaruConsole.DebugWriteLine(MODULE_NAME, "1st fat cluster 1 = {0:X3}", fatCluster2); - if(fatCluster2 < 0xFF0) - return false; + if(fatCluster2 < 0xFF0) return false; ulong fat2SectorNo = 0; switch(fatId) { case 0xE5: - if(imagePlugin.Info.Sectors == 2002 && - imagePlugin.Info.SectorSize == 128) - fat2SectorNo = 2; + if(imagePlugin.Info is { Sectors: 2002, SectorSize: 128 }) fat2SectorNo = 2; break; case 0xFD: - if(imagePlugin.Info.Sectors == 4004 && - imagePlugin.Info.SectorSize == 128) - fat2SectorNo = 7; - else if(imagePlugin.Info.Sectors == 2002 && - imagePlugin.Info.SectorSize == 128) - fat2SectorNo = 7; + switch(imagePlugin.Info.Sectors) + { + case 4004 when imagePlugin.Info.SectorSize == 128: + case 2002 when imagePlugin.Info.SectorSize == 128: + fat2SectorNo = 7; + + break; + } break; case 0xFE: - if(imagePlugin.Info.Sectors == 320 && - imagePlugin.Info.SectorSize == 512) - fat2SectorNo = 2; - else if(imagePlugin.Info.Sectors == 2002 && - imagePlugin.Info.SectorSize == 128) - fat2SectorNo = 7; - else if(imagePlugin.Info.Sectors == 1232 && - imagePlugin.Info.SectorSize == 1024) - fat2SectorNo = 3; - else if(imagePlugin.Info.Sectors == 616 && - imagePlugin.Info.SectorSize == 1024) - fat2SectorNo = 2; - else if(imagePlugin.Info.Sectors == 720 && - imagePlugin.Info.SectorSize == 128) - fat2SectorNo = 5; - else if(imagePlugin.Info.Sectors == 640 && - imagePlugin.Info.SectorSize == 512) - fat2SectorNo = 2; + fat2SectorNo = imagePlugin.Info.Sectors switch + { + 320 when imagePlugin.Info.SectorSize == 512 => 2, + 2002 when imagePlugin.Info.SectorSize == 128 => 7, + 1232 when imagePlugin.Info.SectorSize == 1024 => 3, + 616 when imagePlugin.Info.SectorSize == 1024 => 2, + 720 when imagePlugin.Info.SectorSize == 128 => 5, + 640 when imagePlugin.Info.SectorSize == 512 => 2, + _ => fat2SectorNo + }; break; case 0xFF: - if(imagePlugin.Info.Sectors == 640 && - imagePlugin.Info.SectorSize == 512) - fat2SectorNo = 2; + if(imagePlugin.Info is { Sectors: 640, SectorSize: 512 }) fat2SectorNo = 2; break; default: - if(fatId < 0xE8) - return false; + if(fatId < 0xE8) return false; fat2SectorNo = 2; break; } - if(fat2SectorNo > partition.End || - fat2SectorNo == 0) - return false; + if(fat2SectorNo > partition.End || fat2SectorNo == 0) return false; - AaruConsole.DebugWriteLine("FAT plugin", "2nd fat starts at = {0}", fat2SectorNo); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Second_fat_starts_at_0, fat2SectorNo); errno = imagePlugin.ReadSector(fat2SectorNo, out byte[] fat2Sector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; fat2 = fat2Sector[1]; fat3 = fat2Sector[2]; - fatCluster2 = (ushort)(((fat2 << 8) + fat3) & 0xFFF); + fatCluster2 = (ushort)((fat2 << 8) + fat3 & 0xFFF); - if(fatCluster2 < 0xFF0) - return false; + if(fatCluster2 < 0xFF0) return false; return fatId == fat2Sector[0]; } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = encoding ?? Encoding.GetEncoding("IBM437"); - information = ""; - ErrorNumber errno; + encoding ??= Encoding.GetEncoding("IBM437"); + information = ""; var sb = new StringBuilder(); - XmlFsType = new FileSystemType(); + metadata = new FileSystem(); uint sectorsPerBpb = imagePlugin.Info.SectorSize < 512 ? 512 / imagePlugin.Info.SectorSize : 1; - errno = imagePlugin.ReadSectors(0 + partition.Start, sectorsPerBpb, out byte[] bpbSector); + ErrorNumber errno = imagePlugin.ReadSectors(0 + partition.Start, sectorsPerBpb, out byte[] bpbSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; - BpbKind bpbKind = DetectBpbKind(bpbSector, imagePlugin, partition, out BiosParameterBlockEbpb fakeBpb, - out HumanParameterBlock humanBpb, out AtariParameterBlock atariBpb, - out byte minBootNearJump, out bool andosOemCorrect, out bool bootable); + BpbKind bpbKind = DetectBpbKind(bpbSector, + imagePlugin, + partition, + out BiosParameterBlockEbpb fakeBpb, + out HumanParameterBlock humanBpb, + out AtariParameterBlock atariBpb, + out byte minBootNearJump, + out bool andosOemCorrect, + out bool bootable); var isFat12 = false; var isFat16 = false; @@ -460,7 +473,7 @@ public sealed partial class FAT ulong rootDirectorySector = 0; string extraInfo = null; string bootChk = null; - XmlFsType.Bootable = bootable; + metadata.Bootable = bootable; // This is needed because for FAT16, GEMDOS increases bytes per sector count instead of using big_sectors field. uint sectorsPerRealSector; @@ -488,7 +501,7 @@ public sealed partial class FAT Marshal.ByteArrayToStructureLittleEndian(bpbSector); // This is to support FAT partitions on hybrid ISO/USB images - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) { fat32Bpb.bps *= 4; fat32Bpb.spc /= 4; @@ -499,96 +512,107 @@ public sealed partial class FAT if(fat32Bpb.version != 0) { - sb.AppendLine("FAT+"); - XmlFsType.Type = "FAT+"; + sb.AppendLine(Localization.FAT_Plus); + metadata.Type = FS_TYPE_FAT_PLUS; } else { - sb.AppendLine("Microsoft FAT32"); - XmlFsType.Type = "FAT32"; + sb.AppendLine(Localization.Microsoft_FAT32); + metadata.Type = FS_TYPE_FAT32; } if(fat32Bpb.oem_name != null) - if(fat32Bpb.oem_name[5] == 0x49 && - fat32Bpb.oem_name[6] == 0x48 && - fat32Bpb.oem_name[7] == 0x43) - sb.AppendLine("Volume has been modified by Windows 9x/Me Volume Tracker."); - else - XmlFsType.SystemIdentifier = StringHandlers.CToString(fat32Bpb.oem_name); - - if(!string.IsNullOrEmpty(XmlFsType.SystemIdentifier)) - sb.AppendFormat("OEM Name: {0}", XmlFsType.SystemIdentifier.Trim()).AppendLine(); - - sb.AppendFormat("{0} bytes per sector.", fat32Bpb.bps).AppendLine(); - sb.AppendFormat("{0} sectors per cluster.", fat32Bpb.spc).AppendLine(); - XmlFsType.ClusterSize = (uint)(fat32Bpb.bps * fat32Bpb.spc); - sb.AppendFormat("{0} sectors reserved between BPB and FAT.", fat32Bpb.rsectors).AppendLine(); - - if(fat32Bpb.big_sectors == 0 && - fat32Bpb.signature == 0x28) { - sb.AppendFormat("{0} sectors on volume ({1} bytes).", shortFat32Bpb.huge_sectors, - shortFat32Bpb.huge_sectors * shortFat32Bpb.bps).AppendLine(); + if(fat32Bpb.oem_name[5] == 0x49 && fat32Bpb.oem_name[6] == 0x48 && fat32Bpb.oem_name[7] == 0x43) + sb.AppendLine(Localization.Volume_has_been_modified_by_Windows_9x_Me_Volume_Tracker); + else + metadata.SystemIdentifier = StringHandlers.CToString(fat32Bpb.oem_name); + } - XmlFsType.Clusters = shortFat32Bpb.huge_sectors / shortFat32Bpb.spc; + if(!string.IsNullOrEmpty(metadata.SystemIdentifier)) + sb.AppendFormat(Localization.OEM_name_0, metadata.SystemIdentifier.Trim()).AppendLine(); + + sb.AppendFormat(Localization._0_bytes_per_sector, fat32Bpb.bps).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_cluster, fat32Bpb.spc).AppendLine(); + metadata.ClusterSize = (uint)(fat32Bpb.bps * fat32Bpb.spc); + sb.AppendFormat(Localization._0_sectors_reserved_between_BPB_and_FAT, fat32Bpb.rsectors).AppendLine(); + + if(fat32Bpb is { big_sectors: 0, signature: 0x28 }) + { + sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, + shortFat32Bpb.huge_sectors, + shortFat32Bpb.huge_sectors * shortFat32Bpb.bps) + .AppendLine(); + + metadata.Clusters = shortFat32Bpb.huge_sectors / shortFat32Bpb.spc; } else if(fat32Bpb.sectors == 0) { - sb.AppendFormat("{0} sectors on volume ({1} bytes).", fat32Bpb.big_sectors, - fat32Bpb.big_sectors * fat32Bpb.bps).AppendLine(); + sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, + fat32Bpb.big_sectors, + fat32Bpb.big_sectors * fat32Bpb.bps) + .AppendLine(); - XmlFsType.Clusters = fat32Bpb.big_sectors / fat32Bpb.spc; + metadata.Clusters = fat32Bpb.big_sectors / fat32Bpb.spc; } else { - sb.AppendFormat("{0} sectors on volume ({1} bytes).", fat32Bpb.sectors, - fat32Bpb.sectors * fat32Bpb.bps).AppendLine(); + sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, + fat32Bpb.sectors, + fat32Bpb.sectors * fat32Bpb.bps) + .AppendLine(); - XmlFsType.Clusters = (ulong)(fat32Bpb.sectors / fat32Bpb.spc); + metadata.Clusters = (ulong)(fat32Bpb.sectors / fat32Bpb.spc); } - sb.AppendFormat("{0} clusters on volume.", XmlFsType.Clusters).AppendLine(); - sb.AppendFormat("Media descriptor: 0x{0:X2}", fat32Bpb.media).AppendLine(); - sb.AppendFormat("{0} sectors per FAT.", fat32Bpb.big_spfat).AppendLine(); - sb.AppendFormat("{0} sectors per track.", fat32Bpb.sptrk).AppendLine(); - sb.AppendFormat("{0} heads.", fat32Bpb.heads).AppendLine(); - sb.AppendFormat("{0} hidden sectors before BPB.", fat32Bpb.hsectors).AppendLine(); - sb.AppendFormat("Cluster of root directory: {0}", fat32Bpb.root_cluster).AppendLine(); - sb.AppendFormat("Sector of FSINFO structure: {0}", fat32Bpb.fsinfo_sector).AppendLine(); - sb.AppendFormat("Sector of backup FAT32 parameter block: {0}", fat32Bpb.backup_sector).AppendLine(); - sb.AppendFormat("Drive number: 0x{0:X2}", fat32Bpb.drive_no).AppendLine(); - sb.AppendFormat("Volume Serial Number: 0x{0:X8}", fat32Bpb.serial_no).AppendLine(); - XmlFsType.VolumeSerial = $"{fat32Bpb.serial_no:X8}"; + sb.AppendFormat(Localization._0_clusters_on_volume, metadata.Clusters).AppendLine(); + sb.AppendFormat(Localization.Media_descriptor_0, fat32Bpb.media).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_FAT, fat32Bpb.big_spfat).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_track, fat32Bpb.sptrk).AppendLine(); + sb.AppendFormat(Localization._0_heads, fat32Bpb.heads).AppendLine(); + sb.AppendFormat(Localization._0_hidden_sectors_before_BPB, fat32Bpb.hsectors).AppendLine(); + sb.AppendFormat(Localization.Cluster_of_root_directory_0, fat32Bpb.root_cluster).AppendLine(); + sb.AppendFormat(Localization.Sector_of_FSINFO_structure_0, fat32Bpb.fsinfo_sector).AppendLine(); + + sb.AppendFormat(Localization.Sector_of_backup_FAT32_parameter_block_0, fat32Bpb.backup_sector) + .AppendLine(); + + sb.AppendFormat(Localization.Drive_number_0, fat32Bpb.drive_no).AppendLine(); + sb.AppendFormat(Localization.Volume_Serial_Number_0, fat32Bpb.serial_no).AppendLine(); + metadata.VolumeSerial = $"{fat32Bpb.serial_no:X8}"; if((fat32Bpb.flags & 0xF8) == 0x00) { if((fat32Bpb.flags & 0x01) == 0x01) { - sb.AppendLine("Volume should be checked on next mount."); - XmlFsType.Dirty = true; + sb.AppendLine(Localization.Volume_should_be_checked_on_next_mount); + metadata.Dirty = true; } if((fat32Bpb.flags & 0x02) == 0x02) - sb.AppendLine("Disk surface should be on next mount."); + sb.AppendLine(Localization.Disk_surface_should_be_checked_on_next_mount); } if((fat32Bpb.mirror_flags & 0x80) == 0x80) - sb.AppendFormat("FATs are out of sync. FAT #{0} is in use.", fat32Bpb.mirror_flags & 0xF). - AppendLine(); + { + sb.AppendFormat(Localization.FATs_are_out_of_sync_FAT_0_is_in_use, fat32Bpb.mirror_flags & 0xF) + .AppendLine(); + } else - sb.AppendLine("All copies of FAT are the same."); + sb.AppendLine(Localization.All_copies_of_FAT_are_the_same); if((fat32Bpb.mirror_flags & 0x6F20) == 0x6F20) - sb.AppendLine("DR-DOS will boot this FAT32 using CHS."); + sb.AppendLine(Localization.DR_DOS_will_boot_this_FAT32_using_CHS); else if((fat32Bpb.mirror_flags & 0x4F20) == 0x4F20) - sb.AppendLine("DR-DOS will boot this FAT32 using LBA."); + sb.AppendLine(Localization.DR_DOS_will_boot_this_FAT32_using_LBA); if(fat32Bpb.signature == 0x29) { - XmlFsType.VolumeName = StringHandlers.SpacePaddedToString(fat32Bpb.volume_label, Encoding); - XmlFsType.VolumeName = XmlFsType.VolumeName?.Replace("\0", ""); + metadata.VolumeName = StringHandlers.SpacePaddedToString(fat32Bpb.volume_label, encoding); + metadata.VolumeName = metadata.VolumeName?.Replace("\0", ""); - sb.AppendFormat("Filesystem type: {0}", Encoding.ASCII.GetString(fat32Bpb.fs_type)).AppendLine(); + sb.AppendFormat(Localization.Filesystem_type_0, Encoding.ASCII.GetString(fat32Bpb.fs_type)) + .AppendLine(); bootChk = Sha1Context.Data(fat32Bpb.boot_code, out _); } @@ -597,9 +621,10 @@ public sealed partial class FAT // Check that jumps to a correct boot code position and has boot signature set. // This will mean that the volume will boot, even if just to say "this is not bootable change disk"...... - XmlFsType.Bootable = + metadata.Bootable = fat32Bpb.jump[0] == 0xEB && fat32Bpb.jump[1] >= minBootNearJump && fat32Bpb.jump[1] < 0x80 || - fat32Bpb.jump[0] == 0xE9 && fat32Bpb.jump.Length >= 3 && + fat32Bpb.jump[0] == 0xE9 && + fat32Bpb.jump.Length >= 3 && BitConverter.ToUInt16(fat32Bpb.jump, 1) >= minBootNearJump && BitConverter.ToUInt16(fat32Bpb.jump, 1) <= 0x1FC; @@ -607,8 +632,10 @@ public sealed partial class FAT // First root directory sector rootDirectorySector = - (ulong)((fat32Bpb.root_cluster - 2) * fat32Bpb.spc + fat32Bpb.big_spfat * fat32Bpb.fats_no + - fat32Bpb.rsectors) * sectorsPerRealSector; + (ulong)((fat32Bpb.root_cluster - 2) * fat32Bpb.spc + + fat32Bpb.big_spfat * fat32Bpb.fats_no + + fat32Bpb.rsectors) * + sectorsPerRealSector; sectorsForRootDirectory = 1; @@ -616,25 +643,21 @@ public sealed partial class FAT { errno = imagePlugin.ReadSector(fat32Bpb.fsinfo_sector + partition.Start, out byte[] fsinfoSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; FsInfoSector fsInfo = Marshal.ByteArrayToStructureLittleEndian(fsinfoSector); if(fsInfo.signature1 == FSINFO_SIGNATURE1 && - fsInfo.signature2 == FSINFO_SIGNATURE2 && - fsInfo.signature3 == FSINFO_SIGNATURE3) + fsInfo is { signature2: FSINFO_SIGNATURE2, signature3: FSINFO_SIGNATURE3 }) { if(fsInfo.free_clusters < 0xFFFFFFFF) { - sb.AppendFormat("{0} free clusters", fsInfo.free_clusters).AppendLine(); - XmlFsType.FreeClusters = fsInfo.free_clusters; - XmlFsType.FreeClustersSpecified = true; + sb.AppendFormat(Localization._0_free_clusters, fsInfo.free_clusters).AppendLine(); + metadata.FreeClusters = fsInfo.free_clusters; } - if(fsInfo.last_cluster > 2 && - fsInfo.last_cluster < 0xFFFFFFFF) - sb.AppendFormat("Last allocated cluster {0}", fsInfo.last_cluster).AppendLine(); + if(fsInfo.last_cluster is > 2 and < 0xFFFFFFFF) + sb.AppendFormat(Localization.Last_allocated_cluster_0, fsInfo.last_cluster).AppendLine(); } } @@ -646,23 +669,23 @@ public sealed partial class FAT { ushort sum = 0; - for(var i = 0; i < bpbSector.Length; i += 2) - sum += BigEndianBitConverter.ToUInt16(bpbSector, i); + for(var i = 0; i < bpbSector.Length; i += 2) sum += BigEndianBitConverter.ToUInt16(bpbSector, i); // TODO: Check this if(sum == 0x1234) { - XmlFsType.Bootable = true; + metadata.Bootable = true; var atariSb = new StringBuilder(); - atariSb.AppendFormat("cmdload will be loaded with value {0:X4}h", - BigEndianBitConverter.ToUInt16(bpbSector, 0x01E)).AppendLine(); + atariSb.AppendFormat(Localization.cmdload_will_be_loaded_with_value_0, + BigEndianBitConverter.ToUInt16(bpbSector, 0x01E)) + .AppendLine(); - atariSb.AppendFormat("Boot program will be loaded at address {0:X4}h", atariBpb.ldaaddr). - AppendLine(); + atariSb.AppendFormat(Localization.Boot_program_will_be_loaded_at_address_0, atariBpb.ldaaddr) + .AppendLine(); - atariSb.AppendFormat("FAT and directory will be cached at address {0:X4}h", atariBpb.fatbuf). - AppendLine(); + atariSb.AppendFormat(Localization.FAT_and_directory_will_be_cached_at_address_0, atariBpb.fatbuf) + .AppendLine(); if(atariBpb.ldmode == 0) { @@ -679,12 +702,16 @@ public sealed partial class FAT else filename = fname + "." + extension; - atariSb.AppendFormat("Boot program resides in file \"{0}\"", filename).AppendLine(); + atariSb.AppendFormat(Localization.Boot_program_resides_in_file_0, filename).AppendLine(); } else - atariSb.AppendFormat("Boot program starts in sector {0} and is {1} sectors long ({2} bytes)", - atariBpb.ssect, atariBpb.sectcnt, atariBpb.sectcnt * atariBpb.bps). - AppendLine(); + { + atariSb.AppendFormat(Localization.Boot_program_starts_in_sector_0_and_is_1_sectors_long_2_bytes, + atariBpb.ssect, + atariBpb.sectcnt, + atariBpb.sectcnt * atariBpb.bps) + .AppendLine(); + } extraInfo = atariSb.ToString(); } @@ -693,7 +720,7 @@ public sealed partial class FAT } case BpbKind.Human: - XmlFsType.Bootable = true; + metadata.Bootable = true; break; } @@ -701,7 +728,7 @@ public sealed partial class FAT if(!isFat32) { // This is to support FAT partitions on hybrid ISO/USB images - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) { fakeBpb.bps *= 4; fakeBpb.spc /= 4; @@ -710,23 +737,29 @@ public sealed partial class FAT fakeBpb.sptrk /= 4; fakeBpb.rsectors /= 4; - if(fakeBpb.spc == 0) - fakeBpb.spc = 1; + if(fakeBpb.spc == 0) fakeBpb.spc = 1; } ulong clusters; if(bpbKind != BpbKind.Human) { - int reservedSectors = fakeBpb.rsectors + fakeBpb.fats_no * fakeBpb.spfat + - fakeBpb.root_ent * 32 / fakeBpb.bps; + int reservedSectors = fakeBpb.rsectors + + fakeBpb.fats_no * fakeBpb.spfat + + fakeBpb.root_ent * 32 / fakeBpb.bps; if(fakeBpb.sectors == 0) - clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.big_sectors - reservedSectors + { + clusters = (ulong)(fakeBpb.spc == 0 + ? fakeBpb.big_sectors - reservedSectors : (fakeBpb.big_sectors - reservedSectors) / fakeBpb.spc); + } else - clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.sectors - reservedSectors + { + clusters = (ulong)(fakeBpb.spc == 0 + ? fakeBpb.sectors - reservedSectors : (fakeBpb.sectors - reservedSectors) / fakeBpb.spc); + } } else clusters = humanBpb.clusters == 0 ? humanBpb.big_clusters : humanBpb.clusters; @@ -734,12 +767,12 @@ public sealed partial class FAT // This will walk all the FAT entries and check if they're valid FAT12 or FAT16 entries. // If the whole table is valid in both senses, it considers the type entry in the BPB. // BeOS is known to set the type as FAT16 but treat it as FAT12. - if(!isFat12 && - !isFat16) + if(!isFat12 && !isFat16) { if(clusters < 4089) { - var fat12 = new ushort[clusters]; + // The first 2 FAT entries do not count as allocation clusters in FAT12 and FAT16 + var fat12 = new ushort[clusters + 2]; _reservedSectors = fakeBpb.rsectors; sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize; @@ -747,8 +780,7 @@ public sealed partial class FAT errno = imagePlugin.ReadSectors(_fatFirstSector, fakeBpb.spfat, out byte[] fatBytes); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; var pos = 0; @@ -756,39 +788,20 @@ public sealed partial class FAT { fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]); - if(pos >= fat12.Length) - break; + if(pos >= fat12.Length) break; fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4)); } bool fat12Valid = fat12[0] >= FAT12_RESERVED && fat12[1] >= FAT12_RESERVED; - foreach(ushort entry in fat12) - { - if(entry >= FAT12_RESERVED || - entry <= clusters) - continue; - - fat12Valid = false; - - break; - } + if(fat12.Any(entry => entry < FAT12_RESERVED && entry > clusters + 2)) fat12Valid = false; ushort[] fat16 = MemoryMarshal.Cast(fatBytes).ToArray(); bool fat16Valid = fat16[0] >= FAT16_RESERVED && fat16[1] >= 0x3FF0; - foreach(ushort entry in fat16) - { - if(entry >= FAT16_RESERVED || - entry <= clusters) - continue; - - fat16Valid = false; - - break; - } + if(fat16.Any(entry => entry < FAT16_RESERVED && entry > clusters + 2)) fat16Valid = false; isFat12 = fat12Valid; isFat16 = fat16Valid; @@ -801,9 +814,7 @@ public sealed partial class FAT isFat16 = fakeBpb.fs_type != null && Encoding.ASCII.GetString(fakeBpb.fs_type) == "FAT16 "; } - if(!isFat12 && - !isFat16) - isFat12 = true; + if(!isFat12 && !isFat16) isFat12 = true; } else isFat16 = true; @@ -814,187 +825,196 @@ public sealed partial class FAT switch(bpbKind) { case BpbKind.Atari: - sb.AppendLine("Atari FAT12"); + sb.AppendLine(Localization.Atari_FAT12); break; case BpbKind.Apricot: - sb.AppendLine("Apricot FAT12"); + sb.AppendLine(Localization.Apricot_FAT12); break; case BpbKind.Human: - sb.AppendLine("Human68k FAT12"); + sb.AppendLine(Localization.Human68k_FAT12); break; default: - sb.AppendLine("Microsoft FAT12"); + sb.AppendLine(Localization.Microsoft_FAT12); break; } - XmlFsType.Type = "FAT12"; + metadata.Type = FS_TYPE_FAT12; } else if(isFat16) { - sb.AppendLine(bpbKind == BpbKind.Atari - ? "Atari FAT16" - : bpbKind == BpbKind.Human - ? "Human68k FAT16" - : "Microsoft FAT16"); + sb.AppendLine(bpbKind switch + { + BpbKind.Atari => Localization.Atari_FAT16, + BpbKind.Human => Localization.Human68k_FAT16, + _ => Localization.Microsoft_FAT16 + }); - XmlFsType.Type = "FAT16"; + metadata.Type = FS_TYPE_FAT16; } if(bpbKind == BpbKind.Atari) { - if(atariBpb.serial_no[0] == 0x49 && - atariBpb.serial_no[1] == 0x48 && - atariBpb.serial_no[2] == 0x43) - sb.AppendLine("Volume has been modified by Windows 9x/Me Volume Tracker."); + if(atariBpb.serial_no[0] == 0x49 && atariBpb.serial_no[1] == 0x48 && atariBpb.serial_no[2] == 0x43) + sb.AppendLine(Localization.Volume_has_been_modified_by_Windows_9x_Me_Volume_Tracker); else - XmlFsType.VolumeSerial = - $"{atariBpb.serial_no[0]:X2}{atariBpb.serial_no[1]:X2}{atariBpb.serial_no[2]:X2}"; + { + metadata.VolumeSerial = $"{atariBpb.serial_no[0]:X2}{atariBpb.serial_no[1]:X2}{atariBpb.serial_no[2] + :X2}"; + } - XmlFsType.SystemIdentifier = StringHandlers.CToString(atariBpb.oem_name); + metadata.SystemIdentifier = StringHandlers.CToString(atariBpb.oem_name); - if(string.IsNullOrEmpty(XmlFsType.SystemIdentifier)) - XmlFsType.SystemIdentifier = null; + if(string.IsNullOrEmpty(metadata.SystemIdentifier)) metadata.SystemIdentifier = null; } else if(fakeBpb.oem_name != null) { - if(fakeBpb.oem_name[5] == 0x49 && - fakeBpb.oem_name[6] == 0x48 && - fakeBpb.oem_name[7] == 0x43) - sb.AppendLine("Volume has been modified by Windows 9x/Me Volume Tracker."); + if(fakeBpb.oem_name[5] == 0x49 && fakeBpb.oem_name[6] == 0x48 && fakeBpb.oem_name[7] == 0x43) + sb.AppendLine(Localization.Volume_has_been_modified_by_Windows_9x_Me_Volume_Tracker); else { - // Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies - // OEM ID should be ASCII, otherwise ignore it - if(fakeBpb.oem_name[0] >= 0x20 && - fakeBpb.oem_name[0] <= 0x7F && - fakeBpb.oem_name[1] >= 0x20 && - fakeBpb.oem_name[1] <= 0x7F && - fakeBpb.oem_name[2] >= 0x20 && - fakeBpb.oem_name[2] <= 0x7F && - fakeBpb.oem_name[3] >= 0x20 && - fakeBpb.oem_name[3] <= 0x7F && - fakeBpb.oem_name[4] >= 0x20 && - fakeBpb.oem_name[4] <= 0x7F && - fakeBpb.oem_name[5] >= 0x20 && - fakeBpb.oem_name[5] <= 0x7F && - fakeBpb.oem_name[6] >= 0x20 && - fakeBpb.oem_name[6] <= 0x7F && - fakeBpb.oem_name[7] >= 0x20 && - fakeBpb.oem_name[7] <= 0x7F) - XmlFsType.SystemIdentifier = StringHandlers.CToString(fakeBpb.oem_name); - else if(fakeBpb.oem_name[0] < 0x20 && - fakeBpb.oem_name[1] >= 0x20 && - fakeBpb.oem_name[1] <= 0x7F && - fakeBpb.oem_name[2] >= 0x20 && - fakeBpb.oem_name[2] <= 0x7F && - fakeBpb.oem_name[3] >= 0x20 && - fakeBpb.oem_name[3] <= 0x7F && - fakeBpb.oem_name[4] >= 0x20 && - fakeBpb.oem_name[4] <= 0x7F && - fakeBpb.oem_name[5] >= 0x20 && - fakeBpb.oem_name[5] <= 0x7F && - fakeBpb.oem_name[6] >= 0x20 && - fakeBpb.oem_name[6] <= 0x7F && - fakeBpb.oem_name[7] >= 0x20 && - fakeBpb.oem_name[7] <= 0x7F) - XmlFsType.SystemIdentifier = StringHandlers.CToString(fakeBpb.oem_name, Encoding, start: 1); + metadata.SystemIdentifier = fakeBpb.oem_name[0] switch + { + // Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies + // OEM ID should be ASCII, otherwise ignore it + >= 0x20 and <= 0x7F when fakeBpb.oem_name[1] >= 0x20 && + fakeBpb.oem_name[1] <= 0x7F && + fakeBpb.oem_name[2] >= 0x20 && + fakeBpb.oem_name[2] <= 0x7F && + fakeBpb.oem_name[3] >= 0x20 && + fakeBpb.oem_name[3] <= 0x7F && + fakeBpb.oem_name[4] >= 0x20 && + fakeBpb.oem_name[4] <= 0x7F && + fakeBpb.oem_name[5] >= 0x20 && + fakeBpb.oem_name[5] <= 0x7F && + fakeBpb.oem_name[6] >= 0x20 && + fakeBpb.oem_name[6] <= 0x7F && + fakeBpb.oem_name[7] >= 0x20 && + fakeBpb.oem_name[7] <= 0x7F => + StringHandlers.CToString(fakeBpb.oem_name), + < 0x20 when fakeBpb.oem_name[1] >= 0x20 && + fakeBpb.oem_name[1] <= 0x7F && + fakeBpb.oem_name[2] >= 0x20 && + fakeBpb.oem_name[2] <= 0x7F && + fakeBpb.oem_name[3] >= 0x20 && + fakeBpb.oem_name[3] <= 0x7F && + fakeBpb.oem_name[4] >= 0x20 && + fakeBpb.oem_name[4] <= 0x7F && + fakeBpb.oem_name[5] >= 0x20 && + fakeBpb.oem_name[5] <= 0x7F && + fakeBpb.oem_name[6] >= 0x20 && + fakeBpb.oem_name[6] <= 0x7F && + fakeBpb.oem_name[7] >= 0x20 && + fakeBpb.oem_name[7] <= 0x7F => + StringHandlers.CToString(fakeBpb.oem_name, encoding, start: 1), + _ => metadata.SystemIdentifier + }; } - if(fakeBpb.signature is 0x28 or 0x29) - XmlFsType.VolumeSerial = $"{fakeBpb.serial_no:X8}"; + if(fakeBpb.signature is 0x28 or 0x29) metadata.VolumeSerial = $"{fakeBpb.serial_no:X8}"; } - if(XmlFsType.SystemIdentifier != null) - sb.AppendFormat("OEM Name: {0}", XmlFsType.SystemIdentifier.Trim()).AppendLine(); + if(metadata.SystemIdentifier != null) + sb.AppendFormat(Localization.OEM_name_0, metadata.SystemIdentifier.Trim()).AppendLine(); - sb.AppendFormat("{0} bytes per sector.", fakeBpb.bps).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector, fakeBpb.bps).AppendLine(); if(bpbKind != BpbKind.Human) - if(fakeBpb.sectors == 0) - sb.AppendFormat("{0} sectors on volume ({1} bytes).", fakeBpb.big_sectors, - fakeBpb.big_sectors * fakeBpb.bps).AppendLine(); - else - sb.AppendFormat("{0} sectors on volume ({1} bytes).", fakeBpb.sectors, - fakeBpb.sectors * fakeBpb.bps).AppendLine(); - else - sb.AppendFormat("{0} sectors on volume ({1} bytes).", - clusters * humanBpb.bpc / imagePlugin.Info.SectorSize, clusters * humanBpb.bpc). - AppendLine(); - - XmlFsType.Clusters = clusters; - sb.AppendFormat("{0} sectors per cluster.", fakeBpb.spc).AppendLine(); - sb.AppendFormat("{0} clusters on volume.", XmlFsType.Clusters).AppendLine(); - XmlFsType.ClusterSize = (uint)(fakeBpb.bps * fakeBpb.spc); - sb.AppendFormat("{0} sectors reserved between BPB and FAT.", fakeBpb.rsectors).AppendLine(); - sb.AppendFormat("{0} FATs.", fakeBpb.fats_no).AppendLine(); - sb.AppendFormat("{0} entries on root directory.", fakeBpb.root_ent).AppendLine(); - - if(fakeBpb.media > 0) - sb.AppendFormat("Media descriptor: 0x{0:X2}", fakeBpb.media).AppendLine(); - - sb.AppendFormat("{0} sectors per FAT.", fakeBpb.spfat).AppendLine(); - - if(fakeBpb.sptrk > 0 && - fakeBpb.sptrk < 64 && - fakeBpb.heads > 0 && - fakeBpb.heads < 256) { - sb.AppendFormat("{0} sectors per track.", fakeBpb.sptrk).AppendLine(); - sb.AppendFormat("{0} heads.", fakeBpb.heads).AppendLine(); + if(fakeBpb.sectors == 0) + { + sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, + fakeBpb.big_sectors, + fakeBpb.big_sectors * fakeBpb.bps) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, + fakeBpb.sectors, + fakeBpb.sectors * fakeBpb.bps) + .AppendLine(); + } + } + else + { + sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, + clusters * humanBpb.bpc / imagePlugin.Info.SectorSize, + clusters * humanBpb.bpc) + .AppendLine(); + } + + metadata.Clusters = clusters; + sb.AppendFormat(Localization._0_sectors_per_cluster, fakeBpb.spc).AppendLine(); + sb.AppendFormat(Localization._0_clusters_on_volume, metadata.Clusters).AppendLine(); + metadata.ClusterSize = (uint)(fakeBpb.bps * fakeBpb.spc); + sb.AppendFormat(Localization._0_sectors_reserved_between_BPB_and_FAT, fakeBpb.rsectors).AppendLine(); + sb.AppendFormat(Localization._0_FATs, fakeBpb.fats_no).AppendLine(); + sb.AppendFormat(Localization._0_entries_in_root_directory, fakeBpb.root_ent).AppendLine(); + + if(fakeBpb.media > 0) sb.AppendFormat(Localization.Media_descriptor_0, fakeBpb.media).AppendLine(); + + sb.AppendFormat(Localization._0_sectors_per_FAT, fakeBpb.spfat).AppendLine(); + + if(fakeBpb.sptrk is > 0 and < 64 && fakeBpb.heads is > 0 and < 256) + { + sb.AppendFormat(Localization._0_sectors_per_track, fakeBpb.sptrk).AppendLine(); + sb.AppendFormat(Localization._0_heads, fakeBpb.heads).AppendLine(); } if(fakeBpb.hsectors <= partition.Start) - sb.AppendFormat("{0} hidden sectors before BPB.", fakeBpb.hsectors).AppendLine(); + sb.AppendFormat(Localization._0_hidden_sectors_before_BPB, fakeBpb.hsectors).AppendLine(); if(fakeBpb.signature is 0x28 or 0x29 || andosOemCorrect) { - sb.AppendFormat("Drive number: 0x{0:X2}", fakeBpb.drive_no).AppendLine(); + sb.AppendFormat(Localization.Drive_number_0, fakeBpb.drive_no).AppendLine(); - if(XmlFsType.VolumeSerial != null) - sb.AppendFormat("Volume Serial Number: {0}", XmlFsType.VolumeSerial).AppendLine(); + if(metadata.VolumeSerial != null) + sb.AppendFormat(Localization.Volume_Serial_Number_0, metadata.VolumeSerial).AppendLine(); if((fakeBpb.flags & 0xF8) == 0x00) { if((fakeBpb.flags & 0x01) == 0x01) { - sb.AppendLine("Volume should be checked on next mount."); - XmlFsType.Dirty = true; + sb.AppendLine(Localization.Volume_should_be_checked_on_next_mount); + metadata.Dirty = true; } if((fakeBpb.flags & 0x02) == 0x02) - sb.AppendLine("Disk surface should be on next mount."); + sb.AppendLine(Localization.Disk_surface_should_be_checked_on_next_mount); } if(fakeBpb.signature == 0x29 || andosOemCorrect) { - XmlFsType.VolumeName = StringHandlers.SpacePaddedToString(fakeBpb.volume_label, Encoding); - XmlFsType.VolumeName = XmlFsType.VolumeName?.Replace("\0", ""); - sb.AppendFormat("Filesystem type: {0}", Encoding.ASCII.GetString(fakeBpb.fs_type)).AppendLine(); + metadata.VolumeName = StringHandlers.SpacePaddedToString(fakeBpb.volume_label, encoding); + metadata.VolumeName = metadata.VolumeName?.Replace("\0", ""); + + sb.AppendFormat(Localization.Filesystem_type_0, Encoding.ASCII.GetString(fakeBpb.fs_type)) + .AppendLine(); } } - else if(bpbKind == BpbKind.Atari && - XmlFsType.VolumeSerial != null) - sb.AppendFormat("Volume Serial Number: {0}", XmlFsType.VolumeSerial).AppendLine(); + else if(bpbKind == BpbKind.Atari && metadata.VolumeSerial != null) + sb.AppendFormat(Localization.Volume_Serial_Number_0, metadata.VolumeSerial).AppendLine(); bootChk = Sha1Context.Data(fakeBpb.boot_code, out _); // Workaround that PCExchange jumps into "FAT16 "... - if(XmlFsType.SystemIdentifier == "PCX 2.0 ") - fakeBpb.jump[1] += 8; + if(metadata.SystemIdentifier == "PCX 2.0 ") fakeBpb.jump[1] += 8; // Check that jumps to a correct boot code position and has boot signature set. // This will mean that the volume will boot, even if just to say "this is not bootable change disk"...... - if(XmlFsType.Bootable == false && - fakeBpb.jump != null) - XmlFsType.Bootable |= + if(metadata.Bootable == false && fakeBpb.jump != null) + { + metadata.Bootable |= fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] >= minBootNearJump && fakeBpb.jump[1] < 0x80 || - fakeBpb.jump[0] == 0xE9 && fakeBpb.jump.Length >= 3 && + fakeBpb.jump[0] == 0xE9 && + fakeBpb.jump.Length >= 3 && BitConverter.ToUInt16(fakeBpb.jump, 1) >= minBootNearJump && BitConverter.ToUInt16(fakeBpb.jump, 1) <= 0x1FC; + } sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize; @@ -1004,17 +1024,16 @@ public sealed partial class FAT sectorsForRootDirectory = (uint)(fakeBpb.root_ent * 32 / imagePlugin.Info.SectorSize); } - if(extraInfo != null) - sb.Append(extraInfo); + if(extraInfo != null) sb.Append(extraInfo); if(rootDirectorySector + partition.Start < partition.End && - imagePlugin.Info.XmlMediaType != XmlMediaType.OpticalDisc) + imagePlugin.Info.MetadataMediaType != MetadataMediaType.OpticalDisc) { - errno = imagePlugin.ReadSectors(rootDirectorySector + partition.Start, sectorsForRootDirectory, + errno = imagePlugin.ReadSectors(rootDirectorySector + partition.Start, + sectorsForRootDirectory, out byte[] rootDirectory); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; if(bpbKind == BpbKind.DecRainbow) { @@ -1027,8 +1046,7 @@ public sealed partial class FAT { errno = imagePlugin.ReadSector(rootSector, out byte[] tmp); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; rootMs.Write(tmp, 0, tmp.Length); } @@ -1039,93 +1057,93 @@ public sealed partial class FAT for(var i = 0; i < rootDirectory.Length; i += 32) { // Not a correct entry - if(rootDirectory[i] < DIRENT_MIN && - rootDirectory[i] != DIRENT_E5) - continue; + if(rootDirectory[i] < DIRENT_MIN && rootDirectory[i] != DIRENT_E5) continue; // Deleted or subdirectory entry - if(rootDirectory[i] == DIRENT_SUBDIR || - rootDirectory[i] == DIRENT_DELETED) - continue; + if(rootDirectory[i] == DIRENT_SUBDIR || rootDirectory[i] == DIRENT_DELETED) continue; // Not a volume label - if(rootDirectory[i + 0x0B] != 0x08 && - rootDirectory[i + 0x0B] != 0x28) - continue; + if(rootDirectory[i + 0x0B] != 0x08 && rootDirectory[i + 0x0B] != 0x28) continue; DirectoryEntry entry = Marshal.ByteArrayToStructureLittleEndian(rootDirectory, i, 32); var fullname = new byte[11]; - Array.Copy(entry.filename, 0, fullname, 0, 8); + Array.Copy(entry.filename, 0, fullname, 0, 8); Array.Copy(entry.extension, 0, fullname, 8, 3); - string volname = Encoding.GetString(fullname).Trim(); + string volname = encoding.GetString(fullname).Trim(); if(!string.IsNullOrEmpty(volname)) - XmlFsType.VolumeName = entry.caseinfo.HasFlag(CaseInfo.AllLowerCase) ? volname.ToLower() : volname; + metadata.VolumeName = entry.caseinfo.HasFlag(CaseInfo.AllLowerCase) ? volname.ToLower() : volname; - if(entry.ctime > 0 && - entry.cdate > 0) + if(entry is { ctime: > 0, cdate: > 0 }) { - XmlFsType.CreationDate = DateHandlers.DosToDateTime(entry.cdate, entry.ctime); + metadata.CreationDate = DateHandlers.DosToDateTime(entry.cdate, entry.ctime); if(entry.ctime_ms > 0) - XmlFsType.CreationDate = XmlFsType.CreationDate.AddMilliseconds(entry.ctime_ms * 10); + metadata.CreationDate = metadata.CreationDate?.AddMilliseconds(entry.ctime_ms * 10); - XmlFsType.CreationDateSpecified = true; - sb.AppendFormat("Volume created on {0}", XmlFsType.CreationDate).AppendLine(); + sb.AppendFormat(Localization.Volume_created_on_0, metadata.CreationDate).AppendLine(); } - if(entry.mtime > 0 && - entry.mdate > 0) + if(entry is { mtime: > 0, mdate: > 0 }) { - XmlFsType.ModificationDate = DateHandlers.DosToDateTime(entry.mdate, entry.mtime); - XmlFsType.ModificationDateSpecified = true; - sb.AppendFormat("Volume last modified on {0}", XmlFsType.ModificationDate).AppendLine(); + metadata.ModificationDate = DateHandlers.DosToDateTime(entry.mdate, entry.mtime); + sb.AppendFormat(Localization.Volume_last_modified_on_0, metadata.ModificationDate).AppendLine(); } if(entry.adate > 0) - sb.AppendFormat("Volume last accessed on {0:d}", DateHandlers.DosToDateTime(entry.adate, 0)). - AppendLine(); + { + sb.AppendFormat(Localization.Volume_last_accessed_on_0_d, + DateHandlers.DosToDateTime(entry.adate, 0)) + .AppendLine(); + } break; } } - if(!string.IsNullOrEmpty(XmlFsType.VolumeName)) - sb.AppendFormat("Volume label: {0}", XmlFsType.VolumeName).AppendLine(); + if(!string.IsNullOrEmpty(metadata.VolumeName)) + sb.AppendFormat(Localization.Volume_label_0, metadata.VolumeName).AppendLine(); - if(XmlFsType.Bootable) + if(metadata.Bootable) { - // Intel short jump - if(bpbSector[0] == 0xEB && - bpbSector[1] < 0x80) + switch(bpbSector[0]) { - int sigSize = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0; - var bootCode = new byte[512 - sigSize - bpbSector[1] - 2]; - Array.Copy(bpbSector, bpbSector[1] + 2, bootCode, 0, bootCode.Length); - Sha1Context.Data(bootCode, out _); + // Intel short jump + case 0xEB when bpbSector[1] < 0x80: + { + int sigSize = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0; + var bootCode = new byte[512 - sigSize - bpbSector[1] - 2]; + Array.Copy(bpbSector, bpbSector[1] + 2, bootCode, 0, bootCode.Length); + Sha1Context.Data(bootCode, out _); + + break; + } + + // Intel big jump + case 0xE9 when BitConverter.ToUInt16(bpbSector, 1) < 0x1FC: + { + int sigSize = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0; + var bootCode = new byte[512 - sigSize - BitConverter.ToUInt16(bpbSector, 1) - 3]; + Array.Copy(bpbSector, BitConverter.ToUInt16(bpbSector, 1) + 3, bootCode, 0, bootCode.Length); + Sha1Context.Data(bootCode, out _); + + break; + } } - // Intel big jump - else if(bpbSector[0] == 0xE9 && - BitConverter.ToUInt16(bpbSector, 1) < 0x1FC) - { - int sigSize = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0; - var bootCode = new byte[512 - sigSize - BitConverter.ToUInt16(bpbSector, 1) - 3]; - Array.Copy(bpbSector, BitConverter.ToUInt16(bpbSector, 1) + 3, bootCode, 0, bootCode.Length); - Sha1Context.Data(bootCode, out _); - } - - sb.AppendLine("Volume is bootable"); - sb.AppendFormat("Boot code's SHA1: {0}", bootChk).AppendLine(); + sb.AppendLine(Localization.Volume_is_bootable); + sb.AppendFormat(Localization.Boot_code_SHA1_0, bootChk).AppendLine(); string bootName = _knownBootHashes.FirstOrDefault(t => t.hash == bootChk).name; if(string.IsNullOrWhiteSpace(bootName)) - sb.AppendLine("Unknown boot code."); + sb.AppendLine(Localization.Unknown_boot_code); else - sb.AppendFormat("Boot code corresponds to {0}", bootName).AppendLine(); + sb.AppendFormat(Localization.Boot_code_corresponds_to_0, bootName).AppendLine(); } information = sb.ToString(); } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/FAT/Structs.cs b/Aaru.Filesystems/FAT/Structs.cs index 4056b1f1f..c5b49cd27 100644 --- a/Aaru.Filesystems/FAT/Structs.cs +++ b/Aaru.Filesystems/FAT/Structs.cs @@ -7,10 +7,6 @@ // // Component : Microsoft FAT filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Microsoft FAT filesystem structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,538 +23,23 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable NotAccessedField.Local -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed partial class FAT { const int UMSDOS_MAXNAME = 220; - /// BIOS Parameter Block as used by Atari ST GEMDOS on FAT12 volumes. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct AtariParameterBlock - { - /// 68000 BRA.S jump or x86 loop - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public readonly byte[] jump; - /// OEM Name, 6 bytes, space-padded, "Loader" for Atari ST boot loader - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public readonly byte[] oem_name; - /// Volume serial number - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] serial_no; - /// Bytes per sector - public readonly ushort bps; - /// Sectors per cluster - public readonly byte spc; - /// Reserved sectors between BPB and FAT (inclusive) - public readonly ushort rsectors; - /// Number of FATs - public readonly byte fats_no; - /// Number of entries on root directory - public readonly ushort root_ent; - /// Sectors in volume - public ushort sectors; - /// Media descriptor, unused by GEMDOS - public readonly byte media; - /// Sectors per FAT - public readonly ushort spfat; - /// Sectors per track - public readonly ushort sptrk; - /// Heads - public readonly ushort heads; - /// Hidden sectors before BPB, unused by GEMDOS - public readonly ushort hsectors; - /// Word to be loaded in the cmdload system variable. Big-endian. - public readonly ushort execflag; - /// - /// Word indicating load mode. If zero, file named is located and loaded. It not, sectors - /// specified in and are loaded. Big endian. - /// - public readonly ushort ldmode; - /// Starting sector of boot code. - public readonly ushort ssect; - /// Count of sectors of boot code. - public readonly ushort sectcnt; - /// Address where boot code should be loaded. - public readonly ushort ldaaddr; - /// Padding. - public readonly ushort padding; - /// Address where FAT and root directory sectors must be loaded. - public readonly ushort fatbuf; - /// Unknown. - public readonly ushort unknown; - /// Filename to be loaded for booting. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - public readonly byte[] fname; - /// Reserved - public readonly ushort reserved; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 455)] - public readonly byte[] boot_code; - /// Big endian word to make big endian sum of all sector words be equal to 0x1234 if disk is bootable. - public readonly ushort checksum; - } - - /// BIOS Parameter Block as used by MSX-DOS 2. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct MsxParameterBlock - { - /// x86 loop - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - /// OEM Name, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] oem_name; - /// Bytes per sector - public readonly ushort bps; - /// Sectors per cluster - public readonly byte spc; - /// Reserved sectors between BPB and FAT (inclusive) - public readonly ushort rsectors; - /// Number of FATs - public readonly byte fats_no; - /// Number of entries on root directory - public readonly ushort root_ent; - /// Sectors in volume - public ushort sectors; - /// Media descriptor - public readonly byte media; - /// Sectors per FAT - public readonly ushort spfat; - /// Sectors per track - public readonly ushort sptrk; - /// Heads - public readonly ushort heads; - /// Hidden sectors before BPB - public readonly ushort hsectors; - /// Jump for MSX-DOS 1 boot code - public readonly ushort msxdos_jmp; - /// Set to "VOL_ID" by MSX-DOS 2 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - public readonly byte[] vol_id; - /// Bigger than 0 if there are deleted files (MSX-DOS 2) - public readonly byte undelete_flag; - /// Volume serial number (MSX-DOS 2) - public readonly uint serial_no; - /// Reserved (MSX-DOS 2) - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public readonly byte[] reserved; - /// Jump for MSX-DOS 2 boot code (MSX-DOS 2) - public readonly ushort msxdos2_jmp; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 460)] - public readonly byte[] boot_code; - /// Always 0x55 0xAA. - public readonly ushort boot_signature; - } - - /// DOS 2.0 BIOS Parameter Block. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BiosParameterBlock2 - { - /// x86 jump - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - /// OEM Name, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] oem_name; - /// Bytes per sector - public readonly ushort bps; - /// Sectors per cluster - public readonly byte spc; - /// Reserved sectors between BPB and FAT - public readonly ushort rsectors; - /// Number of FATs - public readonly byte fats_no; - /// Number of entries on root directory - public readonly ushort root_ent; - /// Sectors in volume - public ushort sectors; - /// Media descriptor - public readonly byte media; - /// Sectors per FAT - public readonly ushort spfat; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 486)] - public readonly byte[] boot_code; - /// 0x55 0xAA if bootable. - public readonly ushort boot_signature; - } - - /// DOS 3.0 BIOS Parameter Block. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BiosParameterBlock30 - { - /// x86 jump - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - /// OEM Name, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] oem_name; - /// Bytes per sector - public readonly ushort bps; - /// Sectors per cluster - public readonly byte spc; - /// Reserved sectors between BPB and FAT - public readonly ushort rsectors; - /// Number of FATs - public readonly byte fats_no; - /// Number of entries on root directory - public readonly ushort root_ent; - /// Sectors in volume - public ushort sectors; - /// Media descriptor - public readonly byte media; - /// Sectors per FAT - public readonly ushort spfat; - /// Sectors per track - public readonly ushort sptrk; - /// Heads - public readonly ushort heads; - /// Hidden sectors before BPB - public readonly ushort hsectors; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 480)] - public readonly byte[] boot_code; - /// Always 0x55 0xAA. - public readonly ushort boot_signature; - } - - /// DOS 3.2 BIOS Parameter Block. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BiosParameterBlock32 - { - /// x86 jump - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - /// OEM Name, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] oem_name; - /// Bytes per sector - public readonly ushort bps; - /// Sectors per cluster - public readonly byte spc; - /// Reserved sectors between BPB and FAT - public readonly ushort rsectors; - /// Number of FATs - public readonly byte fats_no; - /// Number of entries on root directory - public readonly ushort root_ent; - /// Sectors in volume - public ushort sectors; - /// Media descriptor - public readonly byte media; - /// Sectors per FAT - public readonly ushort spfat; - /// Sectors per track - public readonly ushort sptrk; - /// Heads - public readonly ushort heads; - /// Hidden sectors before BPB - public readonly ushort hsectors; - /// Total sectors including hidden ones - public readonly ushort total_sectors; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 478)] - public readonly byte[] boot_code; - /// Always 0x55 0xAA. - public readonly ushort boot_signature; - } - - /// DOS 3.31 BIOS Parameter Block. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BiosParameterBlock33 - { - /// x86 jump - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - /// OEM Name, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] oem_name; - /// Bytes per sector - public readonly ushort bps; - /// Sectors per cluster - public readonly byte spc; - /// Reserved sectors between BPB and FAT - public readonly ushort rsectors; - /// Number of FATs - public readonly byte fats_no; - /// Number of entries on root directory - public readonly ushort root_ent; - /// Sectors in volume - public ushort sectors; - /// Media descriptor - public readonly byte media; - /// Sectors per FAT - public readonly ushort spfat; - /// Sectors per track - public readonly ushort sptrk; - /// Heads - public readonly ushort heads; - /// Hidden sectors before BPB - public readonly uint hsectors; - /// Sectors in volume if > 65535 - public uint big_sectors; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 474)] - public readonly byte[] boot_code; - /// Always 0x55 0xAA. - public readonly ushort boot_signature; - } - - /// DOS 3.4 BIOS Parameter Block. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BiosParameterBlockShortEbpb - { - /// x86 jump - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - /// OEM Name, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] oem_name; - /// Bytes per sector - public readonly ushort bps; - /// Sectors per cluster - public readonly byte spc; - /// Reserved sectors between BPB and FAT - public readonly ushort rsectors; - /// Number of FATs - public readonly byte fats_no; - /// Number of entries on root directory - public readonly ushort root_ent; - /// Sectors in volume - public ushort sectors; - /// Media descriptor - public readonly byte media; - /// Sectors per FAT - public readonly ushort spfat; - /// Sectors per track - public readonly ushort sptrk; - /// Heads - public readonly ushort heads; - /// Hidden sectors before BPB - public readonly uint hsectors; - /// Sectors in volume if > 65535 - public uint big_sectors; - /// Drive number - public readonly byte drive_no; - /// Volume flags - public readonly byte flags; - /// EPB signature, 0x28 - public readonly byte signature; - /// Volume serial number - public readonly uint serial_no; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 467)] - public readonly byte[] boot_code; - /// Always 0x55 0xAA. - public readonly ushort boot_signature; - } - - /// DOS 4.0 or higher BIOS Parameter Block. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BiosParameterBlockEbpb - { - /// x86 jump - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] jump; - /// OEM Name, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] oem_name; - /// Bytes per sector - public ushort bps; - /// Sectors per cluster - public byte spc; - /// Reserved sectors between BPB and FAT - public ushort rsectors; - /// Number of FATs - public byte fats_no; - /// Number of entries on root directory - public ushort root_ent; - /// Sectors in volume - public ushort sectors; - /// Media descriptor - public byte media; - /// Sectors per FAT - public ushort spfat; - /// Sectors per track - public ushort sptrk; - /// Heads - public ushort heads; - /// Hidden sectors before BPB - public uint hsectors; - /// Sectors in volume if > 65535 - public uint big_sectors; - /// Drive number - public byte drive_no; - /// Volume flags - public byte flags; - /// EPB signature, 0x29 - public byte signature; - /// Volume serial number - public uint serial_no; - /// Volume label, 11 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - public readonly byte[] volume_label; - /// Filesystem type, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] fs_type; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 448)] - public byte[] boot_code; - /// Always 0x55 0xAA. - public ushort boot_signature; - } - - /// FAT32 Parameter Block - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct Fat32ParameterBlockShort - { - /// x86 jump - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - /// OEM Name, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] oem_name; - /// Bytes per sector - public readonly ushort bps; - /// Sectors per cluster - public readonly byte spc; - /// Reserved sectors between BPB and FAT - public readonly ushort rsectors; - /// Number of FATs - public readonly byte fats_no; - /// Number of entries on root directory, set to 0 - public readonly ushort root_ent; - /// Sectors in volume, set to 0 - public ushort sectors; - /// Media descriptor - public readonly byte media; - /// Sectors per FAT, set to 0 - public readonly ushort spfat; - /// Sectors per track - public readonly ushort sptrk; - /// Heads - public readonly ushort heads; - /// Hidden sectors before BPB - public readonly uint hsectors; - /// Sectors in volume - public uint big_sectors; - /// Sectors per FAT - public readonly uint big_spfat; - /// FAT flags - public readonly ushort mirror_flags; - /// FAT32 version - public readonly ushort version; - /// Cluster of root directory - public readonly uint root_cluster; - /// Sector of FSINFO structure - public readonly ushort fsinfo_sector; - /// Sector of FAT32PB backup - public readonly ushort backup_sector; - /// Reserved - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] reserved; - /// Drive number - public readonly byte drive_no; - /// Volume flags - public readonly byte flags; - /// Signature, should be 0x28 - public readonly byte signature; - /// Volume serial number - public readonly uint serial_no; - /// Volume label, 11 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - public readonly byte[] reserved2; - /// Sectors in volume if equals 0 - public ulong huge_sectors; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 420)] - public readonly byte[] boot_code; - /// Always 0x55 0xAA. - public readonly ushort boot_signature; - } - - /// FAT32 Parameter Block - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct Fat32ParameterBlock - { - /// x86 jump - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - /// OEM Name, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] oem_name; - /// Bytes per sector - public ushort bps; - /// Sectors per cluster - public byte spc; - /// Reserved sectors between BPB and FAT - public readonly ushort rsectors; - /// Number of FATs - public readonly byte fats_no; - /// Number of entries on root directory, set to 0 - public readonly ushort root_ent; - /// Sectors in volume, set to 0 - public ushort sectors; - /// Media descriptor - public readonly byte media; - /// Sectors per FAT, set to 0 - public readonly ushort spfat; - /// Sectors per track - public ushort sptrk; - /// Heads - public readonly ushort heads; - /// Hidden sectors before BPB - public uint hsectors; - /// Sectors in volume - public uint big_sectors; - /// Sectors per FAT - public uint big_spfat; - /// FAT flags - public readonly ushort mirror_flags; - /// FAT32 version - public readonly ushort version; - /// Cluster of root directory - public readonly uint root_cluster; - /// Sector of FSINFO structure - public readonly ushort fsinfo_sector; - /// Sector of FAT32PB backup - public readonly ushort backup_sector; - /// Reserved - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] reserved; - /// Drive number - public readonly byte drive_no; - /// Volume flags - public readonly byte flags; - /// Signature, should be 0x29 - public readonly byte signature; - /// Volume serial number - public readonly uint serial_no; - /// Volume label, 11 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - public readonly byte[] volume_label; - /// Filesystem type, 8 bytes, space-padded, must be "FAT32 " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] fs_type; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 419)] - public readonly byte[] boot_code; - /// Always 0x55 0xAA. - public readonly ushort boot_signature; - } +#region Nested type: ApricotLabel /// Apricot Label. [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -771,6 +252,10 @@ public sealed partial class FAT public readonly bool cpmDoubleSided; } +#endregion + +#region Nested type: ApricotParameterBlock + [StructLayout(LayoutKind.Sequential, Pack = 1)] struct ApricotParameterBlock { @@ -796,6 +281,619 @@ public sealed partial class FAT public readonly ushort startSector; } +#endregion + +#region Nested type: AtariParameterBlock + + /// BIOS Parameter Block as used by Atari ST GEMDOS on FAT12 volumes. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct AtariParameterBlock + { + /// 68000 BRA.S jump or x86 loop + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public readonly byte[] jump; + /// OEM Name, 6 bytes, space-padded, "Loader" for Atari ST boot loader + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public readonly byte[] oem_name; + /// Volume serial number + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] serial_no; + /// Bytes per sector + public readonly ushort bps; + /// Sectors per cluster + public readonly byte spc; + /// Reserved sectors between BPB and FAT (inclusive) + public readonly ushort rsectors; + /// Number of FATs + public readonly byte fats_no; + /// Number of entries on root directory + public readonly ushort root_ent; + /// Sectors in volume + public ushort sectors; + /// Media descriptor, unused by GEMDOS + public readonly byte media; + /// Sectors per FAT + public readonly ushort spfat; + /// Sectors per track + public readonly ushort sptrk; + /// Heads + public readonly ushort heads; + /// Hidden sectors before BPB, unused by GEMDOS + public readonly ushort hsectors; + /// Word to be loaded in the cmdload system variable. Big-endian. + public readonly ushort execflag; + /// + /// Word indicating load mode. If zero, file named is located and loaded. It not, sectors + /// specified in and are loaded. Big endian. + /// + public readonly ushort ldmode; + /// Starting sector of boot code. + public readonly ushort ssect; + /// Count of sectors of boot code. + public readonly ushort sectcnt; + /// Address where boot code should be loaded. + public readonly ushort ldaaddr; + /// Padding. + public readonly ushort padding; + /// Address where FAT and root directory sectors must be loaded. + public readonly ushort fatbuf; + /// Unknown. + public readonly ushort unknown; + /// Filename to be loaded for booting. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public readonly byte[] fname; + /// Reserved + public readonly ushort reserved; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 455)] + public readonly byte[] boot_code; + /// Big endian word to make big endian sum of all sector words be equal to 0x1234 if disk is bootable. + public readonly ushort checksum; + } + +#endregion + +#region Nested type: BiosParameterBlock2 + + /// DOS 2.0 BIOS Parameter Block. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BiosParameterBlock2 + { + /// x86 jump + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + /// OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] oem_name; + /// Bytes per sector + public readonly ushort bps; + /// Sectors per cluster + public readonly byte spc; + /// Reserved sectors between BPB and FAT + public readonly ushort rsectors; + /// Number of FATs + public readonly byte fats_no; + /// Number of entries on root directory + public readonly ushort root_ent; + /// Sectors in volume + public ushort sectors; + /// Media descriptor + public readonly byte media; + /// Sectors per FAT + public readonly ushort spfat; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 486)] + public readonly byte[] boot_code; + /// 0x55 0xAA if bootable. + public readonly ushort boot_signature; + } + +#endregion + +#region Nested type: BiosParameterBlock30 + + /// DOS 3.0 BIOS Parameter Block. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BiosParameterBlock30 + { + /// x86 jump + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + /// OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] oem_name; + /// Bytes per sector + public readonly ushort bps; + /// Sectors per cluster + public readonly byte spc; + /// Reserved sectors between BPB and FAT + public readonly ushort rsectors; + /// Number of FATs + public readonly byte fats_no; + /// Number of entries on root directory + public readonly ushort root_ent; + /// Sectors in volume + public ushort sectors; + /// Media descriptor + public readonly byte media; + /// Sectors per FAT + public readonly ushort spfat; + /// Sectors per track + public readonly ushort sptrk; + /// Heads + public readonly ushort heads; + /// Hidden sectors before BPB + public readonly ushort hsectors; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 480)] + public readonly byte[] boot_code; + /// Always 0x55 0xAA. + public readonly ushort boot_signature; + } + +#endregion + +#region Nested type: BiosParameterBlock32 + + /// DOS 3.2 BIOS Parameter Block. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BiosParameterBlock32 + { + /// x86 jump + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + /// OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] oem_name; + /// Bytes per sector + public readonly ushort bps; + /// Sectors per cluster + public readonly byte spc; + /// Reserved sectors between BPB and FAT + public readonly ushort rsectors; + /// Number of FATs + public readonly byte fats_no; + /// Number of entries on root directory + public readonly ushort root_ent; + /// Sectors in volume + public ushort sectors; + /// Media descriptor + public readonly byte media; + /// Sectors per FAT + public readonly ushort spfat; + /// Sectors per track + public readonly ushort sptrk; + /// Heads + public readonly ushort heads; + /// Hidden sectors before BPB + public readonly ushort hsectors; + /// Total sectors including hidden ones + public readonly ushort total_sectors; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 478)] + public readonly byte[] boot_code; + /// Always 0x55 0xAA. + public readonly ushort boot_signature; + } + +#endregion + +#region Nested type: BiosParameterBlock33 + + /// DOS 3.31 BIOS Parameter Block. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BiosParameterBlock33 + { + /// x86 jump + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + /// OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] oem_name; + /// Bytes per sector + public readonly ushort bps; + /// Sectors per cluster + public readonly byte spc; + /// Reserved sectors between BPB and FAT + public readonly ushort rsectors; + /// Number of FATs + public readonly byte fats_no; + /// Number of entries on root directory + public readonly ushort root_ent; + /// Sectors in volume + public ushort sectors; + /// Media descriptor + public readonly byte media; + /// Sectors per FAT + public readonly ushort spfat; + /// Sectors per track + public readonly ushort sptrk; + /// Heads + public readonly ushort heads; + /// Hidden sectors before BPB + public readonly uint hsectors; + /// Sectors in volume if > 65535 + public uint big_sectors; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 474)] + public readonly byte[] boot_code; + /// Always 0x55 0xAA. + public readonly ushort boot_signature; + } + +#endregion + +#region Nested type: BiosParameterBlockEbpb + + /// DOS 4.0 or higher BIOS Parameter Block. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BiosParameterBlockEbpb + { + /// x86 jump + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] jump; + /// OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] oem_name; + /// Bytes per sector + public ushort bps; + /// Sectors per cluster + public byte spc; + /// Reserved sectors between BPB and FAT + public ushort rsectors; + /// Number of FATs + public byte fats_no; + /// Number of entries on root directory + public ushort root_ent; + /// Sectors in volume + public ushort sectors; + /// Media descriptor + public byte media; + /// Sectors per FAT + public ushort spfat; + /// Sectors per track + public ushort sptrk; + /// Heads + public ushort heads; + /// Hidden sectors before BPB + public uint hsectors; + /// Sectors in volume if > 65535 + public uint big_sectors; + /// Drive number + public byte drive_no; + /// Volume flags + public byte flags; + /// EPB signature, 0x29 + public byte signature; + /// Volume serial number + public uint serial_no; + /// Volume label, 11 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public readonly byte[] volume_label; + /// Filesystem type, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] fs_type; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 448)] + public byte[] boot_code; + /// Always 0x55 0xAA. + public ushort boot_signature; + } + +#endregion + +#region Nested type: BiosParameterBlockShortEbpb + + /// DOS 3.4 BIOS Parameter Block. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BiosParameterBlockShortEbpb + { + /// x86 jump + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + /// OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] oem_name; + /// Bytes per sector + public readonly ushort bps; + /// Sectors per cluster + public readonly byte spc; + /// Reserved sectors between BPB and FAT + public readonly ushort rsectors; + /// Number of FATs + public readonly byte fats_no; + /// Number of entries on root directory + public readonly ushort root_ent; + /// Sectors in volume + public ushort sectors; + /// Media descriptor + public readonly byte media; + /// Sectors per FAT + public readonly ushort spfat; + /// Sectors per track + public readonly ushort sptrk; + /// Heads + public readonly ushort heads; + /// Hidden sectors before BPB + public readonly uint hsectors; + /// Sectors in volume if > 65535 + public uint big_sectors; + /// Drive number + public readonly byte drive_no; + /// Volume flags + public readonly byte flags; + /// EPB signature, 0x28 + public readonly byte signature; + /// Volume serial number + public readonly uint serial_no; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 467)] + public readonly byte[] boot_code; + /// Always 0x55 0xAA. + public readonly ushort boot_signature; + } + +#endregion + +#region Nested type: CompleteDirectoryEntry + + sealed class CompleteDirectoryEntry + { + public DirectoryEntry Dirent; + public DirectoryEntry Fat32Ea; + public HumanDirectoryEntry HumanDirent; + public string HumanName; + public string Lfn; + public UmsdosDirectoryEntry LinuxDirent; + public string LinuxName; + public string Longname; + public string Shortname; + + public override string ToString() + { + // This ensures UMSDOS takes preference when present + if(!string.IsNullOrEmpty(LinuxName)) return LinuxName; + + // This ensures LFN takes preference when eCS is in use + if(!string.IsNullOrEmpty(Lfn)) return Lfn; + + // This ensures Humans takes preference when present + if(!string.IsNullOrEmpty(HumanName)) return HumanName; + + return !string.IsNullOrEmpty(Longname) ? Longname : Shortname; + } + } + +#endregion + +#region Nested type: DirectoryEntry + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DirectoryEntry + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] filename; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] extension; + public readonly FatAttributes attributes; + public readonly CaseInfo caseinfo; + public readonly byte ctime_ms; + public readonly ushort ctime; + public readonly ushort cdate; + public readonly ushort adate; + public readonly ushort ea_handle; + public readonly ushort mtime; + public readonly ushort mdate; + public readonly ushort start_cluster; + public readonly uint size; + } + +#endregion + +#region Nested type: EaHeader + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct EaHeader + { + public readonly ushort magic; + public readonly ushort cluster; + public readonly EaFlags flags; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] filename; + public readonly uint unknown; + public readonly ushort zero; + } + +#endregion + +#region Nested type: Fat32ParameterBlock + + /// FAT32 Parameter Block + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Fat32ParameterBlock + { + /// x86 jump + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + /// OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] oem_name; + /// Bytes per sector + public ushort bps; + /// Sectors per cluster + public byte spc; + /// Reserved sectors between BPB and FAT + public readonly ushort rsectors; + /// Number of FATs + public readonly byte fats_no; + /// Number of entries on root directory, set to 0 + public readonly ushort root_ent; + /// Sectors in volume, set to 0 + public ushort sectors; + /// Media descriptor + public readonly byte media; + /// Sectors per FAT, set to 0 + public readonly ushort spfat; + /// Sectors per track + public ushort sptrk; + /// Heads + public readonly ushort heads; + /// Hidden sectors before BPB + public uint hsectors; + /// Sectors in volume + public uint big_sectors; + /// Sectors per FAT + public uint big_spfat; + /// FAT flags + public readonly ushort mirror_flags; + /// FAT32 version + public readonly ushort version; + /// Cluster of root directory + public readonly uint root_cluster; + /// Sector of FSINFO structure + public readonly ushort fsinfo_sector; + /// Sector of FAT32PB backup + public readonly ushort backup_sector; + /// Reserved + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] reserved; + /// Drive number + public readonly byte drive_no; + /// Volume flags + public readonly byte flags; + /// Signature, should be 0x29 + public readonly byte signature; + /// Volume serial number + public readonly uint serial_no; + /// Volume label, 11 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public readonly byte[] volume_label; + /// Filesystem type, 8 bytes, space-padded, must be "FAT32 " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] fs_type; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 419)] + public readonly byte[] boot_code; + /// Always 0x55 0xAA. + public readonly ushort boot_signature; + } + +#endregion + +#region Nested type: Fat32ParameterBlockShort + + /// FAT32 Parameter Block + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Fat32ParameterBlockShort + { + /// x86 jump + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + /// OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] oem_name; + /// Bytes per sector + public readonly ushort bps; + /// Sectors per cluster + public readonly byte spc; + /// Reserved sectors between BPB and FAT + public readonly ushort rsectors; + /// Number of FATs + public readonly byte fats_no; + /// Number of entries on root directory, set to 0 + public readonly ushort root_ent; + /// Sectors in volume, set to 0 + public ushort sectors; + /// Media descriptor + public readonly byte media; + /// Sectors per FAT, set to 0 + public readonly ushort spfat; + /// Sectors per track + public readonly ushort sptrk; + /// Heads + public readonly ushort heads; + /// Hidden sectors before BPB + public readonly uint hsectors; + /// Sectors in volume + public uint big_sectors; + /// Sectors per FAT + public readonly uint big_spfat; + /// FAT flags + public readonly ushort mirror_flags; + /// FAT32 version + public readonly ushort version; + /// Cluster of root directory + public readonly uint root_cluster; + /// Sector of FSINFO structure + public readonly ushort fsinfo_sector; + /// Sector of FAT32PB backup + public readonly ushort backup_sector; + /// Reserved + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] reserved; + /// Drive number + public readonly byte drive_no; + /// Volume flags + public readonly byte flags; + /// Signature, should be 0x28 + public readonly byte signature; + /// Volume serial number + public readonly uint serial_no; + /// Volume label, 11 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public readonly byte[] reserved2; + /// Sectors in volume if equals 0 + public ulong huge_sectors; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 420)] + public readonly byte[] boot_code; + /// Always 0x55 0xAA. + public readonly ushort boot_signature; + } + +#endregion + +#region Nested type: FatDirNode + + sealed class FatDirNode : IDirNode + { + internal CompleteDirectoryEntry[] Entries; + internal int Position; + +#region IDirNode Members + + /// + public string Path { get; init; } + +#endregion + } + +#endregion + +#region Nested type: FatFileNode + + sealed class FatFileNode : IFileNode + { + internal uint[] Clusters; + +#region IFileNode Members + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + +#endregion + } + +#endregion + +#region Nested type: FsInfoSector + /// FAT32 FS Information Sector [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct FsInfoSector @@ -818,6 +916,30 @@ public sealed partial class FAT public readonly uint signature3; } +#endregion + +#region Nested type: HumanDirectoryEntry + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct HumanDirectoryEntry + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] name1; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] extension; + public readonly FatAttributes attributes; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public readonly byte[] name2; + public readonly ushort mtime; + public readonly ushort mdate; + public readonly ushort start_cluster; + public readonly uint size; + } + +#endregion + +#region Nested type: HumanParameterBlock + /// Human68k Parameter Block, big endian, 512 bytes even on 256 bytes/sector. [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct HumanParameterBlock @@ -851,41 +973,9 @@ public sealed partial class FAT public readonly byte[] boot_code; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DirectoryEntry - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] filename; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] extension; - public readonly FatAttributes attributes; - public readonly CaseInfo caseinfo; - public readonly byte ctime_ms; - public readonly ushort ctime; - public readonly ushort cdate; - public readonly ushort adate; - public readonly ushort ea_handle; - public readonly ushort mtime; - public readonly ushort mdate; - public readonly ushort start_cluster; - public readonly uint size; - } +#endregion - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct HumanDirectoryEntry - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] name1; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] extension; - public readonly FatAttributes attributes; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public readonly byte[] name2; - public readonly ushort mtime; - public readonly ushort mdate; - public readonly ushort start_cluster; - public readonly uint size; - } +#region Nested type: LfnEntry [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct LfnEntry @@ -903,18 +993,67 @@ public sealed partial class FAT public readonly byte[] name3; } +#endregion + +#region Nested type: MsxParameterBlock + + /// BIOS Parameter Block as used by MSX-DOS 2. [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct EaHeader + struct MsxParameterBlock { - public readonly ushort magic; - public readonly ushort cluster; - public readonly EaFlags flags; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] filename; - public readonly uint unknown; - public readonly ushort zero; + /// x86 loop + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + /// OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] oem_name; + /// Bytes per sector + public readonly ushort bps; + /// Sectors per cluster + public readonly byte spc; + /// Reserved sectors between BPB and FAT (inclusive) + public readonly ushort rsectors; + /// Number of FATs + public readonly byte fats_no; + /// Number of entries on root directory + public readonly ushort root_ent; + /// Sectors in volume + public ushort sectors; + /// Media descriptor + public readonly byte media; + /// Sectors per FAT + public readonly ushort spfat; + /// Sectors per track + public readonly ushort sptrk; + /// Heads + public readonly ushort heads; + /// Hidden sectors before BPB + public readonly ushort hsectors; + /// Jump for MSX-DOS 1 boot code + public readonly ushort msxdos_jmp; + /// Set to "VOL_ID" by MSX-DOS 2 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public readonly byte[] vol_id; + /// Bigger than 0 if there are deleted files (MSX-DOS 2) + public readonly byte undelete_flag; + /// Volume serial number (MSX-DOS 2) + public readonly uint serial_no; + /// Reserved (MSX-DOS 2) + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public readonly byte[] reserved; + /// Jump for MSX-DOS 2 boot code (MSX-DOS 2) + public readonly ushort msxdos2_jmp; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 460)] + public readonly byte[] boot_code; + /// Always 0x55 0xAA. + public readonly ushort boot_signature; } +#endregion + +#region Nested type: UmsdosDirectoryEntry + /// This structure is 256 bytes large, depending on the name, only part of it is written to disk [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct UmsdosDirectoryEntry @@ -951,6 +1090,10 @@ public sealed partial class FAT public readonly byte[] name; } +#endregion + +#region Nested type: UmsdosFlags + [SuppressMessage("ReSharper", "InconsistentNaming")] enum UmsdosFlags : byte { @@ -960,33 +1103,5 @@ public sealed partial class FAT UMSDOS_HLINK = 2 } - class CompleteDirectoryEntry - { - public DirectoryEntry Dirent; - public DirectoryEntry Fat32Ea; - public HumanDirectoryEntry HumanDirent; - public string HumanName; - public string Lfn; - public UmsdosDirectoryEntry LinuxDirent; - public string LinuxName; - public string Longname; - public string Shortname; - - public override string ToString() - { - // This ensures UMSDOS takes preference when present - if(!string.IsNullOrEmpty(LinuxName)) - return LinuxName; - - // This ensures LFN takes preference when eCS is in use - if(!string.IsNullOrEmpty(Lfn)) - return Lfn; - - // This ensures Humans takes preference when present - if(!string.IsNullOrEmpty(HumanName)) - return HumanName; - - return !string.IsNullOrEmpty(Longname) ? Longname : Shortname; - } - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/FAT/Super.cs b/Aaru.Filesystems/FAT/Super.cs index b9565b1f4..f50425d37 100644 --- a/Aaru.Filesystems/FAT/Super.cs +++ b/Aaru.Filesystems/FAT/Super.cs @@ -7,10 +7,6 @@ // // Component : Microsoft FAT filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Handles mounting and umounting the Microsoft FAT filesystem. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,11 +23,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Globalization; @@ -39,32 +33,31 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Helpers; -using Schemas; using FileSystemInfo = Aaru.CommonTypes.Structs.FileSystemInfo; using Marshal = Aaru.Helpers.Marshal; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class FAT { - uint _fatEntriesPerSector; - IMediaImage _image; +#region IReadOnlyFilesystem Members /// - public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, - Dictionary options, string @namespace) + public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace) { - XmlFsType = new FileSystemType(); - ErrorNumber errno; + Metadata = new FileSystem(); options ??= GetDefaultOptions(); - if(options.TryGetValue("debug", out string debugString)) - bool.TryParse(debugString, out _debug); + if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out _debug); // Default namespace @namespace ??= "ecs"; @@ -95,27 +88,33 @@ public sealed partial class FAT _namespace = Namespace.Human; break; - default: return ErrorNumber.InvalidArgument; + default: + return ErrorNumber.InvalidArgument; } - AaruConsole.DebugWriteLine("FAT plugin", "Reading BPB"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_BPB); uint sectorsPerBpb = imagePlugin.Info.SectorSize < 512 ? 512 / imagePlugin.Info.SectorSize : 1; - errno = imagePlugin.ReadSectors(0 + partition.Start, sectorsPerBpb, out byte[] bpbSector); + ErrorNumber errno = imagePlugin.ReadSectors(0 + partition.Start, sectorsPerBpb, out byte[] bpbSector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - BpbKind bpbKind = DetectBpbKind(bpbSector, imagePlugin, partition, out BiosParameterBlockEbpb fakeBpb, - out HumanParameterBlock humanBpb, out AtariParameterBlock atariBpb, - out byte minBootNearJump, out bool andosOemCorrect, out bool bootable); + BpbKind bpbKind = DetectBpbKind(bpbSector, + imagePlugin, + partition, + out BiosParameterBlockEbpb fakeBpb, + out HumanParameterBlock humanBpb, + out AtariParameterBlock atariBpb, + out byte minBootNearJump, + out bool andosOemCorrect, + out bool bootable); - _fat12 = false; - _fat16 = false; - _fat32 = false; - _useFirstFat = true; - XmlFsType.Bootable = bootable; + _fat12 = false; + _fat16 = false; + _fat32 = false; + _useFirstFat = true; + Metadata.Bootable = bootable; _statfs = new FileSystemInfo { @@ -133,8 +132,8 @@ public sealed partial class FAT uint sectorsForRootDirectory = 0; uint rootDirectoryCluster = 0; - Encoding = encoding ?? (bpbKind == BpbKind.Human ? Encoding.GetEncoding("shift_jis") - : Encoding.GetEncoding("IBM437")); + _encoding = encoding ?? + (bpbKind == BpbKind.Human ? Encoding.GetEncoding("shift_jis") : Encoding.GetEncoding("IBM437")); switch(bpbKind) { @@ -158,7 +157,7 @@ public sealed partial class FAT rootDirectoryCluster = fat32Bpb.root_cluster; // This is to support FAT partitions on hybrid ISO/USB images - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) { fat32Bpb.bps *= 4; fat32Bpb.spc /= 4; @@ -167,26 +166,25 @@ public sealed partial class FAT fat32Bpb.sptrk /= 4; } - XmlFsType.Type = fat32Bpb.version != 0 ? "FAT+" : "FAT32"; + Metadata.Type = fat32Bpb.version != 0 ? FS_TYPE_FAT_PLUS : FS_TYPE_FAT32; if(fat32Bpb.oem_name != null && (fat32Bpb.oem_name[5] != 0x49 || fat32Bpb.oem_name[6] != 0x48 || fat32Bpb.oem_name[7] != 0x43)) - XmlFsType.SystemIdentifier = StringHandlers.CToString(fat32Bpb.oem_name); + Metadata.SystemIdentifier = StringHandlers.CToString(fat32Bpb.oem_name); - _sectorsPerCluster = fat32Bpb.spc; - XmlFsType.ClusterSize = (uint)(fat32Bpb.bps * fat32Bpb.spc); - _reservedSectors = fat32Bpb.rsectors; + _sectorsPerCluster = fat32Bpb.spc; + Metadata.ClusterSize = (uint)(fat32Bpb.bps * fat32Bpb.spc); + _reservedSectors = fat32Bpb.rsectors; - if(fat32Bpb.big_sectors == 0 && - fat32Bpb.signature == 0x28) - XmlFsType.Clusters = shortFat32Bpb.huge_sectors / shortFat32Bpb.spc; + if(fat32Bpb is { big_sectors: 0, signature: 0x28 }) + Metadata.Clusters = shortFat32Bpb.huge_sectors / shortFat32Bpb.spc; else if(fat32Bpb.sectors == 0) - XmlFsType.Clusters = fat32Bpb.big_sectors / fat32Bpb.spc; + Metadata.Clusters = fat32Bpb.big_sectors / fat32Bpb.spc; else - XmlFsType.Clusters = (ulong)(fat32Bpb.sectors / fat32Bpb.spc); + Metadata.Clusters = (ulong)(fat32Bpb.sectors / fat32Bpb.spc); - _sectorsPerFat = fat32Bpb.big_spfat; - XmlFsType.VolumeSerial = $"{fat32Bpb.serial_no:X8}"; + _sectorsPerFat = fat32Bpb.big_spfat; + Metadata.VolumeSerial = $"{fat32Bpb.serial_no:X8}"; _statfs.Id = new FileSystemId { @@ -196,22 +194,22 @@ public sealed partial class FAT if((fat32Bpb.flags & 0xF8) == 0x00) if((fat32Bpb.flags & 0x01) == 0x01) - XmlFsType.Dirty = true; + Metadata.Dirty = true; - if((fat32Bpb.mirror_flags & 0x80) == 0x80) - _useFirstFat = (fat32Bpb.mirror_flags & 0xF) != 1; + if((fat32Bpb.mirror_flags & 0x80) == 0x80) _useFirstFat = (fat32Bpb.mirror_flags & 0xF) != 1; if(fat32Bpb.signature == 0x29) { - XmlFsType.VolumeName = StringHandlers.SpacePaddedToString(fat32Bpb.volume_label, Encoding); - XmlFsType.VolumeName = XmlFsType.VolumeName?.Replace("\0", ""); + Metadata.VolumeName = StringHandlers.SpacePaddedToString(fat32Bpb.volume_label, _encoding); + Metadata.VolumeName = Metadata.VolumeName?.Replace("\0", ""); } // Check that jumps to a correct boot code position and has boot signature set. // This will mean that the volume will boot, even if just to say "this is not bootable change disk"...... - XmlFsType.Bootable = + Metadata.Bootable = fat32Bpb.jump[0] == 0xEB && fat32Bpb.jump[1] >= minBootNearJump && fat32Bpb.jump[1] < 0x80 || - fat32Bpb.jump[0] == 0xE9 && fat32Bpb.jump.Length >= 3 && + fat32Bpb.jump[0] == 0xE9 && + fat32Bpb.jump.Length >= 3 && BitConverter.ToUInt16(fat32Bpb.jump, 1) >= minBootNearJump && BitConverter.ToUInt16(fat32Bpb.jump, 1) <= 0x1FC; @@ -227,19 +225,13 @@ public sealed partial class FAT { errno = imagePlugin.ReadSector(fat32Bpb.fsinfo_sector + partition.Start, out byte[] fsinfoSector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; FsInfoSector fsInfo = Marshal.ByteArrayToStructureLittleEndian(fsinfoSector); - if(fsInfo.signature1 == FSINFO_SIGNATURE1 && - fsInfo.signature2 == FSINFO_SIGNATURE2 && - fsInfo.signature3 == FSINFO_SIGNATURE3) - if(fsInfo.free_clusters < 0xFFFFFFFF) - { - XmlFsType.FreeClusters = fsInfo.free_clusters; - XmlFsType.FreeClustersSpecified = true; - } + if(fsInfo is { signature1: FSINFO_SIGNATURE1, signature2 : FSINFO_SIGNATURE2 } + and { signature3: FSINFO_SIGNATURE3, free_clusters: < 0xFFFFFFFF }) + Metadata.FreeClusters = fsInfo.free_clusters; } break; @@ -250,12 +242,10 @@ public sealed partial class FAT { ushort sum = 0; - for(var i = 0; i < bpbSector.Length; i += 2) - sum += BigEndianBitConverter.ToUInt16(bpbSector, i); + for(var i = 0; i < bpbSector.Length; i += 2) sum += BigEndianBitConverter.ToUInt16(bpbSector, i); // TODO: Check this - if(sum == 0x1234) - XmlFsType.Bootable = true; + if(sum == 0x1234) Metadata.Bootable = true; // BGM changes the bytes per sector instead of changing the sectors per cluster. Why?! WHY!? uint ratio = fakeBpb.bps / imagePlugin.Info.SectorSize; @@ -272,10 +262,9 @@ public sealed partial class FAT case BpbKind.Human: // If not debug set Human68k namespace and ShiftJIS codepage as defaults - if(!_debug) - _namespace = Namespace.Human; + if(!_debug) _namespace = Namespace.Human; - XmlFsType.Bootable = true; + Metadata.Bootable = true; break; } @@ -285,7 +274,7 @@ public sealed partial class FAT if(!_fat32) { // This is to support FAT partitions on hybrid ISO/USB images - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) { fakeBpb.bps *= 4; fakeBpb.spc /= 4; @@ -294,23 +283,29 @@ public sealed partial class FAT fakeBpb.sptrk /= 4; fakeBpb.rsectors /= 4; - if(fakeBpb.spc == 0) - fakeBpb.spc = 1; + if(fakeBpb.spc == 0) fakeBpb.spc = 1; } ulong clusters; if(bpbKind != BpbKind.Human) { - int reservedSectors = fakeBpb.rsectors + fakeBpb.fats_no * fakeBpb.spfat + - fakeBpb.root_ent * 32 / fakeBpb.bps; + int reservedSectors = fakeBpb.rsectors + + fakeBpb.fats_no * fakeBpb.spfat + + fakeBpb.root_ent * 32 / fakeBpb.bps; if(fakeBpb.sectors == 0) - clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.big_sectors - reservedSectors + { + clusters = (ulong)(fakeBpb.spc == 0 + ? fakeBpb.big_sectors - reservedSectors : (fakeBpb.big_sectors - reservedSectors) / fakeBpb.spc); + } else - clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.sectors - reservedSectors + { + clusters = (ulong)(fakeBpb.spc == 0 + ? fakeBpb.sectors - reservedSectors : (fakeBpb.sectors - reservedSectors) / fakeBpb.spc); + } } else clusters = humanBpb.clusters == 0 ? humanBpb.big_clusters : humanBpb.clusters; @@ -318,12 +313,11 @@ public sealed partial class FAT // This will walk all the FAT entries and check if they're valid FAT12 or FAT16 entries. // If the whole table is valid in both senses, it considers the type entry in the BPB. // BeOS is known to set the type as FAT16 but treat it as FAT12. - if(!_fat12 && - !_fat16) + if(!_fat12 && !_fat16) { if(clusters < 4089) { - var fat12 = new ushort[clusters]; + var fat12 = new ushort[clusters + 1]; _reservedSectors = fakeBpb.rsectors; sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize; @@ -331,8 +325,7 @@ public sealed partial class FAT errno = imagePlugin.ReadSectors(_fatFirstSector, fakeBpb.spfat, out byte[] fatBytes); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; var pos = 0; @@ -340,46 +333,26 @@ public sealed partial class FAT { fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]); - if(pos >= fat12.Length) - break; + if(pos >= fat12.Length) break; fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4)); } bool fat12Valid = fat12[0] >= FAT12_RESERVED && fat12[1] >= FAT12_RESERVED; - foreach(ushort entry in fat12) - { - if(entry >= FAT12_RESERVED || - entry <= clusters) - continue; - - fat12Valid = false; - - break; - } + if(fat12.Any(entry => entry < FAT12_RESERVED && entry > clusters)) fat12Valid = false; ushort[] fat16 = MemoryMarshal.Cast(fatBytes).ToArray(); bool fat16Valid = fat16[0] >= FAT16_RESERVED && fat16[1] >= 0x3FF0; - foreach(ushort entry in fat16) - { - if(entry >= FAT16_RESERVED || - entry <= clusters) - continue; - - fat16Valid = false; - - break; - } + if(fat16.Any(entry => entry < FAT16_RESERVED && entry > clusters)) fat16Valid = false; _fat12 = fat12Valid; _fat16 = fat16Valid; // Check BPB type - if(_fat12 == _fat16 && - fakeBpb.fs_type != null) + if(_fat12 == _fat16 && fakeBpb.fs_type != null) { _fat12 = Encoding.ASCII.GetString(fakeBpb.fs_type) == "FAT12 "; _fat16 = Encoding.ASCII.GetString(fakeBpb.fs_type) == "FAT16 "; @@ -397,78 +370,74 @@ public sealed partial class FAT } if(_fat12) - XmlFsType.Type = "FAT12"; - else if(_fat16) - XmlFsType.Type = "FAT16"; + Metadata.Type = FS_TYPE_FAT12; + else if(_fat16) Metadata.Type = FS_TYPE_FAT16; if(bpbKind == BpbKind.Atari) { - if(atariBpb.serial_no[0] != 0x49 || - atariBpb.serial_no[1] != 0x48 || - atariBpb.serial_no[2] != 0x43) + if(atariBpb.serial_no[0] != 0x49 || atariBpb.serial_no[1] != 0x48 || atariBpb.serial_no[2] != 0x43) { - XmlFsType.VolumeSerial = - $"{atariBpb.serial_no[0]:X2}{atariBpb.serial_no[1]:X2}{atariBpb.serial_no[2]:X2}"; + Metadata.VolumeSerial = $"{atariBpb.serial_no[0]:X2}{atariBpb.serial_no[1]:X2}{atariBpb.serial_no[2] + :X2}"; _statfs.Id = new FileSystemId { IsInt = true, - Serial32 = (uint)((atariBpb.serial_no[0] << 16) + (atariBpb.serial_no[1] << 8) + + Serial32 = (uint)((atariBpb.serial_no[0] << 16) + + (atariBpb.serial_no[1] << 8) + atariBpb.serial_no[2]) }; } - XmlFsType.SystemIdentifier = StringHandlers.CToString(atariBpb.oem_name); + Metadata.SystemIdentifier = StringHandlers.CToString(atariBpb.oem_name); - if(string.IsNullOrEmpty(XmlFsType.SystemIdentifier)) - XmlFsType.SystemIdentifier = null; + if(string.IsNullOrEmpty(Metadata.SystemIdentifier)) Metadata.SystemIdentifier = null; } else if(fakeBpb.oem_name != null) { - if(fakeBpb.oem_name[5] != 0x49 || - fakeBpb.oem_name[6] != 0x48 || - fakeBpb.oem_name[7] != 0x43) + if(fakeBpb.oem_name[5] != 0x49 || fakeBpb.oem_name[6] != 0x48 || fakeBpb.oem_name[7] != 0x43) { - // Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies - // OEM ID should be ASCII, otherwise ignore it - if(fakeBpb.oem_name[0] >= 0x20 && - fakeBpb.oem_name[0] <= 0x7F && - fakeBpb.oem_name[1] >= 0x20 && - fakeBpb.oem_name[1] <= 0x7F && - fakeBpb.oem_name[2] >= 0x20 && - fakeBpb.oem_name[2] <= 0x7F && - fakeBpb.oem_name[3] >= 0x20 && - fakeBpb.oem_name[3] <= 0x7F && - fakeBpb.oem_name[4] >= 0x20 && - fakeBpb.oem_name[4] <= 0x7F && - fakeBpb.oem_name[5] >= 0x20 && - fakeBpb.oem_name[5] <= 0x7F && - fakeBpb.oem_name[6] >= 0x20 && - fakeBpb.oem_name[6] <= 0x7F && - fakeBpb.oem_name[7] >= 0x20 && - fakeBpb.oem_name[7] <= 0x7F) - XmlFsType.SystemIdentifier = StringHandlers.CToString(fakeBpb.oem_name); - else if(fakeBpb.oem_name[0] < 0x20 && - fakeBpb.oem_name[1] >= 0x20 && - fakeBpb.oem_name[1] <= 0x7F && - fakeBpb.oem_name[2] >= 0x20 && - fakeBpb.oem_name[2] <= 0x7F && - fakeBpb.oem_name[3] >= 0x20 && - fakeBpb.oem_name[3] <= 0x7F && - fakeBpb.oem_name[4] >= 0x20 && - fakeBpb.oem_name[4] <= 0x7F && - fakeBpb.oem_name[5] >= 0x20 && - fakeBpb.oem_name[5] <= 0x7F && - fakeBpb.oem_name[6] >= 0x20 && - fakeBpb.oem_name[6] <= 0x7F && - fakeBpb.oem_name[7] >= 0x20 && - fakeBpb.oem_name[7] <= 0x7F) - XmlFsType.SystemIdentifier = StringHandlers.CToString(fakeBpb.oem_name, Encoding, start: 1); + Metadata.SystemIdentifier = fakeBpb.oem_name[0] switch + { + // Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies + // OEM ID should be ASCII, otherwise ignore it + >= 0x20 and <= 0x7F when fakeBpb.oem_name[1] >= 0x20 && + fakeBpb.oem_name[1] <= 0x7F && + fakeBpb.oem_name[2] >= 0x20 && + fakeBpb.oem_name[2] <= 0x7F && + fakeBpb.oem_name[3] >= 0x20 && + fakeBpb.oem_name[3] <= 0x7F && + fakeBpb.oem_name[4] >= 0x20 && + fakeBpb.oem_name[4] <= 0x7F && + fakeBpb.oem_name[5] >= 0x20 && + fakeBpb.oem_name[5] <= 0x7F && + fakeBpb.oem_name[6] >= 0x20 && + fakeBpb.oem_name[6] <= 0x7F && + fakeBpb.oem_name[7] >= 0x20 && + fakeBpb.oem_name[7] <= 0x7F => + StringHandlers.CToString(fakeBpb.oem_name), + < 0x20 when fakeBpb.oem_name[1] >= 0x20 && + fakeBpb.oem_name[1] <= 0x7F && + fakeBpb.oem_name[2] >= 0x20 && + fakeBpb.oem_name[2] <= 0x7F && + fakeBpb.oem_name[3] >= 0x20 && + fakeBpb.oem_name[3] <= 0x7F && + fakeBpb.oem_name[4] >= 0x20 && + fakeBpb.oem_name[4] <= 0x7F && + fakeBpb.oem_name[5] >= 0x20 && + fakeBpb.oem_name[5] <= 0x7F && + fakeBpb.oem_name[6] >= 0x20 && + fakeBpb.oem_name[6] <= 0x7F && + fakeBpb.oem_name[7] >= 0x20 && + fakeBpb.oem_name[7] <= 0x7F => + StringHandlers.CToString(fakeBpb.oem_name, _encoding, start: 1), + _ => Metadata.SystemIdentifier + }; } if(fakeBpb.signature is 0x28 or 0x29) { - XmlFsType.VolumeSerial = $"{fakeBpb.serial_no:X8}"; + Metadata.VolumeSerial = $"{fakeBpb.serial_no:X8}"; _statfs.Id = new FileSystemId { @@ -478,38 +447,39 @@ public sealed partial class FAT } } - XmlFsType.Clusters = clusters; - _sectorsPerCluster = fakeBpb.spc; - XmlFsType.ClusterSize = (uint)(fakeBpb.bps * fakeBpb.spc); - _reservedSectors = fakeBpb.rsectors; - _sectorsPerFat = fakeBpb.spfat; + Metadata.Clusters = clusters; + _sectorsPerCluster = fakeBpb.spc; + Metadata.ClusterSize = (uint)(fakeBpb.bps * fakeBpb.spc); + _reservedSectors = fakeBpb.rsectors; + _sectorsPerFat = fakeBpb.spfat; if(fakeBpb.signature is 0x28 or 0x29 || andosOemCorrect) { if((fakeBpb.flags & 0xF8) == 0x00) if((fakeBpb.flags & 0x01) == 0x01) - XmlFsType.Dirty = true; + Metadata.Dirty = true; if(fakeBpb.signature == 0x29 || andosOemCorrect) { - XmlFsType.VolumeName = StringHandlers.SpacePaddedToString(fakeBpb.volume_label, Encoding); - XmlFsType.VolumeName = XmlFsType.VolumeName?.Replace("\0", ""); + Metadata.VolumeName = StringHandlers.SpacePaddedToString(fakeBpb.volume_label, _encoding); + Metadata.VolumeName = Metadata.VolumeName?.Replace("\0", ""); } } // Workaround that PCExchange jumps into "FAT16 "... - if(XmlFsType.SystemIdentifier == "PCX 2.0 ") - fakeBpb.jump[1] += 8; + if(Metadata.SystemIdentifier == "PCX 2.0 ") fakeBpb.jump[1] += 8; // Check that jumps to a correct boot code position and has boot signature set. // This will mean that the volume will boot, even if just to say "this is not bootable change disk"...... - if(XmlFsType.Bootable == false && - fakeBpb.jump != null) - XmlFsType.Bootable |= + if(Metadata.Bootable == false && fakeBpb.jump != null) + { + Metadata.Bootable |= fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] >= minBootNearJump && fakeBpb.jump[1] < 0x80 || - fakeBpb.jump[0] == 0xE9 && fakeBpb.jump.Length >= 3 && + fakeBpb.jump[0] == 0xE9 && + fakeBpb.jump.Length >= 3 && BitConverter.ToUInt16(fakeBpb.jump, 1) >= minBootNearJump && BitConverter.ToUInt16(fakeBpb.jump, 1) <= 0x1FC; + } // First root directory sector firstRootSector = (ulong)(fakeBpb.spfat * fakeBpb.fats_no + fakeBpb.rsectors) * sectorsPerRealSector + @@ -542,8 +512,7 @@ public sealed partial class FAT _firstClusterSector = firstRootSector + sectorsForRootDirectory - _sectorsPerCluster * 2; errno = imagePlugin.ReadSectors(firstRootSector, sectorsForRootDirectory, out rootDirectory); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; if(bpbKind == BpbKind.DecRainbow) { @@ -556,8 +525,7 @@ public sealed partial class FAT { errno = imagePlugin.ReadSector(rootSector, out byte[] tmp); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; rootMs.Write(tmp, 0, tmp.Length); } @@ -567,19 +535,18 @@ public sealed partial class FAT } else { - if(rootDirectoryCluster == 0) - return ErrorNumber.InvalidArgument; + if(rootDirectoryCluster == 0) return ErrorNumber.InvalidArgument; var rootMs = new MemoryStream(); uint[] rootDirectoryClusters = GetClusters(rootDirectoryCluster); foreach(uint cluster in rootDirectoryClusters) { - errno = imagePlugin.ReadSectors(_firstClusterSector + cluster * _sectorsPerCluster, _sectorsPerCluster, + errno = imagePlugin.ReadSectors(_firstClusterSector + cluster * _sectorsPerCluster, + _sectorsPerCluster, out byte[] buffer); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; rootMs.Write(buffer, 0, buffer.Length); } @@ -587,12 +554,10 @@ public sealed partial class FAT rootDirectory = rootMs.ToArray(); // OS/2 FAT32.IFS uses LFN instead of .LONGNAME - if(_namespace == Namespace.Os2) - _namespace = Namespace.Lfn; + if(_namespace == Namespace.Os2) _namespace = Namespace.Lfn; } - if(rootDirectory is null) - return ErrorNumber.InvalidArgument; + if(rootDirectory is null) return ErrorNumber.InvalidArgument; byte[] lastLfnName = null; byte lastLfnChecksum = 0; @@ -600,25 +565,22 @@ public sealed partial class FAT for(var i = 0; i < rootDirectory.Length; i += Marshal.SizeOf()) { DirectoryEntry entry = - Marshal.ByteArrayToStructureLittleEndian(rootDirectory, i, + Marshal.ByteArrayToStructureLittleEndian(rootDirectory, + i, Marshal.SizeOf()); - if(entry.filename[0] == DIRENT_FINISHED) - break; + if(entry.filename[0] == DIRENT_FINISHED) break; if(entry.attributes.HasFlag(FatAttributes.LFN)) { - if(_namespace != Namespace.Lfn && - _namespace != Namespace.Ecs) - continue; + if(_namespace != Namespace.Lfn && _namespace != Namespace.Ecs) continue; LfnEntry lfnEntry = Marshal.ByteArrayToStructureLittleEndian(rootDirectory, i, Marshal.SizeOf()); int lfnSequence = lfnEntry.sequence & LFN_MASK; - if((lfnEntry.sequence & LFN_ERASED) > 0) - continue; + if((lfnEntry.sequence & LFN_ERASED) > 0) continue; if((lfnEntry.sequence & LFN_LAST) > 0) { @@ -626,15 +588,13 @@ public sealed partial class FAT lastLfnChecksum = lfnEntry.checksum; } - if(lastLfnName is null) - continue; + if(lastLfnName is null) continue; - if(lfnEntry.checksum != lastLfnChecksum) - continue; + if(lfnEntry.checksum != lastLfnChecksum) continue; lfnSequence--; - Array.Copy(lfnEntry.name1, 0, lastLfnName, lfnSequence * 26, 10); + Array.Copy(lfnEntry.name1, 0, lastLfnName, lfnSequence * 26, 10); Array.Copy(lfnEntry.name2, 0, lastLfnName, lfnSequence * 26 + 10, 12); Array.Copy(lfnEntry.name3, 0, lastLfnName, lfnSequence * 26 + 22, 4); @@ -642,54 +602,45 @@ public sealed partial class FAT } // Not a correct entry - if(entry.filename[0] < DIRENT_MIN && - entry.filename[0] != DIRENT_E5) - continue; + if(entry.filename[0] < DIRENT_MIN && entry.filename[0] != DIRENT_E5) continue; // Self - if(Encoding.GetString(entry.filename).TrimEnd() == ".") - continue; + if(_encoding.GetString(entry.filename).TrimEnd() == ".") continue; // Parent - if(Encoding.GetString(entry.filename).TrimEnd() == "..") - continue; + if(_encoding.GetString(entry.filename).TrimEnd() == "..") continue; // Deleted - if(entry.filename[0] == DIRENT_DELETED) - continue; + if(entry.filename[0] == DIRENT_DELETED) continue; string filename; if(entry.attributes.HasFlag(FatAttributes.VolumeLabel)) { var fullname = new byte[11]; - Array.Copy(entry.filename, 0, fullname, 0, 8); + Array.Copy(entry.filename, 0, fullname, 0, 8); Array.Copy(entry.extension, 0, fullname, 8, 3); - string volname = Encoding.GetString(fullname).Trim(); + string volname = _encoding.GetString(fullname).Trim(); if(!string.IsNullOrEmpty(volname)) - XmlFsType.VolumeName = entry.caseinfo.HasFlag(CaseInfo.AllLowerCase) && _namespace == Namespace.Nt - ? volname.ToLower() : volname; - - XmlFsType.VolumeName = XmlFsType.VolumeName?.Replace("\0", ""); - - if(entry.ctime > 0 && - entry.cdate > 0) { - XmlFsType.CreationDate = DateHandlers.DosToDateTime(entry.cdate, entry.ctime); + Metadata.VolumeName = entry.caseinfo.HasFlag(CaseInfo.AllLowerCase) && _namespace == Namespace.Nt + ? volname.ToLower() + : volname; + } + + Metadata.VolumeName = Metadata.VolumeName?.Replace("\0", ""); + + if(entry is { ctime: > 0, cdate: > 0 }) + { + Metadata.CreationDate = DateHandlers.DosToDateTime(entry.cdate, entry.ctime); if(entry.ctime_ms > 0) - XmlFsType.CreationDate = XmlFsType.CreationDate.AddMilliseconds(entry.ctime_ms * 10); - - XmlFsType.CreationDateSpecified = true; + Metadata.CreationDate = Metadata.CreationDate?.AddMilliseconds(entry.ctime_ms * 10); } - if(entry.mtime > 0 && - entry.mdate > 0) - { - XmlFsType.ModificationDate = DateHandlers.DosToDateTime(entry.mdate, entry.mtime); - XmlFsType.ModificationDateSpecified = true; - } + if(entry is { mtime: > 0, mdate: > 0 }) + Metadata.ModificationDate = DateHandlers.DosToDateTime(entry.mdate, entry.mtime); continue; } @@ -699,8 +650,7 @@ public sealed partial class FAT Dirent = entry }; - if(_namespace is Namespace.Lfn or Namespace.Ecs && - lastLfnName != null) + if(_namespace is Namespace.Lfn or Namespace.Ecs && lastLfnName != null) { byte calculatedLfnChecksum = LfnChecksum(entry.filename, entry.extension); @@ -714,19 +664,17 @@ public sealed partial class FAT } } - if(entry.filename[0] == DIRENT_E5) - entry.filename[0] = DIRENT_DELETED; + if(entry.filename[0] == DIRENT_E5) entry.filename[0] = DIRENT_DELETED; - string name = Encoding.GetString(entry.filename).TrimEnd(); - string extension = Encoding.GetString(entry.extension).TrimEnd(); + string name = _encoding.GetString(entry.filename).TrimEnd(); + string extension = _encoding.GetString(entry.extension).TrimEnd(); if(_namespace == Namespace.Nt) { if(entry.caseinfo.HasFlag(CaseInfo.LowerCaseExtension)) extension = extension.ToLower(CultureInfo.CurrentCulture); - if(entry.caseinfo.HasFlag(CaseInfo.LowerCaseBasename)) - name = name.ToLower(CultureInfo.CurrentCulture); + if(entry.caseinfo.HasFlag(CaseInfo.LowerCaseBasename)) name = name.ToLower(CultureInfo.CurrentCulture); } if(extension != "") @@ -734,14 +682,11 @@ public sealed partial class FAT else filename = name; - if(name == "" && - extension == "") + if(name == "" && extension == "") { - AaruConsole.DebugWriteLine("FAT filesystem", "Found empty filename in root directory"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Found_empty_filename_in_root_directory); - if(!_debug || - entry.size > 0 && entry.start_cluster == 0) - continue; // Skip invalid name + if(!_debug || entry is { size: > 0, start_cluster: 0 }) continue; // Skip invalid name // If debug, add it name = ":{EMPTYNAME}:"; @@ -751,13 +696,11 @@ public sealed partial class FAT { extension = $"{uniq:D03}"; - if(!_rootDirectoryCache.ContainsKey($"{name}.{extension}")) - break; + if(!_rootDirectoryCache.ContainsKey($"{name}.{extension}")) break; } // If we couldn't find it, just skip over - if(_rootDirectoryCache.ContainsKey($"{name}.{extension}")) - continue; + if(_rootDirectoryCache.ContainsKey($"{name}.{extension}")) continue; } // Atari ST allows slash AND colon so cannot simply substitute one for the other like in Mac filesystems @@ -768,14 +711,15 @@ public sealed partial class FAT if(_namespace == Namespace.Human) { HumanDirectoryEntry humanEntry = - Marshal.ByteArrayToStructureLittleEndian(rootDirectory, i, + Marshal.ByteArrayToStructureLittleEndian(rootDirectory, + i, Marshal.SizeOf()); completeEntry.HumanDirent = humanEntry; - name = StringHandlers.CToString(humanEntry.name1, Encoding).TrimEnd(); - extension = StringHandlers.CToString(humanEntry.extension, Encoding).TrimEnd(); - string name2 = StringHandlers.CToString(humanEntry.name2, Encoding).TrimEnd(); + name = StringHandlers.CToString(humanEntry.name1, _encoding).TrimEnd(); + extension = StringHandlers.CToString(humanEntry.extension, _encoding).TrimEnd(); + string name2 = StringHandlers.CToString(humanEntry.name2, _encoding).TrimEnd(); if(extension != "") filename = name + name2 + "." + extension; @@ -785,15 +729,13 @@ public sealed partial class FAT completeEntry.HumanName = filename; } - if(!_fat32 && - filename == "EA DATA. SF") + if(!_fat32 && filename == "EA DATA. SF") { _eaDirEntry = entry; lastLfnName = null; lastLfnChecksum = 0; - if(_debug) - _rootDirectoryCache[completeEntry.ToString()] = completeEntry; + if(_debug) _rootDirectoryCache[completeEntry.ToString()] = completeEntry; continue; } @@ -803,71 +745,32 @@ public sealed partial class FAT lastLfnChecksum = 0; } - XmlFsType.VolumeName = XmlFsType.VolumeName?.Trim(); - _statfs.Blocks = XmlFsType.Clusters; + Metadata.VolumeName = Metadata.VolumeName?.Trim(); + _statfs.Blocks = Metadata.Clusters; - switch(bpbKind) - { - case BpbKind.Hardcoded: - _statfs.Type = $"Microsoft FAT{(_fat16 ? "16" : "12")}"; - - break; - case BpbKind.Atari: - _statfs.Type = $"Atari FAT{(_fat16 ? "16" : "12")}"; - - break; - case BpbKind.Msx: - _statfs.Type = $"MSX FAT{(_fat16 ? "16" : "12")}"; - - break; - case BpbKind.Dos2: - case BpbKind.Dos3: - case BpbKind.Dos32: - case BpbKind.Dos33: - case BpbKind.ShortExtended: - case BpbKind.Extended: - _statfs.Type = $"Microsoft FAT{(_fat16 ? "16" : "12")}"; - - break; - case BpbKind.ShortFat32: - case BpbKind.LongFat32: - _statfs.Type = XmlFsType.Type == "FAT+" ? "FAT+" : "Microsoft FAT32"; - - break; - case BpbKind.Andos: - _statfs.Type = $"ANDOS FAT{(_fat16 ? "16" : "12")}"; - - break; - case BpbKind.Apricot: - _statfs.Type = $"Apricot FAT{(_fat16 ? "16" : "12")}"; - - break; - case BpbKind.DecRainbow: - _statfs.Type = $"DEC FAT{(_fat16 ? "16" : "12")}"; - - break; - case BpbKind.Human: - _statfs.Type = $"Human68k FAT{(_fat16 ? "16" : "12")}"; - - break; - default: throw new ArgumentOutOfRangeException(); - } + _statfs.Type = bpbKind switch + { + BpbKind.ShortFat32 or BpbKind.LongFat32 => Metadata.Type == FS_TYPE_FAT_PLUS + ? FS_TYPE_FAT_PLUS + : FS_TYPE_FAT32, + _ => _fat16 ? FS_TYPE_FAT16 : FS_TYPE_FAT12 + }; _bytesPerCluster = _sectorsPerCluster * imagePlugin.Info.SectorSize; - var firstFatEntries = new ushort[_statfs.Blocks]; - var secondFatEntries = new ushort[_statfs.Blocks]; + // The first 2 FAT entries do not count as allocation clusters in FAT12 and FAT16 + var firstFatEntries = new ushort[_statfs.Blocks + 2]; + var secondFatEntries = new ushort[_statfs.Blocks + 2]; var firstFatValid = true; var secondFatValid = true; if(_fat12) { - AaruConsole.DebugWriteLine("FAT plugin", "Reading FAT12"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_FAT12); errno = imagePlugin.ReadSectors(_fatFirstSector, _sectorsPerFat, out byte[] fatBytes); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; var pos = 0; @@ -875,18 +778,16 @@ public sealed partial class FAT { firstFatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]); - if(pos >= firstFatEntries.Length) - break; + if(pos >= firstFatEntries.Length) break; firstFatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4)); } errno = imagePlugin.ReadSectors(_fatFirstSector + _sectorsPerFat, _sectorsPerFat, out fatBytes); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - _fatEntries = new ushort[_statfs.Blocks]; + _fatEntries = new ushort[_statfs.Blocks + 2]; pos = 0; @@ -894,34 +795,17 @@ public sealed partial class FAT { secondFatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]); - if(pos >= secondFatEntries.Length) - break; + if(pos >= secondFatEntries.Length) break; secondFatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4)); } - foreach(ushort entry in firstFatEntries) - { - if(entry >= FAT12_RESERVED || - entry <= _statfs.Blocks) - continue; - + if(firstFatEntries.Any(entry => entry < FAT12_RESERVED && entry > _statfs.Blocks + 2)) firstFatValid = false; - break; - } - - foreach(ushort entry in secondFatEntries) - { - if(entry >= FAT12_RESERVED || - entry <= _statfs.Blocks) - continue; - + if(secondFatEntries.Any(entry => entry < FAT12_RESERVED && entry > _statfs.Blocks + 2)) secondFatValid = false; - break; - } - if(firstFatValid == secondFatValid) _fatEntries = _useFirstFat ? firstFatEntries : secondFatEntries; else if(firstFatValid) @@ -931,46 +815,28 @@ public sealed partial class FAT } else if(_fat16) { - AaruConsole.DebugWriteLine("FAT plugin", "Reading FAT16"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_FAT16); errno = imagePlugin.ReadSectors(_fatFirstSector, _sectorsPerFat, out byte[] fatBytes); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - AaruConsole.DebugWriteLine("FAT plugin", "Casting FAT"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Casting_FAT); firstFatEntries = MemoryMarshal.Cast(fatBytes).ToArray(); errno = imagePlugin.ReadSectors(_fatFirstSector + _sectorsPerFat, _sectorsPerFat, out fatBytes); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - AaruConsole.DebugWriteLine("FAT plugin", "Casting FAT"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Casting_FAT); secondFatEntries = MemoryMarshal.Cast(fatBytes).ToArray(); - foreach(ushort entry in firstFatEntries) - { - if(entry >= FAT16_RESERVED || - entry <= _statfs.Blocks) - continue; - + if(firstFatEntries.Any(entry => entry < FAT16_RESERVED && entry > _statfs.Blocks + 2)) firstFatValid = false; - break; - } - - foreach(ushort entry in secondFatEntries) - { - if(entry >= FAT16_RESERVED || - entry <= _statfs.Blocks) - continue; - + if(secondFatEntries.Any(entry => entry < FAT16_RESERVED && entry > _statfs.Blocks + 2)) secondFatValid = false; - break; - } - if(firstFatValid == secondFatValid) _fatEntries = _useFirstFat ? firstFatEntries : secondFatEntries; else if(firstFatValid) @@ -997,13 +863,10 @@ public sealed partial class FAT else _eaCache = new Dictionary>(); } - else if(_fat32) - _eaCache = new Dictionary>(); + else if(_fat32) _eaCache = new Dictionary>(); // Check OS/2 .LONGNAME - if(_eaCache != null && - _namespace is Namespace.Os2 or Namespace.Ecs && - !_fat32) + if(_eaCache != null && _namespace is Namespace.Os2 or Namespace.Ecs && !_fat32) { var rootFilesWithEas = _rootDirectoryCache.Where(t => t.Value.Dirent.ea_handle != 0).ToList(); @@ -1011,28 +874,23 @@ public sealed partial class FAT { Dictionary eas = GetEas(fileWithEa.Value.Dirent.ea_handle); - if(eas is null) - continue; + if(eas is null) continue; - if(!eas.TryGetValue("com.microsoft.os2.longname", out byte[] longnameEa)) - continue; + if(!eas.TryGetValue("com.microsoft.os2.longname", out byte[] longnameEa)) continue; - if(BitConverter.ToUInt16(longnameEa, 0) != EAT_ASCII) - continue; + if(BitConverter.ToUInt16(longnameEa, 0) != EAT_ASCII) continue; var longnameSize = BitConverter.ToUInt16(longnameEa, 2); - if(longnameSize + 4 > longnameEa.Length) - continue; + if(longnameSize + 4 > longnameEa.Length) continue; var longnameBytes = new byte[longnameSize]; Array.Copy(longnameEa, 4, longnameBytes, 0, longnameSize); - string longname = StringHandlers.CToString(longnameBytes, Encoding); + string longname = StringHandlers.CToString(longnameBytes, _encoding); - if(string.IsNullOrWhiteSpace(longname)) - continue; + if(string.IsNullOrWhiteSpace(longname)) continue; // Forward slash is allowed in .LONGNAME, so change it to visually similar division slash longname = longname.Replace('/', '\u2215'); @@ -1046,35 +904,35 @@ public sealed partial class FAT // Check FAT32.IFS EAs if(_fat32 || _debug) { - var fat32EaSidecars = _rootDirectoryCache.Where(t => t.Key.EndsWith(FAT32_EA_TAIL, true, _cultureInfo)). - ToList(); + var fat32EaSidecars = _rootDirectoryCache.Where(t => t.Key.EndsWith(FAT32_EA_TAIL, true, _cultureInfo)) + .ToList(); foreach(KeyValuePair sidecar in fat32EaSidecars) { // No real file this sidecar accompanies - if(!_rootDirectoryCache.TryGetValue(sidecar.Key.Substring(0, sidecar.Key.Length - FAT32_EA_TAIL.Length), + if(!_rootDirectoryCache.TryGetValue(sidecar.Key[..^FAT32_EA_TAIL.Length], out CompleteDirectoryEntry fileWithEa)) continue; // If not in debug mode we will consider the lack of EA bitflags to mean the EAs are corrupted or not real if(!_debug) + { if(!fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.NormalEaOld) && !fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.CriticalEa) && !fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.NormalEa) && !fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.CriticalEa)) continue; + } fileWithEa.Fat32Ea = sidecar.Value.Dirent; - if(!_debug) - _rootDirectoryCache.Remove(sidecar.Key); + if(!_debug) _rootDirectoryCache.Remove(sidecar.Key); } } _mounted = true; - if(string.IsNullOrWhiteSpace(XmlFsType.VolumeName)) - XmlFsType.VolumeName = null; + if(string.IsNullOrWhiteSpace(Metadata.VolumeName)) Metadata.VolumeName = null; return ErrorNumber.NoError; } @@ -1082,8 +940,7 @@ public sealed partial class FAT /// public ErrorNumber Unmount() { - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; _mounted = false; _fatEntries = null; @@ -1096,11 +953,12 @@ public sealed partial class FAT { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; stat = _statfs.ShallowCopy(); return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/FAT/Xattr.cs b/Aaru.Filesystems/FAT/Xattr.cs index 27b64825b..dbd41c9a3 100644 --- a/Aaru.Filesystems/FAT/Xattr.cs +++ b/Aaru.Filesystems/FAT/Xattr.cs @@ -7,10 +7,6 @@ // // Component : Microsoft FAT filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle Microsoft FAT extended attributes. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,11 +23,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.IO; @@ -40,25 +34,25 @@ using System.Text; using Aaru.CommonTypes.Enums; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class FAT { Dictionary> _eaCache; +#region IReadOnlyFilesystem Members + /// public ErrorNumber ListXAttr(string path, out List xattrs) { xattrs = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; // No other xattr recognized yet - if(_cachedEaData is null && - !_fat32) - return ErrorNumber.NotSupported; + if(_cachedEaData is null && !_fat32) return ErrorNumber.NotSupported; - if(path[0] == '/') - path = path.Substring(1); + if(path[0] == '/') path = path[1..]; if(_eaCache.TryGetValue(path.ToLower(_cultureInfo), out Dictionary eas)) { @@ -69,29 +63,24 @@ public sealed partial class FAT ErrorNumber err = GetFileEntry(path, out CompleteDirectoryEntry entry); - if(err != ErrorNumber.NoError || - entry is null) - return err; + if(err != ErrorNumber.NoError || entry is null) return err; - xattrs = new List(); + xattrs = []; if(!_fat32) { - if(entry.Dirent.ea_handle == 0) - return ErrorNumber.NoError; + if(entry.Dirent.ea_handle == 0) return ErrorNumber.NoError; eas = GetEas(entry.Dirent.ea_handle); } else { - if(entry.Fat32Ea.start_cluster == 0) - return ErrorNumber.NoError; + if(entry.Fat32Ea.start_cluster == 0) return ErrorNumber.NoError; eas = GetEas(entry.Fat32Ea); } - if(eas is null) - return ErrorNumber.NoError; + if(eas is null) return ErrorNumber.NoError; _eaCache.Add(path.ToLower(_cultureInfo), eas); xattrs = eas.Keys.ToList(); @@ -102,25 +91,20 @@ public sealed partial class FAT /// public ErrorNumber GetXattr(string path, string xattr, ref byte[] buf) { - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = ListXAttr(path, out List xattrs); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; - if(path[0] == '/') - path = path.Substring(1); + if(path[0] == '/') path = path[1..]; - if(!xattrs.Contains(xattr.ToLower(_cultureInfo))) - return ErrorNumber.NoSuchExtendedAttribute; + if(!xattrs.Contains(xattr.ToLower(_cultureInfo))) return ErrorNumber.NoSuchExtendedAttribute; if(!_eaCache.TryGetValue(path.ToLower(_cultureInfo), out Dictionary eas)) return ErrorNumber.InvalidArgument; - if(!eas.TryGetValue(xattr.ToLower(_cultureInfo), out byte[] data)) - return ErrorNumber.InvalidArgument; + if(!eas.TryGetValue(xattr.ToLower(_cultureInfo), out byte[] data)) return ErrorNumber.InvalidArgument; buf = new byte[data.Length]; data.CopyTo(buf, 0); @@ -128,6 +112,8 @@ public sealed partial class FAT return ErrorNumber.NoError; } +#endregion + Dictionary GetEas(DirectoryEntry entryFat32Ea) { var eaMs = new MemoryStream(); @@ -136,10 +122,10 @@ public sealed partial class FAT foreach(uint cluster in rootDirectoryClusters) { ErrorNumber errno = _image.ReadSectors(_firstClusterSector + cluster * _sectorsPerCluster, - _sectorsPerCluster, out byte[] buffer); + _sectorsPerCluster, + out byte[] buffer); - if(errno != ErrorNumber.NoError) - return null; + if(errno != ErrorNumber.NoError) return null; eaMs.Write(buffer, 0, buffer.Length); } @@ -165,15 +151,14 @@ public sealed partial class FAT var eaCluster = (uint)(a + b); - if(b == EA_UNUSED) - return null; + if(b == EA_UNUSED) return null; EaHeader header = - Marshal.ByteArrayToStructureLittleEndian(_cachedEaData, (int)(eaCluster * _bytesPerCluster), + Marshal.ByteArrayToStructureLittleEndian(_cachedEaData, + (int)(eaCluster * _bytesPerCluster), Marshal.SizeOf()); - if(header.magic != 0x4145) - return null; + if(header.magic != 0x4145) return null; var eaLen = BitConverter.ToUInt32(_cachedEaData, (int)(eaCluster * _bytesPerCluster) + Marshal.SizeOf()); @@ -187,14 +172,11 @@ public sealed partial class FAT Dictionary GetEas(byte[] eaData) { - if(eaData is null || - eaData.Length < 4) - return null; + if(eaData is null || eaData.Length < 4) return null; Dictionary eas = new(); - if(_debug) - eas.Add("com.microsoft.os2.fea", eaData); + if(_debug) eas.Add("com.microsoft.os2.fea", eaData); var pos = 4; @@ -231,18 +213,17 @@ public sealed partial class FAT void CacheEaData() { - if(_eaDirEntry.start_cluster == 0) - return; + if(_eaDirEntry.start_cluster == 0) return; var eaDataMs = new MemoryStream(); foreach(uint cluster in GetClusters(_eaDirEntry.start_cluster)) { ErrorNumber errno = _image.ReadSectors(_firstClusterSector + cluster * _sectorsPerCluster, - _sectorsPerCluster, out byte[] buffer); + _sectorsPerCluster, + out byte[] buffer); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; eaDataMs.Write(buffer, 0, buffer.Length); } diff --git a/Aaru.Filesystems/FATX/Consts.cs b/Aaru.Filesystems/FATX/Consts.cs index f06c01e0a..7a0cae130 100644 --- a/Aaru.Filesystems/FATX/Consts.cs +++ b/Aaru.Filesystems/FATX/Consts.cs @@ -7,10 +7,6 @@ // // Component : FATX filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// FATX filesystem constants. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,17 +23,15 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable UnusedMember.Local -namespace Aaru.Filesystems; - using System; +namespace Aaru.Filesystems; + public sealed partial class XboxFatPlugin { const uint FATX_MAGIC = 0x58544146; @@ -61,6 +55,11 @@ public sealed partial class XboxFatPlugin const ushort FAT16_RESERVED = 0xFFF0; const ushort FAT_RESERVED = 1; + // Do not translate + const string FS_TYPE = "fatx"; + +#region Nested type: Attributes + [Flags] enum Attributes : byte { @@ -70,4 +69,6 @@ public sealed partial class XboxFatPlugin Directory = 0x10, Archive = 0x20 } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/FATX/Dir.cs b/Aaru.Filesystems/FATX/Dir.cs index bbeefe6ef..bbe7a95a6 100644 --- a/Aaru.Filesystems/FATX/Dir.cs +++ b/Aaru.Filesystems/FATX/Dir.cs @@ -7,10 +7,6 @@ // // Component : FATX filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to show the FATX directories. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,57 +23,67 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class XboxFatPlugin { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber ReadDir(string path, out List contents) + public ErrorNumber OpenDir(string path, out IDirNode node) { - contents = null; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - if(string.IsNullOrWhiteSpace(path) || - path == "/") + if(string.IsNullOrWhiteSpace(path) || path == "/") { - contents = _rootDirectory.Keys.ToList(); + node = new FatxDirNode + { + Path = path, + Position = 0, + Entries = _rootDirectory.Values.ToArray() + }; return ErrorNumber.NoError; } - string cutPath = path.StartsWith('/') ? path.Substring(1).ToLower(_cultureInfo) : path.ToLower(_cultureInfo); + string cutPath = path.StartsWith('/') ? path[1..].ToLower(_cultureInfo) : path.ToLower(_cultureInfo); if(_directoryCache.TryGetValue(cutPath, out Dictionary currentDirectory)) { - contents = currentDirectory.Keys.ToList(); + node = new FatxDirNode + { + Path = path, + Position = 0, + Entries = currentDirectory.Values.ToArray() + }; return ErrorNumber.NoError; } string[] pieces = cutPath.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); KeyValuePair entry = _rootDirectory.FirstOrDefault(t => t.Key.ToLower(_cultureInfo) == pieces[0]); - if(string.IsNullOrEmpty(entry.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(entry.Key)) return ErrorNumber.NoSuchFile; - if(!entry.Value.attributes.HasFlag(Attributes.Directory)) - return ErrorNumber.NotDirectory; + if(!entry.Value.attributes.HasFlag(Attributes.Directory)) return ErrorNumber.NotDirectory; string currentPath = pieces[0]; @@ -87,22 +93,18 @@ public sealed partial class XboxFatPlugin { entry = currentDirectory.FirstOrDefault(t => t.Key.ToLower(_cultureInfo) == pieces[p]); - if(string.IsNullOrEmpty(entry.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(entry.Key)) return ErrorNumber.NoSuchFile; - if(!entry.Value.attributes.HasFlag(Attributes.Directory)) - return ErrorNumber.NotDirectory; + if(!entry.Value.attributes.HasFlag(Attributes.Directory)) return ErrorNumber.NotDirectory; currentPath = p == 0 ? pieces[0] : $"{currentPath}/{pieces[p]}"; uint currentCluster = entry.Value.firstCluster; - if(_directoryCache.TryGetValue(currentPath, out currentDirectory)) - continue; + if(_directoryCache.TryGetValue(currentPath, out currentDirectory)) continue; uint[] clusters = GetClusters(currentCluster); - if(clusters is null) - return ErrorNumber.InvalidArgument; + if(clusters is null) return ErrorNumber.InvalidArgument; var directoryBuffer = new byte[_bytesPerCluster * clusters.Length]; @@ -110,10 +112,10 @@ public sealed partial class XboxFatPlugin { ErrorNumber errno = _imagePlugin.ReadSectors(_firstClusterSector + (clusters[i] - 1) * _sectorsPerCluster, - _sectorsPerCluster, out byte[] buffer); + _sectorsPerCluster, + out byte[] buffer); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; Array.Copy(buffer, 0, directoryBuffer, i * _bytesPerCluster, _bytesPerCluster); } @@ -126,19 +128,19 @@ public sealed partial class XboxFatPlugin { DirectoryEntry dirent = _littleEndian ? Marshal.ByteArrayToStructureLittleEndian(directoryBuffer, - pos, Marshal.SizeOf()) + pos, + Marshal.SizeOf()) : Marshal.ByteArrayToStructureBigEndian(directoryBuffer, - pos, Marshal.SizeOf()); + pos, + Marshal.SizeOf()); pos += Marshal.SizeOf(); - if(dirent.filenameSize is UNUSED_DIRENTRY or FINISHED_DIRENTRY) - break; + if(dirent.filenameSize is UNUSED_DIRENTRY or FINISHED_DIRENTRY) break; - if(dirent.filenameSize is DELETED_DIRENTRY or > MAX_FILENAME) - continue; + if(dirent.filenameSize is DELETED_DIRENTRY or > MAX_FILENAME) continue; - string filename = Encoding.GetString(dirent.filename, 0, dirent.filenameSize); + string filename = _encoding.GetString(dirent.filename, 0, dirent.filenameSize); currentDirectory.Add(filename, dirent); } @@ -146,8 +148,50 @@ public sealed partial class XboxFatPlugin _directoryCache.Add(currentPath, currentDirectory); } - contents = currentDirectory?.Keys.ToList(); + if(currentDirectory is null) return ErrorNumber.NoSuchFile; + + node = new FatxDirNode + { + Path = path, + Position = 0, + Entries = currentDirectory.Values.ToArray() + }; return ErrorNumber.NoError; } + + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) + { + filename = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not FatxDirNode mynode) return ErrorNumber.InvalidArgument; + + if(mynode.Position < 0) return ErrorNumber.InvalidArgument; + + if(mynode.Position >= mynode.Entries.Length) return ErrorNumber.NoError; + + filename = _encoding.GetString(mynode.Entries[mynode.Position].filename, + 0, + mynode.Entries[mynode.Position].filenameSize); + + mynode.Position++; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not FatxDirNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Position = -1; + mynode.Entries = null; + + return ErrorNumber.NoError; + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/FATX/FATX.cs b/Aaru.Filesystems/FATX/FATX.cs index b92853322..dcfc361f5 100644 --- a/Aaru.Filesystems/FATX/FATX.cs +++ b/Aaru.Filesystems/FATX/FATX.cs @@ -7,10 +7,6 @@ // // Component : FATX filesystem plugin // -// --[ Description ] ---------------------------------------------------------- -// -// Constructors and common variables for the FATX filesystem plugin. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,28 +23,30 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Globalization; using System.Text; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; -using Schemas; + +namespace Aaru.Filesystems; /// /// Implements the Xbox File Allocation Table (FATX or XTAF) filesystem. public sealed partial class XboxFatPlugin : IReadOnlyFilesystem { + const string MODULE_NAME = "Xbox FAT plugin"; uint _bytesPerCluster; CultureInfo _cultureInfo; bool _debug; Dictionary> _directoryCache; + Encoding _encoding; ushort[] _fat16; uint[] _fat32; ulong _fatStartSector; @@ -61,16 +59,19 @@ public sealed partial class XboxFatPlugin : IReadOnlyFilesystem FileSystemInfo _statfs; Superblock _superblock; +#region IReadOnlyFilesystem Members + /// - public FileSystemType XmlFsType { get; private set; } + public FileSystem Metadata { get; private set; } + /// - public Encoding Encoding { get; private set; } - /// - public string Name => "FATX Filesystem Plugin"; + public string Name => Localization.XboxFatPlugin_Name; + /// public Guid Id => new("ED27A721-4A17-4649-89FD-33633B46E228"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public ErrorNumber ListXAttr(string path, out List xattrs) @@ -98,6 +99,8 @@ public sealed partial class XboxFatPlugin : IReadOnlyFilesystem /// public Dictionary Namespaces => null; +#endregion + static Dictionary GetDefaultOptions() => new() { { diff --git a/Aaru.Filesystems/FATX/File.cs b/Aaru.Filesystems/FATX/File.cs index b8e29ded3..2220d39a3 100644 --- a/Aaru.Filesystems/FATX/File.cs +++ b/Aaru.Filesystems/FATX/File.cs @@ -7,10 +7,6 @@ // // Component : FATX filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle files. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,61 +23,35 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.IO; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Helpers; using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes; +namespace Aaru.Filesystems; + public sealed partial class XboxFatPlugin { - /// - public ErrorNumber MapBlock(string path, long fileBlock, out long deviceBlock) - { - deviceBlock = 0; - - if(!_mounted) - return ErrorNumber.AccessDenied; - - ErrorNumber err = Stat(path, out FileEntryInfo stat); - - if(err != ErrorNumber.NoError) - return err; - - if(stat.Attributes.HasFlag(FileAttributes.Directory) && - !_debug) - return ErrorNumber.IsDirectory; - - uint[] clusters = GetClusters((uint)stat.Inode); - - if(fileBlock >= clusters.Length) - return ErrorNumber.InvalidArgument; - - deviceBlock = (long)(_firstClusterSector + (clusters[fileBlock] - 1) * _sectorsPerCluster); - - return ErrorNumber.NoError; - } +#region IReadOnlyFilesystem Members /// public ErrorNumber GetAttributes(string path, out FileAttributes attributes) { attributes = new FileAttributes(); - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = Stat(path, out FileEntryInfo stat); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; attributes = stat.Attributes; @@ -89,55 +59,84 @@ public sealed partial class XboxFatPlugin } /// - public ErrorNumber Read(string path, long offset, long size, ref byte[] buf) + public ErrorNumber OpenFile(string path, out IFileNode node) { - if(!_mounted) - return ErrorNumber.AccessDenied; + node = null; + + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = Stat(path, out FileEntryInfo stat); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; - if(stat.Attributes.HasFlag(FileAttributes.Directory) && - !_debug) - return ErrorNumber.IsDirectory; - - if(offset >= stat.Length) - return ErrorNumber.InvalidArgument; - - if(size + offset >= stat.Length) - size = stat.Length - offset; + if(stat.Attributes.HasFlag(FileAttributes.Directory) && !_debug) return ErrorNumber.IsDirectory; uint[] clusters = GetClusters((uint)stat.Inode); - long firstCluster = offset / _bytesPerCluster; - long offsetInCluster = offset % _bytesPerCluster; - long sizeInClusters = (size + offsetInCluster) / _bytesPerCluster; + node = new FatxFileNode + { + Path = path, + Length = stat.Length, + Offset = 0, + Clusters = clusters + }; - if((size + offsetInCluster) % _bytesPerCluster > 0) - sizeInClusters++; + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseFile(IFileNode node) + { + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not FatxFileNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Clusters = null; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(buffer is null || buffer.Length < length) return ErrorNumber.InvalidArgument; + + if(node is not FatxFileNode mynode) return ErrorNumber.InvalidArgument; + + read = length; + + if(length + mynode.Offset >= mynode.Length) read = mynode.Length - mynode.Offset; + + long firstCluster = mynode.Offset / _bytesPerCluster; + long offsetInCluster = mynode.Offset % _bytesPerCluster; + long sizeInClusters = (read + offsetInCluster) / _bytesPerCluster; + + if((read + offsetInCluster) % _bytesPerCluster > 0) sizeInClusters++; var ms = new MemoryStream(); for(var i = 0; i < sizeInClusters; i++) { - if(i + firstCluster >= clusters.Length) - return ErrorNumber.InvalidArgument; + if(i + firstCluster >= mynode.Clusters.Length) return ErrorNumber.InvalidArgument; ErrorNumber errno = - _imagePlugin.ReadSectors(_firstClusterSector + (clusters[i + firstCluster] - 1) * _sectorsPerCluster, - _sectorsPerCluster, out byte[] buffer); + _imagePlugin.ReadSectors(_firstClusterSector + + (mynode.Clusters[i + firstCluster] - 1) * _sectorsPerCluster, + _sectorsPerCluster, + out byte[] buf); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - ms.Write(buffer, 0, buffer.Length); + ms.Write(buf, 0, buf.Length); } ms.Position = offsetInCluster; - buf = new byte[size]; - ms.Read(buf, 0, (int)size); + ms.EnsureRead(buffer, 0, (int)read); + mynode.Offset += read; return ErrorNumber.NoError; } @@ -147,8 +146,7 @@ public sealed partial class XboxFatPlugin { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; if(_debug && (string.IsNullOrEmpty(path) || path is "$" or "/")) { @@ -167,8 +165,7 @@ public sealed partial class XboxFatPlugin ErrorNumber err = GetFileEntry(path, out DirectoryEntry entry); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; stat = new FileEntryInfo { @@ -178,19 +175,20 @@ public sealed partial class XboxFatPlugin Length = entry.length, Inode = entry.firstCluster, Links = 1, - CreationTime = _littleEndian - ? DateHandlers.DosToDateTime(entry.creationDate, entry.creationTime).AddYears(20) - : DateHandlers.DosToDateTime(entry.creationTime, entry.creationDate), - AccessTime = _littleEndian - ? DateHandlers.DosToDateTime(entry.lastAccessDate, entry.lastAccessTime).AddYears(20) - : DateHandlers.DosToDateTime(entry.lastAccessTime, entry.lastAccessDate), + CreationTime = + _littleEndian + ? DateHandlers.DosToDateTime(entry.creationDate, entry.creationTime).AddYears(20) + : DateHandlers.DosToDateTime(entry.creationTime, entry.creationDate), + AccessTime = + _littleEndian + ? DateHandlers.DosToDateTime(entry.lastAccessDate, entry.lastAccessTime).AddYears(20) + : DateHandlers.DosToDateTime(entry.lastAccessTime, entry.lastAccessDate), LastWriteTime = _littleEndian ? DateHandlers.DosToDateTime(entry.lastWrittenDate, entry.lastWrittenTime).AddYears(20) : DateHandlers.DosToDateTime(entry.lastWrittenTime, entry.lastWrittenDate) }; - if(entry.length % _bytesPerCluster > 0) - stat.Blocks++; + if(entry.length % _bytesPerCluster > 0) stat.Blocks++; if(entry.attributes.HasFlag(Attributes.Directory)) { @@ -199,52 +197,49 @@ public sealed partial class XboxFatPlugin stat.Length = stat.Blocks * stat.BlockSize; } - if(entry.attributes.HasFlag(Attributes.ReadOnly)) - stat.Attributes |= FileAttributes.ReadOnly; + if(entry.attributes.HasFlag(Attributes.ReadOnly)) stat.Attributes |= FileAttributes.ReadOnly; - if(entry.attributes.HasFlag(Attributes.Hidden)) - stat.Attributes |= FileAttributes.Hidden; + if(entry.attributes.HasFlag(Attributes.Hidden)) stat.Attributes |= FileAttributes.Hidden; - if(entry.attributes.HasFlag(Attributes.System)) - stat.Attributes |= FileAttributes.System; + if(entry.attributes.HasFlag(Attributes.System)) stat.Attributes |= FileAttributes.System; - if(entry.attributes.HasFlag(Attributes.Archive)) - stat.Attributes |= FileAttributes.Archive; + if(entry.attributes.HasFlag(Attributes.Archive)) stat.Attributes |= FileAttributes.Archive; return ErrorNumber.NoError; } +#endregion + uint[] GetClusters(uint startCluster) { - if(startCluster == 0) - return null; + if(startCluster == 0) return null; if(_fat16 is null) { - if(startCluster >= _fat32.Length) - return null; + if(startCluster >= _fat32.Length) return null; } - else if(startCluster >= _fat16.Length) - return null; + else if(startCluster >= _fat16.Length) return null; - List clusters = new(); + List clusters = []; uint nextCluster = startCluster; if(_fat16 is null) - while((nextCluster & FAT32_MASK) > 0 && - (nextCluster & FAT32_MASK) <= FAT32_RESERVED) + { + while((nextCluster & FAT32_MASK) > 0 && (nextCluster & FAT32_MASK) <= FAT32_RESERVED) { clusters.Add(nextCluster); nextCluster = _fat32[nextCluster]; } + } else - while(nextCluster > 0 && - nextCluster <= FAT16_RESERVED) + { + while(nextCluster is > 0 and <= FAT16_RESERVED) { clusters.Add(nextCluster); nextCluster = _fat16[nextCluster]; } + } return clusters.ToArray(); } @@ -253,35 +248,34 @@ public sealed partial class XboxFatPlugin { entry = new DirectoryEntry(); - string cutPath = path.StartsWith('/') ? path.Substring(1).ToLower(_cultureInfo) : path.ToLower(_cultureInfo); + string cutPath = path.StartsWith('/') ? path[1..].ToLower(_cultureInfo) : path.ToLower(_cultureInfo); string[] pieces = cutPath.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pieces.Length == 0) - return ErrorNumber.InvalidArgument; + if(pieces.Length == 0) return ErrorNumber.InvalidArgument; var parentPath = string.Join("/", pieces, 0, pieces.Length - 1); - ErrorNumber err = ReadDir(parentPath, out _); + ErrorNumber err = OpenDir(parentPath, out IDirNode node); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; + + CloseDir(node); Dictionary parent; if(pieces.Length == 1) parent = _rootDirectory; - else if(!_directoryCache.TryGetValue(parentPath, out parent)) - return ErrorNumber.InvalidArgument; + else if(!_directoryCache.TryGetValue(parentPath, out parent)) return ErrorNumber.InvalidArgument; KeyValuePair dirent = parent.FirstOrDefault(t => t.Key.ToLower(_cultureInfo) == pieces[^1]); - if(string.IsNullOrEmpty(dirent.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(dirent.Key)) return ErrorNumber.NoSuchFile; entry = dirent.Value; diff --git a/Aaru.Filesystems/FATX/Info.cs b/Aaru.Filesystems/FATX/Info.cs index 6959baa93..18dd7ced2 100644 --- a/Aaru.Filesystems/FATX/Info.cs +++ b/Aaru.Filesystems/FATX/Info.cs @@ -7,10 +7,6 @@ // // Component : FATX filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the FATX filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,30 +23,30 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; -using Schemas; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class XboxFatPlugin { +#region IReadOnlyFilesystem Members + /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(imagePlugin.Info.SectorSize < 512) - return false; + if(imagePlugin.Info.SectorSize < 512) return false; ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; Superblock sb = Marshal.ByteArrayToStructureBigEndian(sector); @@ -58,20 +54,19 @@ public sealed partial class XboxFatPlugin } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = Encoding.UTF8; information = ""; + metadata = new FileSystem(); - if(imagePlugin.Info.SectorSize < 512) - return; + if(imagePlugin.Info.SectorSize < 512) return; var bigEndian = true; ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; Superblock fatxSb = Marshal.ByteArrayToStructureBigEndian(sector); @@ -81,42 +76,47 @@ public sealed partial class XboxFatPlugin bigEndian = false; } - if(fatxSb.magic != FATX_MAGIC) - return; + if(fatxSb.magic != FATX_MAGIC) return; int logicalSectorsPerPhysicalSectors = partition.Offset == 0 && !bigEndian ? 8 : 1; var sb = new StringBuilder(); - sb.AppendLine("FATX filesystem"); + sb.AppendLine(Localization.FATX_filesystem); - sb.AppendFormat("{0} logical sectors ({1} bytes) per physical sector", logicalSectorsPerPhysicalSectors, - logicalSectorsPerPhysicalSectors * imagePlugin.Info.SectorSize).AppendLine(); + sb.AppendFormat(Localization._0_logical_sectors_1_bytes_per_physical_sector, + logicalSectorsPerPhysicalSectors, + logicalSectorsPerPhysicalSectors * imagePlugin.Info.SectorSize) + .AppendLine(); - sb.AppendFormat("{0} sectors ({1} bytes) per cluster", fatxSb.sectorsPerCluster, - fatxSb.sectorsPerCluster * logicalSectorsPerPhysicalSectors * imagePlugin.Info.SectorSize). - AppendLine(); + sb.AppendFormat(Localization._0_sectors_1_bytes_per_cluster, + fatxSb.sectorsPerCluster, + fatxSb.sectorsPerCluster * logicalSectorsPerPhysicalSectors * imagePlugin.Info.SectorSize) + .AppendLine(); - sb.AppendFormat("Root directory starts on cluster {0}", fatxSb.rootDirectoryCluster).AppendLine(); + sb.AppendFormat(Localization.Root_directory_starts_at_cluster_0, fatxSb.rootDirectoryCluster).AppendLine(); string volumeLabel = StringHandlers.CToString(fatxSb.volumeLabel, - bigEndian ? Encoding.BigEndianUnicode : Encoding.Unicode, true); + bigEndian ? Encoding.BigEndianUnicode : Encoding.Unicode, + true); - sb.AppendFormat("Volume label: {0}", volumeLabel).AppendLine(); - sb.AppendFormat("Volume serial: {0:X8}", fatxSb.id).AppendLine(); + sb.AppendFormat(Localization.Volume_label_0, volumeLabel).AppendLine(); + sb.AppendFormat(Localization.Volume_serial_0_X8, fatxSb.id).AppendLine(); information = sb.ToString(); - XmlFsType = new FileSystemType + metadata = new FileSystem { - Type = "FATX filesystem", - ClusterSize = (uint)(fatxSb.sectorsPerCluster * logicalSectorsPerPhysicalSectors * + Type = FS_TYPE, + ClusterSize = (uint)(fatxSb.sectorsPerCluster * + logicalSectorsPerPhysicalSectors * imagePlugin.Info.SectorSize), VolumeName = volumeLabel, VolumeSerial = $"{fatxSb.id:X8}" }; - XmlFsType.Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / - XmlFsType.ClusterSize; + metadata.Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / metadata.ClusterSize; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/FATX/Structs.cs b/Aaru.Filesystems/FATX/Structs.cs index 6c6dea002..97c60c917 100644 --- a/Aaru.Filesystems/FATX/Structs.cs +++ b/Aaru.Filesystems/FATX/Structs.cs @@ -7,10 +7,6 @@ // // Component : FATX filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// FATX filesystem structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,27 +23,17 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System.Runtime.InteropServices; +using Aaru.CommonTypes.Interfaces; + namespace Aaru.Filesystems; -using System.Runtime.InteropServices; - public sealed partial class XboxFatPlugin { - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Superblock - { - public readonly uint magic; - public readonly uint id; - public readonly uint sectorsPerCluster; - public readonly uint rootDirectoryCluster; - - // TODO: Undetermined size - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] volumeLabel; - } +#region Nested type: DirectoryEntry [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct DirectoryEntry @@ -65,4 +51,62 @@ public sealed partial class XboxFatPlugin public readonly ushort creationTime; public readonly ushort creationDate; } + +#endregion + +#region Nested type: FatxDirNode + + sealed class FatxDirNode : IDirNode + { + internal DirectoryEntry[] Entries; + internal int Position; + +#region IDirNode Members + + /// + public string Path { get; init; } + +#endregion + } + +#endregion + +#region Nested type: FatxFileNode + + sealed class FatxFileNode : IFileNode + { + internal uint[] Clusters; + +#region IFileNode Members + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + +#endregion + } + +#endregion + +#region Nested type: Superblock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Superblock + { + public readonly uint magic; + public readonly uint id; + public readonly uint sectorsPerCluster; + public readonly uint rootDirectoryCluster; + + // TODO: Undetermined size + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] volumeLabel; + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/FATX/Super.cs b/Aaru.Filesystems/FATX/Super.cs index d063941f8..6d8c104b2 100644 --- a/Aaru.Filesystems/FATX/Super.cs +++ b/Aaru.Filesystems/FATX/Super.cs @@ -7,10 +7,6 @@ // // Component : FATX filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Handles mounting and umounting the FATX filesystem. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,48 +23,47 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Globalization; using System.Runtime.InteropServices; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Helpers; -using Schemas; using Marshal = Aaru.Helpers.Marshal; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class XboxFatPlugin { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, - Dictionary options, string @namespace) + public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace) { - Encoding = Encoding.GetEncoding("iso-8859-15"); + _encoding = Encoding.GetEncoding("iso-8859-15"); _littleEndian = true; options ??= GetDefaultOptions(); - if(options.TryGetValue("debug", out string debugString)) - bool.TryParse(debugString, out _debug); + if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out _debug); - if(imagePlugin.Info.SectorSize < 512) - return ErrorNumber.InvalidArgument; + if(imagePlugin.Info.SectorSize < 512) return ErrorNumber.InvalidArgument; - AaruConsole.DebugWriteLine("Xbox FAT plugin", "Reading superblock"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_superblock); ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; _superblock = Marshal.ByteArrayToStructureLittleEndian(sector); @@ -78,36 +73,38 @@ public sealed partial class XboxFatPlugin _littleEndian = false; } - if(_superblock.magic != FATX_MAGIC) - return ErrorNumber.InvalidArgument; + if(_superblock.magic != FATX_MAGIC) return ErrorNumber.InvalidArgument; - AaruConsole.DebugWriteLine("Xbox FAT plugin", - _littleEndian ? "Filesystem is little endian" : "Filesystem is big endian"); + AaruConsole.DebugWriteLine(MODULE_NAME, + _littleEndian + ? Localization.Filesystem_is_little_endian + : Localization.Filesystem_is_big_endian); int logicalSectorsPerPhysicalSectors = partition.Offset == 0 && _littleEndian ? 8 : 1; - AaruConsole.DebugWriteLine("Xbox FAT plugin", "logicalSectorsPerPhysicalSectors = {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + "logicalSectorsPerPhysicalSectors = {0}", logicalSectorsPerPhysicalSectors); string volumeLabel = StringHandlers.CToString(_superblock.volumeLabel, !_littleEndian ? Encoding.BigEndianUnicode : Encoding.Unicode, true); - XmlFsType = new FileSystemType + Metadata = new FileSystem { - Type = "FATX filesystem", - ClusterSize = (uint)(_superblock.sectorsPerCluster * logicalSectorsPerPhysicalSectors * + Type = Localization.FATX_filesystem, + ClusterSize = (uint)(_superblock.sectorsPerCluster * + logicalSectorsPerPhysicalSectors * imagePlugin.Info.SectorSize), VolumeName = volumeLabel, VolumeSerial = $"{_superblock.id:X8}" }; - XmlFsType.Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / - XmlFsType.ClusterSize; + Metadata.Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / Metadata.ClusterSize; _statfs = new FileSystemInfo { - Blocks = XmlFsType.Clusters, + Blocks = Metadata.Clusters, FilenameLength = MAX_FILENAME, Files = 0, // Requires traversing all directories FreeFiles = 0, @@ -121,89 +118,81 @@ public sealed partial class XboxFatPlugin FreeBlocks = 0 // Requires traversing the FAT }; - AaruConsole.DebugWriteLine("Xbox FAT plugin", "XmlFsType.ClusterSize: {0}", XmlFsType.ClusterSize); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "XmlFsType.VolumeName: {0}", XmlFsType.VolumeName); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "XmlFsType.VolumeSerial: {0}", XmlFsType.VolumeSerial); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "stat.Blocks: {0}", _statfs.Blocks); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "stat.FilenameLength: {0}", _statfs.FilenameLength); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "stat.Id: {0}", _statfs.Id.Serial32); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "stat.Type: {0}", _statfs.Type); + AaruConsole.DebugWriteLine(MODULE_NAME, "XmlFsType.ClusterSize: {0}", Metadata.ClusterSize); + AaruConsole.DebugWriteLine(MODULE_NAME, "XmlFsType.VolumeName: {0}", Metadata.VolumeName); + AaruConsole.DebugWriteLine(MODULE_NAME, "XmlFsType.VolumeSerial: {0}", Metadata.VolumeSerial); + AaruConsole.DebugWriteLine(MODULE_NAME, "stat.Blocks: {0}", _statfs.Blocks); + AaruConsole.DebugWriteLine(MODULE_NAME, "stat.FilenameLength: {0}", _statfs.FilenameLength); + AaruConsole.DebugWriteLine(MODULE_NAME, "stat.Id: {0}", _statfs.Id.Serial32); + AaruConsole.DebugWriteLine(MODULE_NAME, "stat.Type: {0}", _statfs.Type); byte[] buffer; _fatStartSector = FAT_START / imagePlugin.Info.SectorSize + partition.Start; uint fatSize; - AaruConsole.DebugWriteLine("Xbox FAT plugin", "fatStartSector: {0}", _fatStartSector); + AaruConsole.DebugWriteLine(MODULE_NAME, "fatStartSector: {0}", _fatStartSector); if(_statfs.Blocks > MAX_XFAT16_CLUSTERS) { - AaruConsole.DebugWriteLine("Xbox FAT plugin", "Reading FAT32"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_FAT32); fatSize = (uint)((_statfs.Blocks + 1) * sizeof(uint) / imagePlugin.Info.SectorSize); - if((uint)((_statfs.Blocks + 1) * sizeof(uint) % imagePlugin.Info.SectorSize) > 0) - fatSize++; + if((uint)((_statfs.Blocks + 1) * sizeof(uint) % imagePlugin.Info.SectorSize) > 0) fatSize++; long fatClusters = fatSize * imagePlugin.Info.SectorSize / 4096; - if(fatSize * imagePlugin.Info.SectorSize % 4096 > 0) - fatClusters++; + if(fatSize * imagePlugin.Info.SectorSize % 4096 > 0) fatClusters++; fatSize = (uint)(fatClusters * 4096 / imagePlugin.Info.SectorSize); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "FAT is {0} sectors", fatSize); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.FAT_is_0_sectors, fatSize); errno = imagePlugin.ReadSectors(_fatStartSector, fatSize, out buffer); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - AaruConsole.DebugWriteLine("Xbox FAT plugin", "Casting FAT"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Casting_FAT); _fat32 = MemoryMarshal.Cast(buffer).ToArray(); if(!_littleEndian) for(var i = 0; i < _fat32.Length; i++) _fat32[i] = Swapping.Swap(_fat32[i]); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "fat32[0] == FATX32_ID = {0}", _fat32[0] == FATX32_ID); + AaruConsole.DebugWriteLine(MODULE_NAME, "fat32[0] == FATX32_ID = {0}", _fat32[0] == FATX32_ID); - if(_fat32[0] != FATX32_ID) - return ErrorNumber.InvalidArgument; + if(_fat32[0] != FATX32_ID) return ErrorNumber.InvalidArgument; } else { - AaruConsole.DebugWriteLine("Xbox FAT plugin", "Reading FAT16"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_FAT16); fatSize = (uint)((_statfs.Blocks + 1) * sizeof(ushort) / imagePlugin.Info.SectorSize); - if((uint)((_statfs.Blocks + 1) * sizeof(ushort) % imagePlugin.Info.SectorSize) > 0) - fatSize++; + if((uint)((_statfs.Blocks + 1) * sizeof(ushort) % imagePlugin.Info.SectorSize) > 0) fatSize++; long fatClusters = fatSize * imagePlugin.Info.SectorSize / 4096; - if(fatSize * imagePlugin.Info.SectorSize % 4096 > 0) - fatClusters++; + if(fatSize * imagePlugin.Info.SectorSize % 4096 > 0) fatClusters++; fatSize = (uint)(fatClusters * 4096 / imagePlugin.Info.SectorSize); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "FAT is {0} sectors", fatSize); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.FAT_is_0_sectors, fatSize); errno = imagePlugin.ReadSectors(_fatStartSector, fatSize, out buffer); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - AaruConsole.DebugWriteLine("Xbox FAT plugin", "Casting FAT"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Casting_FAT); _fat16 = MemoryMarshal.Cast(buffer).ToArray(); if(!_littleEndian) for(var i = 0; i < _fat16.Length; i++) _fat16[i] = Swapping.Swap(_fat16[i]); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "fat16[0] == FATX16_ID = {0}", _fat16[0] == FATX16_ID); + AaruConsole.DebugWriteLine(MODULE_NAME, "fat16[0] == FATX16_ID = {0}", _fat16[0] == FATX16_ID); - if(_fat16[0] != FATX16_ID) - return ErrorNumber.InvalidArgument; + if(_fat16[0] != FATX16_ID) return ErrorNumber.InvalidArgument; } _sectorsPerCluster = (uint)(_superblock.sectorsPerCluster * logicalSectorsPerPhysicalSectors); @@ -211,26 +200,25 @@ public sealed partial class XboxFatPlugin _firstClusterSector = _fatStartSector + fatSize; _bytesPerCluster = _sectorsPerCluster * imagePlugin.Info.SectorSize; - AaruConsole.DebugWriteLine("Xbox FAT plugin", "sectorsPerCluster = {0}", _sectorsPerCluster); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "bytesPerCluster = {0}", _bytesPerCluster); - AaruConsole.DebugWriteLine("Xbox FAT plugin", "firstClusterSector = {0}", _firstClusterSector); + AaruConsole.DebugWriteLine(MODULE_NAME, "sectorsPerCluster = {0}", _sectorsPerCluster); + AaruConsole.DebugWriteLine(MODULE_NAME, "bytesPerCluster = {0}", _bytesPerCluster); + AaruConsole.DebugWriteLine(MODULE_NAME, "firstClusterSector = {0}", _firstClusterSector); uint[] rootDirectoryClusters = GetClusters(_superblock.rootDirectoryCluster); - if(rootDirectoryClusters is null) - return ErrorNumber.InvalidArgument; + if(rootDirectoryClusters is null) return ErrorNumber.InvalidArgument; var rootDirectoryBuffer = new byte[_bytesPerCluster * rootDirectoryClusters.Length]; - AaruConsole.DebugWriteLine("Xbox FAT plugin", "Reading root directory"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_root_directory); for(var i = 0; i < rootDirectoryClusters.Length; i++) { errno = imagePlugin.ReadSectors(_firstClusterSector + (rootDirectoryClusters[i] - 1) * _sectorsPerCluster, - _sectorsPerCluster, out buffer); + _sectorsPerCluster, + out buffer); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; Array.Copy(buffer, 0, rootDirectoryBuffer, i * _bytesPerCluster, _bytesPerCluster); } @@ -243,19 +231,19 @@ public sealed partial class XboxFatPlugin { DirectoryEntry entry = _littleEndian ? Marshal.ByteArrayToStructureLittleEndian(rootDirectoryBuffer, - pos, Marshal.SizeOf()) - : Marshal.ByteArrayToStructureBigEndian(rootDirectoryBuffer, pos, + pos, + Marshal.SizeOf()) + : Marshal.ByteArrayToStructureBigEndian(rootDirectoryBuffer, + pos, Marshal.SizeOf()); pos += Marshal.SizeOf(); - if(entry.filenameSize is UNUSED_DIRENTRY or FINISHED_DIRENTRY) - break; + if(entry.filenameSize is UNUSED_DIRENTRY or FINISHED_DIRENTRY) break; - if(entry.filenameSize is DELETED_DIRENTRY or > MAX_FILENAME) - continue; + if(entry.filenameSize is DELETED_DIRENTRY or > MAX_FILENAME) continue; - string filename = Encoding.GetString(entry.filename, 0, entry.filenameSize); + string filename = _encoding.GetString(entry.filename, 0, entry.filenameSize); _rootDirectory.Add(filename, entry); } @@ -270,8 +258,7 @@ public sealed partial class XboxFatPlugin /// public ErrorNumber Unmount() { - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; _fat16 = null; _fat32 = null; @@ -286,11 +273,12 @@ public sealed partial class XboxFatPlugin { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; stat = _statfs.ShallowCopy(); return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/FFS.cs b/Aaru.Filesystems/FFS.cs deleted file mode 100644 index 38c789b5f..000000000 --- a/Aaru.Filesystems/FFS.cs +++ /dev/null @@ -1,848 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : FFS.cs -// Author(s) : Natalia Portillo -// -// Component : BSD Fast File System plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the BSD Fast File System and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -using time_t = System.Int32; -using ufs_daddr_t = System.Int32; - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Using information from Linux kernel headers -/// -/// Implements detection of BSD Fast File System (FFS, aka UNIX File System) -[SuppressMessage("ReSharper", "InconsistentNaming")] -public sealed class FFSPlugin : IFilesystem -{ - const uint block_size = 8192; - - // FreeBSD specifies starts at byte offsets 0, 8192, 65536 and 262144, but in other cases it's following sectors - // Without bootcode - const ulong sb_start_floppy = 0; - - // With bootcode - const ulong sb_start_boot = 1; - - // Dunno, longer boot code - const ulong sb_start_long_boot = 8; - - // Found on AT&T for MD-2D floppieslzio - const ulong sb_start_att_dsdd = 14; - - // Found on hard disks (Atari UNIX e.g.) - const ulong sb_start_piggy = 32; - - // MAGICs - // UFS magic - const uint UFS_MAGIC = 0x00011954; - - // Big-endian UFS magic - const uint UFS_CIGAM = 0x54190100; - - // BorderWare UFS - const uint UFS_MAGIC_BW = 0x0F242697; - - // Big-endian BorderWare UFS - const uint UFS_CIGAM_BW = 0x9726240F; - - // UFS2 magic - const uint UFS2_MAGIC = 0x19540119; - - // Big-endian UFS2 magic - const uint UFS2_CIGAM = 0x19015419; - - // Incomplete newfs - const uint UFS_BAD_MAGIC = 0x19960408; - - // Big-endian incomplete newfs - const uint UFS_BAD_CIGAM = 0x08049619; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "BSD Fast File System (aka UNIX File System, UFS)"; - /// - public Guid Id => new("CC90D342-05DB-48A8-988C-C1FE000034A3"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(2 + partition.Start >= partition.End) - return false; - - uint sbSizeInSectors; - - if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448) - sbSizeInSectors = block_size / 2048; - else - sbSizeInSectors = block_size / imagePlugin.Info.SectorSize; - - ulong[] locations = - { - sb_start_floppy, sb_start_boot, sb_start_long_boot, sb_start_piggy, sb_start_att_dsdd, - 8192 / imagePlugin.Info.SectorSize, 65536 / imagePlugin.Info.SectorSize, - 262144 / imagePlugin.Info.SectorSize - }; - - try - { - foreach(ulong loc in locations) - if(partition.End > partition.Start + loc + sbSizeInSectors) - { - ErrorNumber errno = - imagePlugin.ReadSectors(partition.Start + loc, sbSizeInSectors, out byte[] ufsSbSectors); - - if(errno != ErrorNumber.NoError) - continue; - - var magic = BitConverter.ToUInt32(ufsSbSectors, 0x055C); - - if(magic is UFS_MAGIC or UFS_CIGAM or UFS_MAGIC_BW or UFS_CIGAM_BW or UFS2_MAGIC or UFS2_CIGAM - or UFS_BAD_MAGIC or UFS_BAD_CIGAM) - return true; - } - - return false; - } - catch(Exception) - { - return false; - } - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - var sbInformation = new StringBuilder(); - - uint magic = 0; - uint sb_size_in_sectors; - byte[] ufs_sb_sectors; - ulong sb_offset = partition.Start; - var fs_type_42bsd = false; - var fs_type_43bsd = false; - var fs_type_44bsd = false; - var fs_type_ufs = false; - var fs_type_ufs2 = false; - var fs_type_sun = false; - var fs_type_sun86 = false; - - if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448) - sb_size_in_sectors = block_size / 2048; - else - sb_size_in_sectors = block_size / imagePlugin.Info.SectorSize; - - ulong[] locations = - { - sb_start_floppy, sb_start_boot, sb_start_long_boot, sb_start_piggy, sb_start_att_dsdd, - 8192 / imagePlugin.Info.SectorSize, 65536 / imagePlugin.Info.SectorSize, - 262144 / imagePlugin.Info.SectorSize - }; - - ErrorNumber errno; - - foreach(ulong loc in locations.Where(loc => partition.End > partition.Start + loc + sb_size_in_sectors)) - { - errno = imagePlugin.ReadSectors(partition.Start + loc, sb_size_in_sectors, out ufs_sb_sectors); - - if(errno != ErrorNumber.NoError) - continue; - - magic = BitConverter.ToUInt32(ufs_sb_sectors, 0x055C); - - if(magic is UFS_MAGIC or UFS_CIGAM or UFS_MAGIC_BW or UFS_CIGAM_BW or UFS2_MAGIC or UFS2_CIGAM - or UFS_BAD_MAGIC or UFS_BAD_CIGAM) - { - sb_offset = partition.Start + loc; - - break; - } - - magic = 0; - } - - if(magic == 0) - { - information = "Not a UFS filesystem, I shouldn't have arrived here!"; - - return; - } - - XmlFsType = new FileSystemType(); - - switch(magic) - { - case UFS_MAGIC: - sbInformation.AppendLine("UFS filesystem"); - XmlFsType.Type = "UFS"; - - break; - case UFS_CIGAM: - sbInformation.AppendLine("Big-endian UFS filesystem"); - XmlFsType.Type = "UFS"; - - break; - case UFS_MAGIC_BW: - sbInformation.AppendLine("BorderWare UFS filesystem"); - XmlFsType.Type = "UFS"; - - break; - case UFS_CIGAM_BW: - sbInformation.AppendLine("Big-endian BorderWare UFS filesystem"); - XmlFsType.Type = "UFS"; - - break; - case UFS2_MAGIC: - sbInformation.AppendLine("UFS2 filesystem"); - XmlFsType.Type = "UFS2"; - - break; - case UFS2_CIGAM: - sbInformation.AppendLine("Big-endian UFS2 filesystem"); - XmlFsType.Type = "UFS2"; - - break; - case UFS_BAD_MAGIC: - sbInformation.AppendLine("Incompletely initialized UFS filesystem"); - sbInformation.AppendLine("BEWARE!!! Following information may be completely wrong!"); - XmlFsType.Type = "UFS"; - - break; - case UFS_BAD_CIGAM: - sbInformation.AppendLine("Incompletely initialized big-endian UFS filesystem"); - sbInformation.AppendLine("BEWARE!!! Following information may be completely wrong!"); - XmlFsType.Type = "UFS"; - - break; - } - - // Fun with seeking follows on superblock reading! - errno = imagePlugin.ReadSectors(sb_offset, sb_size_in_sectors, out ufs_sb_sectors); - - if(errno != ErrorNumber.NoError) - return; - - SuperBlock sb = Marshal.ByteArrayToStructureLittleEndian(ufs_sb_sectors); - - SuperBlock bs_sfu = Marshal.ByteArrayToStructureBigEndian(ufs_sb_sectors); - - if(bs_sfu.fs_magic == UFS_MAGIC && sb.fs_magic == UFS_CIGAM || - bs_sfu.fs_magic == UFS_MAGIC_BW && sb.fs_magic == UFS_CIGAM_BW || - bs_sfu.fs_magic == UFS2_MAGIC && sb.fs_magic == UFS2_CIGAM || - bs_sfu.fs_magic == UFS_BAD_MAGIC && sb.fs_magic == UFS_BAD_CIGAM) - { - sb = bs_sfu; - sb.fs_old_cstotal.cs_nbfree = Swapping.Swap(sb.fs_old_cstotal.cs_nbfree); - sb.fs_old_cstotal.cs_ndir = Swapping.Swap(sb.fs_old_cstotal.cs_ndir); - sb.fs_old_cstotal.cs_nffree = Swapping.Swap(sb.fs_old_cstotal.cs_nffree); - sb.fs_old_cstotal.cs_nifree = Swapping.Swap(sb.fs_old_cstotal.cs_nifree); - sb.fs_cstotal.cs_numclusters = Swapping.Swap(sb.fs_cstotal.cs_numclusters); - sb.fs_cstotal.cs_nbfree = Swapping.Swap(sb.fs_cstotal.cs_nbfree); - sb.fs_cstotal.cs_ndir = Swapping.Swap(sb.fs_cstotal.cs_ndir); - sb.fs_cstotal.cs_nffree = Swapping.Swap(sb.fs_cstotal.cs_nffree); - sb.fs_cstotal.cs_nifree = Swapping.Swap(sb.fs_cstotal.cs_nifree); - sb.fs_cstotal.cs_spare[0] = Swapping.Swap(sb.fs_cstotal.cs_spare[0]); - sb.fs_cstotal.cs_spare[1] = Swapping.Swap(sb.fs_cstotal.cs_spare[1]); - sb.fs_cstotal.cs_spare[2] = Swapping.Swap(sb.fs_cstotal.cs_spare[2]); - } - - AaruConsole.DebugWriteLine("FFS plugin", "sb offset: 0x{0:X8}", sb_offset); - AaruConsole.DebugWriteLine("FFS plugin", "fs_rlink: 0x{0:X8}", sb.fs_rlink); - AaruConsole.DebugWriteLine("FFS plugin", "fs_sblkno: 0x{0:X8}", sb.fs_sblkno); - AaruConsole.DebugWriteLine("FFS plugin", "fs_cblkno: 0x{0:X8}", sb.fs_cblkno); - AaruConsole.DebugWriteLine("FFS plugin", "fs_iblkno: 0x{0:X8}", sb.fs_iblkno); - AaruConsole.DebugWriteLine("FFS plugin", "fs_dblkno: 0x{0:X8}", sb.fs_dblkno); - AaruConsole.DebugWriteLine("FFS plugin", "fs_size: 0x{0:X8}", sb.fs_size); - AaruConsole.DebugWriteLine("FFS plugin", "fs_dsize: 0x{0:X8}", sb.fs_dsize); - AaruConsole.DebugWriteLine("FFS plugin", "fs_ncg: 0x{0:X8}", sb.fs_ncg); - AaruConsole.DebugWriteLine("FFS plugin", "fs_bsize: 0x{0:X8}", sb.fs_bsize); - AaruConsole.DebugWriteLine("FFS plugin", "fs_fsize: 0x{0:X8}", sb.fs_fsize); - AaruConsole.DebugWriteLine("FFS plugin", "fs_frag: 0x{0:X8}", sb.fs_frag); - AaruConsole.DebugWriteLine("FFS plugin", "fs_minfree: 0x{0:X8}", sb.fs_minfree); - AaruConsole.DebugWriteLine("FFS plugin", "fs_bmask: 0x{0:X8}", sb.fs_bmask); - AaruConsole.DebugWriteLine("FFS plugin", "fs_fmask: 0x{0:X8}", sb.fs_fmask); - AaruConsole.DebugWriteLine("FFS plugin", "fs_bshift: 0x{0:X8}", sb.fs_bshift); - AaruConsole.DebugWriteLine("FFS plugin", "fs_fshift: 0x{0:X8}", sb.fs_fshift); - AaruConsole.DebugWriteLine("FFS plugin", "fs_maxcontig: 0x{0:X8}", sb.fs_maxcontig); - AaruConsole.DebugWriteLine("FFS plugin", "fs_maxbpg: 0x{0:X8}", sb.fs_maxbpg); - AaruConsole.DebugWriteLine("FFS plugin", "fs_fragshift: 0x{0:X8}", sb.fs_fragshift); - AaruConsole.DebugWriteLine("FFS plugin", "fs_fsbtodb: 0x{0:X8}", sb.fs_fsbtodb); - AaruConsole.DebugWriteLine("FFS plugin", "fs_sbsize: 0x{0:X8}", sb.fs_sbsize); - AaruConsole.DebugWriteLine("FFS plugin", "fs_csmask: 0x{0:X8}", sb.fs_csmask); - AaruConsole.DebugWriteLine("FFS plugin", "fs_csshift: 0x{0:X8}", sb.fs_csshift); - AaruConsole.DebugWriteLine("FFS plugin", "fs_nindir: 0x{0:X8}", sb.fs_nindir); - AaruConsole.DebugWriteLine("FFS plugin", "fs_inopb: 0x{0:X8}", sb.fs_inopb); - AaruConsole.DebugWriteLine("FFS plugin", "fs_optim: 0x{0:X8}", sb.fs_optim); - AaruConsole.DebugWriteLine("FFS plugin", "fs_id_1: 0x{0:X8}", sb.fs_id_1); - AaruConsole.DebugWriteLine("FFS plugin", "fs_id_2: 0x{0:X8}", sb.fs_id_2); - AaruConsole.DebugWriteLine("FFS plugin", "fs_csaddr: 0x{0:X8}", sb.fs_csaddr); - AaruConsole.DebugWriteLine("FFS plugin", "fs_cssize: 0x{0:X8}", sb.fs_cssize); - AaruConsole.DebugWriteLine("FFS plugin", "fs_cgsize: 0x{0:X8}", sb.fs_cgsize); - AaruConsole.DebugWriteLine("FFS plugin", "fs_ipg: 0x{0:X8}", sb.fs_ipg); - AaruConsole.DebugWriteLine("FFS plugin", "fs_fpg: 0x{0:X8}", sb.fs_fpg); - AaruConsole.DebugWriteLine("FFS plugin", "fs_fmod: 0x{0:X2}", sb.fs_fmod); - AaruConsole.DebugWriteLine("FFS plugin", "fs_clean: 0x{0:X2}", sb.fs_clean); - AaruConsole.DebugWriteLine("FFS plugin", "fs_ronly: 0x{0:X2}", sb.fs_ronly); - AaruConsole.DebugWriteLine("FFS plugin", "fs_flags: 0x{0:X2}", sb.fs_flags); - AaruConsole.DebugWriteLine("FFS plugin", "fs_magic: 0x{0:X8}", sb.fs_magic); - - if(sb.fs_magic == UFS2_MAGIC) - fs_type_ufs2 = true; - else - { - const uint - SunOSEpoch = 0x1A54C580; // We are supposing there cannot be a Sun's fs created before 1/1/1982 00:00:00 - - fs_type_43bsd = true; // There is no way of knowing this is the version, but there is of knowing it is not. - - if(sb.fs_link > 0) - { - fs_type_42bsd = true; // It was used in 4.2BSD - fs_type_43bsd = false; - } - - if((sb.fs_maxfilesize & 0xFFFFFFFF) > SunOSEpoch && - DateHandlers.UnixUnsignedToDateTime(sb.fs_maxfilesize & 0xFFFFFFFF) < DateTime.Now) - { - fs_type_42bsd = false; - fs_type_sun = true; - fs_type_43bsd = false; - } - - // This is for sure, as it is shared with a sectors/track with non-x86 SunOS, Epoch is absurdly high for that - if(sb.fs_old_npsect > SunOSEpoch && - DateHandlers.UnixToDateTime(sb.fs_old_npsect) < DateTime.Now) - { - fs_type_42bsd = false; - fs_type_sun86 = true; - fs_type_sun = false; - fs_type_43bsd = false; - } - - if(sb.fs_cgrotor > 0x00000000 && - (uint)sb.fs_cgrotor < 0xFFFFFFFF) - { - fs_type_42bsd = false; - fs_type_sun = false; - fs_type_sun86 = false; - fs_type_ufs = true; - fs_type_43bsd = false; - } - - // 4.3BSD code does not use these fields, they are always set up to 0 - fs_type_43bsd &= sb.fs_id_2 == 0 && sb.fs_id_1 == 0; - - // This is the only 4.4BSD inode format - fs_type_44bsd |= sb.fs_old_inodefmt == 2; - } - - if(!fs_type_ufs2) - { - sbInformation.AppendLine("There are a lot of variants of UFS using overlapped values on same fields"); - - sbInformation. - AppendLine("I will try to guess which one it is, but unless it's UFS2, I may be surely wrong"); - } - - if(fs_type_42bsd) - sbInformation.AppendLine("Guessed as 42BSD FFS"); - - if(fs_type_43bsd) - sbInformation.AppendLine("Guessed as 43BSD FFS"); - - if(fs_type_44bsd) - sbInformation.AppendLine("Guessed as 44BSD FFS"); - - if(fs_type_sun) - sbInformation.AppendLine("Guessed as SunOS FFS"); - - if(fs_type_sun86) - sbInformation.AppendLine("Guessed as SunOS/x86 FFS"); - - if(fs_type_ufs) - sbInformation.AppendLine("Guessed as UFS"); - - if(fs_type_42bsd) - sbInformation.AppendFormat("Linked list of filesystems: 0x{0:X8}", sb.fs_link).AppendLine(); - - sbInformation.AppendFormat("Superblock LBA: {0}", sb.fs_sblkno).AppendLine(); - sbInformation.AppendFormat("Cylinder-block LBA: {0}", sb.fs_cblkno).AppendLine(); - sbInformation.AppendFormat("inode-block LBA: {0}", sb.fs_iblkno).AppendLine(); - sbInformation.AppendFormat("First data block LBA: {0}", sb.fs_dblkno).AppendLine(); - sbInformation.AppendFormat("Cylinder group offset in cylinder: {0}", sb.fs_old_cgoffset).AppendLine(); - - sbInformation.AppendFormat("Volume last written on {0}", DateHandlers.UnixToDateTime(sb.fs_old_time)). - AppendLine(); - - XmlFsType.ModificationDate = DateHandlers.UnixToDateTime(sb.fs_old_time); - XmlFsType.ModificationDateSpecified = true; - - sbInformation.AppendFormat("{0} blocks in volume ({1} bytes)", sb.fs_old_size, - (long)sb.fs_old_size * sb.fs_fsize).AppendLine(); - - XmlFsType.Clusters = (ulong)sb.fs_old_size; - XmlFsType.ClusterSize = (uint)sb.fs_fsize; - - sbInformation.AppendFormat("{0} data blocks in volume ({1} bytes)", sb.fs_old_dsize, - (long)sb.fs_old_dsize * sb.fs_fsize).AppendLine(); - - sbInformation.AppendFormat("{0} cylinder groups in volume", sb.fs_ncg).AppendLine(); - sbInformation.AppendFormat("{0} bytes in a basic block", sb.fs_bsize).AppendLine(); - sbInformation.AppendFormat("{0} bytes in a frag block", sb.fs_fsize).AppendLine(); - sbInformation.AppendFormat("{0} frags in a block", sb.fs_frag).AppendLine(); - sbInformation.AppendFormat("{0}% of blocks must be free", sb.fs_minfree).AppendLine(); - sbInformation.AppendFormat("{0}ms for optimal next block", sb.fs_old_rotdelay).AppendLine(); - - sbInformation.AppendFormat("disk rotates {0} times per second ({1}rpm)", sb.fs_old_rps, sb.fs_old_rps * 60). - AppendLine(); - - /* sbInformation.AppendFormat("fs_bmask: 0x{0:X8}", sb.fs_bmask).AppendLine(); - sbInformation.AppendFormat("fs_fmask: 0x{0:X8}", sb.fs_fmask).AppendLine(); - sbInformation.AppendFormat("fs_bshift: 0x{0:X8}", sb.fs_bshift).AppendLine(); - sbInformation.AppendFormat("fs_fshift: 0x{0:X8}", sb.fs_fshift).AppendLine();*/ - sbInformation.AppendFormat("{0} contiguous blocks at maximum", sb.fs_maxcontig).AppendLine(); - sbInformation.AppendFormat("{0} blocks per cylinder group at maximum", sb.fs_maxbpg).AppendLine(); - sbInformation.AppendFormat("Superblock is {0} bytes", sb.fs_sbsize).AppendLine(); - sbInformation.AppendFormat("NINDIR: 0x{0:X8}", sb.fs_nindir).AppendLine(); - sbInformation.AppendFormat("INOPB: 0x{0:X8}", sb.fs_inopb).AppendLine(); - sbInformation.AppendFormat("NSPF: 0x{0:X8}", sb.fs_old_nspf).AppendLine(); - - switch(sb.fs_optim) - { - case 0: - sbInformation.AppendLine("Filesystem will minimize allocation time"); - - break; - case 1: - sbInformation.AppendLine("Filesystem will minimize volume fragmentation"); - - break; - default: - sbInformation.AppendFormat("Unknown optimization value: 0x{0:X8}", sb.fs_optim).AppendLine(); - - break; - } - - if(fs_type_sun) - sbInformation.AppendFormat("{0} sectors/track", sb.fs_old_npsect).AppendLine(); - else if(fs_type_sun86) - sbInformation.AppendFormat("Volume state on {0}", DateHandlers.UnixToDateTime(sb.fs_old_npsect)). - AppendLine(); - - sbInformation.AppendFormat("Hardware sector interleave: {0}", sb.fs_old_interleave).AppendLine(); - sbInformation.AppendFormat("Sector 0 skew: {0}/track", sb.fs_old_trackskew).AppendLine(); - - if(!fs_type_43bsd && - sb.fs_id_1 > 0 && - sb.fs_id_2 > 0) - sbInformation.AppendFormat("Volume ID: 0x{0:X8}{1:X8}", sb.fs_id_1, sb.fs_id_2).AppendLine(); - else if(fs_type_43bsd && - sb.fs_id_1 > 0 && - sb.fs_id_2 > 0) - { - sbInformation.AppendFormat("{0} µsec for head switch", sb.fs_id_1).AppendLine(); - sbInformation.AppendFormat("{0} µsec for track-to-track seek", sb.fs_id_2).AppendLine(); - } - - sbInformation.AppendFormat("Cylinder group summary LBA: {0}", sb.fs_old_csaddr).AppendLine(); - sbInformation.AppendFormat("{0} bytes in cylinder group summary", sb.fs_cssize).AppendLine(); - sbInformation.AppendFormat("{0} bytes in cylinder group", sb.fs_cgsize).AppendLine(); - sbInformation.AppendFormat("{0} tracks/cylinder", sb.fs_old_ntrak).AppendLine(); - sbInformation.AppendFormat("{0} sectors/track", sb.fs_old_nsect).AppendLine(); - sbInformation.AppendFormat("{0} sectors/cylinder", sb.fs_old_spc).AppendLine(); - sbInformation.AppendFormat("{0} cylinder in volume", sb.fs_old_ncyl).AppendLine(); - sbInformation.AppendFormat("{0} cylinders/group", sb.fs_old_cpg).AppendLine(); - sbInformation.AppendFormat("{0} inodes per cylinder group", sb.fs_ipg).AppendLine(); - sbInformation.AppendFormat("{0} blocks per group", sb.fs_fpg / sb.fs_frag).AppendLine(); - sbInformation.AppendFormat("{0} directories", sb.fs_old_cstotal.cs_ndir).AppendLine(); - - sbInformation.AppendFormat("{0} free blocks ({1} bytes)", sb.fs_old_cstotal.cs_nbfree, - (long)sb.fs_old_cstotal.cs_nbfree * sb.fs_fsize).AppendLine(); - - XmlFsType.FreeClusters = (ulong)sb.fs_old_cstotal.cs_nbfree; - XmlFsType.FreeClustersSpecified = true; - sbInformation.AppendFormat("{0} free inodes", sb.fs_old_cstotal.cs_nifree).AppendLine(); - sbInformation.AppendFormat("{0} free frags", sb.fs_old_cstotal.cs_nffree).AppendLine(); - - if(sb.fs_fmod == 1) - { - sbInformation.AppendLine("Superblock is under modification"); - XmlFsType.Dirty = true; - } - - if(sb.fs_clean == 1) - sbInformation.AppendLine("Volume is clean"); - - if(sb.fs_ronly == 1) - sbInformation.AppendLine("Volume is read-only"); - - sbInformation.AppendFormat("Volume flags: 0x{0:X2}", sb.fs_flags).AppendLine(); - - if(fs_type_ufs) - sbInformation.AppendFormat("Volume last mounted on \"{0}\"", StringHandlers.CToString(sb.fs_fsmnt)). - AppendLine(); - else if(fs_type_ufs2) - { - sbInformation.AppendFormat("Volume last mounted on \"{0}\"", StringHandlers.CToString(sb.fs_fsmnt)). - AppendLine(); - - sbInformation.AppendFormat("Volume name: \"{0}\"", StringHandlers.CToString(sb.fs_volname)).AppendLine(); - - XmlFsType.VolumeName = StringHandlers.CToString(sb.fs_volname); - sbInformation.AppendFormat("Volume ID: 0x{0:X16}", sb.fs_swuid).AppendLine(); - - //xmlFSType.VolumeSerial = string.Format("{0:X16}", sb.fs_swuid); - sbInformation.AppendFormat("Last searched cylinder group: {0}", sb.fs_cgrotor).AppendLine(); - sbInformation.AppendFormat("{0} contiguously allocated directories", sb.fs_contigdirs).AppendLine(); - sbInformation.AppendFormat("Standard superblock LBA: {0}", sb.fs_sblkno).AppendLine(); - sbInformation.AppendFormat("{0} directories", sb.fs_cstotal.cs_ndir).AppendLine(); - - sbInformation.AppendFormat("{0} free blocks ({1} bytes)", sb.fs_cstotal.cs_nbfree, - sb.fs_cstotal.cs_nbfree * sb.fs_fsize).AppendLine(); - - XmlFsType.FreeClusters = (ulong)sb.fs_cstotal.cs_nbfree; - XmlFsType.FreeClustersSpecified = true; - sbInformation.AppendFormat("{0} free inodes", sb.fs_cstotal.cs_nifree).AppendLine(); - sbInformation.AppendFormat("{0} free frags", sb.fs_cstotal.cs_nffree).AppendLine(); - sbInformation.AppendFormat("{0} free clusters", sb.fs_cstotal.cs_numclusters).AppendLine(); - - sbInformation.AppendFormat("Volume last written on {0}", DateHandlers.UnixToDateTime(sb.fs_time)). - AppendLine(); - - XmlFsType.ModificationDate = DateHandlers.UnixToDateTime(sb.fs_time); - XmlFsType.ModificationDateSpecified = true; - - sbInformation.AppendFormat("{0} blocks ({1} bytes)", sb.fs_size, sb.fs_size * sb.fs_fsize).AppendLine(); - - XmlFsType.Clusters = (ulong)sb.fs_size; - - sbInformation.AppendFormat("{0} data blocks ({1} bytes)", sb.fs_dsize, sb.fs_dsize * sb.fs_fsize). - AppendLine(); - - sbInformation.AppendFormat("Cylinder group summary area LBA: {0}", sb.fs_csaddr).AppendLine(); - sbInformation.AppendFormat("{0} blocks pending of being freed", sb.fs_pendingblocks).AppendLine(); - sbInformation.AppendFormat("{0} inodes pending of being freed", sb.fs_pendinginodes).AppendLine(); - } - - if(fs_type_sun) - sbInformation.AppendFormat("Volume state on {0}", DateHandlers.UnixToDateTime(sb.fs_old_npsect)). - AppendLine(); - else if(fs_type_sun86) - sbInformation.AppendFormat("{0} sectors/track", sb.fs_state).AppendLine(); - else if(fs_type_44bsd) - { - sbInformation.AppendFormat("{0} blocks on cluster summary array", sb.fs_contigsumsize).AppendLine(); - - sbInformation.AppendFormat("Maximum length of a symbolic link: {0}", sb.fs_maxsymlinklen).AppendLine(); - - sbInformation.AppendFormat("A file can be {0} bytes at max", sb.fs_maxfilesize).AppendLine(); - - sbInformation.AppendFormat("Volume state on {0}", DateHandlers.UnixToDateTime(sb.fs_state)).AppendLine(); - } - - if(sb.fs_old_nrpos > 0) - sbInformation.AppendFormat("{0} rotational positions", sb.fs_old_nrpos).AppendLine(); - - if(sb.fs_old_rotbloff > 0) - sbInformation.AppendFormat("{0} blocks per rotation", sb.fs_old_rotbloff).AppendLine(); - - information = sbInformation.ToString(); - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct csum - { - /// number of directories - public int cs_ndir; - /// number of free blocks - public int cs_nbfree; - /// number of free inodes - public int cs_nifree; - /// number of free frags - public int cs_nffree; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct csum_total - { - /// number of directories - public long cs_ndir; - /// number of free blocks - public long cs_nbfree; - /// number of free inodes - public long cs_nifree; - /// number of free frags - public long cs_nffree; - /// number of free clusters - public long cs_numclusters; - /// future expansion - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly long[] cs_spare; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SuperBlock - { - /// linked list of file systems - public readonly uint fs_link; - /// used for incore super blocks on Sun: uint fs_rolled; // logging only: fs fully rolled - public readonly uint fs_rlink; - /// addr of super-block in filesys - public readonly int fs_sblkno; - /// offset of cyl-block in filesys - public readonly int fs_cblkno; - /// offset of inode-blocks in filesys - public readonly int fs_iblkno; - /// offset of first data after cg - public readonly int fs_dblkno; - /// cylinder group offset in cylinder - public readonly int fs_old_cgoffset; - /// used to calc mod fs_ntrak - public readonly int fs_old_cgmask; - /// last time written - public readonly int fs_old_time; - /// number of blocks in fs - public readonly int fs_old_size; - /// number of data blocks in fs - public readonly int fs_old_dsize; - /// number of cylinder groups - public readonly int fs_ncg; - /// size of basic blocks in fs - public readonly int fs_bsize; - /// size of frag blocks in fs - public readonly int fs_fsize; - /// number of frags in a block in fs - public readonly int fs_frag; - /* these are configuration parameters */ - /// minimum percentage of free blocks - public readonly int fs_minfree; - /// num of ms for optimal next block - public readonly int fs_old_rotdelay; - /// disk revolutions per second - public readonly int fs_old_rps; - /* these fields can be computed from the others */ - /// ``blkoff'' calc of blk offsets - public readonly int fs_bmask; - /// ``fragoff'' calc of frag offsets - public readonly int fs_fmask; - /// ``lblkno'' calc of logical blkno - public readonly int fs_bshift; - /// ``numfrags'' calc number of frags - public readonly int fs_fshift; - /* these are configuration parameters */ - /// max number of contiguous blks - public readonly int fs_maxcontig; - /// max number of blks per cyl group - public readonly int fs_maxbpg; - /* these fields can be computed from the others */ - /// block to frag shift - public readonly int fs_fragshift; - /// fsbtodb and dbtofsb shift constant - public readonly int fs_fsbtodb; - /// actual size of super block - public readonly int fs_sbsize; - /// csum block offset - public readonly int fs_csmask; - /// csum block number - public readonly int fs_csshift; - /// value of NINDIR - public readonly int fs_nindir; - /// value of INOPB - public readonly uint fs_inopb; - /// value of NSPF - public readonly int fs_old_nspf; - /* yet another configuration parameter */ - /// optimization preference, see below On SVR: int fs_state; // file system state - public readonly int fs_optim; - /// # sectors/track including spares - public readonly int fs_old_npsect; - /// hardware sector interleave - public readonly int fs_old_interleave; - /// sector 0 skew, per track On A/UX: int fs_state; // file system state - public readonly int fs_old_trackskew; - /// unique filesystem id On old: int fs_headswitch; // head switch time, usec - public readonly int fs_id_1; - /// unique filesystem id On old: int fs_trkseek; // track-to-track seek, usec - public readonly int fs_id_2; - /* sizes determined by number of cylinder groups and their sizes */ - /// blk addr of cyl grp summary area - public readonly int fs_old_csaddr; - /// size of cyl grp summary area - public readonly int fs_cssize; - /// cylinder group size - public readonly int fs_cgsize; - /* these fields are derived from the hardware */ - /// tracks per cylinder - public readonly int fs_old_ntrak; - /// sectors per track - public readonly int fs_old_nsect; - /// sectors per cylinder - public readonly int fs_old_spc; - /* this comes from the disk driver partitioning */ - /// cylinders in filesystem - public readonly int fs_old_ncyl; - /* these fields can be computed from the others */ - /// cylinders per group - public readonly int fs_old_cpg; - /// inodes per group - public readonly int fs_ipg; - /// blocks per group * fs_frag - public readonly int fs_fpg; - /* this data must be re-computed after crashes */ - /// cylinder summary information - public csum fs_old_cstotal; - /* these fields are cleared at mount time */ - /// super block modified flag - public readonly sbyte fs_fmod; - /// filesystem is clean flag - public readonly sbyte fs_clean; - /// mounted read-only flag - public readonly sbyte fs_ronly; - /// old FS_ flags - public readonly sbyte fs_old_flags; - /// name mounted on - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 468)] - public readonly byte[] fs_fsmnt; - /// volume name - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] fs_volname; - /// system-wide uid - public readonly ulong fs_swuid; - /// due to alignment of fs_swuid - public readonly int fs_pad; - /* these fields retain the current block allocation info */ - /// last cg searched - public readonly int fs_cgrotor; - /// padding; was list of fs_cs buffers - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] - public readonly uint[] fs_ocsp; - /// (u) # of contig. allocated dirs - public readonly uint fs_contigdirs; - /// (u) cg summary info buffer - public readonly uint fs_csp; - /// (u) max cluster in each cyl group - public readonly uint fs_maxcluster; - /// (u) used by snapshots to track fs - public readonly uint fs_active; - /// cyl per cycle in postbl - public readonly int fs_old_cpc; - /// maximum blocking factor permitted - public readonly int fs_maxbsize; - /// number of unreferenced inodes - public readonly long fs_unrefs; - /// size of underlying GEOM provider - public readonly long fs_providersize; - /// size of area reserved for metadata - public readonly long fs_metaspace; - /// old rotation block list head - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] - public readonly long[] fs_sparecon64; - /// byte offset of standard superblock - public readonly long fs_sblockloc; - /// (u) cylinder summary information - public csum_total fs_cstotal; - /// last time written - public readonly long fs_time; - /// number of blocks in fs - public readonly long fs_size; - /// number of data blocks in fs - public readonly long fs_dsize; - /// blk addr of cyl grp summary area - public readonly long fs_csaddr; - /// (u) blocks being freed - public readonly long fs_pendingblocks; - /// (u) inodes being freed - public readonly uint fs_pendinginodes; - /// list of snapshot inode numbers - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public readonly uint[] fs_snapinum; - /// expected average file size - public readonly uint fs_avgfilesize; - /// expected # of files per directory - public readonly uint fs_avgfpdir; - /// save real cg size to use fs_bsize - public readonly int fs_save_cgsize; - /// Last mount or fsck time. - public readonly long fs_mtime; - /// SUJ free list - public readonly int fs_sujfree; - /// reserved for future constants - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 23)] - public readonly int[] fs_sparecon32; - /// see FS_ flags below - public readonly int fs_flags; - /// size of cluster summary array - public readonly int fs_contigsumsize; - /// max length of an internal symlink - public readonly int fs_maxsymlinklen; - /// format of on-disk inodes - public readonly int fs_old_inodefmt; - /// maximum representable file size - public readonly ulong fs_maxfilesize; - /// ~fs_bmask for use with 64-bit size - public readonly long fs_qbmask; - /// ~fs_fmask for use with 64-bit size - public readonly long fs_qfmask; - /// validate fs_clean field - public readonly int fs_state; - /// format of positional layout tables - public readonly int fs_old_postblformat; - /// number of rotational positions - public readonly int fs_old_nrpos; - /// (short) rotation block list head - public readonly int fs_old_postbloff; - /// (uchar_t) blocks for each rotation - public readonly int fs_old_rotbloff; - /// magic number - public readonly uint fs_magic; - /// list of blocks for each rotation - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] - public readonly byte[] fs_rotbl; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/FFS/Consts.cs b/Aaru.Filesystems/FFS/Consts.cs new file mode 100644 index 000000000..d330eed5d --- /dev/null +++ b/Aaru.Filesystems/FFS/Consts.cs @@ -0,0 +1,84 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : BSD Fast File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Using information from Linux kernel headers +/// +/// Implements detection of BSD Fast File System (FFS, aka UNIX File System) +[SuppressMessage("ReSharper", "InconsistentNaming")] +public sealed partial class FFSPlugin +{ + const uint block_size = 8192; + + // FreeBSD specifies starts at byte offsets 0, 8192, 65536 and 262144, but in other cases it's following sectors + // Without bootcode + const ulong sb_start_floppy = 0; + + // With bootcode + const ulong sb_start_boot = 1; + + // Dunno, longer boot code + const ulong sb_start_long_boot = 8; + + // Found on AT&T for MD-2D floppieslzio + const ulong sb_start_att_dsdd = 14; + + // Found on hard disks (Atari UNIX e.g.) + const ulong sb_start_piggy = 32; + + // MAGICs + // UFS magic + const uint UFS_MAGIC = 0x00011954; + + // Big-endian UFS magic + const uint UFS_CIGAM = 0x54190100; + + // BorderWare UFS + const uint UFS_MAGIC_BW = 0x0F242697; + + // Big-endian BorderWare UFS + const uint UFS_CIGAM_BW = 0x9726240F; + + // UFS2 magic + const uint UFS2_MAGIC = 0x19540119; + + // Big-endian UFS2 magic + const uint UFS2_CIGAM = 0x19015419; + + // Incomplete newfs + const uint UFS_BAD_MAGIC = 0x19960408; + + // Big-endian incomplete newfs + const uint UFS_BAD_CIGAM = 0x08049619; + + const string FS_TYPE_UFS = "ufs"; + const string FS_TYPE_UFS2 = "ufs2"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/FFS/FFS.cs b/Aaru.Filesystems/FFS/FFS.cs new file mode 100644 index 000000000..30d28d8de --- /dev/null +++ b/Aaru.Filesystems/FFS/FFS.cs @@ -0,0 +1,55 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : FFS.cs +// Author(s) : Natalia Portillo +// +// Component : BSD Fast File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Using information from Linux kernel headers +/// +/// Implements detection of BSD Fast File System (FFS, aka UNIX File System) +[SuppressMessage("ReSharper", "InconsistentNaming")] +public sealed partial class FFSPlugin : IFilesystem +{ + const string MODULE_NAME = "FFS plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.FFSPlugin_Name; + + /// + public Guid Id => new("CC90D342-05DB-48A8-988C-C1FE000034A3"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/FFS/Info.cs b/Aaru.Filesystems/FFS/Info.cs new file mode 100644 index 000000000..e6c08d86f --- /dev/null +++ b/Aaru.Filesystems/FFS/Info.cs @@ -0,0 +1,557 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : BSD Fast File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Using information from Linux kernel headers +/// +/// Implements detection of BSD Fast File System (FFS, aka UNIX File System) +[SuppressMessage("ReSharper", "InconsistentNaming")] +public sealed partial class FFSPlugin +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(2 + partition.Start >= partition.End) return false; + + uint sbSizeInSectors; + + if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448) + sbSizeInSectors = block_size / 2048; + else + sbSizeInSectors = block_size / imagePlugin.Info.SectorSize; + + ulong[] locations = + [ + sb_start_floppy, sb_start_boot, sb_start_long_boot, sb_start_piggy, sb_start_att_dsdd, + 8192 / imagePlugin.Info.SectorSize, 65536 / imagePlugin.Info.SectorSize, + 262144 / imagePlugin.Info.SectorSize + ]; + + try + { + foreach(ulong loc in locations.Where(loc => partition.End > partition.Start + loc + sbSizeInSectors)) + { + ErrorNumber errno = + imagePlugin.ReadSectors(partition.Start + loc, sbSizeInSectors, out byte[] ufsSbSectors); + + if(errno != ErrorNumber.NoError) continue; + + var magic = BitConverter.ToUInt32(ufsSbSectors, 0x055C); + + if(magic is UFS_MAGIC + or UFS_CIGAM + or UFS_MAGIC_BW + or UFS_CIGAM_BW + or UFS2_MAGIC + or UFS2_CIGAM + or UFS_BAD_MAGIC + or UFS_BAD_CIGAM) + return true; + } + + return false; + } + catch(Exception) + { + return false; + } + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + var sbInformation = new StringBuilder(); + + uint magic = 0; + uint sb_size_in_sectors; + byte[] ufs_sb_sectors; + ulong sb_offset = partition.Start; + var fs_type_42bsd = false; + var fs_type_43bsd = false; + var fs_type_44bsd = false; + var fs_type_ufs = false; + var fs_type_ufs2 = false; + var fs_type_sun = false; + var fs_type_sun86 = false; + + if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448) + sb_size_in_sectors = block_size / 2048; + else + sb_size_in_sectors = block_size / imagePlugin.Info.SectorSize; + + ulong[] locations = + [ + sb_start_floppy, sb_start_boot, sb_start_long_boot, sb_start_piggy, sb_start_att_dsdd, + 8192 / imagePlugin.Info.SectorSize, 65536 / imagePlugin.Info.SectorSize, + 262144 / imagePlugin.Info.SectorSize + ]; + + ErrorNumber errno; + + foreach(ulong loc in locations.Where(loc => partition.End > partition.Start + loc + sb_size_in_sectors)) + { + errno = imagePlugin.ReadSectors(partition.Start + loc, sb_size_in_sectors, out ufs_sb_sectors); + + if(errno != ErrorNumber.NoError) continue; + + magic = BitConverter.ToUInt32(ufs_sb_sectors, 0x055C); + + if(magic is UFS_MAGIC + or UFS_CIGAM + or UFS_MAGIC_BW + or UFS_CIGAM_BW + or UFS2_MAGIC + or UFS2_CIGAM + or UFS_BAD_MAGIC + or UFS_BAD_CIGAM) + { + sb_offset = partition.Start + loc; + + break; + } + + magic = 0; + } + + if(magic == 0) + { + information = Localization.Not_a_UFS_filesystem_I_shouldnt_have_arrived_here; + + return; + } + + metadata = new FileSystem(); + + switch(magic) + { + case UFS_MAGIC: + sbInformation.AppendLine(Localization.UFS_filesystem); + metadata.Type = FS_TYPE_UFS; + + break; + case UFS_CIGAM: + sbInformation.AppendLine(Localization.Big_endian_UFS_filesystem); + metadata.Type = FS_TYPE_UFS; + + break; + case UFS_MAGIC_BW: + sbInformation.AppendLine(Localization.BorderWare_UFS_filesystem); + metadata.Type = FS_TYPE_UFS; + + break; + case UFS_CIGAM_BW: + sbInformation.AppendLine(Localization.Big_endian_BorderWare_UFS_filesystem); + metadata.Type = FS_TYPE_UFS; + + break; + case UFS2_MAGIC: + sbInformation.AppendLine(Localization.UFS2_filesystem); + metadata.Type = FS_TYPE_UFS2; + + break; + case UFS2_CIGAM: + sbInformation.AppendLine(Localization.Big_endian_UFS2_filesystem); + metadata.Type = FS_TYPE_UFS2; + + break; + case UFS_BAD_MAGIC: + sbInformation.AppendLine(Localization.Incompletely_initialized_UFS_filesystem); + sbInformation.AppendLine(Localization.BEWARE_Following_information_may_be_completely_wrong); + metadata.Type = FS_TYPE_UFS; + + break; + case UFS_BAD_CIGAM: + sbInformation.AppendLine(Localization.Incompletely_initialized_big_endian_UFS_filesystem); + sbInformation.AppendLine(Localization.BEWARE_Following_information_may_be_completely_wrong); + metadata.Type = FS_TYPE_UFS; + + break; + } + + // Fun with seeking follows on superblock reading! + errno = imagePlugin.ReadSectors(sb_offset, sb_size_in_sectors, out ufs_sb_sectors); + + if(errno != ErrorNumber.NoError) return; + + SuperBlock sb = Marshal.ByteArrayToStructureLittleEndian(ufs_sb_sectors); + + SuperBlock bs_sfu = Marshal.ByteArrayToStructureBigEndian(ufs_sb_sectors); + + if(bs_sfu.fs_magic == UFS_MAGIC && sb.fs_magic == UFS_CIGAM || + bs_sfu.fs_magic == UFS_MAGIC_BW && sb.fs_magic == UFS_CIGAM_BW || + bs_sfu.fs_magic == UFS2_MAGIC && sb.fs_magic == UFS2_CIGAM || + bs_sfu.fs_magic == UFS_BAD_MAGIC && sb.fs_magic == UFS_BAD_CIGAM) + { + sb = bs_sfu; + sb.fs_old_cstotal.cs_nbfree = Swapping.Swap(sb.fs_old_cstotal.cs_nbfree); + sb.fs_old_cstotal.cs_ndir = Swapping.Swap(sb.fs_old_cstotal.cs_ndir); + sb.fs_old_cstotal.cs_nffree = Swapping.Swap(sb.fs_old_cstotal.cs_nffree); + sb.fs_old_cstotal.cs_nifree = Swapping.Swap(sb.fs_old_cstotal.cs_nifree); + sb.fs_cstotal.cs_numclusters = Swapping.Swap(sb.fs_cstotal.cs_numclusters); + sb.fs_cstotal.cs_nbfree = Swapping.Swap(sb.fs_cstotal.cs_nbfree); + sb.fs_cstotal.cs_ndir = Swapping.Swap(sb.fs_cstotal.cs_ndir); + sb.fs_cstotal.cs_nffree = Swapping.Swap(sb.fs_cstotal.cs_nffree); + sb.fs_cstotal.cs_nifree = Swapping.Swap(sb.fs_cstotal.cs_nifree); + sb.fs_cstotal.cs_spare[0] = Swapping.Swap(sb.fs_cstotal.cs_spare[0]); + sb.fs_cstotal.cs_spare[1] = Swapping.Swap(sb.fs_cstotal.cs_spare[1]); + sb.fs_cstotal.cs_spare[2] = Swapping.Swap(sb.fs_cstotal.cs_spare[2]); + } + + AaruConsole.DebugWriteLine(MODULE_NAME, "sb offset: 0x{0:X8}", sb_offset); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_rlink: 0x{0:X8}", sb.fs_rlink); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_sblkno: 0x{0:X8}", sb.fs_sblkno); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_cblkno: 0x{0:X8}", sb.fs_cblkno); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_iblkno: 0x{0:X8}", sb.fs_iblkno); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_dblkno: 0x{0:X8}", sb.fs_dblkno); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_size: 0x{0:X8}", sb.fs_size); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_dsize: 0x{0:X8}", sb.fs_dsize); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_ncg: 0x{0:X8}", sb.fs_ncg); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_bsize: 0x{0:X8}", sb.fs_bsize); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fsize: 0x{0:X8}", sb.fs_fsize); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_frag: 0x{0:X8}", sb.fs_frag); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_minfree: 0x{0:X8}", sb.fs_minfree); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_bmask: 0x{0:X8}", sb.fs_bmask); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fmask: 0x{0:X8}", sb.fs_fmask); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_bshift: 0x{0:X8}", sb.fs_bshift); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fshift: 0x{0:X8}", sb.fs_fshift); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_maxcontig: 0x{0:X8}", sb.fs_maxcontig); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_maxbpg: 0x{0:X8}", sb.fs_maxbpg); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fragshift: 0x{0:X8}", sb.fs_fragshift); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fsbtodb: 0x{0:X8}", sb.fs_fsbtodb); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_sbsize: 0x{0:X8}", sb.fs_sbsize); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_csmask: 0x{0:X8}", sb.fs_csmask); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_csshift: 0x{0:X8}", sb.fs_csshift); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_nindir: 0x{0:X8}", sb.fs_nindir); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_inopb: 0x{0:X8}", sb.fs_inopb); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_optim: 0x{0:X8}", sb.fs_optim); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_id_1: 0x{0:X8}", sb.fs_id_1); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_id_2: 0x{0:X8}", sb.fs_id_2); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_csaddr: 0x{0:X8}", sb.fs_csaddr); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_cssize: 0x{0:X8}", sb.fs_cssize); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_cgsize: 0x{0:X8}", sb.fs_cgsize); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_ipg: 0x{0:X8}", sb.fs_ipg); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fpg: 0x{0:X8}", sb.fs_fpg); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fmod: 0x{0:X2}", sb.fs_fmod); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_clean: 0x{0:X2}", sb.fs_clean); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_ronly: 0x{0:X2}", sb.fs_ronly); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_flags: 0x{0:X2}", sb.fs_flags); + AaruConsole.DebugWriteLine(MODULE_NAME, "fs_magic: 0x{0:X8}", sb.fs_magic); + + if(sb.fs_magic == UFS2_MAGIC) + fs_type_ufs2 = true; + else + { + const uint + SunOSEpoch = 0x1A54C580; // We are supposing there cannot be a Sun's fs created before 1/1/1982 00:00:00 + + fs_type_43bsd = true; // There is no way of knowing this is the version, but there is of knowing it is not. + + if(sb.fs_link > 0) + { + fs_type_42bsd = true; // It was used in 4.2BSD + fs_type_43bsd = false; + } + + if((sb.fs_maxfilesize & 0xFFFFFFFF) > SunOSEpoch && + DateHandlers.UnixUnsignedToDateTime(sb.fs_maxfilesize & 0xFFFFFFFF) < DateTime.Now) + { + fs_type_42bsd = false; + fs_type_sun = true; + fs_type_43bsd = false; + } + + // This is for sure, as it is shared with a sectors/track with non-x86 SunOS, Epoch is absurdly high for that + if(sb.fs_old_npsect > SunOSEpoch && DateHandlers.UnixToDateTime(sb.fs_old_npsect) < DateTime.Now) + { + fs_type_42bsd = false; + fs_type_sun86 = true; + fs_type_sun = false; + fs_type_43bsd = false; + } + + if(sb.fs_cgrotor > 0x00000000 && (uint)sb.fs_cgrotor < 0xFFFFFFFF) + { + fs_type_42bsd = false; + fs_type_sun = false; + fs_type_sun86 = false; + fs_type_ufs = true; + fs_type_43bsd = false; + } + + // 4.3BSD code does not use these fields, they are always set up to 0 + fs_type_43bsd &= sb is { fs_id_2: 0, fs_id_1: 0 }; + + // This is the only 4.4BSD inode format + fs_type_44bsd |= sb.fs_old_inodefmt == 2; + } + + if(!fs_type_ufs2) + { + sbInformation.AppendLine(Localization + .There_are_a_lot_of_variants_of_UFS_using_overlapped_values_on_same_fields); + + sbInformation.AppendLine(Localization + .I_will_try_to_guess_which_one_it_is_but_unless_its_UFS2_I_may_be_surely_wrong); + } + + if(fs_type_42bsd) sbInformation.AppendLine(Localization.Guessed_as_42BSD_FFS); + + if(fs_type_43bsd) sbInformation.AppendLine(Localization.Guessed_as_43BSD_FFS); + + if(fs_type_44bsd) sbInformation.AppendLine(Localization.Guessed_as_44BSD_FFS); + + if(fs_type_sun) sbInformation.AppendLine(Localization.Guessed_as_SunOS_FFS); + + if(fs_type_sun86) sbInformation.AppendLine(Localization.Guessed_as_SunOS_x86_FFS); + + if(fs_type_ufs) sbInformation.AppendLine(Localization.Guessed_as_UFS); + + if(fs_type_42bsd) + sbInformation.AppendFormat(Localization.Linked_list_of_filesystems_0, sb.fs_link).AppendLine(); + + sbInformation.AppendFormat(Localization.Superblock_LBA_0, sb.fs_sblkno).AppendLine(); + sbInformation.AppendFormat(Localization.Cylinder_block_LBA_0, sb.fs_cblkno).AppendLine(); + sbInformation.AppendFormat(Localization.inode_block_LBA_0, sb.fs_iblkno).AppendLine(); + sbInformation.AppendFormat(Localization.First_data_block_LBA_0, sb.fs_dblkno).AppendLine(); + sbInformation.AppendFormat(Localization.Cylinder_group_offset_in_cylinder_0, sb.fs_old_cgoffset).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_last_written_on_0, DateHandlers.UnixToDateTime(sb.fs_old_time)) + .AppendLine(); + + metadata.ModificationDate = DateHandlers.UnixToDateTime(sb.fs_old_time); + + sbInformation.AppendFormat(Localization._0_blocks_in_volume_1_bytes, + sb.fs_old_size, + (long)sb.fs_old_size * sb.fs_fsize) + .AppendLine(); + + metadata.Clusters = (ulong)sb.fs_old_size; + metadata.ClusterSize = (uint)sb.fs_fsize; + + sbInformation.AppendFormat(Localization._0_data_blocks_in_volume_1_bytes, + sb.fs_old_dsize, + (long)sb.fs_old_dsize * sb.fs_fsize) + .AppendLine(); + + sbInformation.AppendFormat(Localization._0_cylinder_groups_in_volume, sb.fs_ncg).AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_in_a_basic_block, sb.fs_bsize).AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_in_a_frag_block, sb.fs_fsize).AppendLine(); + sbInformation.AppendFormat(Localization._0_frags_in_a_block, sb.fs_frag).AppendLine(); + sbInformation.AppendFormat(Localization._0_of_blocks_must_be_free, sb.fs_minfree).AppendLine(); + sbInformation.AppendFormat(Localization._0_ms_for_optimal_next_block, sb.fs_old_rotdelay).AppendLine(); + + sbInformation + .AppendFormat(Localization.Disk_rotates_0_times_per_second_1_rpm, sb.fs_old_rps, sb.fs_old_rps * 60) + .AppendLine(); + + /* sbInformation.AppendFormat("fs_bmask: 0x{0:X8}", sb.fs_bmask).AppendLine(); + sbInformation.AppendFormat("fs_fmask: 0x{0:X8}", sb.fs_fmask).AppendLine(); + sbInformation.AppendFormat("fs_bshift: 0x{0:X8}", sb.fs_bshift).AppendLine(); + sbInformation.AppendFormat("fs_fshift: 0x{0:X8}", sb.fs_fshift).AppendLine();*/ + sbInformation.AppendFormat(Localization._0_contiguous_blocks_at_maximum, sb.fs_maxcontig).AppendLine(); + sbInformation.AppendFormat(Localization._0_blocks_per_cylinder_group_at_maximum, sb.fs_maxbpg).AppendLine(); + sbInformation.AppendFormat(Localization.Superblock_is_0_bytes, sb.fs_sbsize).AppendLine(); + sbInformation.AppendFormat(Localization.NINDIR_0, sb.fs_nindir).AppendLine(); + sbInformation.AppendFormat(Localization.INOPB_0, sb.fs_inopb).AppendLine(); + sbInformation.AppendFormat(Localization.NSPF_0, sb.fs_old_nspf).AppendLine(); + + switch(sb.fs_optim) + { + case 0: + sbInformation.AppendLine(Localization.Filesystem_will_minimize_allocation_time); + + break; + case 1: + sbInformation.AppendLine(Localization.Filesystem_will_minimize_volume_fragmentation); + + break; + default: + sbInformation.AppendFormat(Localization.Unknown_optimization_value_0, sb.fs_optim).AppendLine(); + + break; + } + + if(fs_type_sun) + sbInformation.AppendFormat(Localization._0_sectors_track, sb.fs_old_npsect).AppendLine(); + else if(fs_type_sun86) + { + sbInformation.AppendFormat(Localization.Volume_state_on_0, DateHandlers.UnixToDateTime(sb.fs_old_npsect)) + .AppendLine(); + } + + sbInformation.AppendFormat(Localization.Hardware_sector_interleave_0, sb.fs_old_interleave).AppendLine(); + sbInformation.AppendFormat(Localization.Sector_zero_skew_0_track, sb.fs_old_trackskew).AppendLine(); + + switch(fs_type_43bsd) + { + case false when sb is { fs_id_1: > 0, fs_id_2: > 0 }: + sbInformation.AppendFormat(Localization.Volume_ID_0_X8_1_X8, sb.fs_id_1, sb.fs_id_2).AppendLine(); + + break; + case true when sb is { fs_id_1: > 0, fs_id_2: > 0 }: + sbInformation.AppendFormat(Localization._0_µsec_for_head_switch, sb.fs_id_1).AppendLine(); + sbInformation.AppendFormat(Localization._0_µsec_for_track_to_track_seek, sb.fs_id_2).AppendLine(); + + break; + } + + sbInformation.AppendFormat(Localization.Cylinder_group_summary_LBA_0, sb.fs_old_csaddr).AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_in_cylinder_group_summary, sb.fs_cssize).AppendLine(); + sbInformation.AppendFormat(Localization._0_bytes_in_cylinder_group, sb.fs_cgsize).AppendLine(); + sbInformation.AppendFormat(Localization._0_tracks_cylinder, sb.fs_old_ntrak).AppendLine(); + sbInformation.AppendFormat(Localization._0_sectors_track, sb.fs_old_nsect).AppendLine(); + sbInformation.AppendFormat(Localization._0_sectors_cylinder, sb.fs_old_spc).AppendLine(); + sbInformation.AppendFormat(Localization._0_cylinders_in_volume, sb.fs_old_ncyl).AppendLine(); + sbInformation.AppendFormat(Localization._0_cylinders_group, sb.fs_old_cpg).AppendLine(); + sbInformation.AppendFormat(Localization._0_inodes_per_cylinder_group, sb.fs_ipg).AppendLine(); + sbInformation.AppendFormat(Localization._0_blocks_per_group, sb.fs_fpg / sb.fs_frag).AppendLine(); + sbInformation.AppendFormat(Localization._0_directories, sb.fs_old_cstotal.cs_ndir).AppendLine(); + + sbInformation.AppendFormat(Localization._0_free_blocks_1_bytes, + sb.fs_old_cstotal.cs_nbfree, + (long)sb.fs_old_cstotal.cs_nbfree * sb.fs_fsize) + .AppendLine(); + + metadata.FreeClusters = (ulong)sb.fs_old_cstotal.cs_nbfree; + sbInformation.AppendFormat(Localization._0_free_inodes, sb.fs_old_cstotal.cs_nifree).AppendLine(); + sbInformation.AppendFormat(Localization._0_free_frags, sb.fs_old_cstotal.cs_nffree).AppendLine(); + + if(sb.fs_fmod == 1) + { + sbInformation.AppendLine(Localization.Superblock_is_being_modified); + metadata.Dirty = true; + } + + if(sb.fs_clean == 1) sbInformation.AppendLine(Localization.Volume_is_clean); + + if(sb.fs_ronly == 1) sbInformation.AppendLine(Localization.Volume_is_read_only); + + sbInformation.AppendFormat(Localization.Volume_flags_0_X2, sb.fs_flags).AppendLine(); + + if(fs_type_ufs) + { + sbInformation.AppendFormat(Localization.Volume_last_mounted_at_0, StringHandlers.CToString(sb.fs_fsmnt)) + .AppendLine(); + } + else if(fs_type_ufs2) + { + sbInformation.AppendFormat(Localization.Volume_last_mounted_at_0, StringHandlers.CToString(sb.fs_fsmnt)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(sb.fs_volname)) + .AppendLine(); + + metadata.VolumeName = StringHandlers.CToString(sb.fs_volname); + sbInformation.AppendFormat(Localization.Volume_ID_0_X16, sb.fs_swuid).AppendLine(); + + //xmlFSType.VolumeSerial = string.Format("{0:X16}", sb.fs_swuid); + sbInformation.AppendFormat(Localization.Last_searched_cylinder_group_0, sb.fs_cgrotor).AppendLine(); + + sbInformation.AppendFormat(Localization._0_contiguously_allocated_directories, sb.fs_contigdirs) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Standard_superblock_LBA_0, sb.fs_sblkno).AppendLine(); + sbInformation.AppendFormat(Localization._0_directories, sb.fs_cstotal.cs_ndir).AppendLine(); + + sbInformation.AppendFormat(Localization._0_free_blocks_1_bytes, + sb.fs_cstotal.cs_nbfree, + sb.fs_cstotal.cs_nbfree * sb.fs_fsize) + .AppendLine(); + + metadata.FreeClusters = (ulong)sb.fs_cstotal.cs_nbfree; + sbInformation.AppendFormat(Localization._0_free_inodes, sb.fs_cstotal.cs_nifree).AppendLine(); + sbInformation.AppendFormat(Localization._0_free_frags, sb.fs_cstotal.cs_nffree).AppendLine(); + sbInformation.AppendFormat(Localization._0_free_clusters, sb.fs_cstotal.cs_numclusters).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_last_written_on_0, DateHandlers.UnixToDateTime(sb.fs_time)) + .AppendLine(); + + metadata.ModificationDate = DateHandlers.UnixToDateTime(sb.fs_time); + + sbInformation.AppendFormat(Localization._0_blocks_1_bytes, sb.fs_size, sb.fs_size * sb.fs_fsize) + .AppendLine(); + + metadata.Clusters = (ulong)sb.fs_size; + + sbInformation.AppendFormat(Localization._0_data_blocks_1_bytes, sb.fs_dsize, sb.fs_dsize * sb.fs_fsize) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Cylinder_group_summary_area_LBA_0, sb.fs_csaddr).AppendLine(); + sbInformation.AppendFormat(Localization._0_blocks_pending_of_being_freed, sb.fs_pendingblocks).AppendLine(); + sbInformation.AppendFormat(Localization._0_inodes_pending_of_being_freed, sb.fs_pendinginodes).AppendLine(); + } + + if(fs_type_sun) + { + sbInformation.AppendFormat(Localization.Volume_state_on_0, DateHandlers.UnixToDateTime(sb.fs_old_npsect)) + .AppendLine(); + } + else if(fs_type_sun86) + sbInformation.AppendFormat(Localization._0_sectors_track, sb.fs_state).AppendLine(); + else if(fs_type_44bsd) + { + sbInformation.AppendFormat(Localization._0_blocks_on_cluster_summary_array, sb.fs_contigsumsize) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Maximum_length_of_a_symbolic_link_0, sb.fs_maxsymlinklen) + .AppendLine(); + + sbInformation.AppendFormat(Localization.A_file_can_be_0_bytes_at_max, sb.fs_maxfilesize).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_state_on_0, DateHandlers.UnixToDateTime(sb.fs_state)) + .AppendLine(); + } + + if(sb.fs_old_nrpos > 0) + sbInformation.AppendFormat(Localization._0_rotational_positions, sb.fs_old_nrpos).AppendLine(); + + if(sb.fs_old_rotbloff > 0) + sbInformation.AppendFormat(Localization._0_blocks_per_rotation, sb.fs_old_rotbloff).AppendLine(); + + information = sbInformation.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/FFS/Structs.cs b/Aaru.Filesystems/FFS/Structs.cs new file mode 100644 index 000000000..50aeae050 --- /dev/null +++ b/Aaru.Filesystems/FFS/Structs.cs @@ -0,0 +1,302 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : BSD Fast File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Using information from Linux kernel headers +/// +/// Implements detection of BSD Fast File System (FFS, aka UNIX File System) +[SuppressMessage("ReSharper", "InconsistentNaming")] +public sealed partial class FFSPlugin +{ +#region Nested type: Checksum + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Checksum + { + /// number of directories + public int cs_ndir; + /// number of free blocks + public int cs_nbfree; + /// number of free inodes + public int cs_nifree; + /// number of free frags + public int cs_nffree; + } + +#endregion + +#region Nested type: csum_total + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct csum_total + { + /// number of directories + public long cs_ndir; + /// number of free blocks + public long cs_nbfree; + /// number of free inodes + public long cs_nifree; + /// number of free frags + public long cs_nffree; + /// number of free clusters + public long cs_numclusters; + /// future expansion + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly long[] cs_spare; + } + +#endregion + +#region Nested type: SuperBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SuperBlock + { + /// linked list of file systems + public readonly uint fs_link; + /// used for incore super blocks on Sun: uint fs_rolled; // logging only: fs fully rolled + public readonly uint fs_rlink; + /// addr of super-block in filesys + public readonly int fs_sblkno; + /// offset of cyl-block in filesys + public readonly int fs_cblkno; + /// offset of inode-blocks in filesys + public readonly int fs_iblkno; + /// offset of first data after cg + public readonly int fs_dblkno; + /// cylinder group offset in cylinder + public readonly int fs_old_cgoffset; + /// used to calc mod fs_ntrak + public readonly int fs_old_cgmask; + /// last time written + public readonly int fs_old_time; + /// number of blocks in fs + public readonly int fs_old_size; + /// number of data blocks in fs + public readonly int fs_old_dsize; + /// number of cylinder groups + public readonly int fs_ncg; + /// size of basic blocks in fs + public readonly int fs_bsize; + /// size of frag blocks in fs + public readonly int fs_fsize; + /// number of frags in a block in fs + public readonly int fs_frag; + /* these are configuration parameters */ + /// minimum percentage of free blocks + public readonly int fs_minfree; + /// num of ms for optimal next block + public readonly int fs_old_rotdelay; + /// disk revolutions per second + public readonly int fs_old_rps; + /* these fields can be computed from the others */ + /// ``blkoff'' calc of blk offsets + public readonly int fs_bmask; + /// ``fragoff'' calc of frag offsets + public readonly int fs_fmask; + /// ``lblkno'' calc of logical blkno + public readonly int fs_bshift; + /// ``numfrags'' calc number of frags + public readonly int fs_fshift; + /* these are configuration parameters */ + /// max number of contiguous blks + public readonly int fs_maxcontig; + /// max number of blks per cyl group + public readonly int fs_maxbpg; + /* these fields can be computed from the others */ + /// block to frag shift + public readonly int fs_fragshift; + /// fsbtodb and dbtofsb shift constant + public readonly int fs_fsbtodb; + /// actual size of super block + public readonly int fs_sbsize; + /// csum block offset + public readonly int fs_csmask; + /// csum block number + public readonly int fs_csshift; + /// value of NINDIR + public readonly int fs_nindir; + /// value of INOPB + public readonly uint fs_inopb; + /// value of NSPF + public readonly int fs_old_nspf; + /* yet another configuration parameter */ + /// optimization preference, see below On SVR: int fs_state; // file system state + public readonly int fs_optim; + /// # sectors/track including spares + public readonly int fs_old_npsect; + /// hardware sector interleave + public readonly int fs_old_interleave; + /// sector 0 skew, per track On A/UX: int fs_state; // file system state + public readonly int fs_old_trackskew; + /// unique filesystem id On old: int fs_headswitch; // head switch time, usec + public readonly int fs_id_1; + /// unique filesystem id On old: int fs_trkseek; // track-to-track seek, usec + public readonly int fs_id_2; + /* sizes determined by number of cylinder groups and their sizes */ + /// blk addr of cyl grp summary area + public readonly int fs_old_csaddr; + /// size of cyl grp summary area + public readonly int fs_cssize; + /// cylinder group size + public readonly int fs_cgsize; + /* these fields are derived from the hardware */ + /// tracks per cylinder + public readonly int fs_old_ntrak; + /// sectors per track + public readonly int fs_old_nsect; + /// sectors per cylinder + public readonly int fs_old_spc; + /* this comes from the disk driver partitioning */ + /// cylinders in filesystem + public readonly int fs_old_ncyl; + /* these fields can be computed from the others */ + /// cylinders per group + public readonly int fs_old_cpg; + /// inodes per group + public readonly int fs_ipg; + /// blocks per group * fs_frag + public readonly int fs_fpg; + /* this data must be re-computed after crashes */ + /// cylinder summary information + public Checksum fs_old_cstotal; + /* these fields are cleared at mount time */ + /// super block modified flag + public readonly sbyte fs_fmod; + /// filesystem is clean flag + public readonly sbyte fs_clean; + /// mounted read-only flag + public readonly sbyte fs_ronly; + /// old FS_ flags + public readonly sbyte fs_old_flags; + /// name mounted on + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 468)] + public readonly byte[] fs_fsmnt; + /// volume name + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] fs_volname; + /// system-wide uid + public readonly ulong fs_swuid; + /// due to alignment of fs_swuid + public readonly int fs_pad; + /* these fields retain the current block allocation info */ + /// last cg searched + public readonly int fs_cgrotor; + /// padding; was list of fs_cs buffers + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] + public readonly uint[] fs_ocsp; + /// (u) # of contig. allocated dirs + public readonly uint fs_contigdirs; + /// (u) cg summary info buffer + public readonly uint fs_csp; + /// (u) max cluster in each cyl group + public readonly uint fs_maxcluster; + /// (u) used by snapshots to track fs + public readonly uint fs_active; + /// cyl per cycle in postbl + public readonly int fs_old_cpc; + /// maximum blocking factor permitted + public readonly int fs_maxbsize; + /// number of unreferenced inodes + public readonly long fs_unrefs; + /// size of underlying GEOM provider + public readonly long fs_providersize; + /// size of area reserved for metadata + public readonly long fs_metaspace; + /// old rotation block list head + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] + public readonly long[] fs_sparecon64; + /// byte offset of standard superblock + public readonly long fs_sblockloc; + /// (u) cylinder summary information + public csum_total fs_cstotal; + /// last time written + public readonly long fs_time; + /// number of blocks in fs + public readonly long fs_size; + /// number of data blocks in fs + public readonly long fs_dsize; + /// blk addr of cyl grp summary area + public readonly long fs_csaddr; + /// (u) blocks being freed + public readonly long fs_pendingblocks; + /// (u) inodes being freed + public readonly uint fs_pendinginodes; + /// list of snapshot inode numbers + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public readonly uint[] fs_snapinum; + /// expected average file size + public readonly uint fs_avgfilesize; + /// expected # of files per directory + public readonly uint fs_avgfpdir; + /// save real cg size to use fs_bsize + public readonly int fs_save_cgsize; + /// Last mount or fsck time. + public readonly long fs_mtime; + /// SUJ free list + public readonly int fs_sujfree; + /// reserved for future constants + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 23)] + public readonly int[] fs_sparecon32; + /// see FS_ flags below + public readonly int fs_flags; + /// size of cluster summary array + public readonly int fs_contigsumsize; + /// max length of an internal symlink + public readonly int fs_maxsymlinklen; + /// format of on-disk inodes + public readonly int fs_old_inodefmt; + /// maximum representable file size + public readonly ulong fs_maxfilesize; + /// ~fs_bmask for use with 64-bit size + public readonly long fs_qbmask; + /// ~fs_fmask for use with 64-bit size + public readonly long fs_qfmask; + /// validate fs_clean field + public readonly int fs_state; + /// format of positional layout tables + public readonly int fs_old_postblformat; + /// number of rotational positions + public readonly int fs_old_nrpos; + /// (short) rotation block list head + public readonly int fs_old_postbloff; + /// (uchar_t) blocks for each rotation + public readonly int fs_old_rotbloff; + /// magic number + public readonly uint fs_magic; + /// list of blocks for each rotation + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public readonly byte[] fs_rotbl; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Fossil.cs b/Aaru.Filesystems/Fossil.cs deleted file mode 100644 index 427df7ae8..000000000 --- a/Aaru.Filesystems/Fossil.cs +++ /dev/null @@ -1,198 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Fossil.cs -// Author(s) : Natalia Portillo -// -// Component : Fossil filesystem plugin -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Fossil filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection for the Plan-9 Fossil on-disk filesystem -public sealed class Fossil : IFilesystem -{ - const uint FOSSIL_HDR_MAGIC = 0x3776AE89; - const uint FOSSIL_SB_MAGIC = 0x2340A3B1; - - // Fossil header starts at 128KiB - const ulong HEADER_POS = 128 * 1024; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Fossil Filesystem Plugin"; - /// - public Guid Id => new("932BF104-43F6-494F-973C-45EF58A51DA9"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - ulong hdrSector = HEADER_POS / imagePlugin.Info.SectorSize; - - if(partition.Start + hdrSector > imagePlugin.Info.Sectors) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start + hdrSector, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - Header hdr = Marshal.ByteArrayToStructureBigEndian
(sector); - - AaruConsole.DebugWriteLine("Fossil plugin", "magic at 0x{0:X8} (expected 0x{1:X8})", hdr.magic, - FOSSIL_HDR_MAGIC); - - return hdr.magic == FOSSIL_HDR_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - // Technically everything on Plan 9 from Bell Labs is in UTF-8 - Encoding = Encoding.UTF8; - information = ""; - - if(imagePlugin.Info.SectorSize < 512) - return; - - ulong hdrSector = HEADER_POS / imagePlugin.Info.SectorSize; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start + hdrSector, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - Header hdr = Marshal.ByteArrayToStructureBigEndian
(sector); - - AaruConsole.DebugWriteLine("Fossil plugin", "magic at 0x{0:X8} (expected 0x{1:X8})", hdr.magic, - FOSSIL_HDR_MAGIC); - - var sb = new StringBuilder(); - - sb.AppendLine("Fossil"); - sb.AppendFormat("Filesystem version {0}", hdr.version).AppendLine(); - sb.AppendFormat("{0} bytes per block", hdr.blockSize).AppendLine(); - sb.AppendFormat("Superblock resides in block {0}", hdr.super).AppendLine(); - sb.AppendFormat("Labels resides in block {0}", hdr.label).AppendLine(); - sb.AppendFormat("Data starts at block {0}", hdr.data).AppendLine(); - sb.AppendFormat("Volume has {0} blocks", hdr.end).AppendLine(); - - ulong sbLocation = hdr.super * (hdr.blockSize / imagePlugin.Info.SectorSize) + partition.Start; - - XmlFsType = new FileSystemType - { - Type = "Fossil filesystem", - ClusterSize = hdr.blockSize, - Clusters = hdr.end - }; - - if(sbLocation <= partition.End) - { - imagePlugin.ReadSector(sbLocation, out sector); - SuperBlock fsb = Marshal.ByteArrayToStructureBigEndian(sector); - - AaruConsole.DebugWriteLine("Fossil plugin", "magic 0x{0:X8} (expected 0x{1:X8})", fsb.magic, - FOSSIL_SB_MAGIC); - - if(fsb.magic == FOSSIL_SB_MAGIC) - { - sb.AppendFormat("Epoch low {0}", fsb.epochLow).AppendLine(); - sb.AppendFormat("Epoch high {0}", fsb.epochHigh).AppendLine(); - sb.AppendFormat("Next QID {0}", fsb.qid).AppendLine(); - sb.AppendFormat("Active root block {0}", fsb.active).AppendLine(); - sb.AppendFormat("Next root block {0}", fsb.next).AppendLine(); - sb.AppendFormat("Current root block {0}", fsb.current).AppendLine(); - sb.AppendFormat("Volume label: \"{0}\"", StringHandlers.CToString(fsb.name, Encoding)).AppendLine(); - XmlFsType.VolumeName = StringHandlers.CToString(fsb.name, Encoding); - } - } - - information = sb.ToString(); - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Header - { - /// Magic number - public readonly uint magic; - /// Header version - public readonly ushort version; - /// Block size - public readonly ushort blockSize; - /// Block containing superblock - public readonly uint super; - /// Block containing labels - public readonly uint label; - /// Where do data blocks start - public readonly uint data; - /// How many data blocks does it have - public readonly uint end; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SuperBlock - { - /// Magic number - public readonly uint magic; - /// Header version - public readonly ushort version; - /// file system low epoch - public readonly uint epochLow; - /// file system high(active) epoch - public readonly uint epochHigh; - /// next qid to allocate - public readonly ulong qid; - /// data block number: root of active file system - public readonly int active; - /// data block number: root of next file system to archive - public readonly int next; - /// data block number: root of file system currently being archived - public readonly int current; - /// Venti score of last successful archive - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public readonly byte[] last; - /// name of file system(just a comment) - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public readonly byte[] name; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/Fossil/Consts.cs b/Aaru.Filesystems/Fossil/Consts.cs new file mode 100644 index 000000000..7f290d183 --- /dev/null +++ b/Aaru.Filesystems/Fossil/Consts.cs @@ -0,0 +1,42 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Fossil filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the Plan-9 Fossil on-disk filesystem +public sealed partial class Fossil +{ + const uint FOSSIL_HDR_MAGIC = 0x3776AE89; + const uint FOSSIL_SB_MAGIC = 0x2340A3B1; + + // Fossil header starts at 128KiB + const ulong HEADER_POS = 128 * 1024; + + const string FS_TYPE = "fossil"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/Fossil/Fossil.cs b/Aaru.Filesystems/Fossil/Fossil.cs new file mode 100644 index 000000000..2ee051b99 --- /dev/null +++ b/Aaru.Filesystems/Fossil/Fossil.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Fossil.cs +// Author(s) : Natalia Portillo +// +// Component : Fossil filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the Plan-9 Fossil on-disk filesystem +public sealed partial class Fossil : IFilesystem +{ + const string MODULE_NAME = "Fossil plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.Fossil_Name; + + /// + public Guid Id => new("932BF104-43F6-494F-973C-45EF58A51DA9"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Fossil/Info.cs b/Aaru.Filesystems/Fossil/Info.cs new file mode 100644 index 000000000..69336392d --- /dev/null +++ b/Aaru.Filesystems/Fossil/Info.cs @@ -0,0 +1,127 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Fossil filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the Plan-9 Fossil on-disk filesystem +public sealed partial class Fossil +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + ulong hdrSector = HEADER_POS / imagePlugin.Info.SectorSize; + + if(partition.Start + hdrSector > imagePlugin.Info.Sectors) return false; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start + hdrSector, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + Header hdr = Marshal.ByteArrayToStructureBigEndian
(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.magic_at_0_expected_1, hdr.magic, FOSSIL_HDR_MAGIC); + + return hdr.magic == FOSSIL_HDR_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + // Technically everything on Plan 9 from Bell Labs is in UTF-8 + encoding = Encoding.UTF8; + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize < 512) return; + + ulong hdrSector = HEADER_POS / imagePlugin.Info.SectorSize; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start + hdrSector, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + Header hdr = Marshal.ByteArrayToStructureBigEndian
(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.magic_at_0_expected_1, hdr.magic, FOSSIL_HDR_MAGIC); + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Fossil_filesystem); + sb.AppendFormat(Localization.Filesystem_version_0, hdr.version).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_block, hdr.blockSize).AppendLine(); + sb.AppendFormat(Localization.Superblock_resides_in_block_0, hdr.super).AppendLine(); + sb.AppendFormat(Localization.Labels_resides_in_block_0, hdr.label).AppendLine(); + sb.AppendFormat(Localization.Data_starts_at_block_0, hdr.data).AppendLine(); + sb.AppendFormat(Localization.Volume_has_0_blocks, hdr.end).AppendLine(); + + ulong sbLocation = hdr.super * (hdr.blockSize / imagePlugin.Info.SectorSize) + partition.Start; + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = hdr.blockSize, + Clusters = hdr.end + }; + + if(sbLocation <= partition.End) + { + imagePlugin.ReadSector(sbLocation, out sector); + SuperBlock fsb = Marshal.ByteArrayToStructureBigEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.magic_0_expected_1, fsb.magic, FOSSIL_SB_MAGIC); + + if(fsb.magic == FOSSIL_SB_MAGIC) + { + sb.AppendFormat(Localization.Epoch_low_0, fsb.epochLow).AppendLine(); + sb.AppendFormat(Localization.Epoch_high_0, fsb.epochHigh).AppendLine(); + sb.AppendFormat(Localization.Next_QID_0, fsb.qid).AppendLine(); + sb.AppendFormat(Localization.Active_root_block_0, fsb.active).AppendLine(); + sb.AppendFormat(Localization.Next_root_block_0, fsb.next).AppendLine(); + sb.AppendFormat(Localization.Current_root_block_0, fsb.current).AppendLine(); + sb.AppendFormat(Localization.Volume_label_0, StringHandlers.CToString(fsb.name, encoding)).AppendLine(); + metadata.VolumeName = StringHandlers.CToString(fsb.name, encoding); + } + } + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Fossil/Structs.cs b/Aaru.Filesystems/Fossil/Structs.cs new file mode 100644 index 000000000..6680ec5ad --- /dev/null +++ b/Aaru.Filesystems/Fossil/Structs.cs @@ -0,0 +1,90 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Fossil filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the Plan-9 Fossil on-disk filesystem +public sealed partial class Fossil +{ +#region Nested type: Header + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Header + { + /// Magic number + public readonly uint magic; + /// Header version + public readonly ushort version; + /// Block size + public readonly ushort blockSize; + /// Block containing superblock + public readonly uint super; + /// Block containing labels + public readonly uint label; + /// Where do data blocks start + public readonly uint data; + /// How many data blocks does it have + public readonly uint end; + } + +#endregion + +#region Nested type: SuperBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SuperBlock + { + /// Magic number + public readonly uint magic; + /// Header version + public readonly ushort version; + /// file system low epoch + public readonly uint epochLow; + /// file system high(active) epoch + public readonly uint epochHigh; + /// next qid to allocate + public readonly ulong qid; + /// data block number: root of active file system + public readonly int active; + /// data block number: root of next file system to archive + public readonly int next; + /// data block number: root of file system currently being archived + public readonly int current; + /// Venti score of last successful archive + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public readonly byte[] last; + /// name of file system(just a comment) + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public readonly byte[] name; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/HAMMER/Consts.cs b/Aaru.Filesystems/HAMMER/Consts.cs new file mode 100644 index 000000000..40fe4ec5d --- /dev/null +++ b/Aaru.Filesystems/HAMMER/Consts.cs @@ -0,0 +1,43 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : HAMMER filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +#pragma warning disable 169 + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the HAMMER filesystem +public sealed partial class HAMMER +{ + const ulong HAMMER_FSBUF_VOLUME = 0xC8414D4DC5523031; + const ulong HAMMER_FSBUF_VOLUME_REV = 0x313052C54D4D41C8; + const uint HAMMER_VOLHDR_SIZE = 1928; + const int HAMMER_BIGBLOCK_SIZE = 8192 * 1024; + + const string FS_TYPE = "hammer"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/HAMMER/HAMMER.cs b/Aaru.Filesystems/HAMMER/HAMMER.cs new file mode 100644 index 000000000..1e6af938b --- /dev/null +++ b/Aaru.Filesystems/HAMMER/HAMMER.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : HAMMER.cs +// Author(s) : Natalia Portillo +// +// Component : HAMMER filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +#pragma warning disable 169 + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the HAMMER filesystem +public sealed partial class HAMMER : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.HAMMER_Name; + + /// + public Guid Id => new("91A188BF-5FD7-4677-BBD3-F59EBA9C864D"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/HAMMER/Info.cs b/Aaru.Filesystems/HAMMER/Info.cs new file mode 100644 index 000000000..593a56012 --- /dev/null +++ b/Aaru.Filesystems/HAMMER/Info.cs @@ -0,0 +1,142 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : HAMMER filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +#pragma warning disable 169 + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the HAMMER filesystem +public sealed partial class HAMMER +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + uint run = HAMMER_VOLHDR_SIZE / imagePlugin.Info.SectorSize; + + if(HAMMER_VOLHDR_SIZE % imagePlugin.Info.SectorSize > 0) run++; + + if(run + partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, run, out byte[] sbSector); + + if(errno != ErrorNumber.NoError) return false; + + var magic = BitConverter.ToUInt64(sbSector, 0); + + return magic is HAMMER_FSBUF_VOLUME or HAMMER_FSBUF_VOLUME_REV; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + uint run = HAMMER_VOLHDR_SIZE / imagePlugin.Info.SectorSize; + + if(HAMMER_VOLHDR_SIZE % imagePlugin.Info.SectorSize > 0) run++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, run, out byte[] sbSector); + + if(errno != ErrorNumber.NoError) return; + + var magic = BitConverter.ToUInt64(sbSector, 0); + + SuperBlock superBlock = magic == HAMMER_FSBUF_VOLUME + ? Marshal.ByteArrayToStructureLittleEndian(sbSector) + : Marshal.ByteArrayToStructureBigEndian(sbSector); + + sb.AppendLine(Localization.HAMMER_filesystem); + + sb.AppendFormat(Localization.Volume_version_0, superBlock.vol_version).AppendLine(); + + sb.AppendFormat(Localization.Volume_0_of_1_on_this_filesystem, superBlock.vol_no + 1, superBlock.vol_count) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(superBlock.vol_label, encoding)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_serial_0, superBlock.vol_fsid).AppendLine(); + sb.AppendFormat(Localization.Filesystem_type_0, superBlock.vol_fstype).AppendLine(); + sb.AppendFormat(Localization.Boot_area_starts_at_0, superBlock.vol_bot_beg).AppendLine(); + sb.AppendFormat(Localization.Memory_log_starts_at_0, superBlock.vol_mem_beg).AppendLine(); + sb.AppendFormat(Localization.First_volume_buffer_starts_at_0, superBlock.vol_buf_beg).AppendLine(); + sb.AppendFormat(Localization.Volume_ends_at_0, superBlock.vol_buf_end).AppendLine(); + + metadata = new FileSystem + { + Clusters = partition.Size / HAMMER_BIGBLOCK_SIZE, + ClusterSize = HAMMER_BIGBLOCK_SIZE, + Dirty = false, + Type = FS_TYPE, + VolumeName = StringHandlers.CToString(superBlock.vol_label, encoding), + VolumeSerial = superBlock.vol_fsid.ToString() + }; + + if(superBlock.vol_no == superBlock.vol_rootvol) + { + sb.AppendFormat(Localization.Filesystem_contains_0_big_blocks_1_bytes, + superBlock.vol0_stat_bigblocks, + superBlock.vol0_stat_bigblocks * HAMMER_BIGBLOCK_SIZE) + .AppendLine(); + + sb.AppendFormat(Localization.Filesystem_has_0_big_blocks_free_1_bytes, + superBlock.vol0_stat_freebigblocks, + superBlock.vol0_stat_freebigblocks * HAMMER_BIGBLOCK_SIZE) + .AppendLine(); + + sb.AppendFormat(Localization.Filesystem_has_0_inodes_used, superBlock.vol0_stat_inodes).AppendLine(); + + metadata.Clusters = (ulong)superBlock.vol0_stat_bigblocks; + metadata.FreeClusters = (ulong)superBlock.vol0_stat_freebigblocks; + metadata.Files = (ulong)superBlock.vol0_stat_inodes; + } + + // 0 ? + //sb.AppendFormat("Volume header CRC: 0x{0:X8}", afs_sb.vol_crc).AppendLine(); + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/HAMMER.cs b/Aaru.Filesystems/HAMMER/Structs.cs similarity index 50% rename from Aaru.Filesystems/HAMMER.cs rename to Aaru.Filesystems/HAMMER/Structs.cs index fcf6245d5..af3b27da7 100644 --- a/Aaru.Filesystems/HAMMER.cs +++ b/Aaru.Filesystems/HAMMER/Structs.cs @@ -2,15 +2,11 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : HAMMER.cs +// Filename : Structs.cs // Author(s) : Natalia Portillo // // Component : HAMMER filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the HAMMER filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,144 +23,49 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -using hammer_crc_t = System.UInt32; -using hammer_off_t = System.UInt64; -using hammer_tid_t = System.UInt64; +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using hammer_crc_t = uint; +using hammer_off_t = ulong; +using hammer_tid_t = ulong; #pragma warning disable 169 namespace Aaru.Filesystems; -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - /// /// Implements detection for the HAMMER filesystem -public sealed class HAMMER : IFilesystem +public sealed partial class HAMMER { - const ulong HAMMER_FSBUF_VOLUME = 0xC8414D4DC5523031; - const ulong HAMMER_FSBUF_VOLUME_REV = 0x313052C54D4D41C8; - const uint HAMMER_VOLHDR_SIZE = 1928; - const int HAMMER_BIGBLOCK_SIZE = 8192 * 1024; +#region Nested type: HammerBlockMap - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "HAMMER Filesystem"; - /// - public Guid Id => new("91A188BF-5FD7-4677-BBD3-F59EBA9C864D"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) + [SuppressMessage("ReSharper", "InconsistentNaming")] + [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] + struct HammerBlockMap { - uint run = HAMMER_VOLHDR_SIZE / imagePlugin.Info.SectorSize; - - if(HAMMER_VOLHDR_SIZE % imagePlugin.Info.SectorSize > 0) - run++; - - if(run + partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, run, out byte[] sbSector); - - if(errno != ErrorNumber.NoError) - return false; - - var magic = BitConverter.ToUInt64(sbSector, 0); - - return magic is HAMMER_FSBUF_VOLUME or HAMMER_FSBUF_VOLUME_REV; + /// zone-2 offset only used by zone-4 + public hammer_off_t phys_offset; + /// zone-X offset only used by zone-3 + public hammer_off_t first_offset; + /// zone-X offset for allocation + public hammer_off_t next_offset; + /// zone-X offset only used by zone-3 + public hammer_off_t alloc_offset; + public uint reserved01; + public hammer_crc_t entry_crc; } - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; +#endregion - var sb = new StringBuilder(); - - SuperBlock superBlock; - - uint run = HAMMER_VOLHDR_SIZE / imagePlugin.Info.SectorSize; - - if(HAMMER_VOLHDR_SIZE % imagePlugin.Info.SectorSize > 0) - run++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, run, out byte[] sbSector); - - if(errno != ErrorNumber.NoError) - return; - - var magic = BitConverter.ToUInt64(sbSector, 0); - - superBlock = magic == HAMMER_FSBUF_VOLUME ? Marshal.ByteArrayToStructureLittleEndian(sbSector) - : Marshal.ByteArrayToStructureBigEndian(sbSector); - - sb.AppendLine("HAMMER filesystem"); - - sb.AppendFormat("Volume version: {0}", superBlock.vol_version).AppendLine(); - - sb.AppendFormat("Volume {0} of {1} on this filesystem", superBlock.vol_no + 1, superBlock.vol_count). - AppendLine(); - - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(superBlock.vol_label, Encoding)).AppendLine(); - sb.AppendFormat("Volume serial: {0}", superBlock.vol_fsid).AppendLine(); - sb.AppendFormat("Filesystem type: {0}", superBlock.vol_fstype).AppendLine(); - sb.AppendFormat("Boot area starts at {0}", superBlock.vol_bot_beg).AppendLine(); - sb.AppendFormat("Memory log starts at {0}", superBlock.vol_mem_beg).AppendLine(); - sb.AppendFormat("First volume buffer starts at {0}", superBlock.vol_buf_beg).AppendLine(); - sb.AppendFormat("Volume ends at {0}", superBlock.vol_buf_end).AppendLine(); - - XmlFsType = new FileSystemType - { - Clusters = partition.Size / HAMMER_BIGBLOCK_SIZE, - ClusterSize = HAMMER_BIGBLOCK_SIZE, - Dirty = false, - Type = "HAMMER", - VolumeName = StringHandlers.CToString(superBlock.vol_label, Encoding), - VolumeSerial = superBlock.vol_fsid.ToString() - }; - - if(superBlock.vol_no == superBlock.vol_rootvol) - { - sb.AppendFormat("Filesystem contains {0} \"big-blocks\" ({1} bytes)", superBlock.vol0_stat_bigblocks, - superBlock.vol0_stat_bigblocks * HAMMER_BIGBLOCK_SIZE).AppendLine(); - - sb.AppendFormat("Filesystem has {0} \"big-blocks\" free ({1} bytes)", superBlock.vol0_stat_freebigblocks, - superBlock.vol0_stat_freebigblocks * HAMMER_BIGBLOCK_SIZE).AppendLine(); - - sb.AppendFormat("Filesystem has {0} inode used", superBlock.vol0_stat_inodes).AppendLine(); - - XmlFsType.Clusters = (ulong)superBlock.vol0_stat_bigblocks; - XmlFsType.FreeClusters = (ulong)superBlock.vol0_stat_freebigblocks; - XmlFsType.FreeClustersSpecified = true; - XmlFsType.Files = (ulong)superBlock.vol0_stat_inodes; - XmlFsType.FilesSpecified = true; - } - - // 0 ? - //sb.AppendFormat("Volume header CRC: 0x{0:X8}", afs_sb.vol_crc).AppendLine(); - - information = sb.ToString(); - } +#region Nested type: SuperBlock /// Hammer superblock - [StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] readonly struct SuperBlock { /// for a valid header @@ -239,18 +140,5 @@ public sealed class HAMMER : IFilesystem public readonly hammer_off_t[] vol0_undo_array; } - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] - struct HammerBlockMap - { - /// zone-2 offset only used by zone-4 - public hammer_off_t phys_offset; - /// zone-X offset only used by zone-3 - public hammer_off_t first_offset; - /// zone-X offset for allocation - public hammer_off_t next_offset; - /// zone-X offset only used by zone-3 - public hammer_off_t alloc_offset; - public uint reserved01; - public hammer_crc_t entry_crc; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/HPFS.cs b/Aaru.Filesystems/HPFS.cs deleted file mode 100644 index 08d076a3b..000000000 --- a/Aaru.Filesystems/HPFS.cs +++ /dev/null @@ -1,403 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : HPFS.cs -// Author(s) : Natalia Portillo -// -// Component : OS/2 High Performance File System plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the OS/2 High Performance File System and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.Checksums; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Information from an old unnamed document -/// -/// Implements detection of IBM's High Performance File System (HPFS) -public sealed class HPFS : IFilesystem -{ - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "OS/2 High Performance File System"; - /// - public Guid Id => new("33513B2C-f590-4acb-8bf2-0b1d5e19dec5"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(16 + partition.Start >= partition.End) - return false; - - ErrorNumber errno = - imagePlugin.ReadSector(16 + partition.Start, - out byte[] hpfsSbSector); // Seek to superblock, on logical sector 16 - - if(errno != ErrorNumber.NoError) - return false; - - var magic1 = BitConverter.ToUInt32(hpfsSbSector, 0x000); - var magic2 = BitConverter.ToUInt32(hpfsSbSector, 0x004); - - return magic1 == 0xF995E849 && magic2 == 0xFA53E9C5; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("ibm850"); - information = ""; - - var sb = new StringBuilder(); - - ErrorNumber errno = - imagePlugin.ReadSector(0 + partition.Start, - out byte[] hpfsBpbSector); // Seek to BIOS parameter block, on logical sector 0 - - if(errno != ErrorNumber.NoError) - return; - - errno = imagePlugin.ReadSector(16 + partition.Start, - out byte[] hpfsSbSector); // Seek to superblock, on logical sector 16 - - if(errno != ErrorNumber.NoError) - return; - - errno = imagePlugin.ReadSector(17 + partition.Start, - out byte[] hpfsSpSector); // Seek to spareblock, on logical sector 17 - - if(errno != ErrorNumber.NoError) - return; - - BiosParameterBlock bpb = Marshal.ByteArrayToStructureLittleEndian(hpfsBpbSector); - - SuperBlock hpfsSb = Marshal.ByteArrayToStructureLittleEndian(hpfsSbSector); - - SpareBlock sp = Marshal.ByteArrayToStructureLittleEndian(hpfsSpSector); - - if(StringHandlers.CToString(bpb.fs_type) != "HPFS " || - hpfsSb.magic1 != 0xF995E849 || - hpfsSb.magic2 != 0xFA53E9C5 || - sp.magic1 != 0xF9911849 || - sp.magic2 != 0xFA5229C5) - { - sb.AppendLine("This may not be HPFS, following information may be not correct."); - sb.AppendFormat("File system type: \"{0}\" (Should be \"HPFS \")", bpb.fs_type).AppendLine(); - sb.AppendFormat("Superblock magic1: 0x{0:X8} (Should be 0xF995E849)", hpfsSb.magic1).AppendLine(); - sb.AppendFormat("Superblock magic2: 0x{0:X8} (Should be 0xFA53E9C5)", hpfsSb.magic2).AppendLine(); - sb.AppendFormat("Spareblock magic1: 0x{0:X8} (Should be 0xF9911849)", sp.magic1).AppendLine(); - sb.AppendFormat("Spareblock magic2: 0x{0:X8} (Should be 0xFA5229C5)", sp.magic2).AppendLine(); - } - - sb.AppendFormat("OEM name: {0}", StringHandlers.CToString(bpb.oem_name)).AppendLine(); - sb.AppendFormat("{0} bytes per sector", bpb.bps).AppendLine(); - - // sb.AppendFormat("{0} sectors per cluster", hpfs_bpb.spc).AppendLine(); - // sb.AppendFormat("{0} reserved sectors", hpfs_bpb.rsectors).AppendLine(); - // sb.AppendFormat("{0} FATs", hpfs_bpb.fats_no).AppendLine(); - // sb.AppendFormat("{0} entries on root directory", hpfs_bpb.root_ent).AppendLine(); - // sb.AppendFormat("{0} mini sectors on volume", hpfs_bpb.sectors).AppendLine(); - sb.AppendFormat("Media descriptor: 0x{0:X2}", bpb.media).AppendLine(); - - // sb.AppendFormat("{0} sectors per FAT", hpfs_bpb.spfat).AppendLine(); - // sb.AppendFormat("{0} sectors per track", hpfs_bpb.sptrk).AppendLine(); - // sb.AppendFormat("{0} heads", hpfs_bpb.heads).AppendLine(); - sb.AppendFormat("{0} sectors hidden before BPB", bpb.hsectors).AppendLine(); - - sb.AppendFormat("{0} sectors on volume ({1} bytes)", hpfsSb.sectors, hpfsSb.sectors * bpb.bps).AppendLine(); - - // sb.AppendFormat("{0} sectors on volume ({1} bytes)", hpfs_bpb.big_sectors, hpfs_bpb.big_sectors * hpfs_bpb.bps).AppendLine(); - sb.AppendFormat("BIOS Drive Number: 0x{0:X2}", bpb.drive_no).AppendLine(); - sb.AppendFormat("NT Flags: 0x{0:X2}", bpb.nt_flags).AppendLine(); - sb.AppendFormat("Signature: 0x{0:X2}", bpb.signature).AppendLine(); - sb.AppendFormat("Serial number: 0x{0:X8}", bpb.serial_no).AppendLine(); - sb.AppendFormat("Volume label: {0}", StringHandlers.CToString(bpb.volume_label, Encoding)).AppendLine(); - - // sb.AppendFormat("Filesystem type: \"{0}\"", hpfs_bpb.fs_type).AppendLine(); - - DateTime lastChk = DateHandlers.UnixToDateTime(hpfsSb.last_chkdsk); - DateTime lastOptim = DateHandlers.UnixToDateTime(hpfsSb.last_optim); - - sb.AppendFormat("HPFS version: {0}", hpfsSb.version).AppendLine(); - sb.AppendFormat("Functional version: {0}", hpfsSb.func_version).AppendLine(); - sb.AppendFormat("Sector of root directory FNode: {0}", hpfsSb.root_fnode).AppendLine(); - sb.AppendFormat("{0} sectors are marked bad", hpfsSb.badblocks).AppendLine(); - sb.AppendFormat("Sector of free space bitmaps: {0}", hpfsSb.bitmap_lsn).AppendLine(); - sb.AppendFormat("Sector of bad blocks list: {0}", hpfsSb.badblock_lsn).AppendLine(); - - if(hpfsSb.last_chkdsk > 0) - sb.AppendFormat("Date of last integrity check: {0}", lastChk).AppendLine(); - else - sb.AppendLine("Filesystem integrity has never been checked"); - - if(hpfsSb.last_optim > 0) - sb.AppendFormat("Date of last optimization {0}", lastOptim).AppendLine(); - else - sb.AppendLine("Filesystem has never been optimized"); - - sb.AppendFormat("Directory band has {0} sectors", hpfsSb.dband_sectors).AppendLine(); - sb.AppendFormat("Directory band starts at sector {0}", hpfsSb.dband_start).AppendLine(); - sb.AppendFormat("Directory band ends at sector {0}", hpfsSb.dband_last).AppendLine(); - sb.AppendFormat("Sector of directory band bitmap: {0}", hpfsSb.dband_bitmap).AppendLine(); - sb.AppendFormat("Sector of ACL directory: {0}", hpfsSb.acl_start).AppendLine(); - - sb.AppendFormat("Sector of Hotfix directory: {0}", sp.hotfix_start).AppendLine(); - sb.AppendFormat("{0} used Hotfix entries", sp.hotfix_used).AppendLine(); - sb.AppendFormat("{0} total Hotfix entries", sp.hotfix_entries).AppendLine(); - sb.AppendFormat("{0} free spare DNodes", sp.spare_dnodes_free).AppendLine(); - sb.AppendFormat("{0} total spare DNodes", sp.spare_dnodes).AppendLine(); - sb.AppendFormat("Sector of codepage directory: {0}", sp.codepage_lsn).AppendLine(); - sb.AppendFormat("{0} codepages used in the volume", sp.codepages).AppendLine(); - sb.AppendFormat("SuperBlock CRC32: {0:X8}", sp.sb_crc32).AppendLine(); - sb.AppendFormat("SpareBlock CRC32: {0:X8}", sp.sp_crc32).AppendLine(); - - sb.AppendLine("Flags:"); - sb.AppendLine((sp.flags1 & 0x01) == 0x01 ? "Filesystem is dirty." : "Filesystem is clean."); - - if((sp.flags1 & 0x02) == 0x02) - sb.AppendLine("Spare directory blocks are in use"); - - if((sp.flags1 & 0x04) == 0x04) - sb.AppendLine("Hotfixes are in use"); - - if((sp.flags1 & 0x08) == 0x08) - sb.AppendLine("Disk contains bad sectors"); - - if((sp.flags1 & 0x10) == 0x10) - sb.AppendLine("Disk has a bad bitmap"); - - if((sp.flags1 & 0x20) == 0x20) - sb.AppendLine("Filesystem was formatted fast"); - - if((sp.flags1 & 0x40) == 0x40) - sb.AppendLine("Unknown flag 0x40 on flags1 is active"); - - if((sp.flags1 & 0x80) == 0x80) - sb.AppendLine("Filesystem has been mounted by an old IFS"); - - if((sp.flags2 & 0x01) == 0x01) - sb.AppendLine("Install DASD limits"); - - if((sp.flags2 & 0x02) == 0x02) - sb.AppendLine("Resync DASD limits"); - - if((sp.flags2 & 0x04) == 0x04) - sb.AppendLine("DASD limits are operational"); - - if((sp.flags2 & 0x08) == 0x08) - sb.AppendLine("Multimedia is active"); - - if((sp.flags2 & 0x10) == 0x10) - sb.AppendLine("DCE ACLs are active"); - - if((sp.flags2 & 0x20) == 0x20) - sb.AppendLine("DASD limits are dirty"); - - if((sp.flags2 & 0x40) == 0x40) - sb.AppendLine("Unknown flag 0x40 on flags2 is active"); - - if((sp.flags2 & 0x80) == 0x80) - sb.AppendLine("Unknown flag 0x80 on flags2 is active"); - - XmlFsType = new FileSystemType(); - - // Theoretically everything from BPB to SB is boot code, should I hash everything or only the sector loaded by BIOS itself? - if(bpb.jump[0] == 0xEB && - bpb.jump[1] > 0x3C && - bpb.jump[1] < 0x80 && - bpb.signature2 == 0xAA55) - { - XmlFsType.Bootable = true; - string bootChk = Sha1Context.Data(bpb.boot_code, out byte[] _); - sb.AppendLine("Volume is bootable"); - sb.AppendFormat("Boot code's SHA1: {0}", bootChk).AppendLine(); - } - - XmlFsType.Dirty |= (sp.flags1 & 0x01) == 0x01; - XmlFsType.Clusters = hpfsSb.sectors; - XmlFsType.ClusterSize = bpb.bps; - XmlFsType.Type = "HPFS"; - XmlFsType.VolumeName = StringHandlers.CToString(bpb.volume_label, Encoding); - XmlFsType.VolumeSerial = $"{bpb.serial_no:X8}"; - XmlFsType.SystemIdentifier = StringHandlers.CToString(bpb.oem_name); - - information = sb.ToString(); - } - - /// BIOS Parameter Block, at sector 0 - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct BiosParameterBlock - { - /// 0x000, Jump to boot code - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - /// 0x003, OEM Name, 8 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] oem_name; - /// 0x00B, Bytes per sector - public readonly ushort bps; - /// 0x00D, Sectors per cluster - public readonly byte spc; - /// 0x00E, Reserved sectors between BPB and... does it have sense in HPFS? - public readonly ushort rsectors; - /// 0x010, Number of FATs... seriously? - public readonly byte fats_no; - /// 0x011, Number of entries on root directory... ok - public readonly ushort root_ent; - /// 0x013, Sectors in volume... doubt it - public readonly ushort sectors; - /// 0x015, Media descriptor - public readonly byte media; - /// 0x016, Sectors per FAT... again - public readonly ushort spfat; - /// 0x018, Sectors per track... you're kidding - public readonly ushort sptrk; - /// 0x01A, Heads... stop! - public readonly ushort heads; - /// 0x01C, Hidden sectors before BPB - public readonly uint hsectors; - /// 0x024, Sectors in volume if > 65535... - public readonly uint big_sectors; - /// 0x028, Drive number - public readonly byte drive_no; - /// 0x029, Volume flags? - public readonly byte nt_flags; - /// 0x02A, EPB signature, 0x29 - public readonly byte signature; - /// 0x02B, Volume serial number - public readonly uint serial_no; - /// 0x02F, Volume label, 11 bytes, space-padded - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - public readonly byte[] volume_label; - /// 0x03A, Filesystem type, 8 bytes, space-padded ("HPFS ") - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] fs_type; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 448)] - public readonly byte[] boot_code; - /// 0x1FE, 0xAA55 - public readonly ushort signature2; - } - - /// HPFS superblock at sector 16 - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SuperBlock - { - /// 0x000, 0xF995E849 - public readonly uint magic1; - /// 0x004, 0xFA53E9C5 - public readonly uint magic2; - /// 0x008, HPFS version - public readonly byte version; - /// 0x009, 2 if <= 4 GiB, 3 if > 4 GiB - public readonly byte func_version; - /// 0x00A, Alignment - public readonly ushort dummy; - /// 0x00C, LSN pointer to root fnode - public readonly uint root_fnode; - /// 0x010, Sectors on volume - public readonly uint sectors; - /// 0x014, Bad blocks on volume - public readonly uint badblocks; - /// 0x018, LSN pointer to volume bitmap - public readonly uint bitmap_lsn; - /// 0x01C, 0 - public readonly uint zero1; - /// 0x020, LSN pointer to badblock directory - public readonly uint badblock_lsn; - /// 0x024, 0 - public readonly uint zero2; - /// 0x028, Time of last CHKDSK - public readonly int last_chkdsk; - /// 0x02C, Time of last optimization - public readonly int last_optim; - /// 0x030, Sectors of dir band - public readonly uint dband_sectors; - /// 0x034, Start sector of dir band - public readonly uint dband_start; - /// 0x038, Last sector of dir band - public readonly uint dband_last; - /// 0x03C, LSN of free space bitmap - public readonly uint dband_bitmap; - /// 0x040, Can be used for volume name (32 bytes) - public readonly ulong zero3; - /// 0x048, ... - public readonly ulong zero4; - /// 0x04C, ... - public readonly ulong zero5; - /// 0x050, ...; - public readonly ulong zero6; - /// 0x058, LSN pointer to ACLs (only HPFS386) - public readonly uint acl_start; - } - - /// HPFS spareblock at sector 17 - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SpareBlock - { - /// 0x000, 0xF9911849 - public readonly uint magic1; - /// 0x004, 0xFA5229C5 - public readonly uint magic2; - /// 0x008, HPFS flags - public readonly byte flags1; - /// 0x009, HPFS386 flags - public readonly byte flags2; - /// 0x00A, Alignment - public readonly ushort dummy; - /// 0x00C, LSN of hotfix directory - public readonly uint hotfix_start; - /// 0x010, Used hotfixes - public readonly uint hotfix_used; - /// 0x014, Total hotfixes available - public readonly uint hotfix_entries; - /// 0x018, Unused spare dnodes - public readonly uint spare_dnodes_free; - /// 0x01C, Length of spare dnodes list - public readonly uint spare_dnodes; - /// 0x020, LSN of codepage directory - public readonly uint codepage_lsn; - /// 0x024, Number of codepages used - public readonly uint codepages; - /// 0x028, SuperBlock CRC32 (only HPFS386) - public readonly uint sb_crc32; - /// 0x02C, SpareBlock CRC32 (only HPFS386) - public readonly uint sp_crc32; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/HPFS/Consts.cs b/Aaru.Filesystems/HPFS/Consts.cs new file mode 100644 index 000000000..db98c43d1 --- /dev/null +++ b/Aaru.Filesystems/HPFS/Consts.cs @@ -0,0 +1,41 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : OS/2 High Performance File System plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the OS/2 High Performance File System and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Information from an old unnamed document +/// +/// Implements detection of IBM's High Performance File System (HPFS) +public sealed partial class HPFS +{ + const string FS_TYPE = "hpfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/HPFS/HPFS.cs b/Aaru.Filesystems/HPFS/HPFS.cs new file mode 100644 index 000000000..f905e0e97 --- /dev/null +++ b/Aaru.Filesystems/HPFS/HPFS.cs @@ -0,0 +1,55 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : HPFS.cs +// Author(s) : Natalia Portillo +// +// Component : OS/2 High Performance File System plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the OS/2 High Performance File System and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from an old unnamed document +/// +/// Implements detection of IBM's High Performance File System (HPFS) +public sealed partial class HPFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.HPFS_Name; + + /// + public Guid Id => new("33513B2C-f590-4acb-8bf2-0b1d5e19dec5"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/HPFS/Info.cs b/Aaru.Filesystems/HPFS/Info.cs new file mode 100644 index 000000000..09fa587cb --- /dev/null +++ b/Aaru.Filesystems/HPFS/Info.cs @@ -0,0 +1,233 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : OS/2 High Performance File System plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the OS/2 High Performance File System and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.Checksums; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from an old unnamed document +/// +/// Implements detection of IBM's High Performance File System (HPFS) +public sealed partial class HPFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(16 + partition.Start >= partition.End) return false; + + ErrorNumber errno = + imagePlugin.ReadSector(16 + partition.Start, + out byte[] hpfsSbSector); // Seek to superblock, on logical sector 16 + + if(errno != ErrorNumber.NoError) return false; + + var magic1 = BitConverter.ToUInt32(hpfsSbSector, 0x000); + var magic2 = BitConverter.ToUInt32(hpfsSbSector, 0x004); + + return magic1 == 0xF995E849 && magic2 == 0xFA53E9C5; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("ibm850"); + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + ErrorNumber errno = + imagePlugin.ReadSector(0 + partition.Start, + out byte[] hpfsBpbSector); // Seek to BIOS parameter block, on logical sector 0 + + if(errno != ErrorNumber.NoError) return; + + errno = imagePlugin.ReadSector(16 + partition.Start, + out byte[] hpfsSbSector); // Seek to superblock, on logical sector 16 + + if(errno != ErrorNumber.NoError) return; + + errno = imagePlugin.ReadSector(17 + partition.Start, + out byte[] hpfsSpSector); // Seek to spareblock, on logical sector 17 + + if(errno != ErrorNumber.NoError) return; + + BiosParameterBlock bpb = Marshal.ByteArrayToStructureLittleEndian(hpfsBpbSector); + + SuperBlock hpfsSb = Marshal.ByteArrayToStructureLittleEndian(hpfsSbSector); + + SpareBlock sp = Marshal.ByteArrayToStructureLittleEndian(hpfsSpSector); + + if(StringHandlers.CToString(bpb.fs_type) != "HPFS " || + hpfsSb.magic1 != 0xF995E849 || + hpfsSb.magic2 != 0xFA53E9C5 || + sp.magic1 != 0xF9911849 || + sp.magic2 != 0xFA5229C5) + { + sb.AppendLine(Localization.This_may_not_be_HPFS_following_information_may_be_not_correct); + sb.AppendFormat(Localization.File_system_type_0_Should_be_HPFS, bpb.fs_type).AppendLine(); + sb.AppendFormat(Localization.Superblock_magic1_0_Should_be_0xF995E849, hpfsSb.magic1).AppendLine(); + sb.AppendFormat(Localization.Superblock_magic2_0_Should_be_0xFA53E9C5, hpfsSb.magic2).AppendLine(); + sb.AppendFormat(Localization.Spareblock_magic1_0_Should_be_0xF9911849, sp.magic1).AppendLine(); + sb.AppendFormat(Localization.Spareblock_magic2_0_Should_be_0xFA5229C5, sp.magic2).AppendLine(); + } + + sb.AppendFormat(Localization.OEM_name_0, StringHandlers.CToString(bpb.oem_name)).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector, bpb.bps).AppendLine(); + + // sb.AppendFormat("{0} sectors per cluster", hpfs_bpb.spc).AppendLine(); + // sb.AppendFormat("{0} reserved sectors", hpfs_bpb.rsectors).AppendLine(); + // sb.AppendFormat("{0} FATs", hpfs_bpb.fats_no).AppendLine(); + // sb.AppendFormat("{0} entries on root directory", hpfs_bpb.root_ent).AppendLine(); + // sb.AppendFormat("{0} mini sectors on volume", hpfs_bpb.sectors).AppendLine(); + sb.AppendFormat(Localization.Media_descriptor_0, bpb.media).AppendLine(); + + // sb.AppendFormat("{0} sectors per FAT", hpfs_bpb.spfat).AppendLine(); + // sb.AppendFormat("{0} sectors per track", hpfs_bpb.sptrk).AppendLine(); + // sb.AppendFormat("{0} heads", hpfs_bpb.heads).AppendLine(); + sb.AppendFormat(Localization._0_sectors_hidden_before_BPB, bpb.hsectors).AppendLine(); + + sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, hpfsSb.sectors, hpfsSb.sectors * bpb.bps) + .AppendLine(); + + // sb.AppendFormat("{0} sectors on volume ({1} bytes)", hpfs_bpb.big_sectors, hpfs_bpb.big_sectors * hpfs_bpb.bps).AppendLine(); + sb.AppendFormat(Localization.BIOS_drive_number_0, bpb.drive_no).AppendLine(); + sb.AppendFormat(Localization.NT_Flags_0, bpb.nt_flags).AppendLine(); + sb.AppendFormat(Localization.Signature_0, bpb.signature).AppendLine(); + sb.AppendFormat(Localization.Serial_number_0, bpb.serial_no).AppendLine(); + sb.AppendFormat(Localization.Volume_label_0, StringHandlers.CToString(bpb.volume_label, encoding)).AppendLine(); + + // sb.AppendFormat("Filesystem type: \"{0}\"", hpfs_bpb.fs_type).AppendLine(); + + DateTime lastChk = DateHandlers.UnixToDateTime(hpfsSb.last_chkdsk); + DateTime lastOptim = DateHandlers.UnixToDateTime(hpfsSb.last_optim); + + sb.AppendFormat(Localization.HPFS_version_0, hpfsSb.version).AppendLine(); + sb.AppendFormat(Localization.Functional_version_0, hpfsSb.func_version).AppendLine(); + sb.AppendFormat(Localization.Sector_of_root_directory_FNode_0, hpfsSb.root_fnode).AppendLine(); + sb.AppendFormat(Localization._0_sectors_are_marked_bad, hpfsSb.badblocks).AppendLine(); + sb.AppendFormat(Localization.Sector_of_free_space_bitmaps_0, hpfsSb.bitmap_lsn).AppendLine(); + sb.AppendFormat(Localization.Sector_of_bad_blocks_list_0, hpfsSb.badblock_lsn).AppendLine(); + + if(hpfsSb.last_chkdsk > 0) + sb.AppendFormat(Localization.Date_of_last_integrity_check_0, lastChk).AppendLine(); + else + sb.AppendLine(Localization.Filesystem_integrity_has_never_been_checked); + + if(hpfsSb.last_optim > 0) + sb.AppendFormat(Localization.Date_of_last_optimization_0, lastOptim).AppendLine(); + else + sb.AppendLine(Localization.Filesystem_has_never_been_optimized); + + sb.AppendFormat(Localization.Directory_band_has_0_sectors, hpfsSb.dband_sectors).AppendLine(); + sb.AppendFormat(Localization.Directory_band_starts_at_sector_0, hpfsSb.dband_start).AppendLine(); + sb.AppendFormat(Localization.Directory_band_ends_at_sector_0, hpfsSb.dband_last).AppendLine(); + sb.AppendFormat(Localization.Sector_of_directory_band_bitmap_0, hpfsSb.dband_bitmap).AppendLine(); + sb.AppendFormat(Localization.Sector_of_ACL_directory_0, hpfsSb.acl_start).AppendLine(); + + sb.AppendFormat(Localization.Sector_of_Hotfix_directory_0, sp.hotfix_start).AppendLine(); + sb.AppendFormat(Localization._0_used_Hotfix_entries, sp.hotfix_used).AppendLine(); + sb.AppendFormat(Localization._0_total_Hotfix_entries, sp.hotfix_entries).AppendLine(); + sb.AppendFormat(Localization._0_free_spare_DNodes, sp.spare_dnodes_free).AppendLine(); + sb.AppendFormat(Localization._0_total_spare_DNodes, sp.spare_dnodes).AppendLine(); + sb.AppendFormat(Localization.Sector_of_codepage_directory_0, sp.codepage_lsn).AppendLine(); + sb.AppendFormat(Localization._0_codepages_used_in_the_volume, sp.codepages).AppendLine(); + sb.AppendFormat(Localization.SuperBlock_CRC32_0, sp.sb_crc32).AppendLine(); + sb.AppendFormat(Localization.SpareBlock_CRC32_0, sp.sp_crc32).AppendLine(); + + sb.AppendLine(Localization.Flags); + sb.AppendLine((sp.flags1 & 0x01) == 0x01 ? Localization.Filesystem_is_dirty : Localization.Filesystem_is_clean); + + if((sp.flags1 & 0x02) == 0x02) sb.AppendLine(Localization.Spare_directory_blocks_are_in_use); + + if((sp.flags1 & 0x04) == 0x04) sb.AppendLine(Localization.Hotfixes_are_in_use); + + if((sp.flags1 & 0x08) == 0x08) sb.AppendLine(Localization.Disk_contains_bad_sectors); + + if((sp.flags1 & 0x10) == 0x10) sb.AppendLine(Localization.Disk_has_a_bad_bitmap); + + if((sp.flags1 & 0x20) == 0x20) sb.AppendLine(Localization.Filesystem_was_formatted_fast); + + if((sp.flags1 & 0x40) == 0x40) sb.AppendLine(Localization.Unknown_flag_0x40_on_flags1_is_active); + + if((sp.flags1 & 0x80) == 0x80) sb.AppendLine(Localization.Filesystem_has_been_mounted_by_an_old_IFS); + + if((sp.flags2 & 0x01) == 0x01) sb.AppendLine(Localization.Install_DASD_limits); + + if((sp.flags2 & 0x02) == 0x02) sb.AppendLine(Localization.Resync_DASD_limits); + + if((sp.flags2 & 0x04) == 0x04) sb.AppendLine(Localization.DASD_limits_are_operational); + + if((sp.flags2 & 0x08) == 0x08) sb.AppendLine(Localization.Multimedia_is_active); + + if((sp.flags2 & 0x10) == 0x10) sb.AppendLine(Localization.DCE_ACLs_are_active); + + if((sp.flags2 & 0x20) == 0x20) sb.AppendLine(Localization.DASD_limits_are_dirty); + + if((sp.flags2 & 0x40) == 0x40) sb.AppendLine(Localization.Unknown_flag_0x40_on_flags2_is_active); + + if((sp.flags2 & 0x80) == 0x80) sb.AppendLine(Localization.Unknown_flag_0x80_on_flags2_is_active); + + metadata = new FileSystem(); + + // Theoretically everything from BPB to SB is boot code, should I hash everything or only the sector loaded by BIOS itself? + if(bpb.jump[0] == 0xEB && bpb.jump[1] > 0x3C && bpb.jump[1] < 0x80 && bpb.signature2 == 0xAA55) + { + metadata.Bootable = true; + string bootChk = Sha1Context.Data(bpb.boot_code, out byte[] _); + sb.AppendLine(Localization.Volume_is_bootable); + sb.AppendFormat(Localization.Boot_code_SHA1_0, bootChk).AppendLine(); + } + + metadata.Dirty |= (sp.flags1 & 0x01) == 0x01; + metadata.Clusters = hpfsSb.sectors; + metadata.ClusterSize = bpb.bps; + metadata.Type = FS_TYPE; + metadata.VolumeName = StringHandlers.CToString(bpb.volume_label, encoding); + metadata.VolumeSerial = $"{bpb.serial_no:X8}"; + metadata.SystemIdentifier = StringHandlers.CToString(bpb.oem_name); + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/HPFS/Structs.cs b/Aaru.Filesystems/HPFS/Structs.cs new file mode 100644 index 000000000..6896d9d6e --- /dev/null +++ b/Aaru.Filesystems/HPFS/Structs.cs @@ -0,0 +1,194 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : OS/2 High Performance File System plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the OS/2 High Performance File System and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Information from an old unnamed document +/// +/// Implements detection of IBM's High Performance File System (HPFS) +public sealed partial class HPFS +{ +#region Nested type: BiosParameterBlock + + /// BIOS Parameter Block, at sector 0 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct BiosParameterBlock + { + /// 0x000, Jump to boot code + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + /// 0x003, OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] oem_name; + /// 0x00B, Bytes per sector + public readonly ushort bps; + /// 0x00D, Sectors per cluster + public readonly byte spc; + /// 0x00E, Reserved sectors between BPB and... does it have sense in HPFS? + public readonly ushort rsectors; + /// 0x010, Number of FATs... seriously? + public readonly byte fats_no; + /// 0x011, Number of entries on root directory... ok + public readonly ushort root_ent; + /// 0x013, Sectors in volume... doubt it + public readonly ushort sectors; + /// 0x015, Media descriptor + public readonly byte media; + /// 0x016, Sectors per FAT... again + public readonly ushort spfat; + /// 0x018, Sectors per track... you're kidding + public readonly ushort sptrk; + /// 0x01A, Heads... stop! + public readonly ushort heads; + /// 0x01C, Hidden sectors before BPB + public readonly uint hsectors; + /// 0x024, Sectors in volume if > 65535... + public readonly uint big_sectors; + /// 0x028, Drive number + public readonly byte drive_no; + /// 0x029, Volume flags? + public readonly byte nt_flags; + /// 0x02A, EPB signature, 0x29 + public readonly byte signature; + /// 0x02B, Volume serial number + public readonly uint serial_no; + /// 0x02F, Volume label, 11 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public readonly byte[] volume_label; + /// 0x03A, Filesystem type, 8 bytes, space-padded ("HPFS ") + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] fs_type; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 448)] + public readonly byte[] boot_code; + /// 0x1FE, 0xAA55 + public readonly ushort signature2; + } + +#endregion + +#region Nested type: SpareBlock + + /// HPFS spareblock at sector 17 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SpareBlock + { + /// 0x000, 0xF9911849 + public readonly uint magic1; + /// 0x004, 0xFA5229C5 + public readonly uint magic2; + /// 0x008, HPFS flags + public readonly byte flags1; + /// 0x009, HPFS386 flags + public readonly byte flags2; + /// 0x00A, Alignment + public readonly ushort dummy; + /// 0x00C, LSN of hotfix directory + public readonly uint hotfix_start; + /// 0x010, Used hotfixes + public readonly uint hotfix_used; + /// 0x014, Total hotfixes available + public readonly uint hotfix_entries; + /// 0x018, Unused spare dnodes + public readonly uint spare_dnodes_free; + /// 0x01C, Length of spare dnodes list + public readonly uint spare_dnodes; + /// 0x020, LSN of codepage directory + public readonly uint codepage_lsn; + /// 0x024, Number of codepages used + public readonly uint codepages; + /// 0x028, SuperBlock CRC32 (only HPFS386) + public readonly uint sb_crc32; + /// 0x02C, SpareBlock CRC32 (only HPFS386) + public readonly uint sp_crc32; + } + +#endregion + +#region Nested type: SuperBlock + + /// HPFS superblock at sector 16 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SuperBlock + { + /// 0x000, 0xF995E849 + public readonly uint magic1; + /// 0x004, 0xFA53E9C5 + public readonly uint magic2; + /// 0x008, HPFS version + public readonly byte version; + /// 0x009, 2 if <= 4 GiB, 3 if > 4 GiB + public readonly byte func_version; + /// 0x00A, Alignment + public readonly ushort dummy; + /// 0x00C, LSN pointer to root fnode + public readonly uint root_fnode; + /// 0x010, Sectors on volume + public readonly uint sectors; + /// 0x014, Bad blocks on volume + public readonly uint badblocks; + /// 0x018, LSN pointer to volume bitmap + public readonly uint bitmap_lsn; + /// 0x01C, 0 + public readonly uint zero1; + /// 0x020, LSN pointer to badblock directory + public readonly uint badblock_lsn; + /// 0x024, 0 + public readonly uint zero2; + /// 0x028, Time of last CHKDSK + public readonly int last_chkdsk; + /// 0x02C, Time of last optimization + public readonly int last_optim; + /// 0x030, Sectors of dir band + public readonly uint dband_sectors; + /// 0x034, Start sector of dir band + public readonly uint dband_start; + /// 0x038, Last sector of dir band + public readonly uint dband_last; + /// 0x03C, LSN of free space bitmap + public readonly uint dband_bitmap; + /// 0x040, Can be used for volume name (32 bytes) + public readonly ulong zero3; + /// 0x048, ... + public readonly ulong zero4; + /// 0x04C, ... + public readonly ulong zero5; + /// 0x050, ...; + public readonly ulong zero6; + /// 0x058, LSN pointer to ACLs (only HPFS386) + public readonly uint acl_start; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/HPOFS/Consts.cs b/Aaru.Filesystems/HPOFS/Consts.cs index 1825c849c..1b82eaf20 100644 --- a/Aaru.Filesystems/HPOFS/Consts.cs +++ b/Aaru.Filesystems/HPOFS/Consts.cs @@ -7,10 +7,6 @@ // // Component : High Performance Optical File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// High Performance Optical File System constants. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,23 +23,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +// ReSharper disable UnusedMember.Local + namespace Aaru.Filesystems; public sealed partial class HPOFS { - readonly byte[] _type = - { - 0x48, 0x50, 0x4F, 0x46, 0x53, 0x00, 0x00, 0x00 - }; - readonly byte[] _medinfoSignature = - { - 0x4D, 0x45, 0x44, 0x49, 0x4E, 0x46, 0x4F, 0x20 - }; - readonly byte[] _volinfoSignature = - { - 0x56, 0x4F, 0x4C, 0x49, 0x4E, 0x46, 0x4F, 0x20 - }; + // Do not translate + const string FS_TYPE = "hpofs"; + readonly byte[] _medinfoSignature = "MEDINFO "u8.ToArray(); + readonly byte[] _type = [0x48, 0x50, 0x4F, 0x46, 0x53, 0x00, 0x00, 0x00]; + readonly byte[] _volinfoSignature = "VOLINFO "u8.ToArray(); } \ No newline at end of file diff --git a/Aaru.Filesystems/HPOFS/HPOFS.cs b/Aaru.Filesystems/HPOFS/HPOFS.cs index f8b4b93d4..7566e9fab 100644 --- a/Aaru.Filesystems/HPOFS/HPOFS.cs +++ b/Aaru.Filesystems/HPOFS/HPOFS.cs @@ -7,10 +7,6 @@ // // Component : High Performance Optical File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// High Performance Optical File System. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,15 +23,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; -using System.Text; using Aaru.CommonTypes.Interfaces; -using Schemas; + +namespace Aaru.Filesystems; // Information from test floppy images created with OS/2 HPOFS 2.0 // Need to get IBM document GA32-0224 -> IBM 3995 Optical Library Dataserver Products: Optical Disk Format @@ -43,14 +37,18 @@ using Schemas; /// Implements identification of IBM's High Performance Optical File System public sealed partial class HPOFS : IFilesystem { + const string MODULE_NAME = "HPOFS Plugin"; + +#region IFilesystem Members + /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "High Performance Optical File System"; + public string Name => Localization.HPOFS_Name; + /// public Guid Id => new("1b72dcd5-d031-4757-8a9f-8d2fb18c59e2"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/HPOFS/Info.cs b/Aaru.Filesystems/HPOFS/Info.cs index 7c795dd1d..47dfe284f 100644 --- a/Aaru.Filesystems/HPOFS/Info.cs +++ b/Aaru.Filesystems/HPOFS/Info.cs @@ -28,37 +28,36 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Linq; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Helpers; -using Schemas; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class HPOFS { +#region IFilesystem Members + /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(16 + partition.Start >= partition.End) - return false; + if(16 + partition.Start >= partition.End) return false; ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] hpofsBpbSector); // Seek to BIOS parameter block, on logical sector 0 - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; - if(hpofsBpbSector.Length < 512) - return false; + if(hpofsBpbSector.Length < 512) return false; BiosParameterBlock bpb = Marshal.ByteArrayToStructureLittleEndian(hpofsBpbSector); @@ -66,10 +65,12 @@ public sealed partial class HPOFS } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = encoding ?? Encoding.GetEncoding("ibm850"); - information = ""; + encoding ??= Encoding.GetEncoding("ibm850"); + information = ""; + metadata = new FileSystem(); var sb = new StringBuilder(); @@ -77,152 +78,164 @@ public sealed partial class HPOFS imagePlugin.ReadSector(0 + partition.Start, out byte[] hpofsBpbSector); // Seek to BIOS parameter block, on logical sector 0 - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; errno = imagePlugin.ReadSector(13 + partition.Start, out byte[] medInfoSector); // Seek to media information block, on logical sector 13 - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; errno = imagePlugin.ReadSector(14 + partition.Start, out byte[] volInfoSector); // Seek to volume information block, on logical sector 14 - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; BiosParameterBlock bpb = Marshal.ByteArrayToStructureLittleEndian(hpofsBpbSector); MediaInformationBlock mib = Marshal.ByteArrayToStructureBigEndian(medInfoSector); VolumeInformationBlock vib = Marshal.ByteArrayToStructureBigEndian(volInfoSector); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.oem_name = \"{0}\"", StringHandlers.CToString(bpb.oem_name)); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.oem_name = \"{0}\"", StringHandlers.CToString(bpb.oem_name)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.bps = {0}", bpb.bps); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.spc = {0}", bpb.spc); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.rsectors = {0}", bpb.rsectors); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.fats_no = {0}", bpb.fats_no); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.root_ent = {0}", bpb.root_ent); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.sectors = {0}", bpb.sectors); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.media = 0x{0:X2}", bpb.media); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.spfat = {0}", bpb.spfat); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.sptrk = {0}", bpb.sptrk); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.heads = {0}", bpb.heads); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.hsectors = {0}", bpb.hsectors); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.big_sectors = {0}", bpb.big_sectors); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.drive_no = 0x{0:X2}", bpb.drive_no); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.nt_flags = {0}", bpb.nt_flags); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.signature = 0x{0:X2}", bpb.signature); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.serial_no = 0x{0:X8}", bpb.serial_no); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.bps = {0}", bpb.bps); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.spc = {0}", bpb.spc); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.rsectors = {0}", bpb.rsectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.fats_no = {0}", bpb.fats_no); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.root_ent = {0}", bpb.root_ent); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.sectors = {0}", bpb.sectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.media = 0x{0:X2}", bpb.media); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.spfat = {0}", bpb.spfat); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.sptrk = {0}", bpb.sptrk); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.heads = {0}", bpb.heads); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.hsectors = {0}", bpb.hsectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.big_sectors = {0}", bpb.big_sectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.drive_no = 0x{0:X2}", bpb.drive_no); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.nt_flags = {0}", bpb.nt_flags); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.signature = 0x{0:X2}", bpb.signature); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.serial_no = 0x{0:X8}", bpb.serial_no); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.volume_label = \"{0}\"", + AaruConsole.DebugWriteLine(MODULE_NAME, + "bpb.volume_label = \"{0}\"", StringHandlers.SpacePaddedToString(bpb.volume_label)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.fs_type = \"{0}\"", StringHandlers.CToString(bpb.fs_type)); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.fs_type = \"{0}\"", StringHandlers.CToString(bpb.fs_type)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.boot_code is empty? = {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + "bpb.boot_code is empty? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(bpb.boot_code)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.unknown = {0}", bpb.unknown); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.unknown2 = {0}", bpb.unknown2); - AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.signature2 = {0}", bpb.signature2); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.blockId = \"{0}\"", StringHandlers.CToString(mib.blockId)); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.unknown = {0}", bpb.unknown); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.unknown2 = {0}", bpb.unknown2); + AaruConsole.DebugWriteLine(MODULE_NAME, "bpb.signature2 = {0}", bpb.signature2); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.blockId = \"{0}\"", StringHandlers.CToString(mib.blockId)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.volumeLabel = \"{0}\"", + AaruConsole.DebugWriteLine(MODULE_NAME, + "mib.volumeLabel = \"{0}\"", StringHandlers.SpacePaddedToString(mib.volumeLabel)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.comment = \"{0}\"", + AaruConsole.DebugWriteLine(MODULE_NAME, + "mib.comment = \"{0}\"", StringHandlers.SpacePaddedToString(mib.comment)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.serial = 0x{0:X8}", mib.serial); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.serial = 0x{0:X8}", mib.serial); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.creationTimestamp = {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + "mib.creationTimestamp = {0}", DateHandlers.DosToDateTime(mib.creationDate, mib.creationTime)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.codepageType = {0}", mib.codepageType); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.codepage = {0}", mib.codepage); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.rps = {0}", mib.rps); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.bps = {0}", mib.bps); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.bpc = {0}", mib.bpc); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown2 = {0}", mib.unknown2); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.sectors = {0}", mib.sectors); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown3 = {0}", mib.unknown3); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown4 = {0}", mib.unknown4); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.major = {0}", mib.major); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.minor = {0}", mib.minor); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown5 = {0}", mib.unknown5); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown6 = {0}", mib.unknown6); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.codepageType = {0}", mib.codepageType); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.codepage = {0}", mib.codepage); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.rps = {0}", mib.rps); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.bps = {0}", mib.bps); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.bpc = {0}", mib.bpc); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.unknown2 = {0}", mib.unknown2); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.sectors = {0}", mib.sectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.unknown3 = {0}", mib.unknown3); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.unknown4 = {0}", mib.unknown4); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.major = {0}", mib.major); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.minor = {0}", mib.minor); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.unknown5 = {0}", mib.unknown5); + AaruConsole.DebugWriteLine(MODULE_NAME, "mib.unknown6 = {0}", mib.unknown6); - AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.filler is empty? = {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + "mib.filler is empty? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(mib.filler)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.blockId = \"{0}\"", StringHandlers.CToString(vib.blockId)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown = {0}", vib.unknown); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown2 = {0}", vib.unknown2); + AaruConsole.DebugWriteLine(MODULE_NAME, "vib.blockId = \"{0}\"", StringHandlers.CToString(vib.blockId)); + AaruConsole.DebugWriteLine(MODULE_NAME, "vib.unknown = {0}", vib.unknown); + AaruConsole.DebugWriteLine(MODULE_NAME, "vib.unknown2 = {0}", vib.unknown2); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown3 is empty? = {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + "vib.unknown3 is empty? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(vib.unknown3)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown4 = \"{0}\"", + AaruConsole.DebugWriteLine(MODULE_NAME, + "vib.unknown4 = \"{0}\"", StringHandlers.SpacePaddedToString(vib.unknown4)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.owner = \"{0}\"", - StringHandlers.SpacePaddedToString(vib.owner)); + AaruConsole.DebugWriteLine(MODULE_NAME, "vib.owner = \"{0}\"", StringHandlers.SpacePaddedToString(vib.owner)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown5 = \"{0}\"", + AaruConsole.DebugWriteLine(MODULE_NAME, + "vib.unknown5 = \"{0}\"", StringHandlers.SpacePaddedToString(vib.unknown5)); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown6 = {0}", vib.unknown6); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.percentFull = {0}", vib.percentFull); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown7 = {0}", vib.unknown7); + AaruConsole.DebugWriteLine(MODULE_NAME, "vib.unknown6 = {0}", vib.unknown6); + AaruConsole.DebugWriteLine(MODULE_NAME, "vib.percentFull = {0}", vib.percentFull); + AaruConsole.DebugWriteLine(MODULE_NAME, "vib.unknown7 = {0}", vib.unknown7); - AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.filler is empty? = {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + "vib.filler is empty? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(vib.filler)); - sb.AppendLine("High Performance Optical File System"); - sb.AppendFormat("OEM name: {0}", StringHandlers.SpacePaddedToString(bpb.oem_name)).AppendLine(); - sb.AppendFormat("{0} bytes per sector", bpb.bps).AppendLine(); - sb.AppendFormat("{0} sectors per cluster", bpb.spc).AppendLine(); - sb.AppendFormat("Media descriptor: 0x{0:X2}", bpb.media).AppendLine(); - sb.AppendFormat("{0} sectors per track", bpb.sptrk).AppendLine(); - sb.AppendFormat("{0} heads", bpb.heads).AppendLine(); - sb.AppendFormat("{0} sectors hidden before BPB", bpb.hsectors).AppendLine(); - sb.AppendFormat("{0} sectors on volume ({1} bytes)", mib.sectors, mib.sectors * bpb.bps).AppendLine(); - sb.AppendFormat("BIOS Drive Number: 0x{0:X2}", bpb.drive_no).AppendLine(); - sb.AppendFormat("Serial number: 0x{0:X8}", mib.serial).AppendLine(); + sb.AppendLine(Localization.HPOFS_Name); + sb.AppendFormat(Localization.OEM_name_0, StringHandlers.SpacePaddedToString(bpb.oem_name)).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector, bpb.bps).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_cluster, bpb.spc).AppendLine(); + sb.AppendFormat(Localization.Media_descriptor_0, bpb.media).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_track, bpb.sptrk).AppendLine(); + sb.AppendFormat(Localization._0_heads, bpb.heads).AppendLine(); + sb.AppendFormat(Localization._0_sectors_hidden_before_BPB, bpb.hsectors).AppendLine(); + sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, mib.sectors, mib.sectors * bpb.bps).AppendLine(); + sb.AppendFormat(Localization.BIOS_drive_number_0, bpb.drive_no).AppendLine(); + sb.AppendFormat(Localization.Serial_number_0, mib.serial).AppendLine(); - sb.AppendFormat("Volume label: {0}", StringHandlers.SpacePaddedToString(mib.volumeLabel, Encoding)). - AppendLine(); + sb.AppendFormat(Localization.Volume_label_0, StringHandlers.SpacePaddedToString(mib.volumeLabel, encoding)) + .AppendLine(); - sb.AppendFormat("Volume comment: {0}", StringHandlers.SpacePaddedToString(mib.comment, Encoding)).AppendLine(); + sb.AppendFormat(Localization.Volume_comment_0, StringHandlers.SpacePaddedToString(mib.comment, encoding)) + .AppendLine(); - sb.AppendFormat("Volume owner: {0}", StringHandlers.SpacePaddedToString(vib.owner, Encoding)).AppendLine(); + sb.AppendFormat(Localization.Volume_owner_0, StringHandlers.SpacePaddedToString(vib.owner, encoding)) + .AppendLine(); - sb.AppendFormat("Volume created on {0}", DateHandlers.DosToDateTime(mib.creationDate, mib.creationTime)). - AppendLine(); + sb.AppendFormat(Localization.Volume_created_on_0, + DateHandlers.DosToDateTime(mib.creationDate, mib.creationTime)) + .AppendLine(); - sb.AppendFormat("Volume uses {0} codepage {1}", mib.codepageType > 0 && mib.codepageType < 3 - ? mib.codepageType == 2 - ? "EBCDIC" - : "ASCII" : "Unknown", mib.codepage).AppendLine(); + sb.AppendFormat(Localization.Volume_uses_0_codepage_1, + mib.codepageType is > 0 and < 3 + ? mib.codepageType == 2 ? Localization.EBCDIC : Localization.ASCII + : Localization.Unknown_codepage, + mib.codepage) + .AppendLine(); - sb.AppendFormat("RPS level: {0}", mib.rps).AppendLine(); - sb.AppendFormat("Filesystem version: {0}.{1}", mib.major, mib.minor).AppendLine(); - sb.AppendFormat("Volume can be filled up to {0}%", vib.percentFull).AppendLine(); + sb.AppendFormat(Localization.RPS_level_0, mib.rps).AppendLine(); + sb.AppendFormat(Localization.Filesystem_version_0_1, mib.major, mib.minor).AppendLine(); + sb.AppendFormat(Localization.Volume_can_be_filled_up_to_0, vib.percentFull).AppendLine(); - XmlFsType = new FileSystemType + metadata = new FileSystem { Clusters = mib.sectors / bpb.spc, ClusterSize = (uint)(bpb.bps * bpb.spc), CreationDate = DateHandlers.DosToDateTime(mib.creationDate, mib.creationTime), - CreationDateSpecified = true, - DataPreparerIdentifier = StringHandlers.SpacePaddedToString(vib.owner, Encoding), - Type = "HPOFS", - VolumeName = StringHandlers.SpacePaddedToString(mib.volumeLabel, Encoding), + DataPreparerIdentifier = StringHandlers.SpacePaddedToString(vib.owner, encoding), + Type = FS_TYPE, + VolumeName = StringHandlers.SpacePaddedToString(mib.volumeLabel, encoding), VolumeSerial = $"{mib.serial:X8}", SystemIdentifier = StringHandlers.SpacePaddedToString(bpb.oem_name) }; information = sb.ToString(); } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/HPOFS/Structs.cs b/Aaru.Filesystems/HPOFS/Structs.cs index ba71bf9b2..c9f2cea26 100644 --- a/Aaru.Filesystems/HPOFS/Structs.cs +++ b/Aaru.Filesystems/HPOFS/Structs.cs @@ -7,10 +7,6 @@ // // Component : High Performance Optical File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// High Performance Optical File System structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,17 +23,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +namespace Aaru.Filesystems; + [SuppressMessage("ReSharper", "UnusedType.Local")] public sealed partial class HPOFS { +#region Nested type: BiosParameterBlock + /// BIOS Parameter Block, at sector 0, little-endian [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct BiosParameterBlock @@ -97,6 +95,180 @@ public sealed partial class HPOFS public readonly ushort signature2; } +#endregion + +#region Nested type: Dci + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Dci + { + /// "DATA" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] blockId; + /// Unknown + public readonly uint unknown; + /// Unknown + public readonly uint unknown2; + /// Unknown + public readonly uint unknown3; + /// Unknown + public readonly uint unknown4; + /// Unknown + public readonly uint unknown5; + /// Unknown + public readonly ushort unknown6; + /// Unknown + public readonly ushort unknown7; + /// Unknown + public readonly uint unknown8; + /// Unknown + public readonly uint unknown9; + /// Entries, size unknown + public readonly DciEntry[] entries; + } + +#endregion + +#region Nested type: DciEntry + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DciEntry + { + /// Key length + public readonly ushort key_len; + /// Record length + public readonly ushort record_len; + /// dci key + public readonly DciKey key; + /// Padding? Size is key_len - size of DciKey + public readonly byte[] padding; + /// Direct + public readonly Direct dir; + /// Padding? Size is record_len - size of Direct + public readonly byte[] unknown; + } + +#endregion + +#region Nested type: DciKey + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DciKey + { + /// Unknown + public readonly byte unknown; + /// Name size + 2 + public readonly byte size; + /// Unknown + public readonly byte unknown2; + /// Unknown + public readonly byte unknown3; + /// Unknown + public readonly byte unknown4; + /// Unknown + public readonly byte unknown5; + /// Name, length = size - 2 + public readonly byte[] name; + } + +#endregion + +#region Nested type: Direct + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Direct + { + /// Unknown + public readonly uint unknown; + /// Unknown + public readonly uint unknown2; + /// Unknown + public readonly uint unknown3; + /// Mask 0x6000 + public readonly ushort subfiles_no; + /// Unknown + public readonly ushort unknown4; + /// Unknown + public readonly uint unknown5; + /// Unknown + public readonly uint unknown6; + /// Unknown + public readonly uint unknown7; + /// Some date + public readonly ushort date1; + /// Some time + public readonly ushort time1; + /// Some date + public readonly ushort date2; + /// Some time + public readonly ushort time2; + /// Unknown + public readonly uint unknown8; + /// Unknown + public readonly uint unknown9; + /// Unknown + public readonly uint unknown10; + /// Unknown + public readonly uint unknown11; + /// Unknown + public readonly uint unknown12; + /// Unknown + public readonly uint unknown13; + /// Unknown + public readonly uint unknown14; + /// Subfiles, length unknown + public readonly SubFile[] subfiles; + } + +#endregion + +#region Nested type: Extent + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Extent + { + /// Extent length in sectors + public readonly ushort length; + /// Unknown + public readonly short unknown; + /// Extent starting sector + public readonly int start; + } + +#endregion + +#region Nested type: MasterRecord + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct MasterRecord + { + /// "MAST" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] blockId; + /// Unknown + public readonly uint unknown; + /// Unknown + public readonly ushort unknown2; + /// Unknown + public readonly ushort unknown3; + /// Unknown + public readonly uint unknown4; + /// Unknown + public readonly ushort unknown5; + /// Unknown + public readonly ushort unknown6; + /// Unknown + public readonly ushort unknown7; + /// Unknown + public readonly ushort unknown8; + /// Unknown + public readonly uint unknown9; + } + +#endregion + +#region Nested type: MediaInformationBlock + /// Media Information Block, at sector 13, big-endian [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct MediaInformationBlock @@ -147,6 +319,39 @@ public sealed partial class HPOFS public readonly byte[] filler; } +#endregion + +#region Nested type: SubFile + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SubFile + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public readonly Extent[] extents; + /// Unknown + public readonly uint unknown; + /// Unknown + public readonly uint unknown2; + /// Logical size in bytes + public readonly uint logical_size; + /// Unknown + public readonly uint unknown3; + /// Physical size in bytes + public readonly uint physical_size; + /// Unknown + public readonly uint unknown4; + /// Physical size in bytes + public readonly uint physical_size2; + /// Unknown + public readonly uint unknown5; + /// Unknown + public readonly uint unknown6; + } + +#endregion + +#region Nested type: VolumeInformationBlock + /// Volume Information Block, at sector 14, big-endian [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct VolumeInformationBlock @@ -185,174 +390,5 @@ public sealed partial class HPOFS public readonly byte[] filler; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Extent - { - /// Extent length in sectors - public readonly ushort length; - /// Unknown - public readonly short unknown; - /// Extent starting sector - public readonly int start; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SubFile - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public readonly Extent[] extents; - /// Unknown - public readonly uint unknown; - /// Unknown - public readonly uint unknown2; - /// Logical size in bytes - public readonly uint logical_size; - /// Unknown - public readonly uint unknown3; - /// Physical size in bytes - public readonly uint physical_size; - /// Unknown - public readonly uint unknown4; - /// Physical size in bytes - public readonly uint physical_size2; - /// Unknown - public readonly uint unknown5; - /// Unknown - public readonly uint unknown6; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Direct - { - /// Unknown - public readonly uint unknown; - /// Unknown - public readonly uint unknown2; - /// Unknown - public readonly uint unknown3; - /// Mask 0x6000 - public readonly ushort subfiles_no; - /// Unknown - public readonly ushort unknown4; - /// Unknown - public readonly uint unknown5; - /// Unknown - public readonly uint unknown6; - /// Unknown - public readonly uint unknown7; - /// Some date - public readonly ushort date1; - /// Some time - public readonly ushort time1; - /// Some date - public readonly ushort date2; - /// Some time - public readonly ushort time2; - /// Unknown - public readonly uint unknown8; - /// Unknown - public readonly uint unknown9; - /// Unknown - public readonly uint unknown10; - /// Unknown - public readonly uint unknown11; - /// Unknown - public readonly uint unknown12; - /// Unknown - public readonly uint unknown13; - /// Unknown - public readonly uint unknown14; - /// Subfiles, length unknown - public readonly SubFile[] subfiles; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct MasterRecord - { - /// "MAST" - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] blockId; - /// Unknown - public readonly uint unknown; - /// Unknown - public readonly ushort unknown2; - /// Unknown - public readonly ushort unknown3; - /// Unknown - public readonly uint unknown4; - /// Unknown - public readonly ushort unknown5; - /// Unknown - public readonly ushort unknown6; - /// Unknown - public readonly ushort unknown7; - /// Unknown - public readonly ushort unknown8; - /// Unknown - public readonly uint unknown9; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DciKey - { - /// Unknown - public readonly byte unknown; - /// Name size + 2 - public readonly byte size; - /// Unknown - public readonly byte unknown2; - /// Unknown - public readonly byte unknown3; - /// Unknown - public readonly byte unknown4; - /// Unknown - public readonly byte unknown5; - /// Name, length = size - 2 - public readonly byte[] name; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DciEntry - { - /// Key length - public readonly ushort key_len; - /// Record length - public readonly ushort record_len; - /// dci key - public readonly DciKey key; - /// Padding? Size is key_len - size of DciKey - public readonly byte[] padding; - /// Direct - public readonly Direct dir; - /// Padding? Size is record_len - size of Direct - public readonly byte[] unknown; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Dci - { - /// "DATA" - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] blockId; - /// Unknown - public readonly uint unknown; - /// Unknown - public readonly uint unknown2; - /// Unknown - public readonly uint unknown3; - /// Unknown - public readonly uint unknown4; - /// Unknown - public readonly uint unknown5; - /// Unknown - public readonly ushort unknown6; - /// Unknown - public readonly ushort unknown7; - /// Unknown - public readonly uint unknown8; - /// Unknown - public readonly uint unknown9; - /// Entries, size unknown - public readonly DciEntry[] entries; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Consts/AAIP.cs b/Aaru.Filesystems/ISO9660/Consts/AAIP.cs index 3585f3879..dc2fa6fae 100644 --- a/Aaru.Filesystems/ISO9660/Consts/AAIP.cs +++ b/Aaru.Filesystems/ISO9660/Consts/AAIP.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// AAIP extensions constants and enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,26 +23,30 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ - - // ReSharper disable UnusedMember.Local -namespace Aaru.Filesystems; - using System; +// ReSharper disable UnusedType.Local + +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { const ushort AAIP_MAGIC = 0x414C; // "AL" const ushort AAIP_MAGIC_OLD = 0x4141; // "AA" +#region Nested type: AAIPFlags + [Flags] enum AAIPFlags : byte { Continue = 1 } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Consts/Amiga.cs b/Aaru.Filesystems/ISO9660/Consts/Amiga.cs index b4fb0ad02..47049858f 100644 --- a/Aaru.Filesystems/ISO9660/Consts/Amiga.cs +++ b/Aaru.Filesystems/ISO9660/Consts/Amiga.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Amiga extensions constants and enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,22 +23,39 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ - - // ReSharper disable UnusedMember.Local -namespace Aaru.Filesystems; - using System; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { const ushort AMIGA_MAGIC = 0x4153; // "AS" +#region Nested type: AmigaAttributes + + [Flags] + enum AmigaAttributes : byte + { + OwnerDelete = 1 << 0, + OwnerExec = 1 << 1, + OwnerWrite = 1 << 2, + OwnerRead = 1 << 3, + Archive = 1 << 4, + Reentrant = 1 << 5, + Script = 1 << 6, + Reserved = 1 << 7 + } + +#endregion + +#region Nested type: AmigaFlags + [Flags] enum AmigaFlags : byte { @@ -51,6 +64,10 @@ public sealed partial class ISO9660 CommentContinues = 1 << 2 } +#endregion + +#region Nested type: AmigaMultiuser + [Flags] enum AmigaMultiuser : byte { @@ -64,16 +81,5 @@ public sealed partial class ISO9660 OtherRead = 1 << 7 } - [Flags] - enum AmigaAttributes : byte - { - OwnerDelete = 1 << 0, - OwnerExec = 1 << 1, - OwnerWrite = 1 << 2, - OwnerRead = 1 << 3, - Archive = 1 << 4, - Reentrant = 1 << 5, - Script = 1 << 6, - Reserved = 1 << 7 - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Consts/Apple.cs b/Aaru.Filesystems/ISO9660/Consts/Apple.cs index cd2c009b6..86f49cb52 100644 --- a/Aaru.Filesystems/ISO9660/Consts/Apple.cs +++ b/Aaru.Filesystems/ISO9660/Consts/Apple.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple extensions constants and enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,7 +23,7 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ @@ -38,12 +34,18 @@ public sealed partial class ISO9660 const ushort APPLE_MAGIC = 0x4141; // "AA" const ushort APPLE_MAGIC_OLD = 0x4241; // "BA" +#region Nested type: AppleId + enum AppleId : byte { ProDOS = 1, HFS = 2 } +#endregion + +#region Nested type: AppleOldId + enum AppleOldId : byte { ProDOS = 1, @@ -53,4 +55,6 @@ public sealed partial class ISO9660 TypeCreatorIconBundle = 5, HFS = 6 } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Consts/CDi.cs b/Aaru.Filesystems/ISO9660/Consts/CDi.cs index 99198562b..6a5e541e8 100644 --- a/Aaru.Filesystems/ISO9660/Consts/CDi.cs +++ b/Aaru.Filesystems/ISO9660/Consts/CDi.cs @@ -27,37 +27,24 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ - - // ReSharper disable UnusedMember.Local -namespace Aaru.Filesystems; - using System; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { const string CDI_MAGIC = "CD-I "; static readonly int _cdiDirectoryRecordSize = Marshal.SizeOf(); static readonly int _cdiSystemAreaSize = Marshal.SizeOf(); - [Flags] - enum CdiVolumeFlags : byte - { - // Escapes are not ISO 2375 but ISO 2022 - NotISO2375 = 1 - } - - [Flags] - enum CdiFileFlags : byte - { - Hidden = 0x01 - } +#region Nested type: CdiAttributes [Flags] enum CdiAttributes : ushort @@ -71,4 +58,27 @@ public sealed partial class ISO9660 DigitalAudio = 1 << 14, Directory = 1 << 15 } + +#endregion + +#region Nested type: CdiFileFlags + + [Flags] + enum CdiFileFlags : byte + { + Hidden = 0x01 + } + +#endregion + +#region Nested type: CdiVolumeFlags + + [Flags] + enum CdiVolumeFlags : byte + { + // Escapes are not ISO 2375 but ISO 2022 + NotISO2375 = 1 + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Consts/ElTorito.cs b/Aaru.Filesystems/ISO9660/Consts/ElTorito.cs index 109b29e7b..b2c55f734 100644 --- a/Aaru.Filesystems/ISO9660/Consts/ElTorito.cs +++ b/Aaru.Filesystems/ISO9660/Consts/ElTorito.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// El Torito extensions constants and enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,41 +23,23 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ - - // ReSharper disable UnusedMember.Local -namespace Aaru.Filesystems; - using System; using System.Diagnostics.CodeAnalysis; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { const ushort EL_TORITO_MAGIC = 0xAA55; const int EL_TORITO_ENTRY_SIZE = 32; - enum ElToritoIndicator : byte - { - Header = 1, - Extension = 0x44, - Bootable = 0x88, - MoreHeaders = 0x90, - LastHeader = 0x91 - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - enum ElToritoPlatform : byte - { - x86 = 0, - PowerPC = 1, - Macintosh = 2, - EFI = 0xef - } +#region Nested type: ElToritoEmulation enum ElToritoEmulation : byte { @@ -72,6 +50,10 @@ public sealed partial class ISO9660 Hdd = 4 } +#endregion + +#region Nested type: ElToritoFlags + [Flags] enum ElToritoFlags : byte { @@ -80,4 +62,32 @@ public sealed partial class ISO9660 ATAPI = 0x40, SCSI = 0x08 } + +#endregion + +#region Nested type: ElToritoIndicator + + enum ElToritoIndicator : byte + { + Header = 1, + Extension = 0x44, + Bootable = 0x88, + MoreHeaders = 0x90, + LastHeader = 0x91 + } + +#endregion + +#region Nested type: ElToritoPlatform + + [SuppressMessage("ReSharper", "InconsistentNaming")] + enum ElToritoPlatform : byte + { + x86 = 0, + PowerPC = 1, + Macintosh = 2, + EFI = 0xef + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Consts/HighSierra.cs b/Aaru.Filesystems/ISO9660/Consts/HighSierra.cs index 5bd42017a..fcf11af3d 100644 --- a/Aaru.Filesystems/ISO9660/Consts/HighSierra.cs +++ b/Aaru.Filesystems/ISO9660/Consts/HighSierra.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// High Sierra Format constants and enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,14 +23,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { const string HIGH_SIERRA_MAGIC = "CDROM"; diff --git a/Aaru.Filesystems/ISO9660/Consts/ISO.cs b/Aaru.Filesystems/ISO9660/Consts/ISO.cs index bbe62a958..dcb46cf07 100644 --- a/Aaru.Filesystems/ISO9660/Consts/ISO.cs +++ b/Aaru.Filesystems/ISO9660/Consts/ISO.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// ISO9660 filesystem constants and enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,22 +23,22 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ - - // ReSharper disable UnusedMember.Local -namespace Aaru.Filesystems; - using System; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { const string ISO_MAGIC = "CD001"; +#region Nested type: FileFlags + [Flags] enum FileFlags : byte { @@ -54,6 +50,10 @@ public sealed partial class ISO9660 MultiExtent = 0x80 } +#endregion + +#region Nested type: Permissions + [Flags] enum Permissions : ushort { @@ -67,6 +67,21 @@ public sealed partial class ISO9660 OtherExecute = 0x4000 } +#endregion + +#region Nested type: RecordAttribute + + enum RecordAttribute : byte + { + LFCR = 0, + ISO1539 = 1, + ControlContained = 2 + } + +#endregion + +#region Nested type: RecordFormat + enum RecordFormat : byte { Unspecified = 0, @@ -75,10 +90,5 @@ public sealed partial class ISO9660 VariableLengthAlternate = 3 } - enum RecordAttribute : byte - { - LFCR = 0, - ISO1539 = 1, - ControlContained = 2 - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Consts/Internal.cs b/Aaru.Filesystems/ISO9660/Consts/Internal.cs index 45cf6eff0..4d19ad1a4 100644 --- a/Aaru.Filesystems/ISO9660/Consts/Internal.cs +++ b/Aaru.Filesystems/ISO9660/Consts/Internal.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Internal constants and enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,20 +23,26 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; using Aaru.Helpers; +namespace Aaru.Filesystems; + [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed partial class ISO9660 { - const byte MODE2_FORM2 = 0x20; - static readonly int _directoryRecordSize = Marshal.SizeOf(); + const byte MODE2_FORM2 = 0x20; + + const string FS_TYPE_HSF = "hfs"; + const string FS_TYPE_CDI = "cdi"; + const string FS_TYPE_ISO = "iso9660"; + static readonly int _directoryRecordSize = Marshal.SizeOf(); + +#region Nested type: Namespace enum Namespace { @@ -50,4 +52,6 @@ public sealed partial class ISO9660 Rrip, Romeo } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Consts/RRIP.cs b/Aaru.Filesystems/ISO9660/Consts/RRIP.cs index b0f4ac491..61643bb6f 100644 --- a/Aaru.Filesystems/ISO9660/Consts/RRIP.cs +++ b/Aaru.Filesystems/ISO9660/Consts/RRIP.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// RRIP extensions constants and enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,18 +23,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ - - // ReSharper disable UnusedMember.Local -namespace Aaru.Filesystems; - using System; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { const ushort RRIP_MAGIC = 0x5252; // "RR" @@ -52,6 +46,21 @@ public sealed partial class ISO9660 const ushort RRIP_TIMESTAMPS = 0x5446; // "TF" const ushort RRIP_SPARSE = 0x5346; // "SF" +#region Nested type: AlternateNameFlags + + [Flags] + enum AlternateNameFlags : byte + { + Continue = 1, + Current = 2, + Parent = 4, + Networkname = 32 + } + +#endregion + +#region Nested type: PosixMode + [Flags] enum PosixMode : uint { @@ -76,11 +85,9 @@ public sealed partial class ISO9660 Pipe = 0x1000 } - [Flags] - enum SymlinkFlags : byte - { - Continue = 1 - } +#endregion + +#region Nested type: SymlinkComponentFlags [Flags] enum SymlinkComponentFlags : byte @@ -93,15 +100,20 @@ public sealed partial class ISO9660 Networkname = 32 } +#endregion + +#region Nested type: SymlinkFlags + [Flags] - enum AlternateNameFlags : byte + enum SymlinkFlags : byte { - Continue = 1, - Current = 2, - Parent = 4, - Networkname = 32 + Continue = 1 } +#endregion + +#region Nested type: TimestampFlags + [Flags] enum TimestampFlags : byte { @@ -114,4 +126,6 @@ public sealed partial class ISO9660 Effective = 1 << 6, LongFormat = 1 << 7 } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Consts/SUSP.cs b/Aaru.Filesystems/ISO9660/Consts/SUSP.cs index 943c4b3d6..3140a7fb7 100644 --- a/Aaru.Filesystems/ISO9660/Consts/SUSP.cs +++ b/Aaru.Filesystems/ISO9660/Consts/SUSP.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// SUSP extensions constants and enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,16 +23,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ // ReSharper disable IdentifierTypo -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; +namespace Aaru.Filesystems; + [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed partial class ISO9660 { diff --git a/Aaru.Filesystems/ISO9660/Consts/XA.cs b/Aaru.Filesystems/ISO9660/Consts/XA.cs index 6ee9cb4fd..e47e545eb 100644 --- a/Aaru.Filesystems/ISO9660/Consts/XA.cs +++ b/Aaru.Filesystems/ISO9660/Consts/XA.cs @@ -27,22 +27,39 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ - - // ReSharper disable UnusedMember.Local -namespace Aaru.Filesystems; - using System; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { const ushort XA_MAGIC = 0x5841; // "XA" +#region Nested type: Mode2Submode + + [Flags] + enum Mode2Submode : byte + { + EndOfFile = 0x80, + RealTime = 0x40, + Form2 = 0x20, + Trigger = 0x10, + Data = 0x08, + Audio = 0x04, + Video = 0x02, + EndOfRecord = 0x01 + } + +#endregion + +#region Nested type: XaAttributes + [Flags] enum XaAttributes : ushort { @@ -59,16 +76,5 @@ public sealed partial class ISO9660 Directory = 0x8000 } - [Flags] - enum Mode2Submode : byte - { - EndOfFile = 0x80, - RealTime = 0x40, - Form2 = 0x20, - Trigger = 0x10, - Data = 0x08, - Audio = 0x04, - Video = 0x02, - EndOfRecord = 0x01 - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Consts/Ziso.cs b/Aaru.Filesystems/ISO9660/Consts/Ziso.cs index 4af1fe4f5..2ad211518 100644 --- a/Aaru.Filesystems/ISO9660/Consts/Ziso.cs +++ b/Aaru.Filesystems/ISO9660/Consts/Ziso.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// zisofs extensions constants and enumerations. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,14 +23,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; +namespace Aaru.Filesystems; + [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed partial class ISO9660 { diff --git a/Aaru.Filesystems/ISO9660/Date.cs b/Aaru.Filesystems/ISO9660/Date.cs index a5abe1d64..91d37e2a3 100644 --- a/Aaru.Filesystems/ISO9660/Date.cs +++ b/Aaru.Filesystems/ISO9660/Date.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Decodes timestamps. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,33 +23,37 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { - static DateTime? DecodeIsoDateTime(byte[] timestamp) - { - switch(timestamp?.Length) - { - case 7: return DecodeIsoDateTime(Marshal.ByteArrayToStructureLittleEndian(timestamp)); - case 17: return DateHandlers.Iso9660ToDateTime(timestamp); - default: return null; - } - } + static DateTime? DecodeIsoDateTime(byte[] timestamp) => timestamp?.Length switch + { + 7 => DecodeIsoDateTime(Marshal + .ByteArrayToStructureLittleEndian< + IsoTimestamp>(timestamp)), + 17 => DateHandlers.Iso9660ToDateTime(timestamp), + _ => null + }; static DateTime? DecodeIsoDateTime(IsoTimestamp timestamp) { try { - var date = new DateTime(timestamp.Years + 1900, timestamp.Month, timestamp.Day, timestamp.Hour, - timestamp.Minute, timestamp.Second, DateTimeKind.Unspecified); + var date = new DateTime(timestamp.Years + 1900, + timestamp.Month, + timestamp.Day, + timestamp.Hour, + timestamp.Minute, + timestamp.Second, + DateTimeKind.Unspecified); date = date.AddMinutes(timestamp.GmtOffset * 15); @@ -70,8 +70,13 @@ public sealed partial class ISO9660 { try { - var date = new DateTime(timestamp.Years + 1900, timestamp.Month, timestamp.Day, timestamp.Hour, - timestamp.Minute, timestamp.Second, DateTimeKind.Unspecified); + var date = new DateTime(timestamp.Years + 1900, + timestamp.Month, + timestamp.Day, + timestamp.Hour, + timestamp.Minute, + timestamp.Second, + DateTimeKind.Unspecified); return TimeZoneInfo.ConvertTimeToUtc(date, TimeZoneInfo.FindSystemTimeZoneById("GMT")); } diff --git a/Aaru.Filesystems/ISO9660/Dir.cs b/Aaru.Filesystems/ISO9660/Dir.cs index d01810e28..694e6366f 100644 --- a/Aaru.Filesystems/ISO9660/Dir.cs +++ b/Aaru.Filesystems/ISO9660/Dir.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Handles directory traversal and listing. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,12 +23,10 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Globalization; @@ -40,52 +34,64 @@ using System.IO; using System.Linq; using System.Text; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { Dictionary> _directoryCache; +#region IReadOnlyFilesystem Members + /// - public ErrorNumber ReadDir(string path, out List contents) + public ErrorNumber OpenDir(string path, out IDirNode node) { - contents = null; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - if(string.IsNullOrWhiteSpace(path) || - path == "/") + if(string.IsNullOrWhiteSpace(path) || path == "/") { - contents = GetFilenames(_rootDirectoryCache); + node = new Iso9660DirNode + { + Path = path, + Position = 0, + Entries = _rootDirectoryCache.Values.ToArray() + }; return ErrorNumber.NoError; } string cutPath = path.StartsWith("/", StringComparison.Ordinal) - ? path.Substring(1).ToLower(CultureInfo.CurrentUICulture) + ? path[1..].ToLower(CultureInfo.CurrentUICulture) : path.ToLower(CultureInfo.CurrentUICulture); if(_directoryCache.TryGetValue(cutPath, out Dictionary currentDirectory)) { - contents = currentDirectory.Keys.ToList(); + node = new Iso9660DirNode + { + Path = path, + Position = 0, + Entries = currentDirectory.Values.ToArray() + }; return ErrorNumber.NoError; } string[] pieces = cutPath.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); KeyValuePair entry = - _rootDirectoryCache.FirstOrDefault(t => t.Key.ToLower(CultureInfo.CurrentUICulture) == pieces[0]); + _rootDirectoryCache.FirstOrDefault(t => t.Key.Equals(pieces[0], StringComparison.CurrentCultureIgnoreCase)); - if(string.IsNullOrEmpty(entry.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(entry.Key)) return ErrorNumber.NoSuchFile; - if(!entry.Value.Flags.HasFlag(FileFlags.Directory)) - return ErrorNumber.NotDirectory; + if(!entry.Value.Flags.HasFlag(FileFlags.Directory)) return ErrorNumber.NotDirectory; string currentPath = pieces[0]; @@ -93,72 +99,104 @@ public sealed partial class ISO9660 for(var p = 0; p < pieces.Length; p++) { - entry = currentDirectory.FirstOrDefault(t => t.Key.ToLower(CultureInfo.CurrentUICulture) == pieces[p]); + entry = currentDirectory.FirstOrDefault(t => t.Key.Equals(pieces[p], + StringComparison.CurrentCultureIgnoreCase)); - if(string.IsNullOrEmpty(entry.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(entry.Key)) return ErrorNumber.NoSuchFile; - if(!entry.Value.Flags.HasFlag(FileFlags.Directory)) - return ErrorNumber.NotDirectory; + if(!entry.Value.Flags.HasFlag(FileFlags.Directory)) return ErrorNumber.NotDirectory; currentPath = p == 0 ? pieces[0] : $"{currentPath}/{pieces[p]}"; - if(_directoryCache.TryGetValue(currentPath, out currentDirectory)) - continue; + if(_directoryCache.TryGetValue(currentPath, out currentDirectory)) continue; - if(entry.Value.Extents.Count == 0) - return ErrorNumber.InvalidArgument; + if(entry.Value.Extents.Count == 0) return ErrorNumber.InvalidArgument; currentDirectory = _cdi ? DecodeCdiDirectory(entry.Value.Extents[0].extent + entry.Value.XattrLength, entry.Value.Extents[0].size) : _highSierra - ? DecodeHighSierraDirectory(entry.Value.Extents[0].extent + entry.Value.XattrLength, + ? DecodeHighSierraDirectory(entry.Value.Extents[0].extent + + entry.Value.XattrLength, entry.Value.Extents[0].size) : DecodeIsoDirectory(entry.Value.Extents[0].extent + entry.Value.XattrLength, entry.Value.Extents[0].size); if(_usePathTable) + { foreach(DecodedDirectoryEntry subDirectory in _cdi ? GetSubdirsFromCdiPathTable(currentPath) : _highSierra ? GetSubdirsFromHighSierraPathTable(currentPath) : GetSubdirsFromIsoPathTable(currentPath)) currentDirectory[subDirectory.Filename] = subDirectory; + } _directoryCache.Add(currentPath, currentDirectory); } - contents = GetFilenames(currentDirectory); + if(currentDirectory is null) return ErrorNumber.NoSuchFile; + + node = new Iso9660DirNode + { + Path = path, + Position = 0, + Entries = currentDirectory.Values.ToArray() + }; return ErrorNumber.NoError; } - List GetFilenames(Dictionary dirents) + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) { - List contents = new(); + filename = null; - foreach(DecodedDirectoryEntry entry in dirents.Values) - switch(_namespace) - { - case Namespace.Normal: - contents.Add(entry.Filename.EndsWith(";1", StringComparison.Ordinal) - ? entry.Filename.Substring(0, entry.Filename.Length - 2) : entry.Filename); + if(!_mounted) return ErrorNumber.AccessDenied; - break; - case Namespace.Vms: - case Namespace.Joliet: - case Namespace.Rrip: - case Namespace.Romeo: - contents.Add(entry.Filename); + if(node is not Iso9660DirNode mynode) return ErrorNumber.InvalidArgument; - break; - default: throw new ArgumentOutOfRangeException(); - } + if(mynode.Position < 0) return ErrorNumber.InvalidArgument; - return contents; + if(mynode.Position >= mynode.Entries.Length) return ErrorNumber.NoError; + + switch(_namespace) + { + case Namespace.Normal: + filename = mynode.Entries[mynode.Position].Filename.EndsWith(";1", StringComparison.Ordinal) + ? mynode.Entries[mynode.Position].Filename[..^2] + : mynode.Entries[mynode.Position].Filename; + + break; + case Namespace.Vms: + case Namespace.Joliet: + case Namespace.Rrip: + case Namespace.Romeo: + filename = mynode.Entries[mynode.Position].Filename; + + break; + default: + return ErrorNumber.InvalidArgument; + } + + mynode.Position++; + + return ErrorNumber.NoError; } + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not Iso9660DirNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Position = -1; + mynode.Entries = null; + + return ErrorNumber.NoError; + } + +#endregion + Dictionary DecodeCdiDirectory(ulong start, uint size) { Dictionary entries = new(); @@ -166,8 +204,7 @@ public sealed partial class ISO9660 ErrorNumber errno = ReadSingleExtent(size, (uint)start, out byte[] data); - if(errno != ErrorNumber.NoError) - return entries; + if(errno != ErrorNumber.NoError) return entries; while(entryOff + _cdiDirectoryRecordSize < data.Length) { @@ -189,27 +226,26 @@ public sealed partial class ISO9660 // Special entries for current and parent directories, skip them if(record.name_len == 1) - if(data[entryOff + _directoryRecordSize] == 0 || - data[entryOff + _directoryRecordSize] == 1) + { + if(data[entryOff + _directoryRecordSize] == 0 || data[entryOff + _directoryRecordSize] == 1) { entryOff += record.length; continue; } + } var entry = new DecodedDirectoryEntry { Size = record.size, - Filename = Encoding.GetString(data, entryOff + _directoryRecordSize, record.name_len), + Filename = _encoding.GetString(data, entryOff + _directoryRecordSize, record.name_len), VolumeSequenceNumber = record.volume_sequence_number, Timestamp = DecodeHighSierraDateTime(record.date), - XattrLength = record.xattr_len + XattrLength = record.xattr_len, + Extents = [] }; - entry.Extents = new List<(uint extent, uint size)>(); - - if(record.size != 0) - entry.Extents.Add((record.start_lbn, record.size)); + if(record.size != 0) entry.Extents.Add((record.start_lbn, record.size)); if(record.flags.HasFlag(CdiFileFlags.Hidden)) { @@ -220,8 +256,7 @@ public sealed partial class ISO9660 int systemAreaStart = entryOff + record.name_len + _cdiDirectoryRecordSize; - if(systemAreaStart % 2 != 0) - systemAreaStart++; + if(systemAreaStart % 2 != 0) systemAreaStart++; entry.CdiSystemArea = Marshal.ByteArrayToStructureBigEndian(data, systemAreaStart, _cdiSystemAreaSize); @@ -229,8 +264,7 @@ public sealed partial class ISO9660 if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.Directory)) entry.Flags |= FileFlags.Directory; - if(!entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.Directory) || - !_usePathTable) + if(!entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.Directory) || !_usePathTable) entries[entry.Filename] = entry; entryOff += record.length; @@ -246,13 +280,13 @@ public sealed partial class ISO9660 ErrorNumber errno = ReadSingleExtent(size, (uint)start, out byte[] data); - if(errno != ErrorNumber.NoError) - return entries; + if(errno != ErrorNumber.NoError) return entries; while(entryOff + _directoryRecordSize < data.Length) { HighSierraDirectoryRecord record = - Marshal.ByteArrayToStructureLittleEndian(data, entryOff, + Marshal.ByteArrayToStructureLittleEndian(data, + entryOff, _highSierraDirectoryRecordSize); if(record.length == 0) @@ -270,13 +304,14 @@ public sealed partial class ISO9660 // Special entries for current and parent directories, skip them if(record.name_len == 1) - if(data[entryOff + _directoryRecordSize] == 0 || - data[entryOff + _directoryRecordSize] == 1) + { + if(data[entryOff + _directoryRecordSize] == 0 || data[entryOff + _directoryRecordSize] == 1) { entryOff += record.length; continue; } + } var entry = new DecodedDirectoryEntry { @@ -284,15 +319,13 @@ public sealed partial class ISO9660 Flags = record.flags, Interleave = record.interleave, VolumeSequenceNumber = record.volume_sequence_number, - Filename = Encoding.GetString(data, entryOff + _directoryRecordSize, record.name_len), + Filename = _encoding.GetString(data, entryOff + _directoryRecordSize, record.name_len), Timestamp = DecodeHighSierraDateTime(record.date), - XattrLength = record.xattr_len + XattrLength = record.xattr_len, + Extents = [] }; - entry.Extents = new List<(uint extent, uint size)>(); - - if(record.size != 0) - entry.Extents.Add((record.extent, record.size)); + if(record.size != 0) entry.Extents.Add((record.extent, record.size)); if(entry.Flags.HasFlag(FileFlags.Directory) && _usePathTable) { @@ -301,14 +334,12 @@ public sealed partial class ISO9660 continue; } - if(!entries.ContainsKey(entry.Filename)) - entries.Add(entry.Filename, entry); + entries.TryAdd(entry.Filename, entry); entryOff += record.length; } - if(_useTransTbl) - DecodeTransTable(entries); + if(_useTransTbl) DecodeTransTable(entries); return entries; } @@ -320,8 +351,7 @@ public sealed partial class ISO9660 ErrorNumber errno = ReadSingleExtent(size, (uint)start, out byte[] data); - if(errno != ErrorNumber.NoError) - return entries; + if(errno != ErrorNumber.NoError) return entries; while(entryOff + _directoryRecordSize < data.Length) { @@ -343,33 +373,33 @@ public sealed partial class ISO9660 // Special entries for current and parent directories, skip them if(record.name_len == 1) - if(data[entryOff + _directoryRecordSize] == 0 || - data[entryOff + _directoryRecordSize] == 1) + { + if(data[entryOff + _directoryRecordSize] == 0 || data[entryOff + _directoryRecordSize] == 1) { entryOff += record.length; continue; } + } var entry = new DecodedDirectoryEntry { Size = record.size, Flags = record.flags, - Filename = - _joliet ? Encoding.BigEndianUnicode.GetString(data, entryOff + _directoryRecordSize, - record.name_len) - : Encoding.GetString(data, entryOff + _directoryRecordSize, record.name_len), + Filename = _joliet + ? Encoding.BigEndianUnicode.GetString(data, + entryOff + _directoryRecordSize, + record.name_len) + : _encoding.GetString(data, entryOff + _directoryRecordSize, record.name_len), FileUnitSize = record.file_unit_size, Interleave = record.interleave, VolumeSequenceNumber = record.volume_sequence_number, Timestamp = DecodeIsoDateTime(record.date), - XattrLength = record.xattr_len + XattrLength = record.xattr_len, + Extents = [] }; - entry.Extents = new List<(uint extent, uint size)>(); - - if(record.size != 0) - entry.Extents.Add((record.extent, record.size)); + if(record.size != 0) entry.Extents.Add((record.extent, record.size)); if(entry.Flags.HasFlag(FileFlags.Directory) && _usePathTable) { @@ -382,15 +412,13 @@ public sealed partial class ISO9660 entry.Filename = entry.Filename.Replace('/', '\u2215'); // Tailing '.' is only allowed on RRIP. If present it will be recreated below with the alternate name - if(entry.Filename.EndsWith(".", StringComparison.Ordinal)) - entry.Filename = entry.Filename.Substring(0, entry.Filename.Length - 1); + if(entry.Filename.EndsWith(".", StringComparison.Ordinal)) entry.Filename = entry.Filename[..^1]; - if(entry.Filename.EndsWith(".;1", StringComparison.Ordinal)) - entry.Filename = entry.Filename.Substring(0, entry.Filename.Length - 3) + ";1"; + if(entry.Filename.EndsWith(".;1", StringComparison.Ordinal)) entry.Filename = entry.Filename[..^3] + ";1"; // This is a legal Joliet name, different from VMS version fields, but Nero MAX incorrectly creates these filenames if(_joliet && entry.Filename.EndsWith(";1", StringComparison.Ordinal)) - entry.Filename = entry.Filename.Substring(0, entry.Filename.Length - 2); + entry.Filename = entry.Filename[..^2]; int systemAreaStart = entryOff + record.name_len + _directoryRecordSize; int systemAreaLength = record.length - record.name_len - _directoryRecordSize; @@ -401,7 +429,10 @@ public sealed partial class ISO9660 systemAreaLength--; } - DecodeSystemArea(data, systemAreaStart, systemAreaStart + systemAreaLength, ref entry, + DecodeSystemArea(data, + systemAreaStart, + systemAreaStart + systemAreaLength, + ref entry, out bool hasResourceFork); if(entry.Flags.HasFlag(FileFlags.Associated)) @@ -448,7 +479,7 @@ public sealed partial class ISO9660 // Can appear after an associated file if(entries[entry.Filename].Extents is null) { - entries[entry.Filename].Extents = new List<(uint extent, uint size)>(); + entries[entry.Filename].Extents = []; entries[entry.Filename].Flags = entry.Flags; entries[entry.Filename].FileUnitSize = entry.FileUnitSize; entries[entry.Filename].Interleave = entry.Interleave; @@ -458,8 +489,7 @@ public sealed partial class ISO9660 entries[entry.Filename].XattrLength = entry.XattrLength; } - if(entry.Extents?.Count > 0) - entries[entry.Filename].Extents.Add(entry.Extents[0]); + if(entry.Extents?.Count > 0) entries[entry.Filename].Extents.Add(entry.Extents[0]); } else entries[entry.Filename] = entry; @@ -468,50 +498,54 @@ public sealed partial class ISO9660 entryOff += record.length; } - if(_useTransTbl) - DecodeTransTable(entries); + if(_useTransTbl) DecodeTransTable(entries); // Relocated directories should be shown in correct place when using Rock Ridge namespace return _namespace == Namespace.Rrip - ? entries.Where(e => !e.Value.RockRidgeRelocated).ToDictionary(x => x.Key, x => x.Value) : entries; + ? entries.Where(e => !e.Value.RockRidgeRelocated).ToDictionary(x => x.Key, x => x.Value) + : entries; } void DecodeTransTable(Dictionary entries) { KeyValuePair transTblEntry = entries.FirstOrDefault(e => !e.Value.Flags.HasFlag(FileFlags.Directory) && - (e.Value.Filename.ToLower(CultureInfo.CurrentUICulture) == "trans.tbl" || - e.Value.Filename.ToLower(CultureInfo.CurrentUICulture) == "trans.tbl;1")); + (e.Value.Filename.Equals("trans.tbl", + StringComparison.CurrentCultureIgnoreCase) || + e.Value.Filename.Equals("trans.tbl;1", + StringComparison.CurrentCultureIgnoreCase))); - if(transTblEntry.Value == null) - return; + if(transTblEntry.Value == null) return; - ErrorNumber errno = ReadWithExtents(0, (long)transTblEntry.Value.Size, transTblEntry.Value.Extents, + ErrorNumber errno = ReadWithExtents(0, + (long)transTblEntry.Value.Size, + transTblEntry.Value.Extents, transTblEntry.Value.XA?.signature == XA_MAGIC && transTblEntry.Value.XA?.attributes.HasFlag(XaAttributes.Interleaved) == - true, transTblEntry.Value.XA?.filenumber ?? 0, out byte[] transTbl); + true, + transTblEntry.Value.XA?.filenumber ?? 0, + out byte[] transTbl); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; var mr = new MemoryStream(transTbl, 0, (int)transTblEntry.Value.Size, false); - var sr = new StreamReader(mr, Encoding); + var sr = new StreamReader(mr, _encoding); string line = sr.ReadLine(); while(line != null) { // Skip the type field and the first space - string cutLine = line.Substring(2); + string cutLine = line[2..]; int spaceIndex = cutLine.IndexOf(' '); - string originalName = cutLine.Substring(0, spaceIndex); + string originalName = cutLine[..spaceIndex]; string originalNameWithVersion; - string newName = cutLine.Substring(spaceIndex + 1).TrimStart(); + string newName = cutLine[(spaceIndex + 1)..].TrimStart(); if(originalName.EndsWith(";1", StringComparison.Ordinal)) { originalNameWithVersion = originalName.ToLower(CultureInfo.CurrentUICulture); - originalName = originalNameWithVersion.Substring(0, originalName.Length - 2); + originalName = originalNameWithVersion[..(originalName.Length - 2)]; } else { @@ -524,9 +558,10 @@ public sealed partial class ISO9660 KeyValuePair originalEntry = entries.FirstOrDefault(e => !e.Value.Flags.HasFlag(FileFlags.Directory) && - (e.Value.Filename.ToLower(CultureInfo.CurrentUICulture) == originalName || - e.Value.Filename.ToLower(CultureInfo.CurrentUICulture) == - originalNameWithVersion)); + (e.Value.Filename.Equals(originalName, + StringComparison.CurrentCultureIgnoreCase) || + e.Value.Filename.Equals(originalNameWithVersion, + StringComparison.CurrentCultureIgnoreCase))); originalEntry.Value.Filename = newName; entries.Remove(originalEntry.Key); @@ -540,16 +575,16 @@ public sealed partial class ISO9660 { int systemAreaOff = start; hasResourceFork = false; - var continueSymlink = false; - var continueSymlinkComponent = false; - AppleCommon.FInfo fInfo; + var continueSymlink = false; + var continueSymlinkComponent = false; while(systemAreaOff + 2 <= end) { var systemAreaSignature = BigEndianBitConverter.ToUInt16(data, systemAreaOff); - if(BigEndianBitConverter.ToUInt16(data, systemAreaOff + 6) == XA_MAGIC) - systemAreaSignature = XA_MAGIC; + if(BigEndianBitConverter.ToUInt16(data, systemAreaOff + 6) == XA_MAGIC) systemAreaSignature = XA_MAGIC; + + AppleCommon.FInfo fInfo; switch(systemAreaSignature) { @@ -558,15 +593,14 @@ public sealed partial class ISO9660 var appleId = (AppleId)data[systemAreaOff + 3]; // Old AAIP - if(appleId == AppleId.ProDOS && - appleLength != 7) - goto case AAIP_MAGIC; + if(appleId == AppleId.ProDOS && appleLength != 7) goto case AAIP_MAGIC; switch(appleId) { case AppleId.ProDOS: AppleProDOSSystemUse appleProDosSystemUse = - Marshal.ByteArrayToStructureLittleEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureLittleEndian(data, + systemAreaOff, Marshal.SizeOf()); entry.AppleProDosType = appleProDosSystemUse.aux_type; @@ -575,15 +609,19 @@ public sealed partial class ISO9660 break; case AppleId.HFS: AppleHFSSystemUse appleHfsSystemUse = - Marshal.ByteArrayToStructureBigEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureBigEndian(data, + systemAreaOff, Marshal.SizeOf()); hasResourceFork = true; - fInfo = new AppleCommon.FInfo(); - fInfo.fdCreator = appleHfsSystemUse.creator; - fInfo.fdFlags = appleHfsSystemUse.finder_flags; - fInfo.fdType = appleHfsSystemUse.type; + fInfo = new AppleCommon.FInfo + { + fdCreator = appleHfsSystemUse.creator, + fdFlags = appleHfsSystemUse.finder_flags, + fdType = appleHfsSystemUse.type + }; + entry.FinderInfo = fInfo; break; @@ -599,7 +637,8 @@ public sealed partial class ISO9660 { case AppleOldId.ProDOS: AppleProDOSOldSystemUse appleProDosOldSystemUse = - Marshal.ByteArrayToStructureLittleEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureLittleEndian(data, + systemAreaOff, Marshal.SizeOf()); entry.AppleProDosType = appleProDosOldSystemUse.aux_type; @@ -611,14 +650,18 @@ public sealed partial class ISO9660 case AppleOldId.TypeCreator: case AppleOldId.TypeCreatorBundle: AppleHFSTypeCreatorSystemUse appleHfsTypeCreatorSystemUse = - Marshal.ByteArrayToStructureBigEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureBigEndian(data, + systemAreaOff, Marshal.SizeOf()); hasResourceFork = true; - fInfo = new AppleCommon.FInfo(); - fInfo.fdCreator = appleHfsTypeCreatorSystemUse.creator; - fInfo.fdType = appleHfsTypeCreatorSystemUse.type; + fInfo = new AppleCommon.FInfo + { + fdCreator = appleHfsTypeCreatorSystemUse.creator, + fdType = appleHfsTypeCreatorSystemUse.type + }; + entry.FinderInfo = fInfo; systemAreaOff += Marshal.SizeOf(); @@ -627,14 +670,18 @@ public sealed partial class ISO9660 case AppleOldId.TypeCreatorIcon: case AppleOldId.TypeCreatorIconBundle: AppleHFSIconSystemUse appleHfsIconSystemUse = - Marshal.ByteArrayToStructureBigEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureBigEndian(data, + systemAreaOff, Marshal.SizeOf()); hasResourceFork = true; - fInfo = new AppleCommon.FInfo(); - fInfo.fdCreator = appleHfsIconSystemUse.creator; - fInfo.fdType = appleHfsIconSystemUse.type; + fInfo = new AppleCommon.FInfo + { + fdCreator = appleHfsIconSystemUse.creator, + fdType = appleHfsIconSystemUse.type + }; + entry.FinderInfo = fInfo; entry.AppleIcon = appleHfsIconSystemUse.icon; @@ -643,15 +690,19 @@ public sealed partial class ISO9660 break; case AppleOldId.HFS: AppleHFSOldSystemUse appleHfsSystemUse = - Marshal.ByteArrayToStructureBigEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureBigEndian(data, + systemAreaOff, Marshal.SizeOf()); hasResourceFork = true; - fInfo = new AppleCommon.FInfo(); - fInfo.fdCreator = appleHfsSystemUse.creator; - fInfo.fdFlags = (AppleCommon.FinderFlags)appleHfsSystemUse.finder_flags; - fInfo.fdType = appleHfsSystemUse.type; + fInfo = new AppleCommon.FInfo + { + fdCreator = appleHfsSystemUse.creator, + fdFlags = (AppleCommon.FinderFlags)appleHfsSystemUse.finder_flags, + fdType = appleHfsSystemUse.type + }; + entry.FinderInfo = fInfo; systemAreaOff += Marshal.SizeOf(); @@ -666,7 +717,8 @@ public sealed partial class ISO9660 break; case XA_MAGIC: - entry.XA = Marshal.ByteArrayToStructureBigEndian(data, systemAreaOff, + entry.XA = Marshal.ByteArrayToStructureBigEndian(data, + systemAreaOff, Marshal.SizeOf()); systemAreaOff += Marshal.SizeOf(); @@ -677,7 +729,8 @@ public sealed partial class ISO9660 case AAIP_MAGIC: case AMIGA_MAGIC: AmigaEntry amiga = - Marshal.ByteArrayToStructureBigEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureBigEndian(data, + systemAreaOff, Marshal.SizeOf()); var protectionLength = 0; @@ -686,24 +739,27 @@ public sealed partial class ISO9660 { entry.AmigaProtection = Marshal.ByteArrayToStructureBigEndian(data, - systemAreaOff + Marshal.SizeOf(), Marshal.SizeOf()); + systemAreaOff + Marshal.SizeOf(), + Marshal.SizeOf()); protectionLength = Marshal.SizeOf(); } if(amiga.flags.HasFlag(AmigaFlags.Comment)) { - if(entry.AmigaComment is null) - entry.AmigaComment = Array.Empty(); + entry.AmigaComment ??= []; var newComment = new byte[entry.AmigaComment.Length + - data - [systemAreaOff + Marshal.SizeOf() + protectionLength] - + data[systemAreaOff + + Marshal.SizeOf() + + protectionLength] - 1]; Array.Copy(entry.AmigaComment, 0, newComment, 0, entry.AmigaComment.Length); - Array.Copy(data, systemAreaOff + Marshal.SizeOf() + protectionLength, newComment, + Array.Copy(data, + systemAreaOff + Marshal.SizeOf() + protectionLength, + newComment, entry.AmigaComment.Length, data[systemAreaOff + Marshal.SizeOf() + protectionLength] - 1); @@ -723,14 +779,23 @@ public sealed partial class ISO9660 case RRIP_POSIX_ATTRIBUTES: byte pxLength = data[systemAreaOff + 2]; - if(pxLength == 36) - entry.PosixAttributesOld = - Marshal.ByteArrayToStructureLittleEndian(data, systemAreaOff, - Marshal.SizeOf()); - else if(pxLength >= 44) - entry.PosixAttributes = - Marshal.ByteArrayToStructureLittleEndian(data, systemAreaOff, - Marshal.SizeOf()); + switch(pxLength) + { + case 36: + entry.PosixAttributesOld = + Marshal.ByteArrayToStructureLittleEndian(data, + systemAreaOff, + Marshal.SizeOf()); + + break; + case >= 44: + entry.PosixAttributes = + Marshal.ByteArrayToStructureLittleEndian(data, + systemAreaOff, + Marshal.SizeOf()); + + break; + } systemAreaOff += pxLength; @@ -739,7 +804,8 @@ public sealed partial class ISO9660 byte pnLength = data[systemAreaOff + 2]; entry.PosixDeviceNumber = - Marshal.ByteArrayToStructureLittleEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureLittleEndian(data, + systemAreaOff, Marshal.SizeOf()); systemAreaOff += pnLength; @@ -749,7 +815,8 @@ public sealed partial class ISO9660 byte slLength = data[systemAreaOff + 2]; SymbolicLink sl = - Marshal.ByteArrayToStructureLittleEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureLittleEndian(data, + systemAreaOff, Marshal.SizeOf()); SymbolicLinkComponent slc = @@ -757,33 +824,30 @@ public sealed partial class ISO9660 systemAreaOff + Marshal.SizeOf(), Marshal.SizeOf()); - if(!continueSymlink || - entry.SymbolicLink is null) - entry.SymbolicLink = ""; + if(!continueSymlink || entry.SymbolicLink is null) entry.SymbolicLink = ""; - if(slc.flags.HasFlag(SymlinkComponentFlags.Root)) - entry.SymbolicLink = "/"; + if(slc.flags.HasFlag(SymlinkComponentFlags.Root)) entry.SymbolicLink = "/"; - if(slc.flags.HasFlag(SymlinkComponentFlags.Current)) - entry.SymbolicLink += "."; + if(slc.flags.HasFlag(SymlinkComponentFlags.Current)) entry.SymbolicLink += "."; - if(slc.flags.HasFlag(SymlinkComponentFlags.Parent)) - entry.SymbolicLink += ".."; + if(slc.flags.HasFlag(SymlinkComponentFlags.Parent)) entry.SymbolicLink += ".."; - if(!continueSymlinkComponent && - !slc.flags.HasFlag(SymlinkComponentFlags.Root)) + if(!continueSymlinkComponent && !slc.flags.HasFlag(SymlinkComponentFlags.Root)) entry.SymbolicLink += "/"; entry.SymbolicLink += slc.flags.HasFlag(SymlinkComponentFlags.Networkname) ? Environment.MachineName : _joliet ? Encoding.BigEndianUnicode.GetString(data, - systemAreaOff + Marshal.SizeOf() + - Marshal.SizeOf(), slc.length) - : Encoding.GetString(data, - systemAreaOff + Marshal.SizeOf() + - Marshal.SizeOf(), - slc.length); + systemAreaOff + + Marshal.SizeOf() + + Marshal.SizeOf(), + slc.length) + : _encoding.GetString(data, + systemAreaOff + + Marshal.SizeOf() + + Marshal.SizeOf(), + slc.length); continueSymlink = sl.flags.HasFlag(SymlinkFlags.Continue); continueSymlinkComponent = slc.flags.HasFlag(SymlinkComponentFlags.Continue); @@ -802,14 +866,18 @@ public sealed partial class ISO9660 } AlternateName alternateName = - Marshal.ByteArrayToStructureLittleEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureLittleEndian(data, + systemAreaOff, Marshal.SizeOf()); byte[] nm; if(alternateName.flags.HasFlag(AlternateNameFlags.Networkname)) - nm = _joliet ? Encoding.BigEndianUnicode.GetBytes(Environment.MachineName) - : Encoding.GetBytes(Environment.MachineName); + { + nm = _joliet + ? Encoding.BigEndianUnicode.GetBytes(Environment.MachineName) + : _encoding.GetBytes(Environment.MachineName); + } else { nm = new byte[nmLength - Marshal.SizeOf()]; @@ -817,19 +885,19 @@ public sealed partial class ISO9660 Array.Copy(data, systemAreaOff + Marshal.SizeOf(), nm, 0, nm.Length); } - if(entry.RockRidgeAlternateName is null) - entry.RockRidgeAlternateName = Array.Empty(); + entry.RockRidgeAlternateName ??= []; var newNm = new byte[entry.RockRidgeAlternateName.Length + nm.Length]; Array.Copy(entry.RockRidgeAlternateName, 0, newNm, 0, entry.RockRidgeAlternateName.Length); - Array.Copy(nm, 0, newNm, entry.RockRidgeAlternateName.Length, nm.Length); + Array.Copy(nm, 0, newNm, entry.RockRidgeAlternateName.Length, nm.Length); entry.RockRidgeAlternateName = newNm; if(!alternateName.flags.HasFlag(AlternateNameFlags.Continue)) { - entry.Filename = _joliet ? Encoding.BigEndianUnicode.GetString(entry.RockRidgeAlternateName) - : Encoding.GetString(entry.RockRidgeAlternateName); + entry.Filename = _joliet + ? Encoding.BigEndianUnicode.GetString(entry.RockRidgeAlternateName) + : _encoding.GetString(entry.RockRidgeAlternateName); entry.RockRidgeAlternateName = null; } @@ -849,7 +917,8 @@ public sealed partial class ISO9660 } ChildLink cl = - Marshal.ByteArrayToStructureLittleEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureLittleEndian(data, + systemAreaOff, Marshal.SizeOf()); ErrorNumber errno = ReadSector(cl.child_dir_lba, out byte[] childSector); @@ -866,10 +935,7 @@ public sealed partial class ISO9660 // As per RRIP 4.1.5.1, we leave name as in previous entry, substitute location with the one in // the CL, and replace all other fields with the ones found in the first entry of the child - entry.Extents = new List<(uint extent, uint size)> - { - (cl.child_dir_lba, childRecord.size) - }; + entry.Extents = [(cl.child_dir_lba, childRecord.size)]; entry.Size = childRecord.size; entry.Flags = childRecord.flags; @@ -899,7 +965,8 @@ public sealed partial class ISO9660 byte tfLength = data[systemAreaOff + 2]; Timestamps timestamps = - Marshal.ByteArrayToStructureLittleEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureLittleEndian(data, + systemAreaOff, Marshal.SizeOf()); int tfOff = systemAreaOff + Marshal.SizeOf(); @@ -966,12 +1033,14 @@ public sealed partial class ISO9660 byte ceLength = data[systemAreaOff + 2]; ContinuationArea ca = - Marshal.ByteArrayToStructureLittleEndian(data, systemAreaOff, + Marshal.ByteArrayToStructureLittleEndian(data, + systemAreaOff, Marshal.SizeOf()); errno = ReadSingleExtent(ca.offset, ca.ca_length, ca.block, out byte[] caData); - if(errno == ErrorNumber.NoError) + // TODO: Check continuation area definition, this is not a proper fix + if(errno == ErrorNumber.NoError && caData.Length > 0) DecodeSystemArea(caData, 0, (int)ca.ca_length, ref entry, out hasResourceFork); systemAreaOff += ceLength; @@ -1022,23 +1091,24 @@ public sealed partial class ISO9660 } } - PathTableEntryInternal[] GetPathTableEntries(string path) + IEnumerable GetPathTableEntries(string path) { IEnumerable tableEntries; - List pathTableList = new(_pathTable); + List pathTableList = [.._pathTable]; if(path is "" or "/") tableEntries = _pathTable.Where(p => p.Parent == 1 && p != _pathTable[0]); else { string cutPath = path.StartsWith("/", StringComparison.Ordinal) - ? path.Substring(1).ToLower(CultureInfo.CurrentUICulture) + ? path[1..].ToLower(CultureInfo.CurrentUICulture) : path.ToLower(CultureInfo.CurrentUICulture); string[] pieces = cutPath.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); var currentParent = 1; var currentPiece = 0; @@ -1046,12 +1116,12 @@ public sealed partial class ISO9660 while(currentPiece < pieces.Length) { PathTableEntryInternal currentEntry = _pathTable.FirstOrDefault(p => p.Parent == currentParent && - p.Name.ToLower(CultureInfo. - CurrentUICulture) == - pieces[currentPiece]); + p.Name.Equals(pieces + [currentPiece], + StringComparison + .CurrentCultureIgnoreCase)); - if(currentEntry is null) - break; + if(currentEntry is null) break; currentPiece++; currentParent = pathTableList.IndexOf(currentEntry) + 1; @@ -1065,22 +1135,21 @@ public sealed partial class ISO9660 DecodedDirectoryEntry[] GetSubdirsFromCdiPathTable(string path) { - PathTableEntryInternal[] tableEntries = GetPathTableEntries(path); - List entries = new(); + IEnumerable tableEntries = GetPathTableEntries(path); + List entries = []; foreach(PathTableEntryInternal tEntry in tableEntries) { ErrorNumber errno = ReadSector(tEntry.Extent, out byte[] sector); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; CdiDirectoryRecord record = - Marshal.ByteArrayToStructureBigEndian(sector, tEntry.XattrLength, + Marshal.ByteArrayToStructureBigEndian(sector, + tEntry.XattrLength, _cdiDirectoryRecordSize); - if(record.length == 0) - break; + if(record.length == 0) break; var entry = new DecodedDirectoryEntry { @@ -1088,21 +1157,17 @@ public sealed partial class ISO9660 Filename = tEntry.Name, VolumeSequenceNumber = record.volume_sequence_number, Timestamp = DecodeHighSierraDateTime(record.date), - XattrLength = tEntry.XattrLength + XattrLength = tEntry.XattrLength, + Extents = [] }; - entry.Extents = new List<(uint extent, uint size)>(); + if(record.size != 0) entry.Extents.Add((record.start_lbn, record.size)); - if(record.size != 0) - entry.Extents.Add((record.start_lbn, record.size)); - - if(record.flags.HasFlag(CdiFileFlags.Hidden)) - entry.Flags |= FileFlags.Hidden; + if(record.flags.HasFlag(CdiFileFlags.Hidden)) entry.Flags |= FileFlags.Hidden; int systemAreaStart = record.name_len + _cdiDirectoryRecordSize; - if(systemAreaStart % 2 != 0) - systemAreaStart++; + if(systemAreaStart % 2 != 0) systemAreaStart++; entry.CdiSystemArea = Marshal.ByteArrayToStructureBigEndian(sector, systemAreaStart, _cdiSystemAreaSize); @@ -1118,22 +1183,21 @@ public sealed partial class ISO9660 DecodedDirectoryEntry[] GetSubdirsFromIsoPathTable(string path) { - PathTableEntryInternal[] tableEntries = GetPathTableEntries(path); - List entries = new(); + IEnumerable tableEntries = GetPathTableEntries(path); + List entries = []; foreach(PathTableEntryInternal tEntry in tableEntries) { ErrorNumber errno = ReadSector(tEntry.Extent, out byte[] sector); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; DirectoryRecord record = - Marshal.ByteArrayToStructureLittleEndian(sector, tEntry.XattrLength, + Marshal.ByteArrayToStructureLittleEndian(sector, + tEntry.XattrLength, _directoryRecordSize); - if(record.length == 0) - break; + if(record.length == 0) break; var entry = new DecodedDirectoryEntry { @@ -1144,13 +1208,11 @@ public sealed partial class ISO9660 Interleave = record.interleave, VolumeSequenceNumber = record.volume_sequence_number, Timestamp = DecodeIsoDateTime(record.date), - XattrLength = tEntry.XattrLength + XattrLength = tEntry.XattrLength, + Extents = [] }; - entry.Extents = new List<(uint extent, uint size)>(); - - if(record.size != 0) - entry.Extents.Add((record.extent, record.size)); + if(record.size != 0) entry.Extents.Add((record.extent, record.size)); int systemAreaStart = record.name_len + _directoryRecordSize; int systemAreaLength = record.length - record.name_len - _directoryRecordSize; @@ -1171,18 +1233,18 @@ public sealed partial class ISO9660 DecodedDirectoryEntry[] GetSubdirsFromHighSierraPathTable(string path) { - PathTableEntryInternal[] tableEntries = GetPathTableEntries(path); - List entries = new(); + IEnumerable tableEntries = GetPathTableEntries(path); + List entries = []; foreach(PathTableEntryInternal tEntry in tableEntries) { ErrorNumber errno = ReadSector(tEntry.Extent, out byte[] sector); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; HighSierraDirectoryRecord record = - Marshal.ByteArrayToStructureLittleEndian(sector, tEntry.XattrLength, + Marshal.ByteArrayToStructureLittleEndian(sector, + tEntry.XattrLength, _highSierraDirectoryRecordSize); var entry = new DecodedDirectoryEntry @@ -1193,13 +1255,11 @@ public sealed partial class ISO9660 Interleave = record.interleave, VolumeSequenceNumber = record.volume_sequence_number, Timestamp = DecodeHighSierraDateTime(record.date), - XattrLength = tEntry.XattrLength + XattrLength = tEntry.XattrLength, + Extents = [] }; - entry.Extents = new List<(uint extent, uint size)>(); - - if(record.size != 0) - entry.Extents.Add((record.extent, record.size)); + if(record.size != 0) entry.Extents.Add((record.extent, record.size)); entries.Add(entry); } diff --git a/Aaru.Filesystems/ISO9660/File.cs b/Aaru.Filesystems/ISO9660/File.cs index 189b09fe7..44e5e2e16 100644 --- a/Aaru.Filesystems/ISO9660/File.cs +++ b/Aaru.Filesystems/ISO9660/File.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Handles file and extents. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,12 +23,10 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Globalization; @@ -40,127 +34,149 @@ using System.IO; using System.Linq; using System.Runtime.CompilerServices; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Helpers; using FileAttributes = Aaru.CommonTypes.Structs.FileAttributes; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { - /// - public ErrorNumber MapBlock(string path, long fileBlock, out long deviceBlock) - { - deviceBlock = 0; - - if(!_mounted) - return ErrorNumber.AccessDenied; - - ErrorNumber err = GetFileEntry(path, out DecodedDirectoryEntry entry); - - if(err != ErrorNumber.NoError) - return err; - - if(entry.Flags.HasFlag(FileFlags.Directory) && - !_debug) - return ErrorNumber.IsDirectory; - - // TODO: Multi-extents - if(entry.Extents.Count > 1) - return ErrorNumber.NotImplemented; - - deviceBlock = entry.Extents[0].extent + fileBlock; - - return ErrorNumber.NoError; - } +#region IReadOnlyFilesystem Members /// public ErrorNumber GetAttributes(string path, out FileAttributes attributes) { attributes = new FileAttributes(); - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = Stat(path, out FileEntryInfo stat); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; attributes = stat.Attributes; return ErrorNumber.NoError; } - // TODO: Resolve symbolic link /// - public ErrorNumber Read(string path, long offset, long size, ref byte[] buf) + public ErrorNumber OpenFile(string path, out IFileNode node) { - buf = null; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = GetFileEntry(path, out DecodedDirectoryEntry entry); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; - if(entry.Flags.HasFlag(FileFlags.Directory) && - !_debug) - return ErrorNumber.IsDirectory; + if(entry.Flags.HasFlag(FileFlags.Directory) && !_debug) return ErrorNumber.IsDirectory; - if(entry.Extents is null) - return ErrorNumber.InvalidArgument; + if(entry.Extents is null) return ErrorNumber.InvalidArgument; - if(entry.Size == 0) + node = new Iso9660FileNode { - buf = Array.Empty(); + Path = path, + Length = (long)entry.Size, + Offset = 0, + Dentry = entry + }; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseFile(IFileNode node) + { + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not Iso9660FileNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Dentry = null; + + return ErrorNumber.NoError; + } + + // TODO: Resolve symbolic link + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(buffer is null || buffer.Length < length) return ErrorNumber.InvalidArgument; + + if(node is not Iso9660FileNode mynode) return ErrorNumber.InvalidArgument; + + read = length; + + if(length + mynode.Offset >= mynode.Length) read = mynode.Length - mynode.Offset; + + long offset = mynode.Offset + mynode.Dentry.XattrLength * _blockSize; + + if(mynode.Dentry.CdiSystemArea?.attributes.HasFlag(CdiAttributes.DigitalAudio) != true || + mynode.Dentry.Extents.Count != 1) + { + ErrorNumber err = ReadWithExtents(offset, + read, + mynode.Dentry.Extents, + mynode.Dentry.XA?.signature == XA_MAGIC && + mynode.Dentry.XA?.attributes.HasFlag(XaAttributes.Interleaved) == true, + mynode.Dentry.XA?.filenumber ?? 0, + out byte[] buf); + + if(err != ErrorNumber.NoError) + { + read = 0; + + return err; + } + + Array.Copy(buf, 0, buffer, 0, read); + + node.Offset += read; return ErrorNumber.NoError; } - if(offset >= (long)entry.Size) - return ErrorNumber.InvalidArgument; + try + { + long firstSector = offset / 2352; + long offsetInSector = offset % 2352; + long sizeInSectors = (read + offsetInSector) / 2352; - if(size + offset >= (long)entry.Size) - size = (long)entry.Size - offset; + if((read + offsetInSector) % 2352 > 0) sizeInSectors++; - offset += entry.XattrLength * _blockSize; + ErrorNumber errno = _image.ReadSectorsLong((ulong)(mynode.Dentry.Extents[0].extent + firstSector), + (uint)sizeInSectors, + out byte[] buf); - if(entry.CdiSystemArea?.attributes.HasFlag(CdiAttributes.DigitalAudio) == true && - entry.Extents.Count == 1) - try + if(errno != ErrorNumber.NoError) { - long firstSector = offset / 2352; - long offsetInSector = offset % 2352; - long sizeInSectors = (size + offsetInSector) / 2352; + read = 0; - if((size + offsetInSector) % 2352 > 0) - sizeInSectors++; - - ErrorNumber errno = _image.ReadSectorsLong((ulong)(entry.Extents[0].extent + firstSector), - (uint)sizeInSectors, out byte[] buffer); - - if(errno != ErrorNumber.NoError) - return errno; - - buf = new byte[size]; - Array.Copy(buffer, offsetInSector, buf, 0, size); - - return ErrorNumber.NoError; - } - catch(Exception e) - { - AaruConsole.DebugWriteLine("ISO9660 plugin", "Exception reading CD-i audio file"); - AaruConsole.DebugWriteLine("ISO9660 plugin", "{0}", e); - - return ErrorNumber.UnexpectedException; + return errno; } - return ReadWithExtents(offset, size, entry.Extents, - entry.XA?.signature == XA_MAGIC && - entry.XA?.attributes.HasFlag(XaAttributes.Interleaved) == true, - entry.XA?.filenumber ?? 0, out buf); + Array.Copy(buf, offsetInSector, buffer, 0, read); + + node.Offset += read; + + return ErrorNumber.NoError; + } + catch(Exception ex) + { + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Exception_reading_CD_i_audio_file); + AaruConsole.WriteException(ex); + + read = 0; + + return ErrorNumber.UnexpectedException; + } } /// @@ -168,13 +184,11 @@ public sealed partial class ISO9660 { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = GetFileEntry(path, out DecodedDirectoryEntry entry); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; stat = new FileEntryInfo { @@ -186,17 +200,13 @@ public sealed partial class ISO9660 LastWriteTimeUtc = entry.Timestamp }; - if(entry.Extents?.Count > 0) - stat.Inode = entry.Extents[0].extent; + if(entry.Extents?.Count > 0) stat.Inode = entry.Extents[0].extent; - if(entry.Size % 2048 > 0) - stat.Blocks++; + if(entry.Size % 2048 > 0) stat.Blocks++; - if(entry.Flags.HasFlag(FileFlags.Directory)) - stat.Attributes |= FileAttributes.Directory; + if(entry.Flags.HasFlag(FileFlags.Directory)) stat.Attributes |= FileAttributes.Directory; - if(entry.Flags.HasFlag(FileFlags.Hidden)) - stat.Attributes |= FileAttributes.Hidden; + if(entry.Flags.HasFlag(FileFlags.Hidden)) stat.Attributes |= FileAttributes.Hidden; if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsAlias) == true) stat.Attributes |= FileAttributes.Alias; @@ -225,28 +235,21 @@ public sealed partial class ISO9660 if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasBundle) == true) stat.Attributes |= FileAttributes.Bundle; - if(entry.AppleIcon != null) - stat.Attributes |= FileAttributes.HasCustomIcon; + if(entry.AppleIcon != null) stat.Attributes |= FileAttributes.HasCustomIcon; if(entry.XA != null) { - if(entry.XA.Value.attributes.HasFlag(XaAttributes.GroupExecute)) - stat.Mode |= 8; + if(entry.XA.Value.attributes.HasFlag(XaAttributes.GroupExecute)) stat.Mode |= 8; - if(entry.XA.Value.attributes.HasFlag(XaAttributes.GroupRead)) - stat.Mode |= 32; + if(entry.XA.Value.attributes.HasFlag(XaAttributes.GroupRead)) stat.Mode |= 32; - if(entry.XA.Value.attributes.HasFlag(XaAttributes.OwnerExecute)) - stat.Mode |= 64; + if(entry.XA.Value.attributes.HasFlag(XaAttributes.OwnerExecute)) stat.Mode |= 64; - if(entry.XA.Value.attributes.HasFlag(XaAttributes.OwnerRead)) - stat.Mode |= 256; + if(entry.XA.Value.attributes.HasFlag(XaAttributes.OwnerRead)) stat.Mode |= 256; - if(entry.XA.Value.attributes.HasFlag(XaAttributes.SystemExecute)) - stat.Mode |= 1; + if(entry.XA.Value.attributes.HasFlag(XaAttributes.SystemExecute)) stat.Mode |= 1; - if(entry.XA.Value.attributes.HasFlag(XaAttributes.SystemRead)) - stat.Mode |= 4; + if(entry.XA.Value.attributes.HasFlag(XaAttributes.SystemRead)) stat.Mode |= 4; stat.UID = entry.XA.Value.user; stat.GID = entry.XA.Value.group; @@ -263,11 +266,9 @@ public sealed partial class ISO9660 if(entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Character)) stat.Attributes |= FileAttributes.CharDevice; - if(entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Pipe)) - stat.Attributes |= FileAttributes.Pipe; + if(entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Pipe)) stat.Attributes |= FileAttributes.Pipe; - if(entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Socket)) - stat.Attributes |= FileAttributes.Socket; + if(entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Socket)) stat.Attributes |= FileAttributes.Socket; if(entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Symlink)) stat.Attributes |= FileAttributes.Symlink; @@ -287,8 +288,7 @@ public sealed partial class ISO9660 if(entry.PosixAttributesOld.Value.st_mode.HasFlag(PosixMode.Character)) stat.Attributes |= FileAttributes.CharDevice; - if(entry.PosixAttributesOld.Value.st_mode.HasFlag(PosixMode.Pipe)) - stat.Attributes |= FileAttributes.Pipe; + if(entry.PosixAttributesOld.Value.st_mode.HasFlag(PosixMode.Pipe)) stat.Attributes |= FileAttributes.Pipe; if(entry.PosixAttributesOld.Value.st_mode.HasFlag(PosixMode.Socket)) stat.Attributes |= FileAttributes.Socket; @@ -303,89 +303,67 @@ public sealed partial class ISO9660 if(entry.AmigaProtection != null) { - if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.GroupExec)) - stat.Mode |= 8; + if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.GroupExec)) stat.Mode |= 8; - if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.GroupRead)) - stat.Mode |= 32; + if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.GroupRead)) stat.Mode |= 32; - if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.GroupWrite)) - stat.Mode |= 16; + if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.GroupWrite)) stat.Mode |= 16; - if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.OtherExec)) - stat.Mode |= 1; + if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.OtherExec)) stat.Mode |= 1; - if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.OtherRead)) - stat.Mode |= 4; + if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.OtherRead)) stat.Mode |= 4; - if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.OtherWrite)) - stat.Mode |= 2; + if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.OtherWrite)) stat.Mode |= 2; - if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.OwnerExec)) - stat.Mode |= 64; + if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.OwnerExec)) stat.Mode |= 64; - if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.OwnerRead)) - stat.Mode |= 256; + if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.OwnerRead)) stat.Mode |= 256; - if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.OwnerWrite)) - stat.Mode |= 128; + if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.OwnerWrite)) stat.Mode |= 128; if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.Archive)) stat.Attributes |= FileAttributes.Archive; } if(entry.PosixDeviceNumber != null) + { stat.DeviceNo = ((ulong)entry.PosixDeviceNumber.Value.dev_t_high << 32) + entry.PosixDeviceNumber.Value.dev_t_low; + } - if(entry.RripModify != null) - stat.LastWriteTimeUtc = DecodeIsoDateTime(entry.RripModify); + if(entry.RripModify != null) stat.LastWriteTimeUtc = DecodeIsoDateTime(entry.RripModify); - if(entry.RripAccess != null) - stat.AccessTimeUtc = DecodeIsoDateTime(entry.RripAccess); + if(entry.RripAccess != null) stat.AccessTimeUtc = DecodeIsoDateTime(entry.RripAccess); - if(entry.RripAttributeChange != null) - stat.StatusChangeTimeUtc = DecodeIsoDateTime(entry.RripAttributeChange); + if(entry.RripAttributeChange != null) stat.StatusChangeTimeUtc = DecodeIsoDateTime(entry.RripAttributeChange); - if(entry.RripBackup != null) - stat.BackupTimeUtc = DecodeIsoDateTime(entry.RripBackup); + if(entry.RripBackup != null) stat.BackupTimeUtc = DecodeIsoDateTime(entry.RripBackup); - if(entry.SymbolicLink != null) - stat.Attributes |= FileAttributes.Symlink; + if(entry.SymbolicLink != null) stat.Attributes |= FileAttributes.Symlink; - if(entry.XattrLength == 0 || - _cdi || - _highSierra) - return ErrorNumber.NoError; + if(entry.XattrLength == 0 || _cdi || _highSierra) return ErrorNumber.NoError; if(entry.CdiSystemArea != null) { stat.UID = entry.CdiSystemArea.Value.owner; stat.GID = entry.CdiSystemArea.Value.group; - if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.GroupExecute)) - stat.Mode |= 8; + if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.GroupExecute)) stat.Mode |= 8; - if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.GroupRead)) - stat.Mode |= 32; + if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.GroupRead)) stat.Mode |= 32; - if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OtherExecute)) - stat.Mode |= 1; + if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OtherExecute)) stat.Mode |= 1; - if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OtherRead)) - stat.Mode |= 4; + if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OtherRead)) stat.Mode |= 4; - if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OwnerExecute)) - stat.Mode |= 64; + if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OwnerExecute)) stat.Mode |= 64; - if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OwnerRead)) - stat.Mode |= 256; + if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OwnerRead)) stat.Mode |= 256; } ErrorNumber errno = ReadSingleExtent(entry.XattrLength * _blockSize, entry.Extents[0].extent, out byte[] ea); - if(errno != ErrorNumber.NoError) - return ErrorNumber.NoError; + if(errno != ErrorNumber.NoError) return ErrorNumber.NoError; ExtendedAttributeRecord ear = Marshal.ByteArrayToStructureLittleEndian(ea); @@ -394,23 +372,17 @@ public sealed partial class ISO9660 stat.Mode = 0; - if(ear.permissions.HasFlag(Permissions.GroupExecute)) - stat.Mode |= 8; + if(ear.permissions.HasFlag(Permissions.GroupExecute)) stat.Mode |= 8; - if(ear.permissions.HasFlag(Permissions.GroupRead)) - stat.Mode |= 32; + if(ear.permissions.HasFlag(Permissions.GroupRead)) stat.Mode |= 32; - if(ear.permissions.HasFlag(Permissions.OwnerExecute)) - stat.Mode |= 64; + if(ear.permissions.HasFlag(Permissions.OwnerExecute)) stat.Mode |= 64; - if(ear.permissions.HasFlag(Permissions.OwnerRead)) - stat.Mode |= 256; + if(ear.permissions.HasFlag(Permissions.OwnerRead)) stat.Mode |= 256; - if(ear.permissions.HasFlag(Permissions.OtherExecute)) - stat.Mode |= 1; + if(ear.permissions.HasFlag(Permissions.OtherExecute)) stat.Mode |= 1; - if(ear.permissions.HasFlag(Permissions.OtherRead)) - stat.Mode |= 4; + if(ear.permissions.HasFlag(Permissions.OtherRead)) stat.Mode |= 4; stat.CreationTimeUtc = DateHandlers.Iso9660ToDateTime(ear.creation_date); stat.LastWriteTimeUtc = DateHandlers.Iso9660ToDateTime(ear.modification_date); @@ -425,62 +397,61 @@ public sealed partial class ISO9660 ErrorNumber err = GetFileEntry(path, out DecodedDirectoryEntry entry); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; - if(entry.SymbolicLink is null) - return ErrorNumber.InvalidArgument; + if(entry.SymbolicLink is null) return ErrorNumber.InvalidArgument; dest = entry.SymbolicLink; return ErrorNumber.NoError; } +#endregion + ErrorNumber GetFileEntry(string path, out DecodedDirectoryEntry entry) { entry = null; string cutPath = path.StartsWith("/", StringComparison.Ordinal) - ? path.Substring(1).ToLower(CultureInfo.CurrentUICulture) + ? path[1..].ToLower(CultureInfo.CurrentUICulture) : path.ToLower(CultureInfo.CurrentUICulture); string[] pieces = cutPath.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pieces.Length == 0) - return ErrorNumber.InvalidArgument; + if(pieces.Length == 0) return ErrorNumber.InvalidArgument; var parentPath = string.Join("/", pieces, 0, pieces.Length - 1); if(!_directoryCache.TryGetValue(parentPath, out _)) { - ErrorNumber err = ReadDir(parentPath, out _); + ErrorNumber err = OpenDir(parentPath, out IDirNode node); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; + + CloseDir(node); } Dictionary parent; if(pieces.Length == 1) parent = _rootDirectoryCache; - else if(!_directoryCache.TryGetValue(parentPath, out parent)) - return ErrorNumber.InvalidArgument; + else if(!_directoryCache.TryGetValue(parentPath, out parent)) return ErrorNumber.InvalidArgument; KeyValuePair dirent = - parent.FirstOrDefault(t => t.Key.ToLower(CultureInfo.CurrentUICulture) == pieces[^1]); + parent.FirstOrDefault(t => t.Key.Equals(pieces[^1], StringComparison.CurrentCultureIgnoreCase)); if(string.IsNullOrEmpty(dirent.Key)) { - if(!_joliet && - !pieces[^1].EndsWith(";1", StringComparison.Ordinal)) + if(!_joliet && !pieces[^1].EndsWith(";1", StringComparison.Ordinal)) { - dirent = parent.FirstOrDefault(t => t.Key.ToLower(CultureInfo.CurrentUICulture) == pieces[^1] + ";1"); + dirent = parent.FirstOrDefault(t => t.Key.Equals(pieces[^1] + ";1", + StringComparison.CurrentCultureIgnoreCase)); - if(string.IsNullOrEmpty(dirent.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(dirent.Key)) return ErrorNumber.NoSuchFile; } else return ErrorNumber.NoSuchFile; @@ -493,21 +464,24 @@ public sealed partial class ISO9660 [MethodImpl(MethodImplOptions.AggressiveInlining)] ErrorNumber ReadSingleExtent(long size, uint startingSector, out byte[] buffer, bool interleaved = false, - byte fileNumber = 0) => ReadWithExtents(0, size, new List<(uint extent, uint size)> - { - (startingSector, (uint)size) - }, interleaved, fileNumber, out buffer); + byte fileNumber = 0) => ReadWithExtents(0, + size, + [(startingSector, (uint)size)], + interleaved, + fileNumber, + out buffer); [MethodImpl(MethodImplOptions.AggressiveInlining)] - ErrorNumber ReadSingleExtent(long offset, long size, uint startingSector, out byte[] buffer, - bool interleaved = false, byte fileNumber = 0) => ReadWithExtents(offset, size, - new List<(uint extent, uint size)> - { - (startingSector, (uint)size) - }, interleaved, fileNumber, out buffer); + ErrorNumber ReadSingleExtent(long offset, long size, uint startingSector, out byte[] buffer, + bool interleaved = false, byte fileNumber = 0) => ReadWithExtents(offset, + size, + [(startingSector, (uint)size)], + interleaved, + fileNumber, + out buffer); // Cannot think how to make this faster, as we don't know the mode sector until it is read, but we have size in bytes - ErrorNumber ReadWithExtents(long offset, long size, List<(uint extent, uint size)> extents, bool interleaved, + ErrorNumber ReadWithExtents(long offset, long size, List<(uint extent, uint size)> extents, bool interleaved, byte fileNumber, out byte[] buffer) { var ms = new MemoryStream(); @@ -527,7 +501,9 @@ public sealed partial class ISO9660 while(leftExtentSize > 0) { - ErrorNumber errno = ReadSector(extents[i].extent + currentExtentSector, out byte[] sector, interleaved, + ErrorNumber errno = ReadSector(extents[i].extent + currentExtentSector, + out byte[] sector, + interleaved, fileNumber); if(errno != ErrorNumber.NoError) @@ -564,16 +540,13 @@ public sealed partial class ISO9660 leftExtentSize -= sector.Length; currentFilePos += sector.Length; - if(ms.Length >= size) - break; + if(ms.Length >= size) break; } - if(ms.Length >= size) - break; + if(ms.Length >= size) break; } - if(ms.Length >= size) - ms.SetLength(size); + if(ms.Length >= size) ms.SetLength(size); buffer = ms.ToArray(); @@ -592,10 +565,10 @@ public sealed partial class ISO9660 while(leftExtentSize > 0) { ErrorNumber errno = _image.ReadSectorTag((extents[i].extent + currentExtentSector) * _blockSize / 2048, - SectorTagType.CdSectorSubHeader, out byte[] fullSector); + SectorTagType.CdSectorSubHeader, + out byte[] fullSector); - if(errno != ErrorNumber.NoError) - return null; + if(errno != ErrorNumber.NoError) return null; ms.Write(fullSector, copy ? 0 : 4, 4); diff --git a/Aaru.Filesystems/ISO9660/ISO9660.cs b/Aaru.Filesystems/ISO9660/ISO9660.cs index f3a4a0fe4..9034de882 100644 --- a/Aaru.Filesystems/ISO9660/ISO9660.cs +++ b/Aaru.Filesystems/ISO9660/ISO9660.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Constructors and common variables for the ISO9660 filesystem plugin. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,19 +23,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; -using Schemas; + +namespace Aaru.Filesystems; // This is coded following ECMA-119. /// @@ -47,8 +43,11 @@ using Schemas; [SuppressMessage("ReSharper", "UnusedType.Local")] public sealed partial class ISO9660 : IReadOnlyFilesystem { + const string MODULE_NAME = "ISO9660 plugin"; + ushort _blockSize; bool _cdi; bool _debug; + Encoding _encoding; bool _highSierra; IMediaImage _image; bool _joliet; @@ -60,18 +59,20 @@ public sealed partial class ISO9660 : IReadOnlyFilesystem bool _useEvd; bool _usePathTable; bool _useTransTbl; - ushort _blockSize; + +#region IReadOnlyFilesystem Members /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } + public FileSystem Metadata { get; private set; } + /// public string Name => "ISO9660 Filesystem"; + /// public Guid Id => new("d812f4d3-c357-400d-90fd-3b22ef786aa8"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public IEnumerable<(string name, Type type, string description)> SupportedOptions => @@ -103,6 +104,8 @@ public sealed partial class ISO9660 : IReadOnlyFilesystem } }; +#endregion + static Dictionary GetDefaultOptions() => new() { { diff --git a/Aaru.Filesystems/ISO9660/Info.cs b/Aaru.Filesystems/ISO9660/Info.cs index b8ab5a79a..8c123c372 100644 --- a/Aaru.Filesystems/ISO9660/Info.cs +++ b/Aaru.Filesystems/ISO9660/Info.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the ISO9660 filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,71 +23,71 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Text; using Aaru.Checksums; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Decoders.Sega; using Aaru.Helpers; -using Schemas; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class ISO9660 { +#region IReadOnlyFilesystem Members + /// public bool Identify(IMediaImage imagePlugin, Partition partition) { // ISO9660 is designed for 2048 bytes/sector devices - if(imagePlugin.Info.SectorSize < 2048) - return false; + if(imagePlugin.Info.SectorSize < 2048) return false; // ISO9660 Primary Volume Descriptor starts at sector 16, so that's minimal size. - if(partition.End <= 16 + partition.Start) - return false; + if(partition.End <= 16 + partition.Start) return false; // Read to Volume Descriptor ErrorNumber errno = imagePlugin.ReadSector(16 + partition.Start, out byte[] vdSector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; var xaOff = 0; - if(vdSector.Length == 2336) - xaOff = 8; + if(vdSector.Length == 2336) xaOff = 8; byte vdType = vdSector[0 + xaOff]; var vdMagic = new byte[5]; var hsMagic = new byte[5]; // This indicates the end of a volume descriptor. HighSierra here would have 16 so no problem - if(vdType == 255) - return false; + if(vdType == 255) return false; Array.Copy(vdSector, 0x001 + xaOff, vdMagic, 0, 5); Array.Copy(vdSector, 0x009 + xaOff, hsMagic, 0, 5); - AaruConsole.DebugWriteLine("ISO9660 plugin", "VDMagic = {0}", Encoding.ASCII.GetString(vdMagic)); - AaruConsole.DebugWriteLine("ISO9660 plugin", "HSMagic = {0}", Encoding.ASCII.GetString(hsMagic)); + AaruConsole.DebugWriteLine(MODULE_NAME, "VDMagic = {0}", Encoding.ASCII.GetString(vdMagic)); + AaruConsole.DebugWriteLine(MODULE_NAME, "HSMagic = {0}", Encoding.ASCII.GetString(hsMagic)); return Encoding.ASCII.GetString(vdMagic) == ISO_MAGIC || - Encoding.ASCII.GetString(hsMagic) == HIGH_SIERRA_MAGIC || Encoding.ASCII.GetString(vdMagic) == CDI_MAGIC; + Encoding.ASCII.GetString(hsMagic) == HIGH_SIERRA_MAGIC || + Encoding.ASCII.GetString(vdMagic) == CDI_MAGIC; } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = encoding ?? Encoding.ASCII; - information = ""; + encoding ??= Encoding.ASCII; + information = ""; + metadata = new FileSystem(); var isoMetadata = new StringBuilder(); var vdMagic = new byte[5]; // Volume Descriptor magic "CD001" var hsMagic = new byte[5]; // Volume Descriptor magic "CDROM" @@ -106,27 +102,23 @@ public sealed partial class ISO9660 ElToritoBootRecord? torito = null; // ISO9660 is designed for 2048 bytes/sector devices - if(imagePlugin.Info.SectorSize < 2048) - return; + if(imagePlugin.Info.SectorSize < 2048) return; // ISO9660 Primary Volume Descriptor starts at sector 16, so that's minimal size. - if(partition.End < 16) - return; + if(partition.End < 16) return; ulong counter = 0; ErrorNumber errno = imagePlugin.ReadSector(16 + partition.Start, out byte[] vdSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; int xaOff = vdSector.Length == 2336 ? 8 : 0; Array.Copy(vdSector, 0x009 + xaOff, hsMagic, 0, 5); - bool highSierraInfo = Encoding.GetString(hsMagic) == HIGH_SIERRA_MAGIC; + bool highSierraInfo = encoding.GetString(hsMagic) == HIGH_SIERRA_MAGIC; var hsOff = 0; - if(highSierraInfo) - hsOff = 8; + if(highSierraInfo) hsOff = 8; var cdiInfo = false; var evd = false; @@ -134,25 +126,23 @@ public sealed partial class ISO9660 while(true) { - AaruConsole.DebugWriteLine("ISO9660 plugin", "Processing VD loop no. {0}", counter); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Processing_VD_loop_no_0, counter); // Seek to Volume Descriptor - AaruConsole.DebugWriteLine("ISO9660 plugin", "Reading sector {0}", 16 + counter + partition.Start); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_sector_0, 16 + counter + partition.Start); errno = imagePlugin.ReadSector(16 + counter + partition.Start, out byte[] vdSectorTmp); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; vdSector = new byte[vdSectorTmp.Length - xaOff]; Array.Copy(vdSectorTmp, xaOff, vdSector, 0, vdSector.Length); byte vdType = vdSector[0 + hsOff]; // Volume Descriptor Type, should be 1 or 2. - AaruConsole.DebugWriteLine("ISO9660 plugin", "VDType = {0}", vdType); + AaruConsole.DebugWriteLine(MODULE_NAME, "VDType = {0}", vdType); if(vdType == 255) // Supposedly we are in the PVD. { - if(counter == 0) - return; + if(counter == 0) return; break; } @@ -160,17 +150,16 @@ public sealed partial class ISO9660 Array.Copy(vdSector, 0x001, vdMagic, 0, 5); Array.Copy(vdSector, 0x009, hsMagic, 0, 5); - if(Encoding.GetString(vdMagic) != ISO_MAGIC && - Encoding.GetString(hsMagic) != HIGH_SIERRA_MAGIC && - Encoding.GetString(vdMagic) != CDI_MAGIC) // Recognized, it is an ISO9660, now check for rest of data. + if(encoding.GetString(vdMagic) != ISO_MAGIC && + encoding.GetString(hsMagic) != HIGH_SIERRA_MAGIC && + encoding.GetString(vdMagic) != CDI_MAGIC) // Recognized, it is an ISO9660, now check for rest of data. { - if(counter == 0) - return; + if(counter == 0) return; break; } - cdiInfo |= Encoding.GetString(vdMagic) == CDI_MAGIC; + cdiInfo |= encoding.GetString(vdMagic) == CDI_MAGIC; switch(vdType) { @@ -178,9 +167,9 @@ public sealed partial class ISO9660 { bvd = Marshal.ByteArrayToStructureLittleEndian(vdSector, hsOff, 2048 - hsOff); - bootSpec = "Unknown"; + bootSpec = Localization.Unknown_specification; - if(Encoding.GetString(bvd.Value.system_id).Substring(0, 23) == "EL TORITO SPECIFICATION") + if(encoding.GetString(bvd.Value.system_id)[..23] == "EL TORITO SPECIFICATION") { bootSpec = "El Torito"; @@ -211,15 +200,18 @@ public sealed partial class ISO9660 // Check if this is Joliet if(svd.version == 1) { - if(svd.escape_sequences[0] == '%' && - svd.escape_sequences[1] == '/') + if(svd.escape_sequences[0] == '%' && svd.escape_sequences[1] == '/') + { if(svd.escape_sequences[2] == '@' || svd.escape_sequences[2] == 'C' || svd.escape_sequences[2] == 'E') jolietvd = svd; else - AaruConsole.WriteLine("ISO9660 plugin", - "Found unknown supplementary volume descriptor"); + { + AaruConsole.WriteLine(MODULE_NAME, + Localization.Found_unknown_supplementary_volume_descriptor); + } + } } else evd = true; @@ -241,13 +233,11 @@ public sealed partial class ISO9660 DecodedVolumeDescriptor decodedVd; var decodedJolietVd = new DecodedVolumeDescriptor(); - XmlFsType = new FileSystemType(); + metadata = new FileSystem(); - if(pvd == null && - hsvd == null && - fsvd == null) + if(pvd == null && hsvd == null && fsvd == null) { - information = "ERROR: Could not find primary volume descriptor"; + information = Localization.ERROR_Could_not_find_primary_volume_descriptor; return; } @@ -259,8 +249,7 @@ public sealed partial class ISO9660 else decodedVd = DecodeVolumeDescriptor(pvd.Value); - if(jolietvd != null) - decodedJolietVd = DecodeJolietDescriptor(jolietvd.Value); + if(jolietvd != null) decodedJolietVd = DecodeJolietDescriptor(jolietvd.Value); uint rootLocation = 0; uint rootSize = 0; @@ -268,26 +257,25 @@ public sealed partial class ISO9660 // No need to read root on CD-i, as extensions are not supported... if(!cdiInfo) { - rootLocation = highSierraInfo ? hsvd.Value.root_directory_record.extent + rootLocation = highSierraInfo + ? hsvd.Value.root_directory_record.extent : pvd.Value.root_directory_record.extent; if(highSierraInfo) { rootSize = hsvd.Value.root_directory_record.size / hsvd.Value.logical_block_size; - if(hsvd.Value.root_directory_record.size % hsvd.Value.logical_block_size > 0) - rootSize++; + if(hsvd.Value.root_directory_record.size % hsvd.Value.logical_block_size > 0) rootSize++; } else { rootSize = pvd.Value.root_directory_record.size / pvd.Value.logical_block_size; - if(pvd.Value.root_directory_record.size % pvd.Value.logical_block_size > 0) - rootSize++; + if(pvd.Value.root_directory_record.size % pvd.Value.logical_block_size > 0) rootSize++; } } - byte[] rootDir = Array.Empty(); + byte[] rootDir = []; var rootOff = 0; var xaExtensions = false; var apple = false; @@ -296,32 +284,30 @@ public sealed partial class ISO9660 var ziso = false; var amiga = false; var aaip = false; - List contareas = new(); - List refareas = new(); + List contareas = []; + List refareas = []; var suspInformation = new StringBuilder(); if(rootLocation + rootSize < imagePlugin.Info.Sectors) { errno = imagePlugin.ReadSectors(rootLocation, rootSize, out rootDir); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; } // Walk thru root directory to see system area extensions in use - while(rootOff + Marshal.SizeOf() < rootDir.Length && - !cdiInfo) + while(rootOff + Marshal.SizeOf() < rootDir.Length && !cdiInfo) { DirectoryRecord record = - Marshal.ByteArrayToStructureLittleEndian(rootDir, rootOff, + Marshal.ByteArrayToStructureLittleEndian(rootDir, + rootOff, Marshal.SizeOf()); int saOff = Marshal.SizeOf() + record.name_len; saOff += saOff % 2; int saLen = record.length - saOff; - if(saLen > 0 && - rootOff + saOff + saLen <= rootDir.Length) + if(saLen > 0 && rootOff + saOff + saLen <= rootDir.Length) { var sa = new byte[saLen]; Array.Copy(rootDir, rootOff + saOff, sa, 0, saLen); @@ -343,8 +329,7 @@ public sealed partial class ISO9660 } } - if(saOff + 2 >= saLen) - break; + if(saOff + 2 >= saLen) break; var nextSignature = BigEndianBitConverter.ToUInt16(sa, saOff); @@ -401,8 +386,7 @@ public sealed partial class ISO9660 switch(nextSignature) { case APPLE_MAGIC: - if(sa[saOff + 3] == 1 && - sa[saOff + 2] == 7) + if(sa[saOff + 3] == 1 && sa[saOff + 2] == 7) apple = true; else apple |= sa[saOff + 3] != 1; @@ -426,34 +410,38 @@ public sealed partial class ISO9660 break; } - rrip |= nextSignature is RRIP_MAGIC or RRIP_POSIX_ATTRIBUTES or RRIP_POSIX_DEV_NO - or RRIP_SYMLINK or RRIP_NAME or RRIP_CHILDLINK or RRIP_PARENTLINK - or RRIP_RELOCATED_DIR or RRIP_TIMESTAMPS or RRIP_SPARSE; + rrip |= nextSignature is RRIP_MAGIC + or RRIP_POSIX_ATTRIBUTES + or RRIP_POSIX_DEV_NO + or RRIP_SYMLINK + or RRIP_NAME + or RRIP_CHILDLINK + or RRIP_PARENTLINK + or RRIP_RELOCATED_DIR + or RRIP_TIMESTAMPS + or RRIP_SPARSE; ziso |= nextSignature == ZISO_MAGIC; amiga |= nextSignature == AMIGA_MAGIC; - aaip |= nextSignature == AAIP_MAGIC || nextSignature == AAIP_MAGIC_OLD && - sa[saOff + 3] == 1 && sa[saOff + 2] >= 9; + aaip |= nextSignature == AAIP_MAGIC || + nextSignature == AAIP_MAGIC_OLD && sa[saOff + 3] == 1 && sa[saOff + 2] >= 9; saOff += sa[saOff + 2]; - if(nextSignature == SUSP_TERMINATOR) - break; + if(nextSignature == SUSP_TERMINATOR) break; } break; } - if(noneFound) - break; + if(noneFound) break; } } rootOff += record.length; - if(record.length == 0) - break; + if(record.length == 0) break; } foreach(ContinuationArea ca in contareas) @@ -462,13 +450,13 @@ public sealed partial class ISO9660 (highSierraInfo ? hsvd.Value.logical_block_size : pvd.Value.logical_block_size); if((ca.ca_length_be + ca.offset_be) % - (highSierraInfo ? hsvd.Value.logical_block_size : pvd.Value.logical_block_size) > 0) + (highSierraInfo ? hsvd.Value.logical_block_size : pvd.Value.logical_block_size) > + 0) caLen++; errno = imagePlugin.ReadSectors(ca.block_be, caLen, out byte[] caSectors); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; var caData = new byte[ca.ca_length_be]; Array.Copy(caSectors, ca.offset_be, caData, 0, ca.ca_length_be); @@ -482,8 +470,7 @@ public sealed partial class ISO9660 { // Apple never said to include its extensions inside a continuation area, but just in case case APPLE_MAGIC: - if(caData[caOff + 3] == 1 && - caData[caOff + 2] == 7) + if(caData[caOff + 3] == 1 && caData[caOff + 2] == 7) apple = true; else apple |= caData[caOff + 3] != 1; @@ -497,15 +484,22 @@ public sealed partial class ISO9660 break; } - rrip |= nextSignature is RRIP_MAGIC or RRIP_POSIX_ATTRIBUTES or RRIP_POSIX_DEV_NO or RRIP_SYMLINK - or RRIP_NAME or RRIP_CHILDLINK or RRIP_PARENTLINK or RRIP_RELOCATED_DIR - or RRIP_TIMESTAMPS or RRIP_SPARSE; + rrip |= nextSignature is RRIP_MAGIC + or RRIP_POSIX_ATTRIBUTES + or RRIP_POSIX_DEV_NO + or RRIP_SYMLINK + or RRIP_NAME + or RRIP_CHILDLINK + or RRIP_PARENTLINK + or RRIP_RELOCATED_DIR + or RRIP_TIMESTAMPS + or RRIP_SPARSE; ziso |= nextSignature == ZISO_MAGIC; amiga |= nextSignature == AMIGA_MAGIC; - aaip |= nextSignature == AAIP_MAGIC || nextSignature == AAIP_MAGIC_OLD && caData[caOff + 3] == 1 && - caData[caOff + 2] >= 9; + aaip |= nextSignature == AAIP_MAGIC || + nextSignature == AAIP_MAGIC_OLD && caData[caOff + 3] == 1 && caData[caOff + 2] >= 9; caOff += caData[caOff + 2]; } @@ -513,261 +507,284 @@ public sealed partial class ISO9660 if(refareas.Count > 0) { - suspInformation.AppendLine("----------------------------------------"); - suspInformation.AppendLine("SYSTEM USE SHARING PROTOCOL INFORMATION:"); - suspInformation.AppendLine("----------------------------------------"); + suspInformation.AppendLine(Localization.SYSTEM_USE_SHARING_PROTOCOL_INFORMATION_border); + suspInformation.AppendLine(Localization.SYSTEM_USE_SHARING_PROTOCOL_INFORMATION); + suspInformation.AppendLine(Localization.SYSTEM_USE_SHARING_PROTOCOL_INFORMATION_border); counter = 1; foreach(byte[] erb in refareas) { ReferenceArea er = Marshal.ByteArrayToStructureBigEndian(erb); - string extId = Encoding.GetString(erb, Marshal.SizeOf(), er.id_len); + string extId = encoding.GetString(erb, Marshal.SizeOf(), er.id_len); - string extDes = Encoding.GetString(erb, Marshal.SizeOf() + er.id_len, er.des_len); + string extDes = encoding.GetString(erb, Marshal.SizeOf() + er.id_len, er.des_len); - string extSrc = Encoding.GetString(erb, Marshal.SizeOf() + er.id_len + er.des_len, - er.src_len); + string extSrc = + encoding.GetString(erb, Marshal.SizeOf() + er.id_len + er.des_len, er.src_len); - suspInformation.AppendFormat("Extension: {0}", counter).AppendLine(); - suspInformation.AppendFormat("\tID: {0}, version {1}", extId, er.ext_ver).AppendLine(); - suspInformation.AppendFormat("\tDescription: {0}", extDes).AppendLine(); - suspInformation.AppendFormat("\tSource: {0}", extSrc).AppendLine(); + suspInformation.AppendFormat(Localization.Extension_0, counter).AppendLine(); + suspInformation.AppendFormat("\t" + Localization.ID_0_version_1, extId, er.ext_ver).AppendLine(); + suspInformation.AppendFormat("\t" + Localization.Description_0, extDes).AppendLine(); + suspInformation.AppendFormat("\t" + Localization.Source_0, extSrc).AppendLine(); counter++; } } errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] ipbinSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; CD.IPBin? segaCd = CD.DecodeIPBin(ipbinSector); Saturn.IPBin? saturn = Saturn.DecodeIPBin(ipbinSector); Dreamcast.IPBin? dreamcast = Dreamcast.DecodeIPBin(ipbinSector); - string fsFormat; - if(highSierraInfo) - fsFormat = "High Sierra Format"; + isoMetadata.AppendLine(Localization.High_Sierra_Format_file_system); else if(cdiInfo) - fsFormat = "CD-i"; + isoMetadata.AppendLine(Localization.CD_i_file_system); else - fsFormat = "ISO9660"; + isoMetadata.AppendLine(Localization.ISO9660_file_system); - isoMetadata.AppendFormat("{0} file system", fsFormat).AppendLine(); + if(xaExtensions) isoMetadata.AppendLine(Localization.CD_ROM_XA_extensions_present); - if(xaExtensions) - isoMetadata.AppendLine("CD-ROM XA extensions present."); + if(amiga) isoMetadata.AppendLine(Localization.Amiga_extensions_present); - if(amiga) - isoMetadata.AppendLine("Amiga extensions present."); + if(apple) isoMetadata.AppendLine(Localization.Apple_extensions_present); - if(apple) - isoMetadata.AppendLine("Apple extensions present."); + if(jolietvd != null) isoMetadata.AppendLine(Localization.Joliet_extensions_present); - if(jolietvd != null) - isoMetadata.AppendLine("Joliet extensions present."); + if(susp) isoMetadata.AppendLine(Localization.System_Use_Sharing_Protocol_present); - if(susp) - isoMetadata.AppendLine("System Use Sharing Protocol present."); + if(rrip) isoMetadata.AppendLine(Localization.Rock_Ridge_Interchange_Protocol_present); - if(rrip) - isoMetadata.AppendLine("Rock Ridge Interchange Protocol present."); + if(aaip) isoMetadata.AppendLine(Localization.Arbitrary_Attribute_Interchange_Protocol_present); - if(aaip) - isoMetadata.AppendLine("Arbitrary Attribute Interchange Protocol present."); + if(ziso) isoMetadata.AppendLine(Localization.zisofs_compression_present); - if(ziso) - isoMetadata.AppendLine("zisofs compression present."); + if(evd) isoMetadata.AppendLine(Localization.Contains_Enhanced_Volume_Descriptor); - if(evd) - isoMetadata.AppendLine("Contains Enhanved Volume Descriptor."); - - if(vpd) - isoMetadata.AppendLine("Contains Volume Partition Descriptor."); + if(vpd) isoMetadata.AppendLine(Localization.Contains_Volume_Partition_Descriptor); if(bvd != null) - isoMetadata.AppendFormat("Disc bootable following {0} specifications.", bootSpec).AppendLine(); + isoMetadata.AppendFormat(Localization.Disc_bootable_following_0_specifications, bootSpec).AppendLine(); if(segaCd != null) { - isoMetadata.AppendLine("This is a SegaCD / MegaCD disc."); + isoMetadata.AppendLine(Localization.This_is_a_SegaCD_MegaCD_disc); isoMetadata.AppendLine(CD.Prettify(segaCd)); } if(saturn != null) { - isoMetadata.AppendLine("This is a Sega Saturn disc."); + isoMetadata.AppendLine(Localization.This_is_a_Sega_Saturn_disc); isoMetadata.AppendLine(Saturn.Prettify(saturn)); } if(dreamcast != null) { - isoMetadata.AppendLine("This is a Sega Dreamcast disc."); + isoMetadata.AppendLine(Localization.This_is_a_Sega_Dreamcast_disc); isoMetadata.AppendLine(Dreamcast.Prettify(dreamcast)); } - isoMetadata.AppendFormat("{0}------------------------------", cdiInfo ? "---------------" : "").AppendLine(); + if(cdiInfo) + { + isoMetadata.AppendLine(Localization.FILE_STRUCTURE_VOLUME_DESCRIPTOR_INFORMATION_border); + isoMetadata.AppendLine(Localization.FILE_STRUCTURE_VOLUME_DESCRIPTOR_INFORMATION); + isoMetadata.AppendLine(Localization.FILE_STRUCTURE_VOLUME_DESCRIPTOR_INFORMATION_border); + } + else + { + isoMetadata.AppendLine(Localization.VOLUME_DESCRIPTOR_INFORMATION_border); + isoMetadata.AppendLine(Localization.VOLUME_DESCRIPTOR_INFORMATION); + isoMetadata.AppendLine(Localization.VOLUME_DESCRIPTOR_INFORMATION_border); + } - isoMetadata.AppendFormat("{0}VOLUME DESCRIPTOR INFORMATION:", cdiInfo ? "FILE STRUCTURE " : "").AppendLine(); + isoMetadata.AppendFormat(Localization.System_identifier_0, decodedVd.SystemIdentifier).AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_identifier_0, decodedVd.VolumeIdentifier).AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_set_identifier_0, decodedVd.VolumeSetIdentifier).AppendLine(); + isoMetadata.AppendFormat(Localization.Publisher_identifier_0, decodedVd.PublisherIdentifier).AppendLine(); - isoMetadata.AppendFormat("{0}------------------------------", cdiInfo ? "---------------" : "").AppendLine(); + isoMetadata.AppendFormat(Localization.Data_preparer_identifier_0, decodedVd.DataPreparerIdentifier) + .AppendLine(); - isoMetadata.AppendFormat("System identifier: {0}", decodedVd.SystemIdentifier).AppendLine(); - isoMetadata.AppendFormat("Volume identifier: {0}", decodedVd.VolumeIdentifier).AppendLine(); - isoMetadata.AppendFormat("Volume set identifier: {0}", decodedVd.VolumeSetIdentifier).AppendLine(); - isoMetadata.AppendFormat("Publisher identifier: {0}", decodedVd.PublisherIdentifier).AppendLine(); - isoMetadata.AppendFormat("Data preparer identifier: {0}", decodedVd.DataPreparerIdentifier).AppendLine(); - isoMetadata.AppendFormat("Application identifier: {0}", decodedVd.ApplicationIdentifier).AppendLine(); - isoMetadata.AppendFormat("Volume creation date: {0}", decodedVd.CreationTime).AppendLine(); + isoMetadata.AppendFormat(Localization.Application_identifier_0, decodedVd.ApplicationIdentifier).AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_creation_date_0, decodedVd.CreationTime).AppendLine(); if(decodedVd.HasModificationTime) - isoMetadata.AppendFormat("Volume modification date: {0}", decodedVd.ModificationTime).AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_modification_date_0, decodedVd.ModificationTime).AppendLine(); else - isoMetadata.AppendFormat("Volume has not been modified.").AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_has_not_been_modified).AppendLine(); if(decodedVd.HasExpirationTime) - isoMetadata.AppendFormat("Volume expiration date: {0}", decodedVd.ExpirationTime).AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_expiration_date_0, decodedVd.ExpirationTime).AppendLine(); else - isoMetadata.AppendFormat("Volume does not expire.").AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_does_not_expire).AppendLine(); if(decodedVd.HasEffectiveTime) - isoMetadata.AppendFormat("Volume effective date: {0}", decodedVd.EffectiveTime).AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_effective_date_0, decodedVd.EffectiveTime).AppendLine(); else - isoMetadata.AppendFormat("Volume has always been effective.").AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_has_always_been_effective).AppendLine(); - isoMetadata.AppendFormat("Volume has {0} blocks of {1} bytes each", decodedVd.Blocks, decodedVd.BlockSize). - AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_has_0_blocks_of_1_bytes_each, + decodedVd.Blocks, + decodedVd.BlockSize) + .AppendLine(); if(jolietvd != null) { - isoMetadata.AppendLine("-------------------------------------"); - isoMetadata.AppendLine("JOLIET VOLUME DESCRIPTOR INFORMATION:"); - isoMetadata.AppendLine("-------------------------------------"); - isoMetadata.AppendFormat("System identifier: {0}", decodedJolietVd.SystemIdentifier).AppendLine(); - isoMetadata.AppendFormat("Volume identifier: {0}", decodedJolietVd.VolumeIdentifier).AppendLine(); + isoMetadata.AppendLine(Localization.JOLIET_VOLUME_DESCRIPTOR_INFORMATION_border); + isoMetadata.AppendLine(Localization.JOLIET_VOLUME_DESCRIPTOR_INFORMATION); + isoMetadata.AppendLine(Localization.JOLIET_VOLUME_DESCRIPTOR_INFORMATION_border); + isoMetadata.AppendFormat(Localization.System_identifier_0, decodedJolietVd.SystemIdentifier).AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_identifier_0, decodedJolietVd.VolumeIdentifier).AppendLine(); - isoMetadata.AppendFormat("Volume set identifier: {0}", decodedJolietVd.VolumeSetIdentifier).AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_set_identifier_0, decodedJolietVd.VolumeSetIdentifier) + .AppendLine(); - isoMetadata.AppendFormat("Publisher identifier: {0}", decodedJolietVd.PublisherIdentifier).AppendLine(); + isoMetadata.AppendFormat(Localization.Publisher_identifier_0, decodedJolietVd.PublisherIdentifier) + .AppendLine(); - isoMetadata.AppendFormat("Data preparer identifier: {0}", decodedJolietVd.DataPreparerIdentifier). - AppendLine(); + isoMetadata.AppendFormat(Localization.Data_preparer_identifier_0, decodedJolietVd.DataPreparerIdentifier) + .AppendLine(); - isoMetadata.AppendFormat("Application identifier: {0}", decodedJolietVd.ApplicationIdentifier).AppendLine(); + isoMetadata.AppendFormat(Localization.Application_identifier_0, decodedJolietVd.ApplicationIdentifier) + .AppendLine(); - isoMetadata.AppendFormat("Volume creation date: {0}", decodedJolietVd.CreationTime).AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_creation_date_0, decodedJolietVd.CreationTime).AppendLine(); if(decodedJolietVd.HasModificationTime) - isoMetadata.AppendFormat("Volume modification date: {0}", decodedJolietVd.ModificationTime). - AppendLine(); + { + isoMetadata.AppendFormat(Localization.Volume_modification_date_0, decodedJolietVd.ModificationTime) + .AppendLine(); + } else - isoMetadata.AppendFormat("Volume has not been modified.").AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_has_not_been_modified).AppendLine(); if(decodedJolietVd.HasExpirationTime) - isoMetadata.AppendFormat("Volume expiration date: {0}", decodedJolietVd.ExpirationTime).AppendLine(); + { + isoMetadata.AppendFormat(Localization.Volume_expiration_date_0, decodedJolietVd.ExpirationTime) + .AppendLine(); + } else - isoMetadata.AppendFormat("Volume does not expire.").AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_does_not_expire).AppendLine(); if(decodedJolietVd.HasEffectiveTime) - isoMetadata.AppendFormat("Volume effective date: {0}", decodedJolietVd.EffectiveTime).AppendLine(); + { + isoMetadata.AppendFormat(Localization.Volume_effective_date_0, decodedJolietVd.EffectiveTime) + .AppendLine(); + } else - isoMetadata.AppendFormat("Volume has always been effective.").AppendLine(); + isoMetadata.AppendFormat(Localization.Volume_has_always_been_effective).AppendLine(); } if(torito != null) { errno = imagePlugin.ReadSector(torito.Value.catalog_sector + partition.Start, out vdSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; var toritoOff = 0; - if(vdSector[toritoOff] != 1) - goto exit_torito; + if(vdSector[toritoOff] != 1) goto exit_torito; ElToritoValidationEntry valentry = - Marshal.ByteArrayToStructureLittleEndian(vdSector, toritoOff, + Marshal.ByteArrayToStructureLittleEndian(vdSector, + toritoOff, EL_TORITO_ENTRY_SIZE); - if(valentry.signature != EL_TORITO_MAGIC) - goto exit_torito; + if(valentry.signature != EL_TORITO_MAGIC) goto exit_torito; toritoOff = EL_TORITO_ENTRY_SIZE; ElToritoInitialEntry initialEntry = - Marshal.ByteArrayToStructureLittleEndian(vdSector, toritoOff, + Marshal.ByteArrayToStructureLittleEndian(vdSector, + toritoOff, EL_TORITO_ENTRY_SIZE); initialEntry.boot_type = (ElToritoEmulation)((byte)initialEntry.boot_type & 0xF); - AaruConsole.DebugWriteLine("DEBUG (ISO9660 plugin)", "initialEntry.load_rba = {0}", initialEntry.load_rba); + AaruConsole.DebugWriteLine(MODULE_NAME, "initialEntry.load_rba = {0}", initialEntry.load_rba); - AaruConsole.DebugWriteLine("DEBUG (ISO9660 plugin)", "initialEntry.sector_count = {0}", - initialEntry.sector_count); + AaruConsole.DebugWriteLine(MODULE_NAME, "initialEntry.sector_count = {0}", initialEntry.sector_count); byte[] bootImage = null; if(initialEntry.load_rba + partition.Start + initialEntry.sector_count - 1 <= partition.End) - imagePlugin.ReadSectors(initialEntry.load_rba + partition.Start, initialEntry.sector_count, + { + imagePlugin.ReadSectors(initialEntry.load_rba + partition.Start, + initialEntry.sector_count, out bootImage); + } - isoMetadata.AppendLine("----------------------"); - isoMetadata.AppendLine("EL TORITO INFORMATION:"); - isoMetadata.AppendLine("----------------------"); + isoMetadata.AppendLine(Localization.EL_TORITO_INFORMATION_border); + isoMetadata.AppendLine(Localization.EL_TORITO_INFORMATION); + isoMetadata.AppendLine(Localization.EL_TORITO_INFORMATION_border); - isoMetadata.AppendLine("Initial entry:"); - isoMetadata.AppendFormat("\tDeveloper ID: {0}", Encoding.GetString(valentry.developer_id)).AppendLine(); + isoMetadata.AppendLine(Localization.Initial_entry); + + isoMetadata.AppendFormat("\t" + Localization.Developer_ID_0, encoding.GetString(valentry.developer_id)) + .AppendLine(); if(initialEntry.bootable == ElToritoIndicator.Bootable) { - isoMetadata.AppendFormat("\tBootable on {0}", valentry.platform_id).AppendLine(); + isoMetadata.AppendFormat("\t" + Localization.Bootable_on_0, valentry.platform_id).AppendLine(); - isoMetadata.AppendFormat("\tBootable image starts at sector {0} and runs for {1} sectors", - initialEntry.load_rba, initialEntry.sector_count).AppendLine(); + isoMetadata.AppendFormat("\t" + Localization.Bootable_image_starts_at_sector_0_and_runs_for_1_sectors, + initialEntry.load_rba, + initialEntry.sector_count) + .AppendLine(); if(valentry.platform_id == ElToritoPlatform.x86) - isoMetadata.AppendFormat("\tBootable image will be loaded at segment {0:X4}h", - initialEntry.load_seg == 0 ? 0x7C0 : initialEntry.load_seg).AppendLine(); + { + isoMetadata.AppendFormat("\t" + Localization.Bootable_image_will_be_loaded_at_segment_0, + initialEntry.load_seg == 0 ? 0x7C0 : initialEntry.load_seg) + .AppendLine(); + } else - isoMetadata.AppendFormat("\tBootable image will be loaded at 0x{0:X8}", - (uint)initialEntry.load_seg * 10).AppendLine(); + { + isoMetadata.AppendFormat("\t" + Localization.Bootable_image_will_be_loaded_at_0, + (uint)initialEntry.load_seg * 10) + .AppendLine(); + } switch(initialEntry.boot_type) { case ElToritoEmulation.None: - isoMetadata.AppendLine("\tImage uses no emulation"); + isoMetadata.AppendLine("\t" + Localization.Image_uses_no_emulation); break; case ElToritoEmulation.Md2Hd: - isoMetadata.AppendLine("\tImage emulates a 5.25\" high-density (MD2HD, 1.2Mb) floppy"); + isoMetadata.AppendLine("\t" + Localization.Image_emulates_a_high_density_MD2HD_floppy); break; case ElToritoEmulation.Mf2Hd: - isoMetadata.AppendLine("\tImage emulates a 3.5\" high-density (MF2HD, 1.44Mb) floppy"); + isoMetadata.AppendLine("\t" + Localization.Image_emulates_a_high_density_MF2HD_floppy); break; case ElToritoEmulation.Mf2Ed: - isoMetadata.AppendLine("\tImage emulates a 3.5\" extra-density (MF2ED, 2.88Mb) floppy"); + isoMetadata.AppendLine("\t" + Localization.Image_emulates_a_extra_density_MF2ED_floppy); break; default: - isoMetadata.AppendFormat("\tImage uses unknown emulation type {0}", - (byte)initialEntry.boot_type).AppendLine(); + isoMetadata.AppendFormat("\t" + Localization.Image_uses_unknown_emulation_type_0, + (byte)initialEntry.boot_type) + .AppendLine(); break; } - isoMetadata.AppendFormat("\tSystem type: 0x{0:X2}", initialEntry.system_type).AppendLine(); + isoMetadata.AppendFormat("\t" + Localization.System_type_0, initialEntry.system_type).AppendLine(); if(bootImage != null) - isoMetadata.AppendFormat("\tBootable image's SHA1: {0}", Sha1Context.Data(bootImage, out _)). - AppendLine(); + { + isoMetadata.AppendFormat("\t" + Localization.Bootable_image_SHA1_0, + Sha1Context.Data(bootImage, out _)) + .AppendLine(); + } } else - isoMetadata.AppendLine("\tNot bootable"); + isoMetadata.AppendLine("\t" + Localization.Not_bootable); toritoOff += EL_TORITO_ENTRY_SIZE; @@ -778,218 +795,232 @@ public sealed partial class ISO9660 vdSector[toritoOff] == (byte)ElToritoIndicator.LastHeader)) { ElToritoSectionHeaderEntry sectionHeader = - Marshal.ByteArrayToStructureLittleEndian(vdSector, toritoOff, + Marshal.ByteArrayToStructureLittleEndian(vdSector, + toritoOff, EL_TORITO_ENTRY_SIZE); toritoOff += EL_TORITO_ENTRY_SIZE; - isoMetadata.AppendFormat("Boot section {0}:", sectionCounter); + isoMetadata.AppendFormat(Localization.Boot_section_0, sectionCounter); - isoMetadata.AppendFormat("\tSection ID: {0}", Encoding.GetString(sectionHeader.identifier)). - AppendLine(); + isoMetadata.AppendFormat("\t" + Localization.Section_ID_0, encoding.GetString(sectionHeader.identifier)) + .AppendLine(); - for(var entryCounter = 1; entryCounter <= sectionHeader.entries && toritoOff < vdSector.Length; + for(var entryCounter = 1; + entryCounter <= sectionHeader.entries && toritoOff < vdSector.Length; entryCounter++) { ElToritoSectionEntry sectionEntry = - Marshal.ByteArrayToStructureLittleEndian(vdSector, toritoOff, + Marshal.ByteArrayToStructureLittleEndian(vdSector, + toritoOff, EL_TORITO_ENTRY_SIZE); toritoOff += EL_TORITO_ENTRY_SIZE; - isoMetadata.AppendFormat("\tEntry {0}:", entryCounter); + isoMetadata.AppendFormat("\t" + Localization.Entry_0, entryCounter); if(sectionEntry.bootable == ElToritoIndicator.Bootable) { bootImage = null; if(sectionEntry.load_rba + partition.Start + sectionEntry.sector_count - 1 <= partition.End) - imagePlugin.ReadSectors(sectionEntry.load_rba + partition.Start, sectionEntry.sector_count, + { + imagePlugin.ReadSectors(sectionEntry.load_rba + partition.Start, + sectionEntry.sector_count, out bootImage); + } - isoMetadata.AppendFormat("\t\tBootable on {0}", sectionHeader.platform_id).AppendLine(); + isoMetadata.AppendFormat("\t\t" + Localization.Bootable_on_0, sectionHeader.platform_id) + .AppendLine(); - isoMetadata.AppendFormat("\t\tBootable image starts at sector {0} and runs for {1} sectors", - sectionEntry.load_rba, sectionEntry.sector_count).AppendLine(); + isoMetadata + .AppendFormat("\t\t" + Localization.Bootable_image_starts_at_sector_0_and_runs_for_1_sectors, + sectionEntry.load_rba, + sectionEntry.sector_count) + .AppendLine(); if(valentry.platform_id == ElToritoPlatform.x86) - isoMetadata.AppendFormat("\t\tBootable image will be loaded at segment {0:X4}h", - sectionEntry.load_seg == 0 ? 0x7C0 : sectionEntry.load_seg). - AppendLine(); + { + isoMetadata.AppendFormat("\t\t" + Localization.Bootable_image_will_be_loaded_at_segment_0, + sectionEntry.load_seg == 0 ? 0x7C0 : sectionEntry.load_seg) + .AppendLine(); + } else - isoMetadata.AppendFormat("\t\tBootable image will be loaded at 0x{0:X8}", - (uint)sectionEntry.load_seg * 10).AppendLine(); + { + isoMetadata.AppendFormat("\t\t" + Localization.Bootable_image_will_be_loaded_at_0, + (uint)sectionEntry.load_seg * 10) + .AppendLine(); + } switch((ElToritoEmulation)((byte)sectionEntry.boot_type & 0xF)) { case ElToritoEmulation.None: - isoMetadata.AppendLine("\t\tImage uses no emulation"); + isoMetadata.AppendLine("\t\t" + Localization.Image_uses_no_emulation); break; case ElToritoEmulation.Md2Hd: - isoMetadata. - AppendLine("\t\tImage emulates a 5.25\" high-density (MD2HD, 1.2Mb) floppy"); + isoMetadata.AppendLine("\t\t" + + Localization.Image_emulates_a_high_density_MD2HD_floppy); break; case ElToritoEmulation.Mf2Hd: - isoMetadata. - AppendLine("\t\tImage emulates a 3.5\" high-density (MF2HD, 1.44Mb) floppy"); + isoMetadata.AppendLine("\t\t" + + Localization.Image_emulates_a_high_density_MF2HD_floppy); break; case ElToritoEmulation.Mf2Ed: - isoMetadata. - AppendLine("\t\tImage emulates a 3.5\" extra-density (MF2ED, 2.88Mb) floppy"); + isoMetadata.AppendLine("\t\t" + + Localization.Image_emulates_a_extra_density_MF2ED_floppy); break; default: - isoMetadata.AppendFormat("\t\tImage uses unknown emulation type {0}", - (byte)initialEntry.boot_type).AppendLine(); + isoMetadata.AppendFormat("\t\t" + Localization.Image_uses_unknown_emulation_type_0, + (byte)initialEntry.boot_type) + .AppendLine(); break; } - isoMetadata.AppendFormat("\t\tSelection criteria type: {0}", - sectionEntry.selection_criteria_type).AppendLine(); + isoMetadata.AppendFormat("\t\t" + Localization.Selection_criteria_type_0, + sectionEntry.selection_criteria_type) + .AppendLine(); - isoMetadata.AppendFormat("\t\tSystem type: 0x{0:X2}", sectionEntry.system_type).AppendLine(); + isoMetadata.AppendFormat("\t\t" + Localization.System_type_0, sectionEntry.system_type) + .AppendLine(); if(bootImage != null) - isoMetadata.AppendFormat("\t\tBootable image's SHA1: {0}", - Sha1Context.Data(bootImage, out _)).AppendLine(); + { + isoMetadata.AppendFormat("\t\t" + Localization.Bootable_image_SHA1_0, + Sha1Context.Data(bootImage, out _)) + .AppendLine(); + } } else - isoMetadata.AppendLine("\t\tNot bootable"); + isoMetadata.AppendLine("\t\t" + Localization.Not_bootable); var flags = (ElToritoFlags)((byte)sectionEntry.boot_type & 0xF0); if(flags.HasFlag(ElToritoFlags.ATAPI)) - isoMetadata.AppendLine("\t\tImage contains ATAPI drivers"); + isoMetadata.AppendLine("\t\t" + Localization.Image_contains_ATAPI_drivers); if(flags.HasFlag(ElToritoFlags.SCSI)) - isoMetadata.AppendLine("\t\tImage contains SCSI drivers"); + isoMetadata.AppendLine("\t\t" + Localization.Image_contains_SCSI_drivers); - if(!flags.HasFlag(ElToritoFlags.Continued)) - continue; + if(!flags.HasFlag(ElToritoFlags.Continued)) continue; while(toritoOff < vdSector.Length) { ElToritoSectionEntryExtension sectionExtension = - Marshal.ByteArrayToStructureLittleEndian(vdSector, toritoOff, + Marshal.ByteArrayToStructureLittleEndian(vdSector, + toritoOff, EL_TORITO_ENTRY_SIZE); toritoOff += EL_TORITO_ENTRY_SIZE; - if(!sectionExtension.extension_flags.HasFlag(ElToritoFlags.Continued)) - break; + if(!sectionExtension.extension_flags.HasFlag(ElToritoFlags.Continued)) break; } } - if(sectionHeader.header_id == ElToritoIndicator.LastHeader) - break; + if(sectionHeader.header_id == ElToritoIndicator.LastHeader) break; } } exit_torito: - if(refareas.Count > 0) - isoMetadata.Append(suspInformation); + if(refareas.Count > 0) isoMetadata.Append(suspInformation); - XmlFsType.Type = fsFormat; + if(highSierraInfo) + metadata.Type = FS_TYPE_HSF; + else if(cdiInfo) + metadata.Type = FS_TYPE_CDI; + else + metadata.Type = FS_TYPE_ISO; if(jolietvd != null) { - XmlFsType.VolumeName = decodedJolietVd.VolumeIdentifier; + metadata.VolumeName = decodedJolietVd.VolumeIdentifier; if(string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) || decodedVd.SystemIdentifier.Length > decodedJolietVd.SystemIdentifier.Length) - XmlFsType.SystemIdentifier = decodedVd.SystemIdentifier; + metadata.SystemIdentifier = decodedVd.SystemIdentifier; else - XmlFsType.SystemIdentifier = string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) ? null - : decodedJolietVd.SystemIdentifier; + { + metadata.SystemIdentifier = string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) + ? null + : decodedJolietVd.SystemIdentifier; + } if(string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) || decodedVd.VolumeSetIdentifier.Length > decodedJolietVd.VolumeSetIdentifier.Length) - XmlFsType.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; + metadata.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; else - XmlFsType.VolumeSetIdentifier = string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) ? null - : decodedJolietVd.VolumeSetIdentifier; + { + metadata.VolumeSetIdentifier = string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) + ? null + : decodedJolietVd.VolumeSetIdentifier; + } if(string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) || decodedVd.PublisherIdentifier.Length > decodedJolietVd.PublisherIdentifier.Length) - XmlFsType.PublisherIdentifier = decodedVd.PublisherIdentifier; + metadata.PublisherIdentifier = decodedVd.PublisherIdentifier; else - XmlFsType.PublisherIdentifier = string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) ? null - : decodedJolietVd.PublisherIdentifier; + { + metadata.PublisherIdentifier = string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) + ? null + : decodedJolietVd.PublisherIdentifier; + } if(string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) || decodedVd.DataPreparerIdentifier.Length > decodedJolietVd.DataPreparerIdentifier.Length) - XmlFsType.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; + metadata.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; else - XmlFsType.DataPreparerIdentifier = string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) ? null - : decodedJolietVd.DataPreparerIdentifier; + { + metadata.DataPreparerIdentifier = string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) + ? null + : decodedJolietVd.DataPreparerIdentifier; + } if(string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) || decodedVd.ApplicationIdentifier.Length > decodedJolietVd.ApplicationIdentifier.Length) - XmlFsType.ApplicationIdentifier = decodedVd.ApplicationIdentifier; + metadata.ApplicationIdentifier = decodedVd.ApplicationIdentifier; else - XmlFsType.ApplicationIdentifier = string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) ? null - : decodedJolietVd.ApplicationIdentifier; - - XmlFsType.CreationDate = decodedJolietVd.CreationTime; - XmlFsType.CreationDateSpecified = true; - - if(decodedJolietVd.HasModificationTime) { - XmlFsType.ModificationDate = decodedJolietVd.ModificationTime; - XmlFsType.ModificationDateSpecified = true; + metadata.ApplicationIdentifier = string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) + ? null + : decodedJolietVd.ApplicationIdentifier; } - if(decodedJolietVd.HasExpirationTime) - { - XmlFsType.ExpirationDate = decodedJolietVd.ExpirationTime; - XmlFsType.ExpirationDateSpecified = true; - } + metadata.CreationDate = decodedJolietVd.CreationTime; - if(decodedJolietVd.HasEffectiveTime) - { - XmlFsType.EffectiveDate = decodedJolietVd.EffectiveTime; - XmlFsType.EffectiveDateSpecified = true; - } + if(decodedJolietVd.HasModificationTime) metadata.ModificationDate = decodedJolietVd.ModificationTime; + + if(decodedJolietVd.HasExpirationTime) metadata.ExpirationDate = decodedJolietVd.ExpirationTime; + + if(decodedJolietVd.HasEffectiveTime) metadata.EffectiveDate = decodedJolietVd.EffectiveTime; } else { - XmlFsType.SystemIdentifier = decodedVd.SystemIdentifier; - XmlFsType.VolumeName = decodedVd.VolumeIdentifier; - XmlFsType.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; - XmlFsType.PublisherIdentifier = decodedVd.PublisherIdentifier; - XmlFsType.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; - XmlFsType.ApplicationIdentifier = decodedVd.ApplicationIdentifier; - XmlFsType.CreationDate = decodedVd.CreationTime; - XmlFsType.CreationDateSpecified = true; + metadata.SystemIdentifier = decodedVd.SystemIdentifier; + metadata.VolumeName = decodedVd.VolumeIdentifier; + metadata.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; + metadata.PublisherIdentifier = decodedVd.PublisherIdentifier; + metadata.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; + metadata.ApplicationIdentifier = decodedVd.ApplicationIdentifier; + metadata.CreationDate = decodedVd.CreationTime; - if(decodedVd.HasModificationTime) - { - XmlFsType.ModificationDate = decodedVd.ModificationTime; - XmlFsType.ModificationDateSpecified = true; - } + if(decodedVd.HasModificationTime) metadata.ModificationDate = decodedVd.ModificationTime; - if(decodedVd.HasExpirationTime) - { - XmlFsType.ExpirationDate = decodedVd.ExpirationTime; - XmlFsType.ExpirationDateSpecified = true; - } + if(decodedVd.HasExpirationTime) metadata.ExpirationDate = decodedVd.ExpirationTime; - if(decodedVd.HasEffectiveTime) - { - XmlFsType.EffectiveDate = decodedVd.EffectiveTime; - XmlFsType.EffectiveDateSpecified = true; - } + if(decodedVd.HasEffectiveTime) metadata.EffectiveDate = decodedVd.EffectiveTime; } - XmlFsType.Bootable |= bvd != null || segaCd != null || saturn != null || dreamcast != null; - XmlFsType.Clusters = decodedVd.Blocks; - XmlFsType.ClusterSize = decodedVd.BlockSize; + metadata.Bootable |= bvd != null || segaCd != null || saturn != null || dreamcast != null; + metadata.Clusters = decodedVd.Blocks; + metadata.ClusterSize = decodedVd.BlockSize; information = isoMetadata.ToString(); } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Mode2.cs b/Aaru.Filesystems/ISO9660/Mode2.cs index aa82f2811..3ac29795c 100644 --- a/Aaru.Filesystems/ISO9660/Mode2.cs +++ b/Aaru.Filesystems/ISO9660/Mode2.cs @@ -27,33 +27,30 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.IO; using Aaru.CommonTypes.Enums; using Aaru.Console; using Aaru.Decoders.CD; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { ErrorNumber ReadSector(ulong sector, out byte[] buffer, bool interleaved = false, byte fileNumber = 0) { - ulong realSector; - uint sectorCount; ErrorNumber errno; buffer = null; - sectorCount = (uint)_blockSize / 2048; + uint sectorCount = (uint)_blockSize / 2048; - if(_blockSize % 2048 > 0) - sectorCount++; + if(_blockSize % 2048 > 0) sectorCount++; - realSector = sector * _blockSize / 2048; + ulong realSector = sector * _blockSize / 2048; ulong offset = sector * _blockSize % 2048; @@ -63,52 +60,80 @@ public sealed partial class ISO9660 { errno = _image.ReadSectorLong(realSector, out data); - if(errno != ErrorNumber.NoError) - errno = _image.ReadSector(realSector, out data); + if(errno != ErrorNumber.NoError) errno = _image.ReadSector(realSector, out data); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; if(_debug) + { switch(data.Length) { case 2048: - AaruConsole.DebugWriteLine("ISO9660 Plugin", "Sector {0}, Cooked, Mode 0/1 / Mode 2 Form 1", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.tor_Sector_0_Cooked_Mode_zero_one_Mode_two_Form_one, realSector); break; case 2324: - AaruConsole.DebugWriteLine("ISO9660 Plugin", "Sector {0}, Cooked, Mode 2 Form 2", realSector); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.tor_Sector_0_Cooked_Mode_two_Form_two, + realSector); break; case 2336: - AaruConsole.DebugWriteLine("ISO9660 Plugin", - "Sector {0}, Cooked, Mode 2 Form {1}, File Number {2}, Channel Number {3}, Submode {4}, Coding Information {5}", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .tor_Sector_0_Cooked_Mode_two_Form_1_File_Number_2_Channel_Number_3_Submode_4_Coding_Information_5, realSector, - ((Mode2Submode)data[2]).HasFlag(Mode2Submode.Form2) ? 2 : 1, data[0], - data[1], (Mode2Submode)data[2], data[3]); + ((Mode2Submode)data[2]).HasFlag(Mode2Submode.Form2) ? 2 : 1, + data[0], + data[1], + (Mode2Submode)data[2], + data[3]); break; - case 2352 when data[0] != 0x00 || data[1] != 0xFF || data[2] != 0xFF || data[3] != 0xFF || - data[4] != 0xFF || data[5] != 0xFF || data[6] != 0xFF || data[7] != 0xFF || - data[8] != 0xFF || data[9] != 0xFF || data[10] != 0xFF || data[11] != 0x00: - AaruConsole.DebugWriteLine("ISO9660 Plugin", "Sector {0}, Raw, Audio", realSector); + case 2352 when data[0] != 0x00 || + data[1] != 0xFF || + data[2] != 0xFF || + data[3] != 0xFF || + data[4] != 0xFF || + data[5] != 0xFF || + data[6] != 0xFF || + data[7] != 0xFF || + data[8] != 0xFF || + data[9] != 0xFF || + data[10] != 0xFF || + data[11] != 0x00: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.tor_Sector_0_Raw_Audio, realSector); break; case 2352 when data[15] != 2: - AaruConsole.DebugWriteLine("ISO9660 Plugin", "Sector {0} ({1:X2}:{2:X2}:{3:X2}), Raw, Mode {4}", - realSector, data[12], data[13], data[14], data[15]); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.tor_Sector_0_1_2_3_Raw_Mode_4, + realSector, + data[12], + data[13], + data[14], + data[15]); break; case 2352: - AaruConsole.DebugWriteLine("ISO9660 Plugin", - "Sector {0} ({1:X2}:{2:X2}:{3:X2}), Raw, Mode 2 Form {4}, File Number {5}, Channel Number {6}, Submode {7}, Coding Information {8}", - realSector, data[12], data[13], data[14], + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .tor_Sector_0_1_2_3_Raw_Mode_two_Form_4_File_Number_5_Channel_Number_6_Submode_7_Coding_Information_8, + realSector, + data[12], + data[13], + data[14], ((Mode2Submode)data[18]).HasFlag(Mode2Submode.Form2) ? 2 : 1, - data[16], data[17], (Mode2Submode)data[18], data[19]); + data[16], + data[17], + (Mode2Submode)data[18], + data[19]); break; } + } if(_blockSize == 2048) { @@ -134,54 +159,80 @@ public sealed partial class ISO9660 errno = _image.ReadSectorLong(dstSector, out data); - if(errno != ErrorNumber.NoError) - errno = _image.ReadSector(dstSector, out data); + if(errno != ErrorNumber.NoError) errno = _image.ReadSector(dstSector, out data); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; if(_debug) + { switch(data.Length) { case 2048: - AaruConsole.DebugWriteLine("ISO9660 Plugin", "Sector {0}, Cooked, Mode 0/1 / Mode 2 Form 1", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.tor_Sector_0_Cooked_Mode_zero_one_Mode_two_Form_one, dstSector); break; case 2324: - AaruConsole.DebugWriteLine("ISO9660 Plugin", "Sector {0}, Cooked, Mode 2 Form 2", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.tor_Sector_0_Cooked_Mode_two_Form_two, dstSector); break; case 2336: - AaruConsole.DebugWriteLine("ISO9660 Plugin", - "Sector {0}, Cooked, Mode 2 Form {1}, File Number {2}, Channel Number {3}, Submode {4}, Coding Information {5}", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .tor_Sector_0_Cooked_Mode_two_Form_1_File_Number_2_Channel_Number_3_Submode_4_Coding_Information_5, dstSector, ((Mode2Submode)data[2]).HasFlag(Mode2Submode.Form2) ? 2 : 1, - data[0], data[1], (Mode2Submode)data[2], data[3]); + data[0], + data[1], + (Mode2Submode)data[2], + data[3]); break; - case 2352 when data[0] != 0x00 || data[1] != 0xFF || data[2] != 0xFF || data[3] != 0xFF || - data[4] != 0xFF || data[5] != 0xFF || data[6] != 0xFF || data[7] != 0xFF || - data[8] != 0xFF || data[9] != 0xFF || data[10] != 0xFF || data[11] != 0x00: - AaruConsole.DebugWriteLine("ISO9660 Plugin", "Sector {0}, Raw, Audio", dstSector); + case 2352 when data[0] != 0x00 || + data[1] != 0xFF || + data[2] != 0xFF || + data[3] != 0xFF || + data[4] != 0xFF || + data[5] != 0xFF || + data[6] != 0xFF || + data[7] != 0xFF || + data[8] != 0xFF || + data[9] != 0xFF || + data[10] != 0xFF || + data[11] != 0x00: + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.tor_Sector_0_Raw_Audio, dstSector); break; case 2352 when data[15] != 2: - AaruConsole.DebugWriteLine("ISO9660 Plugin", - "Sector {0} ({1:X2}:{2:X2}:{3:X2}), Raw, Mode {4}", dstSector, - data[12], data[13], data[14], data[15]); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.tor_Sector_0_1_2_3_Raw_Mode_4, + dstSector, + data[12], + data[13], + data[14], + data[15]); break; case 2352: - AaruConsole.DebugWriteLine("ISO9660 Plugin", - "Sector {0} ({1:X2}:{2:X2}:{3:X2}), Raw, Mode 2 Form {4}, File Number {5}, Channel Number {6}, Submode {7}, Coding Information {8}", - dstSector, data[12], data[13], data[14], + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .tor_Sector_0_1_2_3_Raw_Mode_two_Form_4_File_Number_5_Channel_Number_6_Submode_7_Coding_Information_8, + dstSector, + data[12], + data[13], + data[14], ((Mode2Submode)data[18]).HasFlag(Mode2Submode.Form2) ? 2 : 1, - data[16], data[17], (Mode2Submode)data[18], data[19]); + data[16], + data[17], + (Mode2Submode)data[18], + data[19]); break; } + } byte[] sectorData = Sector.GetUserData(data, interleaved, fileNumber); diff --git a/Aaru.Filesystems/ISO9660/PathTable.cs b/Aaru.Filesystems/ISO9660/PathTable.cs index 3875dabec..45fb276c7 100644 --- a/Aaru.Filesystems/ISO9660/PathTable.cs +++ b/Aaru.Filesystems/ISO9660/PathTable.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Decodes path tables. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,24 +23,22 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Collections.Generic; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { PathTableEntryInternal[] DecodePathTable(byte[] data) { - if(data is null || - data.Length == 0) - return null; + if(data is null || data.Length == 0) return null; - var table = new List(); + List table = []; var off = 0; @@ -61,12 +55,11 @@ public sealed partial class ISO9660 { entry = Marshal.ByteArrayToStructureBigEndian(data, off, Marshal.SizeOf()); - if(entry.name_len == 0) - break; + if(entry.name_len == 0) break; off += Marshal.SizeOf(); - string name = Encoding.GetString(data, off, entry.name_len); + string name = _encoding.GetString(data, off, entry.name_len); table.Add(new PathTableEntryInternal { @@ -78,8 +71,7 @@ public sealed partial class ISO9660 off += entry.name_len; - if(entry.name_len % 2 != 0) - off++; + if(entry.name_len % 2 != 0) off++; } return table.ToArray(); @@ -87,27 +79,26 @@ public sealed partial class ISO9660 PathTableEntryInternal[] DecodeHighSierraPathTable(byte[] data) { - if(data is null) - return null; + if(data is null) return null; - var table = new List(); + List table = []; var off = 0; while(off < data.Length) { HighSierraPathTableEntry entry = - Marshal.ByteArrayToStructureBigEndian(data, off, - Marshal. - SizeOf< + Marshal.ByteArrayToStructureBigEndian(data, + off, + Marshal + .SizeOf< HighSierraPathTableEntry>()); - if(entry.name_len == 0) - break; + if(entry.name_len == 0) break; off += Marshal.SizeOf(); - string name = Encoding.GetString(data, off, entry.name_len); + string name = _encoding.GetString(data, off, entry.name_len); table.Add(new PathTableEntryInternal { @@ -119,8 +110,7 @@ public sealed partial class ISO9660 off += entry.name_len; - if(entry.name_len % 2 != 0) - off++; + if(entry.name_len % 2 != 0) off++; } return table.ToArray(); diff --git a/Aaru.Filesystems/ISO9660/Structs/Amiga.cs b/Aaru.Filesystems/ISO9660/Structs/Amiga.cs index df9a91834..8cd906e42 100644 --- a/Aaru.Filesystems/ISO9660/Structs/Amiga.cs +++ b/Aaru.Filesystems/ISO9660/Structs/Amiga.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Amiga extensions structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,16 +23,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Runtime.InteropServices; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { +#region Nested type: AmigaEntry + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct AmigaEntry { @@ -49,6 +47,10 @@ public sealed partial class ISO9660 // Followed by length-prefixed string for comment if present } +#endregion + +#region Nested type: AmigaProtection + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct AmigaProtection { @@ -57,4 +59,6 @@ public sealed partial class ISO9660 public readonly AmigaMultiuser Multiuser; public readonly AmigaAttributes Protection; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Structs/Apple.cs b/Aaru.Filesystems/ISO9660/Structs/Apple.cs index ae478d938..b7af77319 100644 --- a/Aaru.Filesystems/ISO9660/Structs/Apple.cs +++ b/Aaru.Filesystems/ISO9660/Structs/Apple.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple extensions structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,58 +23,17 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Runtime.InteropServices; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { - // Little-endian - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct AppleProDOSSystemUse - { - public readonly ushort signature; - public readonly byte length; - public readonly AppleId id; - public readonly byte type; - public readonly ushort aux_type; - } - - // Big-endian - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct AppleHFSSystemUse - { - public readonly ushort signature; - public readonly byte length; - public readonly AppleId id; - public readonly uint type; - public readonly uint creator; - public readonly AppleCommon.FinderFlags finder_flags; - } - - // Little-endian - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct AppleProDOSOldSystemUse - { - public readonly ushort signature; - public readonly AppleOldId id; - public readonly byte type; - public readonly ushort aux_type; - } - - // Big-endian - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct AppleHFSTypeCreatorSystemUse - { - public readonly ushort signature; - public readonly AppleOldId id; - public readonly uint type; - public readonly uint creator; - } +#region Nested type: AppleHFSIconSystemUse // Big-endian [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -92,6 +47,10 @@ public sealed partial class ISO9660 public readonly byte[] icon; } +#endregion + +#region Nested type: AppleHFSOldSystemUse + // Big-endian [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct AppleHFSOldSystemUse @@ -102,4 +61,65 @@ public sealed partial class ISO9660 public readonly uint creator; public readonly ushort finder_flags; } + +#endregion + +#region Nested type: AppleHFSSystemUse + + // Big-endian + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct AppleHFSSystemUse + { + public readonly ushort signature; + public readonly byte length; + public readonly AppleId id; + public readonly uint type; + public readonly uint creator; + public readonly AppleCommon.FinderFlags finder_flags; + } + +#endregion + +#region Nested type: AppleHFSTypeCreatorSystemUse + + // Big-endian + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct AppleHFSTypeCreatorSystemUse + { + public readonly ushort signature; + public readonly AppleOldId id; + public readonly uint type; + public readonly uint creator; + } + +#endregion + +#region Nested type: AppleProDOSOldSystemUse + + // Little-endian + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct AppleProDOSOldSystemUse + { + public readonly ushort signature; + public readonly AppleOldId id; + public readonly byte type; + public readonly ushort aux_type; + } + +#endregion + +#region Nested type: AppleProDOSSystemUse + + // Little-endian + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct AppleProDOSSystemUse + { + public readonly ushort signature; + public readonly byte length; + public readonly AppleId id; + public readonly byte type; + public readonly ushort aux_type; + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Structs/CDi.cs b/Aaru.Filesystems/ISO9660/Structs/CDi.cs index 66f7251a8..d5f3ca7a0 100644 --- a/Aaru.Filesystems/ISO9660/Structs/CDi.cs +++ b/Aaru.Filesystems/ISO9660/Structs/CDi.cs @@ -27,16 +27,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Runtime.InteropServices; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { static DecodedVolumeDescriptor DecodeVolumeDescriptor(FileStructureVolumeDescriptor pvd) @@ -51,14 +51,12 @@ public sealed partial class ISO9660 ApplicationIdentifier = StringHandlers.CToString(pvd.application_data).TrimEnd() }; - if(pvd.creation_date[0] == '0' || - pvd.creation_date[0] == 0x00) + if(pvd.creation_date[0] == '0' || pvd.creation_date[0] == 0x00) decodedVd.CreationTime = DateTime.MinValue; else decodedVd.CreationTime = DateHandlers.HighSierraToDateTime(pvd.creation_date); - if(pvd.modification_date[0] == '0' || - pvd.modification_date[0] == 0x00) + if(pvd.modification_date[0] == '0' || pvd.modification_date[0] == 0x00) decodedVd.HasModificationTime = false; else { @@ -66,8 +64,7 @@ public sealed partial class ISO9660 decodedVd.ModificationTime = DateHandlers.HighSierraToDateTime(pvd.modification_date); } - if(pvd.expiration_date[0] == '0' || - pvd.expiration_date[0] == 0x00) + if(pvd.expiration_date[0] == '0' || pvd.expiration_date[0] == 0x00) decodedVd.HasExpirationTime = false; else { @@ -75,8 +72,7 @@ public sealed partial class ISO9660 decodedVd.ExpirationTime = DateHandlers.HighSierraToDateTime(pvd.expiration_date); } - if(pvd.effective_date[0] == '0' || - pvd.effective_date[0] == 0x00) + if(pvd.effective_date[0] == '0' || pvd.effective_date[0] == 0x00) decodedVd.HasEffectiveTime = false; else { @@ -90,6 +86,48 @@ public sealed partial class ISO9660 return decodedVd; } +#region Nested type: CdiDirectoryRecord + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct CdiDirectoryRecord + { + public readonly byte length; + public readonly byte xattr_len; + public readonly uint reserved1; + public readonly uint start_lbn; + public readonly uint reserved2; + public readonly uint size; + public readonly HighSierraTimestamp date; + public readonly byte reserved3; + public readonly CdiFileFlags flags; + public readonly ushort file_unit_size; + public readonly ushort reserved4; + public readonly ushort volume_sequence_number; + public readonly byte name_len; + + // Followed by name[name_len] and then CdiSystemArea until length arrives + } + +#endregion + +#region Nested type: CdiSystemArea + + // Follows filename on directory record + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct CdiSystemArea + { + public readonly ushort group; + public readonly ushort owner; + public readonly CdiAttributes attributes; + public readonly ushort reserved1; + public readonly byte file_no; + public readonly byte reserved2; + } + +#endregion + +#region Nested type: FileStructureVolumeDescriptor + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct FileStructureVolumeDescriptor { @@ -161,35 +199,5 @@ public sealed partial class ISO9660 public readonly byte[] reserved16; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct CdiDirectoryRecord - { - public readonly byte length; - public readonly byte xattr_len; - public readonly uint reserved1; - public readonly uint start_lbn; - public readonly uint reserved2; - public readonly uint size; - public readonly HighSierraTimestamp date; - public readonly byte reserved3; - public readonly CdiFileFlags flags; - public readonly ushort file_unit_size; - public readonly ushort reserved4; - public readonly ushort volume_sequence_number; - public readonly byte name_len; - - // Followed by name[name_len] and then CdiSystemArea until length arrives - } - - // Follows filename on directory record - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct CdiSystemArea - { - public readonly ushort group; - public readonly ushort owner; - public readonly CdiAttributes attributes; - public readonly ushort reserved1; - public readonly byte file_no; - public readonly byte reserved2; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Structs/ElTorito.cs b/Aaru.Filesystems/ISO9660/Structs/ElTorito.cs index 92b947b9b..fb0fdaa69 100644 --- a/Aaru.Filesystems/ISO9660/Structs/ElTorito.cs +++ b/Aaru.Filesystems/ISO9660/Structs/ElTorito.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// El Torito extensions structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,16 +23,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Runtime.InteropServices; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { +#region Nested type: ElToritoBootRecord + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct ElToritoBootRecord { @@ -53,17 +51,9 @@ public sealed partial class ISO9660 public readonly byte[] boot_use; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ElToritoValidationEntry - { - public readonly ElToritoIndicator header_id; - public readonly ElToritoPlatform platform_id; - public readonly ushort reserved; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] - public readonly byte[] developer_id; - public readonly ushort checksum; - public readonly ushort signature; - } +#endregion + +#region Nested type: ElToritoInitialEntry [StructLayout(LayoutKind.Sequential, Pack = 1)] struct ElToritoInitialEntry @@ -79,15 +69,9 @@ public sealed partial class ISO9660 public readonly byte[] reserved2; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ElToritoSectionHeaderEntry - { - public readonly ElToritoIndicator header_id; - public readonly ElToritoPlatform platform_id; - public readonly ushort entries; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] - public readonly byte[] identifier; - } +#endregion + +#region Nested type: ElToritoSectionEntry [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct ElToritoSectionEntry @@ -104,6 +88,10 @@ public sealed partial class ISO9660 public readonly byte[] selection_criterias; } +#endregion + +#region Nested type: ElToritoSectionEntryExtension + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct ElToritoSectionEntryExtension { @@ -112,4 +100,36 @@ public sealed partial class ISO9660 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)] public readonly byte[] selection_criterias; } + +#endregion + +#region Nested type: ElToritoSectionHeaderEntry + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ElToritoSectionHeaderEntry + { + public readonly ElToritoIndicator header_id; + public readonly ElToritoPlatform platform_id; + public readonly ushort entries; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] + public readonly byte[] identifier; + } + +#endregion + +#region Nested type: ElToritoValidationEntry + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ElToritoValidationEntry + { + public readonly ElToritoIndicator header_id; + public readonly ElToritoPlatform platform_id; + public readonly ushort reserved; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] + public readonly byte[] developer_id; + public readonly ushort checksum; + public readonly ushort signature; + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Structs/HighSierra.cs b/Aaru.Filesystems/ISO9660/Structs/HighSierra.cs index 4adb44aa7..b09d479a8 100644 --- a/Aaru.Filesystems/ISO9660/Structs/HighSierra.cs +++ b/Aaru.Filesystems/ISO9660/Structs/HighSierra.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// High Sierra Format structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,17 +23,17 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Runtime.InteropServices; using System.Text; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { static DecodedVolumeDescriptor DecodeVolumeDescriptor(HighSierraPrimaryVolumeDescriptor pvd) @@ -52,14 +48,12 @@ public sealed partial class ISO9660 ApplicationIdentifier = Encoding.ASCII.GetString(pvd.application_data).TrimEnd().Trim('\0') }; - if(pvd.creation_date[0] == '0' || - pvd.creation_date[0] == 0x00) + if(pvd.creation_date[0] == '0' || pvd.creation_date[0] == 0x00) decodedVd.CreationTime = DateTime.MinValue; else decodedVd.CreationTime = DateHandlers.HighSierraToDateTime(pvd.creation_date); - if(pvd.modification_date[0] == '0' || - pvd.modification_date[0] == 0x00) + if(pvd.modification_date[0] == '0' || pvd.modification_date[0] == 0x00) decodedVd.HasModificationTime = false; else { @@ -67,8 +61,7 @@ public sealed partial class ISO9660 decodedVd.ModificationTime = DateHandlers.HighSierraToDateTime(pvd.modification_date); } - if(pvd.expiration_date[0] == '0' || - pvd.expiration_date[0] == 0x00) + if(pvd.expiration_date[0] == '0' || pvd.expiration_date[0] == 0x00) decodedVd.HasExpirationTime = false; else { @@ -76,8 +69,7 @@ public sealed partial class ISO9660 decodedVd.ExpirationTime = DateHandlers.HighSierraToDateTime(pvd.expiration_date); } - if(pvd.effective_date[0] == '0' || - pvd.effective_date[0] == 0x00) + if(pvd.effective_date[0] == '0' || pvd.effective_date[0] == 0x00) decodedVd.HasEffectiveTime = false; else { @@ -91,6 +83,49 @@ public sealed partial class ISO9660 return decodedVd; } +#region Nested type: HighSierraDirectoryRecord + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct HighSierraDirectoryRecord + { + public readonly byte length; + public readonly byte xattr_len; + public readonly uint extent; + public readonly uint extent_be; + public readonly uint size; + public readonly uint size_be; + public readonly HighSierraTimestamp date; + public readonly FileFlags flags; + public readonly byte reserved; + public readonly byte interleave_size; + public readonly byte interleave; + public readonly ushort volume_sequence_number; + public readonly ushort volume_sequence_number_be; + public readonly byte name_len; + + // Followed by name[name_len] and then system area until length arrives + } + +#endregion + +#region Nested type: HighSierraPathTableEntry + + // There are two tables one in little endian one in big endian + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct HighSierraPathTableEntry + { + public readonly uint start_lbn; + public readonly byte xattr_len; + public readonly byte name_len; + public readonly ushort parent_dirno; + + // Followed by name[name_len] + } + +#endregion + +#region Nested type: HighSierraPrimaryVolumeDescriptor + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct HighSierraPrimaryVolumeDescriptor { @@ -158,26 +193,9 @@ public sealed partial class ISO9660 public readonly byte[] reserved3; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct HighSierraDirectoryRecord - { - public readonly byte length; - public readonly byte xattr_len; - public readonly uint extent; - public readonly uint extent_be; - public readonly uint size; - public readonly uint size_be; - public readonly HighSierraTimestamp date; - public readonly FileFlags flags; - public readonly byte reserved; - public readonly byte interleave_size; - public readonly byte interleave; - public readonly ushort volume_sequence_number; - public readonly ushort volume_sequence_number_be; - public readonly byte name_len; +#endregion - // Followed by name[name_len] and then system area until length arrives - } +#region Nested type: HighSierraTimestamp [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct HighSierraTimestamp @@ -190,15 +208,5 @@ public sealed partial class ISO9660 public readonly byte Second; } - // There are two tables one in little endian one in big endian - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct HighSierraPathTableEntry - { - public readonly uint start_lbn; - public readonly byte xattr_len; - public readonly byte name_len; - public readonly ushort parent_dirno; - - // Followed by name[name_len] - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Structs/ISO.cs b/Aaru.Filesystems/ISO9660/Structs/ISO.cs index f4f99cf0d..6f8d80926 100644 --- a/Aaru.Filesystems/ISO9660/Structs/ISO.cs +++ b/Aaru.Filesystems/ISO9660/Structs/ISO.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// ISO9660 filesystem structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,21 +23,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ - - // ReSharper disable UnusedType.Local -namespace Aaru.Filesystems; - using System; using System.Runtime.InteropServices; using System.Text; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { static DecodedVolumeDescriptor DecodeVolumeDescriptor(PrimaryVolumeDescriptor pvd, Encoding encoding = null) @@ -50,22 +44,20 @@ public sealed partial class ISO9660 var decodedVd = new DecodedVolumeDescriptor { - SystemIdentifier = StringHandlers.CToString(pvd.system_id, encoding).TrimEnd(), - VolumeIdentifier = StringHandlers.CToString(pvd.volume_id, encoding).TrimEnd(), - VolumeSetIdentifier = StringHandlers.CToString(pvd.volume_set_id, encoding).TrimEnd(), - PublisherIdentifier = StringHandlers.CToString(pvd.publisher_id, encoding).TrimEnd(), - DataPreparerIdentifier = StringHandlers.CToString(pvd.preparer_id, encoding).TrimEnd(), + SystemIdentifier = StringHandlers.CToString(pvd.system_id, encoding).TrimEnd(), + VolumeIdentifier = StringHandlers.CToString(pvd.volume_id, encoding).TrimEnd(), + VolumeSetIdentifier = StringHandlers.CToString(pvd.volume_set_id, encoding).TrimEnd(), + PublisherIdentifier = StringHandlers.CToString(pvd.publisher_id, encoding).TrimEnd(), + DataPreparerIdentifier = StringHandlers.CToString(pvd.preparer_id, encoding).TrimEnd(), ApplicationIdentifier = StringHandlers.CToString(pvd.application_id, encoding).TrimEnd() }; - if(pvd.creation_date[0] == '0' || - pvd.creation_date[0] == 0x00) + if(pvd.creation_date[0] == '0' || pvd.creation_date[0] == 0x00) decodedVd.CreationTime = DateTime.MinValue; else decodedVd.CreationTime = DateHandlers.Iso9660ToDateTime(pvd.creation_date); - if(pvd.modification_date[0] == '0' || - pvd.modification_date[0] == 0x00) + if(pvd.modification_date[0] == '0' || pvd.modification_date[0] == 0x00) decodedVd.HasModificationTime = false; else { @@ -73,8 +65,7 @@ public sealed partial class ISO9660 decodedVd.ModificationTime = DateHandlers.Iso9660ToDateTime(pvd.modification_date); } - if(pvd.expiration_date[0] == '0' || - pvd.expiration_date[0] == 0x00) + if(pvd.expiration_date[0] == '0' || pvd.expiration_date[0] == 0x00) decodedVd.HasExpirationTime = false; else { @@ -82,8 +73,7 @@ public sealed partial class ISO9660 decodedVd.ExpirationTime = DateHandlers.Iso9660ToDateTime(pvd.expiration_date); } - if(pvd.effective_date[0] == '0' || - pvd.effective_date[0] == 0x00) + if(pvd.effective_date[0] == '0' || pvd.effective_date[0] == 0x00) decodedVd.HasEffectiveTime = false; else { @@ -97,6 +87,143 @@ public sealed partial class ISO9660 return decodedVd; } +#region Nested type: BootRecord + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct BootRecord + { + public readonly byte type; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public readonly byte[] id; + public readonly byte version; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] system_id; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] boot_id; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1977)] + public readonly byte[] boot_use; + } + +#endregion + +#region Nested type: DirectoryRecord + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DirectoryRecord + { + public readonly byte length; + public readonly byte xattr_len; + public readonly uint extent; + public readonly uint extent_be; + public readonly uint size; + public readonly uint size_be; + public readonly IsoTimestamp date; + public readonly FileFlags flags; + public readonly byte file_unit_size; + public readonly byte interleave; + public readonly ushort volume_sequence_number; + public readonly ushort volume_sequence_number_be; + public readonly byte name_len; + + // Followed by name[name_len] and then system area until length arrives + } + +#endregion + +#region Nested type: ExtendedAttributeRecord + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ExtendedAttributeRecord + { + public readonly ushort owner; + public readonly ushort owner_be; + public readonly ushort group; + public readonly ushort group_be; + public readonly Permissions permissions; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] + public readonly byte[] creation_date; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] + public readonly byte[] modification_date; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] + public readonly byte[] expiration_date; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] + public readonly byte[] effective_date; + public readonly RecordFormat record_format; + public readonly RecordAttribute record_attributes; + public readonly ushort record_length; + public readonly ushort record_length_be; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] system_id; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] system_use; + public readonly byte record_version; + public readonly byte escape_len; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] reserved1; + public readonly ushort app_use_len; + public readonly ushort app_use_len_be; + } + +#endregion + +#region Nested type: IsoTimestamp + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct IsoTimestamp + { + public readonly byte Years; + public readonly byte Month; + public readonly byte Day; + public readonly byte Hour; + public readonly byte Minute; + public readonly byte Second; + public readonly sbyte GmtOffset; + } + +#endregion + +#region Nested type: PartitionDescriptor + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct PartitionDescriptor + { + public readonly byte type; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public readonly byte[] id; + public readonly byte version; + public readonly byte reserved1; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] system_id; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] partition_id; + public readonly uint partition_location; + public readonly uint partition_location_be; + public readonly uint partition_size; + public readonly uint partition_size_be; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1960)] + public readonly byte[] system_use; + } + +#endregion + +#region Nested type: PathTableEntry + + // There are two tables one in little endian one in big endian + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct PathTableEntry + { + public readonly byte name_len; + public readonly byte xattr_len; + public readonly uint start_lbn; + public readonly ushort parent_dirno; + + // Followed by name[name_len] + } + +#endregion + +#region Nested type: PrimaryVolumeDescriptor + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct PrimaryVolumeDescriptor { @@ -162,114 +289,5 @@ public sealed partial class ISO9660 public readonly byte[] reserved3; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct BootRecord - { - public readonly byte type; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public readonly byte[] id; - public readonly byte version; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] system_id; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] boot_id; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1977)] - public readonly byte[] boot_use; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct PartitionDescriptor - { - public readonly byte type; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public readonly byte[] id; - public readonly byte version; - public readonly byte reserved1; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] system_id; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] partition_id; - public readonly uint partition_location; - public readonly uint partition_location_be; - public readonly uint partition_size; - public readonly uint partition_size_be; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1960)] - public readonly byte[] system_use; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DirectoryRecord - { - public readonly byte length; - public readonly byte xattr_len; - public readonly uint extent; - public readonly uint extent_be; - public readonly uint size; - public readonly uint size_be; - public readonly IsoTimestamp date; - public readonly FileFlags flags; - public readonly byte file_unit_size; - public readonly byte interleave; - public readonly ushort volume_sequence_number; - public readonly ushort volume_sequence_number_be; - public readonly byte name_len; - - // Followed by name[name_len] and then system area until length arrives - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ExtendedAttributeRecord - { - public readonly ushort owner; - public readonly ushort owner_be; - public readonly ushort group; - public readonly ushort group_be; - public readonly Permissions permissions; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public readonly byte[] creation_date; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public readonly byte[] modification_date; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public readonly byte[] expiration_date; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public readonly byte[] effective_date; - public readonly RecordFormat record_format; - public readonly RecordAttribute record_attributes; - public readonly ushort record_length; - public readonly ushort record_length_be; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] system_id; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] system_use; - public readonly byte record_version; - public readonly byte escape_len; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] reserved1; - public readonly ushort app_use_len; - public readonly ushort app_use_len_be; - } - - // There are two tables one in little endian one in big endian - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct PathTableEntry - { - public readonly byte name_len; - public readonly byte xattr_len; - public readonly uint start_lbn; - public readonly ushort parent_dirno; - - // Followed by name[name_len] - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct IsoTimestamp - { - public readonly byte Years; - public readonly byte Month; - public readonly byte Day; - public readonly byte Hour; - public readonly byte Minute; - public readonly byte Second; - public readonly sbyte GmtOffset; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Structs/Internal.cs b/Aaru.Filesystems/ISO9660/Structs/Internal.cs index 0a1b910bb..1f565e8fd 100644 --- a/Aaru.Filesystems/ISO9660/Structs/Internal.cs +++ b/Aaru.Filesystems/ISO9660/Structs/Internal.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Internal structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,37 +23,21 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; public sealed partial class ISO9660 { - struct DecodedVolumeDescriptor - { - public string SystemIdentifier; - public string VolumeIdentifier; - public string VolumeSetIdentifier; - public string PublisherIdentifier; - public string DataPreparerIdentifier; - public string ApplicationIdentifier; - public DateTime CreationTime; - public bool HasModificationTime; - public DateTime ModificationTime; - public bool HasExpirationTime; - public DateTime ExpirationTime; - public bool HasEffectiveTime; - public DateTime EffectiveTime; - public ushort BlockSize; - public uint Blocks; - } +#region Nested type: DecodedDirectoryEntry - class DecodedDirectoryEntry + sealed class DecodedDirectoryEntry { public byte[] AmigaComment; public AmigaProtection? AmigaProtection; @@ -89,13 +69,81 @@ public sealed partial class ISO9660 public string SymbolicLink; public DateTime? Timestamp; public ushort VolumeSequenceNumber; - public CdromXa? XA; - public byte XattrLength; + + // ReSharper disable once InconsistentNaming + public CdromXa? XA; + public byte XattrLength; public override string ToString() => Filename; } - class PathTableEntryInternal +#endregion + +#region Nested type: DecodedVolumeDescriptor + + struct DecodedVolumeDescriptor + { + public string SystemIdentifier; + public string VolumeIdentifier; + public string VolumeSetIdentifier; + public string PublisherIdentifier; + public string DataPreparerIdentifier; + public string ApplicationIdentifier; + public DateTime CreationTime; + public bool HasModificationTime; + public DateTime ModificationTime; + public bool HasExpirationTime; + public DateTime ExpirationTime; + public bool HasEffectiveTime; + public DateTime EffectiveTime; + public ushort BlockSize; + public uint Blocks; + } + +#endregion + +#region Nested type: Iso9660DirNode + + sealed class Iso9660DirNode : IDirNode + { + internal DecodedDirectoryEntry[] Entries; + internal int Position; + +#region IDirNode Members + + /// + public string Path { get; init; } + +#endregion + } + +#endregion + +#region Nested type: Iso9660FileNode + + sealed class Iso9660FileNode : IFileNode + { + internal DecodedDirectoryEntry Dentry; + +#region IFileNode Members + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + +#endregion + } + +#endregion + +#region Nested type: PathTableEntryInternal + + sealed class PathTableEntryInternal { public uint Extent; public string Name; @@ -104,4 +152,6 @@ public sealed partial class ISO9660 public override string ToString() => Name; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Structs/Joliet.cs b/Aaru.Filesystems/ISO9660/Structs/Joliet.cs index 7f74b1c92..104d9e999 100644 --- a/Aaru.Filesystems/ISO9660/Structs/Joliet.cs +++ b/Aaru.Filesystems/ISO9660/Structs/Joliet.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Joliet extensions structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,16 +23,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Text; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { static DecodedVolumeDescriptor DecodeJolietDescriptor(PrimaryVolumeDescriptor jolietvd) @@ -45,24 +41,23 @@ public sealed partial class ISO9660 { SystemIdentifier = Encoding.BigEndianUnicode.GetString(jolietvd.system_id).Replace('\u0000', ' ').TrimEnd(), VolumeIdentifier = Encoding.BigEndianUnicode.GetString(jolietvd.volume_id).Replace('\u0000', ' ').TrimEnd(), - VolumeSetIdentifier = Encoding.BigEndianUnicode.GetString(jolietvd.volume_set_id).Replace('\u0000', ' '). - TrimEnd(), - PublisherIdentifier = Encoding.BigEndianUnicode.GetString(jolietvd.publisher_id).Replace('\u0000', ' '). - TrimEnd(), - DataPreparerIdentifier = Encoding.BigEndianUnicode.GetString(jolietvd.preparer_id).Replace('\u0000', ' '). - TrimEnd(), - ApplicationIdentifier = Encoding.BigEndianUnicode.GetString(jolietvd.application_id).Replace('\u0000', ' '). - TrimEnd() + VolumeSetIdentifier = + Encoding.BigEndianUnicode.GetString(jolietvd.volume_set_id).Replace('\u0000', ' ').TrimEnd(), + PublisherIdentifier = + Encoding.BigEndianUnicode.GetString(jolietvd.publisher_id).Replace('\u0000', ' ').TrimEnd(), + DataPreparerIdentifier = + Encoding.BigEndianUnicode.GetString(jolietvd.preparer_id).Replace('\u0000', ' ').TrimEnd(), + ApplicationIdentifier = Encoding.BigEndianUnicode.GetString(jolietvd.application_id) + .Replace('\u0000', ' ') + .TrimEnd() }; - if(jolietvd.creation_date[0] < 0x31 || - jolietvd.creation_date[0] > 0x39) + if(jolietvd.creation_date[0] < 0x31 || jolietvd.creation_date[0] > 0x39) decodedVd.CreationTime = DateTime.MinValue; else decodedVd.CreationTime = DateHandlers.Iso9660ToDateTime(jolietvd.creation_date); - if(jolietvd.modification_date[0] < 0x31 || - jolietvd.modification_date[0] > 0x39) + if(jolietvd.modification_date[0] < 0x31 || jolietvd.modification_date[0] > 0x39) decodedVd.HasModificationTime = false; else { @@ -70,8 +65,7 @@ public sealed partial class ISO9660 decodedVd.ModificationTime = DateHandlers.Iso9660ToDateTime(jolietvd.modification_date); } - if(jolietvd.expiration_date[0] < 0x31 || - jolietvd.expiration_date[0] > 0x39) + if(jolietvd.expiration_date[0] < 0x31 || jolietvd.expiration_date[0] > 0x39) decodedVd.HasExpirationTime = false; else { @@ -79,8 +73,7 @@ public sealed partial class ISO9660 decodedVd.ExpirationTime = DateHandlers.Iso9660ToDateTime(jolietvd.expiration_date); } - if(jolietvd.effective_date[0] < 0x31 || - jolietvd.effective_date[0] > 0x39) + if(jolietvd.effective_date[0] < 0x31 || jolietvd.effective_date[0] > 0x39) decodedVd.HasEffectiveTime = false; else { diff --git a/Aaru.Filesystems/ISO9660/Structs/RRIP.cs b/Aaru.Filesystems/ISO9660/Structs/RRIP.cs index f3d7c033c..b3b8f78a1 100644 --- a/Aaru.Filesystems/ISO9660/Structs/RRIP.cs +++ b/Aaru.Filesystems/ISO9660/Structs/RRIP.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// RRIP extensions structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,35 +23,63 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +namespace Aaru.Filesystems; + [SuppressMessage("ReSharper", "UnusedType.Local")] public sealed partial class ISO9660 { - // RRIP 1.10 +#region Nested type: AlternateName + [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct PosixAttributesOld + readonly struct AlternateName { - public readonly ushort signature; - public readonly byte length; - public readonly byte version; - public readonly PosixMode st_mode; - public readonly PosixMode st_mode_be; - public readonly uint st_nlink; - public readonly uint st_nlink_be; - public readonly uint st_uid; - public readonly uint st_uid_be; - public readonly uint st_gid; - public readonly uint st_gid_be; + public readonly ushort signature; + public readonly byte length; + public readonly byte version; + public readonly AlternateNameFlags flags; + + // Folowed by name, can be divided in pieces } +#endregion + +#region Nested type: ChildLink + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ChildLink + { + public readonly ushort signature; + public readonly byte length; + public readonly byte version; + public readonly uint child_dir_lba; + public readonly uint child_dir_lba_be; + } + +#endregion + +#region Nested type: ParentLink + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ParentLink + { + public readonly ushort signature; + public readonly byte length; + public readonly byte version; + public readonly uint parent_dir_lba; + public readonly uint parent_dir_lba_be; + } + +#endregion + +#region Nested type: PosixAttributes + // RRIP 1.12 [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct PosixAttributes @@ -75,6 +99,31 @@ public sealed partial class ISO9660 public readonly uint st_ino_be; } +#endregion + +#region Nested type: PosixAttributesOld + + // RRIP 1.10 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct PosixAttributesOld + { + public readonly ushort signature; + public readonly byte length; + public readonly byte version; + public readonly PosixMode st_mode; + public readonly PosixMode st_mode_be; + public readonly uint st_nlink; + public readonly uint st_nlink_be; + public readonly uint st_uid; + public readonly uint st_uid_be; + public readonly uint st_gid; + public readonly uint st_gid_be; + } + +#endregion + +#region Nested type: PosixDeviceNumber + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct PosixDeviceNumber { @@ -87,6 +136,39 @@ public sealed partial class ISO9660 public readonly uint dev_t_low_be; } +#endregion + +#region Nested type: RelocatedDirectory + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct RelocatedDirectory + { + public readonly ushort signature; + public readonly byte length; + public readonly byte version; + } + +#endregion + +#region Nested type: SparseFile + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SparseFile + { + public readonly ushort signature; + public readonly byte length; + public readonly byte version; + public readonly uint virtual_size_high; + public readonly uint virtual_size_high_be; + public readonly uint virtual_size_low; + public readonly uint virtual_size_low_be; + public readonly byte table_depth; + } + +#endregion + +#region Nested type: SymbolicLink + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct SymbolicLink { @@ -98,6 +180,10 @@ public sealed partial class ISO9660 // Followed by SymbolicLinkComponent (link to /bar/foo uses at least two of these structs) } +#endregion + +#region Nested type: SymbolicLinkComponent + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct SymbolicLinkComponent { @@ -107,44 +193,9 @@ public sealed partial class ISO9660 // Followed by component content } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct AlternateName - { - public readonly ushort signature; - public readonly byte length; - public readonly byte version; - public readonly AlternateNameFlags flags; +#endregion - // Folowed by name, can be divided in pieces - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ChildLink - { - public readonly ushort signature; - public readonly byte length; - public readonly byte version; - public readonly uint child_dir_lba; - public readonly uint child_dir_lba_be; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ParentLink - { - public readonly ushort signature; - public readonly byte length; - public readonly byte version; - public readonly uint parent_dir_lba; - public readonly uint parent_dir_lba_be; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct RelocatedDirectory - { - public readonly ushort signature; - public readonly byte length; - public readonly byte version; - } +#region Nested type: Timestamps [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct Timestamps @@ -164,16 +215,5 @@ public sealed partial class ISO9660 // Followed by effective time if present } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SparseFile - { - public readonly ushort signature; - public readonly byte length; - public readonly byte version; - public readonly uint virtual_size_high; - public readonly uint virtual_size_high_be; - public readonly uint virtual_size_low; - public readonly uint virtual_size_low_be; - public readonly byte table_depth; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Structs/SUSP.cs b/Aaru.Filesystems/ISO9660/Structs/SUSP.cs index f661845fd..6ee40ec5f 100644 --- a/Aaru.Filesystems/ISO9660/Structs/SUSP.cs +++ b/Aaru.Filesystems/ISO9660/Structs/SUSP.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// SUSP extensions structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,20 +23,20 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ - - // ReSharper disable UnusedType.Local -namespace Aaru.Filesystems; - using System.Runtime.InteropServices; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { +#region Nested type: ContinuationArea + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct ContinuationArea { @@ -55,13 +51,9 @@ public sealed partial class ISO9660 public readonly uint ca_length_be; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct PaddingArea - { - public readonly ushort signature; - public readonly byte length; - public readonly byte version; - } +#endregion + +#region Nested type: IndicatorArea [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct IndicatorArea @@ -73,14 +65,22 @@ public sealed partial class ISO9660 public readonly byte skipped; } +#endregion + +#region Nested type: PaddingArea + [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct TerminatorArea + readonly struct PaddingArea { public readonly ushort signature; public readonly byte length; public readonly byte version; } +#endregion + +#region Nested type: ReferenceArea + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct ReferenceArea { @@ -97,6 +97,10 @@ public sealed partial class ISO9660 // Follows extension source for src_len bytes } +#endregion + +#region Nested type: SelectorArea + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct SelectorArea { @@ -105,4 +109,18 @@ public sealed partial class ISO9660 public readonly byte version; public readonly byte sequence; } + +#endregion + +#region Nested type: TerminatorArea + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct TerminatorArea + { + public readonly ushort signature; + public readonly byte length; + public readonly byte version; + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Structs/XA.cs b/Aaru.Filesystems/ISO9660/Structs/XA.cs index cac275d70..e1c085ad2 100644 --- a/Aaru.Filesystems/ISO9660/Structs/XA.cs +++ b/Aaru.Filesystems/ISO9660/Structs/XA.cs @@ -27,16 +27,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Runtime.InteropServices; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { +#region Nested type: CdromXa + // Big-endian [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct CdromXa @@ -49,4 +51,6 @@ public sealed partial class ISO9660 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public readonly byte[] reserved; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Structs/Ziso.cs b/Aaru.Filesystems/ISO9660/Structs/Ziso.cs index bfa8a0c75..9dda4b49d 100644 --- a/Aaru.Filesystems/ISO9660/Structs/Ziso.cs +++ b/Aaru.Filesystems/ISO9660/Structs/Ziso.cs @@ -7,10 +7,6 @@ // // Component : ISO9660 filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// zisofs extensions structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,27 +23,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +namespace Aaru.Filesystems; + [SuppressMessage("ReSharper", "UnusedType.Local")] public sealed partial class ISO9660 { - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ZisofsHeader - { - public readonly ulong magic; - public readonly uint uncomp_len; - public readonly uint uncomp_len_be; - public readonly byte header_size; // Shifted >> 2 - public readonly byte block_size_log; // log2(block_size) - } +#region Nested type: ZisofsEntry [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct ZisofsEntry @@ -61,4 +49,20 @@ public sealed partial class ISO9660 public readonly uint uncomp_len; public readonly uint uncomp_len_be; } + +#endregion + +#region Nested type: ZisofsHeader + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ZisofsHeader + { + public readonly ulong magic; + public readonly uint uncomp_len; + public readonly uint uncomp_len_be; + public readonly byte header_size; // Shifted >> 2 + public readonly byte block_size_log; // log2(block_size) + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Super.cs b/Aaru.Filesystems/ISO9660/Super.cs index de6718427..829211248 100644 --- a/Aaru.Filesystems/ISO9660/Super.cs +++ b/Aaru.Filesystems/ISO9660/Super.cs @@ -27,38 +27,39 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Decoders.Sega; using Aaru.Helpers; -using Schemas; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class ISO9660 { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, - Dictionary options, string @namespace) + public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace) { - Encoding = encoding ?? Encoding.GetEncoding(1252); + _encoding = encoding ?? Encoding.GetEncoding(1252); var vdMagic = new byte[5]; // Volume Descriptor magic "CD001" var hsMagic = new byte[5]; // Volume Descriptor magic "CDROM" options ??= GetDefaultOptions(); - if(options.TryGetValue("debug", out string debugString)) - bool.TryParse(debugString, out _debug); + if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out _debug); if(options.TryGetValue("use_path_table", out string usePathTableString)) bool.TryParse(usePathTableString, out _usePathTable); @@ -66,8 +67,7 @@ public sealed partial class ISO9660 if(options.TryGetValue("use_trans_tbl", out string useTransTblString)) bool.TryParse(useTransTblString, out _useTransTbl); - if(options.TryGetValue("use_evd", out string useEvdString)) - bool.TryParse(useEvdString, out _useEvd); + if(options.TryGetValue("use_evd", out string useEvdString)) bool.TryParse(useEvdString, out _useEvd); // Default namespace @namespace ??= "joliet"; @@ -94,7 +94,8 @@ public sealed partial class ISO9660 _namespace = Namespace.Romeo; break; - default: return ErrorNumber.InvalidArgument; + default: + return ErrorNumber.InvalidArgument; } PrimaryVolumeDescriptor? pvd = null; @@ -104,56 +105,50 @@ public sealed partial class ISO9660 FileStructureVolumeDescriptor? fsvd = null; // ISO9660 is designed for 2048 bytes/sector devices - if(imagePlugin.Info.SectorSize < 2048) - return ErrorNumber.InvalidArgument; + if(imagePlugin.Info.SectorSize < 2048) return ErrorNumber.InvalidArgument; // ISO9660 Primary Volume Descriptor starts at sector 16, so that's minimal size. - if(partition.End < 16) - return ErrorNumber.InvalidArgument; + if(partition.End < 16) return ErrorNumber.InvalidArgument; ulong counter = 0; ErrorNumber errno = imagePlugin.ReadSector(16 + partition.Start, out byte[] vdSector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; int xaOff = vdSector.Length == 2336 ? 8 : 0; Array.Copy(vdSector, 0x009 + xaOff, hsMagic, 0, 5); - _highSierra = Encoding.GetString(hsMagic) == HIGH_SIERRA_MAGIC; + _highSierra = _encoding.GetString(hsMagic) == HIGH_SIERRA_MAGIC; var hsOff = 0; - if(_highSierra) - hsOff = 8; + if(_highSierra) hsOff = 8; _cdi = false; - List bvdSectors = new(); - List pvdSectors = new(); - List svdSectors = new(); - List evdSectors = new(); - List vpdSectors = new(); + List bvdSectors = []; + List pvdSectors = []; + List svdSectors = []; + List evdSectors = []; + List vpdSectors = []; while(true) { - AaruConsole.DebugWriteLine("ISO9660 plugin", "Processing VD loop no. {0}", counter); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Processing_VD_loop_no_0, counter); // Seek to Volume Descriptor - AaruConsole.DebugWriteLine("ISO9660 plugin", "Reading sector {0}", 16 + counter + partition.Start); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_sector_0, 16 + counter + partition.Start); errno = imagePlugin.ReadSector(16 + counter + partition.Start, out byte[] vdSectorTmp); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; vdSector = new byte[vdSectorTmp.Length - xaOff]; Array.Copy(vdSectorTmp, xaOff, vdSector, 0, vdSector.Length); byte vdType = vdSector[0 + hsOff]; // Volume Descriptor Type, should be 1 or 2. - AaruConsole.DebugWriteLine("ISO9660 plugin", "VDType = {0}", vdType); + AaruConsole.DebugWriteLine(MODULE_NAME, "VDType = {0}", vdType); if(vdType == 255) // Supposedly we are in the PVD. { - if(counter == 0) - return ErrorNumber.InvalidArgument; + if(counter == 0) return ErrorNumber.InvalidArgument; break; } @@ -161,24 +156,22 @@ public sealed partial class ISO9660 Array.Copy(vdSector, 0x001, vdMagic, 0, 5); Array.Copy(vdSector, 0x009, hsMagic, 0, 5); - if(Encoding.GetString(vdMagic) != ISO_MAGIC && - Encoding.GetString(hsMagic) != HIGH_SIERRA_MAGIC && - Encoding.GetString(vdMagic) != CDI_MAGIC) // Recognized, it is an ISO9660, now check for rest of data. + if(_encoding.GetString(vdMagic) != ISO_MAGIC && + _encoding.GetString(hsMagic) != HIGH_SIERRA_MAGIC && + _encoding.GetString(vdMagic) != CDI_MAGIC) // Recognized, it is an ISO9660, now check for rest of data. { - if(counter == 0) - return ErrorNumber.InvalidArgument; + if(counter == 0) return ErrorNumber.InvalidArgument; break; } - _cdi |= Encoding.GetString(vdMagic) == CDI_MAGIC; + _cdi |= _encoding.GetString(vdMagic) == CDI_MAGIC; switch(vdType) { case 0: { - if(_debug) - bvdSectors.Add(16 + counter + partition.Start); + if(_debug) bvdSectors.Add(16 + counter + partition.Start); break; } @@ -192,8 +185,7 @@ public sealed partial class ISO9660 else pvd = Marshal.ByteArrayToStructureLittleEndian(vdSector); - if(_debug) - pvdSectors.Add(16 + counter + partition.Start); + if(_debug) pvdSectors.Add(16 + counter + partition.Start); break; } @@ -207,23 +199,24 @@ public sealed partial class ISO9660 // Check if this is Joliet if(svd.version == 1) { - if(svd.escape_sequences[0] == '%' && - svd.escape_sequences[1] == '/') + if(svd.escape_sequences[0] == '%' && svd.escape_sequences[1] == '/') + { if(svd.escape_sequences[2] == '@' || svd.escape_sequences[2] == 'C' || svd.escape_sequences[2] == 'E') jolietvd = svd; else - AaruConsole.DebugWriteLine("ISO9660 plugin", - "Found unknown supplementary volume descriptor"); + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Found_unknown_supplementary_volume_descriptor); + } + } - if(_debug) - svdSectors.Add(16 + counter + partition.Start); + if(_debug) svdSectors.Add(16 + counter + partition.Start); } else { - if(_debug) - evdSectors.Add(16 + counter + partition.Start); + if(_debug) evdSectors.Add(16 + counter + partition.Start); if(_useEvd) { @@ -239,8 +232,7 @@ public sealed partial class ISO9660 case 3: { - if(_debug) - vpdSectors.Add(16 + counter + partition.Start); + if(_debug) vpdSectors.Add(16 + counter + partition.Start); break; } @@ -252,13 +244,11 @@ public sealed partial class ISO9660 DecodedVolumeDescriptor decodedVd; var decodedJolietVd = new DecodedVolumeDescriptor(); - XmlFsType = new FileSystemType(); + Metadata = new FileSystem(); - if(pvd == null && - hsvd == null && - fsvd == null) + if(pvd == null && hsvd == null && fsvd == null) { - AaruConsole.ErrorWriteLine("ERROR: Could not find primary volume descriptor"); + AaruConsole.ErrorWriteLine(Localization.ERROR_Could_not_find_primary_volume_descriptor); return ErrorNumber.InvalidArgument; } @@ -268,13 +258,11 @@ public sealed partial class ISO9660 else if(_cdi) decodedVd = DecodeVolumeDescriptor(fsvd.Value); else - decodedVd = DecodeVolumeDescriptor(pvd.Value, _namespace == Namespace.Romeo ? Encoding : Encoding.ASCII); + decodedVd = DecodeVolumeDescriptor(pvd.Value, _namespace == Namespace.Romeo ? _encoding : Encoding.ASCII); - if(jolietvd != null) - decodedJolietVd = DecodeJolietDescriptor(jolietvd.Value); + if(jolietvd != null) decodedJolietVd = DecodeJolietDescriptor(jolietvd.Value); - if(_namespace != Namespace.Romeo) - Encoding = Encoding.ASCII; + if(_namespace != Namespace.Romeo) _encoding = Encoding.ASCII; string fsFormat; byte[] pathTableData; @@ -288,13 +276,13 @@ public sealed partial class ISO9660 { _blockSize = hsvd.Value.logical_block_size; - errno = ReadSingleExtent(hsvd.Value.path_table_size, Swapping.Swap(hsvd.Value.mandatory_path_table_msb), + errno = ReadSingleExtent(hsvd.Value.path_table_size, + Swapping.Swap(hsvd.Value.mandatory_path_table_msb), out pathTableData); - if(errno != ErrorNumber.NoError) - pathTableData = null; + if(errno != ErrorNumber.NoError) pathTableData = null; - fsFormat = "High Sierra Format"; + fsFormat = FS_TYPE_HSF; pathTableMsbLocation = hsvd.Value.mandatory_path_table_msb; pathTableLsbLocation = hsvd.Value.mandatory_path_table_lsb; @@ -305,27 +293,26 @@ public sealed partial class ISO9660 errno = ReadSingleExtent(fsvd.Value.path_table_size, fsvd.Value.path_table_addr, out pathTableData); - if(errno != ErrorNumber.NoError) - pathTableData = null; + if(errno != ErrorNumber.NoError) pathTableData = null; - fsFormat = "CD-i"; + fsFormat = FS_TYPE_CDI; pathTableMsbLocation = fsvd.Value.path_table_addr; // TODO: Until escape sequences are implemented this is the default CD-i encoding. - Encoding = Encoding.GetEncoding("iso8859-1"); + _encoding = Encoding.GetEncoding("iso8859-1"); } else { _blockSize = pvd.Value.logical_block_size; - errno = ReadSingleExtent(pvd.Value.path_table_size, Swapping.Swap(pvd.Value.type_m_path_table), + errno = ReadSingleExtent(pvd.Value.path_table_size, + Swapping.Swap(pvd.Value.type_m_path_table), out pathTableData); - if(errno != ErrorNumber.NoError) - pathTableData = null; + if(errno != ErrorNumber.NoError) pathTableData = null; - fsFormat = "ISO9660"; + fsFormat = FS_TYPE_ISO; pathTableMsbLocation = pvd.Value.type_m_path_table; pathTableLsbLocation = pvd.Value.type_l_path_table; @@ -341,14 +328,10 @@ public sealed partial class ISO9660 } // High Sierra and CD-i do not support Joliet or RRIP - if((_highSierra || _cdi) && - _namespace != Namespace.Normal && - _namespace != Namespace.Vms) + if((_highSierra || _cdi) && _namespace != Namespace.Normal && _namespace != Namespace.Vms) _namespace = Namespace.Normal; - if(jolietvd is null && - _namespace == Namespace.Joliet) - _namespace = Namespace.Normal; + if(jolietvd is null && _namespace == Namespace.Joliet) _namespace = Namespace.Normal; uint rootLocation; uint rootSize; @@ -356,24 +339,25 @@ public sealed partial class ISO9660 if(!_cdi) { - rootLocation = _highSierra ? hsvd.Value.root_directory_record.extent + rootLocation = _highSierra + ? hsvd.Value.root_directory_record.extent : pvd.Value.root_directory_record.extent; - rootXattrLength = _highSierra ? hsvd.Value.root_directory_record.xattr_len + rootXattrLength = _highSierra + ? hsvd.Value.root_directory_record.xattr_len : pvd.Value.root_directory_record.xattr_len; rootSize = _highSierra ? hsvd.Value.root_directory_record.size : pvd.Value.root_directory_record.size; - if(_pathTable?.Length > 1 && - rootLocation != _pathTable[0].Extent) + if(_pathTable?.Length > 1 && rootLocation != _pathTable[0].Extent) { - AaruConsole.DebugWriteLine("ISO9660 plugin", - "Path table and PVD do not point to the same location for the root directory!"); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .Path_table_and_PVD_do_not_point_to_the_same_location_for_the_root_directory); errno = ReadSector(rootLocation, out byte[] firstRootSector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; var pvdWrongRoot = false; @@ -382,22 +366,21 @@ public sealed partial class ISO9660 HighSierraDirectoryRecord rootEntry = Marshal.ByteArrayToStructureLittleEndian(firstRootSector); - if(rootEntry.extent != rootLocation) - pvdWrongRoot = true; + if(rootEntry.extent != rootLocation) pvdWrongRoot = true; } else { DirectoryRecord rootEntry = Marshal.ByteArrayToStructureLittleEndian(firstRootSector); - if(rootEntry.extent != rootLocation) - pvdWrongRoot = true; + if(rootEntry.extent != rootLocation) pvdWrongRoot = true; } if(pvdWrongRoot) { - AaruConsole.DebugWriteLine("ISO9660 plugin", - "PVD does not point to correct root directory, checking path table..."); + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization + .PVD_does_not_point_to_correct_root_directory_checking_path_table); var pathTableWrongRoot = false; @@ -410,21 +393,19 @@ public sealed partial class ISO9660 HighSierraDirectoryRecord rootEntry = Marshal.ByteArrayToStructureLittleEndian(firstRootSector); - if(rootEntry.extent != rootLocation) - pathTableWrongRoot = true; + if(rootEntry.extent != rootLocation) pathTableWrongRoot = true; } else { DirectoryRecord rootEntry = Marshal.ByteArrayToStructureLittleEndian(firstRootSector); - if(rootEntry.extent != rootLocation) - pathTableWrongRoot = true; + if(rootEntry.extent != rootLocation) pathTableWrongRoot = true; } if(pathTableWrongRoot) { - AaruConsole.ErrorWriteLine("Cannot find root directory..."); + AaruConsole.ErrorWriteLine(Localization.Cannot_find_root_directory); return ErrorNumber.InvalidArgument; } @@ -439,8 +420,7 @@ public sealed partial class ISO9660 errno = ReadSector(rootLocation, out byte[] firstRootSector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; CdiDirectoryRecord rootEntry = Marshal.ByteArrayToStructureBigEndian(firstRootSector); @@ -451,8 +431,7 @@ public sealed partial class ISO9660 } // In case the path table is incomplete - if(_usePathTable && (_pathTable is null || _pathTable?.Length <= 1)) - _usePathTable = false; + if(_usePathTable && (_pathTable is null || _pathTable?.Length <= 1)) _usePathTable = false; if(_usePathTable && !_cdi) { @@ -460,8 +439,7 @@ public sealed partial class ISO9660 errno = ReadSector(rootLocation, out byte[] firstRootSector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; if(_highSierra) { @@ -491,8 +469,7 @@ public sealed partial class ISO9660 errno = ReadSector(partition.Start, out byte[] ipbinSector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; CD.IPBin? segaCd = CD.DecodeIPBin(ipbinSector); Saturn.IPBin? saturn = Saturn.DecodeIPBin(ipbinSector); @@ -505,20 +482,20 @@ public sealed partial class ISO9660 } // Cannot traverse path table if we substitute the names for the ones in TRANS.TBL - if(_useTransTbl) - _usePathTable = false; + if(_useTransTbl) _usePathTable = false; if(_namespace != Namespace.Joliet) + { _rootDirectoryCache = _cdi ? DecodeCdiDirectory(rootLocation + rootXattrLength, rootSize) : _highSierra ? DecodeHighSierraDirectory(rootLocation + rootXattrLength, rootSize) : DecodeIsoDirectory(rootLocation + rootXattrLength, rootSize); + } - XmlFsType.Type = fsFormat; + Metadata.Type = fsFormat; - if(jolietvd != null && - _namespace is Namespace.Joliet or Namespace.Rrip) + if(jolietvd != null && _namespace is Namespace.Joliet or Namespace.Rrip) { rootLocation = jolietvd.Value.root_directory_record.extent; rootXattrLength = jolietvd.Value.root_directory_record.xattr_len; @@ -529,232 +506,220 @@ public sealed partial class ISO9660 _rootDirectoryCache = DecodeIsoDirectory(rootLocation + rootXattrLength, rootSize); - XmlFsType.VolumeName = decodedJolietVd.VolumeIdentifier; + Metadata.VolumeName = decodedJolietVd.VolumeIdentifier; if(string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) || decodedVd.SystemIdentifier.Length > decodedJolietVd.SystemIdentifier.Length) - XmlFsType.SystemIdentifier = decodedVd.SystemIdentifier; + Metadata.SystemIdentifier = decodedVd.SystemIdentifier; else - XmlFsType.SystemIdentifier = string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) ? null - : decodedJolietVd.SystemIdentifier; + { + Metadata.SystemIdentifier = string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) + ? null + : decodedJolietVd.SystemIdentifier; + } if(string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) || decodedVd.VolumeSetIdentifier.Length > decodedJolietVd.VolumeSetIdentifier.Length) - XmlFsType.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; + Metadata.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; else - XmlFsType.VolumeSetIdentifier = string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) ? null - : decodedJolietVd.VolumeSetIdentifier; + { + Metadata.VolumeSetIdentifier = string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) + ? null + : decodedJolietVd.VolumeSetIdentifier; + } if(string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) || decodedVd.PublisherIdentifier.Length > decodedJolietVd.PublisherIdentifier.Length) - XmlFsType.PublisherIdentifier = decodedVd.PublisherIdentifier; + Metadata.PublisherIdentifier = decodedVd.PublisherIdentifier; else - XmlFsType.PublisherIdentifier = string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) ? null - : decodedJolietVd.PublisherIdentifier; + { + Metadata.PublisherIdentifier = string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) + ? null + : decodedJolietVd.PublisherIdentifier; + } if(string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) || decodedVd.DataPreparerIdentifier.Length > decodedJolietVd.DataPreparerIdentifier.Length) - XmlFsType.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; + Metadata.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; else - XmlFsType.DataPreparerIdentifier = string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) ? null - : decodedJolietVd.DataPreparerIdentifier; + { + Metadata.DataPreparerIdentifier = string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) + ? null + : decodedJolietVd.DataPreparerIdentifier; + } if(string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) || decodedVd.ApplicationIdentifier.Length > decodedJolietVd.ApplicationIdentifier.Length) - XmlFsType.ApplicationIdentifier = decodedVd.ApplicationIdentifier; + Metadata.ApplicationIdentifier = decodedVd.ApplicationIdentifier; else - XmlFsType.ApplicationIdentifier = string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) ? null - : decodedJolietVd.ApplicationIdentifier; - - XmlFsType.CreationDate = decodedJolietVd.CreationTime; - XmlFsType.CreationDateSpecified = true; - - if(decodedJolietVd.HasModificationTime) { - XmlFsType.ModificationDate = decodedJolietVd.ModificationTime; - XmlFsType.ModificationDateSpecified = true; + Metadata.ApplicationIdentifier = string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) + ? null + : decodedJolietVd.ApplicationIdentifier; } - if(decodedJolietVd.HasExpirationTime) - { - XmlFsType.ExpirationDate = decodedJolietVd.ExpirationTime; - XmlFsType.ExpirationDateSpecified = true; - } + Metadata.CreationDate = decodedJolietVd.CreationTime; - if(decodedJolietVd.HasEffectiveTime) - { - XmlFsType.EffectiveDate = decodedJolietVd.EffectiveTime; - XmlFsType.EffectiveDateSpecified = true; - } + if(decodedJolietVd.HasModificationTime) Metadata.ModificationDate = decodedJolietVd.ModificationTime; + + if(decodedJolietVd.HasExpirationTime) Metadata.ExpirationDate = decodedJolietVd.ExpirationTime; + + if(decodedJolietVd.HasEffectiveTime) Metadata.EffectiveDate = decodedJolietVd.EffectiveTime; decodedVd = decodedJolietVd; } else { - XmlFsType.SystemIdentifier = decodedVd.SystemIdentifier; - XmlFsType.VolumeName = decodedVd.VolumeIdentifier; - XmlFsType.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; - XmlFsType.PublisherIdentifier = decodedVd.PublisherIdentifier; - XmlFsType.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; - XmlFsType.ApplicationIdentifier = decodedVd.ApplicationIdentifier; - XmlFsType.CreationDate = decodedVd.CreationTime; - XmlFsType.CreationDateSpecified = true; + Metadata.SystemIdentifier = decodedVd.SystemIdentifier; + Metadata.VolumeName = decodedVd.VolumeIdentifier; + Metadata.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; + Metadata.PublisherIdentifier = decodedVd.PublisherIdentifier; + Metadata.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; + Metadata.ApplicationIdentifier = decodedVd.ApplicationIdentifier; + Metadata.CreationDate = decodedVd.CreationTime; - if(decodedVd.HasModificationTime) - { - XmlFsType.ModificationDate = decodedVd.ModificationTime; - XmlFsType.ModificationDateSpecified = true; - } + if(decodedVd.HasModificationTime) Metadata.ModificationDate = decodedVd.ModificationTime; - if(decodedVd.HasExpirationTime) - { - XmlFsType.ExpirationDate = decodedVd.ExpirationTime; - XmlFsType.ExpirationDateSpecified = true; - } + if(decodedVd.HasExpirationTime) Metadata.ExpirationDate = decodedVd.ExpirationTime; - if(decodedVd.HasEffectiveTime) - { - XmlFsType.EffectiveDate = decodedVd.EffectiveTime; - XmlFsType.EffectiveDateSpecified = true; - } + if(decodedVd.HasEffectiveTime) Metadata.EffectiveDate = decodedVd.EffectiveTime; } if(_debug) { - _rootDirectoryCache.Add("$", new DecodedDirectoryEntry - { - Extents = new List<(uint extent, uint size)> - { - (rootLocation, rootSize) - }, - Filename = "$", - Size = rootSize, - Timestamp = decodedVd.CreationTime - }); + _rootDirectoryCache.Add("$", + new DecodedDirectoryEntry + { + Extents = [(rootLocation, rootSize)], + Filename = "$", + Size = rootSize, + Timestamp = decodedVd.CreationTime + }); if(!_cdi) - _rootDirectoryCache.Add("$PATH_TABLE.LSB", new DecodedDirectoryEntry - { - Extents = new List<(uint extent, uint size)> - { - (pathTableLsbLocation, (uint)pathTableData.Length) - }, - Filename = "$PATH_TABLE.LSB", - Size = (uint)pathTableData.Length, - Timestamp = decodedVd.CreationTime - }); - - _rootDirectoryCache.Add("$PATH_TABLE.MSB", new DecodedDirectoryEntry { - Extents = new List<(uint extent, uint size)> - { - (Swapping.Swap(pathTableMsbLocation), (uint)pathTableData.Length) - }, - Filename = "$PATH_TABLE.MSB", - Size = (uint)pathTableData.Length, - Timestamp = decodedVd.CreationTime - }); + _rootDirectoryCache.Add("$PATH_TABLE.LSB", + new DecodedDirectoryEntry + { + Extents = [(pathTableLsbLocation, (uint)pathTableData.Length)], + Filename = "$PATH_TABLE.LSB", + Size = (uint)pathTableData.Length, + Timestamp = decodedVd.CreationTime + }); + } + + _rootDirectoryCache.Add("$PATH_TABLE.MSB", + new DecodedDirectoryEntry + { + Extents = [(Swapping.Swap(pathTableMsbLocation), (uint)pathTableData.Length)], + Filename = "$PATH_TABLE.MSB", + Size = (uint)pathTableData.Length, + Timestamp = decodedVd.CreationTime + }); for(var i = 0; i < bvdSectors.Count; i++) - _rootDirectoryCache.Add(i == 0 ? "$BOOT" : $"$BOOT_{i}", new DecodedDirectoryEntry - { - Extents = new List<(uint extent, uint size)> - { - ((uint)i, 2048) - }, - Filename = i == 0 ? "$BOOT" : $"$BOOT_{i}", - Size = 2048, - Timestamp = decodedVd.CreationTime - }); + { + _rootDirectoryCache.Add(i == 0 ? "$BOOT" : $"$BOOT_{i}", + new DecodedDirectoryEntry + { + Extents = [((uint)i, 2048)], + Filename = i == 0 ? "$BOOT" : $"$BOOT_{i}", + Size = 2048, + Timestamp = decodedVd.CreationTime + }); + } for(var i = 0; i < pvdSectors.Count; i++) - _rootDirectoryCache.Add(i == 0 ? "$PVD" : $"$PVD{i}", new DecodedDirectoryEntry - { - Extents = new List<(uint extent, uint size)> - { - ((uint)i, 2048) - }, - Filename = i == 0 ? "$PVD" : $"PVD_{i}", - Size = 2048, - Timestamp = decodedVd.CreationTime - }); + { + _rootDirectoryCache.Add(i == 0 ? "$PVD" : $"$PVD{i}", + new DecodedDirectoryEntry + { + Extents = [((uint)i, 2048)], + Filename = i == 0 ? "$PVD" : $"PVD_{i}", + Size = 2048, + Timestamp = decodedVd.CreationTime + }); + } for(var i = 0; i < svdSectors.Count; i++) - _rootDirectoryCache.Add(i == 0 ? "$SVD" : $"$SVD_{i}", new DecodedDirectoryEntry - { - Extents = new List<(uint extent, uint size)> - { - ((uint)i, 2048) - }, - Filename = i == 0 ? "$SVD" : $"$SVD_{i}", - Size = 2048, - Timestamp = decodedVd.CreationTime - }); + { + _rootDirectoryCache.Add(i == 0 ? "$SVD" : $"$SVD_{i}", + new DecodedDirectoryEntry + { + Extents = [((uint)i, 2048)], + Filename = i == 0 ? "$SVD" : $"$SVD_{i}", + Size = 2048, + Timestamp = decodedVd.CreationTime + }); + } for(var i = 0; i < evdSectors.Count; i++) - _rootDirectoryCache.Add(i == 0 ? "$EVD" : $"$EVD_{i}", new DecodedDirectoryEntry - { - Extents = new List<(uint extent, uint size)> - { - ((uint)i, 2048) - }, - Filename = i == 0 ? "$EVD" : $"$EVD_{i}", - Size = 2048, - Timestamp = decodedVd.CreationTime - }); + { + _rootDirectoryCache.Add(i == 0 ? "$EVD" : $"$EVD_{i}", + new DecodedDirectoryEntry + { + Extents = [((uint)i, 2048)], + Filename = i == 0 ? "$EVD" : $"$EVD_{i}", + Size = 2048, + Timestamp = decodedVd.CreationTime + }); + } for(var i = 0; i < vpdSectors.Count; i++) - _rootDirectoryCache.Add(i == 0 ? "$VPD" : $"$VPD_{i}", new DecodedDirectoryEntry - { - Extents = new List<(uint extent, uint size)> - { - ((uint)i, 2048) - }, - Filename = i == 0 ? "$VPD" : $"$VPD_{i}", - Size = 2048, - Timestamp = decodedVd.CreationTime - }); + { + _rootDirectoryCache.Add(i == 0 ? "$VPD" : $"$VPD_{i}", + new DecodedDirectoryEntry + { + Extents = [((uint)i, 2048)], + Filename = i == 0 ? "$VPD" : $"$VPD_{i}", + Size = 2048, + Timestamp = decodedVd.CreationTime + }); + } if(segaCd != null) - _rootDirectoryCache.Add("$IP.BIN", new DecodedDirectoryEntry - { - Extents = new List<(uint extent, uint size)> - { - ((uint)partition.Start, (uint)Marshal.SizeOf()) - }, - Filename = "$IP.BIN", - Size = (uint)Marshal.SizeOf(), - Timestamp = decodedVd.CreationTime - }); + { + _rootDirectoryCache.Add("$IP.BIN", + new DecodedDirectoryEntry + { + Extents = [((uint)partition.Start, (uint)Marshal.SizeOf())], + Filename = "$IP.BIN", + Size = (uint)Marshal.SizeOf(), + Timestamp = decodedVd.CreationTime + }); + } if(saturn != null) - _rootDirectoryCache.Add("$IP.BIN", new DecodedDirectoryEntry - { - Extents = new List<(uint extent, uint size)> - { - ((uint)partition.Start, (uint)Marshal.SizeOf()) - }, - Filename = "$IP.BIN", - Size = (uint)Marshal.SizeOf(), - Timestamp = decodedVd.CreationTime - }); + { + _rootDirectoryCache.Add("$IP.BIN", + new DecodedDirectoryEntry + { + Extents = [((uint)partition.Start, (uint)Marshal.SizeOf())], + Filename = "$IP.BIN", + Size = (uint)Marshal.SizeOf(), + Timestamp = decodedVd.CreationTime + }); + } if(dreamcast != null) - _rootDirectoryCache.Add("$IP.BIN", new DecodedDirectoryEntry - { - Extents = new List<(uint extent, uint size)> - { - ((uint)partition.Start, (uint)Marshal.SizeOf()) - }, - Filename = "$IP.BIN", - Size = (uint)Marshal.SizeOf(), - Timestamp = decodedVd.CreationTime - }); + { + _rootDirectoryCache.Add("$IP.BIN", + new DecodedDirectoryEntry + { + Extents = + [ + ((uint)partition.Start, (uint)Marshal.SizeOf()) + ], + Filename = "$IP.BIN", + Size = (uint)Marshal.SizeOf(), + Timestamp = decodedVd.CreationTime + }); + } } - XmlFsType.Bootable |= bvd != null || segaCd != null || saturn != null || dreamcast != null; - XmlFsType.Clusters = decodedVd.Blocks; - XmlFsType.ClusterSize = decodedVd.BlockSize; + Metadata.Bootable |= bvd != null || segaCd != null || saturn != null || dreamcast != null; + Metadata.Clusters = decodedVd.Blocks; + Metadata.ClusterSize = decodedVd.BlockSize; _statfs = new FileSystemInfo { @@ -767,12 +732,14 @@ public sealed partial class ISO9660 _directoryCache = new Dictionary>(); if(_usePathTable) + { foreach(DecodedDirectoryEntry subDirectory in _cdi ? GetSubdirsFromCdiPathTable("") : _highSierra ? GetSubdirsFromHighSierraPathTable("") : GetSubdirsFromIsoPathTable("")) _rootDirectoryCache[subDirectory.Filename] = subDirectory; + } _mounted = true; @@ -782,8 +749,7 @@ public sealed partial class ISO9660 /// public ErrorNumber Unmount() { - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; _rootDirectoryCache = null; _directoryCache = null; @@ -797,11 +763,12 @@ public sealed partial class ISO9660 { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; stat = _statfs.ShallowCopy(); return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ISO9660/Xattr.cs b/Aaru.Filesystems/ISO9660/Xattr.cs index 218de21f3..8d98ef87e 100644 --- a/Aaru.Filesystems/ISO9660/Xattr.cs +++ b/Aaru.Filesystems/ISO9660/Xattr.cs @@ -27,70 +27,58 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // In the loving memory of Facunda "Tata" Suárez Domínguez, R.I.P. 2019/07/24 // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using Aaru.CommonTypes.Enums; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class ISO9660 { +#region IReadOnlyFilesystem Members + /// public ErrorNumber ListXAttr(string path, out List xattrs) { xattrs = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = GetFileEntry(path, out DecodedDirectoryEntry entry); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; - xattrs = new List(); + xattrs = []; - if(entry.XattrLength > 0) - xattrs.Add("org.iso.9660.ea"); + if(entry.XattrLength > 0) xattrs.Add("org.iso.9660.ea"); - if(entry.AssociatedFile != null) - xattrs.Add("org.iso.9660.AssociatedFile"); + if(entry.AssociatedFile != null) xattrs.Add("org.iso.9660.AssociatedFile"); - if(entry.AppleDosType != null) - xattrs.Add("com.apple.dos.type"); + if(entry.AppleDosType is not null) xattrs.Add("com.apple.dos.type"); - if(entry.AppleProDosType != null) - xattrs.Add("com.apple.prodos.type"); + if(entry.AppleProDosType is not null) xattrs.Add("com.apple.prodos.type"); - if(entry.ResourceFork != null) - xattrs.Add("com.apple.ResourceFork"); + if(entry.ResourceFork != null) xattrs.Add("com.apple.ResourceFork"); - if(entry.FinderInfo != null) - xattrs.Add("com.apple.FinderInfo"); + if(entry.FinderInfo != null) xattrs.Add("com.apple.FinderInfo"); - if(entry.AppleIcon != null) - xattrs.Add("com.apple.Macintosh.Icon"); + if(entry.AppleIcon != null) xattrs.Add("com.apple.Macintosh.Icon"); - if(entry.AmigaComment != null) - xattrs.Add("com.amiga.comments"); + if(entry.AmigaComment != null) xattrs.Add("com.amiga.comments"); - if(entry.Flags.HasFlag(FileFlags.Directory) || - entry.Extents == null || - entry.Extents.Count == 0) + if(entry.Flags.HasFlag(FileFlags.Directory) || entry.Extents == null || entry.Extents.Count == 0) return ErrorNumber.NoError; ErrorNumber errno = _image.ReadSectorLong(entry.Extents[0].extent * _blockSize / 2048, out byte[] sector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - if(sector[15] != 2) - return ErrorNumber.NoError; + if(sector[15] != 2) return ErrorNumber.NoError; xattrs.Add("org.iso.mode2.subheader"); xattrs.Add("org.iso.mode2.subheader.copy"); @@ -103,13 +91,11 @@ public sealed partial class ISO9660 { buf = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = GetFileEntry(path, out DecodedDirectoryEntry entry); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; switch(xattr) { @@ -121,74 +107,74 @@ public sealed partial class ISO9660 : ReadSingleExtent(entry.XattrLength * _blockSize, entry.Extents[0].extent, out buf); case "org.iso.9660.AssociatedFile": - if(entry.AssociatedFile is null) - return ErrorNumber.NoSuchExtendedAttribute; + if(entry.AssociatedFile is null) return ErrorNumber.NoSuchExtendedAttribute; - if(entry.AssociatedFile.Extents is null) - return ErrorNumber.InvalidArgument; + if(entry.AssociatedFile.Extents is null) return ErrorNumber.InvalidArgument; - if(entry.AssociatedFile.Size == 0) + if(entry.AssociatedFile.Size != 0) { - buf = Array.Empty(); - - return ErrorNumber.NoError; + return ReadWithExtents(0, + (long)entry.AssociatedFile.Size, + entry.AssociatedFile.Extents, + entry.AssociatedFile.XA?.signature == XA_MAGIC && + entry.AssociatedFile.XA?.attributes.HasFlag(XaAttributes.Interleaved) == + true, + entry.AssociatedFile.XA?.filenumber ?? 0, + out buf); } - return ReadWithExtents(0, (long)entry.AssociatedFile.Size, entry.AssociatedFile.Extents, - entry.AssociatedFile.XA?.signature == XA_MAGIC && - entry.AssociatedFile.XA?.attributes.HasFlag(XaAttributes.Interleaved) == true, - entry.AssociatedFile.XA?.filenumber ?? 0, out buf); + buf = []; + + return ErrorNumber.NoError; + case "com.apple.dos.type": - if(entry.AppleDosType is null) - return ErrorNumber.NoSuchExtendedAttribute; + if(entry.AppleDosType is null) return ErrorNumber.NoSuchExtendedAttribute; buf = new byte[1]; buf[0] = entry.AppleDosType.Value; return ErrorNumber.NoError; case "com.apple.prodos.type": - if(entry.AppleProDosType is null) - return ErrorNumber.NoSuchExtendedAttribute; + if(entry.AppleProDosType is null) return ErrorNumber.NoSuchExtendedAttribute; buf = BitConverter.GetBytes(entry.AppleProDosType.Value); return ErrorNumber.NoError; case "com.apple.ResourceFork": - if(entry.ResourceFork is null) - return ErrorNumber.NoSuchExtendedAttribute; + if(entry.ResourceFork is null) return ErrorNumber.NoSuchExtendedAttribute; - if(entry.ResourceFork.Extents is null) - return ErrorNumber.InvalidArgument; + if(entry.ResourceFork.Extents is null) return ErrorNumber.InvalidArgument; - if(entry.ResourceFork.Size == 0) + if(entry.ResourceFork.Size != 0) { - buf = Array.Empty(); - - return ErrorNumber.NoError; + return ReadWithExtents(0, + (long)entry.ResourceFork.Size, + entry.ResourceFork.Extents, + entry.ResourceFork.XA?.signature == XA_MAGIC && + entry.ResourceFork.XA?.attributes.HasFlag(XaAttributes.Interleaved) == true, + entry.ResourceFork.XA?.filenumber ?? 0, + out buf); } - return ReadWithExtents(0, (long)entry.ResourceFork.Size, entry.ResourceFork.Extents, - entry.ResourceFork.XA?.signature == XA_MAGIC && - entry.ResourceFork.XA?.attributes.HasFlag(XaAttributes.Interleaved) == true, - entry.ResourceFork.XA?.filenumber ?? 0, out buf); + buf = []; + + return ErrorNumber.NoError; + case "com.apple.FinderInfo": - if(entry.FinderInfo is null) - return ErrorNumber.NoSuchExtendedAttribute; + if(entry.FinderInfo is null) return ErrorNumber.NoSuchExtendedAttribute; buf = Marshal.StructureToByteArrayBigEndian(entry.FinderInfo.Value); return ErrorNumber.NoError; case "com.apple.Macintosh.Icon": - if(entry.AppleIcon is null) - return ErrorNumber.NoSuchExtendedAttribute; + if(entry.AppleIcon is null) return ErrorNumber.NoSuchExtendedAttribute; buf = new byte[entry.AppleIcon.Length]; Array.Copy(entry.AppleIcon, 0, buf, 0, entry.AppleIcon.Length); return ErrorNumber.NoError; case "com.amiga.comments": - if(entry.AmigaComment is null) - return ErrorNumber.NoSuchExtendedAttribute; + if(entry.AmigaComment is null) return ErrorNumber.NoSuchExtendedAttribute; buf = new byte[entry.AmigaComment.Length]; Array.Copy(entry.AmigaComment, 0, buf, 0, entry.AmigaComment.Length); @@ -202,7 +188,10 @@ public sealed partial class ISO9660 buf = ReadSubheaderWithExtents(entry.Extents, true); return ErrorNumber.NoError; - default: return ErrorNumber.NoSuchExtendedAttribute; + default: + return ErrorNumber.NoSuchExtendedAttribute; } } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/JFS.cs b/Aaru.Filesystems/JFS.cs deleted file mode 100644 index 5a2af388d..000000000 --- a/Aaru.Filesystems/JFS.cs +++ /dev/null @@ -1,299 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : JFS.cs -// Author(s) : Natalia Portillo -// -// Component : IBM JFS filesystem plugin -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the IBM JFS filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - - - -// ReSharper disable UnusedMember.Local - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of IBM's Journaled File System -public sealed class JFS : IFilesystem -{ - const uint JFS_BOOT_BLOCKS_SIZE = 0x8000; - const uint JFS_MAGIC = 0x3153464A; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "JFS Plugin"; - /// - public Guid Id => new("D3BE2A41-8F28-4055-94DC-BB6C72A0E9C4"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - uint bootSectors = JFS_BOOT_BLOCKS_SIZE / imagePlugin.Info.SectorSize; - - if(partition.Start + bootSectors >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start + bootSectors, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < 512) - return false; - - SuperBlock jfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - return jfsSb.s_magic == JFS_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - var sb = new StringBuilder(); - uint bootSectors = JFS_BOOT_BLOCKS_SIZE / imagePlugin.Info.SectorSize; - ErrorNumber errno = imagePlugin.ReadSector(partition.Start + bootSectors, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < 512) - return; - - SuperBlock jfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - sb.AppendLine("JFS filesystem"); - sb.AppendFormat("Version {0}", jfsSb.s_version).AppendLine(); - sb.AppendFormat("{0} blocks of {1} bytes", jfsSb.s_size, jfsSb.s_bsize).AppendLine(); - sb.AppendFormat("{0} blocks per allocation group", jfsSb.s_agsize).AppendLine(); - - if(jfsSb.s_flags.HasFlag(Flags.Unicode)) - sb.AppendLine("Volume uses Unicode for directory entries"); - - if(jfsSb.s_flags.HasFlag(Flags.RemountRO)) - sb.AppendLine("Volume remounts read-only on error"); - - if(jfsSb.s_flags.HasFlag(Flags.Continue)) - sb.AppendLine("Volume continues on error"); - - if(jfsSb.s_flags.HasFlag(Flags.Panic)) - sb.AppendLine("Volume panics on error"); - - if(jfsSb.s_flags.HasFlag(Flags.UserQuota)) - sb.AppendLine("Volume has user quotas enabled"); - - if(jfsSb.s_flags.HasFlag(Flags.GroupQuota)) - sb.AppendLine("Volume has group quotas enabled"); - - if(jfsSb.s_flags.HasFlag(Flags.NoJournal)) - sb.AppendLine("Volume is not using any journal"); - - if(jfsSb.s_flags.HasFlag(Flags.Discard)) - sb.AppendLine("Volume sends TRIM/UNMAP commands to underlying device"); - - if(jfsSb.s_flags.HasFlag(Flags.GroupCommit)) - sb.AppendLine("Volume commits in groups of 1"); - - if(jfsSb.s_flags.HasFlag(Flags.LazyCommit)) - sb.AppendLine("Volume commits lazy"); - - if(jfsSb.s_flags.HasFlag(Flags.Temporary)) - sb.AppendLine("Volume does not commit to log"); - - if(jfsSb.s_flags.HasFlag(Flags.InlineLog)) - sb.AppendLine("Volume has log withing itself"); - - if(jfsSb.s_flags.HasFlag(Flags.InlineMoving)) - sb.AppendLine("Volume has log withing itself and is moving it out"); - - if(jfsSb.s_flags.HasFlag(Flags.BadSAIT)) - sb.AppendLine("Volume has bad current secondary ait"); - - if(jfsSb.s_flags.HasFlag(Flags.Sparse)) - sb.AppendLine("Volume supports sparse files"); - - if(jfsSb.s_flags.HasFlag(Flags.DASDEnabled)) - sb.AppendLine("Volume has DASD limits enabled"); - - if(jfsSb.s_flags.HasFlag(Flags.DASDPrime)) - sb.AppendLine("Volume primes DASD on boot"); - - if(jfsSb.s_flags.HasFlag(Flags.SwapBytes)) - sb.AppendLine("Volume is in a big-endian system"); - - if(jfsSb.s_flags.HasFlag(Flags.DirIndex)) - sb.AppendLine("Volume has presistent indexes"); - - if(jfsSb.s_flags.HasFlag(Flags.Linux)) - sb.AppendLine("Volume supports Linux"); - - if(jfsSb.s_flags.HasFlag(Flags.DFS)) - sb.AppendLine("Volume supports DCE DFS LFS"); - - if(jfsSb.s_flags.HasFlag(Flags.OS2)) - sb.AppendLine("Volume supports OS/2, and is case insensitive"); - - if(jfsSb.s_flags.HasFlag(Flags.AIX)) - sb.AppendLine("Volume supports AIX"); - - if(jfsSb.s_state != 0) - sb.AppendLine("Volume is dirty"); - - sb.AppendFormat("Volume was last updated on {0}", - DateHandlers.UnixUnsignedToDateTime(jfsSb.s_time.tv_sec, jfsSb.s_time.tv_nsec)).AppendLine(); - - if(jfsSb.s_version == 1) - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(jfsSb.s_fpack, Encoding)).AppendLine(); - else - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(jfsSb.s_label, Encoding)).AppendLine(); - - sb.AppendFormat("Volume UUID: {0}", jfsSb.s_uuid).AppendLine(); - - XmlFsType = new FileSystemType - { - Type = "JFS filesystem", - Clusters = jfsSb.s_size, - ClusterSize = jfsSb.s_bsize, - Bootable = true, - VolumeName = StringHandlers.CToString(jfsSb.s_version == 1 ? jfsSb.s_fpack : jfsSb.s_label, Encoding), - VolumeSerial = $"{jfsSb.s_uuid}", - ModificationDate = DateHandlers.UnixUnsignedToDateTime(jfsSb.s_time.tv_sec, jfsSb.s_time.tv_nsec), - ModificationDateSpecified = true - }; - - if(jfsSb.s_state != 0) - XmlFsType.Dirty = true; - - information = sb.ToString(); - } - - [Flags, SuppressMessage("ReSharper", "InconsistentNaming")] - enum Flags : uint - { - Unicode = 0x00000001, - RemountRO = 0x00000002, - Continue = 0x00000004, - Panic = 0x00000008, - UserQuota = 0x00000010, - GroupQuota = 0x00000020, - NoJournal = 0x00000040, - Discard = 0x00000080, - GroupCommit = 0x00000100, - LazyCommit = 0x00000200, - Temporary = 0x00000400, - InlineLog = 0x00000800, - InlineMoving = 0x00001000, - BadSAIT = 0x00010000, - Sparse = 0x00020000, - DASDEnabled = 0x00040000, - DASDPrime = 0x00080000, - SwapBytes = 0x00100000, - DirIndex = 0x00200000, - Linux = 0x10000000, - DFS = 0x20000000, - OS2 = 0x40000000, - AIX = 0x80000000 - } - - [Flags] - enum State : uint - { - Clean = 0, - Mounted = 1, - Dirty = 2, - Logredo = 4, - Extendfs = 8 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Extent - { - /// Leftmost 24 bits are extent length, rest 8 bits are most significant for - public readonly uint len_addr; - public readonly uint addr2; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct TimeStruct - { - public readonly uint tv_sec; - public readonly uint tv_nsec; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SuperBlock - { - public readonly uint s_magic; - public readonly uint s_version; - public readonly ulong s_size; - public readonly uint s_bsize; - public readonly ushort s_l2bsize; - public readonly ushort s_l2bfactor; - public readonly uint s_pbsize; - public readonly ushort s_l1pbsize; - public readonly ushort pad; - public readonly uint s_agsize; - public readonly Flags s_flags; - public readonly State s_state; - public readonly uint s_compress; - public readonly Extent s_ait2; - public readonly Extent s_aim2; - public readonly uint s_logdev; - public readonly uint s_logserial; - public readonly Extent s_logpxd; - public readonly Extent s_fsckpxd; - public readonly TimeStruct s_time; - public readonly uint s_fsckloglen; - public readonly sbyte s_fscklog; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - public readonly byte[] s_fpack; - public readonly ulong s_xsize; - public readonly Extent s_xfsckpxd; - public readonly Extent s_xlogpxd; - public readonly Guid s_uuid; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] s_label; - public readonly Guid s_loguuid; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/JFS/Consts.cs b/Aaru.Filesystems/JFS/Consts.cs new file mode 100644 index 000000000..102b95b46 --- /dev/null +++ b/Aaru.Filesystems/JFS/Consts.cs @@ -0,0 +1,41 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : IBM JFS filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +namespace Aaru.Filesystems; + +/// +/// Implements detection of IBM's Journaled File System +public sealed partial class JFS +{ + const uint JFS_BOOT_BLOCKS_SIZE = 0x8000; + const uint JFS_MAGIC = 0x3153464A; + + const string FS_TYPE = "jfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/JFS/Enums.cs b/Aaru.Filesystems/JFS/Enums.cs new file mode 100644 index 000000000..022636c2a --- /dev/null +++ b/Aaru.Filesystems/JFS/Enums.cs @@ -0,0 +1,86 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : IBM JFS filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of IBM's Journaled File System +public sealed partial class JFS +{ +#region Nested type: Flags + + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + enum Flags : uint + { + Unicode = 0x00000001, + RemountRO = 0x00000002, + Continue = 0x00000004, + Panic = 0x00000008, + UserQuota = 0x00000010, + GroupQuota = 0x00000020, + NoJournal = 0x00000040, + Discard = 0x00000080, + GroupCommit = 0x00000100, + LazyCommit = 0x00000200, + Temporary = 0x00000400, + InlineLog = 0x00000800, + InlineMoving = 0x00001000, + BadSAIT = 0x00010000, + Sparse = 0x00020000, + DASDEnabled = 0x00040000, + DASDPrime = 0x00080000, + SwapBytes = 0x00100000, + DirIndex = 0x00200000, + Linux = 0x10000000, + DFS = 0x20000000, + OS2 = 0x40000000, + AIX = 0x80000000 + } + +#endregion + +#region Nested type: State + + [Flags] + enum State : uint + { + Clean = 0, + Mounted = 1, + Dirty = 2, + Logredo = 4, + Extendfs = 8 + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/JFS/Info.cs b/Aaru.Filesystems/JFS/Info.cs new file mode 100644 index 000000000..1796280f0 --- /dev/null +++ b/Aaru.Filesystems/JFS/Info.cs @@ -0,0 +1,164 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : IBM JFS filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of IBM's Journaled File System +public sealed partial class JFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + uint bootSectors = JFS_BOOT_BLOCKS_SIZE / imagePlugin.Info.SectorSize; + + if(partition.Start + bootSectors >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start + bootSectors, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < 512) return false; + + SuperBlock jfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + return jfsSb.s_magic == JFS_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + var sb = new StringBuilder(); + uint bootSectors = JFS_BOOT_BLOCKS_SIZE / imagePlugin.Info.SectorSize; + ErrorNumber errno = imagePlugin.ReadSector(partition.Start + bootSectors, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < 512) return; + + SuperBlock jfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + sb.AppendLine(Localization.JFS_filesystem); + sb.AppendFormat(Localization.Version_0, jfsSb.s_version).AppendLine(); + sb.AppendFormat(Localization._0_blocks_of_1_bytes, jfsSb.s_size, jfsSb.s_bsize).AppendLine(); + sb.AppendFormat(Localization._0_blocks_per_allocation_group, jfsSb.s_agsize).AppendLine(); + + if(jfsSb.s_flags.HasFlag(Flags.Unicode)) sb.AppendLine(Localization.Volume_uses_Unicode_for_directory_entries); + + if(jfsSb.s_flags.HasFlag(Flags.RemountRO)) sb.AppendLine(Localization.Volume_remounts_read_only_on_error); + + if(jfsSb.s_flags.HasFlag(Flags.Continue)) sb.AppendLine(Localization.Volume_continues_on_error); + + if(jfsSb.s_flags.HasFlag(Flags.Panic)) sb.AppendLine(Localization.Volume_panics_on_error); + + if(jfsSb.s_flags.HasFlag(Flags.UserQuota)) sb.AppendLine(Localization.Volume_has_user_quotas_enabled); + + if(jfsSb.s_flags.HasFlag(Flags.GroupQuota)) sb.AppendLine(Localization.Volume_has_group_quotas_enabled); + + if(jfsSb.s_flags.HasFlag(Flags.NoJournal)) sb.AppendLine(Localization.Volume_is_not_using_any_journal); + + if(jfsSb.s_flags.HasFlag(Flags.Discard)) + sb.AppendLine(Localization.Volume_sends_TRIM_UNMAP_commands_to_underlying_device); + + if(jfsSb.s_flags.HasFlag(Flags.GroupCommit)) sb.AppendLine(Localization.Volume_commits_in_groups_of_1); + + if(jfsSb.s_flags.HasFlag(Flags.LazyCommit)) sb.AppendLine(Localization.Volume_commits_lazy); + + if(jfsSb.s_flags.HasFlag(Flags.Temporary)) sb.AppendLine(Localization.Volume_does_not_commit_to_log); + + if(jfsSb.s_flags.HasFlag(Flags.InlineLog)) sb.AppendLine(Localization.Volume_has_log_within_itself); + + if(jfsSb.s_flags.HasFlag(Flags.InlineMoving)) + sb.AppendLine(Localization.Volume_has_log_within_itself_and_is_moving_it_out); + + if(jfsSb.s_flags.HasFlag(Flags.BadSAIT)) sb.AppendLine(Localization.Volume_has_bad_current_secondary_ait); + + if(jfsSb.s_flags.HasFlag(Flags.Sparse)) sb.AppendLine(Localization.Volume_supports_sparse_files); + + if(jfsSb.s_flags.HasFlag(Flags.DASDEnabled)) sb.AppendLine(Localization.Volume_has_DASD_limits_enabled); + + if(jfsSb.s_flags.HasFlag(Flags.DASDPrime)) sb.AppendLine(Localization.Volume_primes_DASD_on_boot); + + if(jfsSb.s_flags.HasFlag(Flags.SwapBytes)) sb.AppendLine(Localization.Volume_is_in_a_big_endian_system); + + if(jfsSb.s_flags.HasFlag(Flags.DirIndex)) sb.AppendLine(Localization.Volume_has_persistent_indexes); + + if(jfsSb.s_flags.HasFlag(Flags.Linux)) sb.AppendLine(Localization.Volume_supports_Linux); + + if(jfsSb.s_flags.HasFlag(Flags.DFS)) sb.AppendLine(Localization.Volume_supports_DCE_DFS_LFS); + + if(jfsSb.s_flags.HasFlag(Flags.OS2)) sb.AppendLine(Localization.Volume_supports_OS2_and_is_case_insensitive); + + if(jfsSb.s_flags.HasFlag(Flags.AIX)) sb.AppendLine(Localization.Volume_supports_AIX); + + if(jfsSb.s_state != 0) sb.AppendLine(Localization.Volume_is_dirty); + + sb.AppendFormat(Localization.Volume_was_last_updated_on_0_, + DateHandlers.UnixUnsignedToDateTime(jfsSb.s_time.tv_sec, jfsSb.s_time.tv_nsec)) + .AppendLine(); + + if(jfsSb.s_version == 1) + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(jfsSb.s_fpack, encoding)).AppendLine(); + else + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(jfsSb.s_label, encoding)).AppendLine(); + + sb.AppendFormat(Localization.Volume_UUID_0, jfsSb.s_uuid).AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + Clusters = jfsSb.s_size, + ClusterSize = jfsSb.s_bsize, + Bootable = true, + VolumeName = StringHandlers.CToString(jfsSb.s_version == 1 ? jfsSb.s_fpack : jfsSb.s_label, encoding), + VolumeSerial = $"{jfsSb.s_uuid}", + ModificationDate = DateHandlers.UnixUnsignedToDateTime(jfsSb.s_time.tv_sec, jfsSb.s_time.tv_nsec) + }; + + if(jfsSb.s_state != 0) metadata.Dirty = true; + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/JFS/JFS.cs b/Aaru.Filesystems/JFS/JFS.cs new file mode 100644 index 000000000..e0f889ee1 --- /dev/null +++ b/Aaru.Filesystems/JFS/JFS.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : JFS.cs +// Author(s) : Natalia Portillo +// +// Component : IBM JFS filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of IBM's Journaled File System +public sealed partial class JFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.JFS_Name; + + /// + public Guid Id => new("D3BE2A41-8F28-4055-94DC-BB6C72A0E9C4"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/JFS/Structs.cs b/Aaru.Filesystems/JFS/Structs.cs new file mode 100644 index 000000000..a22c0aa8c --- /dev/null +++ b/Aaru.Filesystems/JFS/Structs.cs @@ -0,0 +1,102 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : IBM JFS filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of IBM's Journaled File System +public sealed partial class JFS +{ +#region Nested type: Extent + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Extent + { + /// Leftmost 24 bits are extent length, rest 8 bits are most significant for + public readonly uint len_addr; + public readonly uint addr2; + } + +#endregion + +#region Nested type: SuperBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SuperBlock + { + public readonly uint s_magic; + public readonly uint s_version; + public readonly ulong s_size; + public readonly uint s_bsize; + public readonly ushort s_l2bsize; + public readonly ushort s_l2bfactor; + public readonly uint s_pbsize; + public readonly ushort s_l1pbsize; + public readonly ushort pad; + public readonly uint s_agsize; + public readonly Flags s_flags; + public readonly State s_state; + public readonly uint s_compress; + public readonly Extent s_ait2; + public readonly Extent s_aim2; + public readonly uint s_logdev; + public readonly uint s_logserial; + public readonly Extent s_logpxd; + public readonly Extent s_fsckpxd; + public readonly TimeStruct s_time; + public readonly uint s_fsckloglen; + public readonly sbyte s_fscklog; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public readonly byte[] s_fpack; + public readonly ulong s_xsize; + public readonly Extent s_xfsckpxd; + public readonly Extent s_xlogpxd; + public readonly Guid s_uuid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] s_label; + public readonly Guid s_loguuid; + } + +#endregion + +#region Nested type: TimeStruct + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct TimeStruct + { + public readonly uint tv_sec; + public readonly uint tv_nsec; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/LIF.cs b/Aaru.Filesystems/LIF.cs deleted file mode 100644 index 30c83f745..000000000 --- a/Aaru.Filesystems/LIF.cs +++ /dev/null @@ -1,146 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : LIF.cs -// Author(s) : Natalia Portillo -// -// Component : HP Logical Interchange Format plugin -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the HP Logical Interchange Format and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Information from http://www.hp9845.net/9845/projects/hpdir/#lif_filesystem -/// -/// Implements detection of the LIF filesystem -public sealed class LIF : IFilesystem -{ - const uint LIF_MAGIC = 0x8000; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "HP Logical Interchange Format Plugin"; - /// - public Guid Id => new("41535647-77A5-477B-9206-DA727ACDC704"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 256) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - SystemBlock lifSb = Marshal.ByteArrayToStructureBigEndian(sector); - AaruConsole.DebugWriteLine("LIF plugin", "magic 0x{0:X8} (expected 0x{1:X8})", lifSb.magic, LIF_MAGIC); - - return lifSb.magic == LIF_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - if(imagePlugin.Info.SectorSize < 256) - return; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - SystemBlock lifSb = Marshal.ByteArrayToStructureBigEndian(sector); - - if(lifSb.magic != LIF_MAGIC) - return; - - var sb = new StringBuilder(); - - sb.AppendLine("HP Logical Interchange Format"); - sb.AppendFormat("Directory starts at cluster {0}", lifSb.directoryStart).AppendLine(); - sb.AppendFormat("LIF identifier: {0}", lifSb.lifId).AppendLine(); - sb.AppendFormat("Directory size: {0} clusters", lifSb.directorySize).AppendLine(); - sb.AppendFormat("LIF version: {0}", lifSb.lifVersion).AppendLine(); - - // How is this related to volume size? I have only CDs to test and makes no sense there - sb.AppendFormat("{0} tracks", lifSb.tracks).AppendLine(); - sb.AppendFormat("{0} heads", lifSb.heads).AppendLine(); - sb.AppendFormat("{0} sectors", lifSb.sectors).AppendLine(); - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(lifSb.volumeLabel, Encoding)).AppendLine(); - sb.AppendFormat("Volume created on {0}", DateHandlers.LifToDateTime(lifSb.creationDate)).AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Type = "HP Logical Interchange Format", - ClusterSize = 256, - Clusters = partition.Size / 256, - CreationDate = DateHandlers.LifToDateTime(lifSb.creationDate), - CreationDateSpecified = true, - VolumeName = StringHandlers.CToString(lifSb.volumeLabel, Encoding) - }; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SystemBlock - { - public readonly ushort magic; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public readonly byte[] volumeLabel; - public readonly uint directoryStart; - public readonly ushort lifId; - public readonly ushort unused; - public readonly uint directorySize; - public readonly ushort lifVersion; - public readonly ushort unused2; - public readonly uint tracks; - public readonly uint heads; - public readonly uint sectors; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public readonly byte[] creationDate; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/LIF/Consts.cs b/Aaru.Filesystems/LIF/Consts.cs new file mode 100644 index 000000000..4f9d2ca67 --- /dev/null +++ b/Aaru.Filesystems/LIF/Consts.cs @@ -0,0 +1,39 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : HP Logical Interchange Format plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Information from http://www.hp9845.net/9845/projects/hpdir/#lif_filesystem +/// +/// Implements detection of the LIF filesystem +public sealed partial class LIF +{ + const uint LIF_MAGIC = 0x8000; + + const string FS_TYPE = "hplif"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/LIF/Info.cs b/Aaru.Filesystems/LIF/Info.cs new file mode 100644 index 000000000..c3bf64c9c --- /dev/null +++ b/Aaru.Filesystems/LIF/Info.cs @@ -0,0 +1,107 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : HP Logical Interchange Format plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from http://www.hp9845.net/9845/projects/hpdir/#lif_filesystem +/// +/// Implements detection of the LIF filesystem +public sealed partial class LIF +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 256) return false; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + SystemBlock lifSb = Marshal.ByteArrayToStructureBigEndian(sector); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.magic_0_expected_1, lifSb.magic, LIF_MAGIC); + + return lifSb.magic == LIF_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize < 256) return; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + SystemBlock lifSb = Marshal.ByteArrayToStructureBigEndian(sector); + + if(lifSb.magic != LIF_MAGIC) return; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.HP_Logical_Interchange_Format); + sb.AppendFormat(Localization.Directory_starts_at_cluster_0, lifSb.directoryStart).AppendLine(); + sb.AppendFormat(Localization.LIF_identifier_0, lifSb.lifId).AppendLine(); + sb.AppendFormat(Localization.Directory_size_0_clusters, lifSb.directorySize).AppendLine(); + sb.AppendFormat(Localization.LIF_version_0, lifSb.lifVersion).AppendLine(); + + // How is this related to volume size? I have only CDs to test and makes no sense there + sb.AppendFormat(Localization._0_tracks, lifSb.tracks).AppendLine(); + sb.AppendFormat(Localization._0_heads, lifSb.heads).AppendLine(); + sb.AppendFormat(Localization._0_sectors, lifSb.sectors).AppendLine(); + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(lifSb.volumeLabel, encoding)).AppendLine(); + sb.AppendFormat(Localization.Volume_created_on_0, DateHandlers.LifToDateTime(lifSb.creationDate)).AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = 256, + Clusters = partition.Size / 256, + CreationDate = DateHandlers.LifToDateTime(lifSb.creationDate), + VolumeName = StringHandlers.CToString(lifSb.volumeLabel, encoding) + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/LIF/LIF.cs b/Aaru.Filesystems/LIF/LIF.cs new file mode 100644 index 000000000..38ebbcd71 --- /dev/null +++ b/Aaru.Filesystems/LIF/LIF.cs @@ -0,0 +1,53 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : LIF.cs +// Author(s) : Natalia Portillo +// +// Component : HP Logical Interchange Format plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from http://www.hp9845.net/9845/projects/hpdir/#lif_filesystem +/// +/// Implements detection of the LIF filesystem +public sealed partial class LIF : IFilesystem +{ + const string MODULE_NAME = "LIF plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.LIF_Name; + + /// + public Guid Id => new("41535647-77A5-477B-9206-DA727ACDC704"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/LIF/Structs.cs b/Aaru.Filesystems/LIF/Structs.cs new file mode 100644 index 000000000..eca3b4083 --- /dev/null +++ b/Aaru.Filesystems/LIF/Structs.cs @@ -0,0 +1,60 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : HP Logical Interchange Format plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Information from http://www.hp9845.net/9845/projects/hpdir/#lif_filesystem +/// +/// Implements detection of the LIF filesystem +public sealed partial class LIF +{ +#region Nested type: SystemBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SystemBlock + { + public readonly ushort magic; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public readonly byte[] volumeLabel; + public readonly uint directoryStart; + public readonly ushort lifId; + public readonly ushort unused; + public readonly uint directorySize; + public readonly ushort lifVersion; + public readonly ushort unused2; + public readonly uint tracks; + public readonly uint heads; + public readonly uint sectors; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public readonly byte[] creationDate; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/LisaFS/Consts.cs b/Aaru.Filesystems/LisaFS/Consts.cs index 4b95af50f..aabace6d0 100644 --- a/Aaru.Filesystems/LisaFS/Consts.cs +++ b/Aaru.Filesystems/LisaFS/Consts.cs @@ -7,10 +7,6 @@ // // Component : Apple Lisa filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple Lisa filesystem constants. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,13 +23,13 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.LisaFS; - using System.Diagnostics.CodeAnalysis; +namespace Aaru.Filesystems; + [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed partial class LisaFS { @@ -75,6 +71,10 @@ public sealed partial class LisaFS /// Root directory ID const short DIRID_ROOT = 0; + const string FS_TYPE = "lisafs"; + +#region Nested type: FileType + enum FileType : byte { /// Undefined file type @@ -110,4 +110,6 @@ public sealed partial class LisaFS /// Erased? KilledObject = 15 } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/LisaFS/Dir.cs b/Aaru.Filesystems/LisaFS/Dir.cs index 7b803f1fa..7b9efb24e 100644 --- a/Aaru.Filesystems/LisaFS/Dir.cs +++ b/Aaru.Filesystems/LisaFS/Dir.cs @@ -27,21 +27,24 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.LisaFS; - using System; using System.Collections.Generic; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Decoders; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class LisaFS { +#region IReadOnlyFilesystem Members + /// public ErrorNumber ReadLink(string path, out string dest) { @@ -52,23 +55,21 @@ public sealed partial class LisaFS } /// - public ErrorNumber ReadDir(string path, out List contents) + public ErrorNumber OpenDir(string path, out IDirNode node) { - contents = null; + node = null; ErrorNumber error = LookupFileId(path, out short fileId, out bool isDir); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; - if(!isDir) - return ErrorNumber.NotDirectory; + if(!isDir) return ErrorNumber.NotDirectory; /*List catalog; error = ReadCatalog(fileId, out catalog); if(error != ErrorNumber.NoError) return error;*/ - ReadDir(fileId, out contents); + ReadDir(fileId, out List contents); // On debug add system files as readable files // Syntax similar to NTFS @@ -84,36 +85,73 @@ public sealed partial class LisaFS contents.Sort(); + node = new LisaDirNode + { + Path = path, + Contents = contents.ToArray(), + Position = 0 + }; + return ErrorNumber.NoError; } + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) + { + filename = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not LisaDirNode mynode) return ErrorNumber.InvalidArgument; + + if(mynode.Position < 0) return ErrorNumber.InvalidArgument; + + if(mynode.Position >= mynode.Contents.Length) return ErrorNumber.NoError; + + filename = mynode.Contents[mynode.Position++]; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not LisaDirNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Position = -1; + mynode.Contents = null; + + return ErrorNumber.NoError; + } + +#endregion + void ReadDir(short dirId, out List contents) => // Do same trick as Mac OS X, replace filesystem '/' with '-', // as '-' is the path separator in Lisa OS - contents = (from entry in _catalogCache where entry.parentID == dirId - select StringHandlers.CToString(entry.filename, Encoding).Replace('/', '-')).ToList(); + contents = (from entry in _catalogCache + where entry.parentID == dirId + select StringHandlers.CToString(entry.filename, _encoding).Replace('/', '-')).ToList(); /// Reads, interprets and caches the Catalog File ErrorNumber ReadCatalog() { ErrorNumber errno; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - _catalogCache = new List(); + _catalogCache = []; // Do differently for V1 and V2 if(_mddf.fsversion is LISA_V2 or LISA_V1) { ErrorNumber error = ReadFile((short)FILEID_CATALOG, out byte[] buf); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; var offset = 0; - List catalogV2 = new(); + List catalogV2 = []; // For each entry on the catalog while(offset + 54 < buf.Length) @@ -135,10 +173,7 @@ public sealed partial class LisaFS offset += 54; // Check that the entry is correct, not empty or garbage - if(entV2.filenameLen != 0 && - entV2.filenameLen <= E_NAME && - entV2.fileType != 0 && - entV2.fileID > 0) + if(entV2.filenameLen != 0 && entV2.filenameLen <= E_NAME && entV2.fileType != 0 && entV2.fileID > 0) catalogV2.Add(entV2); } @@ -147,8 +182,7 @@ public sealed partial class LisaFS { error = ReadExtentsFile(entV2.fileID, out ExtentFile ext); - if(error != ErrorNumber.NoError) - continue; + if(error != ErrorNumber.NoError) continue; var entV3 = new CatalogEntry { @@ -177,26 +211,21 @@ public sealed partial class LisaFS { errno = _device.ReadSectorTag(i, SectorTagType.AppleSectorTag, out byte[] tag); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; DecodeTag(tag, out LisaTag.PriamTag catTag); - if(catTag.FileId != FILEID_CATALOG || - catTag.RelPage != 0) - continue; + if(catTag.FileId != FILEID_CATALOG || catTag.RelPage != 0) continue; errno = _device.ReadSectors(i, 4, out firstCatalogBlock); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; break; } // Catalog not found - if(firstCatalogBlock == null) - return ErrorNumber.NoSuchFile; + if(firstCatalogBlock == null) return ErrorNumber.NoSuchFile; ulong prevCatalogPointer = BigEndianBitConverter.ToUInt32(firstCatalogBlock, 0x7F6); @@ -204,51 +233,46 @@ public sealed partial class LisaFS while(prevCatalogPointer != 0xFFFFFFFF) { errno = _device.ReadSectorTag(prevCatalogPointer + _mddf.mddf_block + _volumePrefix, - SectorTagType.AppleSectorTag, out byte[] tag); + SectorTagType.AppleSectorTag, + out byte[] tag); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; DecodeTag(tag, out LisaTag.PriamTag prevTag); - if(prevTag.FileId != FILEID_CATALOG) - return ErrorNumber.InvalidArgument; + if(prevTag.FileId != FILEID_CATALOG) return ErrorNumber.InvalidArgument; - errno = _device.ReadSectors(prevCatalogPointer + _mddf.mddf_block + _volumePrefix, 4, + errno = _device.ReadSectors(prevCatalogPointer + _mddf.mddf_block + _volumePrefix, + 4, out firstCatalogBlock); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; prevCatalogPointer = BigEndianBitConverter.ToUInt32(firstCatalogBlock, 0x7F6); } ulong nextCatalogPointer = BigEndianBitConverter.ToUInt32(firstCatalogBlock, 0x7FA); - List catalogBlocks = new() - { - firstCatalogBlock - }; + List catalogBlocks = [firstCatalogBlock]; // Traverse double-linked list to read full catalog while(nextCatalogPointer != 0xFFFFFFFF) { errno = _device.ReadSectorTag(nextCatalogPointer + _mddf.mddf_block + _volumePrefix, - SectorTagType.AppleSectorTag, out byte[] tag); + SectorTagType.AppleSectorTag, + out byte[] tag); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; DecodeTag(tag, out LisaTag.PriamTag nextTag); - if(nextTag.FileId != FILEID_CATALOG) - return ErrorNumber.InvalidArgument; + if(nextTag.FileId != FILEID_CATALOG) return ErrorNumber.InvalidArgument; - errno = _device.ReadSectors(nextCatalogPointer + _mddf.mddf_block + _volumePrefix, 4, + errno = _device.ReadSectors(nextCatalogPointer + _mddf.mddf_block + _volumePrefix, + 4, out byte[] nextCatalogBlock); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; nextCatalogPointer = BigEndianBitConverter.ToUInt32(nextCatalogBlock, 0x7FA); catalogBlocks.Add(nextCatalogBlock); @@ -263,6 +287,7 @@ public sealed partial class LisaFS while(offset + 64 <= buf.Length) // Catalog block header + { if(buf[offset + 0x24] == 0x08) offset += 78; @@ -275,8 +300,7 @@ public sealed partial class LisaFS break; // Normal entry - else if(buf[offset + 0x24] == 0x03 && - buf[offset] == 0x24) + else if(buf[offset + 0x24] == 0x03 && buf[offset] == 0x24) { var entry = new CatalogEntry { @@ -295,21 +319,22 @@ public sealed partial class LisaFS }; Array.Copy(buf, offset + 0x03, entry.filename, 0, E_NAME); - Array.Copy(buf, offset + 0x38, entry.tail, 0, 8); + Array.Copy(buf, offset + 0x38, entry.tail, 0, 8); if(ReadExtentsFile(entry.fileID, out _) == ErrorNumber.NoError) + { if(!_fileSizeCache.ContainsKey(entry.fileID)) { _catalogCache.Add(entry); _fileSizeCache.Add(entry.fileID, entry.length); } + } offset += 64; } // Subdirectory entry - else if(buf[offset + 0x24] == 0x01 && - buf[offset] == 0x24) + else if(buf[offset + 0x24] == 0x01 && buf[offset] == 0x24) { var entry = new CatalogEntry { @@ -338,6 +363,7 @@ public sealed partial class LisaFS } else break; + } } return ErrorNumber.NoError; @@ -347,8 +373,7 @@ public sealed partial class LisaFS { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; stat = new FileEntryInfo { diff --git a/Aaru.Filesystems/LisaFS/Extent.cs b/Aaru.Filesystems/LisaFS/Extent.cs index 265263a91..fbb8dfafc 100644 --- a/Aaru.Filesystems/LisaFS/Extent.cs +++ b/Aaru.Filesystems/LisaFS/Extent.cs @@ -7,10 +7,6 @@ // // Component : Apple Lisa filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle Apple Lisa filesystem extents. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,28 +23,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.LisaFS; - using System; using Aaru.CommonTypes.Enums; using Aaru.Console; using Aaru.Decoders; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class LisaFS { - /// - public ErrorNumber MapBlock(string path, long fileBlock, out long deviceBlock) - { - deviceBlock = 0; - - // TODO: Not really important. - return ErrorNumber.NotImplemented; - } - /// Searches the disk for an extents file (or gets it from cache) /// Error. /// File identifier. @@ -58,25 +45,20 @@ public sealed partial class LisaFS file = new ExtentFile(); ErrorNumber errno; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - if(fileId < 4 || - fileId == 4 && _mddf.fsversion != LISA_V2 && _mddf.fsversion != LISA_V1) + if(fileId < 4 || fileId == 4 && _mddf.fsversion != LISA_V2 && _mddf.fsversion != LISA_V1) return ErrorNumber.InvalidArgument; - if(_extentCache.TryGetValue(fileId, out file)) - return ErrorNumber.NoError; + if(_extentCache.TryGetValue(fileId, out file)) return ErrorNumber.NoError; // A file ID that cannot be stored in the S-Records File - if(fileId >= _srecords.Length) - return ErrorNumber.InvalidArgument; + if(fileId >= _srecords.Length) return ErrorNumber.InvalidArgument; ulong ptr = _srecords[fileId].extent_ptr; // An invalid pointer denotes file does not exist - if(ptr is 0xFFFFFFFF or 0x00000000) - return ErrorNumber.NoSuchFile; + if(ptr is 0xFFFFFFFF or 0x00000000) return ErrorNumber.NoSuchFile; // Pointers are relative to MDDF ptr += _mddf.mddf_block + _volumePrefix; @@ -95,13 +77,11 @@ public sealed partial class LisaFS { errno = _device.ReadSectorTag(i, SectorTagType.AppleSectorTag, out tag); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; DecodeTag(tag, out extTag); - if(extTag.FileId != fileId * -1) - continue; + if(extTag.FileId != fileId * -1) continue; ptr = i; found = true; @@ -109,32 +89,25 @@ public sealed partial class LisaFS break; } - if(!found) - return ErrorNumber.InvalidArgument; + if(!found) return ErrorNumber.InvalidArgument; } // Checks that the sector tag indicates its the Extents File we are searching for errno = _device.ReadSectorTag(ptr, SectorTagType.AppleSectorTag, out tag); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; DecodeTag(tag, out extTag); - if(extTag.FileId != (short)(-1 * fileId)) - return ErrorNumber.NoSuchFile; + if(extTag.FileId != (short)(-1 * fileId)) return ErrorNumber.NoSuchFile; - byte[] sector; - - errno = _mddf.fsversion == LISA_V1 ? _device.ReadSectors(ptr, 2, out sector) + errno = _mddf.fsversion == LISA_V1 + ? _device.ReadSectors(ptr, 2, out byte[] sector) : _device.ReadSector(ptr, out sector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - if(sector[0] >= 32 || - sector[0] == 0) - return ErrorNumber.InvalidArgument; + if(sector[0] >= 32 || sector[0] == 0) return ErrorNumber.InvalidArgument; file.filenameLen = sector[0]; file.filename = new byte[file.filenameLen]; @@ -195,8 +168,7 @@ public sealed partial class LisaFS for(var j = 0; j < 41; j++) { - if(BigEndianBitConverter.ToInt16(sector, extentsOffset + j * 6 + 4) == 0) - break; + if(BigEndianBitConverter.ToInt16(sector, extentsOffset + j * 6 + 4) == 0) break; extentsCount++; } @@ -204,91 +176,130 @@ public sealed partial class LisaFS file.extents = new Extent[extentsCount]; for(var j = 0; j < extentsCount; j++) + { file.extents[j] = new Extent { start = BigEndianBitConverter.ToInt32(sector, extentsOffset + j * 6), length = BigEndianBitConverter.ToInt16(sector, extentsOffset + j * 6 + 4) }; + } _extentCache.Add(fileId, file); - if(!_debug) - return ErrorNumber.NoError; + if(!_debug) return ErrorNumber.NoError; - if(_printedExtents.Contains(fileId)) - return ErrorNumber.NoError; + if(_printedExtents.Contains(fileId)) return ErrorNumber.NoError; - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].filenameLen = {1}", fileId, file.filenameLen); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].filenameLen = {1}", fileId, file.filenameLen); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].filename = {1}", fileId, - StringHandlers.CToString(file.filename, Encoding)); + AaruConsole.DebugWriteLine(MODULE_NAME, + "ExtentFile[{0}].filename = {1}", + fileId, + StringHandlers.CToString(file.filename, _encoding)); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown1 = 0x{1:X4}", fileId, file.unknown1); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].file_uid = 0x{1:X16}", fileId, file.file_uid); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown2 = 0x{1:X2}", fileId, file.unknown2); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].etype = 0x{1:X2}", fileId, file.etype); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].ftype = {1}", fileId, file.ftype); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown3 = 0x{1:X2}", fileId, file.unknown3); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].dtc = {1}", fileId, file.dtc); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].dta = {1}", fileId, file.dta); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].dtm = {1}", fileId, file.dtm); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].dtb = {1}", fileId, file.dtb); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].dts = {1}", fileId, file.dts); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].serial = {1}", fileId, file.serial); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown4 = 0x{1:X2}", fileId, file.unknown4); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].locked = {1}", fileId, file.locked > 0); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].protect = {1}", fileId, file.protect > 0); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].master = {1}", fileId, file.master > 0); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].scavenged = {1}", fileId, file.scavenged > 0); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].closed = {1}", fileId, file.closed > 0); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].open = {1}", fileId, file.open > 0); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].unknown1 = 0x{1:X4}", fileId, file.unknown1); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].file_uid = 0x{1:X16}", fileId, file.file_uid); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].unknown2 = 0x{1:X2}", fileId, file.unknown2); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].etype = 0x{1:X2}", fileId, file.etype); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].ftype = {1}", fileId, file.ftype); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].unknown3 = 0x{1:X2}", fileId, file.unknown3); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].dtc = {1}", fileId, file.dtc); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].dta = {1}", fileId, file.dta); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].dtm = {1}", fileId, file.dtm); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].dtb = {1}", fileId, file.dtb); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].dts = {1}", fileId, file.dts); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].serial = {1}", fileId, file.serial); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].unknown4 = 0x{1:X2}", fileId, file.unknown4); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].locked = {1}", fileId, file.locked > 0); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].protect = {1}", fileId, file.protect > 0); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].master = {1}", fileId, file.master > 0); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].scavenged = {1}", fileId, file.scavenged > 0); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].closed = {1}", fileId, file.closed > 0); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].open = {1}", fileId, file.open > 0); - AaruConsole.DebugWriteLine("LisaFS plugin", + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].unknown5 = 0x{1:X2}{2:X2}{3:X2}{4:X2}{5:X2}{6:X2}{7:X2}{8:X2}{9:X2}" + - "{10:X2}{11:X2}", fileId, file.unknown5[0], file.unknown5[1], file.unknown5[2], - file.unknown5[3], file.unknown5[4], file.unknown5[5], file.unknown5[6], - file.unknown5[7], file.unknown5[8], file.unknown5[9], file.unknown5[10]); + "{10:X2}{11:X2}", + fileId, + file.unknown5[0], + file.unknown5[1], + file.unknown5[2], + file.unknown5[3], + file.unknown5[4], + file.unknown5[5], + file.unknown5[6], + file.unknown5[7], + file.unknown5[8], + file.unknown5[9], + file.unknown5[10]); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].release = {1}", fileId, file.release); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].build = {1}", fileId, file.build); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].release = {1}", fileId, file.release); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].build = {1}", fileId, file.build); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].compatibility = {1}", fileId, file.compatibility); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].compatibility = {1}", fileId, file.compatibility); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].revision = {1}", fileId, file.revision); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown6 = 0x{1:X4}", fileId, file.unknown6); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].revision = {1}", fileId, file.revision); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].unknown6 = 0x{1:X4}", fileId, file.unknown6); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].password_valid = {1}", fileId, + AaruConsole.DebugWriteLine(MODULE_NAME, + "ExtentFile[{0}].password_valid = {1}", + fileId, file.password_valid > 0); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].password = {1}", fileId, - Encoding.GetString(file.password)); + AaruConsole.DebugWriteLine(MODULE_NAME, + "ExtentFile[{0}].password = {1}", + fileId, + _encoding.GetString(file.password)); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown7 = 0x{1:X2}{2:X2}{3:X2}", fileId, - file.unknown7[0], file.unknown7[1], file.unknown7[2]); + AaruConsole.DebugWriteLine(MODULE_NAME, + "ExtentFile[{0}].unknown7 = 0x{1:X2}{2:X2}{3:X2}", + fileId, + file.unknown7[0], + file.unknown7[1], + file.unknown7[2]); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].overhead = {1}", fileId, file.overhead); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].overhead = {1}", fileId, file.overhead); - AaruConsole.DebugWriteLine("LisaFS plugin", + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].unknown8 = 0x{1:X2}{2:X2}{3:X2}{4:X2}{5:X2}{6:X2}{7:X2}{8:X2}{9:X2}" + - "{10:X2}{11:X2}{12:X2}{13:X2}{14:X2}{15:X2}{16:X2}", fileId, file.unknown8[0], - file.unknown8[1], file.unknown8[2], file.unknown8[3], file.unknown8[4], - file.unknown8[5], file.unknown8[6], file.unknown8[7], file.unknown8[8], - file.unknown8[9], file.unknown8[10], file.unknown8[11], file.unknown8[12], - file.unknown8[13], file.unknown8[14], file.unknown8[15]); + "{10:X2}{11:X2}{12:X2}{13:X2}{14:X2}{15:X2}{16:X2}", + fileId, + file.unknown8[0], + file.unknown8[1], + file.unknown8[2], + file.unknown8[3], + file.unknown8[4], + file.unknown8[5], + file.unknown8[6], + file.unknown8[7], + file.unknown8[8], + file.unknown8[9], + file.unknown8[10], + file.unknown8[11], + file.unknown8[12], + file.unknown8[13], + file.unknown8[14], + file.unknown8[15]); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].length = {1}", fileId, file.length); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown9 = 0x{1:X8}", fileId, file.unknown9); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].length = {1}", fileId, file.length); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].unknown9 = 0x{1:X8}", fileId, file.unknown9); for(var ext = 0; ext < file.extents.Length; ext++) { - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].extents[{1}].start = {2}", fileId, ext, + AaruConsole.DebugWriteLine(MODULE_NAME, + "ExtentFile[{0}].extents[{1}].start = {2}", + fileId, + ext, file.extents[ext].start); - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].extents[{1}].length = {2}", fileId, ext, + AaruConsole.DebugWriteLine(MODULE_NAME, + "ExtentFile[{0}].extents[{1}].length = {2}", + fileId, + ext, file.extents[ext].length); } - AaruConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown10 = 0x{1:X4}", fileId, file.unknown10); + AaruConsole.DebugWriteLine(MODULE_NAME, "ExtentFile[{0}].unknown10 = 0x{1:X4}", fileId, file.unknown10); _printedExtents.Add(fileId); @@ -298,20 +309,20 @@ public sealed partial class LisaFS /// Reads all the S-Records and caches it ErrorNumber ReadSRecords() { - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; // Searches the S-Records place using MDDF pointers - ErrorNumber errno = _device.ReadSectors(_mddf.srec_ptr + _mddf.mddf_block + _volumePrefix, _mddf.srec_len, + ErrorNumber errno = _device.ReadSectors(_mddf.srec_ptr + _mddf.mddf_block + _volumePrefix, + _mddf.srec_len, out byte[] sectors); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; // Each entry takes 14 bytes _srecords = new SRecord[sectors.Length / 14]; for(var s = 0; s < _srecords.Length; s++) + { _srecords[s] = new SRecord { extent_ptr = BigEndianBitConverter.ToUInt32(sectors, 0x00 + 14 * s), @@ -319,6 +330,7 @@ public sealed partial class LisaFS filesize = BigEndianBitConverter.ToUInt32(sectors, 0x08 + 14 * s), flags = BigEndianBitConverter.ToUInt16(sectors, 0x0C + 14 * s) }; + } return ErrorNumber.NoError; } diff --git a/Aaru.Filesystems/LisaFS/File.cs b/Aaru.Filesystems/LisaFS/File.cs index da1498beb..9e968a8ad 100644 --- a/Aaru.Filesystems/LisaFS/File.cs +++ b/Aaru.Filesystems/LisaFS/File.cs @@ -7,10 +7,6 @@ // // Component : Apple Lisa filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle files. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,20 +23,23 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.LisaFS; - using System; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Decoders; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class LisaFS { +#region IReadOnlyFilesystem Members + /// public ErrorNumber GetAttributes(string path, out FileAttributes attributes) { @@ -48,11 +47,9 @@ public sealed partial class LisaFS ErrorNumber error = LookupFileId(path, out short fileId, out bool isDir); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; - if(!isDir) - return GetAttributes(fileId, out attributes); + if(!isDir) return GetAttributes(fileId, out attributes); attributes = FileAttributes.Directory; @@ -60,56 +57,85 @@ public sealed partial class LisaFS } /// - public ErrorNumber Read(string path, long offset, long size, ref byte[] buf) + public ErrorNumber OpenFile(string path, out IFileNode node) { - if(size == 0) + node = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + ErrorNumber error = LookupFileId(path, out short fileId, out bool isDir); + + if(error != ErrorNumber.NoError) return error; + + if(isDir) return ErrorNumber.IsDirectory; + + error = Stat(fileId, out FileEntryInfo stat); + + if(error != ErrorNumber.NoError) return error; + + node = new LisaFileNode { - buf = Array.Empty(); + Path = path, + Length = stat.Length, + Offset = 0, + FileId = fileId + }; - return ErrorNumber.NoError; - } + return ErrorNumber.NoError; + } - if(offset < 0) - return ErrorNumber.InvalidArgument; + /// + public ErrorNumber CloseFile(IFileNode node) + { + if(!_mounted) return ErrorNumber.AccessDenied; - ErrorNumber error = LookupFileId(path, out short fileId, out _); + return node is not LisaFileNode ? ErrorNumber.InvalidArgument : ErrorNumber.NoError; + } - if(error != ErrorNumber.NoError) - return error; + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; - byte[] tmp; + if(!_mounted) return ErrorNumber.AccessDenied; + + if(buffer is null || buffer.Length < length) return ErrorNumber.InvalidArgument; + + if(node is not LisaFileNode mynode) return ErrorNumber.InvalidArgument; + + read = length; + + if(length + mynode.Offset >= mynode.Length) read = mynode.Length - mynode.Offset; + + byte[] tmp; + ErrorNumber error; if(_debug) - switch(fileId) - { - case FILEID_BOOT_SIGNED: - case FILEID_LOADER_SIGNED: - case (short)FILEID_MDDF: - case (short)FILEID_BITMAP: - case (short)FILEID_SRECORD: - case (short)FILEID_CATALOG: - error = ReadSystemFile(fileId, out tmp); - - break; - default: - error = ReadFile(fileId, out tmp); - - break; - } + { + error = mynode.FileId switch + { + FILEID_BOOT_SIGNED + or FILEID_LOADER_SIGNED + or (short)FILEID_MDDF + or (short)FILEID_BITMAP + or (short)FILEID_SRECORD + or (short)FILEID_CATALOG => ReadSystemFile(mynode.FileId, out tmp), + _ => ReadFile(mynode.FileId, out tmp) + }; + } else - error = ReadFile(fileId, out tmp); + error = ReadFile(mynode.FileId, out tmp); if(error != ErrorNumber.NoError) + { + read = 0; + return error; + } - if(offset >= tmp.Length) - return ErrorNumber.EINVAL; + Array.Copy(tmp, mynode.Offset, buffer, 0, read); - if(size + offset >= tmp.Length) - size = tmp.Length - offset; - - buf = new byte[size]; - Array.Copy(tmp, offset, buf, 0, size); + mynode.Offset += read; return ErrorNumber.NoError; } @@ -120,23 +146,22 @@ public sealed partial class LisaFS stat = null; ErrorNumber error = LookupFileId(path, out short fileId, out bool isDir); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; return isDir ? StatDir(fileId, out stat) : Stat(fileId, out stat); } +#endregion + ErrorNumber GetAttributes(short fileId, out FileAttributes attributes) { attributes = new FileAttributes(); - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; if(fileId < 4) { - if(!_debug) - return ErrorNumber.NoSuchFile; + if(!_debug) return ErrorNumber.NoSuchFile; attributes = new FileAttributes(); attributes = FileAttributes.System; @@ -149,8 +174,7 @@ public sealed partial class LisaFS ErrorNumber error = ReadExtentsFile(fileId, out ExtentFile extFile); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; switch(extFile.ftype) { @@ -167,7 +191,8 @@ public sealed partial class LisaFS attributes |= FileAttributes.Pipe; break; - case FileType.Undefined: break; + case FileType.Undefined: + break; default: attributes |= FileAttributes.File; attributes |= FileAttributes.Extents; @@ -175,14 +200,11 @@ public sealed partial class LisaFS break; } - if(extFile.protect > 0) - attributes |= FileAttributes.Immutable; + if(extFile.protect > 0) attributes |= FileAttributes.Immutable; - if(extFile.locked > 0) - attributes |= FileAttributes.ReadOnly; + if(extFile.locked > 0) attributes |= FileAttributes.ReadOnly; - if(extFile.password_valid > 0) - attributes |= FileAttributes.Password; + if(extFile.password_valid > 0) attributes |= FileAttributes.Password; return ErrorNumber.NoError; } @@ -194,40 +216,36 @@ public sealed partial class LisaFS buf = null; ErrorNumber errno; - if(!_mounted || - !_debug) - return ErrorNumber.AccessDenied; + if(!_mounted || !_debug) return ErrorNumber.AccessDenied; if(fileId is > 4 or <= 0) - if(fileId != FILEID_BOOT_SIGNED && - fileId != FILEID_LOADER_SIGNED) + if(fileId != FILEID_BOOT_SIGNED && fileId != FILEID_LOADER_SIGNED) return ErrorNumber.InvalidArgument; - if(_systemFileCache.TryGetValue(fileId, out buf) && - !tags) - return ErrorNumber.NoError; + if(_systemFileCache.TryGetValue(fileId, out buf) && !tags) return ErrorNumber.NoError; var count = 0; if(fileId == FILEID_SRECORD) + { if(!tags) { errno = _device.ReadSectors(_mddf.mddf_block + _volumePrefix + _mddf.srec_ptr, _mddf.srec_len, out buf); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; _systemFileCache.Add(fileId, buf); return ErrorNumber.NoError; } - else - { - errno = _device.ReadSectorsTag(_mddf.mddf_block + _volumePrefix + _mddf.srec_ptr, _mddf.srec_len, - SectorTagType.AppleSectorTag, out buf); - return errno != ErrorNumber.NoError ? errno : ErrorNumber.NoError; - } + errno = _device.ReadSectorsTag(_mddf.mddf_block + _volumePrefix + _mddf.srec_ptr, + _mddf.srec_len, + SectorTagType.AppleSectorTag, + out buf); + + return errno != ErrorNumber.NoError ? errno : ErrorNumber.NoError; + } LisaTag.PriamTag sysTag; @@ -236,17 +254,14 @@ public sealed partial class LisaFS { errno = _device.ReadSectorTag(i, SectorTagType.AppleSectorTag, out byte[] tag); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; DecodeTag(tag, out sysTag); - if(sysTag.FileId == fileId) - count++; + if(sysTag.FileId == fileId) count++; } - if(count == 0) - return ErrorNumber.NoSuchFile; + if(count == 0) return ErrorNumber.NoSuchFile; buf = !tags ? new byte[count * _device.Info.SectorSize] : new byte[count * _devTagSize]; @@ -255,31 +270,25 @@ public sealed partial class LisaFS { errno = _device.ReadSectorTag(i, SectorTagType.AppleSectorTag, out byte[] tag); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; DecodeTag(tag, out sysTag); - if(sysTag.FileId != fileId) - continue; + if(sysTag.FileId != fileId) continue; - byte[] sector; - - errno = !tags ? _device.ReadSector(i, out sector) + errno = !tags + ? _device.ReadSector(i, out byte[] sector) : _device.ReadSectorTag(i, SectorTagType.AppleSectorTag, out sector); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; // Relative block for $Loader starts at $Boot block - if(sysTag.FileId == FILEID_LOADER_SIGNED) - sysTag.RelPage--; + if(sysTag.FileId == FILEID_LOADER_SIGNED) sysTag.RelPage--; Array.Copy(sector, 0, buf, sector.Length * sysTag.RelPage, sector.Length); } - if(!tags) - _systemFileCache.Add(fileId, buf); + if(!tags) _systemFileCache.Add(fileId, buf); return ErrorNumber.NoError; } @@ -288,80 +297,70 @@ public sealed partial class LisaFS { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber error; ExtentFile file; if(fileId <= 4) - if(!_debug || - fileId == 0) - return ErrorNumber.NoSuchFile; + { + if(!_debug || fileId == 0) return ErrorNumber.NoSuchFile; + + stat = new FileEntryInfo(); + + error = GetAttributes(fileId, out FileAttributes attrs); + + stat.Attributes = attrs; + + if(error != ErrorNumber.NoError) return error; + + if(fileId < 0 && fileId != FILEID_BOOT_SIGNED && fileId != FILEID_LOADER_SIGNED) + { + error = ReadExtentsFile((short)(fileId * -1), out file); + + if(error != ErrorNumber.NoError) return error; + + stat.CreationTime = DateHandlers.LisaToDateTime(file.dtc); + stat.AccessTime = DateHandlers.LisaToDateTime(file.dta); + stat.BackupTime = DateHandlers.LisaToDateTime(file.dtb); + stat.LastWriteTime = DateHandlers.LisaToDateTime(file.dtm); + + stat.Inode = (ulong)fileId; + stat.Links = 0; + stat.Length = _mddf.datasize; + stat.BlockSize = _mddf.datasize; + stat.Blocks = 1; + } else { - stat = new FileEntryInfo(); + error = ReadSystemFile(fileId, out byte[] buf); - error = GetAttributes(fileId, out FileAttributes attrs); + if(error != ErrorNumber.NoError) return error; - stat.Attributes = attrs; + stat.CreationTime = fileId != 4 ? _mddf.dtvc : _mddf.dtcc; - if(error != ErrorNumber.NoError) - return error; + stat.BackupTime = _mddf.dtvb; - if(fileId < 0 && - fileId != FILEID_BOOT_SIGNED && - fileId != FILEID_LOADER_SIGNED) - { - error = ReadExtentsFile((short)(fileId * -1), out file); - - if(error != ErrorNumber.NoError) - return error; - - stat.CreationTime = DateHandlers.LisaToDateTime(file.dtc); - stat.AccessTime = DateHandlers.LisaToDateTime(file.dta); - stat.BackupTime = DateHandlers.LisaToDateTime(file.dtb); - stat.LastWriteTime = DateHandlers.LisaToDateTime(file.dtm); - - stat.Inode = (ulong)fileId; - stat.Links = 0; - stat.Length = _mddf.datasize; - stat.BlockSize = _mddf.datasize; - stat.Blocks = 1; - } - else - { - error = ReadSystemFile(fileId, out byte[] buf); - - if(error != ErrorNumber.NoError) - return error; - - stat.CreationTime = fileId != 4 ? _mddf.dtvc : _mddf.dtcc; - - stat.BackupTime = _mddf.dtvb; - - stat.Inode = (ulong)fileId; - stat.Links = 0; - stat.Length = buf.Length; - stat.BlockSize = _mddf.datasize; - stat.Blocks = buf.Length / _mddf.datasize; - } - - return ErrorNumber.NoError; + stat.Inode = (ulong)fileId; + stat.Links = 0; + stat.Length = buf.Length; + stat.BlockSize = _mddf.datasize; + stat.Blocks = buf.Length / _mddf.datasize; } + return ErrorNumber.NoError; + } + stat = new FileEntryInfo(); error = GetAttributes(fileId, out FileAttributes fileAttributes); stat.Attributes = fileAttributes; - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; error = ReadExtentsFile(fileId, out file); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; stat.CreationTime = DateHandlers.LisaToDateTime(file.dtc); stat.AccessTime = DateHandlers.LisaToDateTime(file.dta); @@ -387,25 +386,19 @@ public sealed partial class LisaFS ErrorNumber ReadFile(short fileId, out byte[] buf, bool tags) { buf = null; - ErrorNumber errno; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; tags &= _debug; - if(fileId < 4 || - fileId == 4 && _mddf.fsversion != LISA_V2 && _mddf.fsversion != LISA_V1) + if(fileId < 4 || fileId == 4 && _mddf.fsversion != LISA_V2 && _mddf.fsversion != LISA_V1) return ErrorNumber.InvalidArgument; - if(!tags && - _fileCache.TryGetValue(fileId, out buf)) - return ErrorNumber.NoError; + if(!tags && _fileCache.TryGetValue(fileId, out buf)) return ErrorNumber.NoError; ErrorNumber error = ReadExtentsFile(fileId, out ExtentFile file); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; int sectorSize; @@ -420,16 +413,20 @@ public sealed partial class LisaFS for(var i = 0; i < file.extents.Length; i++) { - byte[] sector; + ErrorNumber errno = !tags + ? _device.ReadSectors((ulong)file.extents[i].start + + _mddf.mddf_block + + _volumePrefix, + (uint)file.extents[i].length, + out byte[] sector) + : _device.ReadSectorsTag((ulong)file.extents[i].start + + _mddf.mddf_block + + _volumePrefix, + (uint)file.extents[i].length, + SectorTagType.AppleSectorTag, + out sector); - errno = !tags ? _device.ReadSectors((ulong)file.extents[i].start + _mddf.mddf_block + _volumePrefix, - (uint)file.extents[i].length, out sector) - : _device.ReadSectorsTag((ulong)file.extents[i].start + _mddf.mddf_block + _volumePrefix, - (uint)file.extents[i].length, SectorTagType.AppleSectorTag, - out sector); - - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; Array.Copy(sector, 0, temp, offset, sector.Length); offset += sector.Length; @@ -439,7 +436,7 @@ public sealed partial class LisaFS { if(_fileSizeCache.TryGetValue(fileId, out int realSize)) if(realSize > temp.Length) - AaruConsole.ErrorWriteLine("File {0} gets truncated.", fileId); + AaruConsole.ErrorWriteLine(Localization.File_0_gets_truncated, fileId); buf = temp; @@ -456,27 +453,27 @@ public sealed partial class LisaFS fileId = 0; isDir = false; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length == 0) + switch(pathElements.Length) { - fileId = DIRID_ROOT; - isDir = true; + case 0: + fileId = DIRID_ROOT; + isDir = true; - return ErrorNumber.NoError; + return ErrorNumber.NoError; + + // Only V3 supports subdirectories + case > 1 when _mddf.fsversion != LISA_V3: + return ErrorNumber.NotSupported; } - // Only V3 supports subdirectories - if(pathElements.Length > 1 && - _mddf.fsversion != LISA_V3) - return ErrorNumber.NotSupported; - if(_debug && pathElements.Length == 1) { if(string.Compare(pathElements[0], "$MDDF", StringComparison.InvariantCulture) == 0) @@ -529,7 +526,7 @@ public sealed partial class LisaFS foreach(CatalogEntry entry in _catalogCache) { - string filename = StringHandlers.CToString(entry.filename, Encoding); + string filename = StringHandlers.CToString(entry.filename, _encoding); // LisaOS is case insensitive if(string.Compare(wantedFilename, filename, StringComparison.InvariantCultureIgnoreCase) != 0 || @@ -540,13 +537,10 @@ public sealed partial class LisaFS isDir = entry.fileType == 0x01; // Not last path element, and it's not a directory - if(lvl != pathElements.Length - 1 && - !isDir) - return ErrorNumber.NotDirectory; + if(lvl != pathElements.Length - 1 && !isDir) return ErrorNumber.NotDirectory; // Arrived last path element - if(lvl == pathElements.Length - 1) - return ErrorNumber.NoError; + if(lvl == pathElements.Length - 1) return ErrorNumber.NoError; } } diff --git a/Aaru.Filesystems/LisaFS/Info.cs b/Aaru.Filesystems/LisaFS/Info.cs index 50955a8eb..241cd0105 100644 --- a/Aaru.Filesystems/LisaFS/Info.cs +++ b/Aaru.Filesystems/LisaFS/Info.cs @@ -7,10 +7,6 @@ // // Component : Apple Lisa filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Apple Lisa filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,62 +23,55 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.LisaFS; - using System; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Decoders; using Aaru.Helpers; using Claunia.Encoding; -using Schemas; using Encoding = System.Text.Encoding; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class LisaFS { +#region IReadOnlyFilesystem Members + /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - ErrorNumber errno; - - if(imagePlugin.Info.ReadableSectorTags?.Contains(SectorTagType.AppleSectorTag) != true) - return false; + if(imagePlugin.Info.ReadableSectorTags?.Contains(SectorTagType.AppleSectorTag) != true) return false; // Minimal LisaOS disk is 3.5" single sided double density, 800 sectors - if(imagePlugin.Info.Sectors < 800) - return false; + if(imagePlugin.Info.Sectors < 800) return false; int beforeMddf = -1; // LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors for(var i = 0; i < 100; i++) { - errno = imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag, out byte[] tag); + ErrorNumber errno = imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag, out byte[] tag); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; DecodeTag(tag, out LisaTag.PriamTag searchTag); - AaruConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.FileId); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Sector_0_file_ID_1, i, searchTag.FileId); - if(beforeMddf == -1 && - searchTag.FileId == FILEID_LOADER_SIGNED) - beforeMddf = i - 1; + if(beforeMddf == -1 && searchTag.FileId == FILEID_LOADER_SIGNED) beforeMddf = i - 1; - if(searchTag.FileId != FILEID_MDDF) - continue; + if(searchTag.FileId != FILEID_MDDF) continue; errno = imagePlugin.ReadSector((ulong)i, out byte[] sector); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; var infoMddf = new MDDF { @@ -94,36 +83,31 @@ public sealed partial class LisaFS datasize = BigEndianBitConverter.ToUInt16(sector, 0x7E) }; - AaruConsole.DebugWriteLine("LisaFS plugin", "Current sector = {0}", i); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.mddf_block = {0}", infoMddf.mddf_block); - AaruConsole.DebugWriteLine("LisaFS plugin", "Disk size = {0} sectors", imagePlugin.Info.Sectors); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.vol_size = {0} sectors", infoMddf.vol_size); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.vol_size - 1 = {0}", infoMddf.volsize_minus_one); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Current_sector_0, i); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.mddf_block = {0}", infoMddf.mddf_block); + AaruConsole.DebugWriteLine(MODULE_NAME, "Disk size = {0} sectors", imagePlugin.Info.Sectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.vol_size = {0} sectors", infoMddf.vol_size); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.vol_size - 1 = {0}", infoMddf.volsize_minus_one); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.vol_size - mddf.mddf_block -1 = {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + "mddf.vol_size - mddf.mddf_block -1 = {0}", infoMddf.volsize_minus_mddf_minus_one); - AaruConsole.DebugWriteLine("LisaFS plugin", "Disk sector = {0} bytes", imagePlugin.Info.SectorSize); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.blocksize = {0} bytes", infoMddf.blocksize); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.datasize = {0} bytes", infoMddf.datasize); + AaruConsole.DebugWriteLine(MODULE_NAME, "Disk sector = {0} bytes", imagePlugin.Info.SectorSize); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.blocksize = {0} bytes", infoMddf.blocksize); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.datasize = {0} bytes", infoMddf.datasize); - if(infoMddf.mddf_block != i - beforeMddf) - return false; + if(infoMddf.mddf_block != i - beforeMddf) return false; - if(infoMddf.vol_size > imagePlugin.Info.Sectors) - return false; + if(infoMddf.vol_size > imagePlugin.Info.Sectors) return false; - if(infoMddf.vol_size - 1 != infoMddf.volsize_minus_one) - return false; + if(infoMddf.vol_size - 1 != infoMddf.volsize_minus_one) return false; - if(infoMddf.vol_size - i - 1 != infoMddf.volsize_minus_mddf_minus_one - beforeMddf) - return false; + if(infoMddf.vol_size - i - 1 != infoMddf.volsize_minus_mddf_minus_one - beforeMddf) return false; - if(infoMddf.datasize > infoMddf.blocksize) - return false; + if(infoMddf.datasize > infoMddf.blocksize) return false; - if(infoMddf.blocksize < imagePlugin.Info.SectorSize) - return false; + if(infoMddf.blocksize < imagePlugin.Info.SectorSize) return false; return infoMddf.datasize == imagePlugin.Info.SectorSize; } @@ -132,45 +116,39 @@ public sealed partial class LisaFS } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = new LisaRoman(); + encoding = new LisaRoman(); information = ""; - var sb = new StringBuilder(); - ErrorNumber errno; + metadata = new FileSystem(); + var sb = new StringBuilder(); - if(imagePlugin.Info.ReadableSectorTags?.Contains(SectorTagType.AppleSectorTag) != true) - return; + if(imagePlugin.Info.ReadableSectorTags?.Contains(SectorTagType.AppleSectorTag) != true) return; // Minimal LisaOS disk is 3.5" single sided double density, 800 sectors - if(imagePlugin.Info.Sectors < 800) - return; + if(imagePlugin.Info.Sectors < 800) return; int beforeMddf = -1; // LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors for(var i = 0; i < 100; i++) { - errno = imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag, out byte[] tag); + ErrorNumber errno = imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag, out byte[] tag); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; DecodeTag(tag, out LisaTag.PriamTag searchTag); - AaruConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.FileId); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Sector_0_file_ID_1, i, searchTag.FileId); - if(beforeMddf == -1 && - searchTag.FileId == FILEID_LOADER_SIGNED) - beforeMddf = i - 1; + if(beforeMddf == -1 && searchTag.FileId == FILEID_LOADER_SIGNED) beforeMddf = i - 1; - if(searchTag.FileId != FILEID_MDDF) - continue; + if(searchTag.FileId != FILEID_MDDF) continue; errno = imagePlugin.ReadSector((ulong)i, out byte[] sector); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; var infoMddf = new MDDF(); var pString = new byte[33]; @@ -179,12 +157,12 @@ public sealed partial class LisaFS infoMddf.volid = BigEndianBitConverter.ToUInt64(sector, 0x02); infoMddf.volnum = BigEndianBitConverter.ToUInt16(sector, 0x0A); Array.Copy(sector, 0x0C, pString, 0, 33); - infoMddf.volname = StringHandlers.PascalToString(pString, Encoding); + infoMddf.volname = StringHandlers.PascalToString(pString, encoding); infoMddf.unknown1 = sector[0x2D]; Array.Copy(sector, 0x2E, pString, 0, 33); // Prevent garbage - infoMddf.password = pString[0] <= 32 ? StringHandlers.PascalToString(pString, Encoding) : ""; + infoMddf.password = pString[0] <= 32 ? StringHandlers.PascalToString(pString, encoding) : ""; infoMddf.unknown2 = sector[0x4F]; infoMddf.machine_id = BigEndianBitConverter.ToUInt32(sector, 0x50); infoMddf.master_copy_id = BigEndianBitConverter.ToUInt32(sector, 0x54); @@ -255,68 +233,62 @@ public sealed partial class LisaFS infoMddf.vol_sequence = BigEndianBitConverter.ToUInt16(sector, 0x136); infoMddf.vol_left_mounted = sector[0x138]; - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown1 = 0x{0:X2} ({0})", infoMddf.unknown1); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown2 = 0x{0:X2} ({0})", infoMddf.unknown2); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown3 = 0x{0:X8} ({0})", infoMddf.unknown3); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown4 = 0x{0:X4} ({0})", infoMddf.unknown4); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown5 = 0x{0:X8} ({0})", infoMddf.unknown5); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown6 = 0x{0:X8} ({0})", infoMddf.unknown6); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown7 = 0x{0:X8} ({0})", infoMddf.unknown7); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown9 = 0x{0:X4} ({0})", infoMddf.unknown9); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown10 = 0x{0:X8} ({0})", infoMddf.unknown10); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown11 = 0x{0:X8} ({0})", infoMddf.unknown11); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown12 = 0x{0:X8} ({0})", infoMddf.unknown12); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown13 = 0x{0:X8} ({0})", infoMddf.unknown13); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown14 = 0x{0:X8} ({0})", infoMddf.unknown14); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown15 = 0x{0:X8} ({0})", infoMddf.unknown15); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown16 = 0x{0:X8} ({0})", infoMddf.unknown16); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown17 = 0x{0:X4} ({0})", infoMddf.unknown17); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown18 = 0x{0:X8} ({0})", infoMddf.unknown18); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown19 = 0x{0:X8} ({0})", infoMddf.unknown19); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown20 = 0x{0:X8} ({0})", infoMddf.unknown20); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown21 = 0x{0:X8} ({0})", infoMddf.unknown21); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown22 = 0x{0:X8} ({0})", infoMddf.unknown22); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown23 = 0x{0:X8} ({0})", infoMddf.unknown23); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown24 = 0x{0:X8} ({0})", infoMddf.unknown24); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown25 = 0x{0:X8} ({0})", infoMddf.unknown25); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown26 = 0x{0:X8} ({0})", infoMddf.unknown26); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown27 = 0x{0:X8} ({0})", infoMddf.unknown27); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown28 = 0x{0:X8} ({0})", infoMddf.unknown28); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown29 = 0x{0:X8} ({0})", infoMddf.unknown29); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown30 = 0x{0:X8} ({0})", infoMddf.unknown30); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown31 = 0x{0:X8} ({0})", infoMddf.unknown31); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown32 = 0x{0:X8} ({0})", infoMddf.unknown32); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown33 = 0x{0:X8} ({0})", infoMddf.unknown33); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown34 = 0x{0:X8} ({0})", infoMddf.unknown34); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown35 = 0x{0:X8} ({0})", infoMddf.unknown35); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown36 = 0x{0:X8} ({0})", infoMddf.unknown36); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown37 = 0x{0:X8} ({0})", infoMddf.unknown37); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown38 = 0x{0:X8} ({0})", infoMddf.unknown38); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown1 = 0x{0:X2} ({0})", infoMddf.unknown1); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown2 = 0x{0:X2} ({0})", infoMddf.unknown2); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown3 = 0x{0:X8} ({0})", infoMddf.unknown3); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown4 = 0x{0:X4} ({0})", infoMddf.unknown4); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown5 = 0x{0:X8} ({0})", infoMddf.unknown5); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown6 = 0x{0:X8} ({0})", infoMddf.unknown6); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown7 = 0x{0:X8} ({0})", infoMddf.unknown7); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown9 = 0x{0:X4} ({0})", infoMddf.unknown9); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown10 = 0x{0:X8} ({0})", infoMddf.unknown10); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown11 = 0x{0:X8} ({0})", infoMddf.unknown11); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown12 = 0x{0:X8} ({0})", infoMddf.unknown12); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown13 = 0x{0:X8} ({0})", infoMddf.unknown13); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown14 = 0x{0:X8} ({0})", infoMddf.unknown14); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown15 = 0x{0:X8} ({0})", infoMddf.unknown15); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown16 = 0x{0:X8} ({0})", infoMddf.unknown16); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown17 = 0x{0:X4} ({0})", infoMddf.unknown17); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown18 = 0x{0:X8} ({0})", infoMddf.unknown18); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown19 = 0x{0:X8} ({0})", infoMddf.unknown19); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown20 = 0x{0:X8} ({0})", infoMddf.unknown20); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown21 = 0x{0:X8} ({0})", infoMddf.unknown21); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown22 = 0x{0:X8} ({0})", infoMddf.unknown22); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown23 = 0x{0:X8} ({0})", infoMddf.unknown23); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown24 = 0x{0:X8} ({0})", infoMddf.unknown24); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown25 = 0x{0:X8} ({0})", infoMddf.unknown25); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown26 = 0x{0:X8} ({0})", infoMddf.unknown26); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown27 = 0x{0:X8} ({0})", infoMddf.unknown27); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown28 = 0x{0:X8} ({0})", infoMddf.unknown28); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown29 = 0x{0:X8} ({0})", infoMddf.unknown29); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown30 = 0x{0:X8} ({0})", infoMddf.unknown30); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown31 = 0x{0:X8} ({0})", infoMddf.unknown31); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown32 = 0x{0:X8} ({0})", infoMddf.unknown32); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown33 = 0x{0:X8} ({0})", infoMddf.unknown33); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown34 = 0x{0:X8} ({0})", infoMddf.unknown34); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown35 = 0x{0:X8} ({0})", infoMddf.unknown35); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown36 = 0x{0:X8} ({0})", infoMddf.unknown36); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown37 = 0x{0:X8} ({0})", infoMddf.unknown37); + AaruConsole.DebugWriteLine(MODULE_NAME, "mddf.unknown38 = 0x{0:X8} ({0})", infoMddf.unknown38); - AaruConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown_timestamp = 0x{0:X8} ({0}, {1})", + AaruConsole.DebugWriteLine(MODULE_NAME, + "mddf.unknown_timestamp = 0x{0:X8} ({0}, {1})", infoMddf.unknown_timestamp, DateHandlers.LisaToDateTime(infoMddf.unknown_timestamp)); - if(infoMddf.mddf_block != i - beforeMddf) - return; + if(infoMddf.mddf_block != i - beforeMddf) return; - if(infoMddf.vol_size > imagePlugin.Info.Sectors) - return; + if(infoMddf.vol_size > imagePlugin.Info.Sectors) return; - if(infoMddf.vol_size - 1 != infoMddf.volsize_minus_one) - return; + if(infoMddf.vol_size - 1 != infoMddf.volsize_minus_one) return; - if(infoMddf.vol_size - i - 1 != infoMddf.volsize_minus_mddf_minus_one - beforeMddf) - return; + if(infoMddf.vol_size - i - 1 != infoMddf.volsize_minus_mddf_minus_one - beforeMddf) return; - if(infoMddf.datasize > infoMddf.blocksize) - return; + if(infoMddf.datasize > infoMddf.blocksize) return; - if(infoMddf.blocksize < imagePlugin.Info.SectorSize) - return; + if(infoMddf.blocksize < imagePlugin.Info.SectorSize) return; - if(infoMddf.datasize != imagePlugin.Info.SectorSize) - return; + if(infoMddf.datasize != imagePlugin.Info.SectorSize) return; switch(infoMddf.fsversion) { @@ -333,85 +305,81 @@ public sealed partial class LisaFS break; default: - sb.AppendFormat("Unknown LisaFS version {0}", infoMddf.fsversion).AppendLine(); + sb.AppendFormat(Localization.Unknown_LisaFS_version_0, infoMddf.fsversion).AppendLine(); break; } - sb.AppendFormat("Volume name: \"{0}\"", infoMddf.volname).AppendLine(); - sb.AppendFormat("Volume password: \"{0}\"", infoMddf.password).AppendLine(); - sb.AppendFormat("Volume ID: 0x{0:X16}", infoMddf.volid).AppendLine(); - sb.AppendFormat("Backup volume ID: 0x{0:X16}", infoMddf.backup_volid).AppendLine(); + sb.AppendFormat(Localization.Volume_name_0, infoMddf.volname).AppendLine(); + sb.AppendFormat(Localization.Volume_password_0, infoMddf.password).AppendLine(); + sb.AppendFormat(Localization.Volume_ID_0_X16, infoMddf.volid).AppendLine(); + sb.AppendFormat(Localization.Backup_volume_ID_0, infoMddf.backup_volid).AppendLine(); - sb.AppendFormat("Master copy ID: 0x{0:X8}", infoMddf.master_copy_id).AppendLine(); + sb.AppendFormat(Localization.Master_copy_ID_0, infoMddf.master_copy_id).AppendLine(); - sb.AppendFormat("Volume is number {0} of {1}", infoMddf.volnum, infoMddf.vol_sequence).AppendLine(); + sb.AppendFormat(Localization.Volume_is_number_0_of_1, infoMddf.volnum, infoMddf.vol_sequence).AppendLine(); - sb.AppendFormat("Serial number of Lisa computer that created this volume: {0}", infoMddf.machine_id). - AppendLine(); + sb.AppendFormat(Localization.Serial_number_of_Lisa_computer_that_created_this_volume_0, infoMddf.machine_id) + .AppendLine(); - sb.AppendFormat("Serial number of Lisa computer that can use this volume's software {0}", - infoMddf.serialization).AppendLine(); + sb.AppendFormat(Localization.Serial_number_of_Lisa_computer_that_can_use_this_volume_software_0, + infoMddf.serialization) + .AppendLine(); - sb.AppendFormat("Volume created on {0}", infoMddf.dtvc).AppendLine(); - sb.AppendFormat("Some timestamp, says {0}", infoMddf.dtcc).AppendLine(); - sb.AppendFormat("Volume backed up on {0}", infoMddf.dtvb).AppendLine(); - sb.AppendFormat("Volume scavenged on {0}", infoMddf.dtvs).AppendLine(); - sb.AppendFormat("MDDF is in block {0}", infoMddf.mddf_block + beforeMddf).AppendLine(); - sb.AppendFormat("There are {0} reserved blocks before volume", beforeMddf).AppendLine(); - sb.AppendFormat("{0} blocks minus one", infoMddf.volsize_minus_one).AppendLine(); + sb.AppendFormat(Localization.Volume_created_on_0, infoMddf.dtvc).AppendLine(); + sb.AppendFormat(Localization.Volume_catalog_created_on_0, infoMddf.dtcc).AppendLine(); + sb.AppendFormat(Localization.Volume_backed_up_on_0, infoMddf.dtvb).AppendLine(); + sb.AppendFormat(Localization.Volume_scavenged_on_0, infoMddf.dtvs).AppendLine(); + sb.AppendFormat(Localization.MDDF_is_in_block_0, infoMddf.mddf_block + beforeMddf).AppendLine(); + sb.AppendFormat(Localization.There_are_0_reserved_blocks_before_volume, beforeMddf).AppendLine(); + sb.AppendFormat(Localization._0_blocks_minus_one, infoMddf.volsize_minus_one).AppendLine(); - sb.AppendFormat("{0} blocks minus one minus MDDF offset", infoMddf.volsize_minus_mddf_minus_one). - AppendLine(); + sb.AppendFormat(Localization._0_blocks_minus_one_minus_MDDF_offset, infoMddf.volsize_minus_mddf_minus_one) + .AppendLine(); - sb.AppendFormat("{0} blocks in volume", infoMddf.vol_size).AppendLine(); - sb.AppendFormat("{0} bytes per sector (uncooked)", infoMddf.blocksize).AppendLine(); - sb.AppendFormat("{0} bytes per sector", infoMddf.datasize).AppendLine(); - sb.AppendFormat("{0} blocks per cluster", infoMddf.clustersize).AppendLine(); - sb.AppendFormat("{0} blocks in filesystem", infoMddf.fs_size).AppendLine(); - sb.AppendFormat("{0} files in volume", infoMddf.filecount).AppendLine(); - sb.AppendFormat("{0} blocks free", infoMddf.freecount).AppendLine(); - sb.AppendFormat("{0} bytes in LisaInfo", infoMddf.label_size).AppendLine(); - sb.AppendFormat("Filesystem overhead: {0}", infoMddf.fs_overhead).AppendLine(); - sb.AppendFormat("Scavenger result code: 0x{0:X8}", infoMddf.result_scavenge).AppendLine(); - sb.AppendFormat("Boot code: 0x{0:X8}", infoMddf.boot_code).AppendLine(); - sb.AppendFormat("Boot environment: 0x{0:X8}", infoMddf.boot_environ).AppendLine(); - sb.AppendFormat("Overmount stamp: 0x{0:X16}", infoMddf.overmount_stamp).AppendLine(); + sb.AppendFormat(Localization._0_blocks_in_volume, infoMddf.vol_size).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector_uncooked, infoMddf.blocksize).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector, infoMddf.datasize).AppendLine(); + sb.AppendFormat(Localization._0_blocks_per_cluster, infoMddf.clustersize).AppendLine(); + sb.AppendFormat(Localization._0_blocks_in_filesystem, infoMddf.fs_size).AppendLine(); + sb.AppendFormat(Localization._0_files_in_volume, infoMddf.filecount).AppendLine(); + sb.AppendFormat(Localization._0_blocks_free, infoMddf.freecount).AppendLine(); + sb.AppendFormat(Localization._0_bytes_in_LisaInfo, infoMddf.label_size).AppendLine(); + sb.AppendFormat(Localization.Filesystem_overhead_0, infoMddf.fs_overhead).AppendLine(); + sb.AppendFormat(Localization.Scavenger_result_code_0, infoMddf.result_scavenge).AppendLine(); + sb.AppendFormat(Localization.Boot_code_0, infoMddf.boot_code).AppendLine(); + sb.AppendFormat(Localization.Boot_environment_0, infoMddf.boot_environ).AppendLine(); + sb.AppendFormat(Localization.Overmount_stamp_0, infoMddf.overmount_stamp).AppendLine(); - sb.AppendFormat("S-Records start at {0} and spans for {1} blocks", - infoMddf.srec_ptr + infoMddf.mddf_block + beforeMddf, infoMddf.srec_len).AppendLine(); + sb.AppendFormat(Localization.S_Records_start_at_0_and_spans_for_1_blocks, + infoMddf.srec_ptr + infoMddf.mddf_block + beforeMddf, + infoMddf.srec_len) + .AppendLine(); - sb.AppendLine(infoMddf.vol_left_mounted == 0 ? "Volume is clean" : "Volume is dirty"); + sb.AppendLine(infoMddf.vol_left_mounted == 0 ? Localization.Volume_is_clean : Localization.Volume_is_dirty); information = sb.ToString(); - XmlFsType = new FileSystemType(); + metadata = new FileSystem(); - if(DateTime.Compare(infoMddf.dtvb, DateHandlers.LisaToDateTime(0)) > 0) - { - XmlFsType.BackupDate = infoMddf.dtvb; - XmlFsType.BackupDateSpecified = true; - } + if(DateTime.Compare(infoMddf.dtvb, DateHandlers.LisaToDateTime(0)) > 0) metadata.BackupDate = infoMddf.dtvb; - XmlFsType.Clusters = infoMddf.vol_size; - XmlFsType.ClusterSize = (uint)(infoMddf.clustersize * infoMddf.datasize); + metadata.Clusters = infoMddf.vol_size; + metadata.ClusterSize = (uint)(infoMddf.clustersize * infoMddf.datasize); if(DateTime.Compare(infoMddf.dtvc, DateHandlers.LisaToDateTime(0)) > 0) - { - XmlFsType.CreationDate = infoMddf.dtvc; - XmlFsType.CreationDateSpecified = true; - } + metadata.CreationDate = infoMddf.dtvc; - XmlFsType.Dirty = infoMddf.vol_left_mounted != 0; - XmlFsType.Files = infoMddf.filecount; - XmlFsType.FilesSpecified = true; - XmlFsType.FreeClusters = infoMddf.freecount; - XmlFsType.FreeClustersSpecified = true; - XmlFsType.Type = "LisaFS"; - XmlFsType.VolumeName = infoMddf.volname; - XmlFsType.VolumeSerial = $"{infoMddf.volid:X16}"; + metadata.Dirty = infoMddf.vol_left_mounted != 0; + metadata.Files = infoMddf.filecount; + metadata.FreeClusters = infoMddf.freecount; + metadata.Type = FS_TYPE; + metadata.VolumeName = infoMddf.volname; + metadata.VolumeSerial = $"{infoMddf.volid:X16}"; return; } } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/LisaFS/LisaFS.cs b/Aaru.Filesystems/LisaFS/LisaFS.cs index ca3943089..03730dd69 100644 --- a/Aaru.Filesystems/LisaFS/LisaFS.cs +++ b/Aaru.Filesystems/LisaFS/LisaFS.cs @@ -7,10 +7,6 @@ // // Component : Apple Lisa filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Constructors and common variables for the Apple Lisa filesystem plugin. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,16 +23,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.LisaFS; - using System; using System.Collections.Generic; using System.Text; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Interfaces; -using Schemas; + +namespace Aaru.Filesystems; // All information by Natalia Portillo // Variable names from Lisa API @@ -44,24 +40,29 @@ using Schemas; /// Implements the Apple Lisa File System public sealed partial class LisaFS : IReadOnlyFilesystem { - bool _debug; - IMediaImage _device; - int _devTagSize; - MDDF _mddf; - bool _mounted; - SRecord[] _srecords; - ulong _volumePrefix; + const string MODULE_NAME = "LisaFS plugin"; + bool _debug; + IMediaImage _device; + int _devTagSize; + Encoding _encoding; + MDDF _mddf; + bool _mounted; + SRecord[] _srecords; + ulong _volumePrefix; + +#region IReadOnlyFilesystem Members /// public string Name => "Apple Lisa File System"; + + /// + public FileSystem Metadata { get; private set; } + /// public Guid Id => new("7E6034D1-D823-4248-A54D-239742B28391"); + /// - public Encoding Encoding { get; private set; } - /// - public FileSystemType XmlFsType { get; private set; } - /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; // TODO: Implement Lisa 7/7 namespace (needs decoding {!CATALOG} file) /// @@ -79,6 +80,8 @@ public sealed partial class LisaFS : IReadOnlyFilesystem } }; +#endregion + static Dictionary GetDefaultOptions() => new() { { @@ -86,7 +89,8 @@ public sealed partial class LisaFS : IReadOnlyFilesystem } }; - #region Caches +#region Caches + /// Caches Extents Files Dictionary _extentCache; /// Caches system files @@ -101,5 +105,6 @@ public sealed partial class LisaFS : IReadOnlyFilesystem List _printedExtents; /// Caches the creation times for subdirectories as to not have to traverse the Catalog File on each stat Dictionary _directoryDtcCache; - #endregion Caches + +#endregion Caches } \ No newline at end of file diff --git a/Aaru.Filesystems/LisaFS/Structs.cs b/Aaru.Filesystems/LisaFS/Structs.cs index e883f3079..cfb6adc96 100644 --- a/Aaru.Filesystems/LisaFS/Structs.cs +++ b/Aaru.Filesystems/LisaFS/Structs.cs @@ -7,10 +7,6 @@ // // Component : Apple Lisa filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Apple Lisa filesystem structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,20 +23,244 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable NotAccessedField.Local -namespace Aaru.Filesystems.LisaFS; - using System; using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; public sealed partial class LisaFS { +#region Nested type: CatalogEntry + + /// + /// An entry in the catalog from V3. The first entry is bigger than the rest, may be a header, I have not needed + /// any of its values so I just ignored it. Each catalog is divided in 4-sector blocks, and if it needs more than a + /// block there are previous and next block pointers, effectively making the V3 catalog a double-linked list. Garbage + /// is not zeroed. + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + struct CatalogEntry + { + /// 0x00, seems to be 0x24 when the entry is valid + public byte marker; + /// 0x01, parent directory ID for this file, 0 for root directory + public ushort parentID; + /// 0x03, filename, 32-bytes, null-padded + public byte[] filename; + /// 0x23, null-termination + public byte terminator; + /// + /// At 0x24 0x01 here for subdirectories, entries 48 bytes long 0x03 here for entries 64 bytes long 0x08 here for + /// entries 78 bytes long This is incomplete, may fail, mostly works... + /// + public byte fileType; + /// 0x25, lot of values found here, unknown + public byte unknown; + /// 0x26, file ID, must be positive and bigger than 4 + public short fileID; + /// 0x28, creation date + public uint dtc; + /// 0x2C, last modification date + public uint dtm; + /// 0x30, file length in bytes + public int length; + /// 0x34, file length in bytes, including wasted block space + public int wasted; + /// 0x38, unknown + public byte[] tail; + } + +#endregion + +#region Nested type: CatalogEntryV2 + + /// + /// The catalog entry for the V1 and V2 volume formats. It merely contains the file name, type and ID, plus a few + /// (mostly empty) unknown fields. Contrary to V3, it has no header and instead of being a double-linked list it is + /// fragmented using an Extents File. The Extents File position for the root catalog is then stored in the S-Records + /// File. Its entries are not filed sequentially denoting some kind of in-memory structure while at the same time + /// forcing LisaOS to read the whole catalog. That or I missed the pointers. Empty entries just contain a 0-len + /// filename. Garbage is not zeroed. + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + struct CatalogEntryV2 + { + /// 0x00, filename, 32-bytes, null-padded + public byte filenameLen; + /// 0x01, filename, 31-bytes + public byte[] filename; + /// 0x21, unknown + public byte unknown1; + /// 0x22, unknown + public byte fileType; + /// 0x23, unknown + public byte unknown2; + /// 0x24, unknown + public short fileID; + /// 0x26, 16 bytes, unknown + public byte[] unknown3; + } + +#endregion + +#region Nested type: Extent + + /// An extent indicating a start and a run of sectors. + [SuppressMessage("ReSharper", "InconsistentNaming")] + struct Extent + { + public int start; + public short length; + } + +#endregion + +#region Nested type: ExtentFile + + /// + /// The Extents File. There is one Extents File per each file stored on disk. The file ID present on the sectors + /// tags for the Extents File is the negated value of the file ID it represents. e.g. file = 5 (0x0005) extents = -5 + /// (0xFFFB) It spans a single sector on V2 and V3 but 2 sectors on V1. It contains all information about a file, and + /// is indexed in the S-Records file. It also contains the label. Garbage is zeroed. + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + struct ExtentFile + { + /// 0x00, filename length + public byte filenameLen; + /// 0x01, filename + public byte[] filename; + /// 0x20, unknown + public ushort unknown1; + /// 0x22, 8 bytes + public ulong file_uid; + /// 0x2A, unknown + public byte unknown2; + /// 0x2B, entry type? gets modified + public byte etype; + /// 0x2C, file type + public FileType ftype; + /// 0x2D, unknown + public byte unknown3; + /// 0x2E, creation time + public uint dtc; + /// 0x32, last access time + public uint dta; + /// 0x36, modification time + public uint dtm; + /// 0x3A, backup time + public uint dtb; + /// 0x3E, scavenge time + public uint dts; + /// 0x42, machine serial number + public uint serial; + /// 0x46, unknown + public byte unknown4; + /// 0x47, locked file + public byte locked; + /// 0x48, protected file + public byte protect; + /// 0x49, master file + public byte master; + /// 0x4A, scavenged file + public byte scavenged; + /// 0x4B, file closed by os + public byte closed; + /// 0x4C, file left open + public byte open; + /// 0x4D, 11 bytes, unknown + public byte[] unknown5; + /// 0x58, Release number + public ushort release; + /// 0x5A, Build number + public ushort build; + /// 0x5C, Compatibility level + public ushort compatibility; + /// 0x5E, Revision level + public ushort revision; + /// 0x60, unknown + public ushort unknown6; + /// 0x62, 0x08 set if password is valid + public byte password_valid; + /// 0x63, 8 bytes, scrambled password + public byte[] password; + /// 0x6B, 3 bytes, unknown + public byte[] unknown7; + /// 0x6E, filesystem overhead + public ushort overhead; + /// 0x70, 16 bytes, unknown + public byte[] unknown8; + /// 0x80, 0x200 in v1, file length in blocks + public int length; + /// 0x84, 0x204 in v1, unknown + public int unknown9; + /// + /// 0x88, 0x208 in v1, extents, can contain up to 41 extents (85 in v1), dunno LisaOS maximum (never seen more + /// than 3) + /// + public Extent[] extents; + /// 0x17E, unknown, empty, padding? + public short unknown10; + /// + /// At 0x180, this is the label. While 1982 pre-release documentation says the label can be up to 448 bytes, v1 + /// onward only have space for a 128 bytes one. Any application can write whatever they want in the label, however, + /// Lisa Office uses it to store its own information, something that will effectively overwrite any information a user + /// application wrote there. The information written here by Lisa Office is like the information Finder writes in the + /// FinderInfo structures, plus the non-unique name that is shown on the GUI. For this reason I called it LisaInfo. I + /// have not tried to reverse engineer it. + /// + public byte[] LisaInfo; + } + +#endregion + +#region Nested type: LisaDirNode + + sealed class LisaDirNode : IDirNode + { + internal string[] Contents; + internal int Position; + +#region IDirNode Members + + /// + public string Path { get; init; } + +#endregion + } + +#endregion + +#region Nested type: LisaFileNode + + sealed class LisaFileNode : IFileNode + { + internal short FileId; + +#region IFileNode Members + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + +#endregion + } + +#endregion + +#region Nested type: MDDF + /// /// The MDDF is the most import block on a Lisa FS volume. It describes the volume and its contents. On /// initialization the memory where it resides is not emptied so it tends to contain a lot of garbage. This has @@ -191,6 +411,7 @@ public sealed partial class LisaFS public ushort vol_sequence; /// 0x138, Volume is dirty? public byte vol_left_mounted; +#pragma warning disable CS0649 /// Is password present? (On-disk position unknown) public byte passwd_present; /// Opened files (memory-only?) (On-disk position unknown) @@ -211,148 +432,12 @@ public sealed partial class LisaFS public byte copy_flag; /// No idea (On-disk position unknown) public byte scavenge_flag; +#pragma warning restore CS0649 } - /// - /// An entry in the catalog from V3. The first entry is bigger than the rest, may be a header, I have not needed - /// any of its values so I just ignored it. Each catalog is divided in 4-sector blocks, and if it needs more than a - /// block there are previous and next block pointers, effectively making the V3 catalog a double-linked list. Garbage - /// is not zeroed. - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct CatalogEntry - { - /// 0x00, seems to be 0x24 when the entry is valid - public byte marker; - /// 0x01, parent directory ID for this file, 0 for root directory - public ushort parentID; - /// 0x03, filename, 32-bytes, null-padded - public byte[] filename; - /// 0x23, null-termination - public byte terminator; - /// - /// At 0x24 0x01 here for subdirectories, entries 48 bytes long 0x03 here for entries 64 bytes long 0x08 here for - /// entries 78 bytes long This is incomplete, may fail, mostly works... - /// - public byte fileType; - /// 0x25, lot of values found here, unknown - public byte unknown; - /// 0x26, file ID, must be positive and bigger than 4 - public short fileID; - /// 0x28, creation date - public uint dtc; - /// 0x2C, last modification date - public uint dtm; - /// 0x30, file length in bytes - public int length; - /// 0x34, file length in bytes, including wasted block space - public int wasted; - /// 0x38, unknown - public byte[] tail; - } +#endregion - /// An extent indicating a start and a run of sectors. - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct Extent - { - public int start; - public short length; - } - - /// - /// The Extents File. There is one Extents File per each file stored on disk. The file ID present on the sectors - /// tags for the Extents File is the negated value of the file ID it represents. e.g. file = 5 (0x0005) extents = -5 - /// (0xFFFB) It spans a single sector on V2 and V3 but 2 sectors on V1. It contains all information about a file, and - /// is indexed in the S-Records file. It also contains the label. Garbage is zeroed. - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct ExtentFile - { - /// 0x00, filename length - public byte filenameLen; - /// 0x01, filename - public byte[] filename; - /// 0x20, unknown - public ushort unknown1; - /// 0x22, 8 bytes - public ulong file_uid; - /// 0x2A, unknown - public byte unknown2; - /// 0x2B, entry type? gets modified - public byte etype; - /// 0x2C, file type - public FileType ftype; - /// 0x2D, unknown - public byte unknown3; - /// 0x2E, creation time - public uint dtc; - /// 0x32, last access time - public uint dta; - /// 0x36, modification time - public uint dtm; - /// 0x3A, backup time - public uint dtb; - /// 0x3E, scavenge time - public uint dts; - /// 0x42, machine serial number - public uint serial; - /// 0x46, unknown - public byte unknown4; - /// 0x47, locked file - public byte locked; - /// 0x48, protected file - public byte protect; - /// 0x49, master file - public byte master; - /// 0x4A, scavenged file - public byte scavenged; - /// 0x4B, file closed by os - public byte closed; - /// 0x4C, file left open - public byte open; - /// 0x4D, 11 bytes, unknown - public byte[] unknown5; - /// 0x58, Release number - public ushort release; - /// 0x5A, Build number - public ushort build; - /// 0x5C, Compatibility level - public ushort compatibility; - /// 0x5E, Revision level - public ushort revision; - /// 0x60, unknown - public ushort unknown6; - /// 0x62, 0x08 set if password is valid - public byte password_valid; - /// 0x63, 8 bytes, scrambled password - public byte[] password; - /// 0x6B, 3 bytes, unknown - public byte[] unknown7; - /// 0x6E, filesystem overhead - public ushort overhead; - /// 0x70, 16 bytes, unknown - public byte[] unknown8; - /// 0x80, 0x200 in v1, file length in blocks - public int length; - /// 0x84, 0x204 in v1, unknown - public int unknown9; - /// - /// 0x88, 0x208 in v1, extents, can contain up to 41 extents (85 in v1), dunno LisaOS maximum (never seen more - /// than 3) - /// - public Extent[] extents; - /// 0x17E, unknown, empty, padding? - public short unknown10; - /// - /// At 0x180, this is the label. While 1982 pre-release documentation says the label can be up to 448 bytes, v1 - /// onward only have space for a 128 bytes one. Any application can write whatever they want in the label, however, - /// Lisa Office uses it to store its own information, something that will effectively overwrite any information a user - /// application wrote there. The information written here by Lisa Office is like the information Finder writes in the - /// FinderInfo structures, plus the non-unique name that is shown on the GUI. For this reason I called it LisaInfo. I - /// have not tried to reverse engineer it. - /// - public byte[] LisaInfo; - } +#region Nested type: SRecord /// /// The S-Records File is a hashtable of S-Records, where the hash is the file ID they belong to. The S-Records @@ -375,30 +460,5 @@ public sealed partial class LisaFS public ushort flags; } - /// - /// The catalog entry for the V1 and V2 volume formats. It merely contains the file name, type and ID, plus a few - /// (mostly empty) unknown fields. Contrary to V3, it has no header and instead of being a double-linked list it is - /// fragmented using an Extents File. The Extents File position for the root catalog is then stored in the S-Records - /// File. Its entries are not filed sequentially denoting some kind of in-memory structure while at the same time - /// forcing LisaOS to read the whole catalog. That or I missed the pointers. Empty entries just contain a 0-len - /// filename. Garbage is not zeroed. - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct CatalogEntryV2 - { - /// 0x00, filename, 32-bytes, null-padded - public byte filenameLen; - /// 0x01, filename, 31-bytes - public byte[] filename; - /// 0x21, unknown - public byte unknown1; - /// 0x22, unknown - public byte fileType; - /// 0x23, unknown - public byte unknown2; - /// 0x24, unknown - public short fileID; - /// 0x26, 16 bytes, unknown - public byte[] unknown3; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/LisaFS/Super.cs b/Aaru.Filesystems/LisaFS/Super.cs index 6cb13263b..b27cd8cd0 100644 --- a/Aaru.Filesystems/LisaFS/Super.cs +++ b/Aaru.Filesystems/LisaFS/Super.cs @@ -7,10 +7,6 @@ // // Component : Apple Lisa filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Handles mounting and umounting the Apple Lisa filesystem. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,14 +23,12 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.LisaFS; - using System; using System.Collections.Generic; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; @@ -42,26 +36,30 @@ using Aaru.Console; using Aaru.Decoders; using Aaru.Helpers; using Claunia.Encoding; -using Schemas; using Encoding = System.Text.Encoding; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class LisaFS { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, - Dictionary options, string @namespace) + public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace) { try { - _device = imagePlugin; - Encoding = new LisaRoman(); + _device = imagePlugin; + _encoding = new LisaRoman(); // Lisa OS is unable to work on disks without tags. // This code is designed like that. // However with some effort the code may be modified to ignore them. if(_device.Info.ReadableSectorTags?.Contains(SectorTagType.AppleSectorTag) != true) { - AaruConsole.DebugWriteLine("LisaFS plugin", "Underlying device does not support Lisa tags"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Underlying_device_does_not_support_Lisa_tags); return ErrorNumber.InOutError; } @@ -69,7 +67,7 @@ public sealed partial class LisaFS // Minimal LisaOS disk is 3.5" single sided double density, 800 sectors if(_device.Info.Sectors < 800) { - AaruConsole.DebugWriteLine("LisaFS plugin", "Device is too small"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Device_is_too_small); return ErrorNumber.InOutError; } @@ -82,25 +80,21 @@ public sealed partial class LisaFS { ErrorNumber errno = _device.ReadSectorTag(i, SectorTagType.AppleSectorTag, out byte[] tag); - if(errno != ErrorNumber.NoError) - continue; + if(errno != ErrorNumber.NoError) continue; DecodeTag(tag, out LisaTag.PriamTag searchTag); - AaruConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.FileId); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Sector_0_file_ID_1, i, searchTag.FileId); - if(_volumePrefix == _device.Info.Sectors && - searchTag.FileId == FILEID_LOADER_SIGNED) + if(_volumePrefix == _device.Info.Sectors && searchTag.FileId == FILEID_LOADER_SIGNED) _volumePrefix = i - 1; - if(searchTag.FileId != FILEID_MDDF) - continue; + if(searchTag.FileId != FILEID_MDDF) continue; _devTagSize = tag.Length; errno = _device.ReadSector(i, out byte[] sector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; _mddf = new MDDF(); var pString = new byte[33]; @@ -109,12 +103,12 @@ public sealed partial class LisaFS _mddf.volid = BigEndianBitConverter.ToUInt64(sector, 0x02); _mddf.volnum = BigEndianBitConverter.ToUInt16(sector, 0x0A); Array.Copy(sector, 0x0C, pString, 0, 33); - _mddf.volname = StringHandlers.PascalToString(pString, Encoding); + _mddf.volname = StringHandlers.PascalToString(pString, _encoding); _mddf.unknown1 = sector[0x2D]; Array.Copy(sector, 0x2E, pString, 0, 33); // Prevent garbage - _mddf.password = pString[0] <= 32 ? StringHandlers.PascalToString(pString, Encoding) : ""; + _mddf.password = pString[0] <= 32 ? StringHandlers.PascalToString(pString, _encoding) : ""; _mddf.unknown2 = sector[0x4F]; _mddf.machine_id = BigEndianBitConverter.ToUInt32(sector, 0x50); _mddf.master_copy_id = BigEndianBitConverter.ToUInt32(sector, 0x54); @@ -194,7 +188,7 @@ public sealed partial class LisaFS _mddf.blocksize < _device.Info.SectorSize || _mddf.datasize != _device.Info.SectorSize) { - AaruConsole.DebugWriteLine("LisaFS plugin", "Incorrect MDDF found"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Incorrect_MDDF_found); return ErrorNumber.InvalidArgument; } @@ -203,19 +197,20 @@ public sealed partial class LisaFS switch(_mddf.fsversion) { case LISA_V1: - AaruConsole.DebugWriteLine("LisaFS plugin", "Mounting LisaFS v1"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Mounting_LisaFS_v1); break; case LISA_V2: - AaruConsole.DebugWriteLine("LisaFS plugin", "Mounting LisaFS v2"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Mounting_LisaFS_v2); break; case LISA_V3: - AaruConsole.DebugWriteLine("LisaFS plugin", "Mounting LisaFS v3"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Mounting_LisaFS_v3); break; default: - AaruConsole.ErrorWriteLine("Cannot mount LisaFS version {0}", _mddf.fsversion.ToString()); + AaruConsole.ErrorWriteLine(Localization.Cannot_mount_LisaFS_version_0, + _mddf.fsversion.ToString()); return ErrorNumber.NotSupported; } @@ -232,18 +227,16 @@ public sealed partial class LisaFS options ??= GetDefaultOptions(); - if(options.TryGetValue("debug", out string debugString)) - bool.TryParse(debugString, out _debug); + if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out _debug); - if(_debug) - _printedExtents = new List(); + if(_debug) _printedExtents = []; // Read the S-Records file ErrorNumber error = ReadSRecords(); if(error != ErrorNumber.NoError) { - AaruConsole.ErrorWriteLine("Error {0} reading S-Records file.", error); + AaruConsole.ErrorWriteLine(Localization.Error_0_reading_S_Records_file, error); return error; } @@ -260,7 +253,8 @@ public sealed partial class LisaFS if(error != ErrorNumber.NoError) { - AaruConsole.DebugWriteLine("LisaFS plugin", "Cannot read Catalog File, error {0}", + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Cannot_read_Catalog_File_error_0, error.ToString()); _mounted = false; @@ -275,7 +269,7 @@ public sealed partial class LisaFS if(error != ErrorNumber.NoError) { - AaruConsole.DebugWriteLine("LisaFS plugin", "Unable to read boot blocks"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Unable_to_read_boot_blocks); _mounted = false; return error; @@ -285,7 +279,7 @@ public sealed partial class LisaFS if(error != ErrorNumber.NoError) { - AaruConsole.DebugWriteLine("LisaFS plugin", "Unable to read boot loader"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Unable_to_read_boot_loader); _mounted = false; return error; @@ -295,7 +289,7 @@ public sealed partial class LisaFS if(error != ErrorNumber.NoError) { - AaruConsole.DebugWriteLine("LisaFS plugin", "Unable to read MDDF"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Unable_to_read_MDDF); _mounted = false; return error; @@ -305,7 +299,7 @@ public sealed partial class LisaFS if(error != ErrorNumber.NoError) { - AaruConsole.DebugWriteLine("LisaFS plugin", "Unable to read volume bitmap"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Unable_to_read_volume_bitmap); _mounted = false; return error; @@ -315,7 +309,7 @@ public sealed partial class LisaFS if(error != ErrorNumber.NoError) { - AaruConsole.DebugWriteLine("LisaFS plugin", "Unable to read S-Records file"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Unable_to_read_S_Records_file); _mounted = false; return error; @@ -323,42 +317,32 @@ public sealed partial class LisaFS } // Create XML metadata for mounted filesystem - XmlFsType = new FileSystemType(); + Metadata = new FileSystem(); - if(DateTime.Compare(_mddf.dtvb, DateHandlers.LisaToDateTime(0)) > 0) - { - XmlFsType.BackupDate = _mddf.dtvb; - XmlFsType.BackupDateSpecified = true; - } + if(DateTime.Compare(_mddf.dtvb, DateHandlers.LisaToDateTime(0)) > 0) Metadata.BackupDate = _mddf.dtvb; - XmlFsType.Clusters = _mddf.vol_size; - XmlFsType.ClusterSize = (uint)(_mddf.clustersize * _mddf.datasize); + Metadata.Clusters = _mddf.vol_size; + Metadata.ClusterSize = (uint)(_mddf.clustersize * _mddf.datasize); - if(DateTime.Compare(_mddf.dtvc, DateHandlers.LisaToDateTime(0)) > 0) - { - XmlFsType.CreationDate = _mddf.dtvc; - XmlFsType.CreationDateSpecified = true; - } + if(DateTime.Compare(_mddf.dtvc, DateHandlers.LisaToDateTime(0)) > 0) Metadata.CreationDate = _mddf.dtvc; - XmlFsType.Dirty = _mddf.vol_left_mounted != 0; - XmlFsType.Files = _mddf.filecount; - XmlFsType.FilesSpecified = true; - XmlFsType.FreeClusters = _mddf.freecount; - XmlFsType.FreeClustersSpecified = true; - XmlFsType.Type = "LisaFS"; - XmlFsType.VolumeName = _mddf.volname; - XmlFsType.VolumeSerial = $"{_mddf.volid:X16}"; + Metadata.Dirty = _mddf.vol_left_mounted != 0; + Metadata.Files = _mddf.filecount; + Metadata.FreeClusters = _mddf.freecount; + Metadata.Type = FS_TYPE; + Metadata.VolumeName = _mddf.volname; + Metadata.VolumeSerial = $"{_mddf.volid:X16}"; return ErrorNumber.NoError; } - AaruConsole.DebugWriteLine("LisaFS plugin", "Not a Lisa filesystem"); + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Not_a_Lisa_filesystem); return ErrorNumber.NotSupported; } catch(Exception ex) { - AaruConsole.ErrorWriteLine("Exception {0}, {1}, {2}", ex.Message, ex.InnerException, ex.StackTrace); + AaruConsole.WriteException(ex); return ErrorNumber.InOutError; } @@ -387,8 +371,7 @@ public sealed partial class LisaFS { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; stat = new FileSystemInfo { @@ -406,22 +389,16 @@ public sealed partial class LisaFS stat.FreeFiles = FILEID_MAX - stat.Files; - switch(_mddf.fsversion) - { - case LISA_V1: - stat.Type = "LisaFS v1"; - - break; - case LISA_V2: - stat.Type = "LisaFS v2"; - - break; - case LISA_V3: - stat.Type = "LisaFS v3"; - - break; - } + stat.Type = _mddf.fsversion switch + { + LISA_V1 => "LisaFS v1", + LISA_V2 => "LisaFS v2", + LISA_V3 => "LisaFS v3", + _ => stat.Type + }; return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/LisaFS/Xattr.cs b/Aaru.Filesystems/LisaFS/Xattr.cs index 7cd729e43..2c6e4118e 100644 --- a/Aaru.Filesystems/LisaFS/Xattr.cs +++ b/Aaru.Filesystems/LisaFS/Xattr.cs @@ -28,11 +28,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.LisaFS; - using System; using System.Collections.Generic; using System.Text; @@ -40,16 +38,19 @@ using Aaru.CommonTypes.Enums; using Aaru.Decoders; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class LisaFS { +#region IReadOnlyFilesystem Members + /// public ErrorNumber ListXAttr(string path, out List xattrs) { xattrs = null; ErrorNumber error = LookupFileId(path, out short fileId, out bool isDir); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; return isDir ? ErrorNumber.InvalidArgument : ListXAttr(fileId, out xattrs); } @@ -59,12 +60,13 @@ public sealed partial class LisaFS { ErrorNumber error = LookupFileId(path, out short fileId, out bool isDir); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; return isDir ? ErrorNumber.InvalidArgument : GetXattr(fileId, xattr, out buf); } +#endregion + /// Lists special Apple Lisa filesystem features as extended attributes /// Error number. /// File identifier. @@ -73,17 +75,14 @@ public sealed partial class LisaFS { xattrs = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; // System files if(fileId < 4) { - if(!_debug || - fileId == 0) - return ErrorNumber.InvalidArgument; + if(!_debug || fileId == 0) return ErrorNumber.InvalidArgument; - xattrs = new List(); + xattrs = []; // Only MDDF contains an extended attributes if(fileId == FILEID_MDDF) @@ -91,8 +90,7 @@ public sealed partial class LisaFS byte[] buf = Encoding.ASCII.GetBytes(_mddf.password); // If the MDDF contains a password, show it - if(buf.Length > 0) - xattrs.Add("com.apple.lisa.password"); + if(buf.Length > 0) xattrs.Add("com.apple.lisa.password"); } } else @@ -100,27 +98,22 @@ public sealed partial class LisaFS // Search for the file ErrorNumber error = ReadExtentsFile(fileId, out ExtentFile file); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; - xattrs = new List(); + xattrs = []; // Password field is never emptied, check if valid - if(file.password_valid > 0) - xattrs.Add("com.apple.lisa.password"); + if(file.password_valid > 0) xattrs.Add("com.apple.lisa.password"); // Check for a valid copy-protection serial number - if(file.serial > 0) - xattrs.Add("com.apple.lisa.serial"); + if(file.serial > 0) xattrs.Add("com.apple.lisa.serial"); // Check if the label contains something or is empty - if(!ArrayHelpers.ArrayIsNullOrEmpty(file.LisaInfo)) - xattrs.Add("com.apple.lisa.label"); + if(!ArrayHelpers.ArrayIsNullOrEmpty(file.LisaInfo)) xattrs.Add("com.apple.lisa.label"); } // On debug mode allow sector tags to be accessed as an xattr - if(_debug) - xattrs.Add("com.apple.lisa.tags"); + if(_debug) xattrs.Add("com.apple.lisa.tags"); xattrs.Sort(); @@ -136,28 +129,26 @@ public sealed partial class LisaFS { buf = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; // System files if(fileId < 4) { - if(!_debug || - fileId == 0) - return ErrorNumber.InvalidArgument; + if(!_debug || fileId == 0) return ErrorNumber.InvalidArgument; // Only MDDF contains an extended attributes if(fileId == FILEID_MDDF) + { if(xattr == "com.apple.lisa.password") { buf = Encoding.ASCII.GetBytes(_mddf.password); return ErrorNumber.NoError; } + } // But on debug mode even system files contain tags - if(_debug && xattr == "com.apple.lisa.tags") - return ReadSystemFile(fileId, out buf, true); + if(_debug && xattr == "com.apple.lisa.tags") return ReadSystemFile(fileId, out buf, true); return ErrorNumber.NoSuchExtendedAttribute; } @@ -165,8 +156,7 @@ public sealed partial class LisaFS // Search for the file ErrorNumber error = ReadExtentsFile(fileId, out ExtentFile file); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; switch(xattr) { @@ -181,8 +171,7 @@ public sealed partial class LisaFS return ErrorNumber.NoError; } - if(!ArrayHelpers.ArrayIsNullOrEmpty(file.LisaInfo) && - xattr == "com.apple.lisa.label") + if(!ArrayHelpers.ArrayIsNullOrEmpty(file.LisaInfo) && xattr == "com.apple.lisa.label") { buf = new byte[128]; Array.Copy(file.LisaInfo, 0, buf, 0, 128); @@ -190,8 +179,7 @@ public sealed partial class LisaFS return ErrorNumber.NoError; } - if(_debug && xattr == "com.apple.lisa.tags") - return ReadFile(fileId, out buf, true); + if(_debug && xattr == "com.apple.lisa.tags") return ReadFile(fileId, out buf, true); return ErrorNumber.NoSuchExtendedAttribute; } @@ -205,8 +193,7 @@ public sealed partial class LisaFS decoded = new LisaTag.PriamTag(); LisaTag.PriamTag? pmTag = LisaTag.DecodeTag(tag); - if(!pmTag.HasValue) - return ErrorNumber.InvalidArgument; + if(!pmTag.HasValue) return ErrorNumber.InvalidArgument; decoded = pmTag.Value; diff --git a/Aaru.Filesystems/Localization/Localization.Designer.cs b/Aaru.Filesystems/Localization/Localization.Designer.cs new file mode 100644 index 000000000..50998d04c --- /dev/null +++ b/Aaru.Filesystems/Localization/Localization.Designer.cs @@ -0,0 +1,11049 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Aaru.Filesystems { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Localization { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Localization() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aaru.Filesystems.Localization.Localization", typeof(Localization).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to {0}[{1}] = Unknown data type {2}. + /// + internal static string _0_1_equals_unknown_data_type_2 { + get { + return ResourceManager.GetString("_0_1_equals_unknown_data_type_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} allocation blocks.. + /// + internal static string _0_allocation_blocks { + get { + return ResourceManager.GetString("_0_allocation_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} allocation groups in volume. + /// + internal static string _0_allocation_groups_in_volume { + get { + return ResourceManager.GetString("_0_allocation_groups_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks ({1} bytes). + /// + internal static string _0_blocks_1_bytes { + get { + return ResourceManager.GetString("_0_blocks_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks ({1} bytes) free of {2} ({3} bytes). + /// + internal static string _0_blocks_1_bytes_free_of_2_3_bytes { + get { + return ResourceManager.GetString("_0_blocks_1_bytes_free_of_2_3_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks, {1} flags and {2} inodes per group. + /// + internal static string _0_blocks_1_flags_and_2_inodes_per_group { + get { + return ResourceManager.GetString("_0_blocks_1_flags_and_2_inodes_per_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks for bootloader ({1} bytes). + /// + internal static string _0_blocks_for_bootloader_1_bytes { + get { + return ResourceManager.GetString("_0_blocks_for_bootloader_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks free. + /// + internal static string _0_blocks_free { + get { + return ResourceManager.GetString("_0_blocks_free", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks free ({1} bytes). + /// + internal static string _0_blocks_free_1_bytes { + get { + return ResourceManager.GetString("_0_blocks_free_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks in cylinder 0. + /// + internal static string _0_blocks_in_cylinder_zero { + get { + return ResourceManager.GetString("_0_blocks_in_cylinder_zero", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks in filesystem. + /// + internal static string _0_blocks_in_filesystem { + get { + return ResourceManager.GetString("_0_blocks_in_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks in volume. + /// + internal static string _0_blocks_in_volume { + get { + return ResourceManager.GetString("_0_blocks_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks in volume ({1} bytes). + /// + internal static string _0_blocks_in_volume_1_bytes { + get { + return ResourceManager.GetString("_0_blocks_in_volume_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks in volume bitmap cache. + /// + internal static string _0_blocks_in_volume_bitmap_cache { + get { + return ResourceManager.GetString("_0_blocks_in_volume_bitmap_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks in volume cache. + /// + internal static string _0_blocks_in_volume_cache { + get { + return ResourceManager.GetString("_0_blocks_in_volume_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks in volume common cache. + /// + internal static string _0_blocks_in_volume_common_cache { + get { + return ResourceManager.GetString("_0_blocks_in_volume_common_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks minus one. + /// + internal static string _0_blocks_minus_one { + get { + return ResourceManager.GetString("_0_blocks_minus_one", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks minus one minus MDDF offset. + /// + internal static string _0_blocks_minus_one_minus_MDDF_offset { + get { + return ResourceManager.GetString("_0_blocks_minus_one_minus_MDDF_offset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks of {1} bytes. + /// + internal static string _0_blocks_of_1_bytes { + get { + return ResourceManager.GetString("_0_blocks_of_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks on all data disks. + /// + internal static string _0_blocks_on_all_data_disks { + get { + return ResourceManager.GetString("_0_blocks_on_all_data_disks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks on cluster summary array. + /// + internal static string _0_blocks_on_cluster_summary_array { + get { + return ResourceManager.GetString("_0_blocks_on_cluster_summary_array", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks on inode map ({1} bytes). + /// + internal static string _0_blocks_on_inode_map_1_bytes { + get { + return ResourceManager.GetString("_0_blocks_on_inode_map_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks on zone map ({1} bytes). + /// + internal static string _0_blocks_on_zone_map_1_bytes { + get { + return ResourceManager.GetString("_0_blocks_on_zone_map_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks pending of being freed. + /// + internal static string _0_blocks_pending_of_being_freed { + get { + return ResourceManager.GetString("_0_blocks_pending_of_being_freed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks per allocation group. + /// + internal static string _0_blocks_per_allocation_group { + get { + return ResourceManager.GetString("_0_blocks_per_allocation_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks per allocation group ({1} bytes). + /// + internal static string _0_blocks_per_allocation_group_1_bytes { + get { + return ResourceManager.GetString("_0_blocks_per_allocation_group_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks per cluster. + /// + internal static string _0_blocks_per_cluster { + get { + return ResourceManager.GetString("_0_blocks_per_cluster", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks per cylinder. + /// + internal static string _0_blocks_per_cylinder { + get { + return ResourceManager.GetString("_0_blocks_per_cylinder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks per cylinder ({1} bytes). + /// + internal static string _0_blocks_per_cylinder_1_bytes { + get { + return ResourceManager.GetString("_0_blocks_per_cylinder_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks per cylinder group at maximum. + /// + internal static string _0_blocks_per_cylinder_group_at_maximum { + get { + return ResourceManager.GetString("_0_blocks_per_cylinder_group_at_maximum", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks per gap ({1} bytes). + /// + internal static string _0_blocks_per_gap_1_bytes { + get { + return ResourceManager.GetString("_0_blocks_per_gap_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks per group. + /// + internal static string _0_blocks_per_group { + get { + return ResourceManager.GetString("_0_blocks_per_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks per rotation. + /// + internal static string _0_blocks_per_rotation { + get { + return ResourceManager.GetString("_0_blocks_per_rotation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} blocks per segment. + /// + internal static string _0_blocks_per_segment { + get { + return ResourceManager.GetString("_0_blocks_per_segment", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes/block. + /// + internal static string _0_bytes_block { + get { + return ResourceManager.GetString("_0_bytes_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes in a basic block. + /// + internal static string _0_bytes_in_a_basic_block { + get { + return ResourceManager.GetString("_0_bytes_in_a_basic_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes in a frag block. + /// + internal static string _0_bytes_in_a_frag_block { + get { + return ResourceManager.GetString("_0_bytes_in_a_frag_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes in allocation bitmap. + /// + internal static string _0_bytes_in_allocation_bitmap { + get { + return ResourceManager.GetString("_0_bytes_in_allocation_bitmap", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes in cylinder group. + /// + internal static string _0_bytes_in_cylinder_group { + get { + return ResourceManager.GetString("_0_bytes_in_cylinder_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes in cylinder group summary. + /// + internal static string _0_bytes_in_cylinder_group_summary { + get { + return ResourceManager.GetString("_0_bytes_in_cylinder_group_summary", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes in erase block. + /// + internal static string _0_bytes_in_erase_block { + get { + return ResourceManager.GetString("_0_bytes_in_erase_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes in LisaInfo. + /// + internal static string _0_bytes_in_LisaInfo { + get { + return ResourceManager.GetString("_0_bytes_in_LisaInfo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes in the Catalog B-Tree. + /// + internal static string _0_bytes_in_the_Catalog_B_Tree { + get { + return ResourceManager.GetString("_0_bytes_in_the_Catalog_B_Tree", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes in the Extents B-Tree. + /// + internal static string _0_bytes_in_the_Extents_B_Tree { + get { + return ResourceManager.GetString("_0_bytes_in_the_Extents_B_Tree", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes in volume. + /// + internal static string _0_bytes_in_volume { + get { + return ResourceManager.GetString("_0_bytes_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes/leaf. + /// + internal static string _0_bytes_leaf { + get { + return ResourceManager.GetString("_0_bytes_leaf", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes maximum per file. + /// + internal static string _0_bytes_maximum_per_file { + get { + return ResourceManager.GetString("_0_bytes_maximum_per_file", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes/node. + /// + internal static string _0_bytes_node { + get { + return ResourceManager.GetString("_0_bytes_node", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes on bitmap. + /// + internal static string _0_bytes_on_bitmap { + get { + return ResourceManager.GetString("_0_bytes_on_bitmap", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per allocation block.. + /// + internal static string _0_bytes_per_allocation_block { + get { + return ResourceManager.GetString("_0_bytes_per_allocation_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per block. + /// + internal static string _0_bytes_per_block { + get { + return ResourceManager.GetString("_0_bytes_per_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per directory entry. + /// + internal static string _0_bytes_per_directory_entry { + get { + return ResourceManager.GetString("_0_bytes_per_directory_entry", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per fragment. + /// + internal static string _0_bytes_per_fragment { + get { + return ResourceManager.GetString("_0_bytes_per_fragment", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per i-node. + /// + internal static string _0_bytes_per_i_node { + get { + return ResourceManager.GetString("_0_bytes_per_i_node", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per Index block. + /// + internal static string _0_bytes_per_Index_block { + get { + return ResourceManager.GetString("_0_bytes_per_Index_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per inode. + /// + internal static string _0_bytes_per_inode { + get { + return ResourceManager.GetString("_0_bytes_per_inode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per MFT record. + /// + internal static string _0_bytes_per_MFT_record { + get { + return ResourceManager.GetString("_0_bytes_per_MFT_record", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per page. + /// + internal static string _0_bytes_per_page { + get { + return ResourceManager.GetString("_0_bytes_per_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per sector.. + /// + internal static string _0_bytes_per_sector { + get { + return ResourceManager.GetString("_0_bytes_per_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per sector (uncooked). + /// + internal static string _0_bytes_per_sector_uncooked { + get { + return ResourceManager.GetString("_0_bytes_per_sector_uncooked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes per zone. + /// + internal static string _0_bytes_per_zone { + get { + return ResourceManager.GetString("_0_bytes_per_zone", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes/sector. + /// + internal static string _0_bytes_sector { + get { + return ResourceManager.GetString("_0_bytes_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes/stripe. + /// + internal static string _0_bytes_stripe { + get { + return ResourceManager.GetString("_0_bytes_stripe", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes to allocate.. + /// + internal static string _0_bytes_to_allocate { + get { + return ResourceManager.GetString("_0_bytes_to_allocate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes to allocate when extending a Catalog B-Tree.. + /// + internal static string _0_bytes_to_allocate_when_extending_a_Catalog_B_Tree { + get { + return ResourceManager.GetString("_0_bytes_to_allocate_when_extending_a_Catalog_B_Tree", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes to allocate when extending a Extents B-Tree.. + /// + internal static string _0_bytes_to_allocate_when_extending_a_Extents_B_Tree { + get { + return ResourceManager.GetString("_0_bytes_to_allocate_when_extending_a_Extents_B_Tree", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} bytes to allocate when extending a file.. + /// + internal static string _0_bytes_to_allocate_when_extending_a_file { + get { + return ResourceManager.GetString("_0_bytes_to_allocate_when_extending_a_file", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} chars in filename. + /// + internal static string _0_chars_in_filename { + get { + return ResourceManager.GetString("_0_chars_in_filename", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} clusters on volume.. + /// + internal static string _0_clusters_on_volume { + get { + return ResourceManager.GetString("_0_clusters_on_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} clusters per Index block ({1} bytes). + /// + internal static string _0_clusters_per_Index_block_1_bytes { + get { + return ResourceManager.GetString("_0_clusters_per_Index_block_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} clusters per MFT record ({1} bytes). + /// + internal static string _0_clusters_per_MFT_record_1_bytes { + get { + return ResourceManager.GetString("_0_clusters_per_MFT_record_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} codepages used in the volume. + /// + internal static string _0_codepages_used_in_the_volume { + get { + return ResourceManager.GetString("_0_codepages_used_in_the_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} contiguous blocks at maximum. + /// + internal static string _0_contiguous_blocks_at_maximum { + get { + return ResourceManager.GetString("_0_contiguous_blocks_at_maximum", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} contiguously allocated directories. + /// + internal static string _0_contiguously_allocated_directories { + get { + return ResourceManager.GetString("_0_contiguously_allocated_directories", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} cylinder groups. + /// + internal static string _0_cylinder_groups { + get { + return ResourceManager.GetString("_0_cylinder_groups", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} cylinder groups in volume. + /// + internal static string _0_cylinder_groups_in_volume { + get { + return ResourceManager.GetString("_0_cylinder_groups_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} cylinders. + /// + internal static string _0_cylinders { + get { + return ResourceManager.GetString("_0_cylinders", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} cylinders/group. + /// + internal static string _0_cylinders_group { + get { + return ResourceManager.GetString("_0_cylinders_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} cylinders in volume. + /// + internal static string _0_cylinders_in_volume { + get { + return ResourceManager.GetString("_0_cylinders_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} data blocks ({1} bytes). + /// + internal static string _0_data_blocks_1_bytes { + get { + return ResourceManager.GetString("_0_data_blocks_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} data blocks in volume. + /// + internal static string _0_data_blocks_in_volume { + get { + return ResourceManager.GetString("_0_data_blocks_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} data blocks in volume ({1} bytes). + /// + internal static string _0_data_blocks_in_volume_1_bytes { + get { + return ResourceManager.GetString("_0_data_blocks_in_volume_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} data blocks in volume, {1} free. + /// + internal static string _0_data_blocks_in_volume_1_free { + get { + return ResourceManager.GetString("_0_data_blocks_in_volume_1_free", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} data zones ({1} bytes). + /// + internal static string _0_data_zones_1_bytes { + get { + return ResourceManager.GetString("_0_data_zones_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} directories. + /// + internal static string _0_directories { + get { + return ResourceManager.GetString("_0_directories", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} directories in root directory. + /// + internal static string _0_directories_in_root_directory { + get { + return ResourceManager.GetString("_0_directories_in_root_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} directories in volume. + /// + internal static string _0_directories_in_volume { + get { + return ResourceManager.GetString("_0_directories_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} entries in root directory.. + /// + internal static string _0_entries_in_root_directory { + get { + return ResourceManager.GetString("_0_entries_in_root_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} entries per directory block. + /// + internal static string _0_entries_per_directory_block { + get { + return ResourceManager.GetString("_0_entries_per_directory_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} = {1} elements nvlist[], unable to print. + /// + internal static string _0_equals_1_elements_nvlist_array_unable_to_print { + get { + return ResourceManager.GetString("_0_equals_1_elements_nvlist_array_unable_to_print", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} = Unknown data type {1}. + /// + internal static string _0_equals_unknown_data_type_1 { + get { + return ResourceManager.GetString("_0_equals_unknown_data_type_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} errors registered. + /// + internal static string _0_errors_registered { + get { + return ResourceManager.GetString("_0_errors_registered", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} FATs.. + /// + internal static string _0_FATs { + get { + return ResourceManager.GetString("_0_FATs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} files in root directory. + /// + internal static string _0_files_in_root_directory { + get { + return ResourceManager.GetString("_0_files_in_root_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} files in volume. + /// + internal static string _0_files_in_volume { + get { + return ResourceManager.GetString("_0_files_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} size of FLEX_BG group. + /// + internal static string _0_Flexible_block_group_size { + get { + return ResourceManager.GetString("_0_Flexible_block_group_size", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} frags in a block. + /// + internal static string _0_frags_in_a_block { + get { + return ResourceManager.GetString("_0_frags_in_a_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free blocks.. + /// + internal static string _0_free_blocks { + get { + return ResourceManager.GetString("_0_free_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free blocks ({1} bytes). + /// + internal static string _0_free_blocks_1_bytes { + get { + return ResourceManager.GetString("_0_free_blocks_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free blocks on list ({1} bytes). + /// + internal static string _0_free_blocks_on_list_1_bytes { + get { + return ResourceManager.GetString("_0_free_blocks_on_list_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free clusters. + /// + internal static string _0_free_clusters { + get { + return ResourceManager.GetString("_0_free_clusters", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free frags. + /// + internal static string _0_free_frags { + get { + return ResourceManager.GetString("_0_free_frags", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free inodes. + /// + internal static string _0_free_inodes { + get { + return ResourceManager.GetString("_0_free_inodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free inodes on list. + /// + internal static string _0_free_inodes_on_list { + get { + return ResourceManager.GetString("_0_free_inodes_on_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free inodes on volume. + /// + internal static string _0_free_inodes_on_volume { + get { + return ResourceManager.GetString("_0_free_inodes_on_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free spare DNodes. + /// + internal static string _0_free_spare_DNodes { + get { + return ResourceManager.GetString("_0_free_spare_DNodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} free zones on volume ({1} bytes). + /// + internal static string _0_free_zones_on_volume_1_bytes { + get { + return ResourceManager.GetString("_0_free_zones_on_volume_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} heads.. + /// + internal static string _0_heads { + get { + return ResourceManager.GetString("_0_heads", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} heads per cylinder. + /// + internal static string _0_heads_per_cylinder { + get { + return ResourceManager.GetString("_0_heads_per_cylinder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} hidden sectors before BPB.. + /// + internal static string _0_hidden_sectors_before_BPB { + get { + return ResourceManager.GetString("_0_hidden_sectors_before_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} hidden sectors before filesystem. + /// + internal static string _0_hidden_sectors_before_filesystem { + get { + return ResourceManager.GetString("_0_hidden_sectors_before_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} imap zones ({1} bytes). + /// + internal static string _0_imap_zones_1_bytes { + get { + return ResourceManager.GetString("_0_imap_zones_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} inodes. + /// + internal static string _0_inodes { + get { + return ResourceManager.GetString("_0_inodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} inodes free of {1}. + /// + internal static string _0_inodes_free_of_1 { + get { + return ResourceManager.GetString("_0_inodes_free_of_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} inodes in volume. + /// + internal static string _0_inodes_in_volume { + get { + return ResourceManager.GetString("_0_inodes_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} inodes in volume, {1} free. + /// + internal static string _0_inodes_in_volume_1_free { + get { + return ResourceManager.GetString("_0_inodes_in_volume_1_free", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} inodes in volume, {1} free ({2}%). + /// + internal static string _0_inodes_in_volume_1_free_2 { + get { + return ResourceManager.GetString("_0_inodes_in_volume_1_free_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} inodes pending of being freed. + /// + internal static string _0_inodes_pending_of_being_freed { + get { + return ResourceManager.GetString("_0_inodes_pending_of_being_freed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} inodes per cylinder group. + /// + internal static string _0_inodes_per_cylinder_group { + get { + return ResourceManager.GetString("_0_inodes_per_cylinder_group", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} inodes with {1} free inodes ({2}%). + /// + internal static string _0_inodes_with_1_free_inodes_2 { + get { + return ResourceManager.GetString("_0_inodes_with_1_free_inodes_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is first data block. + /// + internal static string _0_is_first_data_block { + get { + return ResourceManager.GetString("_0_is_first_data_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is not set. + /// + internal static string _0_is_not_set { + get { + return ResourceManager.GetString("_0_is_not_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} KiB has been written on volume. + /// + internal static string _0_KiB_has_been_written_on_volume { + get { + return ResourceManager.GetString("_0_KiB_has_been_written_on_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} logical sectors ({1} bytes) per physical sector. + /// + internal static string _0_logical_sectors_1_bytes_per_physical_sector { + get { + return ResourceManager.GetString("_0_logical_sectors_1_bytes_per_physical_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} maximum files on the volume. + /// + internal static string _0_maximum_files_on_the_volume { + get { + return ResourceManager.GetString("_0_maximum_files_on_the_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}ms for optimal next block. + /// + internal static string _0_ms_for_optimal_next_block { + get { + return ResourceManager.GetString("_0_ms_for_optimal_next_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} nanoseconds program time. + /// + internal static string _0_nanoseconds_program_time { + get { + return ResourceManager.GetString("_0_nanoseconds_program_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} nanoseconds random access time. + /// + internal static string _0_nanoseconds_random_access_time { + get { + return ResourceManager.GetString("_0_nanoseconds_random_access_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} nanoseconds read cycle time. + /// + internal static string _0_nanoseconds_read_cycle_time { + get { + return ResourceManager.GetString("_0_nanoseconds_read_cycle_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} nanoseconds write cycle time. + /// + internal static string _0_nanoseconds_write_cycle_time { + get { + return ResourceManager.GetString("_0_nanoseconds_write_cycle_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}% of blocks must be free. + /// + internal static string _0_of_blocks_must_be_free { + get { + return ResourceManager.GetString("_0_of_blocks_must_be_free", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} reserved and {1} free blocks. + /// + internal static string _0_reserved_and_1_free_blocks { + get { + return ResourceManager.GetString("_0_reserved_and_1_free_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} reserved files. + /// + internal static string _0_reserved_files { + get { + return ResourceManager.GetString("_0_reserved_files", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} rotational positions. + /// + internal static string _0_rotational_positions { + get { + return ResourceManager.GetString("_0_rotational_positions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} seconds for multi-mount protection wait, on block {1}. + /// + internal static string _0_seconds_for_multi_mount_protection_wait_on_block_1 { + get { + return ResourceManager.GetString("_0_seconds_for_multi_mount_protection_wait_on_block_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sections. + /// + internal static string _0_sections { + get { + return ResourceManager.GetString("_0_sections", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sections per zone. + /// + internal static string _0_sections_per_zone { + get { + return ResourceManager.GetString("_0_sections_per_zone", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors. + /// + internal static string _0_sectors { + get { + return ResourceManager.GetString("_0_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors ({1} bytes) per block. + /// + internal static string _0_sectors_1_bytes_per_block { + get { + return ResourceManager.GetString("_0_sectors_1_bytes_per_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors ({1} bytes) per cluster. + /// + internal static string _0_sectors_1_bytes_per_cluster { + get { + return ResourceManager.GetString("_0_sectors_1_bytes_per_cluster", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors are marked bad. + /// + internal static string _0_sectors_are_marked_bad { + get { + return ResourceManager.GetString("_0_sectors_are_marked_bad", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors/cylinder. + /// + internal static string _0_sectors_cylinder { + get { + return ResourceManager.GetString("_0_sectors_cylinder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors hidden before BPB. + /// + internal static string _0_sectors_hidden_before_BPB { + get { + return ResourceManager.GetString("_0_sectors_hidden_before_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors in directory.. + /// + internal static string _0_sectors_in_directory { + get { + return ResourceManager.GetString("_0_sectors_in_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors on volume ({1} bytes).. + /// + internal static string _0_sectors_on_volume_1_bytes { + get { + return ResourceManager.GetString("_0_sectors_on_volume_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors per cluster.. + /// + internal static string _0_sectors_per_cluster { + get { + return ResourceManager.GetString("_0_sectors_per_cluster", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors per cluster ({1} bytes). + /// + internal static string _0_sectors_per_cluster_1_bytes { + get { + return ResourceManager.GetString("_0_sectors_per_cluster_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors per FAT.. + /// + internal static string _0_sectors_per_FAT { + get { + return ResourceManager.GetString("_0_sectors_per_FAT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors per track.. + /// + internal static string _0_sectors_per_track { + get { + return ResourceManager.GetString("_0_sectors_per_track", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors reserved between BPB and FAT.. + /// + internal static string _0_sectors_reserved_between_BPB_and_FAT { + get { + return ResourceManager.GetString("_0_sectors_reserved_between_BPB_and_FAT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} sectors/track. + /// + internal static string _0_sectors_track { + get { + return ResourceManager.GetString("_0_sectors_track", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} segments. + /// + internal static string _0_segments { + get { + return ResourceManager.GetString("_0_segments", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} segments per section. + /// + internal static string _0_segments_per_section { + get { + return ResourceManager.GetString("_0_segments_per_section", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} spare blocks. + /// + internal static string _0_spare_blocks { + get { + return ResourceManager.GetString("_0_spare_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} total Hotfix entries. + /// + internal static string _0_total_Hotfix_entries { + get { + return ResourceManager.GetString("_0_total_Hotfix_entries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} total spare DNodes. + /// + internal static string _0_total_spare_DNodes { + get { + return ResourceManager.GetString("_0_total_spare_DNodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} tracks. + /// + internal static string _0_tracks { + get { + return ResourceManager.GetString("_0_tracks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} tracks/cylinder. + /// + internal static string _0_tracks_cylinder { + get { + return ResourceManager.GetString("_0_tracks_cylinder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} tracks in volume. + /// + internal static string _0_tracks_in_volume { + get { + return ResourceManager.GetString("_0_tracks_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} unused allocation blocks.. + /// + internal static string _0_unused_allocation_blocks { + get { + return ResourceManager.GetString("_0_unused_allocation_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} used blocks ({1} bytes). + /// + internal static string _0_used_blocks_1_bytes { + get { + return ResourceManager.GetString("_0_used_blocks_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} used Hotfix entries. + /// + internal static string _0_used_Hotfix_entries { + get { + return ResourceManager.GetString("_0_used_Hotfix_entries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} used sectors on volume. + /// + internal static string _0_used_sectors_on_volume { + get { + return ResourceManager.GetString("_0_used_sectors_on_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} volume allocation blocks.. + /// + internal static string _0_volume_allocation_blocks { + get { + return ResourceManager.GetString("_0_volume_allocation_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} zmap zones ({1} bytes). + /// + internal static string _0_zmap_zones_1_bytes { + get { + return ResourceManager.GetString("_0_zmap_zones_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} zones in volume. + /// + internal static string _0_zones_in_volume { + get { + return ResourceManager.GetString("_0_zones_in_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} zones in volume ({1} bytes). + /// + internal static string _0_zones_in_volume_1_bytes { + get { + return ResourceManager.GetString("_0_zones_in_volume_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} zones reserved for kernel images ({1} bytes). + /// + internal static string _0_zones_reserved_for_kernel_images_1_bytes { + get { + return ResourceManager.GetString("_0_zones_reserved_for_kernel_images_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} µsec for head switch. + /// + internal static string _0_µsec_for_head_switch { + get { + return ResourceManager.GetString("_0_µsec_for_head_switch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} µsec for track-to-track seek. + /// + internal static string _0_µsec_for_track_to_track_seek { + get { + return ResourceManager.GetString("_0_µsec_for_track_to_track_seek", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 1024 bytes per block. + /// + internal static string _1024_bytes_per_block { + get { + return ResourceManager.GetString("_1024_bytes_per_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2048 bytes per block. + /// + internal static string _2048_bytes_per_block { + get { + return ResourceManager.GetString("_2048_bytes_per_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 4096 bytes per block. + /// + internal static string _4096_bytes_per_block { + get { + return ResourceManager.GetString("_4096_bytes_per_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 512 bytes per block. + /// + internal static string _512_bytes_per_block { + get { + return ResourceManager.GetString("_512_bytes_per_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A file can be {0} bytes at max. + /// + internal static string A_file_can_be_0_bytes_at_max { + get { + return ResourceManager.GetString("A_file_can_be_0_bytes_at_max", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (acl): Enable POSIX ACLs. + /// + internal static string acl_Enable_POSIX_ACLs { + get { + return ResourceManager.GetString("acl_Enable_POSIX_ACLs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Acorn Advanced Disc Filing System. + /// + internal static string Acorn_Advanced_Disc_Filing_System { + get { + return ResourceManager.GetString("Acorn_Advanced_Disc_Filing_System", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Acorn Advanced Disc Filing System. + /// + internal static string AcornADFS_Name { + get { + return ResourceManager.GetString("AcornADFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Active root block {0}. + /// + internal static string Active_root_block_0 { + get { + return ResourceManager.GetString("Active_root_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Active snapshot has ID {0}, on inode {1}, with {2} blocks reserved, list starting on block {3}. + /// + internal static string Active_snapshot_has_ID_0_on_inode_1_with_2_blocks_reserved_list_starting_on_block_3 { + get { + return ResourceManager.GetString("Active_snapshot_has_ID_0_on_inode_1_with_2_blocks_reserved_list_starting_on_block" + + "_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Admin space container starts in block {0}. + /// + internal static string Admin_space_container_starts_in_block_0 { + get { + return ResourceManager.GetString("Admin_space_container_starts_in_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Alexander Osipov DOS file system. + /// + internal static string Alexander_Osipov_DOS_file_system { + get { + return ResourceManager.GetString("Alexander_Osipov_DOS_file_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All copies of FAT are the same.. + /// + internal static string All_copies_of_FAT_are_the_same { + get { + return ResourceManager.GetString("All_copies_of_FAT_are_the_same", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All of the following information may be incorrect. + /// + internal static string All_of_the_following_information_may_be_incorrect { + get { + return ResourceManager.GetString("All_of_the_following_information_may_be_incorrect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allocate secondary sound and video buffers at boot.. + /// + internal static string Allocate_secondary_sound_and_video_buffers_at_boot { + get { + return ResourceManager.GetString("Allocate_secondary_sound_and_video_buffers_at_boot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allocate secondary sound buffer at boot.. + /// + internal static string Allocate_secondary_sound_buffer_at_boot { + get { + return ResourceManager.GetString("Allocate_secondary_sound_buffer_at_boot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allocation bitmap descriptor starts at block {0}. + /// + internal static string Allocation_bitmap_descriptor_starts_at_block_0 { + get { + return ResourceManager.GetString("Allocation_bitmap_descriptor_starts_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allocation File is {0} bytes.. + /// + internal static string Allocation_File_is_0_bytes { + get { + return ResourceManager.GetString("Allocation_File_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allocations blocks of the HFS+ volume: {0}. + /// + internal static string Allocations_blocks_of_the_HFS_Plus_volume_0 { + get { + return ResourceManager.GetString("Allocations_blocks_of_the_HFS_Plus_volume_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amiga extensions present.. + /// + internal static string Amiga_extensions_present { + get { + return ResourceManager.GetString("Amiga_extensions_present", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amiga Fast File System. + /// + internal static string Amiga_Fast_File_System { + get { + return ResourceManager.GetString("Amiga_Fast_File_System", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amiga Fast File System with directory cache. + /// + internal static string Amiga_Fast_File_System_with_directory_cache { + get { + return ResourceManager.GetString("Amiga_Fast_File_System_with_directory_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amiga Fast File System with international characters. + /// + internal static string Amiga_Fast_File_System_with_international_characters { + get { + return ResourceManager.GetString("Amiga_Fast_File_System_with_international_characters", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amiga Fast File System with long filenames. + /// + internal static string Amiga_Fast_File_System_with_long_filenames { + get { + return ResourceManager.GetString("Amiga_Fast_File_System_with_long_filenames", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amiga Original File System. + /// + internal static string Amiga_Original_File_System { + get { + return ResourceManager.GetString("Amiga_Original_File_System", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amiga Original File System with directory cache. + /// + internal static string Amiga_Original_File_System_with_directory_cache { + get { + return ResourceManager.GetString("Amiga_Original_File_System_with_directory_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amiga Original File System with international characters. + /// + internal static string Amiga_Original_File_System_with_international_characters { + get { + return ResourceManager.GetString("Amiga_Original_File_System_with_international_characters", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amiga Original File System with long filenames. + /// + internal static string Amiga_Original_File_System_with_long_filenames { + get { + return ResourceManager.GetString("Amiga_Original_File_System_with_long_filenames", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amiga DOS filesystem. + /// + internal static string AmigaDOSPlugin_Name { + get { + return ResourceManager.GetString("AmigaDOSPlugin_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Alexander Osipov DOS file system. + /// + internal static string AODOS_Name { + get { + return ResourceManager.GetString("AODOS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Apple File System. + /// + internal static string APFS_Name { + get { + return ResourceManager.GetString("APFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Apple extensions present.. + /// + internal static string Apple_extensions_present { + get { + return ResourceManager.GetString("Apple_extensions_present", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Apple File System. + /// + internal static string Apple_File_System { + get { + return ResourceManager.GetString("Apple_File_System", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Apple DOS File System. + /// + internal static string AppleDOS_Name { + get { + return ResourceManager.GetString("AppleDOS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Apple HFS+ filesystem. + /// + internal static string AppleHFSPlus_Name { + get { + return ResourceManager.GetString("AppleHFSPlus_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Apple Macintosh File System. + /// + internal static string AppleMFS_Name { + get { + return ResourceManager.GetString("AppleMFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Application identifier: {0}. + /// + internal static string Application_identifier_0 { + get { + return ResourceManager.GetString("Application_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Apricot FAT12. + /// + internal static string Apricot_FAT12 { + get { + return ResourceManager.GetString("Apricot_FAT12", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Arbitrary Attribute Interchange Protocol present.. + /// + internal static string Arbitrary_Attribute_Interchange_Protocol_present { + get { + return ResourceManager.GetString("Arbitrary_Attribute_Interchange_Protocol_present", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ASCII. + /// + internal static string ASCII { + get { + return ResourceManager.GetString("ASCII", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Atari FAT12. + /// + internal static string Atari_FAT12 { + get { + return ResourceManager.GetString("Atari_FAT12", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Atari FAT16. + /// + internal static string Atari_FAT16 { + get { + return ResourceManager.GetString("Atari_FAT16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AtheOS filesystem. + /// + internal static string Atheos_filesystem { + get { + return ResourceManager.GetString("Atheos_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AtheOS Filesystem. + /// + internal static string AtheOS_Name { + get { + return ResourceManager.GetString("AtheOS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Attributes File is {0} bytes.. + /// + internal static string Attributes_File_is_0_bytes { + get { + return ResourceManager.GetString("Attributes_File_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Audio streaming buffer size is {0} bytes. + /// + internal static string Audio_streaming_buffer_size_is_0_bytes { + get { + return ResourceManager.GetString("Audio_streaming_buffer_size_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Australia age rating is {0}. + /// + internal static string Australia_age_rating_is_0 { + get { + return ResourceManager.GetString("Australia_age_rating_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to B-tree filesystem. + /// + internal static string B_tree_filesystem { + get { + return ResourceManager.GetString("B_tree_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Backbone volume. + /// + internal static string Backbone_volume { + get { + return ResourceManager.GetString("Backbone_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Backup INDEXF.SYS;1 is in sector {0} (VBN {1}). + /// + internal static string Backup_INDEXF_SYS_is_in_sector_0_VBN_1 { + get { + return ResourceManager.GetString("Backup_INDEXF_SYS_is_in_sector_0_VBN_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Backup sequence number: {0}. + /// + internal static string Backup_sequence_number_0 { + get { + return ResourceManager.GetString("Backup_sequence_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Backup volume ID: 0x{0:X16}. + /// + internal static string Backup_volume_ID_0 { + get { + return ResourceManager.GetString("Backup_volume_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Be Filesystem. + /// + internal static string BeFS_Name { + get { + return ResourceManager.GetString("BeFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BEWARE!!! Following information may be completely wrong!. + /// + internal static string BEWARE_Following_information_may_be_completely_wrong { + get { + return ResourceManager.GetString("BEWARE_Following_information_may_be_completely_wrong", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UNIX Boot filesystem. + /// + internal static string BFS_Name { + get { + return ResourceManager.GetString("BFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Big-endian. + /// + internal static string Big_endian { + get { + return ResourceManager.GetString("Big_endian", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Big-endian BeFS. + /// + internal static string Big_endian_BeFS { + get { + return ResourceManager.GetString("Big_endian_BeFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Big-endian BorderWare UFS filesystem. + /// + internal static string Big_endian_BorderWare_UFS_filesystem { + get { + return ResourceManager.GetString("Big_endian_BorderWare_UFS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Big-endian UFS filesystem. + /// + internal static string Big_endian_UFS_filesystem { + get { + return ResourceManager.GetString("Big_endian_UFS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Big-endian UFS2 filesystem. + /// + internal static string Big_endian_UFS2_filesystem { + get { + return ResourceManager.GetString("Big_endian_UFS2_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BIOS drive is {0:X2}h. + /// + internal static string BIOS_drive_is_0 { + get { + return ResourceManager.GetString("BIOS_drive_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BIOS drive number: 0x{0:X2}. + /// + internal static string BIOS_drive_number_0 { + get { + return ResourceManager.GetString("BIOS_drive_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bitmap extension at block {0}. + /// + internal static string Bitmap_extension_at_block_0 { + get { + return ResourceManager.GetString("Bitmap_extension_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bitmap resides at block {0}. + /// + internal static string Bitmap_resides_at_block_0 { + get { + return ResourceManager.GetString("Bitmap_resides_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bitmap starts at block {0}. + /// + internal static string Bitmap_starts_at_block_0 { + get { + return ResourceManager.GetString("Bitmap_starts_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Block group number is {0}. + /// + internal static string Block_group_number_is_0 { + get { + return ResourceManager.GetString("Block_group_number_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Block size: {0} bytes. + /// + internal static string Block_size_0_bytes { + get { + return ResourceManager.GetString("Block_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 1 << block_shift == block_size => 1 << {0} == {1} (Should be {2}). + /// + internal static string blockshift_0_1_should_be_2 { + get { + return ResourceManager.GetString("blockshift_0_1_should_be_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot area starts at {0}. + /// + internal static string Boot_area_starts_at_0 { + get { + return ResourceManager.GetString("Boot_area_starts_at_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot Block:. + /// + internal static string Boot_Block { + get { + return ResourceManager.GetString("Boot_Block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot block is in new format.. + /// + internal static string Boot_block_is_in_new_format { + get { + return ResourceManager.GetString("Boot_block_is_in_new_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot block should be executed.. + /// + internal static string Boot_block_should_be_executed { + get { + return ResourceManager.GetString("Boot_block_should_be_executed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot code: 0x{0:X8}. + /// + internal static string Boot_code_0 { + get { + return ResourceManager.GetString("Boot_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot code corresponds to {0}. + /// + internal static string Boot_code_corresponds_to_0 { + get { + return ResourceManager.GetString("Boot_code_corresponds_to_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot code's SHA1: {0}. + /// + internal static string Boot_code_SHA1_0 { + get { + return ResourceManager.GetString("Boot_code_SHA1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot environment: 0x{0:X8}. + /// + internal static string Boot_environment_0 { + get { + return ResourceManager.GetString("Boot_environment_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot file descriptor starts at block {0}. + /// + internal static string Boot_file_descriptor_starts_at_block_0 { + get { + return ResourceManager.GetString("Boot_file_descriptor_starts_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot file starts at block {0} and has {1} bytes. + /// + internal static string Boot_file_starts_at_block_0_and_has_1_bytes { + get { + return ResourceManager.GetString("Boot_file_starts_at_block_0_and_has_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot option: {0}. + /// + internal static string Boot_option_0 { + get { + return ResourceManager.GetString("Boot_option_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot program resides in file "{0}". + /// + internal static string Boot_program_resides_in_file_0 { + get { + return ResourceManager.GetString("Boot_program_resides_in_file_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot program starts in sector {0} and is {1} sectors long ({2} bytes). + /// + internal static string Boot_program_starts_in_sector_0_and_is_1_sectors_long_2_bytes { + get { + return ResourceManager.GetString("Boot_program_starts_in_sector_0_and_is_1_sectors_long_2_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot program will be loaded at address {0:X4}h. + /// + internal static string Boot_program_will_be_loaded_at_address_0 { + get { + return ResourceManager.GetString("Boot_program_will_be_loaded_at_address_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot section {0}:. + /// + internal static string Boot_section_0 { + get { + return ResourceManager.GetString("Boot_section_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Boot volume is inconsistent.. + /// + internal static string Boot_volume_is_inconsistent { + get { + return ResourceManager.GetString("Boot_volume_is_inconsistent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bootable image's SHA1: {0}. + /// + internal static string Bootable_image_SHA1_0 { + get { + return ResourceManager.GetString("Bootable_image_SHA1_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bootable image starts at sector {0} and runs for {1} sectors. + /// + internal static string Bootable_image_starts_at_sector_0_and_runs_for_1_sectors { + get { + return ResourceManager.GetString("Bootable_image_starts_at_sector_0_and_runs_for_1_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bootable image will be loaded at 0x{0:X8}. + /// + internal static string Bootable_image_will_be_loaded_at_0 { + get { + return ResourceManager.GetString("Bootable_image_will_be_loaded_at_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bootable image will be loaded at segment {0:X4}h. + /// + internal static string Bootable_image_will_be_loaded_at_segment_0 { + get { + return ResourceManager.GetString("Bootable_image_will_be_loaded_at_segment_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bootable on {0}. + /// + internal static string Bootable_on_0 { + get { + return ResourceManager.GetString("Bootable_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bootblock points to {0} as Rootblock. + /// + internal static string Bootblock_points_to_0_as_Rootblock { + get { + return ResourceManager.GetString("Bootblock_points_to_0_as_Rootblock", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BorderWare UFS filesystem. + /// + internal static string BorderWare_UFS_filesystem { + get { + return ResourceManager.GetString("BorderWare_UFS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (bsdgroups): Emulate BSD behaviour when creating new files. + /// + internal static string bsdgroups_Emulate_BSD_behaviour_when_creating_new_files { + get { + return ResourceManager.GetString("bsdgroups_Emulate_BSD_behaviour_when_creating_new_files", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to B-tree file system. + /// + internal static string BTRFS_Name { + get { + return ResourceManager.GetString("BTRFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cached directories: {0}. + /// + internal static string Cached_directories_0 { + get { + return ResourceManager.GetString("Cached_directories_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Can have files bigger than 2GiB. + /// + internal static string Can_have_files_bigger_than_2GiB { + get { + return ResourceManager.GetString("Can_have_files_bigger_than_2GiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Can have files bigger than 2TiB (ext4). + /// + internal static string Can_have_files_bigger_than_2TiB_ext4 { + get { + return ResourceManager.GetString("Can_have_files_bigger_than_2TiB_ext4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Can use hashed indexes on directories. + /// + internal static string Can_use_hashed_indexes_on_directories { + get { + return ResourceManager.GetString("Can_use_hashed_indexes_on_directories", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot find root directory.... + /// + internal static string Cannot_find_root_directory { + get { + return ResourceManager.GetString("Cannot_find_root_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot mount LisaFS version {0}. + /// + internal static string Cannot_mount_LisaFS_version_0 { + get { + return ResourceManager.GetString("Cannot_mount_LisaFS_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot read Catalog File, error {0}. + /// + internal static string Cannot_read_Catalog_File_error_0 { + get { + return ResourceManager.GetString("Cannot_read_Catalog_File_error_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Casting FAT. + /// + internal static string Casting_FAT { + get { + return ResourceManager.GetString("Casting_FAT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Catalog File is {0} bytes.. + /// + internal static string Catalog_File_is_0_bytes { + get { + return ResourceManager.GetString("Catalog_File_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Catalog starts at sector {0} of track {1}. + /// + internal static string Catalog_starts_at_sector_0_of_track_1 { + get { + return ResourceManager.GetString("Catalog_starts_at_sector_0_of_track_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This disk contains a relative file. These have not been fully tested, please open a bug report and include this disk image.. + /// + internal static string CBM_Mount_REL_file_warning { + get { + return ResourceManager.GetString("CBM_Mount_REL_file_warning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Commodore file system. + /// + internal static string CBM_Name { + get { + return ResourceManager.GetString("CBM_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-i file system. + /// + internal static string CD_i_file_system { + get { + return ResourceManager.GetString("CD_i_file_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CD-ROM XA extensions present.. + /// + internal static string CD_ROM_XA_extensions_present { + get { + return ResourceManager.GetString("CD_ROM_XA_extensions_present", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to channel. + /// + internal static string channel { + get { + return ResourceManager.GetString("channel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Checksum: 0x{0:X4} (calculated 0x{1:X4}). + /// + internal static string Checksum_0_calculated_1 { + get { + return ResourceManager.GetString("Checksum_0_calculated_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Checksum: 0x{0:X8}. + /// + internal static string Checksum_0_X8 { + get { + return ResourceManager.GetString("Checksum_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Checksums: 0x{0:X4} and 0x{1:X4}. + /// + internal static string Checksums_0_and_1 { + get { + return ResourceManager.GetString("Checksums_0_and_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Chunk tree starts at LBA {0}. + /// + internal static string Chunk_tree_starts_at_LBA_0 { + get { + return ResourceManager.GetString("Chunk_tree_starts_at_LBA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Classification checks are enabled. + /// + internal static string Classification_checks_are_enabled { + get { + return ResourceManager.GetString("Classification_checks_are_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Clean volume. + /// + internal static string Clean_volume { + get { + return ResourceManager.GetString("Clean_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Clipboard filename: {0}. + /// + internal static string Clipboard_filename_0 { + get { + return ResourceManager.GetString("Clipboard_filename_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cluster heap starts at sector {0}, contains {1} clusters and is {2}% used. + /// + internal static string Cluster_heap_starts_at_sector_0_contains_1_clusters_and_is_2_used { + get { + return ResourceManager.GetString("Cluster_heap_starts_at_sector_0_contains_1_clusters_and_is_2_used", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cluster of root directory: {0}. + /// + internal static string Cluster_of_root_directory_0 { + get { + return ResourceManager.GetString("Cluster_of_root_directory_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cluster where $MFT starts: {0}. + /// + internal static string Cluster_where_MFT_starts_0 { + get { + return ResourceManager.GetString("Cluster_where_MFT_starts_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cluster where $MFTMirr starts: {0}. + /// + internal static string Cluster_where_MFTMirr_starts_0 { + get { + return ResourceManager.GetString("Cluster_where_MFTMirr_starts_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to cmdload will be loaded with value {0:X4}h. + /// + internal static string cmdload_will_be_loaded_with_value_0 { + get { + return ResourceManager.GetString("cmdload_will_be_loaded_with_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CNID of bootable Mac OS 8 or 9 directory: {0}. + /// + internal static string CNID_of_bootable_Mac_OS_8_or_9_directory_0 { + get { + return ResourceManager.GetString("CNID_of_bootable_Mac_OS_8_or_9_directory_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CNID of bootable Mac OS X directory: {0}. + /// + internal static string CNID_of_bootable_Mac_OS_X_directory_0 { + get { + return ResourceManager.GetString("CNID_of_bootable_Mac_OS_X_directory_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CNID of bootable system's directory: {0}. + /// + internal static string CNID_of_bootable_system_directory_0 { + get { + return ResourceManager.GetString("CNID_of_bootable_system_directory_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CNID of first-run application's directory: {0}. + /// + internal static string CNID_of_first_run_application_directory_0 { + get { + return ResourceManager.GetString("CNID_of_first_run_application_directory_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CNID of previously opened directory: {0}. + /// + internal static string CNID_of_previously_opened_directory_0 { + get { + return ResourceManager.GetString("CNID_of_previously_opened_directory_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Coherent UNIX filesystem. + /// + internal static string Coherent_UNIX_filesystem { + get { + return ResourceManager.GetString("Coherent_UNIX_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Commodore 64 Virtual Console. + /// + internal static string Commodore_64_Virtual_Console { + get { + return ResourceManager.GetString("Commodore_64_Virtual_Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Commodore file system. + /// + internal static string Commodore_file_system { + get { + return ResourceManager.GetString("Commodore_file_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compatible features…:. + /// + internal static string Compatible_features { + get { + return ResourceManager.GetString("Compatible_features", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compatible features if read-only…:. + /// + internal static string Compatible_features_if_read_only { + get { + return ResourceManager.GetString("Compatible_features_if_read_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compatible flags: 0x{0:X}. + /// + internal static string Compatible_flags_0 { + get { + return ResourceManager.GetString("Compatible_flags_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Container has {0} bytes in {1} blocks. + /// + internal static string Container_has_0_bytes_in_1_blocks { + get { + return ResourceManager.GetString("Container_has_0_bytes_in_1_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Contains Enhanced Volume Descriptor.. + /// + internal static string Contains_Enhanced_Volume_Descriptor { + get { + return ResourceManager.GetString("Contains_Enhanced_Volume_Descriptor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Contains Volume Partition Descriptor.. + /// + internal static string Contains_Volume_Partition_Descriptor { + get { + return ResourceManager.GetString("Contains_Volume_Partition_Descriptor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Copyright: {0}. + /// + internal static string Copyright_0 { + get { + return ResourceManager.GetString("Copyright_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not read dump(8) header block. + /// + internal static string Could_not_read_dump_8_header_block { + get { + return ResourceManager.GetString("Could_not_read_dump_8_header_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Country code: {0}. + /// + internal static string Country_code_0 { + get { + return ResourceManager.GetString("Country_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CP/M filesystem. + /// + internal static string CPM_filesystem { + get { + return ResourceManager.GetString("CPM_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CP/M File System. + /// + internal static string CPM_Name { + get { + return ResourceManager.GetString("CPM_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cram file system. + /// + internal static string Cram_file_system { + get { + return ResourceManager.GetString("Cram_file_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cram filesystem. + /// + internal static string Cram_Name { + get { + return ResourceManager.GetString("Cram_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Created on {0}. + /// + internal static string Created_on_0 { + get { + return ResourceManager.GetString("Created_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Creating allocation blocks.. + /// + internal static string Creating_allocation_blocks { + get { + return ResourceManager.GetString("Creating_allocation_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Creation date: {0}. + /// + internal static string Creation_date_0 { + get { + return ResourceManager.GetString("Creation_date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Creator OS code: {0}. + /// + internal static string Creator_OS_code_0 { + get { + return ResourceManager.GetString("Creator_OS_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current root block {0}. + /// + internal static string Current_root_block_0 { + get { + return ResourceManager.GetString("Current_root_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current sector = {0}. + /// + internal static string Current_sector_0 { + get { + return ResourceManager.GetString("Current_sector_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cylinder-block LBA: {0}. + /// + internal static string Cylinder_block_LBA_0 { + get { + return ResourceManager.GetString("Cylinder_block_LBA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cylinder group offset in cylinder: {0}. + /// + internal static string Cylinder_group_offset_in_cylinder_0 { + get { + return ResourceManager.GetString("Cylinder_group_offset_in_cylinder_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cylinder group size: {0} basic blocks. + /// + internal static string Cylinder_group_size_0_basic_blocks { + get { + return ResourceManager.GetString("Cylinder_group_size_0_basic_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cylinder group summary area LBA: {0}. + /// + internal static string Cylinder_group_summary_area_LBA_0 { + get { + return ResourceManager.GetString("Cylinder_group_summary_area_LBA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cylinder group summary LBA: {0}. + /// + internal static string Cylinder_group_summary_LBA_0 { + get { + return ResourceManager.GetString("Cylinder_group_summary_LBA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CYLINDERS ordering not yet implemented.. + /// + internal static string CYLINDERS_ordering_not_yet_implemented { + get { + return ResourceManager.GetString("CYLINDERS_ordering_not_yet_implemented", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DASD limits are dirty. + /// + internal static string DASD_limits_are_dirty { + get { + return ResourceManager.GetString("DASD_limits_are_dirty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DASD limits are operational. + /// + internal static string DASD_limits_are_operational { + get { + return ResourceManager.GetString("DASD_limits_are_operational", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to data. + /// + internal static string data { + get { + return ResourceManager.GetString("data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data can reside in directory entry (ext4). + /// + internal static string Data_can_reside_in_directory_entry_ext4 { + get { + return ResourceManager.GetString("Data_can_reside_in_directory_entry_ext4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data fork clump size: {0} bytes.. + /// + internal static string Data_fork_clump_size_0_bytes { + get { + return ResourceManager.GetString("Data_fork_clump_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data preparer identifier: {0}. + /// + internal static string Data_preparer_identifier_0 { + get { + return ResourceManager.GetString("Data_preparer_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data starts at block {0}. + /// + internal static string Data_starts_at_block_0 { + get { + return ResourceManager.GetString("Data_starts_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Date of last integrity check: {0}. + /// + internal static string Date_of_last_integrity_check_0 { + get { + return ResourceManager.GetString("Date_of_last_integrity_check_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Date of last optimization {0}. + /// + internal static string Date_of_last_optimization_0 { + get { + return ResourceManager.GetString("Date_of_last_optimization_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dated {0}. + /// + internal static string Dated_0 { + get { + return ResourceManager.GetString("Dated_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Datetime field year {0}, month {1}, day {2}, hour {3}, minute {4}.. + /// + internal static string Datetime_field_year_0_month_1_day_2_hour_3_minute_4 { + get { + return ResourceManager.GetString("Datetime_field_year_0_month_1_day_2_hour_3_minute_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DCE ACLs are active. + /// + internal static string DCE_ACLs_are_active { + get { + return ResourceManager.GetString("DCE_ACLs_are_active", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (debug): Enable debugging code. + /// + internal static string debug_Enable_debugging_code { + get { + return ResourceManager.GetString("debug_Enable_debugging_code", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Debugger descriptor starts at block {0}. + /// + internal static string Debugger_descriptor_starts_at_block_0 { + get { + return ResourceManager.GetString("Debugger_descriptor_starts_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Debugger filename: {0}. + /// + internal static string Debugger_filename_0 { + get { + return ResourceManager.GetString("Debugger_filename_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Default allocation: {0} blocks. + /// + internal static string Default_allocation_0_blocks { + get { + return ResourceManager.GetString("Default_allocation_0_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Default mount options…:. + /// + internal static string Default_mount_options { + get { + return ResourceManager.GetString("Default_mount_options", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Default UID: {0}, GID: {1}. + /// + internal static string Default_UID_0_GID_1 { + get { + return ResourceManager.GetString("Default_UID_0_GID_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Definition "{0}" has a correct directory. + /// + internal static string Definition_0_has_a_correct_directory { + get { + return ResourceManager.GetString("Definition_0_has_a_correct_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Definition contains EVEN-ODD field, with unknown meaning, detection may be wrong.. + /// + internal static string Definition_contains_EVEN_ODD_field_with_unknown_meaning_detection_may_be_wrong { + get { + return ResourceManager.GetString("Definition_contains_EVEN_ODD_field_with_unknown_meaning_detection_may_be_wrong", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Deinterleaving whole volume.. + /// + internal static string Deinterleaving_whole_volume { + get { + return ResourceManager.GetString("Deinterleaving_whole_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Demo. + /// + internal static string Demo { + get { + return ResourceManager.GetString("Demo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Density code: {0}. + /// + internal static string Density_code_0 { + get { + return ResourceManager.GetString("Density_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Description: {0}. + /// + internal static string Description_0 { + get { + return ResourceManager.GetString("Description_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Developer ID: {0}. + /// + internal static string Developer_ID_0 { + get { + return ResourceManager.GetString("Developer_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device is too small. + /// + internal static string Device_is_too_small { + get { + return ResourceManager.GetString("Device_is_too_small", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device uses {0}:1 hardware interleaving. + /// + internal static string Device_uses_0_one_hardware_interleaving { + get { + return ResourceManager.GetString("Device_uses_0_one_hardware_interleaving", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Device's UUID: {0}. + /// + internal static string Device_UUID_0 { + get { + return ResourceManager.GetString("Device_UUID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Diagnostic. + /// + internal static string Diagnostic { + get { + return ResourceManager.GetString("Diagnostic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Directory band ends at sector {0}. + /// + internal static string Directory_band_ends_at_sector_0 { + get { + return ResourceManager.GetString("Directory_band_ends_at_sector_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Directory band has {0} sectors. + /// + internal static string Directory_band_has_0_sectors { + get { + return ResourceManager.GetString("Directory_band_has_0_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Directory band starts at sector {0}. + /// + internal static string Directory_band_starts_at_sector_0 { + get { + return ResourceManager.GetString("Directory_band_starts_at_sector_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Directory cache starts at block {0}. + /// + internal static string Directory_cache_starts_at_block_0 { + get { + return ResourceManager.GetString("Directory_cache_starts_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Directory containing files scheduled for deletion's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes). + /// + internal static string Directory_containing_files_scheduled_for_deletion_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes { + get { + return ResourceManager.GetString("Directory_containing_files_scheduled_for_deletion_i_node_resides_in_block_0_of_al" + + "location_group_1_and_runs_for_2_blocks_3_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Directory size: {0} clusters. + /// + internal static string Directory_size_0_clusters { + get { + return ResourceManager.GetString("Directory_size_0_clusters", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Directory starts at cluster {0}. + /// + internal static string Directory_starts_at_cluster_0 { + get { + return ResourceManager.GetString("Directory_starts_at_cluster_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Directory starts at track {0} sector {1}. + /// + internal static string Directory_starts_at_track_0_sector_1 { + get { + return ResourceManager.GetString("Directory_starts_at_track_0_sector_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dirty volume. + /// + internal static string Dirty_volume { + get { + return ResourceManager.GetString("Dirty_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disassembler filename: {0}. + /// + internal static string Disassembler_filename_0 { + get { + return ResourceManager.GetString("Disassembler_filename_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc bootable following {0} specifications.. + /// + internal static string Disc_bootable_following_0_specifications { + get { + return ResourceManager.GetString("Disc_bootable_following_0_specifications", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc ID is {0}. + /// + internal static string Disc_ID_is_0 { + get { + return ResourceManager.GetString("Disc_ID_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is a {0} disc. + /// + internal static string Disc_is_a_0_disc { + get { + return ResourceManager.GetString("Disc_is_a_0_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc is prepared for audio streaming. + /// + internal static string Disc_is_prepared_for_audio_streaming { + get { + return ResourceManager.GetString("Disc_is_prepared_for_audio_streaming", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc number {0} of a multi-disc set. + /// + internal static string Disc_number_0_of_a_multi_disc_set { + get { + return ResourceManager.GetString("Disc_number_0_of_a_multi_disc_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disc region is {0}. + /// + internal static string Disc_region_is_0 { + get { + return ResourceManager.GetString("Disc_region_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk contains bad sectors. + /// + internal static string Disk_contains_bad_sectors { + get { + return ResourceManager.GetString("Disk_contains_bad_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk DOS type: {0}. + /// + internal static string Disk_DOS_type_0 { + get { + return ResourceManager.GetString("Disk_DOS_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk DOS Version: {0}. + /// + internal static string Disk_DOS_Version_0 { + get { + return ResourceManager.GetString("Disk_DOS_Version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk has a bad bitmap. + /// + internal static string Disk_has_a_bad_bitmap { + get { + return ResourceManager.GetString("Disk_has_a_bad_bitmap", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk ID: {0}. + /// + internal static string Disk_ID_0 { + get { + return ResourceManager.GetString("Disk_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk is 192 TPI. + /// + internal static string Disk_is_192_TPI { + get { + return ResourceManager.GetString("Disk_is_192_TPI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk is 384 TPI. + /// + internal static string Disk_is_384_TPI { + get { + return ResourceManager.GetString("Disk_is_384_TPI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk is 48 TPI. + /// + internal static string Disk_is_48_TPI { + get { + return ResourceManager.GetString("Disk_is_48_TPI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk is 96 TPI or 135 TPI. + /// + internal static string Disk_is_96_TPI_or_135_TPI { + get { + return ResourceManager.GetString("Disk_is_96_TPI_or_135_TPI", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk is double density. + /// + internal static string Disk_is_double_density { + get { + return ResourceManager.GetString("Disk_is_double_density", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk is double sided. + /// + internal static string Disk_is_double_sided { + get { + return ResourceManager.GetString("Disk_is_double_sided", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk is owned by group {0} user {1}. + /// + internal static string Disk_is_owned_by_group_0_user_1 { + get { + return ResourceManager.GetString("Disk_is_owned_by_group_0_user_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk is owned by user {0}. + /// + internal static string Disk_is_owned_by_user_0 { + get { + return ResourceManager.GetString("Disk_is_owned_by_user_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk is single density. + /// + internal static string Disk_is_single_density { + get { + return ResourceManager.GetString("Disk_is_single_density", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk is single sided. + /// + internal static string Disk_is_single_sided { + get { + return ResourceManager.GetString("Disk_is_single_sided", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk name: {0}. + /// + internal static string Disk_name_0 { + get { + return ResourceManager.GetString("Disk_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk rotates {0} times per second ({1}rpm). + /// + internal static string Disk_rotates_0_times_per_second_1_rpm { + get { + return ResourceManager.GetString("Disk_rotates_0_times_per_second_1_rpm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk surface should be checked on next mount.. + /// + internal static string Disk_surface_should_be_checked_on_next_mount { + get { + return ResourceManager.GetString("Disk_surface_should_be_checked_on_next_mount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk Version: {0}. + /// + internal static string Disk_Version_0 { + get { + return ResourceManager.GetString("Disk_Version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disk volume number {0}. + /// + internal static string Disk_volume_number_0 { + get { + return ResourceManager.GetString("Disk_volume_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Don't know how to handle EAGLE ordering, not proceeding with this definition.. + /// + internal static string Don_know_how_to_handle_EAGLE_ordering_not_proceeding_with_this_definition { + get { + return ResourceManager.GetString("Don_know_how_to_handle_EAGLE_ordering_not_proceeding_with_this_definition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Don't know how to handle COLUMBIA ordering, not proceeding with this definition.. + /// + internal static string Dont_know_how_to_handle_COLUMBIA_ordering_not_proceeding_with_this_definition { + get { + return ResourceManager.GetString("Dont_know_how_to_handle_COLUMBIA_ordering_not_proceeding_with_this_definition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DOS (8.3 all uppercase). + /// + internal static string DOS_8_3_all_uppercase { + get { + return ResourceManager.GetString("DOS_8_3_all_uppercase", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DOS Version: {0}. + /// + internal static string DOS_Version_0 { + get { + return ResourceManager.GetString("DOS_Version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DR-DOS will boot this FAT32 using CHS.. + /// + internal static string DR_DOS_will_boot_this_FAT32_using_CHS { + get { + return ResourceManager.GetString("DR_DOS_will_boot_this_FAT32_using_CHS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DR-DOS will boot this FAT32 using LBA.. + /// + internal static string DR_DOS_will_boot_this_FAT32_using_LBA { + get { + return ResourceManager.GetString("DR_DOS_will_boot_this_FAT32_using_LBA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive number: 0x{0:X2}. + /// + internal static string Drive_number_0 { + get { + return ResourceManager.GetString("Drive_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Drive serial number: 0x{0:X8}. + /// + internal static string Drive_serial_number_0 { + get { + return ResourceManager.GetString("Drive_serial_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dump created on {0}. + /// + internal static string Dump_created_on_0 { + get { + return ResourceManager.GetString("Dump_created_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dump hostname: {0}. + /// + internal static string Dump_hostname_0 { + get { + return ResourceManager.GetString("Dump_hostname_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dump label: {0}. + /// + internal static string Dump_label_0 { + get { + return ResourceManager.GetString("Dump_label_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dump level: {0}. + /// + internal static string Dump_level_0 { + get { + return ResourceManager.GetString("Dump_level_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to dump(8) Plugin. + /// + internal static string dump_Name { + get { + return ResourceManager.GetString("dump_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dump volume number: {0}. + /// + internal static string Dump_volume_number_0 { + get { + return ResourceManager.GetString("Dump_volume_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dumped device: {0}. + /// + internal static string Dumped_device_0 { + get { + return ResourceManager.GetString("Dumped_device_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dumped filesystem name: {0}. + /// + internal static string Dumped_filesystem_name_0 { + get { + return ResourceManager.GetString("Dumped_filesystem_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EBCDIC. + /// + internal static string EBCDIC { + get { + return ResourceManager.GetString("EBCDIC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-67. + /// + internal static string ECMA_67 { + get { + return ResourceManager.GetString("ECMA_67", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ECMA-67. + /// + internal static string ECMA67_Name { + get { + return ResourceManager.GetString("ECMA67_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extent File System Plugin. + /// + internal static string EFS_Name { + get { + return ResourceManager.GetString("EFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EL TORITO INFORMATION:. + /// + internal static string EL_TORITO_INFORMATION { + get { + return ResourceManager.GetString("EL_TORITO_INFORMATION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ----------------------. + /// + internal static string EL_TORITO_INFORMATION_border { + get { + return ResourceManager.GetString("EL_TORITO_INFORMATION_border", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Entry {0}:. + /// + internal static string Entry_0 { + get { + return ResourceManager.GetString("Entry_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Epoch high {0}. + /// + internal static string Epoch_high_0 { + get { + return ResourceManager.GetString("Epoch_high_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Epoch low {0}. + /// + internal static string Epoch_low_0 { + get { + return ResourceManager.GetString("Epoch_low_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error {0} reading S-Records file.. + /// + internal static string Error_0_reading_S_Records_file { + get { + return ResourceManager.GetString("Error_0_reading_S_Records_file", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ERROR: Could not find primary volume descriptor. + /// + internal static string ERROR_Could_not_find_primary_volume_descriptor { + get { + return ResourceManager.GetString("ERROR_Could_not_find_primary_volume_descriptor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ESRB age rating is {0}. + /// + internal static string ESRB_age_rating_is_0 { + get { + return ResourceManager.GetString("ESRB_age_rating_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Event queue size: {0}. + /// + internal static string Event_queue_size_0 { + get { + return ResourceManager.GetString("Event_queue_size_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception {0}, {1}, {2}. + /// + internal static string Exception_0_1_2 { + get { + return ResourceManager.GetString("Exception_0_1_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception reading CD-i audio file. + /// + internal static string Exception_reading_CD_i_audio_file { + get { + return ResourceManager.GetString("Exception_reading_CD_i_audio_file", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Microsoft Extended File Allocation Table. + /// + internal static string exFAT_Name { + get { + return ResourceManager.GetString("exFAT_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ext filesystem. + /// + internal static string ext_filesystem { + get { + return ResourceManager.GetString("ext_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ext2 filesystem. + /// + internal static string ext2_filesystem { + get { + return ResourceManager.GetString("ext2_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ext2 (old) filesystem. + /// + internal static string ext2_old_filesystem { + get { + return ResourceManager.GetString("ext2_old_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Linux extended Filesystem 2, 3 and 4. + /// + internal static string ext2FS_Name_Linux_extended_Filesystem_2_3_and_4 { + get { + return ResourceManager.GetString("ext2FS_Name_Linux_extended_Filesystem_2_3_and_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ext3 filesystem. + /// + internal static string ext3_filesystem { + get { + return ResourceManager.GetString("ext3_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ext4 filesystem. + /// + internal static string ext4_filesystem { + get { + return ResourceManager.GetString("ext4_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extended attributes can reside in inode (ext4). + /// + internal static string Extended_attributes_can_reside_in_inode_ext4 { + get { + return ResourceManager.GetString("Extended_attributes_can_reside_in_inode_ext4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extension: {0}. + /// + internal static string Extension_0 { + get { + return ResourceManager.GetString("Extension_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Extents File is {0} bytes.. + /// + internal static string Extents_File_is_0_bytes { + get { + return ResourceManager.GetString("Extents_File_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Linux extended Filesystem. + /// + internal static string extFS_Name { + get { + return ResourceManager.GetString("extFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to F2FS filesystem. + /// + internal static string F2FS_filesystem { + get { + return ResourceManager.GetString("F2FS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to F2FS Plugin. + /// + internal static string F2FS_Name { + get { + return ResourceManager.GetString("F2FS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FAT and directory will be cached at address {0:X4}h. + /// + internal static string FAT_and_directory_will_be_cached_at_address_0 { + get { + return ResourceManager.GetString("FAT_and_directory_will_be_cached_at_address_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FAT is {0} sectors. + /// + internal static string FAT_is_0_sectors { + get { + return ResourceManager.GetString("FAT_is_0_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Microsoft File Allocation Table. + /// + internal static string FAT_Name { + get { + return ResourceManager.GetString("FAT_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FAT+. + /// + internal static string FAT_Plus { + get { + return ResourceManager.GetString("FAT_Plus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FATs are out of sync. FAT #{0} is in use.. + /// + internal static string FATs_are_out_of_sync_FAT_0_is_in_use { + get { + return ResourceManager.GetString("FATs_are_out_of_sync_FAT_0_is_in_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FATX filesystem. + /// + internal static string FATX_filesystem { + get { + return ResourceManager.GetString("FATX_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BSD Fast File System (aka UNIX File System, UFS). + /// + internal static string FFSPlugin_Name { + get { + return ResourceManager.GetString("FFSPlugin_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File {0} gets truncated.. + /// + internal static string File_0_gets_truncated { + get { + return ResourceManager.GetString("File_0_gets_truncated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File protection: 0x{0:X4}. + /// + internal static string File_protection_0 { + get { + return ResourceManager.GetString("File_protection_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FILE STRUCTURE VOLUME DESCRIPTOR INFORMATION:. + /// + internal static string FILE_STRUCTURE_VOLUME_DESCRIPTOR_INFORMATION { + get { + return ResourceManager.GetString("FILE_STRUCTURE_VOLUME_DESCRIPTOR_INFORMATION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ---------------------------------------------. + /// + internal static string FILE_STRUCTURE_VOLUME_DESCRIPTOR_INFORMATION_border { + get { + return ResourceManager.GetString("FILE_STRUCTURE_VOLUME_DESCRIPTOR_INFORMATION_border", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File system initialized by DOS release {0}. + /// + internal static string File_system_initialized_by_DOS_release_0 { + get { + return ResourceManager.GetString("File_system_initialized_by_DOS_release_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File system type: "{0}" (Should be "HPFS "). + /// + internal static string File_system_type_0_Should_be_HPFS { + get { + return ResourceManager.GetString("File_system_type_0_Should_be_HPFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File truncated at block {0}. + /// + internal static string File_truncated_at_block_0 { + get { + return ResourceManager.GetString("File_truncated_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Files should be erased or overwritten when deleted. + /// + internal static string Files_should_be_erased_or_overwritten_when_deleted { + get { + return ResourceManager.GetString("Files_should_be_erased_or_overwritten_when_deleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem contains {0} "big-blocks" ({1} bytes). + /// + internal static string Filesystem_contains_0_big_blocks_1_bytes { + get { + return ResourceManager.GetString("Filesystem_contains_0_big_blocks_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem created on Linux. + /// + internal static string Filesystem_created_on_Linux { + get { + return ResourceManager.GetString("Filesystem_created_on_Linux", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem endianness: 0x{0:X8} (Should be 0x42494745). + /// + internal static string Filesystem_endianness_0_Should_be_0x42494745 { + get { + return ResourceManager.GetString("Filesystem_endianness_0_Should_be_0x42494745", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem has {0} "big-blocks" free ({1} bytes). + /// + internal static string Filesystem_has_0_big_blocks_free_1_bytes { + get { + return ResourceManager.GetString("Filesystem_has_0_big_blocks_free_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem has {0} inodes used. + /// + internal static string Filesystem_has_0_inodes_used { + get { + return ResourceManager.GetString("Filesystem_has_0_inodes_used", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem has been mounted by an old IFS. + /// + internal static string Filesystem_has_been_mounted_by_an_old_IFS { + get { + return ResourceManager.GetString("Filesystem_has_been_mounted_by_an_old_IFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem has never been optimized. + /// + internal static string Filesystem_has_never_been_optimized { + get { + return ResourceManager.GetString("Filesystem_has_never_been_optimized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem integrity has never been checked. + /// + internal static string Filesystem_integrity_has_never_been_checked { + get { + return ResourceManager.GetString("Filesystem_integrity_has_never_been_checked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem is big endian. + /// + internal static string Filesystem_is_big_endian { + get { + return ResourceManager.GetString("Filesystem_is_big_endian", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem is clean.. + /// + internal static string Filesystem_is_clean { + get { + return ResourceManager.GetString("Filesystem_is_clean", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem is dirty.. + /// + internal static string Filesystem_is_dirty { + get { + return ResourceManager.GetString("Filesystem_is_dirty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem is little endian. + /// + internal static string Filesystem_is_little_endian { + get { + return ResourceManager.GetString("Filesystem_is_little_endian", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem is read-only. + /// + internal static string Filesystem_is_read_only { + get { + return ResourceManager.GetString("Filesystem_is_read_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem name: {0}. + /// + internal static string Filesystem_name_0 { + get { + return ResourceManager.GetString("Filesystem_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem overhead: {0}. + /// + internal static string Filesystem_overhead_0 { + get { + return ResourceManager.GetString("Filesystem_overhead_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem revision: {0}.{1}. + /// + internal static string Filesystem_revision_0_1 { + get { + return ResourceManager.GetString("Filesystem_revision_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem revision is {0}.{1:D2}. + /// + internal static string Filesystem_revision_is_0_1 { + get { + return ResourceManager.GetString("Filesystem_revision_is_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem size: {0} basic blocks. + /// + internal static string Filesystem_size_0_basic_blocks { + get { + return ResourceManager.GetString("Filesystem_size_0_basic_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem state: {0:X4}. + /// + internal static string Filesystem_state_0 { + get { + return ResourceManager.GetString("Filesystem_state_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem type: {0}. + /// + internal static string Filesystem_type_0 { + get { + return ResourceManager.GetString("Filesystem_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem version {0}. + /// + internal static string Filesystem_version_0 { + get { + return ResourceManager.GetString("Filesystem_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem version: {0}.{1}. + /// + internal static string Filesystem_version_0_1 { + get { + return ResourceManager.GetString("Filesystem_version_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem version is {0}.. + /// + internal static string Filesystem_version_is_0 { + get { + return ResourceManager.GetString("Filesystem_version_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem was formatted fast. + /// + internal static string Filesystem_was_formatted_fast { + get { + return ResourceManager.GetString("Filesystem_was_formatted_fast", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem will minimize allocation time. + /// + internal static string Filesystem_will_minimize_allocation_time { + get { + return ResourceManager.GetString("Filesystem_will_minimize_allocation_time", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filesystem will minimize volume fragmentation. + /// + internal static string Filesystem_will_minimize_volume_fragmentation { + get { + return ResourceManager.GetString("Filesystem_will_minimize_volume_fragmentation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Filetype in directory entries. + /// + internal static string Filetype_in_directory_entries { + get { + return ResourceManager.GetString("Filetype_in_directory_entries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Finder filename: {0}. + /// + internal static string Finder_filename_0 { + get { + return ResourceManager.GetString("Finder_filename_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Finder info:. + /// + internal static string Finder_info { + get { + return ResourceManager.GetString("Finder_info", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Finland age rating is {0}. + /// + internal static string Finland_age_rating_is_0 { + get { + return ResourceManager.GetString("Finland_age_rating_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First {0} partition starts at sector {1}. + /// + internal static string First_0_partition_starts_at_sector_1 { + get { + return ResourceManager.GetString("First_0_partition_starts_at_sector_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First allocation block (#2) starts in sector {0}.. + /// + internal static string First_allocation_block_number_two_starts_in_sector_0 { + get { + return ResourceManager.GetString("First_allocation_block_number_two_starts_in_sector_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First cylinder group starts at block {0}. + /// + internal static string First_cylinder_group_starts_at_block_0 { + get { + return ResourceManager.GetString("First_cylinder_group_starts_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First data block LBA: {0}. + /// + internal static string First_data_block_LBA_0 { + get { + return ResourceManager.GetString("First_data_block_LBA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First data zone: {0}. + /// + internal static string First_data_zone_0 { + get { + return ResourceManager.GetString("First_data_zone_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First data zone is {0}. + /// + internal static string First_data_zone_is_0 { + get { + return ResourceManager.GetString("First_data_zone_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First directory block seems correct.. + /// + internal static string First_directory_block_seems_correct { + get { + return ResourceManager.GetString("First_directory_block_seems_correct", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First directory sector: {0}. + /// + internal static string First_directory_sector_0 { + get { + return ResourceManager.GetString("First_directory_sector_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First directory segment starts at block {0}. + /// + internal static string First_directory_segment_starts_at_block_0 { + get { + return ResourceManager.GetString("First_directory_segment_starts_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First error block is {0}, last is {1}. + /// + internal static string First_error_block_is_0_last_is_1 { + get { + return ResourceManager.GetString("First_error_block_is_0_last_is_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First error function is "{0}", last is "{1}". + /// + internal static string First_error_function_is_0_last_is_1 { + get { + return ResourceManager.GetString("First_error_function_is_0_last_is_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First error inode is {0}, last is {1}. + /// + internal static string First_error_inode_is_0_last_is_1 { + get { + return ResourceManager.GetString("First_error_inode_is_0_last_is_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First error occurred on {0}, last on {1}. + /// + internal static string First_error_occurred_on_0_last_on_1 { + get { + return ResourceManager.GetString("First_error_occurred_on_0_last_on_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First FAT starts at sector {0} and runs for {1} sectors. + /// + internal static string First_FAT_starts_at_sector_0_and_runs_for_1_sectors { + get { + return ResourceManager.GetString("First_FAT_starts_at_sector_0_and_runs_for_1_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First free block is {0}. + /// + internal static string First_free_block_is_0 { + get { + return ResourceManager.GetString("First_free_block_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First free inode is {0}. + /// + internal static string First_free_inode_is_0 { + get { + return ResourceManager.GetString("First_free_inode_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First inode is {0}. + /// + internal static string First_inode_is_0 { + get { + return ResourceManager.GetString("First_inode_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First kernel zone: {0}. + /// + internal static string First_kernel_zone_0 { + get { + return ResourceManager.GetString("First_kernel_zone_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First metablock group is {0}. + /// + internal static string First_metablock_group_is_0 { + get { + return ResourceManager.GetString("First_metablock_group_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First program to execute at boot: {0}. + /// + internal static string First_program_to_execute_at_boot_0 { + get { + return ResourceManager.GetString("First_program_to_execute_at_boot_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First used block is {0}. + /// + internal static string First_used_block_is_0 { + get { + return ResourceManager.GetString("First_used_block_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to First volume buffer starts at {0}. + /// + internal static string First_volume_buffer_starts_at_0 { + get { + return ResourceManager.GetString("First_volume_buffer_starts_at_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Flags:. + /// + internal static string Flags { + get { + return ResourceManager.GetString("Flags", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Flags: 0x{0:X}. + /// + internal static string Flags_0 { + get { + return ResourceManager.GetString("Flags_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Flags: 0x{0:X8}. + /// + internal static string Flags_0_X8 { + get { + return ResourceManager.GetString("Flags_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Flags…:. + /// + internal static string Flags_ellipsis { + get { + return ResourceManager.GetString("Flags_ellipsis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Flexible block group metadata location (ext4). + /// + internal static string Flexible_block_group_metadata_location_ext4 { + get { + return ResourceManager.GetString("Flexible_block_group_metadata_location_ext4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fossil filesystem. + /// + internal static string Fossil_filesystem { + get { + return ResourceManager.GetString("Fossil_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fossil Filesystem Plugin. + /// + internal static string Fossil_Name { + get { + return ResourceManager.GetString("Fossil_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found Amstrad superblock.. + /// + internal static string Found_Amstrad_superblock { + get { + return ResourceManager.GetString("Found_Amstrad_superblock", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found CP/M-86 floppy identifier.. + /// + internal static string Found_CPM_86_floppy_identifier { + get { + return ResourceManager.GetString("Found_CPM_86_floppy_identifier", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found CP/M-86 hard disk superblock.. + /// + internal static string Found_CPM_86_hard_disk_superblock { + get { + return ResourceManager.GetString("Found_CPM_86_hard_disk_superblock", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found empty filename in {0}. + /// + internal static string Found_empty_filename_in_0 { + get { + return ResourceManager.GetString("Found_empty_filename_in_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found empty filename in root directory. + /// + internal static string Found_empty_filename_in_root_directory { + get { + return ResourceManager.GetString("Found_empty_filename_in_root_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found unknown parameter type {0}. + /// + internal static string Found_unknown_parameter_type_0 { + get { + return ResourceManager.GetString("Found_unknown_parameter_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found unknown supplementary volume descriptor. + /// + internal static string Found_unknown_supplementary_volume_descriptor { + get { + return ResourceManager.GetString("Found_unknown_supplementary_volume_descriptor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fourth {0} partition starts at sector {1}. + /// + internal static string Fourth_0_partition_starts_at_sector_1 { + get { + return ResourceManager.GetString("Fourth_0_partition_starts_at_sector_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Free block list is locked. + /// + internal static string Free_block_list_is_locked { + get { + return ResourceManager.GetString("Free_block_list_is_locked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to fsck in progress. + /// + internal static string fsck_in_progress { + get { + return ResourceManager.GetString("fsck_in_progress", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FST starts at {0} and has {1} bytes. + /// + internal static string FST_starts_at_0_and_has_1_bytes { + get { + return ResourceManager.GetString("FST_starts_at_0_and_has_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Functional version: {0}. + /// + internal static string Functional_version_0 { + get { + return ResourceManager.GetString("Functional_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gamecube. + /// + internal static string Gamecube { + get { + return ResourceManager.GetString("Gamecube", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to German age rating is {0}. + /// + internal static string German_age_rating_is_0 { + get { + return ResourceManager.GetString("German_age_rating_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Global File System number: {0}. + /// + internal static string Global_File_System_number_0 { + get { + return ResourceManager.GetString("Global_File_System_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Global File System pack number {0}. + /// + internal static string Global_File_System_pack_number_0 { + get { + return ResourceManager.GetString("Global_File_System_pack_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Group descriptor checksums and sparse inode table (ext4). + /// + internal static string Group_descriptor_checksums_and_sparse_inode_table_ext4 { + get { + return ResourceManager.GetString("Group_descriptor_checksums_and_sparse_inode_table_ext4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Group descriptor size is {0} bytes. + /// + internal static string Group_descriptor_size_is_0_bytes { + get { + return ResourceManager.GetString("Group_descriptor_size_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Guessed as 42BSD FFS. + /// + internal static string Guessed_as_42BSD_FFS { + get { + return ResourceManager.GetString("Guessed_as_42BSD_FFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Guessed as 43BSD FFS. + /// + internal static string Guessed_as_43BSD_FFS { + get { + return ResourceManager.GetString("Guessed_as_43BSD_FFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Guessed as 44BSD FFS. + /// + internal static string Guessed_as_44BSD_FFS { + get { + return ResourceManager.GetString("Guessed_as_44BSD_FFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Guessed as SunOS FFS. + /// + internal static string Guessed_as_SunOS_FFS { + get { + return ResourceManager.GetString("Guessed_as_SunOS_FFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Guessed as SunOS/x86 FFS. + /// + internal static string Guessed_as_SunOS_x86_FFS { + get { + return ResourceManager.GetString("Guessed_as_SunOS_x86_FFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Guessed as UFS. + /// + internal static string Guessed_as_UFS { + get { + return ResourceManager.GetString("Guessed_as_UFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HAMMER filesystem. + /// + internal static string HAMMER_filesystem { + get { + return ResourceManager.GetString("HAMMER_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HAMMER Filesystem. + /// + internal static string HAMMER_Name { + get { + return ResourceManager.GetString("HAMMER_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hardware sector interleave: {0}. + /// + internal static string Hardware_sector_interleave_0 { + get { + return ResourceManager.GetString("Hardware_sector_interleave_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Has extended attribute blocks. + /// + internal static string Has_extended_attribute_blocks { + get { + return ResourceManager.GetString("Has_extended_attribute_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Has journal (ext3). + /// + internal static string Has_journal_ext3 { + get { + return ResourceManager.GetString("Has_journal_ext3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Has journal on another device (ext3). + /// + internal static string Has_journal_on_another_device_ext3 { + get { + return ResourceManager.GetString("Has_journal_on_another_device_ext3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Has online filesystem resize reservations. + /// + internal static string Has_online_filesystem_resize_reservations { + get { + return ResourceManager.GetString("Has_online_filesystem_resize_reservations", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hash seed: {0:X8}{1:X8}{2:X8}{3:X8}, version {4}. + /// + internal static string Hash_seed_0_1_2_3_version_4 { + get { + return ResourceManager.GetString("Hash_seed_0_1_2_3_version_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Head changes after each whole track. + /// + internal static string Head_changes_after_each_whole_track { + get { + return ResourceManager.GetString("Head_changes_after_each_whole_track", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Head changes after whole side. + /// + internal static string Head_changes_after_whole_side { + get { + return ResourceManager.GetString("Head_changes_after_whole_side", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Heap size with 128KiB of RAM: {0} bytes. + /// + internal static string Heap_size_with_128KiB_of_RAM_0_bytes { + get { + return ResourceManager.GetString("Heap_size_with_128KiB_of_RAM_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Heap size with 256KiB of RAM: {0} bytes. + /// + internal static string Heap_size_with_256KiB_of_RAM_0_bytes { + get { + return ResourceManager.GetString("Heap_size_with_256KiB_of_RAM_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Heap size with 512KiB of RAM or more: {0} bytes. + /// + internal static string Heap_size_with_512KiB_of_RAM_or_more_0_bytes { + get { + return ResourceManager.GetString("Heap_size_with_512KiB_of_RAM_or_more_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HFS+ filesystem.. + /// + internal static string HFS_filesystem { + get { + return ResourceManager.GetString("HFS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HFS uses 512 bytes/sector while device uses 2048 bytes/sector.. + /// + internal static string HFS_uses_512_bytes_sector_while_device_uses_2048_bytes_sector { + get { + return ResourceManager.GetString("HFS_uses_512_bytes_sector_while_device_uses_2048_bytes_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HFSX filesystem.. + /// + internal static string HFSX_filesystem { + get { + return ResourceManager.GetString("HFSX_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to High Sierra Format file system. + /// + internal static string High_Sierra_Format_file_system { + get { + return ResourceManager.GetString("High_Sierra_Format_file_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Highest structure in the volume is Level {0}, revision {1}. + /// + internal static string Highest_structure_in_the_volume_is_Level_0_revision_1 { + get { + return ResourceManager.GetString("Highest_structure_in_the_volume_is_Level_0_revision_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Highwater mark is to be disabled. + /// + internal static string Highwater_mark_is_to_be_disabled { + get { + return ResourceManager.GetString("Highwater_mark_is_to_be_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hotfixes are in use. + /// + internal static string Hotfixes_are_in_use { + get { + return ResourceManager.GetString("Hotfixes_are_in_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Logical Interchange Format. + /// + internal static string HP_Logical_Interchange_Format { + get { + return ResourceManager.GetString("HP_Logical_Interchange_Format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OS/2 High Performance File System. + /// + internal static string HPFS_Name { + get { + return ResourceManager.GetString("HPFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HPFS version: {0}. + /// + internal static string HPFS_version_0 { + get { + return ResourceManager.GetString("HPFS_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to High Performance Optical File System. + /// + internal static string HPOFS_Name { + get { + return ResourceManager.GetString("HPOFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Human68k FAT12. + /// + internal static string Human68k_FAT12 { + get { + return ResourceManager.GetString("Human68k_FAT12", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Human68k FAT16. + /// + internal static string Human68k_FAT16 { + get { + return ResourceManager.GetString("Human68k_FAT16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will try to guess which one it is, but unless it's UFS2, I may be surely wrong. + /// + internal static string I_will_try_to_guess_which_one_it_is_but_unless_its_UFS2_I_may_be_surely_wrong { + get { + return ResourceManager.GetString("I_will_try_to_guess_which_one_it_is_but_unless_its_UFS2_I_may_be_surely_wrong", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ID: {0}, version {1}. + /// + internal static string ID_0_version_1 { + get { + return ResourceManager.GetString("ID_0_version_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identified as {0}. + /// + internal static string Identified_as_0 { + get { + return ResourceManager.GetString("Identified_as_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identifier: {0}. + /// + internal static string Identifier_0 { + get { + return ResourceManager.GetString("Identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image contains ATAPI drivers. + /// + internal static string Image_contains_ATAPI_drivers { + get { + return ResourceManager.GetString("Image_contains_ATAPI_drivers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image contains SCSI drivers. + /// + internal static string Image_contains_SCSI_drivers { + get { + return ResourceManager.GetString("Image_contains_SCSI_drivers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image emulates a 3.5" extra-density (MF2ED, 2.88Mb) floppy. + /// + internal static string Image_emulates_a_extra_density_MF2ED_floppy { + get { + return ResourceManager.GetString("Image_emulates_a_extra_density_MF2ED_floppy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image emulates a 5.25" high-density (MD2HD, 1.2Mb) floppy. + /// + internal static string Image_emulates_a_high_density_MD2HD_floppy { + get { + return ResourceManager.GetString("Image_emulates_a_high_density_MD2HD_floppy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image emulates a 3.5" high-density (MF2HD, 1.44Mb) floppy. + /// + internal static string Image_emulates_a_high_density_MF2HD_floppy { + get { + return ResourceManager.GetString("Image_emulates_a_high_density_MF2HD_floppy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image uses no emulation. + /// + internal static string Image_uses_no_emulation { + get { + return ResourceManager.GetString("Image_uses_no_emulation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image uses unknown emulation type {0}. + /// + internal static string Image_uses_unknown_emulation_type_0 { + get { + return ResourceManager.GetString("Image_uses_unknown_emulation_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Has mapping between inodes and AFS (imagic inodes table). + /// + internal static string imagic_inodes__ { + get { + return ResourceManager.GetString("imagic_inodes__", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Implementation that last mounted the volume: "{0}".. + /// + internal static string Implementation_that_last_mounted_the_volume_0 { + get { + return ResourceManager.GetString("Implementation_that_last_mounted_the_volume_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incompatible features…:. + /// + internal static string Incompatible_features { + get { + return ResourceManager.GetString("Incompatible_features", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incompatible flags: 0x{0:X}. + /// + internal static string Incompatible_flags_0 { + get { + return ResourceManager.GetString("Incompatible_flags_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incompletely initialized big-endian UFS filesystem. + /// + internal static string Incompletely_initialized_big_endian_UFS_filesystem { + get { + return ResourceManager.GetString("Incompletely_initialized_big_endian_UFS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incompletely initialized UFS filesystem. + /// + internal static string Incompletely_initialized_UFS_filesystem { + get { + return ResourceManager.GetString("Incompletely_initialized_UFS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect device size.. + /// + internal static string Incorrect_device_size { + get { + return ResourceManager.GetString("Incorrect_device_size", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect MDDF found. + /// + internal static string Incorrect_MDDF_found { + get { + return ResourceManager.GetString("Incorrect_MDDF_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect sector size.. + /// + internal static string Incorrect_sector_size { + get { + return ResourceManager.GetString("Incorrect_sector_size", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Indices' i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes). + /// + internal static string Indices_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes { + get { + return ResourceManager.GetString("Indices_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_b" + + "ytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Indices' i-node size: {0} blocks (Should be 1). + /// + internal static string Indices_i_node_size_0_blocks_Should_be_one { + get { + return ResourceManager.GetString("Indices_i_node_size_0_blocks_Should_be_one", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Initial entry:. + /// + internal static string Initial_entry { + get { + return ResourceManager.GetString("Initial_entry", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to inode-block LBA: {0}. + /// + internal static string inode_block_LBA_0 { + get { + return ResourceManager.GetString("inode_block_LBA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to inode cache is locked. + /// + internal static string inode_cache_is_locked { + get { + return ResourceManager.GetString("inode_cache_is_locked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I-node list uses {0} blocks. + /// + internal static string Inode_list_uses_0_blocks { + get { + return ResourceManager.GetString("Inode_list_uses_0_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to INOPB: 0x{0:X8}. + /// + internal static string INOPB_0 { + get { + return ResourceManager.GetString("INOPB_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Install DASD limits. + /// + internal static string Install_DASD_limits { + get { + return ResourceManager.GetString("Install_DASD_limits", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ISO9660 file system. + /// + internal static string ISO9660_file_system { + get { + return ResourceManager.GetString("ISO9660_file_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Japan age rating is {0}. + /// + internal static string Japan_age_rating_is_0 { + get { + return ResourceManager.GetString("Japan_age_rating_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to JFS filesystem. + /// + internal static string JFS_filesystem { + get { + return ResourceManager.GetString("JFS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to JFS Plugin. + /// + internal static string JFS_Name { + get { + return ResourceManager.GetString("JFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Joliet extensions present.. + /// + internal static string Joliet_extensions_present { + get { + return ResourceManager.GetString("Joliet_extensions_present", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to JOLIET VOLUME DESCRIPTOR INFORMATION:. + /// + internal static string JOLIET_VOLUME_DESCRIPTOR_INFORMATION { + get { + return ResourceManager.GetString("JOLIET_VOLUME_DESCRIPTOR_INFORMATION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to -------------------------------------. + /// + internal static string JOLIET_VOLUME_DESCRIPTOR_INFORMATION_border { + get { + return ResourceManager.GetString("JOLIET_VOLUME_DESCRIPTOR_INFORMATION_border", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Journal backup type: {0}. + /// + internal static string Journal_backup_type_0 { + get { + return ResourceManager.GetString("Journal_backup_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (journal_data): Journal data and metadata. + /// + internal static string journal_data_Journal_data_and_metadata { + get { + return ResourceManager.GetString("journal_data_Journal_data_and_metadata", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (journal_data_ordered): Write data before journaling metadata. + /// + internal static string journal_data_ordered_Write_data_before_journaling_metadata { + get { + return ResourceManager.GetString("journal_data_ordered_Write_data_before_journaling_metadata", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (journal_data_writeback): Write journal before data. + /// + internal static string journal_data_writeback_Write_journal_before_data { + get { + return ResourceManager.GetString("journal_data_writeback_Write_journal_before_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Journal has inode {0}. + /// + internal static string Journal_has_inode_0 { + get { + return ResourceManager.GetString("Journal_has_inode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Journal is on device {0}. + /// + internal static string Journal_is_on_device_0 { + get { + return ResourceManager.GetString("Journal_is_on_device_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Journal needs recovery (ext3). + /// + internal static string Journal_needs_recovery_ext3 { + get { + return ResourceManager.GetString("Journal_needs_recovery_ext3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Journal resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes). + /// + internal static string Journal_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes { + get { + return ResourceManager.GetString("Journal_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Journal starts at allocation block {0}.. + /// + internal static string Journal_starts_at_allocation_block_0 { + get { + return ResourceManager.GetString("Journal_starts_at_allocation_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Journal starts in byte {0} and ends in byte {1}. + /// + internal static string Journal_starts_in_byte_0_and_ends_in_byte_1 { + get { + return ResourceManager.GetString("Journal_starts_in_byte_0_and_ends_in_byte_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Journal starts in byte {0} and has {1} bytes in {2} blocks. + /// + internal static string Journal_starts_in_byte_0_and_has_1_bytes_in_2_blocks { + get { + return ResourceManager.GetString("Journal_starts_in_byte_0_and_has_1_bytes_in_2_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Journal UUID: {0}. + /// + internal static string Journal_UUID_0 { + get { + return ResourceManager.GetString("Journal_UUID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Korea age rating is {0}. + /// + internal static string Korea_age_rating_is_0 { + get { + return ResourceManager.GetString("Korea_age_rating_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Labels resides in block {0}. + /// + internal static string Labels_resides_in_block_0 { + get { + return ResourceManager.GetString("Labels_resides_in_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last allocated cluster {0}. + /// + internal static string Last_allocated_cluster_0 { + get { + return ResourceManager.GetString("Last_allocated_cluster_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last backup date: {0}. + /// + internal static string Last_backup_date_0 { + get { + return ResourceManager.GetString("Last_backup_date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last check date: {0}. + /// + internal static string Last_check_date_0 { + get { + return ResourceManager.GetString("Last_check_date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last checked on {0}. + /// + internal static string Last_checked_on_0 { + get { + return ResourceManager.GetString("Last_checked_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last checked on {0} (should check every {1} seconds). + /// + internal static string Last_checked_on_0_should_check_every_1_seconds { + get { + return ResourceManager.GetString("Last_checked_on_0_should_check_every_1_seconds", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last inode allocated: {0}. + /// + internal static string Last_inode_allocated_0 { + get { + return ResourceManager.GetString("Last_inode_allocated_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last modification date: {0}. + /// + internal static string Last_modification_date_0 { + get { + return ResourceManager.GetString("Last_modification_date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last mounted at: "{0}". + /// + internal static string Last_mounted_at_0 { + get { + return ResourceManager.GetString("Last_mounted_at_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last mounted on {0}. + /// + internal static string Last_mounted_on_0 { + get { + return ResourceManager.GetString("Last_mounted_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last orphaned inode is {0}. + /// + internal static string Last_orphaned_inode_is_0 { + get { + return ResourceManager.GetString("Last_orphaned_inode_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last root directory copy: {0}. + /// + internal static string Last_root_directory_copy_0 { + get { + return ResourceManager.GetString("Last_root_directory_copy_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last searched cylinder group: {0}. + /// + internal static string Last_searched_cylinder_group_0 { + get { + return ResourceManager.GetString("Last_searched_cylinder_group_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last used mount options were: {0}. + /// + internal static string Last_used_mount_options_were_0 { + get { + return ResourceManager.GetString("Last_used_mount_options_were_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last written on {0}. + /// + internal static string Last_written_on_0 { + get { + return ResourceManager.GetString("Last_written_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LIF identifier: {0}. + /// + internal static string LIF_identifier_0 { + get { + return ResourceManager.GetString("LIF_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HP Logical Interchange Format Plugin. + /// + internal static string LIF_Name { + get { + return ResourceManager.GetString("LIF_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LIF version: {0}. + /// + internal static string LIF_version_0 { + get { + return ResourceManager.GetString("LIF_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Linked list of filesystems: 0x{0:X8}. + /// + internal static string Linked_list_of_filesystems_0 { + get { + return ResourceManager.GetString("Linked_list_of_filesystems_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Little-endian. + /// + internal static string Little_endian { + get { + return ResourceManager.GetString("Little_endian", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Little-endian BeFS. + /// + internal static string Little_endian_BeFS { + get { + return ResourceManager.GetString("Little_endian_BeFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Load {0} sectors from sector {1}. + /// + internal static string Load_0_sectors_from_sector_1 { + get { + return ResourceManager.GetString("Load_0_sectors_from_sector_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Load at 0x{0:X8} and jump to 0x{1:X8}. + /// + internal static string Load_at_0_and_jump_to_1 { + get { + return ResourceManager.GetString("Load_at_0_and_jump_to_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Locus filesystem. + /// + internal static string Locus_filesystem { + get { + return ResourceManager.GetString("Locus_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Locus filesystem (old). + /// + internal static string Locus_filesystem_old { + get { + return ResourceManager.GetString("Locus_filesystem_old", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Locus Filesystem Plugin. + /// + internal static string Locus_Name { + get { + return ResourceManager.GetString("Locus_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Log tree starts at LBA {0}. + /// + internal static string Log_tree_starts_at_LBA_0 { + get { + return ResourceManager.GetString("Log_tree_starts_at_LBA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Log zone size: {0}. + /// + internal static string Log_zone_size_0 { + get { + return ResourceManager.GetString("Log_zone_size_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Long file names. + /// + internal static string Long_file_names { + get { + return ResourceManager.GetString("Long_file_names", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lowest structure in the volume is Level {0}, revision {1}. + /// + internal static string Lowest_structure_in_the_volume_is_Level_0_revision_1 { + get { + return ResourceManager.GetString("Lowest_structure_in_the_volume_is_Level_0_revision_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mac OS X Volume ID: {0:X8}{1:X8}. + /// + internal static string Mac_OS_X_Volume_ID_0_1 { + get { + return ResourceManager.GetString("Mac_OS_X_Volume_ID_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to magic: "{0}". + /// + internal static string magic_0 { + get { + return ResourceManager.GetString("magic_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to magic 0x{0:X8} (expected 0x{1:X8}). + /// + internal static string magic_0_expected_1 { + get { + return ResourceManager.GetString("magic_0_expected_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to magic at {0} = 0x{1:X8} (expected 0x{2:X8}). + /// + internal static string magic_at_0_equals_1_expected_2 { + get { + return ResourceManager.GetString("magic_at_0_equals_1_expected_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to magic at {0} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8}). + /// + internal static string magic_at_0_equals_1_expected_2_or_3 { + get { + return ResourceManager.GetString("magic_at_0_equals_1_expected_2_or_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to magic at {0} = 0x{1:X8} or 0x{2:X8} (expected 0x{3:X8} or 0x{4:X8}). + /// + internal static string magic_at_0_equals_1_or_2_expected_3_or_4 { + get { + return ResourceManager.GetString("magic_at_0_equals_1_or_2_expected_3_or_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to magic at 0x{0:X8} (expected 0x{1:X8}). + /// + internal static string magic_at_0_expected_1 { + get { + return ResourceManager.GetString("magic_at_0_expected_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8}). + /// + internal static string magic_at_0_X3_equals_1_expected_2 { + get { + return ResourceManager.GetString("magic_at_0_X3_equals_1_expected_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8}). + /// + internal static string magic_at_0_X3_equals_1_expected_2_or_3 { + get { + return ResourceManager.GetString("magic_at_0_X3_equals_1_expected_2_or_3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to magic at {1} = 0x{0:X8}. + /// + internal static string magic_at_1_equals_0 { + get { + return ResourceManager.GetString("magic_at_1_equals_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to magic = 0x{0:X16} (expected 0x{1:X16}). + /// + internal static string magic_equals_0_expected_1 { + get { + return ResourceManager.GetString("magic_equals_0_expected_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Magic 1: 0x{0:X8} (Should be 0x42465331). + /// + internal static string Magic_one_0_Should_be_0x42465331 { + get { + return ResourceManager.GetString("Magic_one_0_Should_be_0x42465331", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Magic 3: 0x{0:X8} (Should be 0x15B6830E). + /// + internal static string Magic_three_0_Should_be_0x15B6830E { + get { + return ResourceManager.GetString("Magic_three_0_Should_be_0x15B6830E", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Magic 2: 0x{0:X8} (Should be 0xDD121031). + /// + internal static string Magic_two_0_Should_be_0xDD121031 { + get { + return ResourceManager.GetString("Magic_two_0_Should_be_0xDD121031", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maker ID: {0}. + /// + internal static string Maker_ID_0 { + get { + return ResourceManager.GetString("Maker_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maker name: {0}. + /// + internal static string Maker_name_0 { + get { + return ResourceManager.GetString("Maker_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Master copy ID: 0x{0:X8}. + /// + internal static string Master_copy_ID_0 { + get { + return ResourceManager.GetString("Master_copy_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Master Directory Block:. + /// + internal static string Master_Directory_Block { + get { + return ResourceManager.GetString("Master_Directory_Block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Master System Virtual Console. + /// + internal static string Master_System_Virtual_Console { + get { + return ResourceManager.GetString("Master_System_Virtual_Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Max zone size: {0}. + /// + internal static string Max_zone_size_0 { + get { + return ResourceManager.GetString("Max_zone_size_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum filesize is {0} bytes ({1} MiB). + /// + internal static string Maximum_filesize_is_0_bytes_1_MiB { + get { + return ResourceManager.GetString("Maximum_filesize_is_0_bytes_1_MiB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum length of a symbolic link: {0}. + /// + internal static string Maximum_length_of_a_symbolic_link_0 { + get { + return ResourceManager.GetString("Maximum_length_of_a_symbolic_link_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum opened files: {0}. + /// + internal static string Maximum_opened_files_0 { + get { + return ResourceManager.GetString("Maximum_opened_files_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MDDF is in block {0}. + /// + internal static string MDDF_is_in_block_0 { + get { + return ResourceManager.GetString("MDDF_is_in_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Media descriptor: 0x{0:X2}. + /// + internal static string Media_descriptor_0 { + get { + return ResourceManager.GetString("Media_descriptor_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mega Drive Virtual Console. + /// + internal static string Megadrive_Virtual_Console { + get { + return ResourceManager.GetString("Megadrive_Virtual_Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Memory log starts at {0}. + /// + internal static string Memory_log_starts_at_0 { + get { + return ResourceManager.GetString("Memory_log_starts_at_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MicroDOS filesystem. + /// + internal static string MicroDOS_filesystem { + get { + return ResourceManager.GetString("MicroDOS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MicroDOS file system. + /// + internal static string MicroDOS_Name { + get { + return ResourceManager.GetString("MicroDOS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Microsoft exFAT. + /// + internal static string Microsoft_exFAT { + get { + return ResourceManager.GetString("Microsoft_exFAT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Microsoft FAT12. + /// + internal static string Microsoft_FAT12 { + get { + return ResourceManager.GetString("Microsoft_FAT12", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Microsoft FAT16. + /// + internal static string Microsoft_FAT16 { + get { + return ResourceManager.GetString("Microsoft_FAT16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Microsoft FAT32. + /// + internal static string Microsoft_FAT32 { + get { + return ResourceManager.GetString("Microsoft_FAT32", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Microsoft Resilient File System. + /// + internal static string Microsoft_Resilient_File_System { + get { + return ResourceManager.GetString("Microsoft_Resilient_File_System", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Minix 3 v1 filesystem. + /// + internal static string Minix_3_v1_filesystem { + get { + return ResourceManager.GetString("Minix_3_v1_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Minix 3 v2 filesystem. + /// + internal static string Minix_3_v2_filesystem { + get { + return ResourceManager.GetString("Minix_3_v2_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Minix v1 filesystem. + /// + internal static string Minix_v1_filesystem { + get { + return ResourceManager.GetString("Minix_v1_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Minix v2 filesystem. + /// + internal static string Minix_v2_filesystem { + get { + return ResourceManager.GetString("Minix_v2_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Minix v3 filesystem. + /// + internal static string Minix_v3_filesystem { + get { + return ResourceManager.GetString("Minix_v3_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Minix Filesystem. + /// + internal static string MinixFS_Name { + get { + return ResourceManager.GetString("MinixFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to More than 32000 directory entries (ext4). + /// + internal static string More_than_32000_directory_entries_ext4 { + get { + return ResourceManager.GetString("More_than_32000_directory_entries_ext4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mounting LisaFS v1. + /// + internal static string Mounting_LisaFS_v1 { + get { + return ResourceManager.GetString("Mounting_LisaFS_v1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mounting LisaFS v2. + /// + internal static string Mounting_LisaFS_v2 { + get { + return ResourceManager.GetString("Mounting_LisaFS_v2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mounting LisaFS v3. + /// + internal static string Mounting_LisaFS_v3 { + get { + return ResourceManager.GetString("Mounting_LisaFS_v3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MSX Virtual Console or WiiWare demo. + /// + internal static string MSX_Virtual_Console_or_WiiWare_demo { + get { + return ResourceManager.GetString("MSX_Virtual_Console_or_WiiWare_demo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multi-mount protection (ext4). + /// + internal static string Multi_mount_protection_ext4 { + get { + return ResourceManager.GetString("Multi_mount_protection_ext4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multimedia is active. + /// + internal static string Multimedia_is_active { + get { + return ResourceManager.GetString("Multimedia_is_active", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Apple Hierarchical File System. + /// + internal static string Name_Apple_Hierarchical_File_System { + get { + return ResourceManager.GetString("Name_Apple_Hierarchical_File_System", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Neo-Geo Virtual Console. + /// + internal static string Neo_Geo_Virtual_Console { + get { + return ResourceManager.GetString("Neo_Geo_Virtual_Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NES Virtual Console. + /// + internal static string NES_Virtual_Console { + get { + return ResourceManager.GetString("NES_Virtual_Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New version. + /// + internal static string New_version { + get { + return ResourceManager.GetString("New_version", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Next allocation block: {0}.. + /// + internal static string Next_allocation_block_0 { + get { + return ResourceManager.GetString("Next_allocation_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Next free inode search will start at inode {0}. + /// + internal static string Next_free_inode_search_will_start_at_inode_0 { + get { + return ResourceManager.GetString("Next_free_inode_search_will_start_at_inode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Next QID {0}. + /// + internal static string Next_QID_0 { + get { + return ResourceManager.GetString("Next_QID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Next root block {0}. + /// + internal static string Next_root_block_0 { + get { + return ResourceManager.GetString("Next_root_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Next unused CNID: {0}. + /// + internal static string Next_unused_CNID_0 { + get { + return ResourceManager.GetString("Next_unused_CNID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Next unused file number: {0}. + /// + internal static string Next_unused_file_number_0 { + get { + return ResourceManager.GetString("Next_unused_file_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NFS volume. + /// + internal static string NFS_volume { + get { + return ResourceManager.GetString("NFS_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NILFS2 filesystem. + /// + internal static string NILFS2_filesystem { + get { + return ResourceManager.GetString("NILFS2_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NILFS2 Plugin. + /// + internal static string NILFS2_Name { + get { + return ResourceManager.GetString("NILFS2_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NINDIR: 0x{0:X8}. + /// + internal static string NINDIR_0 { + get { + return ResourceManager.GetString("NINDIR_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nintendo 64 Virtual Console. + /// + internal static string Nintendo_64_Virtual_Console { + get { + return ResourceManager.GetString("Nintendo_64_Virtual_Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nintendo GameCube Optical Disc. + /// + internal static string Nintendo_GameCube_Optical_Disc { + get { + return ResourceManager.GetString("Nintendo_GameCube_Optical_Disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nintendo optical filesystem. + /// + internal static string Nintendo_optical_filesystem { + get { + return ResourceManager.GetString("Nintendo_optical_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nintendo Wii Optical Disc. + /// + internal static string Nintendo_Wii_Optical_Disc { + get { + return ResourceManager.GetString("Nintendo_Wii_Optical_Disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nintendo optical filesystems. + /// + internal static string NintendoPlugin_Name { + get { + return ResourceManager.GetString("NintendoPlugin_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to any region. + /// + internal static string NintendoPlugin_RegionCodeToString_any_region { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_any_region", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Australia. + /// + internal static string NintendoPlugin_RegionCodeToString_Australia { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_Australia", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to France. + /// + internal static string NintendoPlugin_RegionCodeToString_France { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_France", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Germany. + /// + internal static string NintendoPlugin_RegionCodeToString_Germany { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_Germany", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Italy. + /// + internal static string NintendoPlugin_RegionCodeToString_Italy { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_Italy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Japan. + /// + internal static string NintendoPlugin_RegionCodeToString_Japan { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_Japan", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Korea. + /// + internal static string NintendoPlugin_RegionCodeToString_Korea { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_Korea", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PAL. + /// + internal static string NintendoPlugin_RegionCodeToString_PAL { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_PAL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Russia. + /// + internal static string NintendoPlugin_RegionCodeToString_Russia { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_Russia", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Spain. + /// + internal static string NintendoPlugin_RegionCodeToString_Spain { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_Spain", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Taiwan. + /// + internal static string NintendoPlugin_RegionCodeToString_Taiwan { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_Taiwan", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown region code '{0}'. + /// + internal static string NintendoPlugin_RegionCodeToString_unknown_region_code_0 { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_unknown_region_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to USA. + /// + internal static string NintendoPlugin_RegionCodeToString_USA { + get { + return ResourceManager.GetString("NintendoPlugin_RegionCodeToString_USA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not a Lisa filesystem. + /// + internal static string Not_a_Lisa_filesystem { + get { + return ResourceManager.GetString("Not_a_Lisa_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not a UFS filesystem, I shouldn't have arrived here!. + /// + internal static string Not_a_UFS_filesystem_I_shouldnt_have_arrived_here { + get { + return ResourceManager.GetString("Not_a_UFS_filesystem_I_shouldnt_have_arrived_here", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not an ext2/3/4 filesystem. + /// + internal static string Not_an_ext2_3_4_filesystem { + get { + return ResourceManager.GetString("Not_an_ext2_3_4_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not bootable. + /// + internal static string Not_bootable { + get { + return ResourceManager.GetString("Not_bootable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NSPF: 0x{0:X8}. + /// + internal static string NSPF_0 { + get { + return ResourceManager.GetString("NSPF_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NT Flags: 0x{0:X2}. + /// + internal static string NT_Flags_0 { + get { + return ResourceManager.GetString("NT_Flags_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New Technology File System (NTFS). + /// + internal static string NTFS_Name { + get { + return ResourceManager.GetString("NTFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Files-11 On-Disk Structure. + /// + internal static string ODS_Name { + get { + return ResourceManager.GetString("ODS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OEM name: {0}. + /// + internal static string OEM_name_0 { + get { + return ResourceManager.GetString("OEM_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OEM Parameters: {0}. + /// + internal static string OEM_Parameters_0 { + get { + return ResourceManager.GetString("OEM_Parameters_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Old 16-bit dump(8). + /// + internal static string Old_16_bit_dump_8 { + get { + return ResourceManager.GetString("Old_16_bit_dump_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On-disk filesystem version: {0}. + /// + internal static string On_disk_filesystem_version_0 { + get { + return ResourceManager.GetString("On_disk_filesystem_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On errors, filesystem should continue. + /// + internal static string On_errors_filesystem_should_continue { + get { + return ResourceManager.GetString("On_errors_filesystem_should_continue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On errors, filesystem should panic. + /// + internal static string On_errors_filesystem_should_panic { + get { + return ResourceManager.GetString("On_errors_filesystem_should_panic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On errors, filesystem should remount read-only. + /// + internal static string On_errors_filesystem_should_remount_read_only { + get { + return ResourceManager.GetString("On_errors_filesystem_should_remount_read_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On errors filesystem will do an unknown thing ({0}). + /// + internal static string On_errors_filesystem_will_do_an_unknown_thing_0 { + get { + return ResourceManager.GetString("On_errors_filesystem_will_do_an_unknown_thing_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Opera filesystem disc.. + /// + internal static string Opera_filesystem_disc { + get { + return ResourceManager.GetString("Opera_filesystem_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Opera Filesystem Plugin. + /// + internal static string OperaFS_Name { + get { + return ResourceManager.GetString("OperaFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OS-9 Random Block File. + /// + internal static string OS_9_Random_Block_File { + get { + return ResourceManager.GetString("OS_9_Random_Block_File", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OS/2 .LONGNAME extended attribute. + /// + internal static string OS2_LONGNAME_extended_attribute { + get { + return ResourceManager.GetString("OS2_LONGNAME_extended_attribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Overmount stamp: 0x{0:X16}. + /// + internal static string Overmount_stamp_0 { + get { + return ResourceManager.GetString("Overmount_stamp_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pack name: {0}. + /// + internal static string Pack_name_0 { + get { + return ResourceManager.GetString("Pack_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partition offset: {0}. + /// + internal static string Partition_offset_0 { + get { + return ResourceManager.GetString("Partition_offset_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Partitions are not supported.. + /// + internal static string Partitions_are_not_supported { + get { + return ResourceManager.GetString("Partitions_are_not_supported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to U.C.S.D. Pascal filesystem. + /// + internal static string PascalPlugin_Name { + get { + return ResourceManager.GetString("PascalPlugin_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Path descriptor options: {0}. + /// + internal static string Path_descriptor_options_0 { + get { + return ResourceManager.GetString("Path_descriptor_options_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Path table and PVD do not point to the same location for the root directory!. + /// + internal static string Path_table_and_PVD_do_not_point_to_the_same_location_for_the_root_directory { + get { + return ResourceManager.GetString("Path_table_and_PVD_do_not_point_to_the_same_location_for_the_root_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PC-FX executable:. + /// + internal static string PC_FX_executable { + get { + return ResourceManager.GetString("PC_FX_executable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PC Engine CD Plugin. + /// + internal static string PCEnginePlugin_Name { + get { + return ResourceManager.GetString("PCEnginePlugin_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PC-FX Plugin. + /// + internal static string PCFX_Name { + get { + return ResourceManager.GetString("PCFX_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PEGI age rating is {0}. + /// + internal static string PEGI_age_rating_is_0 { + get { + return ResourceManager.GetString("PEGI_age_rating_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Professional File System. + /// + internal static string PFS_Name { + get { + return ResourceManager.GetString("PFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Physical volume name: {0}. + /// + internal static string Physical_volume_name_0 { + get { + return ResourceManager.GetString("Physical_volume_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Portugal age rating is {0}. + /// + internal static string Portugal_age_rating_is_0 { + get { + return ResourceManager.GetString("Portugal_age_rating_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pre-allocate directories. + /// + internal static string Pre_allocate_directories { + get { + return ResourceManager.GetString("Pre_allocate_directories", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Previous dump created on {0}. + /// + internal static string Previous_dump_created_on_0 { + get { + return ResourceManager.GetString("Previous_dump_created_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Processing VD loop no. {0}. + /// + internal static string Processing_VD_loop_no_0 { + get { + return ResourceManager.GetString("Processing_VD_loop_no_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ProDOS uses 512 bytes/sector while device uses 2048 bytes/sector.. + /// + internal static string ProDOS_uses_512_bytes_sector_while_device_uses_2048_bytes_sector { + get { + return ResourceManager.GetString("ProDOS_uses_512_bytes_sector_while_device_uses_2048_bytes_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ProDOS version 1 at least required for reading this volume.. + /// + internal static string ProDOS_version_one_at_least_required_for_reading_this_volume { + get { + return ResourceManager.GetString("ProDOS_version_one_at_least_required_for_reading_this_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ProDOS version 1 used to create this volume.. + /// + internal static string ProDOS_version_one_used_to_create_this_volume { + get { + return ResourceManager.GetString("ProDOS_version_one_used_to_create_this_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Apple ProDOS filesystem. + /// + internal static string ProDOSPlugin_Name { + get { + return ResourceManager.GetString("ProDOSPlugin_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Professional File System v1. + /// + internal static string Professional_File_System_v1 { + get { + return ResourceManager.GetString("Professional_File_System_v1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Professional File System v2. + /// + internal static string Professional_File_System_v2 { + get { + return ResourceManager.GetString("Professional_File_System_v2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Professional File System v3. + /// + internal static string Professional_File_System_v3 { + get { + return ResourceManager.GetString("Professional_File_System_v3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Promotional or TurboGrafx Virtual Console. + /// + internal static string Promotional_or_TurboGrafx_Virtual_Console { + get { + return ResourceManager.GetString("Promotional_or_TurboGrafx_Virtual_Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Published by {0}. + /// + internal static string Published_by_0 { + get { + return ResourceManager.GetString("Published_by_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Publisher identifier: {0}. + /// + internal static string Publisher_identifier_0 { + get { + return ResourceManager.GetString("Publisher_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PVD does not point to correct root directory, checking path table.... + /// + internal static string PVD_does_not_point_to_correct_root_directory_checking_path_table { + get { + return ResourceManager.GetString("PVD_does_not_point_to_correct_root_directory_checking_path_table", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to QNX4 filesystem. + /// + internal static string QNX4_filesystem { + get { + return ResourceManager.GetString("QNX4_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to QNX4 Plugin. + /// + internal static string QNX4_Name { + get { + return ResourceManager.GetString("QNX4_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to QNX6 (Audi) filesystem. + /// + internal static string QNX6_Audi_filesystem { + get { + return ResourceManager.GetString("QNX6_Audi_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to QNX6 filesystem. + /// + internal static string QNX6_filesystem { + get { + return ResourceManager.GetString("QNX6_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to QNX6 Plugin. + /// + internal static string QNX6_Name { + get { + return ResourceManager.GetString("QNX6_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to RAID stride: {0}. + /// + internal static string RAID_stride_0 { + get { + return ResourceManager.GetString("RAID_stride_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OS-9 Random Block File Plugin. + /// + internal static string RBF_Name { + get { + return ResourceManager.GetString("RBF_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read-only compatible flags: 0x{0:X}. + /// + internal static string Read_only_compatible_flags_0 { + get { + return ResourceManager.GetString("Read_only_compatible_flags_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read-only volume. + /// + internal static string Read_only_volume { + get { + return ResourceManager.GetString("Read_only_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reading BPB. + /// + internal static string Reading_BPB { + get { + return ResourceManager.GetString("Reading_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reading directory.. + /// + internal static string Reading_directory { + get { + return ResourceManager.GetString("Reading_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reading FAT12. + /// + internal static string Reading_FAT12 { + get { + return ResourceManager.GetString("Reading_FAT12", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reading FAT16. + /// + internal static string Reading_FAT16 { + get { + return ResourceManager.GetString("Reading_FAT16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reading FAT32. + /// + internal static string Reading_FAT32 { + get { + return ResourceManager.GetString("Reading_FAT32", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reading root directory. + /// + internal static string Reading_root_directory { + get { + return ResourceManager.GetString("Reading_root_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reading sector {0}. + /// + internal static string Reading_sector_0 { + get { + return ResourceManager.GetString("Reading_sector_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reading superblock. + /// + internal static string Reading_superblock { + get { + return ResourceManager.GetString("Reading_superblock", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Readings should be verified. + /// + internal static string Readings_should_be_verified { + get { + return ResourceManager.GetString("Readings_should_be_verified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Record protection: 0x{0:X4}. + /// + internal static string Record_protection_0 { + get { + return ResourceManager.GetString("Record_protection_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reduced block group backups. + /// + internal static string Reduced_block_group_backups { + get { + return ResourceManager.GetString("Reduced_block_group_backups", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reduced number of superblocks. + /// + internal static string Reduced_number_of_superblocks { + get { + return ResourceManager.GetString("Reduced_number_of_superblocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Resilient File System plugin. + /// + internal static string ReFS_Name { + get { + return ResourceManager.GetString("ReFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reiser 3.5 filesystem. + /// + internal static string Reiser_3_5_filesystem { + get { + return ResourceManager.GetString("Reiser_3_5_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reiser 3.6 filesystem. + /// + internal static string Reiser_3_6_filesystem { + get { + return ResourceManager.GetString("Reiser_3_6_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reiser 4 filesystem. + /// + internal static string Reiser_4_filesystem { + get { + return ResourceManager.GetString("Reiser_4_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reiser Jr. filesystem. + /// + internal static string Reiser_Jr_filesystem { + get { + return ResourceManager.GetString("Reiser_Jr_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reiser Filesystem Plugin. + /// + internal static string Reiser_Name { + get { + return ResourceManager.GetString("Reiser_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reiser4 Filesystem Plugin. + /// + internal static string Reiser4_Name { + get { + return ResourceManager.GetString("Reiser4_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removable volume. + /// + internal static string Removable_volume { + get { + return ResourceManager.GetString("Removable_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Replacement superblock resides at block {0}. + /// + internal static string Replacement_superblock_resides_at_block_0 { + get { + return ResourceManager.GetString("Replacement_superblock_resides_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Replicated volume. + /// + internal static string Replicated_volume { + get { + return ResourceManager.GetString("Replicated_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reserved attributes are set: {0:X2}. + /// + internal static string Reserved_attributes_are_set_0 { + get { + return ResourceManager.GetString("Reserved_attributes_are_set_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Resource fork clump size: {0} bytes.. + /// + internal static string Resource_fork_clump_size_0_bytes { + get { + return ResourceManager.GetString("Resource_fork_clump_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Resync DASD limits. + /// + internal static string Resync_DASD_limits { + get { + return ResourceManager.GetString("Resync_DASD_limits", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rock Ridge Interchange Protocol present.. + /// + internal static string Rock_Ridge_Interchange_Protocol_present { + get { + return ResourceManager.GetString("Rock_Ridge_Interchange_Protocol_present", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root block checksum is 0x{0:X8}. + /// + internal static string Root_block_checksum_is_0 { + get { + return ResourceManager.GetString("Root_block_checksum_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root block extension resides at block {0}. + /// + internal static string Root_block_extension_resides_at_block_0 { + get { + return ResourceManager.GetString("Root_block_extension_resides_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root directory block size: {0} bytes. + /// + internal static string Root_directory_block_size_0_bytes { + get { + return ResourceManager.GetString("Root_directory_block_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root directory descriptor starts at block {0}. + /// + internal static string Root_directory_descriptor_starts_at_block_0 { + get { + return ResourceManager.GetString("Root_directory_descriptor_starts_at_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root directory identifier: 0x{0:X8}. + /// + internal static string Root_directory_identifier_0 { + get { + return ResourceManager.GetString("Root_directory_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root directory resides on block {0}. + /// + internal static string Root_directory_resides_on_block_0 { + get { + return ResourceManager.GetString("Root_directory_resides_on_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root directory resides on inode {0}. + /// + internal static string Root_directory_resides_on_inode_0 { + get { + return ResourceManager.GetString("Root_directory_resides_on_inode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root directory size: {0} blocks, {1} bytes. + /// + internal static string Root_directory_size_0_blocks_1_bytes { + get { + return ResourceManager.GetString("Root_directory_size_0_blocks_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root directory starts at cluster {0}. + /// + internal static string Root_directory_starts_at_cluster_0 { + get { + return ResourceManager.GetString("Root_directory_starts_at_cluster_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root folder's i-node size: {0} blocks (Should be 1). + /// + internal static string Root_folder_i_node_size_0_blocks_Should_be_one { + get { + return ResourceManager.GetString("Root_folder_i_node_size_0_blocks_Should_be_one", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root folder's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes). + /// + internal static string Root_folder_s_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes { + get { + return ResourceManager.GetString("Root_folder_s_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_bloc" + + "ks_3_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root node of the extent B-tree resides in block {0}. + /// + internal static string Root_node_of_the_extent_B_tree_resides_in_block_0 { + get { + return ResourceManager.GetString("Root_node_of_the_extent_B_tree_resides_in_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root node of the object B-tree resides in block {0}. + /// + internal static string Root_node_of_the_object_B_tree_resides_in_block_0 { + get { + return ResourceManager.GetString("Root_node_of_the_object_B_tree_resides_in_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root object container starts in block {0}. + /// + internal static string Root_object_container_starts_in_block_0 { + get { + return ResourceManager.GetString("Root_object_container_starts_in_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root resides on inode {0}. + /// + internal static string Root_resides_on_inode_0 { + get { + return ResourceManager.GetString("Root_resides_on_inode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root starts at frag {0}. + /// + internal static string Root_starts_at_frag_0 { + get { + return ResourceManager.GetString("Root_starts_at_frag_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Root tree starts at LBA {0}. + /// + internal static string Root_tree_starts_at_LBA_0 { + get { + return ResourceManager.GetString("Root_tree_starts_at_LBA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to RPS level: {0}. + /// + internal static string RPS_level_0 { + get { + return ResourceManager.GetString("RPS_level_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to RT-11 file system. + /// + internal static string RT11_Name { + get { + return ResourceManager.GetString("RT11_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to S-Records start at {0} and spans for {1} blocks. + /// + internal static string S_Records_start_at_0_and_spans_for_1_blocks { + get { + return ResourceManager.GetString("S_Records_start_at_0_and_spans_for_1_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Scavenger result code: 0x{0:X8}. + /// + internal static string Scavenger_result_code_0 { + get { + return ResourceManager.GetString("Scavenger_result_code_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Searching for Rootblock in sector {0}. + /// + internal static string Searching_for_Rootblock_in_sector_0 { + get { + return ResourceManager.GetString("Searching_for_Rootblock_in_sector_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Second {0} partition starts at sector {1}. + /// + internal static string Second_0_partition_starts_at_sector_1 { + get { + return ResourceManager.GetString("Second_0_partition_starts_at_sector_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2nd FAT is in use. + /// + internal static string Second_FAT_is_in_use { + get { + return ResourceManager.GetString("Second_FAT_is_in_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2nd fat starts at = {0}. + /// + internal static string Second_fat_starts_at_0 { + get { + return ResourceManager.GetString("Second_fat_starts_at_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Secondary home block is on sector {0} (VBN {1}). + /// + internal static string Secondary_home_block_is_on_sector_0_VBN_1 { + get { + return ResourceManager.GetString("Secondary_home_block_is_on_sector_0_VBN_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Section ID: {0}. + /// + internal static string Section_ID_0 { + get { + return ResourceManager.GetString("Section_ID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector {0}, file ID 0x{1:X4}. + /// + internal static string Sector_0_file_ID_1 { + get { + return ResourceManager.GetString("Sector_0_file_ID_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector of ACL directory: {0}. + /// + internal static string Sector_of_ACL_directory_0 { + get { + return ResourceManager.GetString("Sector_of_ACL_directory_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector of backup FAT32 parameter block: {0}. + /// + internal static string Sector_of_backup_FAT32_parameter_block_0 { + get { + return ResourceManager.GetString("Sector_of_backup_FAT32_parameter_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector of bad blocks list: {0}. + /// + internal static string Sector_of_bad_blocks_list_0 { + get { + return ResourceManager.GetString("Sector_of_bad_blocks_list_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector of codepage directory: {0}. + /// + internal static string Sector_of_codepage_directory_0 { + get { + return ResourceManager.GetString("Sector_of_codepage_directory_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector of directory band bitmap: {0}. + /// + internal static string Sector_of_directory_band_bitmap_0 { + get { + return ResourceManager.GetString("Sector_of_directory_band_bitmap_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector of first allocation block: {0}. + /// + internal static string Sector_of_first_allocation_block_0 { + get { + return ResourceManager.GetString("Sector_of_first_allocation_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector of free space bitmaps: {0}. + /// + internal static string Sector_of_free_space_bitmaps_0 { + get { + return ResourceManager.GetString("Sector_of_free_space_bitmaps_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector of FSINFO structure: {0}. + /// + internal static string Sector_of_FSINFO_structure_0 { + get { + return ResourceManager.GetString("Sector_of_FSINFO_structure_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector of Hotfix directory: {0}. + /// + internal static string Sector_of_Hotfix_directory_0 { + get { + return ResourceManager.GetString("Sector_of_Hotfix_directory_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector of root directory FNode: {0}. + /// + internal static string Sector_of_root_directory_FNode_0 { + get { + return ResourceManager.GetString("Sector_of_root_directory_FNode_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector 0 skew: {0}/track. + /// + internal static string Sector_zero_skew_0_track { + get { + return ResourceManager.GetString("Sector_zero_skew_0_track", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sectors allocated at most in track {0}. + /// + internal static string Sectors_allocated_at_most_in_track_0 { + get { + return ResourceManager.GetString("Sectors_allocated_at_most_in_track_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Security mask: 0x{0:X8}. + /// + internal static string Security_mask_0 { + get { + return ResourceManager.GetString("Security_mask_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Selection criteria type: {0}. + /// + internal static string Selection_criteria_type_0 { + get { + return ResourceManager.GetString("Selection_criteria_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serial: 0x{0:X16}. + /// + internal static string Serial_0_X16 { + get { + return ResourceManager.GetString("Serial_0_X16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serial number: 0x{0:X8}. + /// + internal static string Serial_number_0 { + get { + return ResourceManager.GetString("Serial_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serial number of Lisa computer that can use this volume's software {0}. + /// + internal static string Serial_number_of_Lisa_computer_that_can_use_this_volume_software_0 { + get { + return ResourceManager.GetString("Serial_number_of_Lisa_computer_that_can_use_this_volume_software_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serial number of Lisa computer that created this volume: {0}. + /// + internal static string Serial_number_of_Lisa_computer_that_created_this_volume_0 { + get { + return ResourceManager.GetString("Serial_number_of_Lisa_computer_that_created_this_volume_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Set-uid/set-gid is disabled. + /// + internal static string Set_uid_set_gid_is_disabled { + get { + return ResourceManager.GetString("Set_uid_set_gid_is_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SmartFileSystem. + /// + internal static string SFS_Name { + get { + return ResourceManager.GetString("SFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SGI extent filesystem. + /// + internal static string SGI_extent_filesystem { + get { + return ResourceManager.GetString("SGI_extent_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Side 1 uses {0}:1 software interleaving. + /// + internal static string Side_one_uses_0_one_software_interleaving { + get { + return ResourceManager.GetString("Side_one_uses_0_one_software_interleaving", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Side 0 uses {0}:1 software interleaving. + /// + internal static string Side_zero_uses_0_one_software_interleaving { + get { + return ResourceManager.GetString("Side_zero_uses_0_one_software_interleaving", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Signature: 0x{0:X2}. + /// + internal static string Signature_0 { + get { + return ResourceManager.GetString("Signature_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Signed directory hash is in use. + /// + internal static string Signed_directory_hash_is_in_use { + get { + return ResourceManager.GetString("Signed_directory_hash_is_in_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Size of allocation blocks: {0} bytes. + /// + internal static string Size_of_allocation_blocks_0_bytes { + get { + return ResourceManager.GetString("Size_of_allocation_blocks_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Skew: {0}. + /// + internal static string Skew_0 { + get { + return ResourceManager.GetString("Skew_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SmartFileSystem. + /// + internal static string SmartFileSystem { + get { + return ResourceManager.GetString("SmartFileSystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Solar_OS filesystem. + /// + internal static string Solar_OS_filesystem { + get { + return ResourceManager.GetString("Solar_OS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Solar_OS filesystem. + /// + internal static string SolarFS_Name { + get { + return ResourceManager.GetString("SolarFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Source: {0}. + /// + internal static string Source_0 { + get { + return ResourceManager.GetString("Source_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Spare directory blocks are in use. + /// + internal static string Spare_directory_blocks_are_in_use { + get { + return ResourceManager.GetString("Spare_directory_blocks_are_in_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SpareBlock CRC32: {0:X8}. + /// + internal static string SpareBlock_CRC32_0 { + get { + return ResourceManager.GetString("SpareBlock_CRC32_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Spareblock magic1: 0x{0:X8} (Should be 0xF9911849). + /// + internal static string Spareblock_magic1_0_Should_be_0xF9911849 { + get { + return ResourceManager.GetString("Spareblock_magic1_0_Should_be_0xF9911849", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Spareblock magic2: 0x{0:X8} (Should be 0xFA5229C5). + /// + internal static string Spareblock_magic2_0_Should_be_0xFA5229C5 { + get { + return ResourceManager.GetString("Spareblock_magic2_0_Should_be_0xFA5229C5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Squash file system. + /// + internal static string Squash_file_system { + get { + return ResourceManager.GetString("Squash_file_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Squash filesystem. + /// + internal static string Squash_Name { + get { + return ResourceManager.GetString("Squash_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Standard superblock LBA: {0}. + /// + internal static string Standard_superblock_LBA_0 { + get { + return ResourceManager.GetString("Standard_superblock_LBA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Starting block of the HFS+ volume: {0}. + /// + internal static string Starting_block_of_the_HFS_Plus_volume_0 { + get { + return ResourceManager.GetString("Starting_block_of_the_HFS_Plus_volume_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Startup File is {0} bytes.. + /// + internal static string Startup_File_is_0_bytes { + get { + return ResourceManager.GetString("Startup_File_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Startup screen filename: {0}. + /// + internal static string Startup_screen_filename_0 { + get { + return ResourceManager.GetString("Startup_screen_filename_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Super Nintendo Virtual Console. + /// + internal static string Super_Nintendo_Virtual_Console { + get { + return ResourceManager.GetString("Super_Nintendo_Virtual_Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SuperBlock CRC32: {0:X8}. + /// + internal static string SuperBlock_CRC32_0 { + get { + return ResourceManager.GetString("SuperBlock_CRC32_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Superblock is {0} bytes. + /// + internal static string Superblock_is_0_bytes { + get { + return ResourceManager.GetString("Superblock_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Superblock is being modified. + /// + internal static string Superblock_is_being_modified { + get { + return ResourceManager.GetString("Superblock_is_being_modified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Superblock last modified on {0}. + /// + internal static string Superblock_last_modified_on_0 { + get { + return ResourceManager.GetString("Superblock_last_modified_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Superblock last updated on {0}. + /// + internal static string Superblock_last_updated_on_0 { + get { + return ResourceManager.GetString("Superblock_last_updated_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Superblock LBA: {0}. + /// + internal static string Superblock_LBA_0 { + get { + return ResourceManager.GetString("Superblock_LBA_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Superblock magic1: 0x{0:X8} (Should be 0xF995E849). + /// + internal static string Superblock_magic1_0_Should_be_0xF995E849 { + get { + return ResourceManager.GetString("Superblock_magic1_0_Should_be_0xF995E849", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Superblock magic2: 0x{0:X8} (Should be 0xFA53E9C5). + /// + internal static string Superblock_magic2_0_Should_be_0xFA53E9C5 { + get { + return ResourceManager.GetString("Superblock_magic2_0_Should_be_0xFA53E9C5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Superblock resides in block {0}. + /// + internal static string Superblock_resides_in_block_0 { + get { + return ResourceManager.GetString("Superblock_resides_in_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Superblock seems corrupt, following information may be incorrect. + /// + internal static string Superblock_seems_corrupt_following_information_may_be_incorrect { + get { + return ResourceManager.GetString("Superblock_seems_corrupt_following_information_may_be_incorrect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supports nanosecond timestamps and creation time (ext4). + /// + internal static string Supports_nanosecond_timestamps_and_creation_time_ext4 { + get { + return ResourceManager.GetString("Supports_nanosecond_timestamps_and_creation_time_ext4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supports volumes bigger than 2^32 blocks (ext4). + /// + internal static string Supports_volumes_bigger_than_2_32_blocks_ext4 { + get { + return ResourceManager.GetString("Supports_volumes_bigger_than_2_32_blocks_ext4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System filename: {0}. + /// + internal static string System_filename_0 { + get { + return ResourceManager.GetString("System_filename_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System heap will be extended by {0} bytes and a {1} fraction of the available RAM. + /// + internal static string System_heap_will_be_extended_by_0_bytes_and_a_1_fraction_of_the_available_RAM { + get { + return ResourceManager.GetString("System_heap_will_be_extended_by_0_bytes_and_a_1_fraction_of_the_available_RAM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System identifier: {0}. + /// + internal static string System_identifier_0 { + get { + return ResourceManager.GetString("System_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System, owner, group, world. + /// + internal static string System_owner_group_world { + get { + return ResourceManager.GetString("System_owner_group_world", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System type: 0x{0:X2}. + /// + internal static string System_type_0 { + get { + return ResourceManager.GetString("System_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SYSTEM USE SHARING PROTOCOL INFORMATION:. + /// + internal static string SYSTEM_USE_SHARING_PROTOCOL_INFORMATION { + get { + return ResourceManager.GetString("SYSTEM_USE_SHARING_PROTOCOL_INFORMATION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ----------------------------------------. + /// + internal static string SYSTEM_USE_SHARING_PROTOCOL_INFORMATION_border { + get { + return ResourceManager.GetString("SYSTEM_USE_SHARING_PROTOCOL_INFORMATION_border", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System Use Sharing Protocol present.. + /// + internal static string System_Use_Sharing_Protocol_present { + get { + return ResourceManager.GetString("System_Use_Sharing_Protocol_present", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System V Release 2 filesystem. + /// + internal static string System_V_Release_2_filesystem { + get { + return ResourceManager.GetString("System_V_Release_2_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System V Release 4 filesystem. + /// + internal static string System_V_Release_4_filesystem { + get { + return ResourceManager.GetString("System_V_Release_4_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UNIX System V filesystem. + /// + internal static string SysVfs_Name { + get { + return ResourceManager.GetString("SysVfs_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The following information may be incorrect for this volume.. + /// + internal static string The_following_information_may_be_incorrect_for_this_volume { + get { + return ResourceManager.GetString("The_following_information_may_be_incorrect_for_this_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are {0} reserved blocks before volume. + /// + internal static string There_are_0_reserved_blocks_before_volume { + get { + return ResourceManager.GetString("There_are_0_reserved_blocks_before_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are a lot of variants of UFS using overlapped values on same fields. + /// + internal static string There_are_a_lot_of_variants_of_UFS_using_overlapped_values_on_same_fields { + get { + return ResourceManager.GetString("There_are_a_lot_of_variants_of_UFS_using_overlapped_values_on_same_fields", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are an estimate of {0} free inodes before next search start. + /// + internal static string There_are_an_estimate_of_0_free_inodes_before_next_search_start { + get { + return ResourceManager.GetString("There_are_an_estimate_of_0_free_inodes_before_next_search_start", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are bad blocks in the extents file.. + /// + internal static string There_are_bad_blocks_in_the_extents_file { + get { + return ResourceManager.GetString("There_are_bad_blocks_in_the_extents_file", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are no orphaned inodes. + /// + internal static string There_are_no_orphaned_inodes { + get { + return ResourceManager.GetString("There_are_no_orphaned_inodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are reused CNIDs.. + /// + internal static string There_are_reused_CNIDs { + get { + return ResourceManager.GetString("There_are_reused_CNIDs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Third {0} partition starts at sector {1}. + /// + internal static string Third_0_partition_starts_at_sector_1 { + get { + return ResourceManager.GetString("Third_0_partition_starts_at_sector_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This home block is on sector {0} (VBN {1}). + /// + internal static string This_home_block_is_on_sector_0_VBN_1 { + get { + return ResourceManager.GetString("This_home_block_is_on_sector_0_VBN_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is a Sega Dreamcast disc.. + /// + internal static string This_is_a_Sega_Dreamcast_disc { + get { + return ResourceManager.GetString("This_is_a_Sega_Dreamcast_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is a Sega Saturn disc.. + /// + internal static string This_is_a_Sega_Saturn_disc { + get { + return ResourceManager.GetString("This_is_a_Sega_Saturn_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is a SegaCD / MegaCD disc.. + /// + internal static string This_is_a_SegaCD_MegaCD_disc { + get { + return ResourceManager.GetString("This_is_a_SegaCD_MegaCD_disc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is the primary pack. + /// + internal static string This_is_the_primary_pack { + get { + return ResourceManager.GetString("This_is_the_primary_pack", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This may not be HPFS, following information may be not correct.. + /// + internal static string This_may_not_be_HPFS_following_information_may_be_not_correct { + get { + return ResourceManager.GetString("This_may_not_be_HPFS_following_information_may_be_not_correct", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This superblock resides on physical block {0}. + /// + internal static string This_superblock_resides_on_physical_block_0 { + get { + return ResourceManager.GetString("This_superblock_resides_on_physical_block_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This version is not supported yet.. + /// + internal static string This_version_is_not_supported_yet { + get { + return ResourceManager.GetString("This_version_is_not_supported_yet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This volume may be corrupted.. + /// + internal static string This_volume_may_be_corrupted { + get { + return ResourceManager.GetString("This_volume_may_be_corrupted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Title: {0}. + /// + internal static string Title_0 { + get { + return ResourceManager.GetString("Title_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector {0} ({1:X2}:{2:X2}:{3:X2}), Raw, Mode {4}. + /// + internal static string tor_Sector_0_1_2_3_Raw_Mode_4 { + get { + return ResourceManager.GetString("tor_Sector_0_1_2_3_Raw_Mode_4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector {0} ({1:X2}:{2:X2}:{3:X2}), Raw, Mode 2 Form {4}, File Number {5}, Channel Number {6}, Submode {7}, Coding Information {8}. + /// + internal static string tor_Sector_0_1_2_3_Raw_Mode_two_Form_4_File_Number_5_Channel_Number_6_Submode_7_Coding_Information_8 { + get { + return ResourceManager.GetString("tor_Sector_0_1_2_3_Raw_Mode_two_Form_4_File_Number_5_Channel_Number_6_Submode_7_C" + + "oding_Information_8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector {0}, Cooked, Mode 2 Form {1}, File Number {2}, Channel Number {3}, Submode {4}, Coding Information {5}. + /// + internal static string tor_Sector_0_Cooked_Mode_two_Form_1_File_Number_2_Channel_Number_3_Submode_4_Coding_Information_5 { + get { + return ResourceManager.GetString("tor_Sector_0_Cooked_Mode_two_Form_1_File_Number_2_Channel_Number_3_Submode_4_Codi" + + "ng_Information_5", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector {0}, Cooked, Mode 2 Form 2. + /// + internal static string tor_Sector_0_Cooked_Mode_two_Form_two { + get { + return ResourceManager.GetString("tor_Sector_0_Cooked_Mode_two_Form_two", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector {0}, Cooked, Mode 0/1 / Mode 2 Form 1. + /// + internal static string tor_Sector_0_Cooked_Mode_zero_one_Mode_two_Form_one { + get { + return ResourceManager.GetString("tor_Sector_0_Cooked_Mode_zero_one_Mode_two_Form_one", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sector {0}, Raw, Audio. + /// + internal static string tor_Sector_0_Raw_Audio { + get { + return ResourceManager.GetString("tor_Sector_0_Raw_Audio", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track allocation is forward. + /// + internal static string Track_allocation_is_forward { + get { + return ResourceManager.GetString("Track_allocation_is_forward", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Track allocation is reverse. + /// + internal static string Track_allocation_is_reverse { + get { + return ResourceManager.GetString("Track_allocation_is_reverse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Traversing directory.. + /// + internal static string Traversing_directory { + get { + return ResourceManager.GetString("Traversing_directory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trying all known definitions.. + /// + internal static string Trying_all_known_definitions { + get { + return ResourceManager.GetString("Trying_all_known_definitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trying definition "{0}". + /// + internal static string Trying_definition_0 { + get { + return ResourceManager.GetString("Trying_definition_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trying to load definitions.. + /// + internal static string Trying_to_load_definitions { + get { + return ResourceManager.GetString("Trying_to_load_definitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TurboGrafx CD Virtual Console. + /// + internal static string TurboGrafx_CD_Virtual_Console { + get { + return ResourceManager.GetString("TurboGrafx_CD_Virtual_Console", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Universal Disk Format. + /// + internal static string UDF_Name { + get { + return ResourceManager.GetString("UDF_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UFS filesystem. + /// + internal static string UFS_filesystem { + get { + return ResourceManager.GetString("UFS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UFS2 filesystem. + /// + internal static string UFS2_filesystem { + get { + return ResourceManager.GetString("UFS2_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (uid16): Disable 32bit UIDs and GIDs. + /// + internal static string uid16_Disable_32bit_UIDs_and_GIDs { + get { + return ResourceManager.GetString("uid16_Disable_32bit_UIDs_and_GIDs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UK age rating is {0}. + /// + internal static string UK_age_rating_is_0 { + get { + return ResourceManager.GetString("UK_age_rating_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable cache all files.. + /// + internal static string Unable_cache_all_files { + get { + return ResourceManager.GetString("Unable_cache_all_files", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to read boot blocks. + /// + internal static string Unable_to_read_boot_blocks { + get { + return ResourceManager.GetString("Unable_to_read_boot_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to read boot loader. + /// + internal static string Unable_to_read_boot_loader { + get { + return ResourceManager.GetString("Unable_to_read_boot_loader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to read catalog.. + /// + internal static string Unable_to_read_catalog { + get { + return ResourceManager.GetString("Unable_to_read_catalog", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to read MDDF. + /// + internal static string Unable_to_read_MDDF { + get { + return ResourceManager.GetString("Unable_to_read_MDDF", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to read S-Records file. + /// + internal static string Unable_to_read_S_Records_file { + get { + return ResourceManager.GetString("Unable_to_read_S_Records_file", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to read volume bitmap. + /// + internal static string Unable_to_read_volume_bitmap { + get { + return ResourceManager.GetString("Unable_to_read_volume_bitmap", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unaligned magic: "{0}". + /// + internal static string unaligned_magic_0 { + get { + return ResourceManager.GetString("unaligned_magic_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Underlying device does not support Lisa tags. + /// + internal static string Underlying_device_does_not_support_Lisa_tags { + get { + return ResourceManager.GetString("Underlying_device_does_not_support_Lisa_tags", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Underlying media presented errors. + /// + internal static string Underlying_media_presented_errors { + get { + return ResourceManager.GetString("Underlying_media_presented_errors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UNICOS filesystem. + /// + internal static string UNICOS_filesystem { + get { + return ResourceManager.GetString("UNICOS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UNICOS Filesystem Plugin. + /// + internal static string UNICOS_Name { + get { + return ResourceManager.GetString("UNICOS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Universal Disk Format. + /// + internal static string Universal_Disk_Format { + get { + return ResourceManager.GetString("Universal_Disk_Format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UNIX 7th Edition filesystem. + /// + internal static string UNIX_7th_Edition_filesystem { + get { + return ResourceManager.GetString("UNIX_7th_Edition_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UNIX Boot Filesystem. + /// + internal static string UNIX_Boot_Filesystem { + get { + return ResourceManager.GetString("UNIX_Boot_Filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown boot code.. + /// + internal static string Unknown_boot_code { + get { + return ResourceManager.GetString("Unknown_boot_code", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown. + /// + internal static string Unknown_codepage { + get { + return ResourceManager.GetString("Unknown_codepage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown compatible features: {0:X8}. + /// + internal static string Unknown_compatible_features_0 { + get { + return ResourceManager.GetString("Unknown_compatible_features_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown flag 0x40 on flags1 is active. + /// + internal static string Unknown_flag_0x40_on_flags1_is_active { + get { + return ResourceManager.GetString("Unknown_flag_0x40_on_flags1_is_active", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown flag 0x40 on flags2 is active. + /// + internal static string Unknown_flag_0x40_on_flags2_is_active { + get { + return ResourceManager.GetString("Unknown_flag_0x40_on_flags2_is_active", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown flag 0x80 on flags2 is active. + /// + internal static string Unknown_flag_0x80_on_flags2_is_active { + get { + return ResourceManager.GetString("Unknown_flag_0x80_on_flags2_is_active", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown flags: {0:X8}. + /// + internal static string Unknown_flags_0_X8 { + get { + return ResourceManager.GetString("Unknown_flags_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown how {0} side ordering works. + /// + internal static string Unknown_how_0_side_ordering_works { + get { + return ResourceManager.GetString("Unknown_how_0_side_ordering_works", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown incompatible features: {0:X8}. + /// + internal static string Unknown_incompatible_features_0 { + get { + return ResourceManager.GetString("Unknown_incompatible_features_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown LisaFS version {0}. + /// + internal static string Unknown_LisaFS_version_0 { + get { + return ResourceManager.GetString("Unknown_LisaFS_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown optimization value: 0x{0:X8}. + /// + internal static string Unknown_optimization_value_0 { + get { + return ResourceManager.GetString("Unknown_optimization_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown order type "{0}", not proceeding with this definition.. + /// + internal static string Unknown_order_type_0_not_proceeding_with_this_definition { + get { + return ResourceManager.GetString("Unknown_order_type_0_not_proceeding_with_this_definition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown OS ({0}). + /// + internal static string Unknown_OS_0 { + get { + return ResourceManager.GetString("Unknown_OS_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown partition type {0}. + /// + internal static string unknown_partition_type_0 { + get { + return ResourceManager.GetString("unknown_partition_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown ProDOS version with field {0} is at least required for reading this volume.. + /// + internal static string Unknown_ProDOS_version_with_field_0_is_at_least_required_for_reading_this_volume { + get { + return ResourceManager.GetString("Unknown_ProDOS_version_with_field_0_is_at_least_required_for_reading_this_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown ProDOS version with field {0} used to create this volume.. + /// + internal static string Unknown_ProDOS_version_with_field_0_used_to_create_this_volume { + get { + return ResourceManager.GetString("Unknown_ProDOS_version_with_field_0_used_to_create_this_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown publisher '{0}'. + /// + internal static string Unknown_publisher_0 { + get { + return ResourceManager.GetString("Unknown_publisher_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown read-only compatible features: {0:X8}. + /// + internal static string Unknown_read_only_compatible_features_0 { + get { + return ResourceManager.GetString("Unknown_read_only_compatible_features_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown s_type value: 0x{0:X8}. + /// + internal static string Unknown_s_type_value_0 { + get { + return ResourceManager.GetString("Unknown_s_type_value_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown set default mount options: {0:X8}. + /// + internal static string Unknown_set_default_mount_options_0 { + get { + return ResourceManager.GetString("Unknown_set_default_mount_options_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown set flags: {0:X8}. + /// + internal static string Unknown_set_flags_0 { + get { + return ResourceManager.GetString("Unknown_set_flags_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown. + /// + internal static string Unknown_specification { + get { + return ResourceManager.GetString("Unknown_specification", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown structures:. + /// + internal static string Unknown_structures { + get { + return ResourceManager.GetString("Unknown_structures", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown type '{0}'. + /// + internal static string unknown_type_0 { + get { + return ResourceManager.GetString("unknown_type_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unsigned directory hash is in use. + /// + internal static string Unsigned_directory_hash_is_in_use { + get { + return ResourceManager.GetString("Unsigned_directory_hash_is_in_use", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to update. + /// + internal static string update { + get { + return ResourceManager.GetString("update", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use LFN when available with fallback to .LONGNAME (default). + /// + internal static string Use_LFN_when_available_with_fallback_to_LONGNAME_default { + get { + return ResourceManager.GetString("Use_LFN_when_available_with_fallback_to_LONGNAME_default", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User replicated volume. + /// + internal static string User_replicated_volume { + get { + return ResourceManager.GetString("User_replicated_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (user_xattr): Enable user-specified extended attributes. + /// + internal static string user_xattr_Enable_user_specified_extended_attributes { + get { + return ResourceManager.GetString("user_xattr_Enable_user_specified_extended_attributes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Uses B-Tree for directories. + /// + internal static string Uses_B_Tree_for_directories { + get { + return ResourceManager.GetString("Uses_B_Tree_for_directories", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Uses compression. + /// + internal static string Uses_compression { + get { + return ResourceManager.GetString("Uses_compression", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using Apricot BPB. + /// + internal static string Using_Apricot_BPB { + get { + return ResourceManager.GetString("Using_Apricot_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using Atari BPB. + /// + internal static string Using_Atari_BPB { + get { + return ResourceManager.GetString("Using_Atari_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using DEC Rainbow hardcoded BPB.. + /// + internal static string Using_DEC_Rainbow_hardcoded_BPB { + get { + return ResourceManager.GetString("Using_DEC_Rainbow_hardcoded_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using DOS 2.0 BPB. + /// + internal static string Using_DOS_2_0_BPB { + get { + return ResourceManager.GetString("Using_DOS_2_0_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using DOS 3.0 BPB. + /// + internal static string Using_DOS_3_0_BPB { + get { + return ResourceManager.GetString("Using_DOS_3_0_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using DOS 3.2 BPB. + /// + internal static string Using_DOS_3_2_BPB { + get { + return ResourceManager.GetString("Using_DOS_3_2_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using DOS 3.3 BPB. + /// + internal static string Using_DOS_3_3_BPB { + get { + return ResourceManager.GetString("Using_DOS_3_3_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using DOS 3.4 BPB. + /// + internal static string Using_DOS_3_4_BPB { + get { + return ResourceManager.GetString("Using_DOS_3_4_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using DOS 4.0 BPB. + /// + internal static string Using_DOS_4_0_BPB { + get { + return ResourceManager.GetString("Using_DOS_4_0_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using FAT32 BPB. + /// + internal static string Using_FAT32_BPB { + get { + return ResourceManager.GetString("Using_FAT32_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using hardcoded BPB.. + /// + internal static string Using_hardcoded_BPB { + get { + return ResourceManager.GetString("Using_hardcoded_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using hardcoded BPB for 5.25" DSDD.. + /// + internal static string Using_hardcoded_BPB_for_5_25_DSDD { + get { + return ResourceManager.GetString("Using_hardcoded_BPB_for_5_25_DSDD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using hardcoded BPB for 5.25" SSDD.. + /// + internal static string Using_hardcoded_BPB_for_5_25_SSDD { + get { + return ResourceManager.GetString("Using_hardcoded_BPB_for_5_25_SSDD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using Human68k BPB. + /// + internal static string Using_Human68k_BPB { + get { + return ResourceManager.GetString("Using_Human68k_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using MSX BPB. + /// + internal static string Using_MSX_BPB { + get { + return ResourceManager.GetString("Using_MSX_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using short FAT32 BPB. + /// + internal static string Using_short_FAT32_BPB { + get { + return ResourceManager.GetString("Using_short_FAT32_BPB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Utility. + /// + internal static string Utility { + get { + return ResourceManager.GetString("Utility", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UUID: {0}. + /// + internal static string UUID_0 { + get { + return ResourceManager.GetString("UUID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Veritas file system. + /// + internal static string Veritas_file_system { + get { + return ResourceManager.GetString("Veritas_file_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version {0}. + /// + internal static string Version_0 { + get { + return ResourceManager.GetString("Version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version {0}.{1}. + /// + internal static string Version_0_1 { + get { + return ResourceManager.GetString("Version_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version1: 0x{0:X4}. + /// + internal static string Version1_0_X4 { + get { + return ResourceManager.GetString("Version1_0_X4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version2: 0x{0:X4}. + /// + internal static string Version2_0_X4 { + get { + return ResourceManager.GetString("Version2_0_X4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to VMware filesystem. + /// + internal static string VMfs_Name { + get { + return ResourceManager.GetString("VMfs_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to VMware file system. + /// + internal static string VMware_file_system { + get { + return ResourceManager.GetString("VMware_file_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume {0} of {1} on this filesystem. + /// + internal static string Volume_0_of_1_on_this_filesystem { + get { + return ResourceManager.GetString("Volume_0_of_1_on_this_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume attributes: {0:X2}. + /// + internal static string Volume_attributes_0 { + get { + return ResourceManager.GetString("Volume_attributes_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume backed up on {0}. + /// + internal static string Volume_backed_up_on_0 { + get { + return ResourceManager.GetString("Volume_backed_up_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume bitmap is valid. + /// + internal static string Volume_bitmap_is_valid { + get { + return ResourceManager.GetString("Volume_bitmap_is_valid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume bitmap runs for {0} sectors ({1} bytes). + /// + internal static string Volume_bitmap_runs_for_0_sectors_1_bytes { + get { + return ResourceManager.GetString("Volume_bitmap_runs_for_0_sectors_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume bitmap starting sector (in 512-bytes): {0}. + /// + internal static string Volume_bitmap_starting_sector_in_512_bytes_0 { + get { + return ResourceManager.GetString("Volume_bitmap_starting_sector_in_512_bytes_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume bitmap starts in sector {0} (VBN {1}). + /// + internal static string Volume_bitmap_starts_in_sector_0_VBN_1 { + get { + return ResourceManager.GetString("Volume_bitmap_starts_in_sector_0_VBN_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume block is {0} bytes. + /// + internal static string Volume_block_is_0_bytes { + get { + return ResourceManager.GetString("Volume_block_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume block size is {0} bytes. + /// + internal static string Volume_block_size_is_0_bytes { + get { + return ResourceManager.GetString("Volume_block_size_is_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume can be destroyed. + /// + internal static string Volume_can_be_destroyed { + get { + return ResourceManager.GetString("Volume_can_be_destroyed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume can be filled up to {0}%. + /// + internal static string Volume_can_be_filled_up_to_0 { + get { + return ResourceManager.GetString("Volume_can_be_filled_up_to_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume can be mounted {0} times before checking. + /// + internal static string Volume_can_be_mounted_0_times_before_checking { + get { + return ResourceManager.GetString("Volume_can_be_mounted_0_times_before_checking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume can be read. + /// + internal static string Volume_can_be_read { + get { + return ResourceManager.GetString("Volume_can_be_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume can be renamed. + /// + internal static string Volume_can_be_renamed { + get { + return ResourceManager.GetString("Volume_can_be_renamed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume can be written. + /// + internal static string Volume_can_be_written { + get { + return ResourceManager.GetString("Volume_can_be_written", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume cannot be written by any UDF version higher than {0}.{1:X2}. + /// + internal static string Volume_cannot_be_written_by_any_UDF_version_higher_than_0_1 { + get { + return ResourceManager.GetString("Volume_cannot_be_written_by_any_UDF_version_higher_than_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume's catalog created on {0}. + /// + internal static string Volume_catalog_created_on_0 { + get { + return ResourceManager.GetString("Volume_catalog_created_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume comment: {0}. + /// + internal static string Volume_comment_0 { + get { + return ResourceManager.GetString("Volume_comment_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume commits in groups of 1. + /// + internal static string Volume_commits_in_groups_of_1 { + get { + return ResourceManager.GetString("Volume_commits_in_groups_of_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume commits lazy. + /// + internal static string Volume_commits_lazy { + get { + return ResourceManager.GetString("Volume_commits_lazy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume conforms to {0}. + /// + internal static string Volume_conforms_to_0 { + get { + return ResourceManager.GetString("Volume_conforms_to_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume contains {0} blocks ({1} bytes). + /// + internal static string Volume_contains_0_blocks_1_bytes { + get { + return ResourceManager.GetString("Volume_contains_0_blocks_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume contains {0} directory entries. + /// + internal static string Volume_contains_0_directory_entries { + get { + return ResourceManager.GetString("Volume_contains_0_directory_entries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume contains {0} files. + /// + internal static string Volume_contains_0_files { + get { + return ResourceManager.GetString("Volume_contains_0_files", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume contains {0} files and {1} directories. + /// + internal static string Volume_contains_0_files_and_1_directories { + get { + return ResourceManager.GetString("Volume_contains_0_files_and_1_directories", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume contains {0} partitions. + /// + internal static string Volume_contains_0_partitions { + get { + return ResourceManager.GetString("Volume_contains_0_partitions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume continues on error. + /// + internal static string Volume_continues_on_error { + get { + return ResourceManager.GetString("Volume_continues_on_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume copied on {0}. + /// + internal static string Volume_copied_on_0 { + get { + return ResourceManager.GetString("Volume_copied_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume created on {0}. + /// + internal static string Volume_created_on_0 { + get { + return ResourceManager.GetString("Volume_created_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume created on kernel version: {0}. + /// + internal static string Volume_created_on_kernel_version_0 { + get { + return ResourceManager.GetString("Volume_created_on_kernel_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume creation date: {0}. + /// + internal static string Volume_creation_date_0 { + get { + return ResourceManager.GetString("Volume_creation_date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to VOLUME DESCRIPTOR INFORMATION:. + /// + internal static string VOLUME_DESCRIPTOR_INFORMATION { + get { + return ResourceManager.GetString("VOLUME_DESCRIPTOR_INFORMATION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ------------------------------. + /// + internal static string VOLUME_DESCRIPTOR_INFORMATION_border { + get { + return ResourceManager.GetString("VOLUME_DESCRIPTOR_INFORMATION_border", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume disk format: {0}. + /// + internal static string Volume_disk_format_0 { + get { + return ResourceManager.GetString("Volume_disk_format_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume does not commit to log. + /// + internal static string Volume_does_not_commit_to_log { + get { + return ResourceManager.GetString("Volume_does_not_commit_to_log", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume does not expire.. + /// + internal static string Volume_does_not_expire { + get { + return ResourceManager.GetString("Volume_does_not_expire", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume does not need cache.. + /// + internal static string Volume_does_not_need_cache { + get { + return ResourceManager.GetString("Volume_does_not_need_cache", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume edition {0}. + /// + internal static string Volume_edition_0 { + get { + return ResourceManager.GetString("Volume_edition_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume effective date: {0}. + /// + internal static string Volume_effective_date_0 { + get { + return ResourceManager.GetString("Volume_effective_date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume ends at {0}. + /// + internal static string Volume_ends_at_0 { + get { + return ResourceManager.GetString("Volume_ends_at_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume expiration date: {0}. + /// + internal static string Volume_expiration_date_0 { + get { + return ResourceManager.GetString("Volume_expiration_date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume flags: 0x{0:X2}. + /// + internal static string Volume_flags_0_X2 { + get { + return ResourceManager.GetString("Volume_flags_0_X2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume flags: 0x{0:X4}. + /// + internal static string Volume_flags_0_X4 { + get { + return ResourceManager.GetString("Volume_flags_0_X4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume format is {0}. + /// + internal static string Volume_format_is_0 { + get { + return ResourceManager.GetString("Volume_format_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume goes from byte {0} to byte {1}, for {2} bytes. + /// + internal static string Volume_goes_from_byte_0_to_byte_1_for_2_bytes { + get { + return ResourceManager.GetString("Volume_goes_from_byte_0_to_byte_1_for_2_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} blocks. + /// + internal static string Volume_has_0_blocks { + get { + return ResourceManager.GetString("Volume_has_0_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} blocks ({1} bytes). + /// + internal static string Volume_has_0_blocks_1_bytes { + get { + return ResourceManager.GetString("Volume_has_0_blocks_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} blocks of {1} bytes each. + /// + internal static string Volume_has_0_blocks_of_1_bytes_each { + get { + return ResourceManager.GetString("Volume_has_0_blocks_of_1_bytes_each", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} blocks of {1} bytes each (total {2} bytes). + /// + internal static string Volume_has_0_blocks_of_1_bytes_each_total_2_bytes { + get { + return ResourceManager.GetString("Volume_has_0_blocks_of_1_bytes_each_total_2_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} blocks of {1} bytes, for a total of {2} bytes. + /// + internal static string Volume_has_0_blocks_of_1_bytes_for_a_total_of_2_bytes { + get { + return ResourceManager.GetString("Volume_has_0_blocks_of_1_bytes_for_a_total_of_2_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} blocks used ({1} bytes). + /// + internal static string Volume_has_0_blocks_used_1_bytes { + get { + return ResourceManager.GetString("Volume_has_0_blocks_used_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} blocks with {1} blocks free. + /// + internal static string Volume_has_0_blocks_with_1_blocks_free { + get { + return ResourceManager.GetString("Volume_has_0_blocks_with_1_blocks_free", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} bytes. + /// + internal static string Volume_has_0_bytes { + get { + return ResourceManager.GetString("Volume_has_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} bytes in {1} zones. + /// + internal static string Volume_has_0_bytes_in_1_zones { + get { + return ResourceManager.GetString("Volume_has_0_bytes_in_1_zones", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} bytes per block. + /// + internal static string Volume_has_0_bytes_per_block { + get { + return ResourceManager.GetString("Volume_has_0_bytes_per_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} bytes spanned in {1} devices. + /// + internal static string Volume_has_0_bytes_spanned_in_1_devices { + get { + return ResourceManager.GetString("Volume_has_0_bytes_spanned_in_1_devices", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} bytes used. + /// + internal static string Volume_has_0_bytes_used { + get { + return ResourceManager.GetString("Volume_has_0_bytes_used", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} files. + /// + internal static string Volume_has_0_files { + get { + return ResourceManager.GetString("Volume_has_0_files", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} free blocks. + /// + internal static string Volume_has_0_free_blocks { + get { + return ResourceManager.GetString("Volume_has_0_free_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} free inodes. + /// + internal static string Volume_has_0_free_inodes { + get { + return ResourceManager.GetString("Volume_has_0_free_inodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} free sectors of {1}. + /// + internal static string Volume_has_0_free_sectors_of_1 { + get { + return ResourceManager.GetString("Volume_has_0_free_sectors_of_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} inodes. + /// + internal static string Volume_has_0_inodes { + get { + return ResourceManager.GetString("Volume_has_0_inodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} inodes per block. + /// + internal static string Volume_has_0_inodes_per_block { + get { + return ResourceManager.GetString("Volume_has_0_inodes_per_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} sectors ({1} bytes). + /// + internal static string Volume_has_0_sectors_1_bytes { + get { + return ResourceManager.GetString("Volume_has_0_sectors_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has {0} sectors of {1} bytes each for a total of {2} bytes. + /// + internal static string Volume_has_0_sectors_of_1_bytes_each_for_a_total_of_2_bytes { + get { + return ResourceManager.GetString("Volume_has_0_sectors_of_1_bytes_each_for_a_total_of_2_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has always been effective.. + /// + internal static string Volume_has_always_been_effective { + get { + return ResourceManager.GetString("Volume_has_always_been_effective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has bad current secondary ait. + /// + internal static string Volume_has_bad_current_secondary_ait { + get { + return ResourceManager.GetString("Volume_has_bad_current_secondary_ait", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has been modified by Windows 9x/Me Volume Tracker.. + /// + internal static string Volume_has_been_modified_by_Windows_9x_Me_Volume_Tracker { + get { + return ResourceManager.GetString("Volume_has_been_modified_by_Windows_9x_Me_Volume_Tracker", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has been mounted {0} times of a maximum of {1} mounts before checking. + /// + internal static string Volume_has_been_mounted_0_times_of_a_maximum_of_1_mounts_before_checking { + get { + return ResourceManager.GetString("Volume_has_been_mounted_0_times_of_a_maximum_of_1_mounts_before_checking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has been mounted {0} times with no maximum no. of mounts before checking. + /// + internal static string Volume_has_been_mounted_0_times_with_no_maximum_no_of_mounts_before_checking { + get { + return ResourceManager.GetString("Volume_has_been_mounted_0_times_with_no_maximum_no_of_mounts_before_checking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has been mounted writable {0} times.. + /// + internal static string Volume_has_been_mounted_writable_0_times { + get { + return ResourceManager.GetString("Volume_has_been_mounted_writable_0_times", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has DASD limits enabled. + /// + internal static string Volume_has_DASD_limits_enabled { + get { + return ResourceManager.GetString("Volume_has_DASD_limits_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has group quotas enabled. + /// + internal static string Volume_has_group_quotas_enabled { + get { + return ResourceManager.GetString("Volume_has_group_quotas_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has log within itself. + /// + internal static string Volume_has_log_within_itself { + get { + return ResourceManager.GetString("Volume_has_log_within_itself", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has log within itself and is moving it out. + /// + internal static string Volume_has_log_within_itself_and_is_moving_it_out { + get { + return ResourceManager.GetString("Volume_has_log_within_itself_and_is_moving_it_out", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has never been backed up. + /// + internal static string Volume_has_never_been_backed_up { + get { + return ResourceManager.GetString("Volume_has_never_been_backed_up", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has never been checked. + /// + internal static string Volume_has_never_been_checked { + get { + return ResourceManager.GetString("Volume_has_never_been_checked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has never been checked (should check every {0}). + /// + internal static string Volume_has_never_been_checked_should_check_every_0_ { + get { + return ResourceManager.GetString("Volume_has_never_been_checked_should_check_every_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has never been checked up. + /// + internal static string Volume_has_never_been_checked_up { + get { + return ResourceManager.GetString("Volume_has_never_been_checked_up", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has never been mounted. + /// + internal static string Volume_has_never_been_mounted { + get { + return ResourceManager.GetString("Volume_has_never_been_mounted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has no maximum no. of mounts before checking. + /// + internal static string Volume_has_no_maximum_no_of_mounts_before_checking { + get { + return ResourceManager.GetString("Volume_has_no_maximum_no_of_mounts_before_checking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has not been cleanly umounted. + /// + internal static string Volume_has_not_been_cleanly_umounted { + get { + return ResourceManager.GetString("Volume_has_not_been_cleanly_umounted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has not been modified.. + /// + internal static string Volume_has_not_been_modified { + get { + return ResourceManager.GetString("Volume_has_not_been_modified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has persistent indexes. + /// + internal static string Volume_has_persistent_indexes { + get { + return ResourceManager.GetString("Volume_has_persistent_indexes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has spared bad blocks.. + /// + internal static string Volume_has_spared_bad_blocks { + get { + return ResourceManager.GetString("Volume_has_spared_bad_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume has user quotas enabled. + /// + internal static string Volume_has_user_quotas_enabled { + get { + return ResourceManager.GetString("Volume_has_user_quotas_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume ID: 0x{0:X16}. + /// + internal static string Volume_ID_0_X16 { + get { + return ResourceManager.GetString("Volume_ID_0_X16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume ID: {0:X4}. + /// + internal static string Volume_ID_0_X4 { + get { + return ResourceManager.GetString("Volume_ID_0_X4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume ID: {0:X8}. + /// + internal static string Volume_ID_0_X8 { + get { + return ResourceManager.GetString("Volume_ID_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume ID: 0x{0:X8}{1:X8}. + /// + internal static string Volume_ID_0_X8_1_X8 { + get { + return ResourceManager.GetString("Volume_ID_0_X8_1_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume's identification block was last written on {0}. + /// + internal static string Volume_identification_block_was_last_written_on_0 { + get { + return ResourceManager.GetString("Volume_identification_block_was_last_written_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume identifier: {0}. + /// + internal static string Volume_identifier_0 { + get { + return ResourceManager.GetString("Volume_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume identifier: 0x{0:X8}. + /// + internal static string Volume_identifier_0_X8 { + get { + return ResourceManager.GetString("Volume_identifier_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume inhibits automatic fsck. + /// + internal static string Volume_inhibits_automatic_fsck { + get { + return ResourceManager.GetString("Volume_inhibits_automatic_fsck", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is {0} of {1} in set "{2}".. + /// + internal static string Volume_is_0_of_1_in_set_2 { + get { + return ResourceManager.GetString("Volume_is_0_of_1_in_set_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is bootable.. + /// + internal static string Volume_is_bootable { + get { + return ResourceManager.GetString("Volume_is_bootable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is case sensitive. + /// + internal static string Volume_is_case_sensitive { + get { + return ResourceManager.GetString("Volume_is_case_sensitive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is clean. + /// + internal static string Volume_is_clean { + get { + return ResourceManager.GetString("Volume_is_clean", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is compressed using GZIP. + /// + internal static string Volume_is_compressed_using_GZIP { + get { + return ResourceManager.GetString("Volume_is_compressed_using_GZIP", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is compressed using LZ4. + /// + internal static string Volume_is_compressed_using_LZ4 { + get { + return ResourceManager.GetString("Volume_is_compressed_using_LZ4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is compressed using LZMA. + /// + internal static string Volume_is_compressed_using_LZMA { + get { + return ResourceManager.GetString("Volume_is_compressed_using_LZMA", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is compressed using LZO. + /// + internal static string Volume_is_compressed_using_LZO { + get { + return ResourceManager.GetString("Volume_is_compressed_using_LZO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is compressed using unknown algorithm {0}. + /// + internal static string Volume_is_compressed_using_unknown_algorithm_0 { + get { + return ResourceManager.GetString("Volume_is_compressed_using_unknown_algorithm_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is compressed using XZ. + /// + internal static string Volume_is_compressed_using_XZ { + get { + return ResourceManager.GetString("Volume_is_compressed_using_XZ", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is compressed using Zstandard. + /// + internal static string Volume_is_compressed_using_Zstandard { + get { + return ResourceManager.GetString("Volume_is_compressed_using_Zstandard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is dirty. + /// + internal static string Volume_is_dirty { + get { + return ResourceManager.GetString("Volume_is_dirty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is dirty, error code = 0x{0:X16}. + /// + internal static string Volume_is_dirty_error_code_equals_0 { + get { + return ResourceManager.GetString("Volume_is_dirty_error_code_equals_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is in a big-endian system. + /// + internal static string Volume_is_in_a_big_endian_system { + get { + return ResourceManager.GetString("Volume_is_in_a_big_endian_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is in an unknown state ({0}). + /// + internal static string Volume_is_in_an_unknown_state_0 { + get { + return ResourceManager.GetString("Volume_is_in_an_unknown_state_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is journaled.. + /// + internal static string Volume_is_journaled { + get { + return ResourceManager.GetString("Volume_is_journaled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is Level {0} revision {1}. + /// + internal static string Volume_is_Level_0_revision_1 { + get { + return ResourceManager.GetString("Volume_is_Level_0_revision_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is locked by hardware.. + /// + internal static string Volume_is_locked_by_hardware { + get { + return ResourceManager.GetString("Volume_is_locked_by_hardware", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is locked by software.. + /// + internal static string Volume_is_locked_by_software { + get { + return ResourceManager.GetString("Volume_is_locked_by_software", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is mounted.. + /// + internal static string Volume_is_mounted { + get { + return ResourceManager.GetString("Volume_is_mounted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is mounted read-only. + /// + internal static string Volume_is_mounted_read_only { + get { + return ResourceManager.GetString("Volume_is_mounted_read_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is not bootable.. + /// + internal static string Volume_is_not_bootable { + get { + return ResourceManager.GetString("Volume_is_not_bootable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is not using any journal. + /// + internal static string Volume_is_not_using_any_journal { + get { + return ResourceManager.GetString("Volume_is_not_using_any_journal", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is number {0} of {1}. + /// + internal static string Volume_is_number_0_of_1 { + get { + return ResourceManager.GetString("Volume_is_number_0_of_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is read-only. + /// + internal static string Volume_is_read_only { + get { + return ResourceManager.GetString("Volume_is_read_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is recovering orphan files. + /// + internal static string Volume_is_recovering_orphan_files { + get { + return ResourceManager.GetString("Volume_is_recovering_orphan_files", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is secure. + /// + internal static string Volume_is_secure { + get { + return ResourceManager.GetString("Volume_is_secure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is seriously inconsistent.. + /// + internal static string Volume_is_seriously_inconsistent { + get { + return ResourceManager.GetString("Volume_is_seriously_inconsistent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is testing development code. + /// + internal static string Volume_is_testing_development_code { + get { + return ResourceManager.GetString("Volume_is_testing_development_code", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is unmounted.. + /// + internal static string Volume_is_unmounted { + get { + return ResourceManager.GetString("Volume_is_unmounted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume is wrapped inside an HFS volume.. + /// + internal static string Volume_is_wrapped_inside_an_HFS_volume { + get { + return ResourceManager.GetString("Volume_is_wrapped_inside_an_HFS_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume label: {0}. + /// + internal static string Volume_label_0 { + get { + return ResourceManager.GetString("Volume_label_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume last accessed on {0:d}. + /// + internal static string Volume_last_accessed_on_0_d { + get { + return ResourceManager.GetString("Volume_last_accessed_on_0_d", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume last booted on {0}. + /// + internal static string Volume_last_booted_on_0 { + get { + return ResourceManager.GetString("Volume_last_booted_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume last checked on {0}. + /// + internal static string Volume_last_checked_on_0 { + get { + return ResourceManager.GetString("Volume_last_checked_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume last modified on {0}. + /// + internal static string Volume_last_modified_on_0 { + get { + return ResourceManager.GetString("Volume_last_modified_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume last mounted at "{0}". + /// + internal static string Volume_last_mounted_at_0 { + get { + return ResourceManager.GetString("Volume_last_mounted_at_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume last mounted on {0}. + /// + internal static string Volume_last_mounted_on_0 { + get { + return ResourceManager.GetString("Volume_last_mounted_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume last mounted on kernel version: {0}. + /// + internal static string Volume_last_mounted_on_kernel_version_0 { + get { + return ResourceManager.GetString("Volume_last_mounted_on_kernel_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume last updated on {0}. + /// + internal static string Volume_last_updated_on_0 { + get { + return ResourceManager.GetString("Volume_last_updated_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume last written on {0}. + /// + internal static string Volume_last_written_on_0 { + get { + return ResourceManager.GetString("Volume_last_written_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume modification date: {0}. + /// + internal static string Volume_modification_date_0 { + get { + return ResourceManager.GetString("Volume_modification_date_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume moves deleted files to a recycled folder. + /// + internal static string Volume_moves_deleted_files_to_a_recycled_folder { + get { + return ResourceManager.GetString("Volume_moves_deleted_files_to_a_recycled_folder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume must be backed up. + /// + internal static string Volume_must_be_backed_up { + get { + return ResourceManager.GetString("Volume_must_be_backed_up", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume name: {0}. + /// + internal static string Volume_name_0 { + get { + return ResourceManager.GetString("Volume_name_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume name is {0}. + /// + internal static string Volume_name_is_0 { + get { + return ResourceManager.GetString("Volume_name_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume number: {0}. + /// + internal static string Volume_number_0 { + get { + return ResourceManager.GetString("Volume_number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume owner: {0}. + /// + internal static string Volume_owner_0 { + get { + return ResourceManager.GetString("Volume_owner_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume owner is "{0}". + /// + internal static string Volume_owner_is_0 { + get { + return ResourceManager.GetString("Volume_owner_is_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume owner is "{0}" (ID 0x{1:X8}). + /// + internal static string Volume_owner_is_0_ID_1 { + get { + return ResourceManager.GetString("Volume_owner_is_0_ID_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume pack: {0}. + /// + internal static string Volume_pack_0 { + get { + return ResourceManager.GetString("Volume_pack_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume panics on error. + /// + internal static string Volume_panics_on_error { + get { + return ResourceManager.GetString("Volume_panics_on_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume password: "{0}". + /// + internal static string Volume_password_0 { + get { + return ResourceManager.GetString("Volume_password_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume permissions (r = read, w = write, c = create, d = delete). + /// + internal static string Volume_permissions_r_read_w_write_c_create_d_delete { + get { + return ResourceManager.GetString("Volume_permissions_r_read_w_write_c_create_d_delete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume primes DASD on boot. + /// + internal static string Volume_primes_DASD_on_boot { + get { + return ResourceManager.GetString("Volume_primes_DASD_on_boot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume record spans from block {0} to block {1}. + /// + internal static string Volume_record_spans_from_block_0_to_block_1 { + get { + return ResourceManager.GetString("Volume_record_spans_from_block_0_to_block_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume remounts read-only on error. + /// + internal static string Volume_remounts_read_only_on_error { + get { + return ResourceManager.GetString("Volume_remounts_read_only_on_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume requires UDF version {0}.{1:X2} to be read. + /// + internal static string Volume_requires_UDF_version_0_1_to_be_read { + get { + return ResourceManager.GetString("Volume_requires_UDF_version_0_1_to_be_read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume requires UDF version {0}.{1:X2} to be written to. + /// + internal static string Volume_requires_UDF_version_0_1_to_be_written_to { + get { + return ResourceManager.GetString("Volume_requires_UDF_version_0_1_to_be_written_to", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume reserves {0} sectors for system. + /// + internal static string Volume_reserves_0_sectors_for_system { + get { + return ResourceManager.GetString("Volume_reserves_0_sectors_for_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume reserves {1} tracks ({0} sectors) for system. + /// + internal static string Volume_reserves_1_tracks_0_sectors_for_system { + get { + return ResourceManager.GetString("Volume_reserves_1_tracks_0_sectors_for_system", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume root directory last modified on {0}. + /// + internal static string Volume_root_directory_last_modified_on_0 { + get { + return ResourceManager.GetString("Volume_root_directory_last_modified_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume scavenged on {0}. + /// + internal static string Volume_scavenged_on_0 { + get { + return ResourceManager.GetString("Volume_scavenged_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume sends TRIM/UNMAP commands to underlying device. + /// + internal static string Volume_sends_TRIM_UNMAP_commands_to_underlying_device { + get { + return ResourceManager.GetString("Volume_sends_TRIM_UNMAP_commands_to_underlying_device", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume serial: {0}. + /// + internal static string Volume_serial_0 { + get { + return ResourceManager.GetString("Volume_serial_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume serial: {0:X8}. + /// + internal static string Volume_serial_0_X8 { + get { + return ResourceManager.GetString("Volume_serial_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume Serial Number: {0}. + /// + internal static string Volume_Serial_Number_0 { + get { + return ResourceManager.GetString("Volume_Serial_Number_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume serial number: {0:X16}. + /// + internal static string Volume_serial_number_0_X16 { + get { + return ResourceManager.GetString("Volume_serial_number_0_X16", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume serial number: {0:X8}. + /// + internal static string Volume_serial_number_0_X8 { + get { + return ResourceManager.GetString("Volume_serial_number_0_X8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume set identifier: {0}. + /// + internal static string Volume_set_identifier_0 { + get { + return ResourceManager.GetString("Volume_set_identifier_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume should be checked on next mount.. + /// + internal static string Volume_should_be_checked_on_next_mount { + get { + return ResourceManager.GetString("Volume_should_be_checked_on_next_mount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume size: {0} blocks, {1} bytes. + /// + internal static string Volume_size_0_blocks_1_bytes { + get { + return ResourceManager.GetString("Volume_size_0_blocks_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume size {0} bytes. + /// + internal static string Volume_size_0_bytes { + get { + return ResourceManager.GetString("Volume_size_0_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume starts on device byte {0} and ends on byte {1}. + /// + internal static string Volume_starts_on_device_byte_0_and_ends_on_byte_1 { + get { + return ResourceManager.GetString("Volume_starts_on_device_byte_0_and_ends_on_byte_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume state is inconsistent.. + /// + internal static string Volume_state_is_inconsistent { + get { + return ResourceManager.GetString("Volume_state_is_inconsistent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume state on {0}. + /// + internal static string Volume_state_on_0 { + get { + return ResourceManager.GetString("Volume_state_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume supports AIX. + /// + internal static string Volume_supports_AIX { + get { + return ResourceManager.GetString("Volume_supports_AIX", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume supports DCE DFS LFS. + /// + internal static string Volume_supports_DCE_DFS_LFS { + get { + return ResourceManager.GetString("Volume_supports_DCE_DFS_LFS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume supports Linux. + /// + internal static string Volume_supports_Linux { + get { + return ResourceManager.GetString("Volume_supports_Linux", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume supports OS/2, and is case insensitive. + /// + internal static string Volume_supports_OS2_and_is_case_insensitive { + get { + return ResourceManager.GetString("Volume_supports_OS2_and_is_case_insensitive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume supports sparse files. + /// + internal static string Volume_supports_sparse_files { + get { + return ResourceManager.GetString("Volume_supports_sparse_files", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume updated on {0}. + /// + internal static string Volume_updated_on_0 { + get { + return ResourceManager.GetString("Volume_updated_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume use extents (ext4). + /// + internal static string Volume_use_extents_ext4 { + get { + return ResourceManager.GetString("Volume_use_extents_ext4", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume uses {0} bytes per block. + /// + internal static string Volume_uses_0_bytes_per_block { + get { + return ResourceManager.GetString("Volume_uses_0_bytes_per_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume uses {0} bytes per sector. + /// + internal static string Volume_uses_0_bytes_per_sector { + get { + return ResourceManager.GetString("Volume_uses_0_bytes_per_sector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume uses {0} codepage {1}. + /// + internal static string Volume_uses_0_codepage_1 { + get { + return ResourceManager.GetString("Volume_uses_0_codepage_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume uses {0} FATs. + /// + internal static string Volume_uses_0_FATs { + get { + return ResourceManager.GetString("Volume_uses_0_FATs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume uses {0} sectors per cluster ({1} bytes). + /// + internal static string Volume_uses_0_sectors_per_cluster_1_bytes { + get { + return ResourceManager.GetString("Volume_uses_0_sectors_per_cluster_1_bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume uses clusters of {0} sectors ({1} bytes) each. + /// + internal static string Volume_uses_clusters_of_0_sectors_1_bytes_each { + get { + return ResourceManager.GetString("Volume_uses_clusters_of_0_sectors_1_bytes_each", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume uses standard CP/M timestamps. + /// + internal static string Volume_uses_standard_CPM_timestamps { + get { + return ResourceManager.GetString("Volume_uses_standard_CPM_timestamps", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume uses synchronous writes. + /// + internal static string Volume_uses_synchronous_writes { + get { + return ResourceManager.GetString("Volume_uses_synchronous_writes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume uses third party timestamps. + /// + internal static string Volume_uses_third_party_timestamps { + get { + return ResourceManager.GetString("Volume_uses_third_party_timestamps", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume uses Unicode for directory entries. + /// + internal static string Volume_uses_Unicode_for_directory_entries { + get { + return ResourceManager.GetString("Volume_uses_Unicode_for_directory_entries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume UUID: {0}. + /// + internal static string Volume_UUID_0 { + get { + return ResourceManager.GetString("Volume_UUID_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume version {0}. + /// + internal static string Volume_version_0 { + get { + return ResourceManager.GetString("Volume_version_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume version {0}.{1}. + /// + internal static string Volume_version_0_1 { + get { + return ResourceManager.GetString("Volume_version_0_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume was created for {0}. + /// + internal static string Volume_was_created_for_0 { + get { + return ResourceManager.GetString("Volume_was_created_for_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume was created on {0}. + /// + internal static string Volume_was_created_on_0 { + get { + return ResourceManager.GetString("Volume_was_created_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume was created on {0} for {1}. + /// + internal static string Volume_was_created_on_0_for_1 { + get { + return ResourceManager.GetString("Volume_was_created_on_0_for_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume was last modified on {0}. + /// + internal static string Volume_was_last_modified_on_0 { + get { + return ResourceManager.GetString("Volume_was_last_modified_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume was last updated on {0}. + /// + internal static string Volume_was_last_updated_on_0_ { + get { + return ResourceManager.GetString("Volume_was_last_updated_on_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume was last written by: {0}. + /// + internal static string Volume_was_last_written_by_0 { + get { + return ResourceManager.GetString("Volume_was_last_written_by_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume was last written on {0}. + /// + internal static string Volume_was_last_written_on_0 { + get { + return ResourceManager.GetString("Volume_was_last_written_on_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume was unmonted.. + /// + internal static string Volume_was_unmonted { + get { + return ResourceManager.GetString("Volume_was_unmonted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume wraps a HFS+ volume.. + /// + internal static string Volume_wraps_a_HFS_Plus_volume { + get { + return ResourceManager.GetString("Volume_wraps_a_HFS_Plus_volume", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume write count: {0}. + /// + internal static string Volume_write_count_0 { + get { + return ResourceManager.GetString("Volume_write_count_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Veritas filesystem. + /// + internal static string VxFS_Name { + get { + return ResourceManager.GetString("VxFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WARNING: Filesystem indicates {0} blocks while device indicates {1} blocks. + /// + internal static string WARNING__Filesystem_indicates_0_blocks_while_device_indicates_1_blocks { + get { + return ResourceManager.GetString("WARNING__Filesystem_indicates_0_blocks_while_device_indicates_1_blocks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warning! Detected unknown ProDOS version ProDOS filesystem.. + /// + internal static string Warning_Detected_unknown_ProDOS_version_ProDOS_filesystem { + get { + return ResourceManager.GetString("Warning_Detected_unknown_ProDOS_version_ProDOS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WARNING: Filesystem describes a {0} bytes/sector, while device describes a {1} bytes/sector. + /// + internal static string WARNING_Filesystem_describes_a_0_bytes_sector_while_device_describes_a_1_bytes_sector { + get { + return ResourceManager.GetString("WARNING_Filesystem_describes_a_0_bytes_sector_while_device_describes_a_1_bytes_se" + + "ctor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WARNING: Filesystem describes a {0} sectors volume, bigger than device ({1} sectors). + /// + internal static string WARNING_Filesystem_describes_a_0_sectors_volume_bigger_than_device_1_sectors { + get { + return ResourceManager.GetString("WARNING_Filesystem_describes_a_0_sectors_volume_bigger_than_device_1_sectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/block. + /// + internal static string WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block { + get { + return ResourceManager.GetString("WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wii. + /// + internal static string Wii { + get { + return ResourceManager.GetString("Wii", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wii Backup. + /// + internal static string Wii_Backup { + get { + return ResourceManager.GetString("Wii_Backup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wii channel. + /// + internal static string Wii_channel { + get { + return ResourceManager.GetString("Wii_channel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WiiFit. + /// + internal static string WiiFit { + get { + return ResourceManager.GetString("WiiFit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WiiWare. + /// + internal static string WiiWare { + get { + return ResourceManager.GetString("WiiWare", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Window: {0}. + /// + internal static string Window_0 { + get { + return ResourceManager.GetString("Window_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Windows NT (8.3 mixed case). + /// + internal static string Windows_NT_8_3_mixed_case { + get { + return ResourceManager.GetString("Windows_NT_8_3_mixed_case", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to , with multi-user patches. + /// + internal static string with_multi_user_patches { + get { + return ResourceManager.GetString("with_multi_user_patches", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to , with multi-user support. + /// + internal static string with_multi_user_support { + get { + return ResourceManager.GetString("with_multi_user_support", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Writings should be verified. + /// + internal static string Writings_should_be_verified { + get { + return ResourceManager.GetString("Writings_should_be_verified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FATX Filesystem Plugin. + /// + internal static string XboxFatPlugin_Name { + get { + return ResourceManager.GetString("XboxFatPlugin_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XENIX filesystem. + /// + internal static string XENIX_filesystem { + get { + return ResourceManager.GetString("XENIX_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XFS filesystem. + /// + internal static string XFS_filesystem { + get { + return ResourceManager.GetString("XFS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XFS Filesystem Plugin. + /// + internal static string XFS_Name { + get { + return ResourceManager.GetString("XFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Xia filesystem. + /// + internal static string Xia_Name { + get { + return ResourceManager.GetString("Xia_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ZFS filesystem. + /// + internal static string ZFS_filesystem { + get { + return ResourceManager.GetString("ZFS_filesystem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ZFS Filesystem Plugin. + /// + internal static string ZFS_Name { + get { + return ResourceManager.GetString("ZFS_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to zisofs compression present.. + /// + internal static string zisofs_compression_present { + get { + return ResourceManager.GetString("zisofs_compression_present", resourceCulture); + } + } + } +} diff --git a/Aaru.Filesystems/Localization/Localization.es.resx b/Aaru.Filesystems/Localization/Localization.es.resx new file mode 100644 index 000000000..8b12e023b --- /dev/null +++ b/Aaru.Filesystems/Localization/Localization.es.resx @@ -0,0 +1,3686 @@ + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + (acl): Activar ACLs POSIX + + + Sistema de Ficheros de Disco Avanzado de Acorn + + + Sistema de Ficheros de Disco Avanzado de Acorn + + + Bloque raíz activo: {0} + + + La instantánea activa tiene el ID {0}, en el inodo {1}, con {2} bloques reservados, y la lista empezando en el bloque {3} + + + El contenedor de espacio administrativo comienza en el bloque {0} + + + Sistema de ficheros de DOS de Alexander Osipov + + + Asignar búferes secundarios de sonido y video en el arranque. + + + Asignar búfer secundario de sonido en el arranque. + + + Bloques de asignación del volumen HFS+: {0} + + + El descriptor del mapa de bits de asignación comienza en el bloque {0} + + + El Archivo de Asignación ocupa {0} bytes. + + + Todas las copias de la FAT son iguales. + + + La siguiente información puede ser incorrecta + + + Sistema de ficheros de Amiga DOS + + + Extensiones de Amiga presentes. + + + Sistema de ficheros rápido de Amiga + + + Sistema de ficheros rápido de Amiga con caché de directorio + + + Sistema de ficheros rápido de Amiga con caracteres internacionales + + + Sistema de ficheros rápido de Amiga con nombres de archivo largos + + + Sistema de ficheros original de Amiga + + + Sistema de ficheros original de Amiga con caché de directorio + + + Sistema de ficheros original de Amiga con caracteres internacionales + + + Sistema de ficheros original de Amiga con nombres de archivo largos + + + Sistema de ficheros de DOS de Alexander Osipov + + + Sistema de ficheros Apple (APFS) + + + Sistema de ficheros de Apple DOS + + + Sistema de ficheros Apple HFS+ + + + Sistema de ficheros de Apple Macintosh + + + Extensiones de Apple presentes. + + + Sistema de ficheros Apple (APFS) + + + Identificador de aplicación: {0} + + + FAT12 de Apricot + + + Protocolo de Intercambio de Atributos Arbitrarios presente. + + + ASCII + + + FAT12 de Atari + + + FAT16 de Atari + + + Sistema de ficheros de AtheOS + + + Sistema de ficheros de AtheOS + + + El Archivo de Atributos ocupa {0} bytes. + + + El búfer de transmisión de audio tiene {0} bytes. + + + La recomendación de edad para Australia es {0} + + + Un archivo puede ocupar un máximo de {0} bytes + + + Volumen vertebral + + + El INDEXF.SYS;1 de respaldo está en el sector {0} (VBN {1}) + + + Número de sencuencia de respaldo: {0} + + + ID del volumen de respaldo: 0x{0:X16} + + + Sistema de ficheros Be + + + ¡¡¡ATENCIÓN!!! ¡La siguiente información podría estar completamente incorrecta! + + + Sistema de ficheros de arranque de UNIX + + + Big-endian + + + BeFS big-endian + + + Sistema de ficheros big-endian UFS de BorderWare + + + Sistema de ficheros big-endian UFS2 + + + Sistema de ficheros big-endian UFS + + + La unidad BIOS es {0:X2}h + + + Número de unidad BIOS: 0x{0:X2} + + + La extensión del mapa de bits está en el bloque {0} + + + El mapa de bits reside en el bloque {0} + + + El mapa de bits comienza en el bloque {0} + + + 1 << block_shift == block_size => 1 << {0} == {1} (debería ser {2}) + + + El número del grupo del bloque es {0} + + + Tamaño del bloque: {0} bytes + + + SHA1 de la imagen de arranque: {0} + + + La imagen de arranque comienza en el sector {0} y ocupa {1} sectores + + + La imagen de arranque se cargará en 0x{0:X8} + + + La imagen de arranque se cargará en el segmento {0:X4}h + + + Arrancable en {0} + + + El bloque de arranque apunta a {0} como el bloque raíz + + + El área de arranque comienza en el bloque {0} + + + Bloque de arranque: + + + El bloque de arranque está en el nuevo formato. + + + El bloque de arranque debe ejecutarse. + + + Código de arranque: 0x{0:X8} + + + El código de arranque corresponde a {0} + + + SHA1 del código de arranque: {0} + + + Entorno de arranque: 0x{0:X8} + + + El descriptor del archivo de arranque comienza en el bloque {0} + + + El archivo de arranque comienza en el bloque {0} y ocupa {1} bytes + + + Opción de arranque: {0} + + + El programa de arranque reside en el fichero "{0}" + + + El programa de arranque comienza en el sector {0} y ocupa {1} sectores ({2} bytes) + + + El programa de arranque se cargará en la dirección {0:X4}h + + + Sección de arranque {0}: + + + El volumen de arranque es inconsistente. + + + Sistema de ficheros UFS de BorderWare + + + (bsdgroups): Emular el comportamiento de BSD al crear nuevos ficheros + + + Sistema de ficheros B-tree + + + Sistema de ficheros B-tree + + + Directorios cacheados: {0} + + + No se pudo encontrar el directorio raíz... + + + No se puede montar la versión {0} de LisaFS + + + No se pudo leer en Archivo de Catálogo, error {0} + + + No puede haber ficheros de más de 2GiB + + + No puede haber ficheros de más de 2TiB (ext4) + + + Puede usar índices de hash en los directorios + + + Moldeando la FAT + + + El Archivo de Catálogo ocupa {0} bytes. + + + El catálogo comienza en el sector {0} de la pista {1} + + + Sistema de ficheros de Commodore + + + Sistema de ficheros de CD-i + + + Extensiones CD-ROM XA presentes. + + + canal + + + Checksums: 0x{0:X4} y 0x{1:X4} + + + Checksum: 0x{0:X4} (calculado 0x{1:X4}) + + + Checksum: 0x{0:X8} + + + El árbol de pedazos comienza en el LBA {0} + + + Las comprobaciones de clasificación están activadas + + + Volumen limpio + + + Nombre del fichero del portapeles: {0} + + + La pila de clústeres comienza en el sector {0}, contiene {1} clústeres y está usada al {2}% + + + Clúster del directorio raíz: {0} + + + Clúster donde empieza $MFTMirr: {0} + + + Clúster donde empieza $MFT: {0} + + + cmdload se cargará con el valor {0:X4}h + + + CNID del directorio de arranque de Mac OS 8 ó 9: {0} + + + CNID del directorio de arranque de Mac OS X: {0} + + + CNID del directorio de arranque del sistema: {0} + + + CNID del directorio de la primera aplicación a ejecutar: {0} + + + CNID del directorio anteriormente abierto: {0} + + + Sistema de ficheros de Coherent UNIX + + + Consola Virtual de Commodore 64 + + + Sistema de ficheros de Commodore: + + + Funciones compatibles…: + + + Funciones compatibles en sólo lectura…: + + + Banderas compatibles: 0x{0:X} + + + El contenedor tiene {0} bytes en {1} bloques. + + + Contiene Descriptor Mejorado de Volumen. + + + Contiene Descriptor de Partición de Volumen. + + + Copyright: {0} + + + No se pudo leer el bloque cabecera de dump(8) + + + Código de país: {0} + + + Sistema de ficheros de CP/M + + + Sistema de ficheros de CP/M + + + Sistema de ficheros Cram + + + Sistema de ficheros Cram + + + Creado el {0} + + + Creando bloques de asignación. + + + Fecha de creación: {0} + + + Código del SO creador: {0} + + + Bloque raíz actual: {0} + + + Sector actual = {0} + + + El orden por CILINDROS aún no ha sido implementado. + + + LBA del bloque de cilindros: {0} + + + Ajusta del grupo de cilindros en cilindros: {0} + + + Tamaño del grupo de cilindros: {0} bloques básicos + + + LBA del área de sumario del grupo de cilindros: {0} + + + LBA del grupo de sumario de cilindros: {0} + + + Los límites DASD estaban en uso + + + Los límites DASD están operacionales + + + datos + + + Los datos pueden residir en la entrada del directorio (ext4) + + + Tamaño del grupo del fork de datos: {0} bytes + + + Identificador del preparador de los datos: {0} + + + Los datos comienzan en el bloque {0} + + + Fechado el {0} + + + Campo de fecha: año {0}, mes {1}, día {2}, hora {3}, minuto {4}. + + + Fecha de la última comprobación de integridad: {0} + + + Fecha de la última optimización: {0} + + + Los ACLs DCE están activos + + + El descriptor del depurador comienza en el bloque {0} + + + Nombre de fichero del depurador: {0} + + + (debug): Activar código de depuración + + + Asignación por defecto: {0} bloques + + + Opciones de montaje por defecto…: + + + Predeterminados UID: {0}, GID: {1} + + + La definición "{0}" tiene un directorio correcto + + + La definición contiene un campo PAR-IMPAR, cuyo significado es desconocido, así que la detección puede ser incorrecta. + + + Desentrelazando el volumen completo. + + + Demo + + + Código de densidad: {0} + + + Descripción: {0} + + + ID del desarrollador: {0} + + + El dispositivo es demasiado pequeño + + + El dispositivo usa entrelazado {0} a 1 por hardware + + + UUID del dispositivo: {0} + + + Diagnóstico + + + La banda de directorio termina en el sector {0} + + + La banda de directorio ocupa {0} sectores + + + La banda de directorio comienza en el sector {0} + + + La caché de directorio comienza en el bloque {0} + + + El directorio que contiene los inodos de los ficheros pendientes de eliminación reside en el bloque {0} del grupo de asignación {1} y ocupa {2} bloques ({3} bytes) + + + Tamaño del directorio: {0} clústeres + + + El directorio comienza en el clúster {0} + + + El directorio comienza en la pista {0} sector {1} + + + Volumen no desmontado + + + Nombre de fichero del desensamblador: {0} + + + El disco arranca siguiendo las especificaciones {0}. + + + El ID del disco es {0} + + + El disco es un disco {0} + + + El disco está preparado para la transmisión de audio + + + El disco es el número {0} de un conjunto de múltiples discos + + + La región del disco es {0} + + + El disco contiene sectores dañados + + + Tipo DOS del disco: {0} + + + Versión DOS del disco: {0} + + + El disco tiene un mapa de bits dañado + + + ID del disco: {0} + + + El disco tiene 192 PPP + + + El disco tiene 384 PPP + + + El disco tiene 48 PPP + + + El disco tiene 96 ó 135 PPP + + + El disco es de doble densidad + + + El disco es de doble cara + + + El disco pertenece al grupo {0} usuario {1} + + + El disco pertenece al usuario {0} + + + El disco es de densidad sencilla + + + El disco es de una cara + + + Nombre del disco: {0} + + + El disco rota {0} veces por segundo ({1}rpm) + + + La superficie del disco debería comprobarse en el próximo montaje. + + + Versión del disco: {0} + + + Volumen del disco número {0} + + + Desconocemos como gestionar el orden COLUMBIA, no procedemos con esta definición. + + + Desconocemos como gestionar el orden EAGLE, no procedemos con esta definición. + + + DOS (8.3 todo mayúsculas) + + + Versión de DOS: {0} + + + Número de la unidad: 0x{0:X2} + + + Número de serie de la unidad: 0x{0:X8} + + + DR-DOS arrancará este FAT32 usando CHS. + + + DR-DOS arrancará este FAT32 usando LBA. + + + Dispositivo volcado: {0} + + + Nombre del sistema de ficheros volcado: {0} + + + Volcado creado el {0} + + + Nombre del host del volcado: {0} + + + Etiqueta del volcado: {0} + + + Nivel de volcado: {0} + + + Extensión dump(8) + + + Número del volumen volcado: {0} + + + EBCDIC + + + ECMA-67 + + + ECMA-67 + + + Extensión del Sistema de Ficheros de Extents (EFS) + + + INFORMACIÓN DE EL TORITO: + + + ------------------------- + + + Entrada {0}: + + + Época alta {0} + + + Epoca baja {0} + + + Error {0} leyendo el fichero de Registros-S + + + ERROR: No se pudo encontrar el descriptor primario de volumen + + + La recomendación de edad del ESRB es {0} + + + Tamaño de la cola de eventos: {0} + + + Excepción {0}, {1}, {2} + + + Excepción leyendo archivo de audio de CD-i + + + Tabla de Asignación de Archivos Extendida de Microsoft (exFAT) + + + Sistemas de ficheros de Linux extendidos 2, 3 y 4 + + + Sistema de ficheros ext2 + + + Sistema de ficheros ext2 (antiguo) + + + Sistema de ficheros ext3 + + + Sistema de ficheros ext4 + + + Los atributos extendidos puede residir en el inodo (ext4) + + + Extensión: {0} + + + El Archivo de Extents ocupa {0} bytes. + + + Sistema de ficheros de Linux extendido + + + Sistema de ficheros ext + + + Sistema de ficheros F2FS + + + Extensión F2FS + + + Las FATs están desincronizadas. Se usará la FAT nº {0}. + + + Sistema de ficheros FATX + + + La FAT y el directorio se cachearan en la dirección {0:X4}h + + + La FAT ocupa {0} sectores + + + Tabla de Asignacion de Ficheros de Microsoft (FAT) + + + FAT+ + + + Sistema de Ficheros Rápido de BSD (o Sistema de Ficheros de UNIX, UFS) + + + El sistema de ficheros contiene {0} "bloques grandes" ({1} bytes) + + + Sistema de ficheros creado en Linux + + + Endianada del sistema de ficheros: 0x{0:X8} (debería ser 0x42494745) + + + El sistema de ficheros tiene {0} "bloques grandes" libres ({1} bytes) + + + El sistema de ficheros tiene {0} inodos sin usar + + + El sistema de ficheros ha sido montado por un IFS antigup + + + El sistema de ficheros no ha sido optimizado nunca + + + La integridad del sistema de ficheros nunca ha sido comprobada + + + El sistema de ficheros usa big endian + + + El sistema de ficheros está limpio. + + + El sistema de ficheros no fue desmontado correctamente. + + + El sistema de ficheros usa little endian + + + El sistema de ficheros es de sólo lectura + + + Nombre del sistema de ficheros: {0} + + + Carga extra del sistema de ficheros: {0} + + + Revisión del sistema de ficheros: {0}.{1} + + + La revisión del sistema de ficheros es {0}.{1:D2} + + + Tamaño del sistema de ficheros: {0} bloques básicos + + + Estado del sistema de ficheros: {0:X4} + + + Tipo del sistema de ficheros: {0} + + + Sistema de ficheros versión {0} + + + Versión del sistema de ficheros: {0}.{1}. + + + La versión del sistema de ficheros es {0}. + + + El sistema de ficheros se formateo rápidamente + + + El sistema de ficheros minimizará el tiempo de asignación + + + El sistema de ficheros minimizará la fragmentación del volumen + + + Los ficheros deben ser borrados o sobrescritos cuando son eliminados + + + Tipo de fichero en las entradas de directorio + + + El fichero {0} queda truncado. + + + Protección de fichero: 0x{0:X4} + + + DESCRIPTOR DE INFORMACIÓN DE LA ESTRUCTURA DE FICHEROS DEL VOLUMEN: + + + ------------------------------------------------------------------- + + + El sistema de ficheros fue inicializado por la versión de DOS {0} + + + Tipo del sistema de ficheros: "{0}" (debería ser "HPFS ") + + + Fichero truncado en el bloque {0} + + + Nombre de fichero del Finder: {0} + + + Información del Finder: + + + La recomendación de edad en Finlandia es {0} + + + La primera partición {0} comienza en el sector {1} + + + El primer bloque de asignación (nº 2) comienza en el sector {0}. + + + El primer grupo de cilindros comienza en el bloque {0} + + + LBA del primer bloque de datos: {0} + + + Primera zona de datos: {0} + + + La primera zona de datos es {0} + + + El primer bloque del directorio parece correcto. + + + Primer directorio del sector: {0} + + + El segmento del directorio comienza en el bloque {0} + + + El primer bloque erróneo es el {0} y el último es el {1} + + + La primera función fallida es "{0}" y la última es "{1}" + + + El primer inodo erróneo es el {0} y el último es el {1} + + + El primer error ocurrió el {0}, el último el {1} + + + La primera FAT empieza en el sector {0} y ocupa {1} sectores + + + El primer bloque libre es el {0} + + + El primer inodo libre es el {0} + + + El primer inodo es el {0} + + + Primera zona del núcleo: {0} + + + El primer grupo de metabloques es el {0} + + + Primer programa a ejecutar en el arranque: {0} + + + El primer bloque usado es el {0} + + + El primer búfer del volumen empieza en el {0} + + + Banderas: + + + Banderas: 0x{0:X} + + + Banderas: 0x{0:X8} + + + Banderas…: + + + La localización del grupo de metadatos del bloque es flexible (ext4) + + + Sistema de ficheros Fossil + + + Extensión para el sistema de ficheros Fossil + + + Encontrado superbloque Amstrad. + + + Encontrado identificador de disquete de CP/M-86. + + + Encontrado superbloque de disco duro de CP/M-86. + + + Encontrado nombre de fichero vacío en {0} + + + Encontrado nombre de fichero vacío en el directorio raíz + + + Encontrado paramétro de tipo desconocido {0} + + + Encontrado descriptor de volumen suplementario desconocido + + + La cuarta partición {0} comienza en el sector {1} + + + La lista de bloques libres está bloqueada + + + fsck en progreso + + + La FST comienza en el sector {0} y ocupa {1} bytes + + + Versión funcional: {0} + + + Gamecube + + + La recomendación de edad en Alemania es {0} + + + Número de Sistema de Ficheros Global: {0} + + + Número de paquete de Sistema de Ficheros Global: {0} + + + Tabla de grupo descriptor de checksums y inodos dispersos + + + El descriptor de grupo ocupa {0} bytes + + + Adivinado como 42BSD FFS + + + Adivinado como 43BSD FFS + + + Adivinado como 44BSD FFS + + + Adivinado como SunOS FFS + + + Adivinado como SunOS/x86 FFS + + + Adivinado como UFS + + + Sistema de ficheros HAMMER + + + Sistema de ficheros HAMMER + + + Entrelazado de sectores por hardware: {0} + + + Semilla del hash: {0:X8}{1:X8}{2:X8}{3:X8}, versión {4} + + + Tiene bloques de atributos extendidos + + + Tiene registro (ext3) + + + Tiene el registro en otro dispositivo (ext3) + + + Tiene reservas de redimensionado en línea + + + La cabeza cambia después de cada pista entera + + + La cabeza cambia después de una cara completa + + + Tamaño de la pila con 128KiB de RAM: {0} bytes + + + Tamaño de la pila con 256KiB de RAM: {0} bytes + + + Tamaño de la pila con 512KiB o más de RAM: {0} bytes + + + Sistema de ficheros HFSX. + + + Sistema de ficheros HFS. + + + HFS usa 512 bytes por sector pero el dispostiivo usa 2048 bytes por sector. + + + La estructura más alta del volumen tiene nivel {0}, revisión {1} + + + La marca de nivel máximo se desactivará + + + Sistema de ficheros del Formato High Sierra + + + Hay revisiones en uso + + + Sistema de ficheros de alto rendimiendo de OS/2 + + + Versión HPFS: {0} + + + Sistema de ficheros óptico de alto rendimiento + + + Format de Intercambio Lógico de HP + + + FAT12 de Human68k + + + FAT16 de Human68k + + + Identificado como {0} + + + Identificador: {0} + + + ID: {0}, versión {1} + + + La imagen contiene controladores ATAPI + + + La imagen contiene controladores SCSI + + + La imagen emula un disquete de 3,5" de densidad extra (MF2ED, 2,88Mb) + + + La imagen emula un disquete de 5,25" de alta densidad (MD2HD, 1,2Mb) + + + La imagen emula un disquete de 3,5" de alta densidad (MF2HD, 1,44Mb) + + + La imagen no usa emulación + + + La imagen usa un tipo de emulación desconocido ({0}) + + + Tiene un mapa entre inodos y AFS (tabla de inodos i-mágicos) + + + Implementación que montó el volumen por última vez: "{0}". + + + Funciones incompatibles…: + + + Banderas incompatibles: 0x{0:X} + + + Sistema de ficheros UFS en big-endian sin completar la inicialización + + + Sistema de ficheros UFS sin completar la inicialización + + + Tamaño incorrecto del dispositivo. + + + MDDF incorrecto encontrado + + + Tamaño del sector incorrecto + + + Los índices de los inodos residen en el bloque {0} del grupo de asignación {1} y ocupan {2} bloques ({3} bytes) + + + Tamaño de los índices de inodos: {0} bloques (debería ser 1) + + + Entrada inicial: + + + LBA del bloque de inodo: {0} + + + La caché de inodo está bloqueada + + + La lista de inodos ocupa {0} bloques + + + INOPB: 0x{0:X8} + + + Instalar límites DASD + + + Sistema de ficheros ISO9660 + + + Intentaré adivinar cuál es, pero si no es UFS2, probablemente me equivoque + + + La recomendación de edad en Japón es {0} + + + Sistema de ficheros JFS + + + Extensión JFS + + + Extensiones Joliet presentes. + + + DESCRIPTOR JOLIET DE INFORMACIÓN DEL VOLUMEN: + + + --------------------------------------------- + + + Tipo de respaldo del registro: {0} + + + (journal_data): Registrar datos y metadatos + + + (journal_data_ordered): Escribir los datos antes de registrar los metadatos + + + (journal_data_writeback): Escribir el registro antes que los datos + + + El registro tiene el inodo {0} + + + El registro está en el dispositivo {0} + + + El registro necesita recuperación (ext3) + + + El registro reside en el bloque {0} del grupo de asignación {1} y ocupa {2} bloques ({3} bytes) + + + El registro comienza en el bloque de asignación {0}. + + + El registro comienza en el byte {0} y termina en el byte {1} + + + El registro comienza en el byte {0} y ocupa {1} bytes en {2} bloques + + + UUID del registro: {0} + + + La recomendación de edad en Corea es {0} + + + Las etiquetas residen en el bloque {0} + + + Último clúster asignado: {0} + + + Fecha del último respaldo: {0} + + + Comprobado por última vez el {0} + + + Comprobado por última vez el {0} (debería comprobarse cada {1} segundos) + + + Fecha de la última comprobación: {0} + + + Último inodo asignado: {0} + + + Fecha de la última modificación: {0} + + + Montado por última vez en: "{0}" + + + Montado por última vez el {0} + + + El último inodo huérfano es el {0} + + + Última copia del directorio raíz: {0} + + + Último grupo de cilindros buscado: {0} + + + Las opciones de montaje usadas por última vez fueron: {0} + + + Escrito por última vez el {0} + + + Identificador LIF: {0} + + + Extensión del formato de intercambio lógico de HP + + + Versión LIF: {0} + + + Lista vinculada de sistemas de ficheros: 0x{0:X8} + + + Little-endian + + + BeFS little-endian + + + Cargar {0} sectores a partir del sector {1} + + + Cargar en 0x{0:X8} y saltar a 0x{1:X8} + + + Sistema de ficheros Locus + + + Sistema de ficheros Locus (antiguo) + + + Extensión del sistema de ficheros Locus + + + El árbol de registro comienza en el LBA {0} + + + Tamaño de la zona de registro: {0} + + + Nombres de archivo largos + + + La estructura más baja en el volumen tiene nivel {0}, revisión {1} + + + ID de Mac OS X del volumen: {0:X8}{1:X8} + + + mágico: "{0}" + + + mágico 0x{0:X8} (se esperaba 0x{1:X8}) + + + mágico en {0} = 0x{1:X8} (se esperaba 0x{2:X8}) + + + mágico en {0} = 0x{1:X8} (se esperaba 0x{2:X8} ó 0x{3:X8}) + + + mágico en {0} = 0x{1:X8} ó 0x{2:X8} (se esperaba 0x{3:X8} ó 0x{4:X8}) + + + mágico en 0x{0:X8} (se esperaba 0x{1:X8}) + + + mágico en 0x{0:X3} = 0x{1:X8} (se esperaba 0x{2:X8}) + + + mágico en 0x{0:X3} = 0x{1:X8} (se esperaba 0x{2:X8} ó 0x{3:X8}) + + + mágico en {1} = 0x{0:X8} + + + mágico = 0x{0:X16) (se esperaba 0x{1:X16}) + + + Mágico 1: 0x{0:X8} (debería ser 0x42465331) + + + Mágico 3: 0x{0:X8} (debería ser 0x15B6830E) + + + Mágico 2: 0x{0:X8} (debería ser 0xDD121031) + + + ID del creador: {0} + + + Nombre del creado: {0} + + + ID de la copia maestra: 0x{0:X8} + + + Bloque del Directorio Maestro: + + + Consola Virtual Master System + + + El tamaño máximo del fichero es de {0} bytes ({1} MiB) + + + Longitud máxima de un vínculo simbólico: {0} + + + Número máximo de archivos abiertos: {0} + + + Tamaño máximo de la zona: {0} + + + El MDDF está en el bloque {0} + + + Descriptor del medio: 0x{0:X2} + + + Consola Virtual Mega Drive + + + El registro de memoria comienza en {0} + + + Sistema de ficheros MicroDOS + + + Sistema de ficheros MicroDOS + + + exFAT de Microsoft + + + FAT12 de Microsoft + + + FAT16 de Microsoft + + + FAT32 de Microsoft + + + Sistema de ficheros resiliente de Microsoft + + + Sistema de ficheros Minix + + + Sistema de ficheros Minix 3 v1 + + + Sistema de ficheros Minix 3 v2 + + + Sistema de ficheros Minix v1 + + + Sistema de ficheros Minix v2 + + + Sistema de ficheros Minix v3 + + + Más de 32000 entradas de directorio (ext4) + + + Montando LisaFS v1 + + + Montando LisaFS v2 + + + Montando LisaFS v3 + + + Consola Virtual MSX o demo WiiWare + + + Multimedia activo + + + Protección multi-montaje (ext4) + + + Sistema de ficheros jerárquico de Apple (HFS) + + + Consola Virtual Neo-Geo + + + Consola Virtual NES + + + Nueva versión + + + Siguiente bloque de asignación: {0}. + + + La búsqueda del siguiente inodo libre comenzará en el inodo {0} + + + Siguiente QID: {0} + + + Siguiente bloque raíz: {0} + + + Siguiente CNID sin usar: {0} + + + Siguiente número de fichero sin usar: {0} + + + Volumen NFS + + + Sistemas de ficheros NILFS2 + + + Extensión NILFS2 + + + NINDIR: 0x{0:X8} + + + Sistemas de ficheros ópticos de Nintendo + + + cualquier región + + + Australia + + + Francia + + + Alemania + + + Italia + + + Japón + + + Corea + + + PAL + + + Rusia + + + España + + + Taiwán + + + código desconocido de región '{0}' + + + EEUU + + + Consola Virtual Nintendo 64 + + + Disco óptico de Nintendo GameCube + + + Sistema de ficheros óptico de NIntendo + + + Disco óptico de Nintendo Wii + + + No es un sistema de ficheros ext2/3/4 + + + No es un sistema de ficheros Lisa + + + No es un sistema de ficheros UFS, ¡no debería haber llegado aquí! + + + No es arrancable + + + NSPF: 0x{0:X8} + + + Sistema de ficheros de nueva tecnología (NTFS) + + + Banderas NT: 0x{0:X2} + + + Estructura en disco Ficheros-11 + + + Nombre OEM: {0} + + + Parámetros OEM: {0} + + + Antiguo dump(8) de 16-bits + + + Versión del sistema de ficheros en disco: {0} + + + Ante los errores, continuar + + + Ante los errores, entrar en pánico + + + Ante los errores, remontar en sólo lectura + + + Ante los errores el sistema de ficheros hará algo desconocido ({0}) + + + Extensión del sistema de ficheros Opera + + + Sistema de ficheros de un disco Opera. + + + Atributo extendido .LONGNAME de OS/2 + + + Fichero de bloques aleatorios de OS-9 + + + Marca de sobremontaje: 0x{0:X16} + + + Nombre de paquete: {0} + + + Las particiones no están soportadas. + + + Desplazamiento de la partición: {0} + + + Sistema de ficheros U.C.S.D. Pascal + + + Opciones del descriptor de ruta: {0} + + + ¡La table de rutas y el DVP no apuntan al mismo lugar para el directorio raíz! + + + Extension de PC Engine CD + + + Extensión de PC-FX + + + Ejecutable de PC-FX + + + La recomendación de edad PEGI es {0} + + + Sistema de ficheros profesional + + + Nombre del volumen físico: {0} + + + La recomendación de edad en Portugal es {0} + + + Volcado anterior creado el {0} + + + Pre-asignar directorios + + + Procesando DV vuelta nº {0} + + + Sistema de ficheros de Apple ProDOS + + + ProDOS usa 512 bytes por sector y el dispositivo usa 2048. + + + Se requiere al menos la versión 1 de ProDOS para leer este volumen. + + + Se usó la versión 1 de ProDOS para crear este volumen. + + + Sistema de ficheros profesional v1 + + + Sistema de ficheros profesional v2 + + + Sistema de ficheros profesional v3 + + + Promocional o Consola Virtual TurboGrafx + + + Publicado por {0} + + + Identificador del publicador: {0} + + + DVP no apunta a un directorio raíz correcto, comprobando tabla de rutas... + + + Sistema de ficheros QNX4 + + + Extensión QNX4 + + + Sistema de ficheros QNX6 (Audi) + + + Sistema de ficheros QNX6 + + + Extensión QNX6 + + + Paso RAID: {0} + + + Extensión del archivo de acceso aleatorio de OS-9 + + + Las lecturas deberían verificarse + + + Leyendo BPB + + + Leyendo directorio. + + + Leyendo FAT12 + + + Leyendo FAT16 + + + Leyendo FAT32 + + + Leyendo directorio raíz + + + Leyendo sector {0} + + + Leyendo superbloque + + + Banderas compatibles en sólo lectura: 0x{0:X} + + + Volumen de sólo lectura + + + Protección de registro: 0x{0:X4} + + + Volcados reducidos de grupos de bloques + + + Número de superbloques reducidos + + + Extensión del sistema de ficheros resiliente + + + Extensión del sistema de ficheros Reiser 4 + + + Sistema de ficheros Reiser 3.5 + + + Sistema de ficheros Reiser 3.6 + + + Sistema de ficheros Reiser 4 + + + Sistema de ficheros Reiser Jr. + + + Extensión del sistema de ficheros Reiser + + + Volumen extraíble + + + El superbloque de reemplazo reside en el bloque {0} + + + Volumen replicado + + + Atributos reservados establecidos: {0:X2} + + + Tamaño del grupo del fork de recursos: {0} bytes + + + Resincronizar límites DASD + + + Protocolo de Intercambio Rock Ridge presente. + + + El checksum del bloque raíz es 0x{0:X8} + + + El bloque raíz de extensión reside en el bloque {0} + + + Tamaño del bloque del directorio raíz: {0} bytes + + + El descriptor del directorio raíz comienza en el bloque {0} + + + Identificador del directorio raíz: 0x{0:X8} + + + El directorio raíz reside en el bloque {0} + + + El directorio raíz reside en el inodo {0} + + + Tamaño del directorio raíz: {0} bloques, {1} bytes + + + El directorio raíz comienza en el clúster {0} + + + Tamaño del inodo de la carpeta raíz: {0} bloques (debería ser 1) + + + El inodo del directorio raíz reside en el bloque {0} del grupo de asignación {1} y ocupa {2} bloques ({3} bytes) + + + El nodo raíz del árbol-B de extents reside en el bloque {0} + + + El nodo raíz del árbol-B de objetos reside en el bloque {0} + + + El contenedor raíz de objetos empieza en el bloque {0} + + + La raíz reside en el inodo {0} + + + La raíz empieza en el fragmento {0} + + + El árbol raíz empieza en el LBA {0} + + + Novel RPS: {0} + + + Sistema de ficheros RT-11 + + + Código de resultado del carroñero: 0x{0:X8} + + + Buscando el bloque raíz en el sector {0} + + + El bloque hogar secundario está en el sector {0} (VBN {1}) + + + La segunda partición {0} empieza en el sector {1} + + + Se está usando la 2ª FAT + + + La 2ª FAT comienza en {0} + + + ID de sección: {0} + + + Máximo de {0} sectores asginados en una pista + + + Sector {0}, ID de fichero 0x{1:X4} + + + Sector del directorio de ACL: {0} + + + Sector del bloque de parámetros FAT32 de respaldo: {0} + + + Sector de la lista de bloques dañados: {0} + + + Sector del directorio de páginas de código: {0} + + + Sector del mapa de bits de banda de directorio: {0} + + + Sector del primer bloque de asignación: {0} + + + Sector de los mapas de bits de espacio libre: {0} + + + Sector de la estructura FSINFO: {0} + + + Sector del directorio de revisiones: {0} + + + Sector del nodo-F del directorio raíz: {0} + + + Sesgo del sector 0: {0} por pista + + + Máscara de seguridad: 0x{0:X8} + + + Tipo de criterio de selección: {0} + + + Serie: 0x{0:X16} + + + Número de serie: 0x{0:X8} + + + Número de serie del ordenador Lisa que puede usar el software de este volumen: {0} + + + Número de serie del ordenador Lisa que creó este volumen: {0} + + + Set-uid y set-gid están desactivados + + + SmartFileSystem + + + Sistema de ficheros de extents de SGI + + + La cara 1 usa entrelzado {0} a 1 por software + + + La cara 0 usa entrelzado {0} a 1 por software + + + Firma: 0x{0:X2} + + + El hash firmado de directorio está en uso + + + Tamaño de los bloques de asignación: {0} bytes + + + Sesgo: {0} + + + SmartFileSystem + + + Sistema de ficheros Solar_OS + + + Sistema de ficheros Solar_OS + + + Origen: {0} + + + CRC32 del Bloque Reserva: {0:X8} + + + Mágico 1 del Bloque Reserva: 0x{0:X8} (debería ser 0xF9911849) + + + Mágico 2 del Bloque Reserva: 0x{0:X8} (debería ser 0xFA5229C5) + + + Los bloques dispersos de directorio están en uso + + + Sistema de ficheros Squash + + + Sistema de ficheros Squash + + + LBA del superbloque estándar: {0} + + + Bloque de comienzo del volumen HFS+: {0} + + + El archivo de arranque ocupa {0} bytes. + + + Nombre de fichero de la pantalla de arranque: {0} + + + CRC32 del SuperBloque: {0:X8} + + + El superbloque ocupa {0} bytes + + + El superbloque está siendo modificado + + + El superbloque se modificó por última vez el {0} + + + El superbloque se actualizó por última vez el {0} + + + LBA del superbloque: {0} + + + Mágica 1 del superbloque: 0x{0:X8} (debería ser 0xF995E849) + + + Mágica 2 del superbloque: 0x{0:X8} (debería ser 0xFA53E9C5) + + + El superbloque reside en el bloque {0} + + + El superbloque parece corrupto, la siguiente información podría ser incorrecta + + + Consola Virtual Super Nintendo + + + Soporta marcas de tiempo al nanosegundo y tiempo de creación (ext4) + + + Soporta volúmenes de más de 2^32 bloques (ext4) + + + Nombre de fichero del sistema: {0} + + + La pila del sistema se extenderá {0} bytes y una {1} fracción de la RAM disponible + + + Identificador del sistema: {0} + + + Sistema, dueño, grupo, mundo + + + Tipo de sistema: 0x{0:X2} + + + INFORMACIÓN DEL PROTOCOLO DE USO COMPARTIDO DE SISTEMA: + + + ------------------------------------------------------- + + + El Procolo de Uso Compartido de Sistema está presente. + + + Sistema de ficheros System V Release 2 + + + Sistema de ficheros System V Release 4 + + + Sistema de ficheros UNIX System V + + + Los registros-S empiezan en el sector {0} y ocupan {1} bloques + + + Hay {0} bloques reservados antes del volumen + + + Hay un estimado de {0} inodos libres antes de comenzar la siguiente búsqueda + + + Hay muchas variantes de UFS usando valores superpuestos en los mismos campos + + + Hay bloques dañados en el archivo de extents. + + + No hay inodos huérfanos. + + + Hay CNIDs reutilizadas. + + + La siguiente información podría ser incorrecta para este volumen. + + + La tercera partición {0} empieza en el sector {1} + + + El bloque hogar está en el sector {0} (VBN {1}) + + + Este es un disco de SegaCD / MegaCD. + + + Este es un disco de Sega Dreamcast. + + + Este es un disco de Sega Saturn. + + + Este es el paquete primario + + + Puede no ser HPFS, la siguiente información podría no ser correcta. + + + Este superbloque reside en el bloque físico {0}. + + + Está versión no está soportada aún. + + + Este volumen podría esta corrupto. + + + Título: {0} + + + Sector {0} ({1:X2}:{2:X2}:{3:X2}), sin procesar, modo {4} + + + Sector {0} ({1:X2}:{2:X2}:{3:X2}), sin procesar, modo 2 forma 4}, fichero número {5}, canal número {6}, submodo {7}, información de codificación {8} + + + Sector {0}, procesado, modo 2 forma {1}, fichero número {2}, canal número {3}, submodo {4}, información de codificación {5} + + + Sector {0}, procesado, modo 2 forma 2 + + + Sector {0}, procesado, modo 0, 1 ó 2 forma 1 + + + Sector {0}, sin procesar, audio + + + La asignación de pistas es hacia adelante + + + La asignación de pistas es hacia atrás + + + Recorriendo el directorio. + + + Intentando todas las definiciones conocidas. + + + Intentando definición "{0}" + + + Intentando cargar las definicones. + + + Consola Virtual TurboGrafx CD + + + Formato de Disco Universal + + + Sistema de ficheros UFS2 + + + Sistema de ficheros UFS + + + (uid16): Desactivar UIDs y GIDs de 32-bits + + + La recomendación de edad en Reino Unido es {0} + + + No se pudo cachear todos los ficheros. + + + No se pudieron leer los bloques de arranque + + + No se pudo leer el cargador de arranque + + + No se pudo leer el catálogo. + + + No se pudo leer el MDDF + + + No se pudo leer el fichero de registros-S + + + No se pudo leer el mapa de bits del volumen + + + mágico sin alinear: "{0}" + + + El dispositivo usado no soporta las etiquetas Lisa + + + El medio usado tenía errores + + + Sistema de ficheros UNICOS + + + Extensión del sistema de ficheros UNICOS + + + Formato de Disco Universal + + + Sistema de ficheros de UNIX 7ª edición + + + Sistema de ficheros de arranque de UNIX + + + Código de arranque desconocido. + + + Desconocida + + + Funciones compatibles desconocidas: {0:X8} + + + Banderas desconocidas: {0:X8} + + + Bandera desconocida 0x40 en banderas 1 activa + + + Bandera desconocida 0x40 en banderas 2 activa + + + Bandera desconocida 0x80 en banderas 2 activa + + + Desconocemos como funciona el orden de caras {0} + + + Funciones incompatibles desconocidas: {0:X8} + + + Versión de LisaFS desconocida: {0} + + + Valor de optimización desconocido: 0x{0:X8} + + + Tipo de orden "{0}" desconocido, no se procederá con esta definición. + + + SO desconocido ({0}) + + + tipo de partición desconocido ({0}) + + + Se requiere al menos la versión desconocida de ProDOS con el campo {0} para leer este volumen. + + + Este volumen fue creado con la versión desconocida de ProDOS con el campo {0}. + + + Publicador desconocido '{0}' + + + Funciones compatibles en sólo lectura desconocidas: {0:X8} + + + Opciones por defecto de montaje desconocidas: {0:X8} + + + Banderas activadas desconocidas: {0:X8} + + + Desconocida + + + Estructuras desconocidas: + + + Valor de s_type desconocido: 0x{0:X8} + + + tipo desconocido '{0}' + + + Hash sin firmar de directorio en uso + + + actualización + + + Volumen replicado por el usuario + + + (user_xattr): Activar atributos extendidos especificados por el usuario + + + Usa árboles-B para los directorios + + + Usa compresión + + + Usar LFN si está disponible, si no usar .LONGNAME (por defecto) + + + Usando BPB de Apricot + + + Usando BPB de Atari + + + Usando BPB forzado de DEC Rainbow + + + Usando BPB de DOS 2.0 + + + Usando BPB de DOS 3.0 + + + Usando BPB de DOS 3.2 + + + Usando BPB de DOS 3.3 + + + Usando BPB de DOS 3.4 + + + Usando BPB de DOS 4.0 + + + Usando BPB de FAT32 + + + Usando BPB forzado. + + + Usando BPB forzado para 5,25" DSDD. + + + Usando BPB forzado para 5,25" SSDD. + + + Usando BPB de Human68k + + + Usando BPB de MSX + + + Usando BPB corto de FAT32 + + + Utilidad + + + UUID: {0} + + + Sistema de ficheros Veritas + + + Versión 1: 0x{0:X4} + + + Versión 2: 0x{0:X4} + + + Versión {0} + + + Versión {0}.{1} + + + Sistema de ficheros VMware + + + Sistema de ficheros VMware + + + Volumen {0} de {1} en este sistema de ficheros + + + Atributos del volumen: {0:X2} + + + Volumen respaldado el {0} + + + El mapa de bits del volumen es válido + + + El mapa de bits del volumen ocupa {0} sectores ({1} bytes) + + + Sector (en 512-bytes) de comienzo del mapa de bits del volumen: {0} + + + El mapa de bits del volumen empieza en el sector {0} (VBN {1}) + + + El bloque del volumen ocupa {0} bytes + + + El tamaño de bloque del volumen es {0} bytes + + + El volumen no puede ser escrito por ninguna versión de UDF mayor que {0}.{1:X2} + + + El volumen puede ser destruido + + + El volumen se puede llenar hasta el {0}% + + + El volumen se puede montar {0} veces antes de necesitar una comprobación + + + El volumen se puede leer + + + El volumen se puede renombrar + + + El volumen se puede escribir + + + El catálogo del volumen se creó el {0} + + + Comentario del volumen: {0} + + + El volumen graba en grupos de 1 + + + El volumen graba vagamente + + + El volumen expresa conformidad con {0} + + + El volumen contiene {0} bloques ({1} bytes) + + + El volumen contiene {0} entradas de directorio + + + El volumen contiene {0} ficheros + + + El volumen contiene {0} ficheros y {1} directorios + + + El volumen contiene {0} particiones + + + El volumen continúa ante los errores + + + El volumen se copió el {0} + + + El volumen se creó el {0} + + + El volumen se creó usando el núcleo versión: {0} + + + Fecha de creación del volumen: {0} + + + INFORMACIÓN DEL DESCRIPTOR DEL VOLUMEN: + + + --------------------------------------- + + + Formato del disco del volumen: {0} + + + El volumen no graba en el registro + + + El volumen no caduca. + + + El volumen no necesita caché. + + + Volumen edición {0} + + + Fecha efectiva del volumen: {0} + + + El volumen termina en el {0} + + + Fecha de expiración del volumen: {0} + + + Banderas del volumen: 0x{0:X2} + + + Banderas del volumen: 0x{0:X4} + + + El formato del volumen es {0} + + + El volume va desde el byte {0} hasta el byte {1}, ocupando {2} bytes + + + El volumen tiene {0} bloques + + + El volumen tiene {0} bloques ({1} bytes) + + + El volumen tiene {0} bloques de {1} bytes cada uno + + + El volumen tiene {0} bloques de {1} bytes cada uno ({2} bytes totales) + + + El volumen tiene {0} bloques de {1} bytes para un total de {2} bytes + + + El volumen tiene {0} bloques usados ({1} bytes) + + + El volumen tiene {0} bloques con {1} libres + + + El volumen tiene {0} bytes + + + El volumen tiene {0} bytes en {1} zonas + + + El volumen tiene {0} bytes por bloque + + + El volumen tiene {0} bytes distribuidos en {1} dispositivos + + + El volumen tiene {0} bytes usados + + + El volumen tiene {0} ficheros + + + El volumen tiene {0} bloques libres + + + El volumen tiene {0} inodos libres + + + El volumen tiene {0} sectores libres de {1} + + + El volumen tiene {0} inodos + + + El volumen tiene {0} inodos por bloque + + + El volumen tiene {0} sectores ({1} bytes) + + + El volumen tiene {0} sectores de {1} bytes cada uno para un total de {2} bytes + + + El volumen siempre ha sido efectivo. + + + El volumen tiene la AIT secundaria actual dañada + + + El volumen ha sido modificado por el Gestor de Volúmenes de Windows 9x/Me. + + + El volumen ha sido montado {0} veces de un máximo de {1} antes de ser comprobado + + + El volumen ha sido montado {0} veces sin un nº máximo antes de ser comprobado + + + El volumen ha sido montado para escritura {0} veces. + + + El volumen tiene los límites DASD activados + + + El volumen tiene las cuotas grupales activadas + + + El volumen contiene el registro + + + El volumen contiene el registro y lo está moviendo fuera + + + El volumen nunca ha sido respaldado + + + El volumen nunca ha sido comprobado + + + El volumen nunca ha sido comprobado (debería serlo cada {0}) + + + El volumen nunca ha sido comprobado + + + El volumen nunca ha sido montado + + + El volumen no ha sido desmontado limpiamente + + + El volumen no ha sido modificado. + + + El volumen no tiene un nº máximo de montajes antes de ser comprobado + + + El volumen tiene índices persistentes + + + El volumen tiene bloques dañados reasignados. + + + El volumen tiene las cuotas de usuario activadas + + + El bloque de identificación del volumen fue escrito por última vez el {0} + + + Identificador del volumen: {0} + + + Identificador del volumen: 0x{0:X8} + + + ID del volumen: 0x{0:X16} + + + ID del volumen: 0x{0:X4} + + + ID del volumen: 0x{0:X8} + + + ID del volumen: 0x{0:X8}{1:X8} + + + El volumen inhibe el fsck automático + + + El volumen es el {0} de {1} en el conjunto "{2}". + + + El volumen es arrancable. + + + El volumen es sensible a las mayúsculas. + + + El volumen está limpio + + + El volumen está comprimido usando GZIP + + + El volumen está comprimido usando LZ4 + + + El volumen está comprimido usando LZMA + + + El volumen está comprimido usando LZO + + + El volumen está comprimido usando el algoritmo desconocido {0} + + + El volumen está comprimido usando XZ + + + El volumen está comprimido usando Zstandard + + + El volumen está sucio + + + El volumen está sucio, código de error = 0x{0:X16} + + + El volumen está en un estado desconocido ({0}) + + + El volumen está en un sistema big-endian. + + + El volumen usa un registro. + + + El volumen tiene nivel {0} revisión {1} + + + El volumen está bloqueado por hardware. + + + El volumen está bloqueado por software. + + + El volumen está montado. + + + El volumen está montado en sólo lectura + + + El volumen no es arrancable. + + + El volumen no usa ningún registro + + + El volumen es el nº {0} de {1} + + + El volumen es de sólo lectura + + + El volumen está recuperando ficheros huérfanos + + + El volumen es seguro + + + El volumen presenta inconsistencias serias. + + + El volumen está probando código en desarrollo. + + + El volumen está desmontado. + + + El volumen está envuelto en un volumen HFS. + + + Etiqueta del volumen: {0} + + + El volumen fue accedido por última vez el {0:d} + + + El volumen arrancó por última vez el {0} + + + El volumen fue comprobado por última vez el {0} + + + El volumen fue modificado por última vez el {0} + + + El volumen fue montado por última vez en "{0}" + + + El volumen fue montado por última vez el {0} + + + El volumen fue montado por última vez por el núcleo versión {0} + + + El volumen fue actualizado por última vez el {0} + + + El volumen fue escrito por última vez el {0} + + + Fecha de modificación del volumen: {0} + + + El volumen mueve los archivos eliminados a una carpeta de reciclaje + + + El volumen debe ser respaldado + + + Nombre del volumen: {0} + + + El nombre del volumen es {0} + + + Número del volumen: {0} + + + Dueño del volumen: {0} + + + El dueño del volumen es "{0}" + + + El dueño del volumen es "{0}" (ID 0x{1:X8}) + + + Paquete del volumen: {0} + + + El volumen entra en pánico ante un error + + + Contraseña del volumen: "{0}" + + + Permisos del volumen (r = lectura, w = escritura, c = creación, d = eliminación) + + + El volumen prima DASD al arranque + + + El registro del volumen se extiende sde el bloque {0} al {1} + + + El volumen se remonta en sólo lectura ante un error + + + El volumen requiere la versión {0}.{1:X2} de UDF para ser leído + + + El volumen requiere la versión {0}.{1:X2} de UDF para ser escrito + + + El volumen reserva {0} sectores para el sistema + + + El volumen reserva {1} pistas ({0} sectores) para el sistema + + + El directorio raíz del volumen fue modificado por últiva vez el {0} + + + El volumen fue carroñeado el {0} + + + El volumen envía comandos TRIM/UNMAP al dispositivo que lo contiene + + + Serie del volumen: {0} + + + Serie del volumen: {0:X8} + + + El volumen debería comprobarse en el siguiente montaje. + + + Identificador del conjunto del volumen: {0} + + + Número de serie del volumen: {0:X8} + + + Número de serie del volumen: {0:X16} + + + Número de serie del volumen: {0} + + + Tamaño del volumen: {0} bloques, {1} bytes + + + El volumen ocupa {0} bytes + + + El volumen empieza en el byte {0} del dispositivo y termina en el {1} + + + El estado del volumen es inconsistente. + + + Estado del volumen el {0} + + + El volumen soporta AIX + + + El volumen soporta DCE DFS LFS + + + El volumen soporta Linux + + + El volumen soporta OS/2 y es insensible a las mayúsculas + + + El volumen soporta ficheros dispersos + + + El volumen fue actualizado el {0} + + + El volumen usa {0} bytes por bloque + + + El volumen usa {0} bytes por sector + + + El volumen usa la página de código {1} de tipo {0} + + + El volumen usa {0} FATs + + + El volumen usa {0} sectores por clúster ({1} bytes) + + + El volumen usa clústeres de {0} sectores ({1} bytes) cada uno + + + El volumen usa los estampados de fecha estándares de CP/M + + + El volumen usa escrituras síncronas + + + El volumen usa estampados de fechas de terceras partes + + + El volumen usa Unicode para las entradas de directorio + + + El volumen usa extents (ext4) + + + UUID del volumen: {0} + + + Volumen versión {0} + + + Volumen versión {0}.{1} + + + El volumen fue creado para {0} + + + El volumen fue creado el {0} + + + El volumen fue creado el {0} para {1} + + + El volumen fue modificado por última vez el {0} + + + El volumen fue actualizado por última vez el {0} + + + El volumen fue escrito la última vez por: {0} + + + El volumen fue desmontado + + + El volumen fue escrito por última vez el {0} + + + El volumen envuelve un volumen HFS+. + + + Contador de escrituras del volumen: {0} + + + Sistema de ficheros Veritas + + + ¡Atención! Detectado sistema de ficheros ProDOS de una versión de ProDOS desconocida + + + ATENCIÓN: El sistema de ficheros describe sectores de {0} bytes pero el dispositivo lo hace de {1} bytes + + + ATENCIÓN: El sistema de ficheros describe un volumen de {0} sectores, más grande que el dispositivo ({1} sectores) + + + ATENCIÓN: El sistema de ficheros describe bloques de {0} bytes pero el dispositivo lo hace de {1} bytes + + + ATENCIÓN: El sistema de ficheros describe {0} bloques pero el dispositivo indica {1} + + + Wii + + + WiiFit + + + WiiWare + + + Respaldo de Wii + + + Canal de Wii + + + Windows NT (8.3 mayúsculas mezcladas) + + + Ventana: {0} + + + , con parches multi-usuario + + + , con soporta multi-usuario + + + Las escrituras se verificarán + + + Extensión del sistema de ficheros FATX + + + Sistema de ficheros de XENIX + + + Sistema de ficheros XFS + + + Extensión del sistema de ficheros XFS + + + Sistema de ficheros Xia + + + Sistema de ficheros ZFS + + + Extensión del sistema de ficheros ZFS + + + Compresión zisofs presente. + + + {0}[{1}] = Tipo de datos desconocido {2} + + + {0} bloques de asignación. + + + {0} grupos de asignación en el volumen + + + {0} bloques ({1} bytes) + + + {0} bloques ({1} bytes) libres de {2} ({3} bytes) + + + {0} bloques, {1} banderas y {2} inodos por grupo + + + {0} bloques para el cargador de arranque ({1} bytes) + + + {0} bloques libres + + + {0} bloques libres ({1} bytes) + + + {0} bloques en el cilindro 0 + + + {0} bloques en el sistema de ficheros + + + {0} bloques en el volumen + + + {0} bloques en el volumen ({1} bytes) + + + {0} bloques en la caché del mapa de bits del volumen + + + {0} bloques en la caché del volumen + + + {0} bloques en la caché común del volumen + + + {0} bloques menos uno + + + {0} bloques menos uno menos el desplazamiento del MDDF + + + {0} bloques de {1} bytes + + + {0} bloques en todos los discos de datos + + + {0} bloques en la colección sumaria de clústeres + + + {0} bloques en el mapa de inodos ({1} bytes) + + + {0} bloques en el mapa de zona ({1} bytes) + + + {0} bloques pendientes de ser liberados + + + {0} bloques por grupo de asignación + + + {0} bloques por grupo de asignación ({1} bytes) + + + {0} bloques por clúster + + + {0} bloques por cilindro + + + {0} bloques por cilindro ({1} bytes) + + + Máximo de {0} bloques por grupo de cilindro + + + {0} bloques por separación ({1} bytes) + + + {0} bloques por grupo + + + {0} bloques por rotación + + + {0} bloques por segmento + + + {0} bytes por bloque + + + {0} bytes en el mapa de bits de asignación + + + {0} bytes en un bloque básico + + + {0} bytes en un bloque de fragmento + + + {0} bytes en un grupo de cilindro + + + {0} bytes en el sumario de un grupo de cilindro + + + {0} bytes en un bloque de borrado + + + {0} bytes en LisaInfo + + + {0} bytes en el árbol-B del catálogo + + + {0} bytes en el árbol-B de extents + + + {0} bytes en el volumen + + + {0} bytes por hoja + + + Máximo de {0} bytes por fichero + + + {0} bytes por nodo + + + {0} bytes en el mapa de bits + + + {0} bytes por bloque de asignación. + + + {0} bytes por bloque + + + {0} bytes por entrada de directorio + + + {0} bytes por fragmento + + + {0} bytes por bloque índice + + + {0} bytes por inodo + + + {0} bytes por inodo + + + {0} bytes por registro MFT + + + {0} bytes por página + + + {0} bytes por sector. + + + {0} bytes por sector (sin procesar) + + + {0} bytes por zona + + + {0} bytes por sector + + + {0} bytes por división + + + {0} bytes para asignar. + + + {0} bytes para asignar cuando se extiende un árbol-B de catálogo + + + {0} bytes para asignar cuando se extiende un árbol-B de extents + + + {0} bytes para asignar cuando se extiende un fichero. + + + {0} caracteres en un nombre de fichero + + + {0} clústeres en el volumen. + + + {0} clústeres por bloque índice ({1} bytes) + + + {0} clústeres por registro MFT ({1} bytes) + + + {0} páginas de código usadas en el volumen + + + {0} directorios asignados contiguamente + + + Máximo de {0} bloques contiguos + + + {0} cilindros + + + {0} cilindros por grupo + + + {0} cilindros en el volumen + + + {0} grupos de cilindro + + + {0} grupos de cilindro en el volumen + + + {0} bloques de datos ({1} bytes) + + + {0} bloques de datos en el volumen + + + {0} bloques de datos en el volumen ({1} bytes) + + + {0} bloques de datos en el volumen, {1} libres + + + {0} zonas de datos ({1} bytes) + + + {0} directorios + + + {0} directorios en el directorio raíz + + + {0} directorios en el volumen + + + {0} entradas en el directorio raíz. + + + {0} entradas por bloque de directorio + + + {0} = nvlist[] de {1} elementos, no se puede mostrar + + + {0} = Tipo de datos desconocido {1} + + + {0} errores registrados + + + {0} FATs + + + {0} ficheros en el directorio raíz + + + {0} ficheros en el volumen + + + Tamaño del grupo FLEX_BG: {0} + + + {0} fragmentos por bloque + + + {0} bloques libres. + + + {0} bloques libres ({1} bytes) + + + {0} bloques libres en lista ({1} bytes) + + + {0} clústeres libres + + + {0} fragmentos libres + + + {0} inodos libres + + + {0} inodos libres en lista + + + {0} inodos libres en el volumen + + + {0} nodos-D alternativos libres + + + {0} zonas libres en el volumen ({1} bytes) + + + {0} cabezas. + + + {0} cabezas por cilindro + + + {0} sectores ocultos antes del BPB. + + + {0} sectores ocultos antes del sistema de ficheros + + + {0} zonas imap ({1} bytes) + + + {0} inodos + + + {0} inodos libres de {1} + + + {0} inodos en el volumen + + + {0} inodos en el volumen, {1} libres + + + {0} inodos en el volumen, {1} libres ({2}%) + + + {0} inodos pendientes de liberarse + + + {0} inodos por grupo de cilindro + + + {0} inodos con {1} libres ({2}%) + + + {0} es el primer bloque de datos + + + {0} no está establecido + + + {0} KiB se han escrito en el volumen + + + {0} sectores lógicos ({1} bytes) por sector físico + + + Máximo de {0} ficheros en el volumen + + + {0}ms para el siguiente bloque óptimo + + + {0} nanosegundos para programar + + + {0} nanosegundos para acceso aleatorio + + + {0} nanosegundos para un ciclo de lectura + + + {0} nanosegundos para un ciclo de escritura + + + El {0}% de los bloques deben estár libres + + + {0} bloques reservados y {1} libres + + + {0} ficheros reservados + + + {0} posiciones rotacionales + + + {0} segundos para la espera de protección ante multi-montaje, en el bloque {1} + + + {0} secciones + + + {0} secciones por zona + + + {0} sectores + + + {0} sectores ({1} bytes) por bloque + + + {0} sectores ({1} bytes) por clúster + + + {0} sectores marcados dañados + + + {0} sectores por cilindro + + + {0} sectores ocultos antes del BPB + + + {0} sectores en el directorio. + + + {0} sectores en el volumen ({1} bytes). + + + {0} sectores por clúster. + + + {0} sectores por clúster ({1} bytes) + + + {0} sectores por FAT. + + + {0} sectores por pista. + + + {0} sectores reservados entre el BPB y la FAT. + + + {0} sectores por pista + + + {0} segmentos + + + {0} segmentos por sección + + + {0} bloques de reserva + + + {0} entradas de revisiones en total + + + {0} nodos-D de reserva en total + + + {0} pistas + + + {0} pistas por cilindro + + + {0} pistas en el volumen + + + {0} bloques de asignación libres. + + + {0} bloques usados ({1} bytes) + + + {0} entradas de revisión usadas + + + {0} sectores usados en el volumen + + + {0} bloques de asignación en el volumen + + + {0} zonas zmap ({1} bytes) + + + {0} zonas en el volumen ({1} bytes) + + + {0} zonas en el volumen + + + {0} zonas reservadas para imágenes del núclero ({1} bytes) + + + {0} µseg para cambiar la cabeza + + + {0} µseg para posicionar de pista a pista + + + 1024 bytes por bloque + + + 2048 bytes por bloque + + + 4096 bytes por bloque + + + 512 bytes por bloque + + + Este disco contiene un fichero relativo. Estos no han sido totalmente probados, por favor abra un reporte de errores y adjunte esta imagen de disco. + + \ No newline at end of file diff --git a/Aaru.Filesystems/Localization/Localization.resx b/Aaru.Filesystems/Localization/Localization.resx new file mode 100644 index 000000000..a8b4a9784 --- /dev/null +++ b/Aaru.Filesystems/Localization/Localization.resx @@ -0,0 +1,3695 @@ + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + Boot Block: + + + Boot block is in new format. + + + Boot block should be executed. + + + System heap will be extended by {0} bytes and a {1} fraction of the available RAM + + + Allocate secondary sound buffer at boot. + + + Allocate secondary sound and video buffers at boot. + + + System filename: {0} + + + Finder filename: {0} + + + Debugger filename: {0} + + + Disassembler filename: {0} + + + Startup screen filename: {0} + + + First program to execute at boot: {0} + + + Clipboard filename: {0} + + + Maximum opened files: {0} + + + Event queue size: {0} + + + Heap size with 128KiB of RAM: {0} bytes + + + Heap size with 256KiB of RAM: {0} bytes + + + Heap size with 512KiB of RAM or more: {0} bytes + + + Apple DOS File System + + + Catalog starts at sector {0} of track {1} + + + File system initialized by DOS release {0} + + + Disk volume number {0} + + + Sectors allocated at most in track {0} + + + {0} tracks in volume + + + {0} sectors per track. + + + {0} bytes per sector. + + + Track allocation is forward + + + Track allocation is reverse + + + Incorrect device size. + + + Partitions are not supported. + + + Incorrect sector size. + + + Unable to read catalog. + + + Unable cache all files. + + + Apple Hierarchical File System + + + HFS uses 512 bytes/sector while device uses 2048 bytes/sector. + + + Master Directory Block: + + + Creation date: {0} + + + Last modification date: {0} + + + Last backup date: {0} + + + Backup sequence number: {0} + + + Volume has never been backed up + + + Volume is locked by hardware. + + + Volume was unmonted. + + + Volume is mounted. + + + Volume has spared bad blocks. + + + Volume does not need cache. + + + Boot volume is inconsistent. + + + There are reused CNIDs. + + + Volume is journaled. + + + Volume is seriously inconsistent. + + + Volume is locked by software. + + + {0} directories in root directory + + + {0} directories in volume + + + Volume write count: {0} + + + Volume bitmap starting sector (in 512-bytes): {0} + + + Next allocation block: {0}. + + + {0} volume allocation blocks. + + + {0} bytes per allocation block. + + + {0} bytes to allocate when extending a file. + + + {0} bytes to allocate when extending a Extents B-Tree. + + + {0} bytes to allocate when extending a Catalog B-Tree. + + + Sector of first allocation block: {0} + + + Next unused CNID: {0} + + + {0} unused allocation blocks. + + + {0} bytes in the Extents B-Tree + + + {0} bytes in the Catalog B-Tree + + + Volume name: {0} + + + Finder info: + + + CNID of bootable system's directory: {0} + + + CNID of first-run application's directory: {0} + + + CNID of previously opened directory: {0} + + + CNID of bootable Mac OS 8 or 9 directory: {0} + + + CNID of bootable Mac OS X directory: {0} + + + Mac OS X Volume ID: {0:X8}{1:X8} + + + Volume wraps a HFS+ volume. + + + Starting block of the HFS+ volume: {0} + + + Allocations blocks of the HFS+ volume: {0} + + + {0} blocks in volume cache + + + {0} blocks in volume bitmap cache + + + {0} blocks in volume common cache + + + Volume is bootable. + + + Volume is not bootable. + + + File truncated at block {0} + + + Apple Macintosh File System + + + First directory sector: {0} + + + {0} sectors in directory. + + + Size of allocation blocks: {0} bytes + + + {0} bytes to allocate. + + + First allocation block (#2) starts in sector {0}. + + + Next unused file number: {0} + + + CP/M File System + + + Found Amstrad superblock. + + + Found CP/M-86 hard disk superblock. + + + Found CP/M-86 floppy identifier. + + + First directory block seems correct. + + + Trying to load definitions. + + + Trying all known definitions. + + + Trying definition "{0}" + + + Don't know how to handle COLUMBIA ordering, not proceeding with this definition. + + + Don't know how to handle EAGLE ordering, not proceeding with this definition. + + + Unknown order type "{0}", not proceeding with this definition. + + + Definition contains EVEN-ODD field, with unknown meaning, detection may be wrong. + + + Definition "{0}" has a correct directory + + + Identified as {0} + + + Volume block is {0} bytes + + + Volume contains {0} blocks ({1} bytes) + + + CP/M filesystem + + + Volume contains {0} directory entries + + + Volume reserves {0} sectors for system + + + Volume reserves {1} tracks ({0} sectors) for system + + + Side 0 uses {0}:1 software interleaving + + + Side 1 uses {0}:1 software interleaving + + + Head changes after each whole track + + + Head changes after whole side + + + Unknown how {0} side ordering works + + + Device uses {0}:1 hardware interleaving + + + Volume label: {0} + + + Volume uses standard CP/M timestamps + + + Volume uses third party timestamps + + + Volume created on {0} + + + Volume updated on {0} + + + CYLINDERS ordering not yet implemented. + + + Deinterleaving whole volume. + + + Creating allocation blocks. + + + Reading directory. + + + Traversing directory. + + + Using Human68k BPB + + + Using FAT32 BPB + + + Using short FAT32 BPB + + + Using MSX BPB + + + Using Apricot BPB + + + Using DOS 4.0 BPB + + + Using DOS 3.4 BPB + + + Using DOS 3.3 BPB + + + Using Atari BPB + + + Using DOS 3.2 BPB + + + Using DOS 3.0 BPB + + + Using DOS 2.0 BPB + + + Using DEC Rainbow hardcoded BPB. + + + Using hardcoded BPB. + + + Using hardcoded BPB for 5.25" SSDD. + + + Using hardcoded BPB for 5.25" DSDD. + + + Found empty filename in {0} + + + Microsoft File Allocation Table + + + DOS (8.3 all uppercase) + + + Windows NT (8.3 mixed case) + + + OS/2 .LONGNAME extended attribute + + + Use LFN when available with fallback to .LONGNAME (default) + + + Long file names + + + 2nd fat starts at = {0} + + + FAT+ + + + Microsoft FAT32 + + + Volume has been modified by Windows 9x/Me Volume Tracker. + + + {0} sectors per cluster. + + + {0} sectors reserved between BPB and FAT. + + + {0} sectors on volume ({1} bytes). + + + {0} clusters on volume. + + + Media descriptor: 0x{0:X2} + + + {0} sectors per FAT. + + + {0} heads. + + + {0} hidden sectors before BPB. + + + Cluster of root directory: {0} + + + Sector of FSINFO structure: {0} + + + Sector of backup FAT32 parameter block: {0} + + + Drive number: 0x{0:X2} + + + Volume should be checked on next mount. + + + Disk surface should be checked on next mount. + + + FATs are out of sync. FAT #{0} is in use. + + + All copies of FAT are the same. + + + DR-DOS will boot this FAT32 using CHS. + + + DR-DOS will boot this FAT32 using LBA. + + + Filesystem type: {0} + + + {0} free clusters + + + Last allocated cluster {0} + + + cmdload will be loaded with value {0:X4}h + + + Boot program will be loaded at address {0:X4}h + + + FAT and directory will be cached at address {0:X4}h + + + Boot program resides in file "{0}" + + + Boot program starts in sector {0} and is {1} sectors long ({2} bytes) + + + Atari FAT12 + + + Apricot FAT12 + + + Human68k FAT12 + + + Microsoft FAT12 + + + Atari FAT16 + + + Human68k FAT16 + + + Microsoft FAT16 + + + {0} FATs. + + + {0} entries in root directory. + + + Volume Serial Number: {0} + + + Volume last modified on {0} + + + Volume last accessed on {0:d} + + + Boot code's SHA1: {0} + + + Unknown boot code. + + + Boot code corresponds to {0} + + + Reading BPB + + + Found empty filename in root directory + + + Reading FAT12 + + + Reading FAT16 + + + Casting FAT + + + FATX Filesystem Plugin + + + FATX filesystem + + + {0} logical sectors ({1} bytes) per physical sector + + + {0} sectors ({1} bytes) per cluster + + + Volume serial: {0:X8} + + + Reading superblock + + + Filesystem is little endian + + + Filesystem is big endian + + + Reading FAT32 + + + FAT is {0} sectors + + + Reading root directory + + + High Performance Optical File System + + + OEM name: {0} + + + {0} sectors hidden before BPB + + + Serial number: 0x{0:X8} + + + Volume comment: {0} + + + Volume owner: {0} + + + Volume uses {0} codepage {1} + + + EBCDIC + + + ASCII + + + Unknown + + + RPS level: {0} + + + Filesystem version: {0}.{1} + + + Volume can be filled up to {0}% + + + Exception reading CD-i audio file + + + Processing VD loop no. {0} + + + Reading sector {0} + + + Unknown + + + Found unknown supplementary volume descriptor + + + ERROR: Could not find primary volume descriptor + + + SYSTEM USE SHARING PROTOCOL INFORMATION: + + + ---------------------------------------- + + + Extension: {0} + + + ID: {0}, version {1} + + + Description: {0} + + + Source: {0} + + + High Sierra Format file system + + + CD-i file system + + + ISO9660 file system + + + CD-ROM XA extensions present. + + + Amiga extensions present. + + + Apple extensions present. + + + Joliet extensions present. + + + System Use Sharing Protocol present. + + + Rock Ridge Interchange Protocol present. + + + Arbitrary Attribute Interchange Protocol present. + + + zisofs compression present. + + + Contains Enhanced Volume Descriptor. + + + Contains Volume Partition Descriptor. + + + Disc bootable following {0} specifications. + + + This is a SegaCD / MegaCD disc. + + + This is a Sega Saturn disc. + + + This is a Sega Dreamcast disc. + + + FILE STRUCTURE VOLUME DESCRIPTOR INFORMATION: + + + --------------------------------------------- + + + VOLUME DESCRIPTOR INFORMATION: + + + ------------------------------ + + + System identifier: {0} + + + Volume identifier: {0} + + + Volume set identifier: {0} + + + Publisher identifier: {0} + + + Data preparer identifier: {0} + + + Application identifier: {0} + + + Volume creation date: {0} + + + Volume modification date: {0} + + + Volume has not been modified. + + + Volume expiration date: {0} + + + Volume does not expire. + + + Volume effective date: {0} + + + Volume has always been effective. + + + Volume has {0} blocks of {1} bytes each + + + JOLIET VOLUME DESCRIPTOR INFORMATION: + + + ------------------------------------- + + + EL TORITO INFORMATION: + + + ---------------------- + + + Initial entry: + + + Developer ID: {0} + + + Bootable on {0} + + + Bootable image starts at sector {0} and runs for {1} sectors + + + Bootable image will be loaded at segment {0:X4}h + + + Bootable image will be loaded at 0x{0:X8} + + + Image uses no emulation + + + Image emulates a 5.25" high-density (MD2HD, 1.2Mb) floppy + + + Image emulates a 3.5" high-density (MF2HD, 1.44Mb) floppy + + + Image emulates a 3.5" extra-density (MF2ED, 2.88Mb) floppy + + + Image uses unknown emulation type {0} + + + System type: 0x{0:X2} + + + Bootable image's SHA1: {0} + + + Not bootable + + + Boot section {0}: + + + Section ID: {0} + + + Entry {0}: + + + Selection criteria type: {0} + + + Image contains ATAPI drivers + + + Image contains SCSI drivers + + + Sector {0}, Cooked, Mode 0/1 / Mode 2 Form 1 + + + Sector {0}, Cooked, Mode 2 Form 2 + + + Sector {0}, Cooked, Mode 2 Form {1}, File Number {2}, Channel Number {3}, Submode {4}, Coding Information {5} + + + Sector {0}, Raw, Audio + + + Sector {0} ({1:X2}:{2:X2}:{3:X2}), Raw, Mode {4} + + + Sector {0} ({1:X2}:{2:X2}:{3:X2}), Raw, Mode 2 Form {4}, File Number {5}, Channel Number {6}, Submode {7}, Coding Information {8} + + + Path table and PVD do not point to the same location for the root directory! + + + PVD does not point to correct root directory, checking path table... + + + Cannot find root directory... + + + File {0} gets truncated. + + + Sector {0}, file ID 0x{1:X4} + + + Current sector = {0} + + + Unknown LisaFS version {0} + + + Volume password: "{0}" + + + Volume ID: 0x{0:X16} + + + Backup volume ID: 0x{0:X16} + + + Master copy ID: 0x{0:X8} + + + Volume is number {0} of {1} + + + Serial number of Lisa computer that created this volume: {0} + + + Serial number of Lisa computer that can use this volume's software {0} + + + Volume's catalog created on {0} + + + Volume backed up on {0} + + + Volume scavenged on {0} + + + MDDF is in block {0} + + + There are {0} reserved blocks before volume + + + {0} blocks minus one + + + {0} blocks minus one minus MDDF offset + + + {0} blocks in volume + + + {0} bytes per sector (uncooked) + + + {0} blocks per cluster + + + {0} blocks in filesystem + + + {0} files in volume + + + {0} blocks free + + + {0} bytes in LisaInfo + + + Filesystem overhead: {0} + + + Scavenger result code: 0x{0:X8} + + + Boot code: 0x{0:X8} + + + Boot environment: 0x{0:X8} + + + Overmount stamp: 0x{0:X16} + + + S-Records start at {0} and spans for {1} blocks + + + Volume is clean + + + Volume is dirty + + + Underlying device does not support Lisa tags + + + Device is too small + + + Incorrect MDDF found + + + Mounting LisaFS v1 + + + Mounting LisaFS v2 + + + Mounting LisaFS v3 + + + Cannot mount LisaFS version {0} + + + Error {0} reading S-Records file. + + + Cannot read Catalog File, error {0} + + + Unable to read boot blocks + + + Unable to read boot loader + + + Unable to read MDDF + + + Unable to read volume bitmap + + + Unable to read S-Records file + + + Not a Lisa filesystem + + + Exception {0}, {1}, {2} + + + Opera Filesystem Plugin + + + Opera filesystem disc. + + + Volume identifier: 0x{0:X8} + + + Block size: {0} bytes + + + WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/block + + + Volume size: {0} blocks, {1} bytes + + + WARNING: Filesystem indicates {0} blocks while device indicates {1} blocks + + + Root directory identifier: 0x{0:X8} + + + Root directory block size: {0} bytes + + + Root directory size: {0} blocks, {1} bytes + + + Last root directory copy: {0} + + + U.C.S.D. Pascal filesystem + + + Volume record spans from block {0} to block {1} + + + Volume has {0} blocks + + + Volume has {0} files + + + Volume last booted on {0} + + + Acorn Advanced Disc Filing System + + + Acorn Advanced Disc Filing System + + + Volume has {0} bytes + + + Volume ID: {0:X4} + + + Version {0} + + + Density code: {0} + + + Skew: {0} + + + Boot option: {0} + + + Root starts at frag {0} + + + Volume has {0} bytes in {1} zones + + + Volume flags: 0x{0:X4} + + + Amiga DOS filesystem + + + Bootblock points to {0} as Rootblock + + + Searching for Rootblock in sector {0} + + + Amiga Original File System + + + Amiga Fast File System + + + Amiga Original File System with international characters + + + Amiga Fast File System with international characters + + + Amiga Original File System with directory cache + + + Amiga Fast File System with directory cache + + + Amiga Original File System with long filenames + + + Amiga Fast File System with long filenames + + + , with multi-user patches + + + Volume bitmap is valid + + + Bitmap extension at block {0} + + + Directory cache starts at block {0} + + + Volume block size is {0} bytes + + + Volume root directory last modified on {0} + + + Root block checksum is 0x{0:X8} + + + Alexander Osipov DOS file system + + + Alexander Osipov DOS file system + + + {0} used sectors on volume + + + Disk name: {0} + + + Apple File System + + + Apple File System + + + {0} bytes per block + + + Container has {0} bytes in {1} blocks + + + Apple HFS+ filesystem + + + HFS+ filesystem. + + + HFSX filesystem. + + + Volume is wrapped inside an HFS volume. + + + Filesystem version is {0}. + + + Volume is unmounted. + + + There are bad blocks in the extents file. + + + Volume state is inconsistent. + + + Implementation that last mounted the volume: "{0}". + + + Journal starts at allocation block {0}. + + + Last check date: {0} + + + Volume has never been checked up + + + {0} allocation blocks. + + + {0} free blocks. + + + Resource fork clump size: {0} bytes. + + + Data fork clump size: {0} bytes. + + + Volume has been mounted writable {0} times. + + + Allocation File is {0} bytes. + + + Extents File is {0} bytes. + + + Catalog File is {0} bytes. + + + Attributes File is {0} bytes. + + + Startup File is {0} bytes. + + + This version is not supported yet. + + + AtheOS Filesystem + + + AtheOS filesystem + + + Filesystem is read-only + + + {0} blocks in volume ({1} bytes) + + + {0} used blocks ({1} bytes) + + + {0} bytes per i-node + + + {0} blocks per allocation group ({1} bytes) + + + {0} allocation groups in volume + + + Journal resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes) + + + Journal starts in byte {0} and has {1} bytes in {2} blocks + + + Root folder's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes) + + + Directory containing files scheduled for deletion's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes) + + + Indices' i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes) + + + {0} blocks for bootloader ({1} bytes) + + + Be Filesystem + + + Little-endian BeFS + + + Big-endian BeFS + + + Superblock seems corrupt, following information may be incorrect + + + Magic 1: 0x{0:X8} (Should be 0x42465331) + + + Magic 2: 0x{0:X8} (Should be 0xDD121031) + + + Magic 3: 0x{0:X8} (Should be 0x15B6830E) + + + Filesystem endianness: 0x{0:X8} (Should be 0x42494745) + + + Root folder's i-node size: {0} blocks (Should be 1) + + + Indices' i-node size: {0} blocks (Should be 1) + + + 1 << block_shift == block_size => 1 << {0} == {1} (Should be {2}) + + + Unknown flags: {0:X8} + + + Journal starts in byte {0} and ends in byte {1} + + + B-tree file system + + + B-tree filesystem + + + UUID: {0} + + + This superblock resides on physical block {0} + + + Root tree starts at LBA {0} + + + Chunk tree starts at LBA {0} + + + Log tree starts at LBA {0} + + + Volume has {0} bytes spanned in {1} devices + + + Volume has {0} bytes used + + + {0} bytes/sector + + + {0} bytes/node + + + {0} bytes/leaf + + + {0} bytes/stripe + + + Flags: 0x{0:X} + + + Compatible flags: 0x{0:X} + + + Read-only compatible flags: 0x{0:X} + + + Incompatible flags: 0x{0:X} + + + Device's UUID: {0} + + + Commodore file system + + + Commodore file system + + + Directory starts at track {0} sector {1} + + + Disk DOS Version: {0} + + + DOS Version: {0} + + + Disk Version: {0} + + + Disk ID: {0} + + + Disk DOS type: {0} + + + Cram filesystem + + + Cram file system + + + Little-endian + + + Big-endian + + + Volume edition {0} + + + dump(8) Plugin + + + Could not read dump(8) header block + + + Old 16-bit dump(8) + + + Dump created on {0} + + + Previous dump created on {0} + + + Dump volume number: {0} + + + Dump level: {0} + + + Dump label: {0} + + + Dumped filesystem name: {0} + + + Dumped device: {0} + + + Dump hostname: {0} + + + ECMA-67 + + + ECMA-67 + + + Extent File System Plugin + + + magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8}) + + + magic at {0} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8}) + + + SGI extent filesystem + + + New version + + + Filesystem size: {0} basic blocks + + + First cylinder group starts at block {0} + + + Cylinder group size: {0} basic blocks + + + {0} inodes per cylinder group + + + {0} heads per cylinder + + + {0} cylinder groups + + + {0} bytes on bitmap + + + {0} free inodes + + + Bitmap resides at block {0} + + + Replacement superblock resides at block {0} + + + Last inode allocated: {0} + + + Checksum: 0x{0:X8} + + + Volume pack: {0} + + + Microsoft Extended File Allocation Table + + + Microsoft exFAT + + + Partition offset: {0} + + + Volume has {0} sectors of {1} bytes each for a total of {2} bytes + + + Volume uses clusters of {0} sectors ({1} bytes) each + + + First FAT starts at sector {0} and runs for {1} sectors + + + Volume uses {0} FATs + + + Cluster heap starts at sector {0}, contains {1} clusters and is {2}% used + + + Root directory starts at cluster {0} + + + Filesystem revision is {0}.{1:D2} + + + Volume serial number: {0:X8} + + + BIOS drive is {0:X2}h + + + 2nd FAT is in use + + + Underlying media presented errors + + + OEM Parameters: {0} + + + {0} bytes in erase block + + + {0} bytes per page + + + {0} spare blocks + + + {0} nanoseconds random access time + + + {0} nanoseconds program time + + + {0} nanoseconds read cycle time + + + {0} nanoseconds write cycle time + + + Found unknown parameter type {0} + + + Linux extended Filesystem 2, 3 and 4 + + + ext2 (old) filesystem + + + ext2 filesystem + + + ext3 filesystem + + + ext4 filesystem + + + Not an ext2/3/4 filesystem + + + Unknown OS ({0}) + + + Volume was created on {0} for {1} + + + Volume was created for {0} + + + Volume has {0} blocks of {1} bytes, for a total of {2} bytes + + + Last mounted on {0} + + + Volume has been mounted {0} times of a maximum of {1} mounts before checking + + + Volume has been mounted {0} times with no maximum no. of mounts before checking + + + Last mounted at: "{0}" + + + Last used mount options were: {0} + + + Volume has never been mounted + + + Volume can be mounted {0} times before checking + + + Volume has no maximum no. of mounts before checking + + + Last checked on {0} (should check every {1} seconds) + + + Last checked on {0} + + + Volume has never been checked (should check every {0}) + + + Volume has never been checked + + + Last written on {0} + + + Volume is recovering orphan files + + + Volume is in an unknown state ({0}) + + + On errors, filesystem should continue + + + On errors, filesystem should remount read-only + + + On errors, filesystem should panic + + + On errors filesystem will do an unknown thing ({0}) + + + Filesystem revision: {0}.{1} + + + Volume UUID: {0} + + + {0} KiB has been written on volume + + + {0} reserved and {1} free blocks + + + {0} inodes with {1} free inodes ({2}%) + + + First inode is {0} + + + {0} bytes per fragment + + + {0} blocks, {1} flags and {2} inodes per group + + + {0} is first data block + + + Default UID: {0}, GID: {1} + + + Block group number is {0} + + + Group descriptor size is {0} bytes + + + First metablock group is {0} + + + RAID stride: {0} + + + {0} blocks on all data disks + + + {0} seconds for multi-mount protection wait, on block {1} + + + {0} size of FLEX_BG group + + + Hash seed: {0:X8}{1:X8}{2:X8}{3:X8}, version {4} + + + Journal UUID: {0} + + + Journal has inode {0} + + + Journal is on device {0} + + + Journal backup type: {0} + + + Last orphaned inode is {0} + + + There are no orphaned inodes + + + Active snapshot has ID {0}, on inode {1}, with {2} blocks reserved, list starting on block {3} + + + {0} errors registered + + + First error occurred on {0}, last on {1} + + + First error inode is {0}, last is {1} + + + First error block is {0}, last is {1} + + + First error function is "{0}", last is "{1}" + + + Flags…: + + + Signed directory hash is in use + + + Unsigned directory hash is in use + + + Volume is testing development code + + + Unknown set flags: {0:X8} + + + Default mount options…: + + + (debug): Enable debugging code + + + (bsdgroups): Emulate BSD behaviour when creating new files + + + (user_xattr): Enable user-specified extended attributes + + + (acl): Enable POSIX ACLs + + + (uid16): Disable 32bit UIDs and GIDs + + + (journal_data): Journal data and metadata + + + (journal_data_ordered): Write data before journaling metadata + + + (journal_data_writeback): Write journal before data + + + Unknown set default mount options: {0:X8} + + + Compatible features…: + + + Pre-allocate directories + + + Has mapping between inodes and AFS (imagic inodes table) + + + Has journal (ext3) + + + Has extended attribute blocks + + + Has online filesystem resize reservations + + + Can use hashed indexes on directories + + + Unknown compatible features: {0:X8} + + + Compatible features if read-only…: + + + Reduced number of superblocks + + + Can have files bigger than 2GiB + + + Uses B-Tree for directories + + + Can have files bigger than 2TiB (ext4) + + + Group descriptor checksums and sparse inode table (ext4) + + + More than 32000 directory entries (ext4) + + + Supports nanosecond timestamps and creation time (ext4) + + + Unknown read-only compatible features: {0:X8} + + + Incompatible features…: + + + Uses compression + + + Filetype in directory entries + + + Journal needs recovery (ext3) + + + Has journal on another device (ext3) + + + Reduced block group backups + + + Volume use extents (ext4) + + + Supports volumes bigger than 2^32 blocks (ext4) + + + Multi-mount protection (ext4) + + + Flexible block group metadata location (ext4) + + + Extended attributes can reside in inode (ext4) + + + Data can reside in directory entry (ext4) + + + Unknown incompatible features: {0:X8} + + + Linux extended Filesystem + + + ext filesystem + + + {0} zones in volume + + + {0} free blocks ({1} bytes) + + + {0} inodes in volume, {1} free ({2}%) + + + First free inode is {0} + + + First free block is {0} + + + First data zone is {0} + + + Log zone size: {0} + + + Max zone size: {0} + + + F2FS Plugin + + + F2FS filesystem + + + Version {0}.{1} + + + {0} sectors ({1} bytes) per block + + + {0} blocks per segment + + + {0} segments per section + + + {0} sections per zone + + + {0} sections + + + {0} segments + + + Root directory resides on inode {0} + + + Volume last mounted on kernel version: {0} + + + Volume created on kernel version: {0} + + + BSD Fast File System (aka UNIX File System, UFS) + + + Not a UFS filesystem, I shouldn't have arrived here! + + + UFS filesystem + + + Big-endian UFS filesystem + + + BorderWare UFS filesystem + + + Big-endian BorderWare UFS filesystem + + + UFS2 filesystem + + + Big-endian UFS2 filesystem + + + Incompletely initialized UFS filesystem + + + BEWARE!!! Following information may be completely wrong! + + + Incompletely initialized big-endian UFS filesystem + + + There are a lot of variants of UFS using overlapped values on same fields + + + I will try to guess which one it is, but unless it's UFS2, I may be surely wrong + + + Guessed as 42BSD FFS + + + Guessed as 43BSD FFS + + + Guessed as 44BSD FFS + + + Guessed as SunOS FFS + + + Guessed as SunOS/x86 FFS + + + Guessed as UFS + + + Linked list of filesystems: 0x{0:X8} + + + Superblock LBA: {0} + + + Cylinder-block LBA: {0} + + + inode-block LBA: {0} + + + First data block LBA: {0} + + + Cylinder group offset in cylinder: {0} + + + Volume last written on {0} + + + {0} data blocks in volume ({1} bytes) + + + {0} cylinder groups in volume + + + {0} bytes in a basic block + + + {0} bytes in a frag block + + + {0} frags in a block + + + {0}% of blocks must be free + + + {0}ms for optimal next block + + + Disk rotates {0} times per second ({1}rpm) + + + {0} contiguous blocks at maximum + + + {0} blocks per cylinder group at maximum + + + Superblock is {0} bytes + + + NINDIR: 0x{0:X8} + + + INOPB: 0x{0:X8} + + + NSPF: 0x{0:X8} + + + Filesystem will minimize allocation time + + + Filesystem will minimize volume fragmentation + + + Unknown optimization value: 0x{0:X8} + + + {0} sectors/track + + + Volume state on {0} + + + Hardware sector interleave: {0} + + + Sector 0 skew: {0}/track + + + Volume ID: 0x{0:X8}{1:X8} + + + {0} µsec for head switch + + + {0} µsec for track-to-track seek + + + Cylinder group summary LBA: {0} + + + {0} bytes in cylinder group summary + + + {0} bytes in cylinder group + + + {0} tracks/cylinder + + + {0} sectors/cylinder + + + {0} cylinders in volume + + + {0} cylinders/group + + + {0} blocks per group + + + {0} directories + + + {0} free frags + + + Volume is read-only + + + Volume flags: 0x{0:X2} + + + Volume last mounted at "{0}" + + + Last searched cylinder group: {0} + + + {0} contiguously allocated directories + + + Standard superblock LBA: {0} + + + {0} blocks ({1} bytes) + + + {0} data blocks ({1} bytes) + + + Cylinder group summary area LBA: {0} + + + {0} blocks pending of being freed + + + {0} inodes pending of being freed + + + {0} blocks on cluster summary array + + + Maximum length of a symbolic link: {0} + + + A file can be {0} bytes at max + + + {0} rotational positions + + + {0} blocks per rotation + + + Fossil Filesystem Plugin + + + magic at 0x{0:X8} (expected 0x{1:X8}) + + + Fossil filesystem + + + Filesystem version {0} + + + Superblock resides in block {0} + + + Labels resides in block {0} + + + Data starts at block {0} + + + magic 0x{0:X8} (expected 0x{1:X8}) + + + Epoch low {0} + + + Epoch high {0} + + + Next QID {0} + + + Active root block {0} + + + Next root block {0} + + + Current root block {0} + + + HAMMER Filesystem + + + HAMMER filesystem + + + Volume {0} of {1} on this filesystem + + + Volume serial: {0} + + + Boot area starts at {0} + + + Memory log starts at {0} + + + First volume buffer starts at {0} + + + Volume ends at {0} + + + Filesystem contains {0} "big-blocks" ({1} bytes) + + + Filesystem has {0} "big-blocks" free ({1} bytes) + + + Filesystem has {0} inodes used + + + OS/2 High Performance File System + + + This may not be HPFS, following information may be not correct. + + + File system type: "{0}" (Should be "HPFS ") + + + Superblock magic1: 0x{0:X8} (Should be 0xF995E849) + + + Superblock magic2: 0x{0:X8} (Should be 0xFA53E9C5) + + + Spareblock magic1: 0x{0:X8} (Should be 0xF9911849) + + + Spareblock magic2: 0x{0:X8} (Should be 0xFA5229C5) + + + NT Flags: 0x{0:X2} + + + Signature: 0x{0:X2} + + + HPFS version: {0} + + + Functional version: {0} + + + Sector of root directory FNode: {0} + + + {0} sectors are marked bad + + + Sector of free space bitmaps: {0} + + + Sector of bad blocks list: {0} + + + Date of last integrity check: {0} + + + Filesystem integrity has never been checked + + + Date of last optimization {0} + + + Filesystem has never been optimized + + + Directory band has {0} sectors + + + Directory band starts at sector {0} + + + Directory band ends at sector {0} + + + Sector of directory band bitmap: {0} + + + Sector of ACL directory: {0} + + + Sector of Hotfix directory: {0} + + + {0} used Hotfix entries + + + {0} total Hotfix entries + + + {0} free spare DNodes + + + {0} total spare DNodes + + + Sector of codepage directory: {0} + + + {0} codepages used in the volume + + + SuperBlock CRC32: {0:X8} + + + SpareBlock CRC32: {0:X8} + + + Flags: + + + Filesystem is dirty. + + + Filesystem is clean. + + + Spare directory blocks are in use + + + Hotfixes are in use + + + Disk contains bad sectors + + + Disk has a bad bitmap + + + Filesystem was formatted fast + + + Unknown flag 0x40 on flags1 is active + + + Filesystem has been mounted by an old IFS + + + Install DASD limits + + + Resync DASD limits + + + DASD limits are operational + + + Multimedia is active + + + DCE ACLs are active + + + DASD limits are dirty + + + Unknown flag 0x40 on flags2 is active + + + Unknown flag 0x80 on flags2 is active + + + JFS Plugin + + + JFS filesystem + + + {0} blocks of {1} bytes + + + {0} blocks per allocation group + + + Volume uses Unicode for directory entries + + + Volume remounts read-only on error + + + Volume continues on error + + + Volume panics on error + + + Volume has user quotas enabled + + + Volume has group quotas enabled + + + Volume is not using any journal + + + Volume sends TRIM/UNMAP commands to underlying device + + + Volume commits in groups of 1 + + + Volume commits lazy + + + Volume does not commit to log + + + Volume has log within itself + + + Volume has log within itself and is moving it out + + + Volume supports sparse files + + + Volume has bad current secondary ait + + + Volume has DASD limits enabled + + + Volume primes DASD on boot + + + Volume is in a big-endian system + + + Volume has persistent indexes + + + Volume supports Linux + + + Volume supports DCE DFS LFS + + + Volume supports OS/2, and is case insensitive + + + Volume supports AIX + + + Volume was last updated on {0} + + + HP Logical Interchange Format Plugin + + + HP Logical Interchange Format + + + Directory starts at cluster {0} + + + LIF identifier: {0} + + + Directory size: {0} clusters + + + LIF version: {0} + + + {0} tracks + + + {0} sectors + + + Locus Filesystem Plugin + + + magic at {1} = 0x{0:X8} + + + Locus filesystem (old) + + + Locus filesystem + + + Superblock last modified on {0} + + + Volume has {0} blocks of {1} bytes each (total {2} bytes) + + + {0} blocks free ({1} bytes) + + + I-node list uses {0} blocks + + + Next free inode search will start at inode {0} + + + There are an estimate of {0} free inodes before next search start + + + Read-only volume + + + Clean volume + + + Dirty volume + + + Removable volume + + + This is the primary pack + + + Replicated volume + + + User replicated volume + + + Backbone volume + + + NFS volume + + + Volume inhibits automatic fsck + + + Set-uid/set-gid is disabled + + + Volume uses synchronous writes + + + Physical volume name: {0} + + + Global File System number: {0} + + + Global File System pack number {0} + + + MicroDOS file system + + + MicroDOS filesystem + + + Volume has {0} blocks ({1} bytes) + + + Volume has {0} blocks used ({1} bytes) + + + Volume contains {0} files + + + First used block is {0} + + + Minix Filesystem + + + Minix v3 filesystem + + + Minix 3 v2 filesystem + + + Minix 3 v1 filesystem + + + Minix v1 filesystem + + + Minix v2 filesystem + + + {0} chars in filename + + + {0} zones in volume ({1} bytes) + + + {0} bytes/block + + + {0} blocks on inode map ({1} bytes) + + + {0} blocks on zone map ({1} bytes) + + + First data zone: {0} + + + {0} bytes maximum per file + + + On-disk filesystem version: {0} + + + Filesystem state: {0:X4} + + + NILFS2 Plugin + + + NILFS2 filesystem + + + {0} bytes in volume + + + Filesystem created on Linux + + + Creator OS code: {0} + + + {0} bytes per inode + + + Volume last mounted on {0} + + + Nintendo optical filesystems + + + Nintendo optical filesystem + + + Nintendo Wii Optical Disc + + + Nintendo GameCube Optical Disc + + + Disc ID is {0} + + + Disc is a {0} disc + + + Disc region is {0} + + + Published by {0} + + + Disc number {0} of a multi-disc set + + + Disc is prepared for audio streaming + + + Audio streaming buffer size is {0} bytes + + + Title: {0} + + + First {0} partition starts at sector {1} + + + Second {0} partition starts at sector {1} + + + Third {0} partition starts at sector {1} + + + Fourth {0} partition starts at sector {1} + + + Japan age rating is {0} + + + ESRB age rating is {0} + + + German age rating is {0} + + + PEGI age rating is {0} + + + Finland age rating is {0} + + + Portugal age rating is {0} + + + UK age rating is {0} + + + Australia age rating is {0} + + + Korea age rating is {0} + + + FST starts at {0} and has {1} bytes + + + Commodore 64 Virtual Console + + + Demo + + + Neo-Geo Virtual Console + + + NES Virtual Console + + + Gamecube + + + Wii channel + + + Super Nintendo Virtual Console + + + Master System Virtual Console + + + Mega Drive Virtual Console + + + Nintendo 64 Virtual Console + + + Promotional or TurboGrafx Virtual Console + + + TurboGrafx CD Virtual Console + + + Wii + + + Utility + + + WiiWare + + + MSX Virtual Console or WiiWare demo + + + Diagnostic + + + Wii Backup + + + WiiFit + + + unknown type '{0}' + + + any region + + + Germany + + + USA + + + France + + + Italy + + + Japan + + + Korea + + + PAL + + + Russia + + + Spain + + + Taiwan + + + Australia + + + unknown region code '{0}' + + + Unknown publisher '{0}' + + + data + + + update + + + channel + + + unknown partition type {0} + + + New Technology File System (NTFS) + + + {0} sectors per cluster ({1} bytes) + + + {0} hidden sectors before filesystem + + + BIOS drive number: 0x{0:X2} + + + Cluster where $MFT starts: {0} + + + Cluster where $MFTMirr starts: {0} + + + {0} clusters per MFT record ({1} bytes) + + + {0} bytes per MFT record + + + {0} clusters per Index block ({1} bytes) + + + {0} bytes per Index block + + + Volume serial number: {0:X16} + + + Files-11 On-Disk Structure + + + magic: "{0}" + + + unaligned magic: "{0}" + + + The following information may be incorrect for this volume. + + + This volume may be corrupted. + + + Volume format is {0} + + + Volume is Level {0} revision {1} + + + Lowest structure in the volume is Level {0}, revision {1} + + + Highest structure in the volume is Level {0}, revision {1} + + + This home block is on sector {0} (VBN {1}) + + + Secondary home block is on sector {0} (VBN {1}) + + + Volume bitmap starts in sector {0} (VBN {1}) + + + Volume bitmap runs for {0} sectors ({1} bytes) + + + Backup INDEXF.SYS;1 is in sector {0} (VBN {1}) + + + {0} maximum files on the volume + + + {0} reserved files + + + Volume is {0} of {1} in set "{2}". + + + Volume owner is "{0}" (ID 0x{1:X8}) + + + Drive serial number: 0x{0:X8} + + + Volume was created on {0} + + + Volume was last modified on {0} + + + Volume copied on {0} + + + Checksums: 0x{0:X4} and 0x{1:X4} + + + Window: {0} + + + Cached directories: {0} + + + Default allocation: {0} blocks + + + Readings should be verified + + + Writings should be verified + + + Files should be erased or overwritten when deleted + + + Highwater mark is to be disabled + + + Classification checks are enabled + + + Volume permissions (r = read, w = write, c = create, d = delete) + Do not translate r, w, c or d letters + + + System, owner, group, world + + + Unknown structures: + + + Security mask: 0x{0:X8} + + + File protection: 0x{0:X4} + + + Record protection: 0x{0:X4} + + + PC Engine CD Plugin + + + PC-FX Plugin + + + PC-FX executable: + + + Identifier: {0} + + + Copyright: {0} + + + Maker ID: {0} + + + Maker name: {0} + + + Volume number: {0} + + + Country code: {0} + + + Dated {0} + + + Load {0} sectors from sector {1} + + + Load at 0x{0:X8} and jump to 0x{1:X8} + + + Professional File System + + + Professional File System v1 + + + Professional File System v2 + + + Professional File System v3 + + + , with multi-user support + + + Volume has {0} free sectors of {1} + + + Root block extension resides at block {0} + + + Apple ProDOS filesystem + + + Datetime field year {0}, month {1}, day {2}, hour {3}, minute {4}. + + + ProDOS uses 512 bytes/sector while device uses 2048 bytes/sector. + + + Warning! Detected unknown ProDOS version ProDOS filesystem. + + + All of the following information may be incorrect + + + ProDOS version 1 used to create this volume. + + + Unknown ProDOS version with field {0} used to create this volume. + + + ProDOS version 1 at least required for reading this volume. + + + Unknown ProDOS version with field {0} is at least required for reading this volume. + + + Volume name is {0} + + + {0} bytes per directory entry + + + {0} entries per directory block + + + {0} files in root directory + + + Bitmap starts at block {0} + + + Volume can be read + + + Volume can be written + + + Volume can be renamed + + + Volume can be destroyed + + + Volume must be backed up + + + Reserved attributes are set: {0:X2} + + + QNX4 Plugin + + + QNX4 filesystem + + + Created on {0} + + + QNX6 Plugin + + + QNX6 (Audi) filesystem + + + Serial: 0x{0:X16} + + + {0} inodes free of {1} + + + {0} blocks ({1} bytes) free of {2} ({3} bytes) + + + QNX6 filesystem + + + Flags: 0x{0:X8} + + + Version1: 0x{0:X4} + + + Version2: 0x{0:X4} + + + OS-9 Random Block File Plugin + + + magic at {0} = 0x{1:X8} or 0x{2:X8} (expected 0x{3:X8} or 0x{4:X8}) + + + OS-9 Random Block File + + + Volume ID: {0:X8} + + + {0} cylinders + + + {0} blocks in cylinder 0 + + + {0} blocks per cylinder + + + Disk is double sided + + + Disk is single sided + + + Disk is double density + + + Disk is single density + + + Disk is 384 TPI + + + Disk is 192 TPI + + + Disk is 96 TPI or 135 TPI + + + Disk is 48 TPI + + + Allocation bitmap descriptor starts at block {0} + + + Debugger descriptor starts at block {0} + + + Boot file descriptor starts at block {0} + + + Root directory descriptor starts at block {0} + + + Disk is owned by group {0} user {1} + + + Volume's identification block was last written on {0} + + + {0} bytes in allocation bitmap + + + Boot file starts at block {0} and has {1} bytes + + + Disk is owned by user {0} + + + Volume attributes: {0:X2} + + + Path descriptor options: {0} + + + Resilient File System plugin + + + Microsoft Resilient File System + + + Volume uses {0} bytes per sector + + + Volume uses {0} sectors per cluster ({1} bytes) + + + Volume has {0} sectors ({1} bytes) + + + Reiser Filesystem Plugin + + + Reiser 3.5 filesystem + + + Reiser 3.6 filesystem + + + Reiser Jr. filesystem + + + Volume has {0} blocks with {1} blocks free + + + Root directory resides on block {0} + + + Volume has not been cleanly umounted + + + Volume last checked on {0} + + + Reiser4 Filesystem Plugin + + + Reiser 4 filesystem + + + Volume disk format: {0} + + + RT-11 file system + + + First directory segment starts at block {0} + + + Volume owner is "{0}" + + + Checksum: 0x{0:X4} (calculated 0x{1:X4}) + + + SmartFileSystem + + + SmartFileSystem + + + Volume version {0} + + + Volume starts on device byte {0} and ends on byte {1} + + + Admin space container starts in block {0} + + + Root object container starts in block {0} + + + Root node of the extent B-tree resides in block {0} + + + Root node of the object B-tree resides in block {0} + + + Volume is case sensitive + + + Volume moves deleted files to a recycled folder + + + Solar_OS filesystem + + + Solar_OS filesystem + + + WARNING: Filesystem describes a {0} bytes/sector, while device describes a {1} bytes/sector + + + WARNING: Filesystem describes a {0} sectors volume, bigger than device ({1} sectors) + + + Squash filesystem + + + Squash file system + + + Volume version {0}.{1} + + + Volume has {0} bytes per block + + + Volume has {0} inodes + + + Volume is compressed using LZ4 + + + Volume is compressed using LZO + + + Volume is compressed using LZMA + + + Volume is compressed using XZ + + + Volume is compressed using GZIP + + + Volume is compressed using Zstandard + + + Volume is compressed using unknown algorithm {0} + + + UNIX System V filesystem + + + XENIX filesystem + + + 512 bytes per block + + + 1024 bytes per block + + + 2048 bytes per block + + + Unknown s_type value: 0x{0:X8} + + + {0} free zones on volume ({1} bytes) + + + {0} free blocks on list ({1} bytes) + + + {0} blocks per cylinder ({1} bytes) + + + {0} blocks per gap ({1} bytes) + + + {0} free inodes on volume + + + {0} free inodes on list + + + Free block list is locked + + + inode cache is locked + + + Superblock is being modified + + + Volume is mounted read-only + + + Superblock last updated on {0} + + + Pack name: {0} + + + System V Release 4 filesystem + + + System V Release 2 filesystem + + + Coherent UNIX filesystem + + + UNIX 7th Edition filesystem + + + Universal Disk Format + + + Universal Disk Format + + + Volume uses {0} bytes per block + + + Volume was last written on {0} + + + Volume contains {0} partitions + + + Volume contains {0} files and {1} directories + + + Volume conforms to {0} + + + Volume was last written by: {0} + + + Volume requires UDF version {0}.{1:X2} to be read + + + Volume requires UDF version {0}.{1:X2} to be written to + + + Volume cannot be written by any UDF version higher than {0}.{1:X2} + + + UNICOS Filesystem Plugin + + + magic = 0x{0:X16} (expected 0x{1:X16}) + + + UNICOS filesystem + + + Volume is secure + + + 4096 bytes per block + + + {0} data blocks in volume + + + Root resides on inode {0} + + + {0} inodes in volume + + + Volume last updated on {0} + + + Volume is dirty, error code = 0x{0:X16} + + + UNIX Boot filesystem + + + Volume goes from byte {0} to byte {1}, for {2} bytes + + + Filesystem name: {0} + + + UNIX Boot Filesystem + + + VMware filesystem + + + VMware file system + + + Volume size {0} bytes + + + Veritas filesystem + + + Veritas file system + + + Volume has {0} inodes per block + + + Volume has {0} free inodes + + + Volume has {0} free blocks + + + XFS Filesystem Plugin + + + magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8}) + + + magic at {0} = 0x{1:X8} (expected 0x{2:X8}) + + + XFS filesystem + + + {0} data blocks in volume, {1} free + + + {0} inodes in volume, {1} free + + + fsck in progress + + + Xia filesystem + + + {0} bytes per zone + + + {0} inodes + + + {0} data zones ({1} bytes) + + + {0} imap zones ({1} bytes) + + + {0} zmap zones ({1} bytes) + + + Maximum filesize is {0} bytes ({1} MiB) + + + {0} zones reserved for kernel images ({1} bytes) + + + First kernel zone: {0} + + + ZFS Filesystem Plugin + + + ZFS filesystem + + + {0} is not set + + + {0} = {1} elements nvlist[], unable to print + + + {0}[{1}] = Unknown data type {2} + + + {0} = Unknown data type {1} + + + This disk contains a relative file. These have not been fully tested, please open a bug report and include this disk image. + + \ No newline at end of file diff --git a/Aaru.Filesystems/Locus.cs b/Aaru.Filesystems/Locus.cs deleted file mode 100644 index 39797c911..000000000 --- a/Aaru.Filesystems/Locus.cs +++ /dev/null @@ -1,421 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Locus.cs -// Author(s) : Natalia Portillo -// -// Component : Locus filesystem plugin -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Locus filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License aint with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -// Commit count - -using commitcnt_t = System.Int32; - -// Disk address -using daddr_t = System.Int32; - -// Fstore -using fstore_t = System.Int32; - -// Global File System number -using gfs_t = System.Int32; - -// Inode number -using ino_t = System.Int32; - -// Filesystem pack number -using pckno_t = System.Int16; - -// Timestamp -using time_t = System.Int32; - -// ReSharper disable UnusedMember.Local -// ReSharper disable UnusedType.Local - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the Locus filesystem -public sealed class Locus : IFilesystem -{ - const int NICINOD = 325; - const int NICFREE = 600; - const int OLDNICINOD = 700; - const int OLDNICFREE = 500; - - const uint LOCUS_MAGIC = 0xFFEEDDCD; - const uint LOCUS_CIGAM = 0xCDDDEEFF; - const uint LOCUS_MAGIC_OLD = 0xFFEEDDCC; - const uint LOCUS_CIGAM_OLD = 0xCCDDEEFF; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Locus Filesystem Plugin"; - /// - public Guid Id => new("1A70B30A-437D-479A-88E1-D0C9C1797FF4"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 512) - return false; - - for(ulong location = 0; location <= 8; location++) - { - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - if(partition.Start + location + sbSize >= imagePlugin.Info.Sectors) - break; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - Superblock locusSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - AaruConsole.DebugWriteLine("Locus plugin", "magic at {1} = 0x{0:X8}", locusSb.s_magic, location); - - if(locusSb.s_magic is LOCUS_MAGIC or LOCUS_CIGAM or LOCUS_MAGIC_OLD or LOCUS_CIGAM_OLD) - return true; - } - - return false; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - if(imagePlugin.Info.SectorSize < 512) - return; - - var locusSb = new Superblock(); - byte[] sector = null; - - for(ulong location = 0; location <= 8; location++) - { - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out sector); - - if(errno != ErrorNumber.NoError) - continue; - - if(sector.Length < Marshal.SizeOf()) - return; - - locusSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - if(locusSb.s_magic is LOCUS_MAGIC or LOCUS_CIGAM or LOCUS_MAGIC_OLD or LOCUS_CIGAM_OLD) - break; - } - - // We don't care about old version for information - if(locusSb.s_magic != LOCUS_MAGIC && - locusSb.s_magic != LOCUS_CIGAM && - locusSb.s_magic != LOCUS_MAGIC_OLD && - locusSb.s_magic != LOCUS_CIGAM_OLD) - return; - - // Numerical arrays are not important for information so no need to swap them - if(locusSb.s_magic is LOCUS_CIGAM or LOCUS_CIGAM_OLD) - { - locusSb = Marshal.ByteArrayToStructureBigEndian(sector); - locusSb.s_flags = (Flags)Swapping.Swap((ushort)locusSb.s_flags); - } - - var sb = new StringBuilder(); - - sb.AppendLine(locusSb.s_magic == LOCUS_MAGIC_OLD ? "Locus filesystem (old)" : "Locus filesystem"); - - int blockSize = locusSb.s_version == Version.SB_SB4096 ? 4096 : 1024; - - // ReSharper disable once InconsistentNaming - string s_fsmnt = StringHandlers.CToString(locusSb.s_fsmnt, Encoding); - - // ReSharper disable once InconsistentNaming - string s_fpack = StringHandlers.CToString(locusSb.s_fpack, Encoding); - - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_magic = 0x{0:X8}", locusSb.s_magic); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_gfs = {0}", locusSb.s_gfs); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fsize = {0}", locusSb.s_fsize); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_lwm = {0}", locusSb.s_lwm); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_hwm = {0}", locusSb.s_hwm); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_llst = {0}", locusSb.s_llst); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fstore = {0}", locusSb.s_fstore); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_time = {0}", locusSb.s_time); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_tfree = {0}", locusSb.s_tfree); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_isize = {0}", locusSb.s_isize); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_nfree = {0}", locusSb.s_nfree); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_flags = {0}", locusSb.s_flags); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_tinode = {0}", locusSb.s_tinode); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_lasti = {0}", locusSb.s_lasti); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_nbehind = {0}", locusSb.s_nbehind); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_gfspack = {0}", locusSb.s_gfspack); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_ninode = {0}", locusSb.s_ninode); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_flock = {0}", locusSb.s_flock); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_ilock = {0}", locusSb.s_ilock); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fmod = {0}", locusSb.s_fmod); - AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_version = {0}", locusSb.s_version); - - sb.AppendFormat("Superblock last modified on {0}", DateHandlers.UnixToDateTime(locusSb.s_time)).AppendLine(); - - sb.AppendFormat("Volume has {0} blocks of {1} bytes each (total {2} bytes)", locusSb.s_fsize, blockSize, - locusSb.s_fsize * blockSize).AppendLine(); - - sb.AppendFormat("{0} blocks free ({1} bytes)", locusSb.s_tfree, locusSb.s_tfree * blockSize).AppendLine(); - sb.AppendFormat("I-node list uses {0} blocks", locusSb.s_isize).AppendLine(); - sb.AppendFormat("{0} free inodes", locusSb.s_tinode).AppendLine(); - sb.AppendFormat("Next free inode search will start at inode {0}", locusSb.s_lasti).AppendLine(); - - sb.AppendFormat("There are an estimate of {0} free inodes before next search start", locusSb.s_nbehind). - AppendLine(); - - if(locusSb.s_flags.HasFlag(Flags.SB_RDONLY)) - sb.AppendLine("Read-only volume"); - - if(locusSb.s_flags.HasFlag(Flags.SB_CLEAN)) - sb.AppendLine("Clean volume"); - - if(locusSb.s_flags.HasFlag(Flags.SB_DIRTY)) - sb.AppendLine("Dirty volume"); - - if(locusSb.s_flags.HasFlag(Flags.SB_RMV)) - sb.AppendLine("Removable volume"); - - if(locusSb.s_flags.HasFlag(Flags.SB_PRIMPACK)) - sb.AppendLine("This is the primary pack"); - - if(locusSb.s_flags.HasFlag(Flags.SB_REPLTYPE)) - sb.AppendLine("Replicated volume"); - - if(locusSb.s_flags.HasFlag(Flags.SB_USER)) - sb.AppendLine("User replicated volume"); - - if(locusSb.s_flags.HasFlag(Flags.SB_BACKBONE)) - sb.AppendLine("Backbone volume"); - - if(locusSb.s_flags.HasFlag(Flags.SB_NFS)) - sb.AppendLine("NFS volume"); - - if(locusSb.s_flags.HasFlag(Flags.SB_BYHAND)) - sb.AppendLine("Volume inhibits automatic fsck"); - - if(locusSb.s_flags.HasFlag(Flags.SB_NOSUID)) - sb.AppendLine("Set-uid/set-gid is disabled"); - - if(locusSb.s_flags.HasFlag(Flags.SB_SYNCW)) - sb.AppendLine("Volume uses synchronous writes"); - - sb.AppendFormat("Volume label: {0}", s_fsmnt).AppendLine(); - sb.AppendFormat("Physical volume name: {0}", s_fpack).AppendLine(); - sb.AppendFormat("Global File System number: {0}", locusSb.s_gfs).AppendLine(); - sb.AppendFormat("Global File System pack number {0}", locusSb.s_gfspack).AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Type = "Locus filesystem", - ClusterSize = (uint)blockSize, - Clusters = (ulong)locusSb.s_fsize, - - // Sometimes it uses one, or the other. Use the bigger - VolumeName = string.IsNullOrEmpty(s_fsmnt) ? s_fpack : s_fsmnt, - ModificationDate = DateHandlers.UnixToDateTime(locusSb.s_time), - ModificationDateSpecified = true, - Dirty = !locusSb.s_flags.HasFlag(Flags.SB_CLEAN) || locusSb.s_flags.HasFlag(Flags.SB_DIRTY), - FreeClusters = (ulong)locusSb.s_tfree, - FreeClustersSpecified = true - }; - } - - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle"), - StructLayout(LayoutKind.Sequential, Pack = 1)] - struct Superblock - { - public readonly uint s_magic; /* identifies this as a locus filesystem */ - /* defined as a constant below */ - public readonly gfs_t s_gfs; /* global filesystem number */ - public readonly daddr_t s_fsize; /* size in blocks of entire volume */ - /* several ints for replicated filesystems */ - public readonly commitcnt_t s_lwm; /* all prior commits propagated */ - public readonly commitcnt_t s_hwm; /* highest commit propagated */ - /* oldest committed version in the list. - * llst mod NCMTLST is the offset of commit #llst in the list, - * which wraps around from there. - */ - public readonly commitcnt_t s_llst; - public readonly fstore_t s_fstore; /* filesystem storage bit mask; if the - filsys is replicated and this is not a - primary or backbone copy, this bit mask - determines which files are stored */ - - public readonly time_t s_time; /* last super block update */ - public readonly daddr_t s_tfree; /* total free blocks*/ - - public readonly ino_t s_isize; /* size in blocks of i-list */ - public readonly short s_nfree; /* number of addresses in s_free */ - public Flags s_flags; /* filsys flags, defined below */ - public readonly ino_t s_tinode; /* total free inodes */ - public readonly ino_t s_lasti; /* start place for circular search */ - public readonly ino_t s_nbehind; /* est # free inodes before s_lasti */ - public readonly pckno_t s_gfspack; /* global filesystem pack number */ - public readonly short s_ninode; /* number of i-nodes in s_inode */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly short[] s_dinfo; /* interleave stuff */ - - //#define s_m s_dinfo[0] - //#define s_skip s_dinfo[0] /* AIX defines */ - //#define s_n s_dinfo[1] - //#define s_cyl s_dinfo[1] /* AIX defines */ - public readonly byte s_flock; /* lock during free list manipulation */ - public readonly byte s_ilock; /* lock during i-list manipulation */ - public readonly byte s_fmod; /* super block modified flag */ - public readonly Version s_version; /* version of the data format in fs. */ - /* defined below. */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] s_fsmnt; /* name of this file system */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] s_fpack; /* name of this physical volume */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = NICINOD)] - public readonly ino_t[] s_inode; /* free i-node list */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = NICFREE)] - public readonly daddr_t[] su_free; /* free block list for non-replicated filsys */ - public readonly byte s_byteorder; /* byte order of integers */ - } - - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle"), - StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct OldSuperblock - { - public readonly uint s_magic; /* identifies this as a locus filesystem */ - /* defined as a constant below */ - public readonly gfs_t s_gfs; /* global filesystem number */ - public readonly daddr_t s_fsize; /* size in blocks of entire volume */ - /* several ints for replicated filsystems */ - public readonly commitcnt_t s_lwm; /* all prior commits propagated */ - public readonly commitcnt_t s_hwm; /* highest commit propagated */ - /* oldest committed version in the list. - * llst mod NCMTLST is the offset of commit #llst in the list, - * which wraps around from there. - */ - public readonly commitcnt_t s_llst; - public readonly fstore_t s_fstore; /* filesystem storage bit mask; if the - filsys is replicated and this is not a - primary or backbone copy, this bit mask - determines which files are stored */ - - public readonly time_t s_time; /* last super block update */ - public readonly daddr_t s_tfree; /* total free blocks*/ - - public readonly ino_t s_isize; /* size in blocks of i-list */ - public readonly short s_nfree; /* number of addresses in s_free */ - public readonly Flags s_flags; /* filsys flags, defined below */ - public readonly ino_t s_tinode; /* total free inodes */ - public readonly ino_t s_lasti; /* start place for circular search */ - public readonly ino_t s_nbehind; /* est # free inodes before s_lasti */ - public readonly pckno_t s_gfspack; /* global filesystem pack number */ - public readonly short s_ninode; /* number of i-nodes in s_inode */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly short[] s_dinfo; /* interleave stuff */ - - //#define s_m s_dinfo[0] - //#define s_skip s_dinfo[0] /* AIX defines */ - //#define s_n s_dinfo[1] - //#define s_cyl s_dinfo[1] /* AIX defines */ - public readonly byte s_flock; /* lock during free list manipulation */ - public readonly byte s_ilock; /* lock during i-list manipulation */ - public readonly byte s_fmod; /* super block modified flag */ - public readonly Version s_version; /* version of the data format in fs. */ - /* defined below. */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] s_fsmnt; /* name of this file system */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] s_fpack; /* name of this physical volume */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = OLDNICINOD)] - public readonly ino_t[] s_inode; /* free i-node list */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = OLDNICFREE)] - public readonly daddr_t[] su_free; /* free block list for non-replicated filsys */ - public readonly byte s_byteorder; /* byte order of integers */ - } - - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle"), - Flags] - enum Flags : ushort - { - SB_RDONLY = 0x1, /* no writes on filesystem */ - SB_CLEAN = 0x2, /* fs unmounted cleanly (or checks run) */ - SB_DIRTY = 0x4, /* fs mounted without CLEAN bit set */ - SB_RMV = 0x8, /* fs is a removable file system */ - SB_PRIMPACK = 0x10, /* This is the primary pack of the filesystem */ - SB_REPLTYPE = 0x20, /* This is a replicated type filesystem. */ - SB_USER = 0x40, /* This is a "user" replicated filesystem. */ - SB_BACKBONE = 0x80, /* backbone pack ; complete copy of primary pack but not modifiable */ - SB_NFS = 0x100, /* This is a NFS type filesystem */ - SB_BYHAND = 0x200, /* Inhibits automatic fscks on a mangled file system */ - SB_NOSUID = 0x400, /* Set-uid/Set-gid is disabled */ - SB_SYNCW = 0x800 /* Synchronous Write */ - } - - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle"), - Flags] - enum Version : byte - { - SB_SB4096 = 1, /* smallblock filesys with 4096 byte blocks */ - SB_B1024 = 2, /* 1024 byte block filesystem */ - NUMSCANDEV = 5 /* Used by scangfs(), refed in space.h */ - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/Locus/Consts.cs b/Aaru.Filesystems/Locus/Consts.cs new file mode 100644 index 000000000..dba82a943 --- /dev/null +++ b/Aaru.Filesystems/Locus/Consts.cs @@ -0,0 +1,63 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Locus filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License aint with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// Commit count + +// Disk address + +// Fstore + +// Global File System number + +// Inode number + +// Filesystem pack number + +// Timestamp + +// ReSharper disable UnusedMember.Local +// ReSharper disable UnusedType.Local + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Locus filesystem +public sealed partial class Locus +{ + const int NICINOD = 325; + const int NICFREE = 600; + const int OLDNICINOD = 700; + const int OLDNICFREE = 500; + + const uint LOCUS_MAGIC = 0xFFEEDDCD; + const uint LOCUS_CIGAM = 0xCDDDEEFF; + const uint LOCUS_MAGIC_OLD = 0xFFEEDDCC; + const uint LOCUS_CIGAM_OLD = 0xCCDDEEFF; + + const string FS_TYPE = "locus"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/Locus/Enums.cs b/Aaru.Filesystems/Locus/Enums.cs new file mode 100644 index 000000000..eba0ee7d9 --- /dev/null +++ b/Aaru.Filesystems/Locus/Enums.cs @@ -0,0 +1,91 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Locus filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License aint with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// Commit count + +using System; +using System.Diagnostics.CodeAnalysis; + +// Disk address + +// Fstore + +// Global File System number + +// Inode number + +// Filesystem pack number + +// Timestamp + +// ReSharper disable UnusedMember.Local +// ReSharper disable UnusedType.Local + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Locus filesystem +public sealed partial class Locus +{ +#region Nested type: Flags + + [SuppressMessage("ReSharper", "InconsistentNaming")] + [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] + [Flags] + enum Flags : ushort + { + SB_RDONLY = 0x1, /* no writes on filesystem */ + SB_CLEAN = 0x2, /* fs unmounted cleanly (or checks run) */ + SB_DIRTY = 0x4, /* fs mounted without CLEAN bit set */ + SB_RMV = 0x8, /* fs is a removable file system */ + SB_PRIMPACK = 0x10, /* This is the primary pack of the filesystem */ + SB_REPLTYPE = 0x20, /* This is a replicated type filesystem. */ + SB_USER = 0x40, /* This is a "user" replicated filesystem. */ + SB_BACKBONE = 0x80, /* backbone pack ; complete copy of primary pack but not modifiable */ + SB_NFS = 0x100, /* This is a NFS type filesystem */ + SB_BYHAND = 0x200, /* Inhibits automatic fscks on a mangled file system */ + SB_NOSUID = 0x400, /* Set-uid/Set-gid is disabled */ + SB_SYNCW = 0x800 /* Synchronous Write */ + } + +#endregion + +#region Nested type: Version + + [SuppressMessage("ReSharper", "InconsistentNaming")] + [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] + [Flags] + enum Version : byte + { + SB_SB4096 = 1, /* smallblock filesys with 4096 byte blocks */ + SB_B1024 = 2, /* 1024 byte block filesystem */ + NUMSCANDEV = 5 /* Used by scangfs(), refed in space.h */ + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Locus/Info.cs b/Aaru.Filesystems/Locus/Info.cs new file mode 100644 index 000000000..2891dbcc3 --- /dev/null +++ b/Aaru.Filesystems/Locus/Info.cs @@ -0,0 +1,234 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Locus filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License aint with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// Commit count + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; + +// Disk address + +// Fstore + +// Global File System number + +// Inode number +using Partition = Aaru.CommonTypes.Partition; + +// Filesystem pack number + +// Timestamp + +// ReSharper disable UnusedMember.Local +// ReSharper disable UnusedType.Local + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Locus filesystem +public sealed partial class Locus +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 512) return false; + + for(ulong location = 0; location <= 8; location++) + { + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + if(partition.Start + location + sbSize >= imagePlugin.Info.Sectors) break; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + Superblock locusSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.magic_at_1_equals_0, locusSb.s_magic, location); + + if(locusSb.s_magic is LOCUS_MAGIC or LOCUS_CIGAM or LOCUS_MAGIC_OLD or LOCUS_CIGAM_OLD) return true; + } + + return false; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize < 512) return; + + var locusSb = new Superblock(); + byte[] sector = null; + + for(ulong location = 0; location <= 8; location++) + { + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out sector); + + if(errno != ErrorNumber.NoError) continue; + + if(sector.Length < Marshal.SizeOf()) return; + + locusSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + if(locusSb.s_magic is LOCUS_MAGIC or LOCUS_CIGAM or LOCUS_MAGIC_OLD or LOCUS_CIGAM_OLD) break; + } + + // We don't care about old version for information + if(locusSb.s_magic != LOCUS_MAGIC && + locusSb.s_magic != LOCUS_CIGAM && + locusSb.s_magic != LOCUS_MAGIC_OLD && + locusSb.s_magic != LOCUS_CIGAM_OLD) + return; + + // Numerical arrays are not important for information so no need to swap them + if(locusSb.s_magic is LOCUS_CIGAM or LOCUS_CIGAM_OLD) + { + locusSb = Marshal.ByteArrayToStructureBigEndian(sector); + locusSb.s_flags = (Flags)Swapping.Swap((ushort)locusSb.s_flags); + } + + var sb = new StringBuilder(); + + sb.AppendLine(locusSb.s_magic == LOCUS_MAGIC_OLD + ? Localization.Locus_filesystem_old + : Localization.Locus_filesystem); + + int blockSize = locusSb.s_version == Version.SB_SB4096 ? 4096 : 1024; + + // ReSharper disable once InconsistentNaming + string s_fsmnt = StringHandlers.CToString(locusSb.s_fsmnt, encoding); + + // ReSharper disable once InconsistentNaming + string s_fpack = StringHandlers.CToString(locusSb.s_fpack, encoding); + + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_magic = 0x{0:X8}", locusSb.s_magic); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_gfs = {0}", locusSb.s_gfs); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_fsize = {0}", locusSb.s_fsize); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_lwm = {0}", locusSb.s_lwm); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_hwm = {0}", locusSb.s_hwm); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_llst = {0}", locusSb.s_llst); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_fstore = {0}", locusSb.s_fstore); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_time = {0}", locusSb.s_time); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_tfree = {0}", locusSb.s_tfree); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_isize = {0}", locusSb.s_isize); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_nfree = {0}", locusSb.s_nfree); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_flags = {0}", locusSb.s_flags); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_tinode = {0}", locusSb.s_tinode); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_lasti = {0}", locusSb.s_lasti); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_nbehind = {0}", locusSb.s_nbehind); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_gfspack = {0}", locusSb.s_gfspack); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_ninode = {0}", locusSb.s_ninode); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_flock = {0}", locusSb.s_flock); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_ilock = {0}", locusSb.s_ilock); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_fmod = {0}", locusSb.s_fmod); + AaruConsole.DebugWriteLine(MODULE_NAME, "LocusSb.s_version = {0}", locusSb.s_version); + + sb.AppendFormat(Localization.Superblock_last_modified_on_0, DateHandlers.UnixToDateTime(locusSb.s_time)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_has_0_blocks_of_1_bytes_each_total_2_bytes, + locusSb.s_fsize, + blockSize, + locusSb.s_fsize * blockSize) + .AppendLine(); + + sb.AppendFormat(Localization._0_blocks_free_1_bytes, locusSb.s_tfree, locusSb.s_tfree * blockSize).AppendLine(); + sb.AppendFormat(Localization.Inode_list_uses_0_blocks, locusSb.s_isize).AppendLine(); + sb.AppendFormat(Localization._0_free_inodes, locusSb.s_tinode).AppendLine(); + sb.AppendFormat(Localization.Next_free_inode_search_will_start_at_inode_0, locusSb.s_lasti).AppendLine(); + + sb.AppendFormat(Localization.There_are_an_estimate_of_0_free_inodes_before_next_search_start, locusSb.s_nbehind) + .AppendLine(); + + if(locusSb.s_flags.HasFlag(Flags.SB_RDONLY)) sb.AppendLine(Localization.Read_only_volume); + + if(locusSb.s_flags.HasFlag(Flags.SB_CLEAN)) sb.AppendLine(Localization.Clean_volume); + + if(locusSb.s_flags.HasFlag(Flags.SB_DIRTY)) sb.AppendLine(Localization.Dirty_volume); + + if(locusSb.s_flags.HasFlag(Flags.SB_RMV)) sb.AppendLine(Localization.Removable_volume); + + if(locusSb.s_flags.HasFlag(Flags.SB_PRIMPACK)) sb.AppendLine(Localization.This_is_the_primary_pack); + + if(locusSb.s_flags.HasFlag(Flags.SB_REPLTYPE)) sb.AppendLine(Localization.Replicated_volume); + + if(locusSb.s_flags.HasFlag(Flags.SB_USER)) sb.AppendLine(Localization.User_replicated_volume); + + if(locusSb.s_flags.HasFlag(Flags.SB_BACKBONE)) sb.AppendLine(Localization.Backbone_volume); + + if(locusSb.s_flags.HasFlag(Flags.SB_NFS)) sb.AppendLine(Localization.NFS_volume); + + if(locusSb.s_flags.HasFlag(Flags.SB_BYHAND)) sb.AppendLine(Localization.Volume_inhibits_automatic_fsck); + + if(locusSb.s_flags.HasFlag(Flags.SB_NOSUID)) sb.AppendLine(Localization.Set_uid_set_gid_is_disabled); + + if(locusSb.s_flags.HasFlag(Flags.SB_SYNCW)) sb.AppendLine(Localization.Volume_uses_synchronous_writes); + + sb.AppendFormat(Localization.Volume_label_0, s_fsmnt).AppendLine(); + sb.AppendFormat(Localization.Physical_volume_name_0, s_fpack).AppendLine(); + sb.AppendFormat(Localization.Global_File_System_number_0, locusSb.s_gfs).AppendLine(); + sb.AppendFormat(Localization.Global_File_System_pack_number_0, locusSb.s_gfspack).AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = (uint)blockSize, + Clusters = (ulong)locusSb.s_fsize, + + // Sometimes it uses one, or the other. Use the bigger + VolumeName = string.IsNullOrEmpty(s_fsmnt) ? s_fpack : s_fsmnt, + ModificationDate = DateHandlers.UnixToDateTime(locusSb.s_time), + Dirty = !locusSb.s_flags.HasFlag(Flags.SB_CLEAN) || locusSb.s_flags.HasFlag(Flags.SB_DIRTY), + FreeClusters = (ulong)locusSb.s_tfree + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Locus/Locus.cs b/Aaru.Filesystems/Locus/Locus.cs new file mode 100644 index 000000000..d30cfeeb4 --- /dev/null +++ b/Aaru.Filesystems/Locus/Locus.cs @@ -0,0 +1,69 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Locus.cs +// Author(s) : Natalia Portillo +// +// Component : Locus filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License aint with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// Commit count + +using System; +using Aaru.CommonTypes.Interfaces; + +// Disk address + +// Fstore + +// Global File System number + +// Inode number + +// Filesystem pack number + +// Timestamp + +// ReSharper disable UnusedMember.Local +// ReSharper disable UnusedType.Local + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Locus filesystem +public sealed partial class Locus : IFilesystem +{ + const string MODULE_NAME = "Locus plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.Locus_Name; + + /// + public Guid Id => new("1A70B30A-437D-479A-88E1-D0C9C1797FF4"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Locus/Structs.cs b/Aaru.Filesystems/Locus/Structs.cs new file mode 100644 index 000000000..7d12eaeb2 --- /dev/null +++ b/Aaru.Filesystems/Locus/Structs.cs @@ -0,0 +1,181 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Locus filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License aint with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// Commit count + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using commitcnt_t = int; + +// Disk address +using daddr_t = int; + +// Fstore +using fstore_t = int; + +// Global File System number +using gfs_t = int; + +// Inode number +using ino_t = int; + +// Filesystem pack number +using pckno_t = short; + +// Timestamp +using time_t = int; + +// ReSharper disable UnusedMember.Local +// ReSharper disable UnusedType.Local + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Locus filesystem +public sealed partial class Locus +{ +#region Nested type: OldSuperblock + + [SuppressMessage("ReSharper", "InconsistentNaming")] + [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct OldSuperblock + { + public readonly uint s_magic; /* identifies this as a locus filesystem */ + /* defined as a constant below */ + public readonly gfs_t s_gfs; /* global filesystem number */ + public readonly daddr_t s_fsize; /* size in blocks of entire volume */ + /* several ints for replicated filsystems */ + public readonly commitcnt_t s_lwm; /* all prior commits propagated */ + public readonly commitcnt_t s_hwm; /* highest commit propagated */ + /* oldest committed version in the list. + * llst mod NCMTLST is the offset of commit #llst in the list, + * which wraps around from there. + */ + public readonly commitcnt_t s_llst; + public readonly fstore_t s_fstore; /* filesystem storage bit mask; if the + filsys is replicated and this is not a + primary or backbone copy, this bit mask + determines which files are stored */ + + public readonly time_t s_time; /* last super block update */ + public readonly daddr_t s_tfree; /* total free blocks*/ + + public readonly ino_t s_isize; /* size in blocks of i-list */ + public readonly short s_nfree; /* number of addresses in s_free */ + public readonly Flags s_flags; /* filsys flags, defined below */ + public readonly ino_t s_tinode; /* total free inodes */ + public readonly ino_t s_lasti; /* start place for circular search */ + public readonly ino_t s_nbehind; /* est # free inodes before s_lasti */ + public readonly pckno_t s_gfspack; /* global filesystem pack number */ + public readonly short s_ninode; /* number of i-nodes in s_inode */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly short[] s_dinfo; /* interleave stuff */ + + //#define s_m s_dinfo[0] + //#define s_skip s_dinfo[0] /* AIX defines */ + //#define s_n s_dinfo[1] + //#define s_cyl s_dinfo[1] /* AIX defines */ + public readonly byte s_flock; /* lock during free list manipulation */ + public readonly byte s_ilock; /* lock during i-list manipulation */ + public readonly byte s_fmod; /* super block modified flag */ + public readonly Version s_version; /* version of the data format in fs. */ + /* defined below. */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] s_fsmnt; /* name of this file system */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] s_fpack; /* name of this physical volume */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = OLDNICINOD)] + public readonly ino_t[] s_inode; /* free i-node list */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = OLDNICFREE)] + public readonly daddr_t[] su_free; /* free block list for non-replicated filsys */ + public readonly byte s_byteorder; /* byte order of integers */ + } + +#endregion + +#region Nested type: Superblock + + [SuppressMessage("ReSharper", "InconsistentNaming")] + [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Superblock + { + public readonly uint s_magic; /* identifies this as a locus filesystem */ + /* defined as a constant below */ + public readonly gfs_t s_gfs; /* global filesystem number */ + public readonly daddr_t s_fsize; /* size in blocks of entire volume */ + /* several ints for replicated filesystems */ + public readonly commitcnt_t s_lwm; /* all prior commits propagated */ + public readonly commitcnt_t s_hwm; /* highest commit propagated */ + /* oldest committed version in the list. + * llst mod NCMTLST is the offset of commit #llst in the list, + * which wraps around from there. + */ + public readonly commitcnt_t s_llst; + public readonly fstore_t s_fstore; /* filesystem storage bit mask; if the + filsys is replicated and this is not a + primary or backbone copy, this bit mask + determines which files are stored */ + + public readonly time_t s_time; /* last super block update */ + public readonly daddr_t s_tfree; /* total free blocks*/ + + public readonly ino_t s_isize; /* size in blocks of i-list */ + public readonly short s_nfree; /* number of addresses in s_free */ + public Flags s_flags; /* filsys flags, defined below */ + public readonly ino_t s_tinode; /* total free inodes */ + public readonly ino_t s_lasti; /* start place for circular search */ + public readonly ino_t s_nbehind; /* est # free inodes before s_lasti */ + public readonly pckno_t s_gfspack; /* global filesystem pack number */ + public readonly short s_ninode; /* number of i-nodes in s_inode */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly short[] s_dinfo; /* interleave stuff */ + + //#define s_m s_dinfo[0] + //#define s_skip s_dinfo[0] /* AIX defines */ + //#define s_n s_dinfo[1] + //#define s_cyl s_dinfo[1] /* AIX defines */ + public readonly byte s_flock; /* lock during free list manipulation */ + public readonly byte s_ilock; /* lock during i-list manipulation */ + public readonly byte s_fmod; /* super block modified flag */ + public readonly Version s_version; /* version of the data format in fs. */ + /* defined below. */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] s_fsmnt; /* name of this file system */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] s_fpack; /* name of this physical volume */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = NICINOD)] + public readonly ino_t[] s_inode; /* free i-node list */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = NICFREE)] + public readonly daddr_t[] su_free; /* free block list for non-replicated filsys */ + public readonly byte s_byteorder; /* byte order of integers */ + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/MicroDOS/Consts.cs b/Aaru.Filesystems/MicroDOS/Consts.cs new file mode 100644 index 000000000..9d1c96219 --- /dev/null +++ b/Aaru.Filesystems/MicroDOS/Consts.cs @@ -0,0 +1,45 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : MicroDOS filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedType.Local +// ReSharper disable UnusedMember.Local + +namespace Aaru.Filesystems; + +/// +/// +/// Implements detection for the MicroDOS filesystem. Information from http://www.owg.ru/mkt/BK/MKDOS.TXT Thanks +/// to tarlabnor for translating it +/// +public sealed partial class MicroDOS +{ + const ushort MAGIC = 0xA72E; + const ushort MAGIC2 = 0x530C; + + const string FS_TYPE = "microdos"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/MicroDOS/Enums.cs b/Aaru.Filesystems/MicroDOS/Enums.cs new file mode 100644 index 000000000..fc3c948c8 --- /dev/null +++ b/Aaru.Filesystems/MicroDOS/Enums.cs @@ -0,0 +1,53 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : MicroDOS filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedType.Local +// ReSharper disable UnusedMember.Local + +namespace Aaru.Filesystems; + +/// +/// +/// Implements detection for the MicroDOS filesystem. Information from http://www.owg.ru/mkt/BK/MKDOS.TXT Thanks +/// to tarlabnor for translating it +/// +public sealed partial class MicroDOS +{ +#region Nested type: FileStatus + + enum FileStatus : byte + { + CommonFile = 0, + Protected = 1, + LogicalDisk = 2, + BadFile = 0x80, + Deleted = 0xFF + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/MicroDOS/Info.cs b/Aaru.Filesystems/MicroDOS/Info.cs new file mode 100644 index 000000000..a75ee47ba --- /dev/null +++ b/Aaru.Filesystems/MicroDOS/Info.cs @@ -0,0 +1,103 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : MicroDOS filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedType.Local +// ReSharper disable UnusedMember.Local + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// +/// Implements detection for the MicroDOS filesystem. Information from http://www.owg.ru/mkt/BK/MKDOS.TXT Thanks +/// to tarlabnor for translating it +/// +public sealed partial class MicroDOS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(1 + partition.Start >= partition.End) return false; + + if(imagePlugin.Info.SectorSize < 512) return false; + + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bk0); + + if(errno != ErrorNumber.NoError) return false; + + Block0 block0 = Marshal.ByteArrayToStructureLittleEndian(bk0); + + return block0 is { label: MAGIC, mklabel: MAGIC2 }; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bk0); + + if(errno != ErrorNumber.NoError) return; + + Block0 block0 = Marshal.ByteArrayToStructureLittleEndian(bk0); + + sb.AppendLine(Localization.MicroDOS_filesystem); + sb.AppendFormat(Localization.Volume_has_0_blocks_1_bytes, block0.blocks, block0.blocks * 512).AppendLine(); + + sb.AppendFormat(Localization.Volume_has_0_blocks_used_1_bytes, block0.usedBlocks, block0.usedBlocks * 512) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_contains_0_files, block0.files).AppendLine(); + sb.AppendFormat(Localization.First_used_block_is_0, block0.firstUsedBlock).AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = 512, + Clusters = block0.blocks, + Files = block0.files, + FreeClusters = (ulong)(block0.blocks - block0.usedBlocks) + }; + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/MicroDOS/MicroDOS.cs b/Aaru.Filesystems/MicroDOS/MicroDOS.cs new file mode 100644 index 000000000..ba77e2710 --- /dev/null +++ b/Aaru.Filesystems/MicroDOS/MicroDOS.cs @@ -0,0 +1,56 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : MicroDOS.cs +// Author(s) : Natalia Portillo +// +// Component : MicroDOS filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedType.Local +// ReSharper disable UnusedMember.Local + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// +/// Implements detection for the MicroDOS filesystem. Information from http://www.owg.ru/mkt/BK/MKDOS.TXT Thanks +/// to tarlabnor for translating it +/// +public sealed partial class MicroDOS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.MicroDOS_Name; + + /// + public Guid Id => new("9F9A364A-1A27-48A3-B730-7A7122000324"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/MicroDOS.cs b/Aaru.Filesystems/MicroDOS/Structs.cs similarity index 56% rename from Aaru.Filesystems/MicroDOS.cs rename to Aaru.Filesystems/MicroDOS/Structs.cs index c078d3bcb..6ae902376 100644 --- a/Aaru.Filesystems/MicroDOS.cs +++ b/Aaru.Filesystems/MicroDOS/Structs.cs @@ -2,15 +2,11 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : MicroDOS.cs +// Filename : Structs.cs // Author(s) : Natalia Portillo // // Component : MicroDOS filesystem plugin // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the MicroDOS filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,102 +23,24 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable UnusedType.Local // ReSharper disable UnusedMember.Local -namespace Aaru.Filesystems; - -using System; using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; + +namespace Aaru.Filesystems; /// /// /// Implements detection for the MicroDOS filesystem. Information from http://www.owg.ru/mkt/BK/MKDOS.TXT Thanks /// to tarlabnor for translating it /// -public sealed class MicroDOS : IFilesystem +public sealed partial class MicroDOS { - const ushort MAGIC = 0xA72E; - const ushort MAGIC2 = 0x530C; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "MicroDOS file system"; - /// - public Guid Id => new("9F9A364A-1A27-48A3-B730-7A7122000324"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(1 + partition.Start >= partition.End) - return false; - - if(imagePlugin.Info.SectorSize < 512) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bk0); - - if(errno != ErrorNumber.NoError) - return false; - - Block0 block0 = Marshal.ByteArrayToStructureLittleEndian(bk0); - - return block0.label == MAGIC && block0.mklabel == MAGIC2; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("koi8-r"); - information = ""; - - var sb = new StringBuilder(); - - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bk0); - - if(errno != ErrorNumber.NoError) - return; - - Block0 block0 = Marshal.ByteArrayToStructureLittleEndian(bk0); - - sb.AppendLine("MicroDOS filesystem"); - sb.AppendFormat("Volume has {0} blocks ({1} bytes)", block0.blocks, block0.blocks * 512).AppendLine(); - - sb.AppendFormat("Volume has {0} blocks used ({1} bytes)", block0.usedBlocks, block0.usedBlocks * 512). - AppendLine(); - - sb.AppendFormat("Volume contains {0} files", block0.files).AppendLine(); - sb.AppendFormat("First used block is {0}", block0.firstUsedBlock).AppendLine(); - - XmlFsType = new FileSystemType - { - Type = "MicroDOS", - ClusterSize = 512, - Clusters = block0.blocks, - Files = block0.files, - FilesSpecified = true, - FreeClusters = (ulong)(block0.blocks - block0.usedBlocks), - FreeClustersSpecified = true - }; - - information = sb.ToString(); - } +#region Nested type: Block0 // Followed by directory entries [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -157,6 +75,10 @@ public sealed class MicroDOS : IFilesystem public readonly byte[] unknown3; } +#endregion + +#region Nested type: DirectoryEntry + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct DirectoryEntry { @@ -177,12 +99,5 @@ public sealed class MicroDOS : IFilesystem public readonly ushort length; } - enum FileStatus : byte - { - CommonFile = 0, - Protected = 1, - LogicalDisk = 2, - BadFile = 0x80, - Deleted = 0xFF - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/MinixFS.cs b/Aaru.Filesystems/MinixFS.cs deleted file mode 100644 index 02fd9945f..000000000 --- a/Aaru.Filesystems/MinixFS.cs +++ /dev/null @@ -1,380 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : MinixFS.cs -// Author(s) : Natalia Portillo -// -// Component : MINIX filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the MINIX filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Information from the Linux kernel -/// -/// Implements detection of the MINIX filesystem -public sealed class MinixFS : IFilesystem -{ - /// Minix v1, 14 char filenames - const ushort MINIX_MAGIC = 0x137F; - /// Minix v1, 30 char filenames - const ushort MINIX_MAGIC2 = 0x138F; - /// Minix v2, 14 char filenames - const ushort MINIX2_MAGIC = 0x2468; - /// Minix v2, 30 char filenames - const ushort MINIX2_MAGIC2 = 0x2478; - /// Minix v3, 60 char filenames - const ushort MINIX3_MAGIC = 0x4D5A; - - // Byteswapped - /// Minix v1, 14 char filenames - const ushort MINIX_CIGAM = 0x7F13; - /// Minix v1, 30 char filenames - const ushort MINIX_CIGAM2 = 0x8F13; - /// Minix v2, 14 char filenames - const ushort MINIX2_CIGAM = 0x6824; - /// Minix v2, 30 char filenames - const ushort MINIX2_CIGAM2 = 0x7824; - /// Minix v3, 60 char filenames - const ushort MINIX3_CIGAM = 0x5A4D; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Minix Filesystem"; - /// - public Guid Id => new("FE248C3B-B727-4AE5-A39F-79EA9A07D4B3"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - uint sector = 2; - uint offset = 0; - - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) - { - sector = 0; - offset = 0x400; - } - - if(sector + partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(sector + partition.Start, out byte[] minixSbSector); - - if(errno != ErrorNumber.NoError) - return false; - - // Optical media - if(offset > 0) - { - var tmp = new byte[0x200]; - Array.Copy(minixSbSector, offset, tmp, 0, 0x200); - minixSbSector = tmp; - } - - var magic = BitConverter.ToUInt16(minixSbSector, 0x010); - - if(magic is MINIX_MAGIC or MINIX_MAGIC2 or MINIX2_MAGIC or MINIX2_MAGIC2 or MINIX_CIGAM or MINIX_CIGAM2 - or MINIX2_CIGAM or MINIX2_CIGAM2) - return true; - - magic = BitConverter.ToUInt16(minixSbSector, 0x018); // Here should reside magic number on Minix v3 - - return magic is MINIX_MAGIC or MINIX2_MAGIC or MINIX3_MAGIC or MINIX_CIGAM or MINIX2_CIGAM or MINIX3_CIGAM; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - var sb = new StringBuilder(); - - uint sector = 2; - uint offset = 0; - - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) - { - sector = 0; - offset = 0x400; - } - - var minix3 = false; - int filenamesize; - string minixVersion; - ErrorNumber errno = imagePlugin.ReadSector(sector + partition.Start, out byte[] minixSbSector); - - if(errno != ErrorNumber.NoError) - return; - - // Optical media - if(offset > 0) - { - var tmp = new byte[0x200]; - Array.Copy(minixSbSector, offset, tmp, 0, 0x200); - minixSbSector = tmp; - } - - var magic = BitConverter.ToUInt16(minixSbSector, 0x018); - - XmlFsType = new FileSystemType(); - - bool littleEndian; - - if(magic is MINIX3_MAGIC or MINIX3_CIGAM or MINIX2_MAGIC or MINIX2_CIGAM or MINIX_MAGIC or MINIX_CIGAM) - { - filenamesize = 60; - littleEndian = magic is not MINIX3_CIGAM or MINIX2_CIGAM or MINIX_CIGAM; - - switch(magic) - { - case MINIX3_MAGIC: - case MINIX3_CIGAM: - minixVersion = "Minix v3 filesystem"; - XmlFsType.Type = "Minix v3"; - - break; - case MINIX2_MAGIC: - case MINIX2_CIGAM: - minixVersion = "Minix 3 v2 filesystem"; - XmlFsType.Type = "Minix 3 v2"; - - break; - default: - minixVersion = "Minix 3 v1 filesystem"; - XmlFsType.Type = "Minix 3 v1"; - - break; - } - - minix3 = true; - } - else - { - magic = BitConverter.ToUInt16(minixSbSector, 0x010); - - switch(magic) - { - case MINIX_MAGIC: - filenamesize = 14; - minixVersion = "Minix v1 filesystem"; - littleEndian = true; - XmlFsType.Type = "Minix v1"; - - break; - case MINIX_MAGIC2: - filenamesize = 30; - minixVersion = "Minix v1 filesystem"; - littleEndian = true; - XmlFsType.Type = "Minix v1"; - - break; - case MINIX2_MAGIC: - filenamesize = 14; - minixVersion = "Minix v2 filesystem"; - littleEndian = true; - XmlFsType.Type = "Minix v2"; - - break; - case MINIX2_MAGIC2: - filenamesize = 30; - minixVersion = "Minix v2 filesystem"; - littleEndian = true; - XmlFsType.Type = "Minix v2"; - - break; - case MINIX_CIGAM: - filenamesize = 14; - minixVersion = "Minix v1 filesystem"; - littleEndian = false; - XmlFsType.Type = "Minix v1"; - - break; - case MINIX_CIGAM2: - filenamesize = 30; - minixVersion = "Minix v1 filesystem"; - littleEndian = false; - XmlFsType.Type = "Minix v1"; - - break; - case MINIX2_CIGAM: - filenamesize = 14; - minixVersion = "Minix v2 filesystem"; - littleEndian = false; - XmlFsType.Type = "Minix v2"; - - break; - case MINIX2_CIGAM2: - filenamesize = 30; - minixVersion = "Minix v2 filesystem"; - littleEndian = false; - XmlFsType.Type = "Minix v2"; - - break; - default: return; - } - } - - if(minix3) - { - SuperBlock3 mnxSb = littleEndian ? Marshal.ByteArrayToStructureLittleEndian(minixSbSector) - : Marshal.ByteArrayToStructureBigEndian(minixSbSector); - - if(magic != MINIX3_MAGIC && - magic != MINIX3_CIGAM) - mnxSb.s_blocksize = 1024; - - sb.AppendLine(minixVersion); - sb.AppendFormat("{0} chars in filename", filenamesize).AppendLine(); - - if(mnxSb.s_zones > 0) // On V2 - sb.AppendFormat("{0} zones on volume ({1} bytes)", mnxSb.s_zones, mnxSb.s_zones * 1024).AppendLine(); - else - sb.AppendFormat("{0} zones on volume ({1} bytes)", mnxSb.s_nzones, mnxSb.s_nzones * 1024).AppendLine(); - - sb.AppendFormat("{0} bytes/block", mnxSb.s_blocksize).AppendLine(); - sb.AppendFormat("{0} inodes on volume", mnxSb.s_ninodes).AppendLine(); - - sb.AppendFormat("{0} blocks on inode map ({1} bytes)", mnxSb.s_imap_blocks, - mnxSb.s_imap_blocks * mnxSb.s_blocksize).AppendLine(); - - sb.AppendFormat("{0} blocks on zone map ({1} bytes)", mnxSb.s_zmap_blocks, - mnxSb.s_zmap_blocks * mnxSb.s_blocksize).AppendLine(); - - sb.AppendFormat("First data zone: {0}", mnxSb.s_firstdatazone).AppendLine(); - - //sb.AppendFormat("log2 of blocks/zone: {0}", mnx_sb.s_log_zone_size).AppendLine(); // Apparently 0 - sb.AppendFormat("{0} bytes maximum per file", mnxSb.s_max_size).AppendLine(); - sb.AppendFormat("On-disk filesystem version: {0}", mnxSb.s_disk_version).AppendLine(); - - XmlFsType.ClusterSize = mnxSb.s_blocksize; - XmlFsType.Clusters = mnxSb.s_zones > 0 ? mnxSb.s_zones : mnxSb.s_nzones; - } - else - { - SuperBlock mnxSb = littleEndian ? Marshal.ByteArrayToStructureLittleEndian(minixSbSector) - : Marshal.ByteArrayToStructureBigEndian(minixSbSector); - - sb.AppendLine(minixVersion); - sb.AppendFormat("{0} chars in filename", filenamesize).AppendLine(); - - if(mnxSb.s_zones > 0) // On V2 - sb.AppendFormat("{0} zones on volume ({1} bytes)", mnxSb.s_zones, mnxSb.s_zones * 1024).AppendLine(); - else - sb.AppendFormat("{0} zones on volume ({1} bytes)", mnxSb.s_nzones, mnxSb.s_nzones * 1024).AppendLine(); - - sb.AppendFormat("{0} inodes on volume", mnxSb.s_ninodes).AppendLine(); - - sb.AppendFormat("{0} blocks on inode map ({1} bytes)", mnxSb.s_imap_blocks, mnxSb.s_imap_blocks * 1024). - AppendLine(); - - sb.AppendFormat("{0} blocks on zone map ({1} bytes)", mnxSb.s_zmap_blocks, mnxSb.s_zmap_blocks * 1024). - AppendLine(); - - sb.AppendFormat("First data zone: {0}", mnxSb.s_firstdatazone).AppendLine(); - - //sb.AppendFormat("log2 of blocks/zone: {0}", mnx_sb.s_log_zone_size).AppendLine(); // Apparently 0 - sb.AppendFormat("{0} bytes maximum per file", mnxSb.s_max_size).AppendLine(); - sb.AppendFormat("Filesystem state: {0:X4}", mnxSb.s_state).AppendLine(); - XmlFsType.ClusterSize = 1024; - XmlFsType.Clusters = mnxSb.s_zones > 0 ? mnxSb.s_zones : mnxSb.s_nzones; - } - - information = sb.ToString(); - } - - /// Superblock for Minix v1 and V2 filesystems - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SuperBlock - { - /// 0x00, inodes on volume - public readonly ushort s_ninodes; - /// 0x02, zones on volume - public readonly ushort s_nzones; - /// 0x04, blocks on inode map - public readonly short s_imap_blocks; - /// 0x06, blocks on zone map - public readonly short s_zmap_blocks; - /// 0x08, first data zone - public readonly ushort s_firstdatazone; - /// 0x0A, log2 of blocks/zone - public readonly short s_log_zone_size; - /// 0x0C, max file size - public readonly uint s_max_size; - /// 0x10, magic - public readonly ushort s_magic; - /// 0x12, filesystem state - public readonly ushort s_state; - /// 0x14, number of zones - public readonly uint s_zones; - } - - /// Superblock for Minix v3 filesystems - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SuperBlock3 - { - /// 0x00, inodes on volume - public readonly uint s_ninodes; - /// 0x02, old zones on volume - public readonly ushort s_nzones; - /// 0x06, blocks on inode map - public readonly ushort s_imap_blocks; - /// 0x08, blocks on zone map - public readonly ushort s_zmap_blocks; - /// 0x0A, first data zone - public readonly ushort s_firstdatazone; - /// 0x0C, log2 of blocks/zone - public readonly ushort s_log_zone_size; - /// 0x0E, padding - public readonly ushort s_pad1; - /// 0x10, max file size - public readonly uint s_max_size; - /// 0x14, number of zones - public readonly uint s_zones; - /// 0x18, magic - public readonly ushort s_magic; - /// 0x1A, padding - public readonly ushort s_pad2; - /// 0x1C, bytes in a block - public ushort s_blocksize; - /// 0x1E, on-disk structures version - public readonly byte s_disk_version; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/MinixFS/Consts.cs b/Aaru.Filesystems/MinixFS/Consts.cs new file mode 100644 index 000000000..900a4c0e4 --- /dev/null +++ b/Aaru.Filesystems/MinixFS/Consts.cs @@ -0,0 +1,62 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : MINIX filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the MINIX filesystem +public sealed partial class MinixFS +{ + /// Minix v1, 14 char filenames + const ushort MINIX_MAGIC = 0x137F; + /// Minix v1, 30 char filenames + const ushort MINIX_MAGIC2 = 0x138F; + /// Minix v2, 14 char filenames + const ushort MINIX2_MAGIC = 0x2468; + /// Minix v2, 30 char filenames + const ushort MINIX2_MAGIC2 = 0x2478; + /// Minix v3, 60 char filenames + const ushort MINIX3_MAGIC = 0x4D5A; + + // Byteswapped + /// Minix v1, 14 char filenames + const ushort MINIX_CIGAM = 0x7F13; + /// Minix v1, 30 char filenames + const ushort MINIX_CIGAM2 = 0x8F13; + /// Minix v2, 14 char filenames + const ushort MINIX2_CIGAM = 0x6824; + /// Minix v2, 30 char filenames + const ushort MINIX2_CIGAM2 = 0x7824; + /// Minix v3, 60 char filenames + const ushort MINIX3_CIGAM = 0x5A4D; + + const string FS_TYPE_V1 = "minix"; + const string FS_TYPE_V2 = "minix2"; + const string FS_TYPE_V3 = "minix3"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/MinixFS/Info.cs b/Aaru.Filesystems/MinixFS/Info.cs new file mode 100644 index 000000000..d8993a653 --- /dev/null +++ b/Aaru.Filesystems/MinixFS/Info.cs @@ -0,0 +1,310 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : MINIX filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the MINIX filesystem +public sealed partial class MinixFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + uint sector = 2; + uint offset = 0; + + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) + { + sector = 0; + offset = 0x400; + } + + if(sector + partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(sector + partition.Start, out byte[] minixSbSector); + + if(errno != ErrorNumber.NoError) return false; + + // Optical media + if(offset > 0) + { + var tmp = new byte[0x200]; + Array.Copy(minixSbSector, offset, tmp, 0, 0x200); + minixSbSector = tmp; + } + + var magic = BitConverter.ToUInt16(minixSbSector, 0x010); + + if(magic is MINIX_MAGIC + or MINIX_MAGIC2 + or MINIX2_MAGIC + or MINIX2_MAGIC2 + or MINIX_CIGAM + or MINIX_CIGAM2 + or MINIX2_CIGAM + or MINIX2_CIGAM2) + return true; + + magic = BitConverter.ToUInt16(minixSbSector, 0x018); // Here should reside magic number on Minix v3 + + return magic is MINIX_MAGIC or MINIX2_MAGIC or MINIX3_MAGIC or MINIX_CIGAM or MINIX2_CIGAM or MINIX3_CIGAM; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + uint sector = 2; + uint offset = 0; + + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) + { + sector = 0; + offset = 0x400; + } + + var minix3 = false; + int filenamesize; + string minixVersion; + ErrorNumber errno = imagePlugin.ReadSector(sector + partition.Start, out byte[] minixSbSector); + + if(errno != ErrorNumber.NoError) return; + + // Optical media + if(offset > 0) + { + var tmp = new byte[0x200]; + Array.Copy(minixSbSector, offset, tmp, 0, 0x200); + minixSbSector = tmp; + } + + var magic = BitConverter.ToUInt16(minixSbSector, 0x018); + + metadata = new FileSystem(); + + bool littleEndian; + + if(magic is MINIX3_MAGIC or MINIX3_CIGAM or MINIX2_MAGIC or MINIX2_CIGAM or MINIX_MAGIC or MINIX_CIGAM) + { + filenamesize = 60; + littleEndian = magic is not (MINIX3_CIGAM or MINIX2_CIGAM or MINIX_CIGAM); + + switch(magic) + { + case MINIX3_MAGIC: + case MINIX3_CIGAM: + minixVersion = Localization.Minix_v3_filesystem; + metadata.Type = FS_TYPE_V3; + + break; + case MINIX2_MAGIC: + case MINIX2_CIGAM: + minixVersion = Localization.Minix_3_v2_filesystem; + metadata.Type = FS_TYPE_V3; + + break; + default: + minixVersion = Localization.Minix_3_v1_filesystem; + metadata.Type = FS_TYPE_V3; + + break; + } + + minix3 = true; + } + else + { + magic = BitConverter.ToUInt16(minixSbSector, 0x010); + + switch(magic) + { + case MINIX_MAGIC: + filenamesize = 14; + minixVersion = Localization.Minix_v1_filesystem; + littleEndian = true; + metadata.Type = FS_TYPE_V1; + + break; + case MINIX_MAGIC2: + filenamesize = 30; + minixVersion = Localization.Minix_v1_filesystem; + littleEndian = true; + metadata.Type = FS_TYPE_V1; + + break; + case MINIX2_MAGIC: + filenamesize = 14; + minixVersion = Localization.Minix_v2_filesystem; + littleEndian = true; + metadata.Type = FS_TYPE_V2; + + break; + case MINIX2_MAGIC2: + filenamesize = 30; + minixVersion = Localization.Minix_v2_filesystem; + littleEndian = true; + metadata.Type = FS_TYPE_V2; + + break; + case MINIX_CIGAM: + filenamesize = 14; + minixVersion = Localization.Minix_v1_filesystem; + littleEndian = false; + metadata.Type = FS_TYPE_V1; + + break; + case MINIX_CIGAM2: + filenamesize = 30; + minixVersion = Localization.Minix_v1_filesystem; + littleEndian = false; + metadata.Type = FS_TYPE_V1; + + break; + case MINIX2_CIGAM: + filenamesize = 14; + minixVersion = Localization.Minix_v2_filesystem; + littleEndian = false; + metadata.Type = FS_TYPE_V2; + + break; + case MINIX2_CIGAM2: + filenamesize = 30; + minixVersion = Localization.Minix_v2_filesystem; + littleEndian = false; + metadata.Type = FS_TYPE_V2; + + break; + default: + return; + } + } + + if(minix3) + { + SuperBlock3 mnxSb = littleEndian + ? Marshal.ByteArrayToStructureLittleEndian(minixSbSector) + : Marshal.ByteArrayToStructureBigEndian(minixSbSector); + + if(magic != MINIX3_MAGIC && magic != MINIX3_CIGAM) mnxSb.s_blocksize = 1024; + + sb.AppendLine(minixVersion); + sb.AppendFormat(Localization._0_chars_in_filename, filenamesize).AppendLine(); + + if(mnxSb.s_zones > 0) // On V2 + { + sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, mnxSb.s_zones, mnxSb.s_zones * 1024) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, mnxSb.s_nzones, mnxSb.s_nzones * 1024) + .AppendLine(); + } + + sb.AppendFormat(Localization._0_bytes_block, mnxSb.s_blocksize).AppendLine(); + sb.AppendFormat(Localization._0_inodes_in_volume, mnxSb.s_ninodes).AppendLine(); + + sb.AppendFormat(Localization._0_blocks_on_inode_map_1_bytes, + mnxSb.s_imap_blocks, + mnxSb.s_imap_blocks * mnxSb.s_blocksize) + .AppendLine(); + + sb.AppendFormat(Localization._0_blocks_on_zone_map_1_bytes, + mnxSb.s_zmap_blocks, + mnxSb.s_zmap_blocks * mnxSb.s_blocksize) + .AppendLine(); + + sb.AppendFormat(Localization.First_data_zone_0, mnxSb.s_firstdatazone).AppendLine(); + + //sb.AppendFormat("log2 of blocks/zone: {0}", mnx_sb.s_log_zone_size).AppendLine(); // Apparently 0 + sb.AppendFormat(Localization._0_bytes_maximum_per_file, mnxSb.s_max_size).AppendLine(); + sb.AppendFormat(Localization.On_disk_filesystem_version_0, mnxSb.s_disk_version).AppendLine(); + + metadata.ClusterSize = mnxSb.s_blocksize; + metadata.Clusters = mnxSb.s_zones > 0 ? mnxSb.s_zones : mnxSb.s_nzones; + } + else + { + SuperBlock mnxSb = littleEndian + ? Marshal.ByteArrayToStructureLittleEndian(minixSbSector) + : Marshal.ByteArrayToStructureBigEndian(minixSbSector); + + sb.AppendLine(minixVersion); + sb.AppendFormat(Localization._0_chars_in_filename, filenamesize).AppendLine(); + + if(mnxSb.s_zones > 0) // On V2 + { + sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, mnxSb.s_zones, mnxSb.s_zones * 1024) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, mnxSb.s_nzones, mnxSb.s_nzones * 1024) + .AppendLine(); + } + + sb.AppendFormat(Localization._0_inodes_in_volume, mnxSb.s_ninodes).AppendLine(); + + sb.AppendFormat(Localization._0_blocks_on_inode_map_1_bytes, + mnxSb.s_imap_blocks, + mnxSb.s_imap_blocks * 1024) + .AppendLine(); + + sb.AppendFormat(Localization._0_blocks_on_zone_map_1_bytes, mnxSb.s_zmap_blocks, mnxSb.s_zmap_blocks * 1024) + .AppendLine(); + + sb.AppendFormat(Localization.First_data_zone_0, mnxSb.s_firstdatazone).AppendLine(); + + //sb.AppendFormat("log2 of blocks/zone: {0}", mnx_sb.s_log_zone_size).AppendLine(); // Apparently 0 + sb.AppendFormat(Localization._0_bytes_maximum_per_file, mnxSb.s_max_size).AppendLine(); + sb.AppendFormat(Localization.Filesystem_state_0, mnxSb.s_state).AppendLine(); + metadata.ClusterSize = 1024; + metadata.Clusters = mnxSb.s_zones > 0 ? mnxSb.s_zones : mnxSb.s_nzones; + } + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/MinixFS/MinixFS.cs b/Aaru.Filesystems/MinixFS/MinixFS.cs new file mode 100644 index 000000000..ff58a643c --- /dev/null +++ b/Aaru.Filesystems/MinixFS/MinixFS.cs @@ -0,0 +1,51 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : MinixFS.cs +// Author(s) : Natalia Portillo +// +// Component : MINIX filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the MINIX filesystem +public sealed partial class MinixFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.MinixFS_Name; + + /// + public Guid Id => new("FE248C3B-B727-4AE5-A39F-79EA9A07D4B3"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/MinixFS/Structs.cs b/Aaru.Filesystems/MinixFS/Structs.cs new file mode 100644 index 000000000..a4899b597 --- /dev/null +++ b/Aaru.Filesystems/MinixFS/Structs.cs @@ -0,0 +1,103 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : MINIX filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the MINIX filesystem +public sealed partial class MinixFS +{ +#region Nested type: SuperBlock + + /// Superblock for Minix v1 and V2 filesystems + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SuperBlock + { + /// 0x00, inodes on volume + public readonly ushort s_ninodes; + /// 0x02, zones on volume + public readonly ushort s_nzones; + /// 0x04, blocks on inode map + public readonly short s_imap_blocks; + /// 0x06, blocks on zone map + public readonly short s_zmap_blocks; + /// 0x08, first data zone + public readonly ushort s_firstdatazone; + /// 0x0A, log2 of blocks/zone + public readonly short s_log_zone_size; + /// 0x0C, max file size + public readonly uint s_max_size; + /// 0x10, magic + public readonly ushort s_magic; + /// 0x12, filesystem state + public readonly ushort s_state; + /// 0x14, number of zones + public readonly uint s_zones; + } + +#endregion + +#region Nested type: SuperBlock3 + + /// Superblock for Minix v3 filesystems + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SuperBlock3 + { + /// 0x00, inodes on volume + public readonly uint s_ninodes; + /// 0x02, old zones on volume + public readonly ushort s_nzones; + /// 0x06, blocks on inode map + public readonly ushort s_imap_blocks; + /// 0x08, blocks on zone map + public readonly ushort s_zmap_blocks; + /// 0x0A, first data zone + public readonly ushort s_firstdatazone; + /// 0x0C, log2 of blocks/zone + public readonly ushort s_log_zone_size; + /// 0x0E, padding + public readonly ushort s_pad1; + /// 0x10, max file size + public readonly uint s_max_size; + /// 0x14, number of zones + public readonly uint s_zones; + /// 0x18, magic + public readonly ushort s_magic; + /// 0x1A, padding + public readonly ushort s_pad2; + /// 0x1C, bytes in a block + public ushort s_blocksize; + /// 0x1E, on-disk structures version + public readonly byte s_disk_version; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/NILFS2.cs b/Aaru.Filesystems/NILFS2.cs deleted file mode 100644 index 87d90b6e5..000000000 --- a/Aaru.Filesystems/NILFS2.cs +++ /dev/null @@ -1,227 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : NILFS2.cs -// Author(s) : Natalia Portillo -// -// Component : NILFS2 filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the NILFS2 filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - - - -// ReSharper disable UnusedMember.Local - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the New Implementation of a Log-structured File System v2 -public sealed class NILFS2 : IFilesystem -{ - const ushort NILFS2_MAGIC = 0x3434; - const uint NILFS2_SUPER_OFFSET = 1024; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "NILFS2 Plugin"; - /// - public Guid Id => new("35224226-C5CC-48B5-8FFD-3781E91E86B6"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 512) - return false; - - uint sbAddr = NILFS2_SUPER_OFFSET / imagePlugin.Info.SectorSize; - - if(sbAddr == 0) - sbAddr = 1; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - if(partition.Start + sbAddr + sbSize >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - Superblock nilfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - return nilfsSb.magic == NILFS2_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.UTF8; - information = ""; - - if(imagePlugin.Info.SectorSize < 512) - return; - - uint sbAddr = NILFS2_SUPER_OFFSET / imagePlugin.Info.SectorSize; - - if(sbAddr == 0) - sbAddr = 1; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < Marshal.SizeOf()) - return; - - Superblock nilfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - if(nilfsSb.magic != NILFS2_MAGIC) - return; - - var sb = new StringBuilder(); - - sb.AppendLine("NILFS2 filesystem"); - sb.AppendFormat("Version {0}.{1}", nilfsSb.rev_level, nilfsSb.minor_rev_level).AppendLine(); - sb.AppendFormat("{0} bytes per block", 1 << (int)(nilfsSb.log_block_size + 10)).AppendLine(); - sb.AppendFormat("{0} bytes in volume", nilfsSb.dev_size).AppendLine(); - sb.AppendFormat("{0} blocks per segment", nilfsSb.blocks_per_segment).AppendLine(); - sb.AppendFormat("{0} segments", nilfsSb.nsegments).AppendLine(); - - if(nilfsSb.creator_os == 0) - sb.AppendLine("Filesystem created on Linux"); - else - sb.AppendFormat("Creator OS code: {0}", nilfsSb.creator_os).AppendLine(); - - sb.AppendFormat("{0} bytes per inode", nilfsSb.inode_size).AppendLine(); - sb.AppendFormat("Volume UUID: {0}", nilfsSb.uuid).AppendLine(); - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(nilfsSb.volume_name, Encoding)).AppendLine(); - sb.AppendFormat("Volume created on {0}", DateHandlers.UnixUnsignedToDateTime(nilfsSb.ctime)).AppendLine(); - - sb.AppendFormat("Volume last mounted on {0}", DateHandlers.UnixUnsignedToDateTime(nilfsSb.mtime)).AppendLine(); - - sb.AppendFormat("Volume last written on {0}", DateHandlers.UnixUnsignedToDateTime(nilfsSb.wtime)).AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Type = "NILFS2 filesystem", - ClusterSize = (uint)(1 << (int)(nilfsSb.log_block_size + 10)), - VolumeName = StringHandlers.CToString(nilfsSb.volume_name, Encoding), - VolumeSerial = nilfsSb.uuid.ToString(), - CreationDate = DateHandlers.UnixUnsignedToDateTime(nilfsSb.ctime), - CreationDateSpecified = true, - ModificationDate = DateHandlers.UnixUnsignedToDateTime(nilfsSb.wtime), - ModificationDateSpecified = true - }; - - if(nilfsSb.creator_os == 0) - XmlFsType.SystemIdentifier = "Linux"; - - XmlFsType.Clusters = nilfsSb.dev_size / XmlFsType.ClusterSize; - } - - enum State : ushort - { - Valid = 0x0001, - Error = 0x0002, - Resize = 0x0004 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Superblock - { - public readonly uint rev_level; - public readonly ushort minor_rev_level; - public readonly ushort magic; - public readonly ushort bytes; - public readonly ushort flags; - public readonly uint crc_seed; - public readonly uint sum; - public readonly uint log_block_size; - public readonly ulong nsegments; - public readonly ulong dev_size; - public readonly ulong first_data_block; - public readonly uint blocks_per_segment; - public readonly uint r_segments_percentage; - public readonly ulong last_cno; - public readonly ulong last_pseg; - public readonly ulong last_seq; - public readonly ulong free_blocks_count; - public readonly ulong ctime; - public readonly ulong mtime; - public readonly ulong wtime; - public readonly ushort mnt_count; - public readonly ushort max_mnt_count; - public readonly State state; - public readonly ushort errors; - public readonly ulong lastcheck; - public readonly uint checkinterval; - public readonly uint creator_os; - public readonly ushort def_resuid; - public readonly ushort def_resgid; - public readonly uint first_ino; - public readonly ushort inode_size; - public readonly ushort dat_entry_size; - public readonly ushort checkpoint_size; - public readonly ushort segment_usage_size; - public readonly Guid uuid; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] - public readonly byte[] volume_name; - public readonly uint c_interval; - public readonly uint c_block_max; - public readonly ulong feature_compat; - public readonly ulong feature_compat_ro; - public readonly ulong feature_incompat; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/NILFS2/Consts.cs b/Aaru.Filesystems/NILFS2/Consts.cs new file mode 100644 index 000000000..61f511596 --- /dev/null +++ b/Aaru.Filesystems/NILFS2/Consts.cs @@ -0,0 +1,41 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : NILFS2 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the New Implementation of a Log-structured File System v2 +public sealed partial class NILFS2 +{ + const ushort NILFS2_MAGIC = 0x3434; + const uint NILFS2_SUPER_OFFSET = 1024; + + const string FS_TYPE = "nilfs2"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/NILFS2/Enums.cs b/Aaru.Filesystems/NILFS2/Enums.cs new file mode 100644 index 000000000..0961b6281 --- /dev/null +++ b/Aaru.Filesystems/NILFS2/Enums.cs @@ -0,0 +1,47 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : NILFS2 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the New Implementation of a Log-structured File System v2 +public sealed partial class NILFS2 +{ +#region Nested type: State + + enum State : ushort + { + Valid = 0x0001, + Error = 0x0002, + Resize = 0x0004 + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/NILFS2/Info.cs b/Aaru.Filesystems/NILFS2/Info.cs new file mode 100644 index 000000000..4f966b366 --- /dev/null +++ b/Aaru.Filesystems/NILFS2/Info.cs @@ -0,0 +1,147 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : NILFS2 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the New Implementation of a Log-structured File System v2 +public sealed partial class NILFS2 +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 512) return false; + + uint sbAddr = NILFS2_SUPER_OFFSET / imagePlugin.Info.SectorSize; + + if(sbAddr == 0) sbAddr = 1; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + if(partition.Start + sbAddr + sbSize >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + Superblock nilfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + return nilfsSb.magic == NILFS2_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.UTF8; + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize < 512) return; + + uint sbAddr = NILFS2_SUPER_OFFSET / imagePlugin.Info.SectorSize; + + if(sbAddr == 0) sbAddr = 1; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < Marshal.SizeOf()) return; + + Superblock nilfsSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + if(nilfsSb.magic != NILFS2_MAGIC) return; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.NILFS2_filesystem); + sb.AppendFormat(Localization.Version_0_1, nilfsSb.rev_level, nilfsSb.minor_rev_level).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_block, 1 << (int)(nilfsSb.log_block_size + 10)).AppendLine(); + sb.AppendFormat(Localization._0_bytes_in_volume, nilfsSb.dev_size).AppendLine(); + sb.AppendFormat(Localization._0_blocks_per_segment, nilfsSb.blocks_per_segment).AppendLine(); + sb.AppendFormat(Localization._0_segments, nilfsSb.nsegments).AppendLine(); + + if(nilfsSb.creator_os == 0) + sb.AppendLine(Localization.Filesystem_created_on_Linux); + else + sb.AppendFormat(Localization.Creator_OS_code_0, nilfsSb.creator_os).AppendLine(); + + sb.AppendFormat(Localization._0_bytes_per_inode, nilfsSb.inode_size).AppendLine(); + sb.AppendFormat(Localization.Volume_UUID_0, nilfsSb.uuid).AppendLine(); + + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(nilfsSb.volume_name, encoding)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_created_on_0, DateHandlers.UnixUnsignedToDateTime(nilfsSb.ctime)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_last_mounted_on_0, DateHandlers.UnixUnsignedToDateTime(nilfsSb.mtime)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_last_written_on_0, DateHandlers.UnixUnsignedToDateTime(nilfsSb.wtime)) + .AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = (uint)(1 << (int)(nilfsSb.log_block_size + 10)), + VolumeName = StringHandlers.CToString(nilfsSb.volume_name, encoding), + VolumeSerial = nilfsSb.uuid.ToString(), + CreationDate = DateHandlers.UnixUnsignedToDateTime(nilfsSb.ctime), + ModificationDate = DateHandlers.UnixUnsignedToDateTime(nilfsSb.wtime) + }; + + if(nilfsSb.creator_os == 0) metadata.SystemIdentifier = "Linux"; + + metadata.Clusters = nilfsSb.dev_size / metadata.ClusterSize; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/NILFS2/NILFS2.cs b/Aaru.Filesystems/NILFS2/NILFS2.cs new file mode 100644 index 000000000..37426f477 --- /dev/null +++ b/Aaru.Filesystems/NILFS2/NILFS2.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : NILFS2.cs +// Author(s) : Natalia Portillo +// +// Component : NILFS2 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the New Implementation of a Log-structured File System v2 +public sealed partial class NILFS2 : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.NILFS2_Name; + + /// + public Guid Id => new("35224226-C5CC-48B5-8FFD-3781E91E86B6"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/NILFS2/Structs.cs b/Aaru.Filesystems/NILFS2/Structs.cs new file mode 100644 index 000000000..6963aa28e --- /dev/null +++ b/Aaru.Filesystems/NILFS2/Structs.cs @@ -0,0 +1,90 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : NILFS2 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedMember.Local + +using System; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the New Implementation of a Log-structured File System v2 +public sealed partial class NILFS2 +{ +#region Nested type: Superblock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Superblock + { + public readonly uint rev_level; + public readonly ushort minor_rev_level; + public readonly ushort magic; + public readonly ushort bytes; + public readonly ushort flags; + public readonly uint crc_seed; + public readonly uint sum; + public readonly uint log_block_size; + public readonly ulong nsegments; + public readonly ulong dev_size; + public readonly ulong first_data_block; + public readonly uint blocks_per_segment; + public readonly uint r_segments_percentage; + public readonly ulong last_cno; + public readonly ulong last_pseg; + public readonly ulong last_seq; + public readonly ulong free_blocks_count; + public readonly ulong ctime; + public readonly ulong mtime; + public readonly ulong wtime; + public readonly ushort mnt_count; + public readonly ushort max_mnt_count; + public readonly State state; + public readonly ushort errors; + public readonly ulong lastcheck; + public readonly uint checkinterval; + public readonly uint creator_os; + public readonly ushort def_resuid; + public readonly ushort def_resgid; + public readonly uint first_ino; + public readonly ushort inode_size; + public readonly ushort dat_entry_size; + public readonly ushort checkpoint_size; + public readonly ushort segment_usage_size; + public readonly Guid uuid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] + public readonly byte[] volume_name; + public readonly uint c_interval; + public readonly uint c_block_max; + public readonly ulong feature_compat; + public readonly ulong feature_compat_ro; + public readonly ulong feature_incompat; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/NTFS.cs b/Aaru.Filesystems/NTFS.cs deleted file mode 100644 index 15657d71e..000000000 --- a/Aaru.Filesystems/NTFS.cs +++ /dev/null @@ -1,243 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : NTFS.cs -// Author(s) : Natalia Portillo -// -// Component : Microsoft NT File System plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Microsoft NT File System and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.Checksums; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Information from Inside Windows NT -/// -/// Implements detection of the New Technology File System (NTFS) -public sealed class NTFS : IFilesystem -{ - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "New Technology File System (NTFS)"; - /// - public Guid Id => new("33513B2C-1e6d-4d21-a660-0bbc789c3871"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(2 + partition.Start >= partition.End) - return false; - - var eigthBytes = new byte[8]; - - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] ntfsBpb); - - if(errno != ErrorNumber.NoError) - return false; - - Array.Copy(ntfsBpb, 0x003, eigthBytes, 0, 8); - string oemName = StringHandlers.CToString(eigthBytes); - - if(oemName != "NTFS ") - return false; - - byte fatsNo = ntfsBpb[0x010]; - var spFat = BitConverter.ToUInt16(ntfsBpb, 0x016); - var signature = BitConverter.ToUInt16(ntfsBpb, 0x1FE); - - if(fatsNo != 0) - return false; - - if(spFat != 0) - return false; - - return signature == 0xAA55; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = Encoding.Unicode; - information = ""; - - var sb = new StringBuilder(); - - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] ntfsBpb); - - if(errno != ErrorNumber.NoError) - return; - - BiosParameterBlock ntfsBb = Marshal.ByteArrayToStructureLittleEndian(ntfsBpb); - - sb.AppendFormat("{0} bytes per sector", ntfsBb.bps).AppendLine(); - sb.AppendFormat("{0} sectors per cluster ({1} bytes)", ntfsBb.spc, ntfsBb.spc * ntfsBb.bps).AppendLine(); - - // sb.AppendFormat("{0} reserved sectors", ntfs_bb.rsectors).AppendLine(); - // sb.AppendFormat("{0} FATs", ntfs_bb.fats_no).AppendLine(); - // sb.AppendFormat("{0} entries in the root folder", ntfs_bb.root_ent).AppendLine(); - // sb.AppendFormat("{0} sectors on volume (small)", ntfs_bb.sml_sectors).AppendLine(); - sb.AppendFormat("Media descriptor: 0x{0:X2}", ntfsBb.media).AppendLine(); - - // sb.AppendFormat("{0} sectors per FAT", ntfs_bb.spfat).AppendLine(); - sb.AppendFormat("{0} sectors per track", ntfsBb.sptrk).AppendLine(); - sb.AppendFormat("{0} heads", ntfsBb.heads).AppendLine(); - sb.AppendFormat("{0} hidden sectors before filesystem", ntfsBb.hsectors).AppendLine(); - - // sb.AppendFormat("{0} sectors on volume (big)", ntfs_bb.big_sectors).AppendLine(); - sb.AppendFormat("BIOS drive number: 0x{0:X2}", ntfsBb.drive_no).AppendLine(); - - // sb.AppendFormat("NT flags: 0x{0:X2}", ntfs_bb.nt_flags).AppendLine(); - // sb.AppendFormat("Signature 1: 0x{0:X2}", ntfs_bb.signature1).AppendLine(); - sb.AppendFormat("{0} sectors on volume ({1} bytes)", ntfsBb.sectors, ntfsBb.sectors * ntfsBb.bps).AppendLine(); - - sb.AppendFormat("Cluster where $MFT starts: {0}", ntfsBb.mft_lsn).AppendLine(); - sb.AppendFormat("Cluster where $MFTMirr starts: {0}", ntfsBb.mftmirror_lsn).AppendLine(); - - if(ntfsBb.mft_rc_clusters > 0) - sb.AppendFormat("{0} clusters per MFT record ({1} bytes)", ntfsBb.mft_rc_clusters, - ntfsBb.mft_rc_clusters * ntfsBb.bps * ntfsBb.spc).AppendLine(); - else - sb.AppendFormat("{0} bytes per MFT record", 1 << -ntfsBb.mft_rc_clusters).AppendLine(); - - if(ntfsBb.index_blk_cts > 0) - sb.AppendFormat("{0} clusters per Index block ({1} bytes)", ntfsBb.index_blk_cts, - ntfsBb.index_blk_cts * ntfsBb.bps * ntfsBb.spc).AppendLine(); - else - sb.AppendFormat("{0} bytes per Index block", 1 << -ntfsBb.index_blk_cts).AppendLine(); - - sb.AppendFormat("Volume serial number: {0:X16}", ntfsBb.serial_no).AppendLine(); - - // sb.AppendFormat("Signature 2: 0x{0:X4}", ntfs_bb.signature2).AppendLine(); - - XmlFsType = new FileSystemType(); - - if(ntfsBb.jump[0] == 0xEB && - ntfsBb.jump[1] > 0x4E && - ntfsBb.jump[1] < 0x80 && - ntfsBb.signature2 == 0xAA55) - { - XmlFsType.Bootable = true; - string bootChk = Sha1Context.Data(ntfsBb.boot_code, out _); - sb.AppendLine("Volume is bootable"); - sb.AppendFormat("Boot code's SHA1: {0}", bootChk).AppendLine(); - } - - XmlFsType.ClusterSize = (uint)(ntfsBb.spc * ntfsBb.bps); - XmlFsType.Clusters = (ulong)(ntfsBb.sectors / ntfsBb.spc); - XmlFsType.VolumeSerial = $"{ntfsBb.serial_no:X16}"; - XmlFsType.Type = "NTFS"; - - information = sb.ToString(); - } - - /// NTFS $BOOT - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct BiosParameterBlock - { - // Start of BIOS Parameter Block - /// 0x000, Jump to boot code - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - /// 0x003, OEM Name, 8 bytes, space-padded, must be "NTFS " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] oem_name; - /// 0x00B, Bytes per sector - public readonly ushort bps; - /// 0x00D, Sectors per cluster - public readonly byte spc; - /// 0x00E, Reserved sectors, seems 0 - public readonly ushort rsectors; - /// 0x010, Number of FATs... obviously, 0 - public readonly byte fats_no; - /// 0x011, Number of entries on root directory... 0 - public readonly ushort root_ent; - /// 0x013, Sectors in volume... 0 - public readonly ushort sml_sectors; - /// 0x015, Media descriptor - public readonly byte media; - /// 0x016, Sectors per FAT... 0 - public readonly ushort spfat; - /// 0x018, Sectors per track, required to boot - public readonly ushort sptrk; - /// 0x01A, Heads... required to boot - public readonly ushort heads; - /// 0x01C, Hidden sectors before BPB - public readonly uint hsectors; - /// 0x020, Sectors in volume if > 65535... 0 - public readonly uint big_sectors; - /// 0x024, Drive number - public readonly byte drive_no; - /// 0x025, 0 - public readonly byte nt_flags; - /// 0x026, EPB signature, 0x80 - public readonly byte signature1; - /// 0x027, Alignment - public readonly byte dummy; - - // End of BIOS Parameter Block - - // Start of NTFS real superblock - /// 0x028, Sectors on volume - public readonly long sectors; - /// 0x030, LSN of $MFT - public readonly long mft_lsn; - /// 0x038, LSN of $MFTMirror - public readonly long mftmirror_lsn; - /// 0x040, Clusters per MFT record - public readonly sbyte mft_rc_clusters; - /// 0x041, Alignment - public readonly byte dummy2; - /// 0x042, Alignment - public readonly ushort dummy3; - /// 0x044, Clusters per index block - public readonly sbyte index_blk_cts; - /// 0x045, Alignment - public readonly byte dummy4; - /// 0x046, Alignment - public readonly ushort dummy5; - /// 0x048, Volume serial number - public readonly ulong serial_no; - /// Boot code. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 430)] - public readonly byte[] boot_code; - /// 0x1FE, 0xAA55 - public readonly ushort signature2; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/NTFS/Consts.cs b/Aaru.Filesystems/NTFS/Consts.cs new file mode 100644 index 000000000..0182c55b9 --- /dev/null +++ b/Aaru.Filesystems/NTFS/Consts.cs @@ -0,0 +1,37 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Microsoft NT File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Information from Inside Windows NT +/// +/// Implements detection of the New Technology File System (NTFS) +public sealed partial class NTFS +{ + const string FS_TYPE = "ntfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/NTFS/Info.cs b/Aaru.Filesystems/NTFS/Info.cs new file mode 100644 index 000000000..f7adf08d4 --- /dev/null +++ b/Aaru.Filesystems/NTFS/Info.cs @@ -0,0 +1,157 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Microsoft NT File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.Checksums; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from Inside Windows NT +/// +/// Implements detection of the New Technology File System (NTFS) +public sealed partial class NTFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(2 + partition.Start >= partition.End) return false; + + var eigthBytes = new byte[8]; + + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] ntfsBpb); + + if(errno != ErrorNumber.NoError) return false; + + Array.Copy(ntfsBpb, 0x003, eigthBytes, 0, 8); + string oemName = StringHandlers.CToString(eigthBytes); + + if(oemName != "NTFS ") return false; + + byte fatsNo = ntfsBpb[0x010]; + var spFat = BitConverter.ToUInt16(ntfsBpb, 0x016); + var signature = BitConverter.ToUInt16(ntfsBpb, 0x1FE); + + if(fatsNo != 0) return false; + + if(spFat != 0) return false; + + return signature == 0xAA55; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] ntfsBpb); + + if(errno != ErrorNumber.NoError) return; + + BiosParameterBlock ntfsBb = Marshal.ByteArrayToStructureLittleEndian(ntfsBpb); + + sb.AppendFormat(Localization._0_bytes_per_sector, ntfsBb.bps).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_cluster_1_bytes, ntfsBb.spc, ntfsBb.spc * ntfsBb.bps).AppendLine(); + + // sb.AppendFormat("{0} reserved sectors", ntfs_bb.rsectors).AppendLine(); + // sb.AppendFormat("{0} FATs", ntfs_bb.fats_no).AppendLine(); + // sb.AppendFormat("{0} entries in the root folder", ntfs_bb.root_ent).AppendLine(); + // sb.AppendFormat("{0} sectors on volume (small)", ntfs_bb.sml_sectors).AppendLine(); + sb.AppendFormat(Localization.Media_descriptor_0, ntfsBb.media).AppendLine(); + + // sb.AppendFormat("{0} sectors per FAT", ntfs_bb.spfat).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_track, ntfsBb.sptrk).AppendLine(); + sb.AppendFormat(Localization._0_heads, ntfsBb.heads).AppendLine(); + sb.AppendFormat(Localization._0_hidden_sectors_before_filesystem, ntfsBb.hsectors).AppendLine(); + + // sb.AppendFormat("{0} sectors on volume (big)", ntfs_bb.big_sectors).AppendLine(); + sb.AppendFormat(Localization.BIOS_drive_number_0, ntfsBb.drive_no).AppendLine(); + + // sb.AppendFormat("NT flags: 0x{0:X2}", ntfs_bb.nt_flags).AppendLine(); + // sb.AppendFormat("Signature 1: 0x{0:X2}", ntfs_bb.signature1).AppendLine(); + sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, ntfsBb.sectors, ntfsBb.sectors * ntfsBb.bps) + .AppendLine(); + + sb.AppendFormat(Localization.Cluster_where_MFT_starts_0, ntfsBb.mft_lsn).AppendLine(); + sb.AppendFormat(Localization.Cluster_where_MFTMirr_starts_0, ntfsBb.mftmirror_lsn).AppendLine(); + + if(ntfsBb.mft_rc_clusters > 0) + { + sb.AppendFormat(Localization._0_clusters_per_MFT_record_1_bytes, + ntfsBb.mft_rc_clusters, + ntfsBb.mft_rc_clusters * ntfsBb.bps * ntfsBb.spc) + .AppendLine(); + } + else + sb.AppendFormat(Localization._0_bytes_per_MFT_record, 1 << -ntfsBb.mft_rc_clusters).AppendLine(); + + if(ntfsBb.index_blk_cts > 0) + { + sb.AppendFormat(Localization._0_clusters_per_Index_block_1_bytes, + ntfsBb.index_blk_cts, + ntfsBb.index_blk_cts * ntfsBb.bps * ntfsBb.spc) + .AppendLine(); + } + else + sb.AppendFormat(Localization._0_bytes_per_Index_block, 1 << -ntfsBb.index_blk_cts).AppendLine(); + + sb.AppendFormat(Localization.Volume_serial_number_0_X16, ntfsBb.serial_no).AppendLine(); + + // sb.AppendFormat("Signature 2: 0x{0:X4}", ntfs_bb.signature2).AppendLine(); + + metadata = new FileSystem(); + + if(ntfsBb.jump[0] == 0xEB && ntfsBb.jump[1] > 0x4E && ntfsBb.jump[1] < 0x80 && ntfsBb.signature2 == 0xAA55) + { + metadata.Bootable = true; + string bootChk = Sha1Context.Data(ntfsBb.boot_code, out _); + sb.AppendLine(Localization.Volume_is_bootable); + sb.AppendFormat(Localization.Boot_code_SHA1_0, bootChk).AppendLine(); + } + + metadata.ClusterSize = (uint)(ntfsBb.spc * ntfsBb.bps); + metadata.Clusters = (ulong)(ntfsBb.sectors / ntfsBb.spc); + metadata.VolumeSerial = $"{ntfsBb.serial_no:X16}"; + metadata.Type = FS_TYPE; + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/NTFS/NTFS.cs b/Aaru.Filesystems/NTFS/NTFS.cs new file mode 100644 index 000000000..765d5f3dc --- /dev/null +++ b/Aaru.Filesystems/NTFS/NTFS.cs @@ -0,0 +1,51 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : NTFS.cs +// Author(s) : Natalia Portillo +// +// Component : Microsoft NT File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from Inside Windows NT +/// +/// Implements detection of the New Technology File System (NTFS) +public sealed partial class NTFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.NTFS_Name; + + /// + public Guid Id => new("33513B2C-1e6d-4d21-a660-0bbc789c3871"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/NTFS/Structs.cs b/Aaru.Filesystems/NTFS/Structs.cs new file mode 100644 index 000000000..c36e87da8 --- /dev/null +++ b/Aaru.Filesystems/NTFS/Structs.cs @@ -0,0 +1,115 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Microsoft NT File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Information from Inside Windows NT +/// +/// Implements detection of the New Technology File System (NTFS) +public sealed partial class NTFS +{ +#region Nested type: BiosParameterBlock + + /// NTFS $BOOT + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct BiosParameterBlock + { + // Start of BIOS Parameter Block + /// 0x000, Jump to boot code + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + /// 0x003, OEM Name, 8 bytes, space-padded, must be "NTFS " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] oem_name; + /// 0x00B, Bytes per sector + public readonly ushort bps; + /// 0x00D, Sectors per cluster + public readonly byte spc; + /// 0x00E, Reserved sectors, seems 0 + public readonly ushort rsectors; + /// 0x010, Number of FATs... obviously, 0 + public readonly byte fats_no; + /// 0x011, Number of entries on root directory... 0 + public readonly ushort root_ent; + /// 0x013, Sectors in volume... 0 + public readonly ushort sml_sectors; + /// 0x015, Media descriptor + public readonly byte media; + /// 0x016, Sectors per FAT... 0 + public readonly ushort spfat; + /// 0x018, Sectors per track, required to boot + public readonly ushort sptrk; + /// 0x01A, Heads... required to boot + public readonly ushort heads; + /// 0x01C, Hidden sectors before BPB + public readonly uint hsectors; + /// 0x020, Sectors in volume if > 65535... 0 + public readonly uint big_sectors; + /// 0x024, Drive number + public readonly byte drive_no; + /// 0x025, 0 + public readonly byte nt_flags; + /// 0x026, EPB signature, 0x80 + public readonly byte signature1; + /// 0x027, Alignment + public readonly byte dummy; + + // End of BIOS Parameter Block + + // Start of NTFS real superblock + /// 0x028, Sectors on volume + public readonly long sectors; + /// 0x030, LSN of $MFT + public readonly long mft_lsn; + /// 0x038, LSN of $MFTMirror + public readonly long mftmirror_lsn; + /// 0x040, Clusters per MFT record + public readonly sbyte mft_rc_clusters; + /// 0x041, Alignment + public readonly byte dummy2; + /// 0x042, Alignment + public readonly ushort dummy3; + /// 0x044, Clusters per index block + public readonly sbyte index_blk_cts; + /// 0x045, Alignment + public readonly byte dummy4; + /// 0x046, Alignment + public readonly ushort dummy5; + /// 0x048, Volume serial number + public readonly ulong serial_no; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 430)] + public readonly byte[] boot_code; + /// 0x1FE, 0xAA55 + public readonly ushort signature2; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Nintendo.cs b/Aaru.Filesystems/Nintendo.cs deleted file mode 100644 index 3101f3134..000000000 --- a/Aaru.Filesystems/Nintendo.cs +++ /dev/null @@ -1,476 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Nintendo.cs -// Author(s) : Natalia Portillo -// -// Component : Nintendo optical filesystems plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Nintendo optical filesystems and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; - -/// -/// Implements detection of the filesystem used by Nintendo Gamecube and Wii discs -public sealed class NintendoPlugin : IFilesystem -{ - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Nintendo optical filesystems"; - /// - public Guid Id => new("4675fcb4-4418-4288-9e4a-33d6a4ac1126"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start != 0) - return false; - - if(imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize < 0x50000) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(0, 0x50000 / imagePlugin.Info.SectorSize, out byte[] header); - - if(errno != ErrorNumber.NoError) - return false; - - var magicGc = BigEndianBitConverter.ToUInt32(header, 0x1C); - var magicWii = BigEndianBitConverter.ToUInt32(header, 0x18); - - return magicGc == 0xC2339F3D || magicWii == 0x5D1C9EA3; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("shift_jis"); - var sbInformation = new StringBuilder(); - information = ""; - XmlFsType = new FileSystemType(); - - var fields = new NintendoFields(); - - ErrorNumber errno = imagePlugin.ReadSectors(0, 0x50000 / imagePlugin.Info.SectorSize, out byte[] header); - - if(errno != ErrorNumber.NoError) - return; - - var wii = false; - - var magicGc = BigEndianBitConverter.ToUInt32(header, 0x1C); - var magicWii = BigEndianBitConverter.ToUInt32(header, 0x18); - - if(magicWii == 0x5D1C9EA3) - wii = true; - else if(magicGc != 0xC2339F3D) - return; - - fields.DiscType = Encoding.ASCII.GetString(header, 0, 1); - fields.GameCode = Encoding.ASCII.GetString(header, 1, 2); - fields.RegionCode = Encoding.ASCII.GetString(header, 3, 1); - fields.PublisherCode = Encoding.ASCII.GetString(header, 4, 2); - fields.DiscId = Encoding.ASCII.GetString(header, 0, 6); - fields.DiscNumber = header[6]; - fields.DiscVersion = header[7]; - fields.Streaming |= header[8] > 0; - fields.StreamBufferSize = header[9]; - var temp = new byte[64]; - Array.Copy(header, 0x20, temp, 0, 64); - fields.Title = StringHandlers.CToString(temp, Encoding); - - if(!wii) - { - fields.DebugOff = BigEndianBitConverter.ToUInt32(header, 0x0400); - fields.DebugAddr = BigEndianBitConverter.ToUInt32(header, 0x0404); - fields.DolOff = BigEndianBitConverter.ToUInt32(header, 0x0420); - fields.FstOff = BigEndianBitConverter.ToUInt32(header, 0x0424); - fields.FstSize = BigEndianBitConverter.ToUInt32(header, 0x0428); - fields.FstMax = BigEndianBitConverter.ToUInt32(header, 0x042C); - } - - if(wii) - { - uint offset1 = BigEndianBitConverter.ToUInt32(header, 0x40004) << 2; - uint offset2 = BigEndianBitConverter.ToUInt32(header, 0x4000C) << 2; - uint offset3 = BigEndianBitConverter.ToUInt32(header, 0x40014) << 2; - uint offset4 = BigEndianBitConverter.ToUInt32(header, 0x4001C) << 2; - - fields.FirstPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40000)]; - fields.SecondPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40008)]; - fields.ThirdPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40010)]; - fields.FourthPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40018)]; - - for(var i = 0; i < fields.FirstPartitions.Length; i++) - if(offset1 + i * 8 + 8 < 0x50000) - { - fields.FirstPartitions[i].Offset = - BigEndianBitConverter.ToUInt32(header, (int)(offset1 + i * 8 + 0)) << 2; - - fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset1 + i * 8 + 4)); - } - - for(var i = 0; i < fields.SecondPartitions.Length; i++) - if(offset1 + i * 8 + 8 < 0x50000) - { - fields.FirstPartitions[i].Offset = - BigEndianBitConverter.ToUInt32(header, (int)(offset2 + i * 8 + 0)) << 2; - - fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset2 + i * 8 + 4)); - } - - for(var i = 0; i < fields.ThirdPartitions.Length; i++) - if(offset1 + i * 8 + 8 < 0x50000) - { - fields.FirstPartitions[i].Offset = - BigEndianBitConverter.ToUInt32(header, (int)(offset3 + i * 8 + 0)) << 2; - - fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset3 + i * 8 + 4)); - } - - for(var i = 0; i < fields.FourthPartitions.Length; i++) - if(offset1 + i * 8 + 8 < 0x50000) - { - fields.FirstPartitions[i].Offset = - BigEndianBitConverter.ToUInt32(header, (int)(offset4 + i * 8 + 0)) << 2; - - fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset4 + i * 8 + 4)); - } - - fields.Region = header[0x4E000]; - fields.JapanAge = header[0x4E010]; - fields.UsaAge = header[0x4E011]; - fields.GermanAge = header[0x4E013]; - fields.PegiAge = header[0x4E014]; - fields.FinlandAge = header[0x4E015]; - fields.PortugalAge = header[0x4E016]; - fields.UkAge = header[0x4E017]; - fields.AustraliaAge = header[0x4E018]; - fields.KoreaAge = header[0x4E019]; - } - else - { - fields.FirstPartitions = Array.Empty(); - fields.SecondPartitions = Array.Empty(); - fields.ThirdPartitions = Array.Empty(); - fields.FourthPartitions = Array.Empty(); - } - - AaruConsole.DebugWriteLine("Nintendo plugin", "discType = {0}", fields.DiscType); - AaruConsole.DebugWriteLine("Nintendo plugin", "gameCode = {0}", fields.GameCode); - AaruConsole.DebugWriteLine("Nintendo plugin", "regionCode = {0}", fields.RegionCode); - AaruConsole.DebugWriteLine("Nintendo plugin", "publisherCode = {0}", fields.PublisherCode); - AaruConsole.DebugWriteLine("Nintendo plugin", "discID = {0}", fields.DiscId); - AaruConsole.DebugWriteLine("Nintendo plugin", "discNumber = {0}", fields.DiscNumber); - AaruConsole.DebugWriteLine("Nintendo plugin", "discVersion = {0}", fields.DiscVersion); - AaruConsole.DebugWriteLine("Nintendo plugin", "streaming = {0}", fields.Streaming); - AaruConsole.DebugWriteLine("Nintendo plugin", "streamBufferSize = {0}", fields.StreamBufferSize); - AaruConsole.DebugWriteLine("Nintendo plugin", "title = \"{0}\"", fields.Title); - AaruConsole.DebugWriteLine("Nintendo plugin", "debugOff = 0x{0:X8}", fields.DebugOff); - AaruConsole.DebugWriteLine("Nintendo plugin", "debugAddr = 0x{0:X8}", fields.DebugAddr); - AaruConsole.DebugWriteLine("Nintendo plugin", "dolOff = 0x{0:X8}", fields.DolOff); - AaruConsole.DebugWriteLine("Nintendo plugin", "fstOff = 0x{0:X8}", fields.FstOff); - AaruConsole.DebugWriteLine("Nintendo plugin", "fstSize = {0}", fields.FstSize); - AaruConsole.DebugWriteLine("Nintendo plugin", "fstMax = {0}", fields.FstMax); - - for(var i = 0; i < fields.FirstPartitions.Length; i++) - { - AaruConsole.DebugWriteLine("Nintendo plugin", "firstPartitions[{1}].offset = {0}", - fields.FirstPartitions[i].Offset, i); - - AaruConsole.DebugWriteLine("Nintendo plugin", "firstPartitions[{1}].type = {0}", - fields.FirstPartitions[i].Type, i); - } - - for(var i = 0; i < fields.SecondPartitions.Length; i++) - { - AaruConsole.DebugWriteLine("Nintendo plugin", "secondPartitions[{1}].offset = {0}", - fields.SecondPartitions[i].Offset, i); - - AaruConsole.DebugWriteLine("Nintendo plugin", "secondPartitions[{1}].type = {0}", - fields.SecondPartitions[i].Type, i); - } - - for(var i = 0; i < fields.ThirdPartitions.Length; i++) - { - AaruConsole.DebugWriteLine("Nintendo plugin", "thirdPartitions[{1}].offset = {0}", - fields.ThirdPartitions[i].Offset, i); - - AaruConsole.DebugWriteLine("Nintendo plugin", "thirdPartitions[{1}].type = {0}", - fields.ThirdPartitions[i].Type, i); - } - - for(var i = 0; i < fields.FourthPartitions.Length; i++) - { - AaruConsole.DebugWriteLine("Nintendo plugin", "fourthPartitions[{1}].offset = {0}", - fields.FourthPartitions[i].Offset, i); - - AaruConsole.DebugWriteLine("Nintendo plugin", "fourthPartitions[{1}].type = {0}", - fields.FourthPartitions[i].Type, i); - } - - AaruConsole.DebugWriteLine("Nintendo plugin", "region = {0}", fields.Region); - AaruConsole.DebugWriteLine("Nintendo plugin", "japanAge = {0}", fields.JapanAge); - AaruConsole.DebugWriteLine("Nintendo plugin", "usaAge = {0}", fields.UsaAge); - AaruConsole.DebugWriteLine("Nintendo plugin", "germanAge = {0}", fields.GermanAge); - AaruConsole.DebugWriteLine("Nintendo plugin", "pegiAge = {0}", fields.PegiAge); - AaruConsole.DebugWriteLine("Nintendo plugin", "finlandAge = {0}", fields.FinlandAge); - AaruConsole.DebugWriteLine("Nintendo plugin", "portugalAge = {0}", fields.PortugalAge); - AaruConsole.DebugWriteLine("Nintendo plugin", "ukAge = {0}", fields.UkAge); - AaruConsole.DebugWriteLine("Nintendo plugin", "australiaAge = {0}", fields.AustraliaAge); - AaruConsole.DebugWriteLine("Nintendo plugin", "koreaAge = {0}", fields.KoreaAge); - - sbInformation.AppendLine("Nintendo optical filesystem"); - sbInformation.AppendLine(wii ? "Nintendo Wii Optical Disc" : "Nintendo GameCube Optical Disc"); - sbInformation.AppendFormat("Disc ID is {0}", fields.DiscId).AppendLine(); - sbInformation.AppendFormat("Disc is a {0} disc", DiscTypeToString(fields.DiscType)).AppendLine(); - sbInformation.AppendFormat("Disc region is {0}", RegionCodeToString(fields.RegionCode)).AppendLine(); - sbInformation.AppendFormat("Published by {0}", PublisherCodeToString(fields.PublisherCode)).AppendLine(); - - if(fields.DiscNumber > 0) - sbInformation.AppendFormat("Disc number {0} of a multi-disc set", fields.DiscNumber + 1).AppendLine(); - - if(fields.Streaming) - sbInformation.AppendLine("Disc is prepared for audio streaming"); - - if(fields.StreamBufferSize > 0) - sbInformation.AppendFormat("Audio streaming buffer size is {0} bytes", fields.StreamBufferSize). - AppendLine(); - - sbInformation.AppendFormat("Title: {0}", fields.Title).AppendLine(); - - if(wii) - { - for(var i = 0; i < fields.FirstPartitions.Length; i++) - sbInformation.AppendFormat("First {0} partition starts at sector {1}", - PartitionTypeToString(fields.FirstPartitions[i].Type), - fields.FirstPartitions[i].Offset / 2048).AppendLine(); - - for(var i = 0; i < fields.SecondPartitions.Length; i++) - sbInformation.AppendFormat("Second {0} partition starts at sector {1}", - PartitionTypeToString(fields.SecondPartitions[i].Type), - fields.SecondPartitions[i].Offset / 2048).AppendLine(); - - for(var i = 0; i < fields.ThirdPartitions.Length; i++) - sbInformation.AppendFormat("Third {0} partition starts at sector {1}", - PartitionTypeToString(fields.ThirdPartitions[i].Type), - fields.ThirdPartitions[i].Offset / 2048).AppendLine(); - - for(var i = 0; i < fields.FourthPartitions.Length; i++) - sbInformation.AppendFormat("Fourth {0} partition starts at sector {1}", - PartitionTypeToString(fields.FourthPartitions[i].Type), - fields.FourthPartitions[i].Offset / 2048).AppendLine(); - - // sbInformation.AppendFormat("Region byte is {0}", fields.region).AppendLine(); - if((fields.JapanAge & 0x80) != 0x80) - sbInformation.AppendFormat("Japan age rating is {0}", fields.JapanAge).AppendLine(); - - if((fields.UsaAge & 0x80) != 0x80) - sbInformation.AppendFormat("ESRB age rating is {0}", fields.UsaAge).AppendLine(); - - if((fields.GermanAge & 0x80) != 0x80) - sbInformation.AppendFormat("German age rating is {0}", fields.GermanAge).AppendLine(); - - if((fields.PegiAge & 0x80) != 0x80) - sbInformation.AppendFormat("PEGI age rating is {0}", fields.PegiAge).AppendLine(); - - if((fields.FinlandAge & 0x80) != 0x80) - sbInformation.AppendFormat("Finland age rating is {0}", fields.FinlandAge).AppendLine(); - - if((fields.PortugalAge & 0x80) != 0x80) - sbInformation.AppendFormat("Portugal age rating is {0}", fields.PortugalAge).AppendLine(); - - if((fields.UkAge & 0x80) != 0x80) - sbInformation.AppendFormat("UK age rating is {0}", fields.UkAge).AppendLine(); - - if((fields.AustraliaAge & 0x80) != 0x80) - sbInformation.AppendFormat("Australia age rating is {0}", fields.AustraliaAge).AppendLine(); - - if((fields.KoreaAge & 0x80) != 0x80) - sbInformation.AppendFormat("Korea age rating is {0}", fields.KoreaAge).AppendLine(); - } - else - sbInformation.AppendFormat("FST starts at {0} and has {1} bytes", fields.FstOff, fields.FstSize). - AppendLine(); - - information = sbInformation.ToString(); - XmlFsType.Bootable = true; - XmlFsType.Clusters = imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize / 2048; - XmlFsType.ClusterSize = 2048; - XmlFsType.Type = wii ? "Nintendo Wii filesystem" : "Nintendo Gamecube filesystem"; - XmlFsType.VolumeName = fields.Title; - XmlFsType.VolumeSerial = fields.DiscId; - } - - static string DiscTypeToString(string discType) - { - switch(discType) - { - case "C": return "Commodore 64 Virtual Console"; - case "D": return "Demo"; - case "E": return "Neo-Geo Virtual Console"; - case "F": return "NES Virtual Console"; - case "G": return "Gamecube"; - case "H": return "Wii channel"; - case "J": return "Super Nintendo Virtual Console"; - case "L": return "Master System Virtual Console"; - case "M": return "Megadrive Virtual Console"; - case "N": return "Nintendo 64 Virtual Console"; - case "P": return "Promotional or TurboGrafx Virtual Console"; - case "Q": return "TurboGrafx CD Virtual Console"; - case "R": - case "S": return "Wii"; - case "U": return "Utility"; - case "W": return "WiiWare"; - case "X": return "MSX Virtual Console or WiiWare demo"; - case "0": - case "1": return "Diagnostic"; - case "4": return "Wii Backup"; - case "_": return "WiiFit"; - } - - return $"unknown type '{discType}'"; - } - - static string RegionCodeToString(string regionCode) - { - switch(regionCode) - { - case "A": return "any region"; - case "D": return "Germany"; - case "N": - case "E": return "USA"; - case "F": return "France"; - case "I": return "Italy"; - case "J": return "Japan"; - case "K": - case "Q": return "Korea"; - case "L": - case "M": - case "P": return "PAL"; - case "R": return "Russia"; - case "S": return "Spain"; - case "T": return "Taiwan"; - case "U": return "Australia"; - } - - return $"unknown code '{regionCode}'"; - } - - static string PublisherCodeToString(string publisherCode) - { - switch(publisherCode) - { - case "01": return "Nintendo"; - case "08": return "CAPCOM"; - case "41": return "Ubisoft"; - case "4F": return "Eidos"; - case "51": return "Acclaim"; - case "52": return "Activision"; - case "5D": return "Midway"; - case "5G": return "Hudson"; - case "64": return "LucasArts"; - case "69": return "Electronic Arts"; - case "6S": return "TDK Mediactive"; - case "8P": return "SEGA"; - case "A4": return "Mirage Studios"; - case "AF": return "Namco"; - case "B2": return "Bandai"; - case "DA": return "Tomy"; - case "EM": return "Konami"; - case "70": return "Atari"; - case "4Q": return "Disney Interactive"; - case "GD": return "Square Enix"; - case "7D": return "Sierra"; - } - - return $"Unknown publisher '{publisherCode}'"; - } - - static string PartitionTypeToString(uint type) - { - switch(type) - { - case 0: return "data"; - case 1: return "update"; - case 2: return "channel"; - } - - return $"unknown type {type}"; - } - - struct NintendoFields - { - public string DiscType; - public string GameCode; - public string RegionCode; - public string PublisherCode; - public string DiscId; - public byte DiscNumber; - public byte DiscVersion; - public bool Streaming; - public byte StreamBufferSize; - public string Title; - public uint DebugOff; - public uint DebugAddr; - public uint DolOff; - public uint FstOff; - public uint FstSize; - public uint FstMax; - public NintendoPartition[] FirstPartitions; - public NintendoPartition[] SecondPartitions; - public NintendoPartition[] ThirdPartitions; - public NintendoPartition[] FourthPartitions; - public byte Region; - public byte JapanAge; - public byte UsaAge; - public byte GermanAge; - public byte PegiAge; - public byte FinlandAge; - public byte PortugalAge; - public byte UkAge; - public byte AustraliaAge; - public byte KoreaAge; - } - - struct NintendoPartition - { - public uint Offset; - public uint Type; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/Nintendo/Consts.cs b/Aaru.Filesystems/Nintendo/Consts.cs new file mode 100644 index 000000000..f28f42247 --- /dev/null +++ b/Aaru.Filesystems/Nintendo/Consts.cs @@ -0,0 +1,37 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Nintendo optical filesystems plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used by Nintendo Gamecube and Wii discs +public sealed partial class NintendoPlugin +{ + const string FS_TYPE_NGC = "ngcfs"; + const string FS_TYPE_WII = "wiifs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/Nintendo/Helpers.cs b/Aaru.Filesystems/Nintendo/Helpers.cs new file mode 100644 index 000000000..14b23079c --- /dev/null +++ b/Aaru.Filesystems/Nintendo/Helpers.cs @@ -0,0 +1,140 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Helpers.cs +// Author(s) : Natalia Portillo +// +// Component : Nintendo optical filesystems plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used by Nintendo Gamecube and Wii discs +public sealed partial class NintendoPlugin +{ + static string DiscTypeToString(string discType) => discType switch + { + "C" => Localization.Commodore_64_Virtual_Console, + "D" => Localization.Demo, + "E" => Localization.Neo_Geo_Virtual_Console, + "F" => Localization.NES_Virtual_Console, + "G" => Localization.Gamecube, + "H" => Localization.Wii_channel, + "J" => Localization.Super_Nintendo_Virtual_Console, + "L" => Localization.Master_System_Virtual_Console, + "M" => Localization.Megadrive_Virtual_Console, + "N" => Localization.Nintendo_64_Virtual_Console, + "P" => Localization + .Promotional_or_TurboGrafx_Virtual_Console, + "Q" => Localization.TurboGrafx_CD_Virtual_Console, + "R" => Localization.Wii, + "S" => Localization.Wii, + "U" => Localization.Utility, + "W" => Localization.WiiWare, + "X" => Localization.MSX_Virtual_Console_or_WiiWare_demo, + "0" => Localization.Diagnostic, + "1" => Localization.Diagnostic, + "4" => Localization.Wii_Backup, + "_" => Localization.WiiFit, + _ => string.Format(Localization.unknown_type_0, discType) + }; + + static string RegionCodeToString(string regionCode) => regionCode switch + { + "A" => Localization + .NintendoPlugin_RegionCodeToString_any_region, + "D" => Localization + .NintendoPlugin_RegionCodeToString_Germany, + "N" => Localization + .NintendoPlugin_RegionCodeToString_USA, + "E" => Localization + .NintendoPlugin_RegionCodeToString_USA, + "F" => Localization + .NintendoPlugin_RegionCodeToString_France, + "I" => Localization + .NintendoPlugin_RegionCodeToString_Italy, + "J" => Localization + .NintendoPlugin_RegionCodeToString_Japan, + "K" => Localization + .NintendoPlugin_RegionCodeToString_Korea, + "Q" => Localization + .NintendoPlugin_RegionCodeToString_Korea, + "L" => Localization + .NintendoPlugin_RegionCodeToString_PAL, + "M" => Localization + .NintendoPlugin_RegionCodeToString_PAL, + "P" => Localization + .NintendoPlugin_RegionCodeToString_PAL, + "R" => Localization + .NintendoPlugin_RegionCodeToString_Russia, + "S" => Localization + .NintendoPlugin_RegionCodeToString_Spain, + "T" => Localization + .NintendoPlugin_RegionCodeToString_Taiwan, + "U" => Localization + .NintendoPlugin_RegionCodeToString_Australia, + _ => string.Format(Localization + .NintendoPlugin_RegionCodeToString_unknown_region_code_0, + regionCode) + }; + + [SuppressMessage("ReSharper", "StringLiteralTypo")] + static string PublisherCodeToString(string publisherCode) => publisherCode switch + { + "01" => "Nintendo", + "08" => "CAPCOM", + "41" => "Ubisoft", + "4F" => "Eidos", + "51" => "Acclaim", + "52" => "Activision", + "5D" => "Midway", + "5G" => "Hudson", + "64" => "LucasArts", + "69" => "Electronic Arts", + "6S" => "TDK Mediactive", + "8P" => "SEGA", + "A4" => "Mirage Studios", + "AF" => "Namco", + "B2" => "Bandai", + "DA" => "Tomy", + "EM" => "Konami", + "70" => "Atari", + "4Q" => "Disney Interactive", + "GD" => "Square Enix", + "7D" => "Sierra", + _ => string.Format(Localization + .Unknown_publisher_0, + publisherCode) + }; + + static string PartitionTypeToString(uint type) => type switch + { + 0 => Localization.data, + 1 => Localization.update, + 2 => Localization.channel, + _ => string.Format(Localization.unknown_partition_type_0, + type) + }; +} \ No newline at end of file diff --git a/Aaru.Filesystems/Nintendo/Info.cs b/Aaru.Filesystems/Nintendo/Info.cs new file mode 100644 index 000000000..a9d390897 --- /dev/null +++ b/Aaru.Filesystems/Nintendo/Info.cs @@ -0,0 +1,368 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Nintendo optical filesystems plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used by Nintendo Gamecube and Wii discs +public sealed partial class NintendoPlugin +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start != 0) return false; + + if(imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize < 0x50000) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(0, 0x50000 / imagePlugin.Info.SectorSize, out byte[] header); + + if(errno != ErrorNumber.NoError) return false; + + var magicGc = BigEndianBitConverter.ToUInt32(header, 0x1C); + var magicWii = BigEndianBitConverter.ToUInt32(header, 0x18); + + return magicGc == 0xC2339F3D || magicWii == 0x5D1C9EA3; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("shift_jis"); + var sbInformation = new StringBuilder(); + information = ""; + metadata = new FileSystem(); + + var fields = new NintendoFields(); + + ErrorNumber errno = imagePlugin.ReadSectors(0, 0x50000 / imagePlugin.Info.SectorSize, out byte[] header); + + if(errno != ErrorNumber.NoError) return; + + var wii = false; + + var magicGc = BigEndianBitConverter.ToUInt32(header, 0x1C); + var magicWii = BigEndianBitConverter.ToUInt32(header, 0x18); + + if(magicWii == 0x5D1C9EA3) + wii = true; + else if(magicGc != 0xC2339F3D) return; + + fields.DiscType = Encoding.ASCII.GetString(header, 0, 1); + fields.GameCode = Encoding.ASCII.GetString(header, 1, 2); + fields.RegionCode = Encoding.ASCII.GetString(header, 3, 1); + fields.PublisherCode = Encoding.ASCII.GetString(header, 4, 2); + fields.DiscId = Encoding.ASCII.GetString(header, 0, 6); + fields.DiscNumber = header[6]; + fields.DiscVersion = header[7]; + fields.Streaming |= header[8] > 0; + fields.StreamBufferSize = header[9]; + var temp = new byte[64]; + Array.Copy(header, 0x20, temp, 0, 64); + fields.Title = StringHandlers.CToString(temp, encoding); + + if(!wii) + { + fields.DebugOff = BigEndianBitConverter.ToUInt32(header, 0x0400); + fields.DebugAddr = BigEndianBitConverter.ToUInt32(header, 0x0404); + fields.DolOff = BigEndianBitConverter.ToUInt32(header, 0x0420); + fields.FstOff = BigEndianBitConverter.ToUInt32(header, 0x0424); + fields.FstSize = BigEndianBitConverter.ToUInt32(header, 0x0428); + fields.FstMax = BigEndianBitConverter.ToUInt32(header, 0x042C); + } + + if(wii) + { + uint offset1 = BigEndianBitConverter.ToUInt32(header, 0x40004) << 2; + uint offset2 = BigEndianBitConverter.ToUInt32(header, 0x4000C) << 2; + uint offset3 = BigEndianBitConverter.ToUInt32(header, 0x40014) << 2; + uint offset4 = BigEndianBitConverter.ToUInt32(header, 0x4001C) << 2; + + fields.FirstPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40000)]; + fields.SecondPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40008)]; + fields.ThirdPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40010)]; + fields.FourthPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40018)]; + + for(var i = 0; i < fields.FirstPartitions.Length; i++) + { + if(offset1 + i * 8 + 8 >= 0x50000) continue; + + fields.FirstPartitions[i].Offset = + BigEndianBitConverter.ToUInt32(header, (int)(offset1 + i * 8 + 0)) << 2; + + fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset1 + i * 8 + 4)); + } + + for(var i = 0; i < fields.SecondPartitions.Length; i++) + { + if(offset1 + i * 8 + 8 >= 0x50000) continue; + + fields.FirstPartitions[i].Offset = + BigEndianBitConverter.ToUInt32(header, (int)(offset2 + i * 8 + 0)) << 2; + + fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset2 + i * 8 + 4)); + } + + for(var i = 0; i < fields.ThirdPartitions.Length; i++) + { + if(offset1 + i * 8 + 8 >= 0x50000) continue; + + fields.FirstPartitions[i].Offset = + BigEndianBitConverter.ToUInt32(header, (int)(offset3 + i * 8 + 0)) << 2; + + fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset3 + i * 8 + 4)); + } + + for(var i = 0; i < fields.FourthPartitions.Length; i++) + { + if(offset1 + i * 8 + 8 >= 0x50000) continue; + + fields.FirstPartitions[i].Offset = + BigEndianBitConverter.ToUInt32(header, (int)(offset4 + i * 8 + 0)) << 2; + + fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset4 + i * 8 + 4)); + } + + fields.Region = header[0x4E000]; + fields.JapanAge = header[0x4E010]; + fields.UsaAge = header[0x4E011]; + fields.GermanAge = header[0x4E013]; + fields.PegiAge = header[0x4E014]; + fields.FinlandAge = header[0x4E015]; + fields.PortugalAge = header[0x4E016]; + fields.UkAge = header[0x4E017]; + fields.AustraliaAge = header[0x4E018]; + fields.KoreaAge = header[0x4E019]; + } + else + { + fields.FirstPartitions = []; + fields.SecondPartitions = []; + fields.ThirdPartitions = []; + fields.FourthPartitions = []; + } + + AaruConsole.DebugWriteLine(MODULE_NAME, "discType = {0}", fields.DiscType); + AaruConsole.DebugWriteLine(MODULE_NAME, "gameCode = {0}", fields.GameCode); + AaruConsole.DebugWriteLine(MODULE_NAME, "regionCode = {0}", fields.RegionCode); + AaruConsole.DebugWriteLine(MODULE_NAME, "publisherCode = {0}", fields.PublisherCode); + AaruConsole.DebugWriteLine(MODULE_NAME, "discID = {0}", fields.DiscId); + AaruConsole.DebugWriteLine(MODULE_NAME, "discNumber = {0}", fields.DiscNumber); + AaruConsole.DebugWriteLine(MODULE_NAME, "discVersion = {0}", fields.DiscVersion); + AaruConsole.DebugWriteLine(MODULE_NAME, "streaming = {0}", fields.Streaming); + AaruConsole.DebugWriteLine(MODULE_NAME, "streamBufferSize = {0}", fields.StreamBufferSize); + AaruConsole.DebugWriteLine(MODULE_NAME, "title = \"{0}\"", fields.Title); + AaruConsole.DebugWriteLine(MODULE_NAME, "debugOff = 0x{0:X8}", fields.DebugOff); + AaruConsole.DebugWriteLine(MODULE_NAME, "debugAddr = 0x{0:X8}", fields.DebugAddr); + AaruConsole.DebugWriteLine(MODULE_NAME, "dolOff = 0x{0:X8}", fields.DolOff); + AaruConsole.DebugWriteLine(MODULE_NAME, "fstOff = 0x{0:X8}", fields.FstOff); + AaruConsole.DebugWriteLine(MODULE_NAME, "fstSize = {0}", fields.FstSize); + AaruConsole.DebugWriteLine(MODULE_NAME, "fstMax = {0}", fields.FstMax); + + for(var i = 0; i < fields.FirstPartitions.Length; i++) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "firstPartitions[{1}].offset = {0}", + fields.FirstPartitions[i].Offset, + i); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "firstPartitions[{1}].type = {0}", + fields.FirstPartitions[i].Type, + i); + } + + for(var i = 0; i < fields.SecondPartitions.Length; i++) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "secondPartitions[{1}].offset = {0}", + fields.SecondPartitions[i].Offset, + i); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "secondPartitions[{1}].type = {0}", + fields.SecondPartitions[i].Type, + i); + } + + for(var i = 0; i < fields.ThirdPartitions.Length; i++) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "thirdPartitions[{1}].offset = {0}", + fields.ThirdPartitions[i].Offset, + i); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "thirdPartitions[{1}].type = {0}", + fields.ThirdPartitions[i].Type, + i); + } + + for(var i = 0; i < fields.FourthPartitions.Length; i++) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + "fourthPartitions[{1}].offset = {0}", + fields.FourthPartitions[i].Offset, + i); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "fourthPartitions[{1}].type = {0}", + fields.FourthPartitions[i].Type, + i); + } + + AaruConsole.DebugWriteLine(MODULE_NAME, "region = {0}", fields.Region); + AaruConsole.DebugWriteLine(MODULE_NAME, "japanAge = {0}", fields.JapanAge); + AaruConsole.DebugWriteLine(MODULE_NAME, "usaAge = {0}", fields.UsaAge); + AaruConsole.DebugWriteLine(MODULE_NAME, "germanAge = {0}", fields.GermanAge); + AaruConsole.DebugWriteLine(MODULE_NAME, "pegiAge = {0}", fields.PegiAge); + AaruConsole.DebugWriteLine(MODULE_NAME, "finlandAge = {0}", fields.FinlandAge); + AaruConsole.DebugWriteLine(MODULE_NAME, "portugalAge = {0}", fields.PortugalAge); + AaruConsole.DebugWriteLine(MODULE_NAME, "ukAge = {0}", fields.UkAge); + AaruConsole.DebugWriteLine(MODULE_NAME, "australiaAge = {0}", fields.AustraliaAge); + AaruConsole.DebugWriteLine(MODULE_NAME, "koreaAge = {0}", fields.KoreaAge); + + sbInformation.AppendLine(Localization.Nintendo_optical_filesystem); + + sbInformation.AppendLine(wii + ? Localization.Nintendo_Wii_Optical_Disc + : Localization.Nintendo_GameCube_Optical_Disc); + + sbInformation.AppendFormat(Localization.Disc_ID_is_0, fields.DiscId).AppendLine(); + sbInformation.AppendFormat(Localization.Disc_is_a_0_disc, DiscTypeToString(fields.DiscType)).AppendLine(); + sbInformation.AppendFormat(Localization.Disc_region_is_0, RegionCodeToString(fields.RegionCode)).AppendLine(); + + sbInformation.AppendFormat(Localization.Published_by_0, PublisherCodeToString(fields.PublisherCode)) + .AppendLine(); + + if(fields.DiscNumber > 0) + { + sbInformation.AppendFormat(Localization.Disc_number_0_of_a_multi_disc_set, fields.DiscNumber + 1) + .AppendLine(); + } + + if(fields.Streaming) sbInformation.AppendLine(Localization.Disc_is_prepared_for_audio_streaming); + + if(fields.StreamBufferSize > 0) + { + sbInformation.AppendFormat(Localization.Audio_streaming_buffer_size_is_0_bytes, fields.StreamBufferSize) + .AppendLine(); + } + + sbInformation.AppendFormat(Localization.Title_0, fields.Title).AppendLine(); + + if(wii) + { + for(var i = 0; i < fields.FirstPartitions.Length; i++) + { + sbInformation.AppendFormat(Localization.First_0_partition_starts_at_sector_1, + PartitionTypeToString(fields.FirstPartitions[i].Type), + fields.FirstPartitions[i].Offset / 2048) + .AppendLine(); + } + + for(var i = 0; i < fields.SecondPartitions.Length; i++) + { + sbInformation.AppendFormat(Localization.Second_0_partition_starts_at_sector_1, + PartitionTypeToString(fields.SecondPartitions[i].Type), + fields.SecondPartitions[i].Offset / 2048) + .AppendLine(); + } + + for(var i = 0; i < fields.ThirdPartitions.Length; i++) + { + sbInformation.AppendFormat(Localization.Third_0_partition_starts_at_sector_1, + PartitionTypeToString(fields.ThirdPartitions[i].Type), + fields.ThirdPartitions[i].Offset / 2048) + .AppendLine(); + } + + for(var i = 0; i < fields.FourthPartitions.Length; i++) + { + sbInformation.AppendFormat(Localization.Fourth_0_partition_starts_at_sector_1, + PartitionTypeToString(fields.FourthPartitions[i].Type), + fields.FourthPartitions[i].Offset / 2048) + .AppendLine(); + } + + // sbInformation.AppendFormat("Region byte is {0}", fields.region).AppendLine(); + if((fields.JapanAge & 0x80) != 0x80) + sbInformation.AppendFormat(Localization.Japan_age_rating_is_0, fields.JapanAge).AppendLine(); + + if((fields.UsaAge & 0x80) != 0x80) + sbInformation.AppendFormat(Localization.ESRB_age_rating_is_0, fields.UsaAge).AppendLine(); + + if((fields.GermanAge & 0x80) != 0x80) + sbInformation.AppendFormat(Localization.German_age_rating_is_0, fields.GermanAge).AppendLine(); + + if((fields.PegiAge & 0x80) != 0x80) + sbInformation.AppendFormat(Localization.PEGI_age_rating_is_0, fields.PegiAge).AppendLine(); + + if((fields.FinlandAge & 0x80) != 0x80) + sbInformation.AppendFormat(Localization.Finland_age_rating_is_0, fields.FinlandAge).AppendLine(); + + if((fields.PortugalAge & 0x80) != 0x80) + sbInformation.AppendFormat(Localization.Portugal_age_rating_is_0, fields.PortugalAge).AppendLine(); + + if((fields.UkAge & 0x80) != 0x80) + sbInformation.AppendFormat(Localization.UK_age_rating_is_0, fields.UkAge).AppendLine(); + + if((fields.AustraliaAge & 0x80) != 0x80) + sbInformation.AppendFormat(Localization.Australia_age_rating_is_0, fields.AustraliaAge).AppendLine(); + + if((fields.KoreaAge & 0x80) != 0x80) + sbInformation.AppendFormat(Localization.Korea_age_rating_is_0, fields.KoreaAge).AppendLine(); + } + else + { + sbInformation.AppendFormat(Localization.FST_starts_at_0_and_has_1_bytes, fields.FstOff, fields.FstSize) + .AppendLine(); + } + + information = sbInformation.ToString(); + metadata.Bootable = true; + metadata.Clusters = imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize / 2048; + metadata.ClusterSize = 2048; + metadata.Type = wii ? FS_TYPE_WII : FS_TYPE_NGC; + metadata.VolumeName = fields.Title; + metadata.VolumeSerial = fields.DiscId; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Nintendo/Nintendo.cs b/Aaru.Filesystems/Nintendo/Nintendo.cs new file mode 100644 index 000000000..7fabbaffd --- /dev/null +++ b/Aaru.Filesystems/Nintendo/Nintendo.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Nintendo.cs +// Author(s) : Natalia Portillo +// +// Component : Nintendo optical filesystems plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used by Nintendo Gamecube and Wii discs +public sealed partial class NintendoPlugin : IFilesystem +{ + const string MODULE_NAME = "Nintendo plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.NintendoPlugin_Name; + + /// + public Guid Id => new("4675fcb4-4418-4288-9e4a-33d6a4ac1126"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Nintendo/Structs.cs b/Aaru.Filesystems/Nintendo/Structs.cs new file mode 100644 index 000000000..88a8045a1 --- /dev/null +++ b/Aaru.Filesystems/Nintendo/Structs.cs @@ -0,0 +1,82 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Nintendo optical filesystems plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the filesystem used by Nintendo Gamecube and Wii discs +public sealed partial class NintendoPlugin +{ +#region Nested type: NintendoFields + + struct NintendoFields + { + public string DiscType; + public string GameCode; + public string RegionCode; + public string PublisherCode; + public string DiscId; + public byte DiscNumber; + public byte DiscVersion; + public bool Streaming; + public byte StreamBufferSize; + public string Title; + public uint DebugOff; + public uint DebugAddr; + public uint DolOff; + public uint FstOff; + public uint FstSize; + public uint FstMax; + public NintendoPartition[] FirstPartitions; + public NintendoPartition[] SecondPartitions; + public NintendoPartition[] ThirdPartitions; + public NintendoPartition[] FourthPartitions; + public byte Region; + public byte JapanAge; + public byte UsaAge; + public byte GermanAge; + public byte PegiAge; + public byte FinlandAge; + public byte PortugalAge; + public byte UkAge; + public byte AustraliaAge; + public byte KoreaAge; + } + +#endregion + +#region Nested type: NintendoPartition + + struct NintendoPartition + { + public uint Offset; + public uint Type; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ODS.cs b/Aaru.Filesystems/ODS.cs deleted file mode 100644 index d51399d8d..000000000 --- a/Aaru.Filesystems/ODS.cs +++ /dev/null @@ -1,397 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : ODS.cs -// Author(s) : Natalia Portillo -// -// Component : Files-11 On-Disk Structure plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Files-11 On-Disk Structure and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Information from VMS File System Internals by Kirby McCoy -// ISBN: 1-55558-056-4 -// With some hints from http://www.decuslib.com/DECUS/vmslt97b/gnusoftware/gccaxp/7_1/vms/hm2def.h -// Expects the home block to be always in sector #1 (does not check deltas) -// Assumes a sector size of 512 bytes (VMS does on HDDs and optical drives, dunno about M.O.) -// Book only describes ODS-2. Need to test ODS-1 and ODS-5 -// There is an ODS with signature "DECFILES11A", yet to be seen -// Time is a 64 bit unsigned integer, tenths of microseconds since 1858/11/17 00:00:00. -// TODO: Implement checksum -/// -/// Implements detection of DEC's On-Disk Structure, aka the ODS filesystem -public sealed class ODS : IFilesystem -{ - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Files-11 On-Disk Structure"; - /// - public Guid Id => new("de20633c-8021-4384-aeb0-83b0df14491f"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(2 + partition.Start >= partition.End) - return false; - - if(imagePlugin.Info.SectorSize < 512) - return false; - - var magicB = new byte[12]; - ErrorNumber errno = imagePlugin.ReadSector(1 + partition.Start, out byte[] hbSector); - - if(errno != ErrorNumber.NoError) - return false; - - Array.Copy(hbSector, 0x1F0, magicB, 0, 12); - string magic = Encoding.ASCII.GetString(magicB); - - AaruConsole.DebugWriteLine("Files-11 plugin", "magic: \"{0}\"", magic); - - if(magic is "DECFILE11A " or "DECFILE11B ") - return true; - - // Optical disc - if(imagePlugin.Info.XmlMediaType != XmlMediaType.OpticalDisc) - return false; - - if(hbSector.Length < 0x400) - return false; - - errno = imagePlugin.ReadSector(partition.Start, out hbSector); - - if(errno != ErrorNumber.NoError) - return false; - - Array.Copy(hbSector, 0x3F0, magicB, 0, 12); - magic = Encoding.ASCII.GetString(magicB); - - AaruConsole.DebugWriteLine("Files-11 plugin", "unaligned magic: \"{0}\"", magic); - - return magic is "DECFILE11A " or "DECFILE11B "; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); - information = ""; - - var sb = new StringBuilder(); - - ErrorNumber errno = imagePlugin.ReadSector(1 + partition.Start, out byte[] hbSector); - - if(errno != ErrorNumber.NoError) - return; - - HomeBlock homeblock = Marshal.ByteArrayToStructureLittleEndian(hbSector); - - // Optical disc - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc && - StringHandlers.CToString(homeblock.format) != "DECFILE11A " && - StringHandlers.CToString(homeblock.format) != "DECFILE11B ") - { - if(hbSector.Length < 0x400) - return; - - errno = imagePlugin.ReadSector(partition.Start, out byte[] tmp); - - if(errno != ErrorNumber.NoError) - return; - - hbSector = new byte[0x200]; - Array.Copy(tmp, 0x200, hbSector, 0, 0x200); - - homeblock = Marshal.ByteArrayToStructureLittleEndian(hbSector); - - if(StringHandlers.CToString(homeblock.format) != "DECFILE11A " && - StringHandlers.CToString(homeblock.format) != "DECFILE11B ") - return; - } - - if((homeblock.struclev & 0xFF00) != 0x0200 || - (homeblock.struclev & 0xFF) != 1 || - StringHandlers.CToString(homeblock.format) != "DECFILE11B ") - sb.AppendLine("The following information may be incorrect for this volume."); - - if(homeblock.resfiles < 5 || - homeblock.devtype != 0) - sb.AppendLine("This volume may be corrupted."); - - sb.AppendFormat("Volume format is {0}", StringHandlers.SpacePaddedToString(homeblock.format, Encoding)). - AppendLine(); - - sb.AppendFormat("Volume is Level {0} revision {1}", (homeblock.struclev & 0xFF00) >> 8, - homeblock.struclev & 0xFF).AppendLine(); - - sb.AppendFormat("Lowest structure in the volume is Level {0}, revision {1}", - (homeblock.lowstruclev & 0xFF00) >> 8, homeblock.lowstruclev & 0xFF).AppendLine(); - - sb.AppendFormat("Highest structure in the volume is Level {0}, revision {1}", - (homeblock.highstruclev & 0xFF00) >> 8, homeblock.highstruclev & 0xFF).AppendLine(); - - sb.AppendFormat("{0} sectors per cluster ({1} bytes)", homeblock.cluster, homeblock.cluster * 512).AppendLine(); - - sb.AppendFormat("This home block is on sector {0} (VBN {1})", homeblock.homelbn, homeblock.homevbn). - AppendLine(); - - sb.AppendFormat("Secondary home block is on sector {0} (VBN {1})", homeblock.alhomelbn, homeblock.alhomevbn). - AppendLine(); - - sb.AppendFormat("Volume bitmap starts in sector {0} (VBN {1})", homeblock.ibmaplbn, homeblock.ibmapvbn). - AppendLine(); - - sb.AppendFormat("Volume bitmap runs for {0} sectors ({1} bytes)", homeblock.ibmapsize, - homeblock.ibmapsize * 512).AppendLine(); - - sb.AppendFormat("Backup INDEXF.SYS;1 is in sector {0} (VBN {1})", homeblock.altidxlbn, homeblock.altidxvbn). - AppendLine(); - - sb.AppendFormat("{0} maximum files on the volume", homeblock.maxfiles).AppendLine(); - sb.AppendFormat("{0} reserved files", homeblock.resfiles).AppendLine(); - - if(homeblock.rvn > 0 && - homeblock.setcount > 0 && - StringHandlers.CToString(homeblock.strucname) != " ") - sb.AppendFormat("Volume is {0} of {1} in set \"{2}\".", homeblock.rvn, homeblock.setcount, - StringHandlers.SpacePaddedToString(homeblock.strucname, Encoding)).AppendLine(); - - sb.AppendFormat("Volume owner is \"{0}\" (ID 0x{1:X8})", - StringHandlers.SpacePaddedToString(homeblock.ownername, Encoding), homeblock.volowner). - AppendLine(); - - sb.AppendFormat("Volume label: \"{0}\"", StringHandlers.SpacePaddedToString(homeblock.volname, Encoding)). - AppendLine(); - - sb.AppendFormat("Drive serial number: 0x{0:X8}", homeblock.serialnum).AppendLine(); - sb.AppendFormat("Volume was created on {0}", DateHandlers.VmsToDateTime(homeblock.credate)).AppendLine(); - - if(homeblock.revdate > 0) - sb.AppendFormat("Volume was last modified on {0}", DateHandlers.VmsToDateTime(homeblock.revdate)). - AppendLine(); - - if(homeblock.copydate > 0) - sb.AppendFormat("Volume copied on {0}", DateHandlers.VmsToDateTime(homeblock.copydate)).AppendLine(); - - sb.AppendFormat("Checksums: 0x{0:X4} and 0x{1:X4}", homeblock.checksum1, homeblock.checksum2).AppendLine(); - sb.AppendLine("Flags:"); - sb.AppendFormat("Window: {0}", homeblock.window).AppendLine(); - sb.AppendFormat("Cached directores: {0}", homeblock.lru_lim).AppendLine(); - sb.AppendFormat("Default allocation: {0} blocks", homeblock.extend).AppendLine(); - - if((homeblock.volchar & 0x01) == 0x01) - sb.AppendLine("Readings should be verified"); - - if((homeblock.volchar & 0x02) == 0x02) - sb.AppendLine("Writings should be verified"); - - if((homeblock.volchar & 0x04) == 0x04) - sb.AppendLine("Files should be erased or overwritten when deleted"); - - if((homeblock.volchar & 0x08) == 0x08) - sb.AppendLine("Highwater mark is to be disabled"); - - if((homeblock.volchar & 0x10) == 0x10) - sb.AppendLine("Classification checks are enabled"); - - sb.AppendLine("Volume permissions (r = read, w = write, c = create, d = delete)"); - sb.AppendLine("System, owner, group, world"); - - // System - sb.Append((homeblock.protect & 0x1000) == 0x1000 ? "-" : "r"); - sb.Append((homeblock.protect & 0x2000) == 0x2000 ? "-" : "w"); - sb.Append((homeblock.protect & 0x4000) == 0x4000 ? "-" : "c"); - sb.Append((homeblock.protect & 0x8000) == 0x8000 ? "-" : "d"); - - // Owner - sb.Append((homeblock.protect & 0x100) == 0x100 ? "-" : "r"); - sb.Append((homeblock.protect & 0x200) == 0x200 ? "-" : "w"); - sb.Append((homeblock.protect & 0x400) == 0x400 ? "-" : "c"); - sb.Append((homeblock.protect & 0x800) == 0x800 ? "-" : "d"); - - // Group - sb.Append((homeblock.protect & 0x10) == 0x10 ? "-" : "r"); - sb.Append((homeblock.protect & 0x20) == 0x20 ? "-" : "w"); - sb.Append((homeblock.protect & 0x40) == 0x40 ? "-" : "c"); - sb.Append((homeblock.protect & 0x80) == 0x80 ? "-" : "d"); - - // World (other) - sb.Append((homeblock.protect & 0x1) == 0x1 ? "-" : "r"); - sb.Append((homeblock.protect & 0x2) == 0x2 ? "-" : "w"); - sb.Append((homeblock.protect & 0x4) == 0x4 ? "-" : "c"); - sb.Append((homeblock.protect & 0x8) == 0x8 ? "-" : "d"); - - sb.AppendLine(); - - sb.AppendLine("Unknown structures:"); - sb.AppendFormat("Security mask: 0x{0:X8}", homeblock.sec_mask).AppendLine(); - sb.AppendFormat("File protection: 0x{0:X4}", homeblock.fileprot).AppendLine(); - sb.AppendFormat("Record protection: 0x{0:X4}", homeblock.recprot).AppendLine(); - - XmlFsType = new FileSystemType - { - Type = "FILES-11", - ClusterSize = (uint)(homeblock.cluster * 512), - Clusters = partition.Size / (ulong)(homeblock.cluster * 512), - VolumeName = StringHandlers.SpacePaddedToString(homeblock.volname, Encoding), - VolumeSerial = $"{homeblock.serialnum:X8}" - }; - - if(homeblock.credate > 0) - { - XmlFsType.CreationDate = DateHandlers.VmsToDateTime(homeblock.credate); - XmlFsType.CreationDateSpecified = true; - } - - if(homeblock.revdate > 0) - { - XmlFsType.ModificationDate = DateHandlers.VmsToDateTime(homeblock.revdate); - XmlFsType.ModificationDateSpecified = true; - } - - information = sb.ToString(); - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct HomeBlock - { - /// 0x000, LBN of THIS home block - public readonly uint homelbn; - /// 0x004, LBN of the secondary home block - public readonly uint alhomelbn; - /// 0x008, LBN of backup INDEXF.SYS;1 - public readonly uint altidxlbn; - /// 0x00C, High byte contains filesystem version (1, 2 or 5), low byte contains revision (1) - public readonly ushort struclev; - /// 0x00E, Number of blocks each bit of the volume bitmap represents - public readonly ushort cluster; - /// 0x010, VBN of THIS home block - public readonly ushort homevbn; - /// 0x012, VBN of the secondary home block - public readonly ushort alhomevbn; - /// 0x014, VBN of backup INDEXF.SYS;1 - public readonly ushort altidxvbn; - /// 0x016, VBN of the bitmap - public readonly ushort ibmapvbn; - /// 0x018, LBN of the bitmap - public readonly uint ibmaplbn; - /// 0x01C, Max files on volume - public readonly uint maxfiles; - /// 0x020, Bitmap size in sectors - public readonly ushort ibmapsize; - /// 0x022, Reserved files, 5 at minimum - public readonly ushort resfiles; - /// 0x024, Device type, ODS-2 defines it as always 0 - public readonly ushort devtype; - /// 0x026, Relative volume number (number of the volume in a set) - public readonly ushort rvn; - /// 0x028, Total number of volumes in the set this volume is - public readonly ushort setcount; - /// 0x02A, Flags - public readonly ushort volchar; - /// 0x02C, User ID of the volume owner - public readonly uint volowner; - /// 0x030, Security mask (??) - public readonly uint sec_mask; - /// 0x034, Volume permissions (system, owner, group and other) - public readonly ushort protect; - /// 0x036, Default file protection, unsupported in ODS-2 - public readonly ushort fileprot; - /// 0x038, Default file record protection - public readonly ushort recprot; - /// 0x03A, Checksum of all preceding entries - public readonly ushort checksum1; - /// 0x03C, Creation date - public readonly ulong credate; - /// 0x044, Window size (pointers for the window) - public readonly byte window; - /// 0x045, Directories to be stored in cache - public readonly byte lru_lim; - /// 0x046, Default allocation size in blocks - public readonly ushort extend; - /// 0x048, Minimum file retention period - public readonly ulong retainmin; - /// 0x050, Maximum file retention period - public readonly ulong retainmax; - /// 0x058, Last modification date - public readonly ulong revdate; - /// 0x060, Minimum security class, 20 bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public readonly byte[] min_class; - /// 0x074, Maximum security class, 20 bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public readonly byte[] max_class; - /// 0x088, File lookup table FID - public readonly ushort filetab_fid1; - /// 0x08A, File lookup table FID - public readonly ushort filetab_fid2; - /// 0x08C, File lookup table FID - public readonly ushort filetab_fid3; - /// 0x08E, Lowest structure level on the volume - public readonly ushort lowstruclev; - /// 0x090, Highest structure level on the volume - public readonly ushort highstruclev; - /// 0x092, Volume copy date (??) - public readonly ulong copydate; - /// 0x09A, 302 bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 302)] - public readonly byte[] reserved1; - /// 0x1C8, Physical drive serial number - public readonly uint serialnum; - /// 0x1CC, Name of the volume set, 12 bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] strucname; - /// 0x1D8, Volume label, 12 bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] volname; - /// 0x1E4, Name of the volume owner, 12 bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] ownername; - /// 0x1F0, ODS-2 defines it as "DECFILE11B", 12 bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] format; - /// 0x1FC, Reserved - public readonly ushort reserved2; - /// 0x1FE, Checksum of preceding 255 words (16 bit units) - public readonly ushort checksum2; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/ODS/Consts.cs b/Aaru.Filesystems/ODS/Consts.cs new file mode 100644 index 000000000..56ee0c052 --- /dev/null +++ b/Aaru.Filesystems/ODS/Consts.cs @@ -0,0 +1,49 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Files-11 On-Disk Structure plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Files-11 On-Disk Structure and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Information from VMS File System Internals by Kirby McCoy +// ISBN: 1-55558-056-4 +// With some hints from http://www.decuslib.com/DECUS/vmslt97b/gnusoftware/gccaxp/7_1/vms/hm2def.h +// Expects the home block to be always in sector #1 (does not check deltas) +// Assumes a sector size of 512 bytes (VMS does on HDDs and optical drives, dunno about M.O.) +// Book only describes ODS-2. Need to test ODS-1 and ODS-5 +// There is an ODS with signature "DECFILES11A", yet to be seen +// Time is a 64 bit unsigned integer, tenths of microseconds since 1858/11/17 00:00:00. +// TODO: Implement checksum +/// +/// Implements detection of DEC's On-Disk Structure, aka the ODS filesystem +public sealed partial class ODS +{ + const string FS_TYPE = "files11"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/ODS/Info.cs b/Aaru.Filesystems/ODS/Info.cs new file mode 100644 index 000000000..a5209b850 --- /dev/null +++ b/Aaru.Filesystems/ODS/Info.cs @@ -0,0 +1,284 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Files-11 On-Disk Structure plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Files-11 On-Disk Structure and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from VMS File System Internals by Kirby McCoy +// ISBN: 1-55558-056-4 +// With some hints from http://www.decuslib.com/DECUS/vmslt97b/gnusoftware/gccaxp/7_1/vms/hm2def.h +// Expects the home block to be always in sector #1 (does not check deltas) +// Assumes a sector size of 512 bytes (VMS does on HDDs and optical drives, dunno about M.O.) +// Book only describes ODS-2. Need to test ODS-1 and ODS-5 +// There is an ODS with signature "DECFILES11A", yet to be seen +// Time is a 64 bit unsigned integer, tenths of microseconds since 1858/11/17 00:00:00. +// TODO: Implement checksum +/// +/// Implements detection of DEC's On-Disk Structure, aka the ODS filesystem +public sealed partial class ODS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(2 + partition.Start >= partition.End) return false; + + if(imagePlugin.Info.SectorSize < 512) return false; + + var magicB = new byte[12]; + ErrorNumber errno = imagePlugin.ReadSector(1 + partition.Start, out byte[] hbSector); + + if(errno != ErrorNumber.NoError) return false; + + Array.Copy(hbSector, 0x1F0, magicB, 0, 12); + string magic = Encoding.ASCII.GetString(magicB); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.magic_0, magic); + + if(magic is "DECFILE11A " or "DECFILE11B ") return true; + + // Optical disc + if(imagePlugin.Info.MetadataMediaType != MetadataMediaType.OpticalDisc) return false; + + if(hbSector.Length < 0x400) return false; + + errno = imagePlugin.ReadSector(partition.Start, out hbSector); + + if(errno != ErrorNumber.NoError) return false; + + Array.Copy(hbSector, 0x3F0, magicB, 0, 12); + magic = Encoding.ASCII.GetString(magicB); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.unaligned_magic_0, magic); + + return magic is "DECFILE11A " or "DECFILE11B "; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-1"); + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + ErrorNumber errno = imagePlugin.ReadSector(1 + partition.Start, out byte[] hbSector); + + if(errno != ErrorNumber.NoError) return; + + HomeBlock homeblock = Marshal.ByteArrayToStructureLittleEndian(hbSector); + + // Optical disc + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc && + StringHandlers.CToString(homeblock.format) != "DECFILE11A " && + StringHandlers.CToString(homeblock.format) != "DECFILE11B ") + { + if(hbSector.Length < 0x400) return; + + errno = imagePlugin.ReadSector(partition.Start, out byte[] tmp); + + if(errno != ErrorNumber.NoError) return; + + hbSector = new byte[0x200]; + Array.Copy(tmp, 0x200, hbSector, 0, 0x200); + + homeblock = Marshal.ByteArrayToStructureLittleEndian(hbSector); + + if(StringHandlers.CToString(homeblock.format) != "DECFILE11A " && + StringHandlers.CToString(homeblock.format) != "DECFILE11B ") + return; + } + + if((homeblock.struclev & 0xFF00) != 0x0200 || + (homeblock.struclev & 0xFF) != 1 || + StringHandlers.CToString(homeblock.format) != "DECFILE11B ") + sb.AppendLine(Localization.The_following_information_may_be_incorrect_for_this_volume); + + if(homeblock.resfiles < 5 || homeblock.devtype != 0) sb.AppendLine(Localization.This_volume_may_be_corrupted); + + sb.AppendFormat(Localization.Volume_format_is_0, StringHandlers.SpacePaddedToString(homeblock.format, encoding)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_is_Level_0_revision_1, + (homeblock.struclev & 0xFF00) >> 8, + homeblock.struclev & 0xFF) + .AppendLine(); + + sb.AppendFormat(Localization.Lowest_structure_in_the_volume_is_Level_0_revision_1, + (homeblock.lowstruclev & 0xFF00) >> 8, + homeblock.lowstruclev & 0xFF) + .AppendLine(); + + sb.AppendFormat(Localization.Highest_structure_in_the_volume_is_Level_0_revision_1, + (homeblock.highstruclev & 0xFF00) >> 8, + homeblock.highstruclev & 0xFF) + .AppendLine(); + + sb.AppendFormat(Localization._0_sectors_per_cluster_1_bytes, homeblock.cluster, homeblock.cluster * 512) + .AppendLine(); + + sb.AppendFormat(Localization.This_home_block_is_on_sector_0_VBN_1, homeblock.homelbn, homeblock.homevbn) + .AppendLine(); + + sb.AppendFormat(Localization.Secondary_home_block_is_on_sector_0_VBN_1, + homeblock.alhomelbn, + homeblock.alhomevbn) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_bitmap_starts_in_sector_0_VBN_1, homeblock.ibmaplbn, homeblock.ibmapvbn) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_bitmap_runs_for_0_sectors_1_bytes, + homeblock.ibmapsize, + homeblock.ibmapsize * 512) + .AppendLine(); + + sb.AppendFormat(Localization.Backup_INDEXF_SYS_is_in_sector_0_VBN_1, homeblock.altidxlbn, homeblock.altidxvbn) + .AppendLine(); + + sb.AppendFormat(Localization._0_maximum_files_on_the_volume, homeblock.maxfiles).AppendLine(); + sb.AppendFormat(Localization._0_reserved_files, homeblock.resfiles).AppendLine(); + + if(homeblock is { rvn: > 0, setcount: > 0 } && StringHandlers.CToString(homeblock.strucname) != " ") + { + sb.AppendFormat(Localization.Volume_is_0_of_1_in_set_2, + homeblock.rvn, + homeblock.setcount, + StringHandlers.SpacePaddedToString(homeblock.strucname, encoding)) + .AppendLine(); + } + + sb.AppendFormat(Localization.Volume_owner_is_0_ID_1, + StringHandlers.SpacePaddedToString(homeblock.ownername, encoding), + homeblock.volowner) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_label_0, StringHandlers.SpacePaddedToString(homeblock.volname, encoding)) + .AppendLine(); + + sb.AppendFormat(Localization.Drive_serial_number_0, homeblock.serialnum).AppendLine(); + + sb.AppendFormat(Localization.Volume_was_created_on_0, DateHandlers.VmsToDateTime(homeblock.credate)) + .AppendLine(); + + if(homeblock.revdate > 0) + { + sb.AppendFormat(Localization.Volume_was_last_modified_on_0, DateHandlers.VmsToDateTime(homeblock.revdate)) + .AppendLine(); + } + + if(homeblock.copydate > 0) + { + sb.AppendFormat(Localization.Volume_copied_on_0, DateHandlers.VmsToDateTime(homeblock.copydate)) + .AppendLine(); + } + + sb.AppendFormat(Localization.Checksums_0_and_1, homeblock.checksum1, homeblock.checksum2).AppendLine(); + sb.AppendLine(Localization.Flags); + sb.AppendFormat(Localization.Window_0, homeblock.window).AppendLine(); + sb.AppendFormat(Localization.Cached_directories_0, homeblock.lru_lim).AppendLine(); + sb.AppendFormat(Localization.Default_allocation_0_blocks, homeblock.extend).AppendLine(); + + if((homeblock.volchar & 0x01) == 0x01) sb.AppendLine(Localization.Readings_should_be_verified); + + if((homeblock.volchar & 0x02) == 0x02) sb.AppendLine(Localization.Writings_should_be_verified); + + if((homeblock.volchar & 0x04) == 0x04) + sb.AppendLine(Localization.Files_should_be_erased_or_overwritten_when_deleted); + + if((homeblock.volchar & 0x08) == 0x08) sb.AppendLine(Localization.Highwater_mark_is_to_be_disabled); + + if((homeblock.volchar & 0x10) == 0x10) sb.AppendLine(Localization.Classification_checks_are_enabled); + + sb.AppendLine(Localization.Volume_permissions_r_read_w_write_c_create_d_delete); + sb.AppendLine(Localization.System_owner_group_world); + + // System + sb.Append((homeblock.protect & 0x1000) == 0x1000 ? "-" : "r"); + sb.Append((homeblock.protect & 0x2000) == 0x2000 ? "-" : "w"); + sb.Append((homeblock.protect & 0x4000) == 0x4000 ? "-" : "c"); + sb.Append((homeblock.protect & 0x8000) == 0x8000 ? "-" : "d"); + + // Owner + sb.Append((homeblock.protect & 0x100) == 0x100 ? "-" : "r"); + sb.Append((homeblock.protect & 0x200) == 0x200 ? "-" : "w"); + sb.Append((homeblock.protect & 0x400) == 0x400 ? "-" : "c"); + sb.Append((homeblock.protect & 0x800) == 0x800 ? "-" : "d"); + + // Group + sb.Append((homeblock.protect & 0x10) == 0x10 ? "-" : "r"); + sb.Append((homeblock.protect & 0x20) == 0x20 ? "-" : "w"); + sb.Append((homeblock.protect & 0x40) == 0x40 ? "-" : "c"); + sb.Append((homeblock.protect & 0x80) == 0x80 ? "-" : "d"); + + // World (other) + sb.Append((homeblock.protect & 0x1) == 0x1 ? "-" : "r"); + sb.Append((homeblock.protect & 0x2) == 0x2 ? "-" : "w"); + sb.Append((homeblock.protect & 0x4) == 0x4 ? "-" : "c"); + sb.Append((homeblock.protect & 0x8) == 0x8 ? "-" : "d"); + + sb.AppendLine(); + + sb.AppendLine(Localization.Unknown_structures); + sb.AppendFormat(Localization.Security_mask_0, homeblock.sec_mask).AppendLine(); + sb.AppendFormat(Localization.File_protection_0, homeblock.fileprot).AppendLine(); + sb.AppendFormat(Localization.Record_protection_0, homeblock.recprot).AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = (uint)(homeblock.cluster * 512), + Clusters = partition.Size / (ulong)(homeblock.cluster * 512), + VolumeName = StringHandlers.SpacePaddedToString(homeblock.volname, encoding), + VolumeSerial = $"{homeblock.serialnum:X8}" + }; + + if(homeblock.credate > 0) metadata.CreationDate = DateHandlers.VmsToDateTime(homeblock.credate); + + if(homeblock.revdate > 0) metadata.ModificationDate = DateHandlers.VmsToDateTime(homeblock.revdate); + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ODS/ODS.cs b/Aaru.Filesystems/ODS/ODS.cs new file mode 100644 index 000000000..aee619aa6 --- /dev/null +++ b/Aaru.Filesystems/ODS/ODS.cs @@ -0,0 +1,65 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ODS.cs +// Author(s) : Natalia Portillo +// +// Component : Files-11 On-Disk Structure plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Files-11 On-Disk Structure and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from VMS File System Internals by Kirby McCoy +// ISBN: 1-55558-056-4 +// With some hints from http://www.decuslib.com/DECUS/vmslt97b/gnusoftware/gccaxp/7_1/vms/hm2def.h +// Expects the home block to be always in sector #1 (does not check deltas) +// Assumes a sector size of 512 bytes (VMS does on HDDs and optical drives, dunno about M.O.) +// Book only describes ODS-2. Need to test ODS-1 and ODS-5 +// There is an ODS with signature "DECFILES11A", yet to be seen +// Time is a 64 bit unsigned integer, tenths of microseconds since 1858/11/17 00:00:00. +// TODO: Implement checksum +/// +/// Implements detection of DEC's On-Disk Structure, aka the ODS filesystem +public sealed partial class ODS : IFilesystem +{ + const string MODULE_NAME = "Files-11 plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.ODS_Name; + + /// + public Guid Id => new("de20633c-8021-4384-aeb0-83b0df14491f"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ODS/Structs.cs b/Aaru.Filesystems/ODS/Structs.cs new file mode 100644 index 000000000..02eba2396 --- /dev/null +++ b/Aaru.Filesystems/ODS/Structs.cs @@ -0,0 +1,157 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Files-11 On-Disk Structure plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Files-11 On-Disk Structure and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Information from VMS File System Internals by Kirby McCoy +// ISBN: 1-55558-056-4 +// With some hints from http://www.decuslib.com/DECUS/vmslt97b/gnusoftware/gccaxp/7_1/vms/hm2def.h +// Expects the home block to be always in sector #1 (does not check deltas) +// Assumes a sector size of 512 bytes (VMS does on HDDs and optical drives, dunno about M.O.) +// Book only describes ODS-2. Need to test ODS-1 and ODS-5 +// There is an ODS with signature "DECFILES11A", yet to be seen +// Time is a 64 bit unsigned integer, tenths of microseconds since 1858/11/17 00:00:00. +// TODO: Implement checksum +/// +/// Implements detection of DEC's On-Disk Structure, aka the ODS filesystem +public sealed partial class ODS +{ +#region Nested type: HomeBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct HomeBlock + { + /// 0x000, LBN of THIS home block + public readonly uint homelbn; + /// 0x004, LBN of the secondary home block + public readonly uint alhomelbn; + /// 0x008, LBN of backup INDEXF.SYS;1 + public readonly uint altidxlbn; + /// 0x00C, High byte contains filesystem version (1, 2 or 5), low byte contains revision (1) + public readonly ushort struclev; + /// 0x00E, Number of blocks each bit of the volume bitmap represents + public readonly ushort cluster; + /// 0x010, VBN of THIS home block + public readonly ushort homevbn; + /// 0x012, VBN of the secondary home block + public readonly ushort alhomevbn; + /// 0x014, VBN of backup INDEXF.SYS;1 + public readonly ushort altidxvbn; + /// 0x016, VBN of the bitmap + public readonly ushort ibmapvbn; + /// 0x018, LBN of the bitmap + public readonly uint ibmaplbn; + /// 0x01C, Max files on volume + public readonly uint maxfiles; + /// 0x020, Bitmap size in sectors + public readonly ushort ibmapsize; + /// 0x022, Reserved files, 5 at minimum + public readonly ushort resfiles; + /// 0x024, Device type, ODS-2 defines it as always 0 + public readonly ushort devtype; + /// 0x026, Relative volume number (number of the volume in a set) + public readonly ushort rvn; + /// 0x028, Total number of volumes in the set this volume is + public readonly ushort setcount; + /// 0x02A, Flags + public readonly ushort volchar; + /// 0x02C, User ID of the volume owner + public readonly uint volowner; + /// 0x030, Security mask (??) + public readonly uint sec_mask; + /// 0x034, Volume permissions (system, owner, group and other) + public readonly ushort protect; + /// 0x036, Default file protection, unsupported in ODS-2 + public readonly ushort fileprot; + /// 0x038, Default file record protection + public readonly ushort recprot; + /// 0x03A, Checksum of all preceding entries + public readonly ushort checksum1; + /// 0x03C, Creation date + public readonly ulong credate; + /// 0x044, Window size (pointers for the window) + public readonly byte window; + /// 0x045, Directories to be stored in cache + public readonly byte lru_lim; + /// 0x046, Default allocation size in blocks + public readonly ushort extend; + /// 0x048, Minimum file retention period + public readonly ulong retainmin; + /// 0x050, Maximum file retention period + public readonly ulong retainmax; + /// 0x058, Last modification date + public readonly ulong revdate; + /// 0x060, Minimum security class, 20 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public readonly byte[] min_class; + /// 0x074, Maximum security class, 20 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public readonly byte[] max_class; + /// 0x088, File lookup table FID + public readonly ushort filetab_fid1; + /// 0x08A, File lookup table FID + public readonly ushort filetab_fid2; + /// 0x08C, File lookup table FID + public readonly ushort filetab_fid3; + /// 0x08E, Lowest structure level on the volume + public readonly ushort lowstruclev; + /// 0x090, Highest structure level on the volume + public readonly ushort highstruclev; + /// 0x092, Volume copy date (??) + public readonly ulong copydate; + /// 0x09A, 302 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 302)] + public readonly byte[] reserved1; + /// 0x1C8, Physical drive serial number + public readonly uint serialnum; + /// 0x1CC, Name of the volume set, 12 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] strucname; + /// 0x1D8, Volume label, 12 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] volname; + /// 0x1E4, Name of the volume owner, 12 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] ownername; + /// 0x1F0, ODS-2 defines it as "DECFILE11B", 12 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] format; + /// 0x1FC, Reserved + public readonly ushort reserved2; + /// 0x1FE, Checksum of preceding 255 words (16 bit units) + public readonly ushort checksum2; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Opera/Consts.cs b/Aaru.Filesystems/Opera/Consts.cs index 4a849598b..a045afe99 100644 --- a/Aaru.Filesystems/Opera/Consts.cs +++ b/Aaru.Filesystems/Opera/Consts.cs @@ -7,10 +7,6 @@ // // Component : Opera filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Opera filesystem constants. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,14 +23,14 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Diagnostics.CodeAnalysis; using Aaru.Helpers; +namespace Aaru.Filesystems; + [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed partial class OperaFS { @@ -48,7 +44,11 @@ public sealed partial class OperaFS const uint TYPE_LBL = 0x2A6C626C; /// Catapult const uint TYPE_ZAP = 0x2A7A6170; - static readonly int _directoryEntrySize = Marshal.SizeOf(); + + const string FS_TYPE = "opera"; + static readonly int _directoryEntrySize = Marshal.SizeOf(); + +#region Nested type: FileFlags enum FileFlags : uint { @@ -58,4 +58,6 @@ public sealed partial class OperaFS LastEntryInBlock = 0x40000000, LastEntry = 0x80000000 } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/Opera/Dir.cs b/Aaru.Filesystems/Opera/Dir.cs index 4582f8860..6e9e920aa 100644 --- a/Aaru.Filesystems/Opera/Dir.cs +++ b/Aaru.Filesystems/Opera/Dir.cs @@ -7,10 +7,6 @@ // // Component : Opera filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle Opera filesystem directories. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,60 +23,70 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; +namespace Aaru.Filesystems; + public sealed partial class OperaFS { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber ReadDir(string path, out List contents) + public ErrorNumber OpenDir(string path, out IDirNode node) { - contents = null; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - if(string.IsNullOrWhiteSpace(path) || - path == "/") + if(string.IsNullOrWhiteSpace(path) || path == "/") { - contents = _rootDirectoryCache.Keys.ToList(); + node = new OperaDirNode + { + Path = path, + Contents = _rootDirectoryCache.Keys.ToArray(), + Position = 0 + }; return ErrorNumber.NoError; } string cutPath = path.StartsWith("/", StringComparison.Ordinal) - ? path.Substring(1).ToLower(CultureInfo.CurrentUICulture) + ? path[1..].ToLower(CultureInfo.CurrentUICulture) : path.ToLower(CultureInfo.CurrentUICulture); if(_directoryCache.TryGetValue(cutPath, out Dictionary currentDirectory)) { - contents = currentDirectory.Keys.ToList(); + node = new OperaDirNode + { + Path = path, + Contents = currentDirectory.Keys.ToArray(), + Position = 0 + }; return ErrorNumber.NoError; } string[] pieces = cutPath.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); KeyValuePair entry = - _rootDirectoryCache.FirstOrDefault(t => t.Key.ToLower(CultureInfo.CurrentUICulture) == pieces[0]); + _rootDirectoryCache.FirstOrDefault(t => t.Key.Equals(pieces[0], StringComparison.CurrentCultureIgnoreCase)); - if(string.IsNullOrEmpty(entry.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(entry.Key)) return ErrorNumber.NoSuchFile; - if((entry.Value.Entry.flags & FLAGS_MASK) != (int)FileFlags.Directory) - return ErrorNumber.NotDirectory; + if((entry.Value.Entry.flags & FLAGS_MASK) != (int)FileFlags.Directory) return ErrorNumber.NotDirectory; string currentPath = pieces[0]; @@ -88,32 +94,67 @@ public sealed partial class OperaFS for(var p = 0; p < pieces.Length; p++) { - entry = currentDirectory.FirstOrDefault(t => t.Key.ToLower(CultureInfo.CurrentUICulture) == pieces[p]); + entry = currentDirectory.FirstOrDefault(t => t.Key.Equals(pieces[p], + StringComparison.CurrentCultureIgnoreCase)); - if(string.IsNullOrEmpty(entry.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(entry.Key)) return ErrorNumber.NoSuchFile; - if((entry.Value.Entry.flags & FLAGS_MASK) != (int)FileFlags.Directory) - return ErrorNumber.NotDirectory; + if((entry.Value.Entry.flags & FLAGS_MASK) != (int)FileFlags.Directory) return ErrorNumber.NotDirectory; currentPath = p == 0 ? pieces[0] : $"{currentPath}/{pieces[p]}"; - if(_directoryCache.TryGetValue(currentPath, out currentDirectory)) - continue; + if(_directoryCache.TryGetValue(currentPath, out currentDirectory)) continue; - if(entry.Value.Pointers.Length < 1) - return ErrorNumber.InvalidArgument; + if(entry.Value.Pointers.Length < 1) return ErrorNumber.InvalidArgument; currentDirectory = DecodeDirectory((int)entry.Value.Pointers[0]); _directoryCache.Add(currentPath, currentDirectory); } - contents = currentDirectory?.Keys.ToList(); + if(currentDirectory is null) return ErrorNumber.NoSuchFile; + + node = new OperaDirNode + { + Path = path, + Contents = currentDirectory.Keys.ToArray(), + Position = 0 + }; return ErrorNumber.NoError; } + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) + { + filename = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not OperaDirNode mynode) return ErrorNumber.InvalidArgument; + + if(mynode.Position < 0) return ErrorNumber.InvalidArgument; + + if(mynode.Position >= mynode.Contents.Length) return ErrorNumber.NoError; + + filename = mynode.Contents[mynode.Position++]; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not OperaDirNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Position = -1; + mynode.Contents = null; + + return ErrorNumber.NoError; + } + +#endregion + Dictionary DecodeDirectory(int firstBlock) { Dictionary entries = new(); @@ -124,11 +165,11 @@ public sealed partial class OperaFS do { - ErrorNumber errno = _image.ReadSectors((ulong)(nextBlock * _volumeBlockSizeRatio), _volumeBlockSizeRatio, + ErrorNumber errno = _image.ReadSectors((ulong)(nextBlock * _volumeBlockSizeRatio), + _volumeBlockSizeRatio, out byte[] data); - if(errno != ErrorNumber.NoError) - break; + if(errno != ErrorNumber.NoError) break; header = Marshal.ByteArrayToStructureBigEndian(data); nextBlock = header.next_block + firstBlock; @@ -140,7 +181,7 @@ public sealed partial class OperaFS while(off + _directoryEntrySize < data.Length) { entry = Marshal.ByteArrayToStructureBigEndian(data, off, _directoryEntrySize); - string name = StringHandlers.CToString(entry.name, Encoding); + string name = StringHandlers.CToString(entry.name, _encoding); var entryWithPointers = new DirectoryEntryWithPointers { @@ -149,8 +190,10 @@ public sealed partial class OperaFS }; for(var i = 0; i <= entry.last_copy; i++) + { entryWithPointers.Pointers[i] = BigEndianBitConverter.ToUInt32(data, off + _directoryEntrySize + i * 4); + } entries.Add(name, entryWithPointers); @@ -161,8 +204,7 @@ public sealed partial class OperaFS off += (int)(_directoryEntrySize + (entry.last_copy + 1) * 4); } - if((entry.flags & (uint)FileFlags.LastEntry) != 0) - break; + if((entry.flags & (uint)FileFlags.LastEntry) != 0) break; } while(header.next_block != -1); return entries; diff --git a/Aaru.Filesystems/Opera/File.cs b/Aaru.Filesystems/Opera/File.cs index 2f993624c..93a94283a 100644 --- a/Aaru.Filesystems/Opera/File.cs +++ b/Aaru.Filesystems/Opera/File.cs @@ -7,10 +7,6 @@ // // Component : Opera filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle files. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,54 +23,33 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; +namespace Aaru.Filesystems; + public sealed partial class OperaFS { - /// - public ErrorNumber MapBlock(string path, long fileBlock, out long deviceBlock) - { - deviceBlock = 0; - - if(!_mounted) - return ErrorNumber.AccessDenied; - - ErrorNumber err = GetFileEntry(path, out DirectoryEntryWithPointers entry); - - if(err != ErrorNumber.NoError) - return err; - - if((entry.Entry.flags & FLAGS_MASK) == (uint)FileFlags.Directory && - !_debug) - return ErrorNumber.IsDirectory; - - deviceBlock = entry.Pointers[0] + fileBlock; - - return ErrorNumber.NoError; - } +#region IReadOnlyFilesystem Members /// public ErrorNumber GetAttributes(string path, out FileAttributes attributes) { attributes = new FileAttributes(); - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = Stat(path, out FileEntryInfo stat); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; attributes = stat.Attributes; @@ -82,60 +57,81 @@ public sealed partial class OperaFS } /// - public ErrorNumber Read(string path, long offset, long size, ref byte[] buf) + public ErrorNumber OpenFile(string path, out IFileNode node) { - buf = null; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = GetFileEntry(path, out DirectoryEntryWithPointers entry); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; - if((entry.Entry.flags & FLAGS_MASK) == (uint)FileFlags.Directory && - !_debug) - return ErrorNumber.IsDirectory; + if((entry.Entry.flags & FLAGS_MASK) == (uint)FileFlags.Directory && !_debug) return ErrorNumber.IsDirectory; - if(entry.Pointers.Length < 1) - return ErrorNumber.InvalidArgument; + if(entry.Pointers.Length < 1) return ErrorNumber.InvalidArgument; - if(entry.Entry.byte_count == 0) + node = new OperaFileNode { - buf = Array.Empty(); + Path = path, + Length = entry.Entry.byte_count, + Offset = 0, + Dentry = entry + }; - return ErrorNumber.NoError; - } + return ErrorNumber.NoError; + } - if(offset >= entry.Entry.byte_count) - return ErrorNumber.InvalidArgument; + /// + public ErrorNumber CloseFile(IFileNode node) + { + if(!_mounted) return ErrorNumber.AccessDenied; - if(size + offset >= entry.Entry.byte_count) - size = entry.Entry.byte_count - offset; + return node is not OperaFileNode ? ErrorNumber.InvalidArgument : ErrorNumber.NoError; + } - long firstBlock = offset / entry.Entry.block_size; - long offsetInBlock = offset % entry.Entry.block_size; - long sizeInBlocks = (size + offsetInBlock) / entry.Entry.block_size; + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; - if((size + offsetInBlock) % entry.Entry.block_size > 0) - sizeInBlocks++; + if(!_mounted) return ErrorNumber.AccessDenied; + + if(buffer is null || buffer.Length < length) return ErrorNumber.InvalidArgument; + + if(node is not OperaFileNode mynode) return ErrorNumber.InvalidArgument; + + read = length; + + if(length + mynode.Offset >= mynode.Length) read = mynode.Length - mynode.Offset; + + long firstBlock = mynode.Offset / mynode.Dentry.Entry.block_size; + long offsetInBlock = mynode.Offset % mynode.Dentry.Entry.block_size; + long sizeInBlocks = (read + offsetInBlock) / mynode.Dentry.Entry.block_size; + + if((read + offsetInBlock) % mynode.Dentry.Entry.block_size > 0) sizeInBlocks++; uint fileBlockSizeRatio; if(_image.Info.SectorSize is 2336 or 2352 or 2448) - fileBlockSizeRatio = entry.Entry.block_size / 2048; + fileBlockSizeRatio = mynode.Dentry.Entry.block_size / 2048; else - fileBlockSizeRatio = entry.Entry.block_size / _image.Info.SectorSize; + fileBlockSizeRatio = mynode.Dentry.Entry.block_size / _image.Info.SectorSize; - ErrorNumber errno = _image.ReadSectors((ulong)(entry.Pointers[0] + firstBlock * fileBlockSizeRatio), - (uint)(sizeInBlocks * fileBlockSizeRatio), out byte[] buffer); + ErrorNumber errno = _image.ReadSectors((ulong)(mynode.Dentry.Pointers[0] + firstBlock * fileBlockSizeRatio), + (uint)(sizeInBlocks * fileBlockSizeRatio), + out byte[] buf); if(errno != ErrorNumber.NoError) - return errno; + { + read = 0; - buf = new byte[size]; - Array.Copy(buffer, offsetInBlock, buf, 0, size); + return errno; + } + + Array.Copy(buf, offsetInBlock, buffer, 0, read); + + mynode.Offset += read; return ErrorNumber.NoError; } @@ -145,13 +141,11 @@ public sealed partial class OperaFS { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; ErrorNumber err = GetFileEntry(path, out DirectoryEntryWithPointers entryWithPointers); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; DirectoryEntry entry = entryWithPointers.Entry; @@ -167,53 +161,60 @@ public sealed partial class OperaFS var flags = (FileFlags)(entry.flags & FLAGS_MASK); - if(flags == FileFlags.Directory) - stat.Attributes |= FileAttributes.Directory; + switch(flags) + { + case FileFlags.Directory: + stat.Attributes |= FileAttributes.Directory; - if(flags == FileFlags.Special) - stat.Attributes |= FileAttributes.Device; + break; + case FileFlags.Special: + stat.Attributes |= FileAttributes.Device; + + break; + } return ErrorNumber.NoError; } +#endregion + ErrorNumber GetFileEntry(string path, out DirectoryEntryWithPointers entry) { entry = null; string cutPath = path.StartsWith("/", StringComparison.Ordinal) - ? path.Substring(1).ToLower(CultureInfo.CurrentUICulture) + ? path[1..].ToLower(CultureInfo.CurrentUICulture) : path.ToLower(CultureInfo.CurrentUICulture); string[] pieces = cutPath.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pieces.Length == 0) - return ErrorNumber.InvalidArgument; + if(pieces.Length == 0) return ErrorNumber.InvalidArgument; var parentPath = string.Join("/", pieces, 0, pieces.Length - 1); if(!_directoryCache.TryGetValue(parentPath, out _)) { - ErrorNumber err = ReadDir(parentPath, out _); + ErrorNumber err = OpenDir(parentPath, out IDirNode node); - if(err != ErrorNumber.NoError) - return err; + if(err != ErrorNumber.NoError) return err; + + CloseDir(node); } Dictionary parent; if(pieces.Length == 1) parent = _rootDirectoryCache; - else if(!_directoryCache.TryGetValue(parentPath, out parent)) - return ErrorNumber.InvalidArgument; + else if(!_directoryCache.TryGetValue(parentPath, out parent)) return ErrorNumber.InvalidArgument; KeyValuePair dirent = - parent.FirstOrDefault(t => t.Key.ToLower(CultureInfo.CurrentUICulture) == pieces[^1]); + parent.FirstOrDefault(t => t.Key.Equals(pieces[^1], StringComparison.CurrentCultureIgnoreCase)); - if(string.IsNullOrEmpty(dirent.Key)) - return ErrorNumber.NoSuchFile; + if(string.IsNullOrEmpty(dirent.Key)) return ErrorNumber.NoSuchFile; entry = dirent.Value; diff --git a/Aaru.Filesystems/Opera/Info.cs b/Aaru.Filesystems/Opera/Info.cs index 01bcc7575..7c47bc154 100644 --- a/Aaru.Filesystems/Opera/Info.cs +++ b/Aaru.Filesystems/Opera/Info.cs @@ -7,10 +7,6 @@ // // Component : Opera filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Opera filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,31 +23,31 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; -using Schemas; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class OperaFS { +#region IReadOnlyFilesystem Members + /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(2 + partition.Start >= partition.End) - return false; + if(2 + partition.Start >= partition.End) return false; ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] sbSector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; var syncBytes = new byte[5]; @@ -59,85 +55,100 @@ public sealed partial class OperaFS Array.Copy(sbSector, 0x001, syncBytes, 0, 5); byte recordVersion = sbSector[0x006]; - if(recordType != 1 || - recordVersion != 1) - return false; + if(recordType != 1 || recordVersion != 1) return false; return Encoding.ASCII.GetString(syncBytes) == SYNC; } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { // TODO: Find correct default encoding - Encoding = Encoding.ASCII; + encoding = Encoding.ASCII; information = ""; - var superBlockMetadata = new StringBuilder(); + metadata = new FileSystem(); + var superBlockmetadata = new StringBuilder(); ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] sbSector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; SuperBlock sb = Marshal.ByteArrayToStructureBigEndian(sbSector); - if(sb.record_type != 1 || - sb.record_version != 1) - return; + if(sb.record_type != 1 || sb.record_version != 1) return; - if(Encoding.ASCII.GetString(sb.sync_bytes) != SYNC) - return; + if(Encoding.ASCII.GetString(sb.sync_bytes) != SYNC) return; - superBlockMetadata.AppendFormat("Opera filesystem disc.").AppendLine(); + superBlockmetadata.AppendFormat(Localization.Opera_filesystem_disc).AppendLine(); - if(!string.IsNullOrEmpty(StringHandlers.CToString(sb.volume_label, Encoding))) - superBlockMetadata.AppendFormat("Volume label: {0}", StringHandlers.CToString(sb.volume_label, Encoding)). - AppendLine(); + if(!string.IsNullOrEmpty(StringHandlers.CToString(sb.volume_label, encoding))) + { + superBlockmetadata + .AppendFormat(Localization.Volume_label_0, StringHandlers.CToString(sb.volume_label, encoding)) + .AppendLine(); + } - if(!string.IsNullOrEmpty(StringHandlers.CToString(sb.volume_comment, Encoding))) - superBlockMetadata. - AppendFormat("Volume comment: {0}", StringHandlers.CToString(sb.volume_comment, Encoding)).AppendLine(); + if(!string.IsNullOrEmpty(StringHandlers.CToString(sb.volume_comment, encoding))) + { + superBlockmetadata + .AppendFormat(Localization.Volume_comment_0, StringHandlers.CToString(sb.volume_comment, encoding)) + .AppendLine(); + } - superBlockMetadata.AppendFormat("Volume identifier: 0x{0:X8}", sb.volume_id).AppendLine(); - superBlockMetadata.AppendFormat("Block size: {0} bytes", sb.block_size).AppendLine(); + superBlockmetadata.AppendFormat(Localization.Volume_identifier_0_X8, sb.volume_id).AppendLine(); + superBlockmetadata.AppendFormat(Localization.Block_size_0_bytes, sb.block_size).AppendLine(); if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448) { if(sb.block_size != 2048) - superBlockMetadata. - AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/block", - sb.block_size, 2048); + { + superBlockmetadata.AppendFormat(Localization + .WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block, + sb.block_size, + 2048); + } } else if(imagePlugin.Info.SectorSize != sb.block_size) - superBlockMetadata. - AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/block", - sb.block_size, imagePlugin.Info.SectorSize); + { + superBlockmetadata.AppendFormat(Localization + .WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block, + sb.block_size, + imagePlugin.Info.SectorSize); + } - superBlockMetadata. - AppendFormat("Volume size: {0} blocks, {1} bytes", sb.block_count, sb.block_size * sb.block_count). - AppendLine(); + superBlockmetadata + .AppendFormat(Localization.Volume_size_0_blocks_1_bytes, sb.block_count, sb.block_size * sb.block_count) + .AppendLine(); if(sb.block_count > imagePlugin.Info.Sectors) - superBlockMetadata. - AppendFormat("WARNING: Filesystem indicates {0} blocks while device indicates {1} blocks", - sb.block_count, imagePlugin.Info.Sectors); - - superBlockMetadata.AppendFormat("Root directory identifier: 0x{0:X8}", sb.root_dirid).AppendLine(); - superBlockMetadata.AppendFormat("Root directory block size: {0} bytes", sb.rootdir_bsize).AppendLine(); - - superBlockMetadata.AppendFormat("Root directory size: {0} blocks, {1} bytes", sb.rootdir_blocks, - sb.rootdir_bsize * sb.rootdir_blocks).AppendLine(); - - superBlockMetadata.AppendFormat("Last root directory copy: {0}", sb.last_root_copy).AppendLine(); - - information = superBlockMetadata.ToString(); - - XmlFsType = new FileSystemType { - Type = "Opera", - VolumeName = StringHandlers.CToString(sb.volume_label, Encoding), + superBlockmetadata.AppendFormat(Localization + .WARNING__Filesystem_indicates_0_blocks_while_device_indicates_1_blocks, + sb.block_count, + imagePlugin.Info.Sectors); + } + + superBlockmetadata.AppendFormat(Localization.Root_directory_identifier_0, sb.root_dirid).AppendLine(); + superBlockmetadata.AppendFormat(Localization.Root_directory_block_size_0_bytes, sb.rootdir_bsize).AppendLine(); + + superBlockmetadata.AppendFormat(Localization.Root_directory_size_0_blocks_1_bytes, + sb.rootdir_blocks, + sb.rootdir_bsize * sb.rootdir_blocks) + .AppendLine(); + + superBlockmetadata.AppendFormat(Localization.Last_root_directory_copy_0, sb.last_root_copy).AppendLine(); + + information = superBlockmetadata.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + VolumeName = StringHandlers.CToString(sb.volume_label, encoding), ClusterSize = sb.block_size, Clusters = sb.block_count }; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/Opera/Opera.cs b/Aaru.Filesystems/Opera/Opera.cs index c51ddfb7f..3c228f0bd 100644 --- a/Aaru.Filesystems/Opera/Opera.cs +++ b/Aaru.Filesystems/Opera/Opera.cs @@ -7,10 +7,6 @@ // // Component : Opera filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Opera filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,18 +23,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Text; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; -using Schemas; + +namespace Aaru.Filesystems; /// /// Implements the 3DO Opera filesystem @@ -46,22 +42,26 @@ public sealed partial class OperaFS : IReadOnlyFilesystem { bool _debug; Dictionary> _directoryCache; + Encoding _encoding; IMediaImage _image; bool _mounted; Dictionary _rootDirectoryCache; FileSystemInfo _statfs; uint _volumeBlockSizeRatio; +#region IReadOnlyFilesystem Members + /// - public FileSystemType XmlFsType { get; private set; } + public FileSystem Metadata { get; private set; } + /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Opera Filesystem Plugin"; + public string Name => Localization.OperaFS_Name; + /// public Guid Id => new("0ec84ec7-eae6-4196-83fe-943b3fe46dbd"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public ErrorNumber ListXAttr(string path, out List xattrs) @@ -89,6 +89,8 @@ public sealed partial class OperaFS : IReadOnlyFilesystem /// public Dictionary Namespaces => null; +#endregion + static Dictionary GetDefaultOptions() => new() { { diff --git a/Aaru.Filesystems/Opera/Structs.cs b/Aaru.Filesystems/Opera/Structs.cs index a77fa6f2a..694895a31 100644 --- a/Aaru.Filesystems/Opera/Structs.cs +++ b/Aaru.Filesystems/Opera/Structs.cs @@ -7,10 +7,6 @@ // // Component : Opera filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Opera filesystem structures. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,15 +23,116 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System.Runtime.InteropServices; +using Aaru.CommonTypes.Interfaces; + namespace Aaru.Filesystems; -using System.Runtime.InteropServices; - public sealed partial class OperaFS { +#region Nested type: DirectoryEntry + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DirectoryEntry + { + /// File flags, see + public readonly uint flags; + /// Unique file identifier + public readonly uint id; + /// Entry type + public readonly uint type; + /// Block size + public readonly uint block_size; + /// Size in bytes + public readonly uint byte_count; + /// Block count + public readonly uint block_count; + /// Unknown + public readonly uint burst; + /// Unknown + public readonly uint gap; + /// Filename + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_NAME)] + public readonly byte[] name; + /// Last copy + public readonly uint last_copy; + } + +#endregion + +#region Nested type: DirectoryEntryWithPointers + + sealed class DirectoryEntryWithPointers + { + public DirectoryEntry Entry; + public uint[] Pointers; + } + +#endregion + +#region Nested type: DirectoryHeader + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DirectoryHeader + { + /// Next block from this directory, -1 if last + public readonly int next_block; + /// Previous block from this directory, -1 if first + public readonly int prev_block; + /// Directory flags + public readonly uint flags; + /// Offset to first free unused byte in the directory + public readonly uint first_free; + /// Offset to first directory entry + public readonly uint first_used; + } + +#endregion + +#region Nested type: OperaDirNode + + sealed class OperaDirNode : IDirNode + { + internal string[] Contents; + internal int Position; + +#region IDirNode Members + + /// + public string Path { get; init; } + +#endregion + } + +#endregion + +#region Nested type: OperaFileNode + + sealed class OperaFileNode : IFileNode + { + internal DirectoryEntryWithPointers Dentry; + +#region IFileNode Members + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + +#endregion + } + +#endregion + +#region Nested type: SuperBlock + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct SuperBlock { @@ -70,50 +167,5 @@ public sealed partial class OperaFS public readonly uint last_root_copy; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DirectoryHeader - { - /// Next block from this directory, -1 if last - public readonly int next_block; - /// Previous block from this directory, -1 if first - public readonly int prev_block; - /// Directory flags - public readonly uint flags; - /// Offset to first free unused byte in the directory - public readonly uint first_free; - /// Offset to first directory entry - public readonly uint first_used; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DirectoryEntry - { - /// File flags, see - public readonly uint flags; - /// Unique file identifier - public readonly uint id; - /// Entry type - public readonly uint type; - /// Block size - public readonly uint block_size; - /// Size in bytes - public readonly uint byte_count; - /// Block count - public readonly uint block_count; - /// Unknown - public readonly uint burst; - /// Unknown - public readonly uint gap; - /// Filename - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_NAME)] - public readonly byte[] name; - /// Last copy - public readonly uint last_copy; - } - - class DirectoryEntryWithPointers - { - public DirectoryEntry Entry; - public uint[] Pointers; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/Opera/Super.cs b/Aaru.Filesystems/Opera/Super.cs index 84a9f57d0..a6ef9ff7a 100644 --- a/Aaru.Filesystems/Opera/Super.cs +++ b/Aaru.Filesystems/Opera/Super.cs @@ -7,10 +7,6 @@ // // Component : Opera filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Handles mounting and umounting the Opera filesystem. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,57 +23,54 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System.Collections.Generic; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Helpers; -using Schemas; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; public sealed partial class OperaFS { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, - Dictionary options, string @namespace) + public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace) { // TODO: Find correct default encoding - Encoding = Encoding.ASCII; + _encoding = Encoding.ASCII; options ??= GetDefaultOptions(); - if(options.TryGetValue("debug", out string debugString)) - bool.TryParse(debugString, out _debug); + if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out _debug); ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] sbSector); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; SuperBlock sb = Marshal.ByteArrayToStructureBigEndian(sbSector); - if(sb.record_type != 1 || - sb.record_version != 1) - return ErrorNumber.InvalidArgument; + if(sb.record_type != 1 || sb.record_version != 1) return ErrorNumber.InvalidArgument; - if(Encoding.ASCII.GetString(sb.sync_bytes) != SYNC) - return ErrorNumber.InvalidArgument; + if(Encoding.ASCII.GetString(sb.sync_bytes) != SYNC) return ErrorNumber.InvalidArgument; if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448) _volumeBlockSizeRatio = sb.block_size / 2048; else _volumeBlockSizeRatio = sb.block_size / imagePlugin.Info.SectorSize; - XmlFsType = new FileSystemType + Metadata = new FileSystem { - Type = "Opera", - VolumeName = StringHandlers.CToString(sb.volume_label, Encoding), + Type = FS_TYPE, + VolumeName = StringHandlers.CToString(sb.volume_label, _encoding), ClusterSize = sb.block_size, Clusters = sb.block_count, Bootable = true, @@ -95,7 +88,7 @@ public sealed partial class OperaFS Serial32 = sb.volume_id }, PluginId = Id, - Type = "Opera" + Type = FS_TYPE }; _image = imagePlugin; @@ -110,8 +103,7 @@ public sealed partial class OperaFS /// public ErrorNumber Unmount() { - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; _mounted = false; @@ -123,11 +115,12 @@ public sealed partial class OperaFS { stat = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; stat = _statfs.ShallowCopy(); return ErrorNumber.NoError; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/PCEngine/Consts.cs b/Aaru.Filesystems/PCEngine/Consts.cs new file mode 100644 index 000000000..5d4237105 --- /dev/null +++ b/Aaru.Filesystems/PCEngine/Consts.cs @@ -0,0 +1,40 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : NEC PC-Engine CD filesystem plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the NEC PC-Engine CD filesystem and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the PC-Engine CD file headers +public sealed partial class PCEnginePlugin +{ + const string FS_TYPE = "pcengine"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/PCEngine.cs b/Aaru.Filesystems/PCEngine/Info.cs similarity index 72% rename from Aaru.Filesystems/PCEngine.cs rename to Aaru.Filesystems/PCEngine/Info.cs index 5be8de704..cbfade225 100644 --- a/Aaru.Filesystems/PCEngine.cs +++ b/Aaru.Filesystems/PCEngine/Info.cs @@ -2,7 +2,7 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : PCEngine.cs +// Filename : Info.cs // Author(s) : Natalia Portillo // // Component : NEC PC-Engine CD filesystem plugin. @@ -27,44 +27,33 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; -using Schemas; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; /// /// Implements detection of the PC-Engine CD file headers -public sealed class PCEnginePlugin : IFilesystem +public sealed partial class PCEnginePlugin { - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "PC Engine CD Plugin"; - /// - public Guid Id => new("e5ee6d7c-90fa-49bd-ac89-14ef750b8af3"); - /// - public string Author => "Natalia Portillo"; +#region IFilesystem Members /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(2 + partition.Start >= partition.End) - return false; + if(2 + partition.Start >= partition.End) return false; var systemDescriptor = new byte[23]; ErrorNumber errno = imagePlugin.ReadSector(1 + partition.Start, out byte[] sector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; Array.Copy(sector, 0x20, systemDescriptor, 0, 23); @@ -72,16 +61,18 @@ public sealed class PCEnginePlugin : IFilesystem } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = encoding ?? Encoding.GetEncoding("shift_jis"); information = ""; - XmlFsType = new FileSystemType + metadata = new FileSystem { - Type = "PC Engine filesystem", + Type = FS_TYPE, Clusters = (partition.End - partition.Start + 1) / imagePlugin.Info.SectorSize * 2048, ClusterSize = 2048 }; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/PCEngine/PCEngine.cs b/Aaru.Filesystems/PCEngine/PCEngine.cs new file mode 100644 index 000000000..ac15499da --- /dev/null +++ b/Aaru.Filesystems/PCEngine/PCEngine.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PCEngine.cs +// Author(s) : Natalia Portillo +// +// Component : NEC PC-Engine CD filesystem plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the NEC PC-Engine CD filesystem and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the PC-Engine CD file headers +public sealed partial class PCEnginePlugin : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.PCEnginePlugin_Name; + + /// + public Guid Id => new("e5ee6d7c-90fa-49bd-ac89-14ef750b8af3"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/PCFX.cs b/Aaru.Filesystems/PCFX.cs deleted file mode 100644 index 0e3873d70..000000000 --- a/Aaru.Filesystems/PCFX.cs +++ /dev/null @@ -1,169 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : PCEngine.cs -// Author(s) : Natalia Portillo -// -// Component : NEC PC-FX plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the NEC PC-FX track header and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Not a filesystem, more like an executable header -/// -/// Implements detection of NEC PC-FX headers -public sealed class PCFX : IFilesystem -{ - const string IDENTIFIER = "PC-FX:Hu_CD-ROM "; - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "PC-FX Plugin"; - /// - public Guid Id => new("8BC27CCE-D9E9-48F8-BA93-C66A86EB565A"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(2 + partition.Start >= partition.End || - imagePlugin.Info.XmlMediaType != XmlMediaType.OpticalDisc) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, 2, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - var encoding = Encoding.GetEncoding("shift_jis"); - - return encoding.GetString(sector, 0, 16) == IDENTIFIER; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - // Always Shift-JIS - Encoding = Encoding.GetEncoding("shift_jis"); - information = ""; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, 2, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - Header header = Marshal.ByteArrayToStructureLittleEndian
(sector); - - string date; - DateTime dateTime = DateTime.MinValue; - - try - { - date = Encoding.GetString(header.date); - var year = int.Parse(date.Substring(0, 4)); - var month = int.Parse(date.Substring(4, 2)); - var day = int.Parse(date.Substring(6, 2)); - dateTime = new DateTime(year, month, day); - } - catch - { - date = null; - } - - var sb = new StringBuilder(); - sb.AppendLine("PC-FX executable:"); - sb.AppendFormat("Identifier: {0}", StringHandlers.CToString(header.signature, Encoding)).AppendLine(); - sb.AppendFormat("Copyright: {0}", StringHandlers.CToString(header.copyright, Encoding)).AppendLine(); - sb.AppendFormat("Title: {0}", StringHandlers.CToString(header.title, Encoding)).AppendLine(); - sb.AppendFormat("Maker ID: {0}", StringHandlers.CToString(header.makerId, Encoding)).AppendLine(); - sb.AppendFormat("Maker name: {0}", StringHandlers.CToString(header.makerName, Encoding)).AppendLine(); - sb.AppendFormat("Volume number: {0}", header.volumeNumber).AppendLine(); - sb.AppendFormat("Country code: {0}", header.country).AppendLine(); - sb.AppendFormat("Version: {0}.{1}", header.minorVersion, header.majorVersion).AppendLine(); - - if(date != null) - sb.AppendFormat("Dated {0}", dateTime).AppendLine(); - - sb.AppendFormat("Load {0} sectors from sector {1}", header.loadCount, header.loadOffset).AppendLine(); - - sb.AppendFormat("Load at 0x{0:X8} and jump to 0x{1:X8}", header.loadAddress, header.entryPoint).AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Type = "PC-FX", - Clusters = partition.Length, - ClusterSize = 2048, - Bootable = true, - CreationDate = dateTime, - CreationDateSpecified = date != null, - PublisherIdentifier = StringHandlers.CToString(header.makerName, Encoding), - VolumeName = StringHandlers.CToString(header.title, Encoding), - SystemIdentifier = "PC-FX" - }; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Header - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] signature; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xE0)] - public readonly byte[] copyright; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x710)] - public readonly byte[] unknown; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] title; - public readonly uint loadOffset; - public readonly uint loadCount; - public readonly uint loadAddress; - public readonly uint entryPoint; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] makerId; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 60)] - public readonly byte[] makerName; - public readonly uint volumeNumber; - public readonly byte majorVersion; - public readonly byte minorVersion; - public readonly ushort country; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] date; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/PCFX/Consts.cs b/Aaru.Filesystems/PCFX/Consts.cs new file mode 100644 index 000000000..1dfa55e51 --- /dev/null +++ b/Aaru.Filesystems/PCFX/Consts.cs @@ -0,0 +1,43 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : NEC PC-FX plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the NEC PC-FX track header and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Not a filesystem, more like an executable header +/// +/// Implements detection of NEC PC-FX headers +public sealed partial class PCFX +{ + const string IDENTIFIER = "PC-FX:Hu_CD-ROM "; + + const string FS_TYPE = "pcfx"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/PCFX/Info.cs b/Aaru.Filesystems/PCFX/Info.cs new file mode 100644 index 000000000..1682f1ab3 --- /dev/null +++ b/Aaru.Filesystems/PCFX/Info.cs @@ -0,0 +1,129 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : NEC PC-FX plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the NEC PC-FX track header and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Not a filesystem, more like an executable header +/// +/// Implements detection of NEC PC-FX headers +public sealed partial class PCFX +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(2 + partition.Start >= partition.End || imagePlugin.Info.MetadataMediaType != MetadataMediaType.OpticalDisc) + return false; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, 2, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + var encoding = Encoding.GetEncoding("shift_jis"); + + return encoding.GetString(sector, 0, 16) == IDENTIFIER; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + // Always Shift-JIS + encoding = Encoding.GetEncoding("shift_jis"); + information = ""; + metadata = new FileSystem(); + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, 2, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + Header header = Marshal.ByteArrayToStructureLittleEndian
(sector); + + string date; + DateTime dateTime = DateTime.MinValue; + + try + { + date = encoding.GetString(header.date); + var year = int.Parse(date[..4]); + var month = int.Parse(date.Substring(4, 2)); + var day = int.Parse(date.Substring(6, 2)); + dateTime = new DateTime(year, month, day); + } + catch + { + date = null; + } + + var sb = new StringBuilder(); + sb.AppendLine(Localization.PC_FX_executable); + sb.AppendFormat(Localization.Identifier_0, StringHandlers.CToString(header.signature, encoding)).AppendLine(); + sb.AppendFormat(Localization.Copyright_0, StringHandlers.CToString(header.copyright, encoding)).AppendLine(); + sb.AppendFormat(Localization.Title_0, StringHandlers.CToString(header.title, encoding)).AppendLine(); + sb.AppendFormat(Localization.Maker_ID_0, StringHandlers.CToString(header.makerId, encoding)).AppendLine(); + sb.AppendFormat(Localization.Maker_name_0, StringHandlers.CToString(header.makerName, encoding)).AppendLine(); + sb.AppendFormat(Localization.Volume_number_0, header.volumeNumber).AppendLine(); + sb.AppendFormat(Localization.Country_code_0, header.country).AppendLine(); + sb.AppendFormat(Localization.Version_0_1, header.minorVersion, header.majorVersion).AppendLine(); + + if(date != null) sb.AppendFormat(Localization.Dated_0, dateTime).AppendLine(); + + sb.AppendFormat(Localization.Load_0_sectors_from_sector_1, header.loadCount, header.loadOffset).AppendLine(); + + sb.AppendFormat(Localization.Load_at_0_and_jump_to_1, header.loadAddress, header.entryPoint).AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + Clusters = partition.Length, + ClusterSize = 2048, + Bootable = true, + CreationDate = date != null ? dateTime : null, + PublisherIdentifier = StringHandlers.CToString(header.makerName, encoding), + VolumeName = StringHandlers.CToString(header.title, encoding), + SystemIdentifier = "PC-FX" + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/PCFX/PCFX.cs b/Aaru.Filesystems/PCFX/PCFX.cs new file mode 100644 index 000000000..125819bd7 --- /dev/null +++ b/Aaru.Filesystems/PCFX/PCFX.cs @@ -0,0 +1,55 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PCEngine.cs +// Author(s) : Natalia Portillo +// +// Component : NEC PC-FX plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the NEC PC-FX track header and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Not a filesystem, more like an executable header +/// +/// Implements detection of NEC PC-FX headers +public sealed partial class PCFX : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.PCFX_Name; + + /// + public Guid Id => new("8BC27CCE-D9E9-48F8-BA93-C66A86EB565A"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/PCFX/Structs.cs b/Aaru.Filesystems/PCFX/Structs.cs new file mode 100644 index 000000000..f1a141572 --- /dev/null +++ b/Aaru.Filesystems/PCFX/Structs.cs @@ -0,0 +1,72 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : NEC PC-FX plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the NEC PC-FX track header and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Not a filesystem, more like an executable header +/// +/// Implements detection of NEC PC-FX headers +public sealed partial class PCFX +{ +#region Nested type: Header + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Header + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] signature; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xE0)] + public readonly byte[] copyright; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x710)] + public readonly byte[] unknown; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] title; + public readonly uint loadOffset; + public readonly uint loadCount; + public readonly uint loadAddress; + public readonly uint entryPoint; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] makerId; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 60)] + public readonly byte[] makerName; + public readonly uint volumeNumber; + public readonly byte majorVersion; + public readonly byte minorVersion; + public readonly ushort country; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] date; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/PFS.cs b/Aaru.Filesystems/PFS.cs deleted file mode 100644 index e4b654cc3..000000000 --- a/Aaru.Filesystems/PFS.cs +++ /dev/null @@ -1,211 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : PFS.cs -// Author(s) : Natalia Portillo -// -// Component : Professional File System plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Professional File System and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -// ReSharper disable UnusedType.Local - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the Professional File System -public sealed class PFS : IFilesystem -{ - /// Identifier for AFS (PFS v1) - const uint AFS_DISK = 0x41465301; - /// Identifier for PFS v2 - const uint PFS2_DISK = 0x50465302; - /// Identifier for PFS v3 - const uint PFS_DISK = 0x50465301; - /// Identifier for multi-user AFS - const uint MUAF_DISK = 0x6D754146; - /// Identifier for multi-user PFS - const uint MUPFS_DISK = 0x6D755046; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Professional File System"; - /// - public Guid Id => new("68DE769E-D957-406A-8AE4-3781CA8CDA77"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Length < 3) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(2 + partition.Start, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - var magic = BigEndianBitConverter.ToUInt32(sector, 0x00); - - return magic is AFS_DISK or PFS2_DISK or PFS_DISK or MUAF_DISK or MUPFS_DISK; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - information = ""; - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); - ErrorNumber errno = imagePlugin.ReadSector(2 + partition.Start, out byte[] rootBlockSector); - - if(errno != ErrorNumber.NoError) - return; - - RootBlock rootBlock = Marshal.ByteArrayToStructureBigEndian(rootBlockSector); - - var sbInformation = new StringBuilder(); - XmlFsType = new FileSystemType(); - - switch(rootBlock.diskType) - { - case AFS_DISK: - case MUAF_DISK: - sbInformation.Append("Professional File System v1"); - XmlFsType.Type = "PFS v1"; - - break; - case PFS2_DISK: - sbInformation.Append("Professional File System v2"); - XmlFsType.Type = "PFS v2"; - - break; - case PFS_DISK: - case MUPFS_DISK: - sbInformation.Append("Professional File System v3"); - XmlFsType.Type = "PFS v3"; - - break; - } - - if(rootBlock.diskType is MUAF_DISK or MUPFS_DISK) - sbInformation.Append(", with multi-user support"); - - sbInformation.AppendLine(); - - sbInformation.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(rootBlock.diskname, Encoding)). - AppendLine(); - - sbInformation.AppendFormat("Volume has {0} free sectors of {1}", rootBlock.blocksfree, rootBlock.diskSize). - AppendLine(); - - sbInformation.AppendFormat("Volume created on {0}", - DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute, - rootBlock.creationtick)).AppendLine(); - - if(rootBlock.extension > 0) - sbInformation.AppendFormat("Root block extension resides at block {0}", rootBlock.extension).AppendLine(); - - information = sbInformation.ToString(); - - XmlFsType.CreationDate = - DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute, rootBlock.creationtick); - - XmlFsType.CreationDateSpecified = true; - XmlFsType.FreeClusters = rootBlock.blocksfree; - XmlFsType.FreeClustersSpecified = true; - XmlFsType.Clusters = rootBlock.diskSize; - XmlFsType.ClusterSize = imagePlugin.Info.SectorSize; - XmlFsType.VolumeName = StringHandlers.PascalToString(rootBlock.diskname, Encoding); - } - - /// Boot block, first 2 sectors - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct BootBlock - { - /// "PFS\1" disk type - public readonly uint diskType; - /// Boot code, til completion - public readonly byte[] bootCode; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct RootBlock - { - /// Disk type - public readonly uint diskType; - /// Options - public readonly uint options; - /// Current datestamp - public readonly uint datestamp; - /// Volume creation day - public readonly ushort creationday; - /// Volume creation minute - public readonly ushort creationminute; - /// Volume creation tick - public readonly ushort creationtick; - /// AmigaDOS protection bits - public readonly ushort protection; - /// Volume label (Pascal string) - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] diskname; - /// Last reserved block - public readonly uint lastreserved; - /// First reserved block - public readonly uint firstreserved; - /// Free reserved blocks - public readonly uint reservedfree; - /// Size of reserved blocks in bytes - public readonly ushort reservedblocksize; - /// Blocks in rootblock, including bitmap - public readonly ushort rootblockclusters; - /// Free blocks - public readonly uint blocksfree; - /// Blocks that must be always free - public readonly uint alwaysfree; - /// Current bitmapfield number for allocation - public readonly uint rovingPointer; - /// Pointer to deldir - public readonly uint delDirPtr; - /// Disk size in sectors - public readonly uint diskSize; - /// Rootblock extension - public readonly uint extension; - /// Unused - public readonly uint unused; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/PFS/Consts.cs b/Aaru.Filesystems/PFS/Consts.cs new file mode 100644 index 000000000..bbd936bb8 --- /dev/null +++ b/Aaru.Filesystems/PFS/Consts.cs @@ -0,0 +1,49 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Professional File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedType.Local + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Professional File System +public sealed partial class PFS +{ + /// Identifier for AFS (PFS v1) + const uint AFS_DISK = 0x41465301; + /// Identifier for PFS v2 + const uint PFS2_DISK = 0x50465302; + /// Identifier for PFS v3 + const uint PFS_DISK = 0x50465301; + /// Identifier for multi-user AFS + const uint MUAF_DISK = 0x6D754146; + /// Identifier for multi-user PFS + const uint MUPFS_DISK = 0x6D755046; + + const string FS_TYPE = "pfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/PFS/Info.cs b/Aaru.Filesystems/PFS/Info.cs new file mode 100644 index 000000000..01df33c1e --- /dev/null +++ b/Aaru.Filesystems/PFS/Info.cs @@ -0,0 +1,133 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Professional File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedType.Local + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Professional File System +public sealed partial class PFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Length < 3) return false; + + ErrorNumber errno = imagePlugin.ReadSector(2 + partition.Start, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + var magic = BigEndianBitConverter.ToUInt32(sector, 0x00); + + return magic is AFS_DISK or PFS2_DISK or PFS_DISK or MUAF_DISK or MUPFS_DISK; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + encoding ??= Encoding.GetEncoding("iso-8859-1"); + metadata = new FileSystem(); + ErrorNumber errno = imagePlugin.ReadSector(2 + partition.Start, out byte[] rootBlockSector); + + if(errno != ErrorNumber.NoError) return; + + RootBlock rootBlock = Marshal.ByteArrayToStructureBigEndian(rootBlockSector); + + var sbInformation = new StringBuilder(); + metadata = new FileSystem(); + + switch(rootBlock.diskType) + { + case AFS_DISK: + case MUAF_DISK: + sbInformation.Append(Localization.Professional_File_System_v1); + metadata.Type = FS_TYPE; + + break; + case PFS2_DISK: + sbInformation.Append(Localization.Professional_File_System_v2); + metadata.Type = FS_TYPE; + + break; + case PFS_DISK: + case MUPFS_DISK: + sbInformation.Append(Localization.Professional_File_System_v3); + metadata.Type = FS_TYPE; + + break; + } + + if(rootBlock.diskType is MUAF_DISK or MUPFS_DISK) sbInformation.Append(Localization.with_multi_user_support); + + sbInformation.AppendLine(); + + sbInformation + .AppendFormat(Localization.Volume_name_0, StringHandlers.PascalToString(rootBlock.diskname, encoding)) + .AppendLine(); + + sbInformation + .AppendFormat(Localization.Volume_has_0_free_sectors_of_1, rootBlock.blocksfree, rootBlock.diskSize) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_created_on_0, + DateHandlers.AmigaToDateTime(rootBlock.creationday, + rootBlock.creationminute, + rootBlock.creationtick)) + .AppendLine(); + + if(rootBlock.extension > 0) + { + sbInformation.AppendFormat(Localization.Root_block_extension_resides_at_block_0, rootBlock.extension) + .AppendLine(); + } + + information = sbInformation.ToString(); + + metadata.CreationDate = + DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute, rootBlock.creationtick); + + metadata.FreeClusters = rootBlock.blocksfree; + metadata.Clusters = rootBlock.diskSize; + metadata.ClusterSize = imagePlugin.Info.SectorSize; + metadata.VolumeName = StringHandlers.PascalToString(rootBlock.diskname, encoding); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/PFS/PFS.cs b/Aaru.Filesystems/PFS/PFS.cs new file mode 100644 index 000000000..e1b85aea4 --- /dev/null +++ b/Aaru.Filesystems/PFS/PFS.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PFS.cs +// Author(s) : Natalia Portillo +// +// Component : Professional File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedType.Local + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Professional File System +public sealed partial class PFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.PFS_Name; + + /// + public Guid Id => new("68DE769E-D957-406A-8AE4-3781CA8CDA77"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/PFS/Structs.cs b/Aaru.Filesystems/PFS/Structs.cs new file mode 100644 index 000000000..647579371 --- /dev/null +++ b/Aaru.Filesystems/PFS/Structs.cs @@ -0,0 +1,102 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Professional File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable UnusedType.Local + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Professional File System +public sealed partial class PFS +{ +#region Nested type: BootBlock + + /// Boot block, first 2 sectors + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct BootBlock + { + /// "PFS\1" disk type + public readonly uint diskType; + /// Boot code, til completion + public readonly byte[] bootCode; + } + +#endregion + +#region Nested type: RootBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct RootBlock + { + /// Disk type + public readonly uint diskType; + /// Options + public readonly uint options; + /// Current datestamp + public readonly uint datestamp; + /// Volume creation day + public readonly ushort creationday; + /// Volume creation minute + public readonly ushort creationminute; + /// Volume creation tick + public readonly ushort creationtick; + /// AmigaDOS protection bits + public readonly ushort protection; + /// Volume label (Pascal string) + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] diskname; + /// Last reserved block + public readonly uint lastreserved; + /// First reserved block + public readonly uint firstreserved; + /// Free reserved blocks + public readonly uint reservedfree; + /// Size of reserved blocks in bytes + public readonly ushort reservedblocksize; + /// Blocks in rootblock, including bitmap + public readonly ushort rootblockclusters; + /// Free blocks + public readonly uint blocksfree; + /// Blocks that must be always free + public readonly uint alwaysfree; + /// Current bitmapfield number for allocation + public readonly uint rovingPointer; + /// Pointer to deldir + public readonly uint delDirPtr; + /// Disk size in sectors + public readonly uint diskSize; + /// Rootblock extension + public readonly uint extension; + /// Unused + public readonly uint unused; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ProDOS.cs b/Aaru.Filesystems/ProDOS.cs deleted file mode 100644 index 39c431ca1..000000000 --- a/Aaru.Filesystems/ProDOS.cs +++ /dev/null @@ -1,510 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : ProDOS.cs -// Author(s) : Natalia Portillo -// -// Component : Apple ProDOS filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Apple ProDOS filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -// ReSharper disable NotAccessedField.Local - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Claunia.Encoding; -using Schemas; -using Encoding = System.Text.Encoding; - -// Information from Apple ProDOS 8 Technical Reference -/// -/// Implements detection of Apple ProDOS filesystem -[SuppressMessage("ReSharper", "UnusedMember.Local"), SuppressMessage("ReSharper", "UnusedType.Local")] -public sealed class ProDOSPlugin : IFilesystem -{ - const byte EMPTY_STORAGE_TYPE = 0x00; - /// A file that occupies one block or less - const byte SEEDLING_FILE_TYPE = 0x01; - /// A file that occupies between 2 and 256 blocks - const byte SAPLING_FILE_TYPE = 0x02; - /// A file that occupies between 257 and 32768 blocks - const byte TREE_FILE_TYPE = 0x03; - const byte PASCAL_AREA_TYPE = 0x04; - const byte SUBDIRECTORY_TYPE = 0x0D; - const byte SUBDIRECTORY_HEADER_TYPE = 0x0E; - const byte ROOT_DIRECTORY_TYPE = 0x0F; - - const byte VERSION1 = 0x00; - - const uint YEAR_MASK = 0xFE000000; - const uint MONTH_MASK = 0x1E00000; - const uint DAY_MASK = 0x1F0000; - const uint HOUR_MASK = 0x1F00; - const uint MINUTE_MASK = 0x3F; - - const byte DESTROY_ATTRIBUTE = 0x80; - const byte RENAME_ATTRIBUTE = 0x40; - const byte BACKUP_ATTRIBUTE = 0x20; - const byte WRITE_ATTRIBUTE = 0x02; - const byte READ_ATTRIBUTE = 0x01; - const byte RESERVED_ATTRIBUTE_MASK = 0x1C; - - const byte STORAGE_TYPE_MASK = 0xF0; - const byte NAME_LENGTH_MASK = 0x0F; - const byte ENTRY_LENGTH = 0x27; - const byte ENTRIES_PER_BLOCK = 0x0D; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Apple ProDOS filesystem"; - /// - public Guid Id => new("43874265-7B8A-4739-BCF7-07F80D5932BF"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Length < 3) - return false; - - var multiplier = (uint)(imagePlugin.Info.SectorSize == 256 ? 2 : 1); - - // Blocks 0 and 1 are boot code - ErrorNumber errno = imagePlugin.ReadSectors(2 * multiplier + partition.Start, multiplier, - out byte[] rootDirectoryKeyBlock); - - if(errno != ErrorNumber.NoError) - return false; - - var apmFromHddOnCd = false; - - if(imagePlugin.Info.SectorSize is 2352 or 2448 or 2048) - { - errno = imagePlugin.ReadSectors(partition.Start, 2, out byte[] tmp); - - if(errno != ErrorNumber.NoError) - return false; - - foreach(int offset in new[] - { - 0, 0x200, 0x400, 0x600, 0x800, 0xA00 - }.Where(offset => tmp.Length > offset + 0x200 && BitConverter.ToUInt16(tmp, offset) == 0 && - (byte)((tmp[offset + 0x04] & STORAGE_TYPE_MASK) >> 4) == ROOT_DIRECTORY_TYPE && - tmp[offset + 0x23] == ENTRY_LENGTH && tmp[offset + 0x24] == ENTRIES_PER_BLOCK)) - { - Array.Copy(tmp, offset, rootDirectoryKeyBlock, 0, 0x200); - apmFromHddOnCd = true; - - break; - } - } - - var prePointer = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0); - AaruConsole.DebugWriteLine("ProDOS plugin", "prePointer = {0}", prePointer); - - if(prePointer != 0) - return false; - - var storageType = (byte)((rootDirectoryKeyBlock[0x04] & STORAGE_TYPE_MASK) >> 4); - AaruConsole.DebugWriteLine("ProDOS plugin", "storage_type = {0}", storageType); - - if(storageType != ROOT_DIRECTORY_TYPE) - return false; - - byte entryLength = rootDirectoryKeyBlock[0x23]; - AaruConsole.DebugWriteLine("ProDOS plugin", "entry_length = {0}", entryLength); - - if(entryLength != ENTRY_LENGTH) - return false; - - byte entriesPerBlock = rootDirectoryKeyBlock[0x24]; - AaruConsole.DebugWriteLine("ProDOS plugin", "entries_per_block = {0}", entriesPerBlock); - - if(entriesPerBlock != ENTRIES_PER_BLOCK) - return false; - - var bitMapPointer = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x27); - AaruConsole.DebugWriteLine("ProDOS plugin", "bit_map_pointer = {0}", bitMapPointer); - - if(bitMapPointer > partition.End) - return false; - - var totalBlocks = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x29); - - if(apmFromHddOnCd) - totalBlocks /= 4; - - AaruConsole.DebugWriteLine("ProDOS plugin", "{0} <= ({1} - {2} + 1)? {3}", totalBlocks, partition.End, - partition.Start, totalBlocks <= partition.End - partition.Start + 1); - - return totalBlocks <= partition.End - partition.Start + 1; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? new Apple2c(); - information = ""; - var sbInformation = new StringBuilder(); - var multiplier = (uint)(imagePlugin.Info.SectorSize == 256 ? 2 : 1); - - // Blocks 0 and 1 are boot code - ErrorNumber errno = imagePlugin.ReadSectors(2 * multiplier + partition.Start, multiplier, - out byte[] rootDirectoryKeyBlockBytes); - - if(errno != ErrorNumber.NoError) - return; - - var apmFromHddOnCd = false; - - if(imagePlugin.Info.SectorSize is 2352 or 2448 or 2048) - { - errno = imagePlugin.ReadSectors(partition.Start, 2, out byte[] tmp); - - if(errno != ErrorNumber.NoError) - return; - - foreach(int offset in new[] - { - 0, 0x200, 0x400, 0x600, 0x800, 0xA00 - }.Where(offset => BitConverter.ToUInt16(tmp, offset) == 0 && - (byte)((tmp[offset + 0x04] & STORAGE_TYPE_MASK) >> 4) == ROOT_DIRECTORY_TYPE && - tmp[offset + 0x23] == ENTRY_LENGTH && tmp[offset + 0x24] == ENTRIES_PER_BLOCK)) - { - Array.Copy(tmp, offset, rootDirectoryKeyBlockBytes, 0, 0x200); - apmFromHddOnCd = true; - - break; - } - } - - var rootDirectoryKeyBlock = new RootDirectoryKeyBlock - { - header = new RootDirectoryHeader(), - zero = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x00), - next_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x02) - }; - - rootDirectoryKeyBlock.header.storage_type = (byte)((rootDirectoryKeyBlockBytes[0x04] & STORAGE_TYPE_MASK) >> 4); - - rootDirectoryKeyBlock.header.name_length = (byte)(rootDirectoryKeyBlockBytes[0x04] & NAME_LENGTH_MASK); - var temporal = new byte[rootDirectoryKeyBlock.header.name_length]; - Array.Copy(rootDirectoryKeyBlockBytes, 0x05, temporal, 0, rootDirectoryKeyBlock.header.name_length); - rootDirectoryKeyBlock.header.volume_name = Encoding.GetString(temporal); - rootDirectoryKeyBlock.header.reserved = BitConverter.ToUInt64(rootDirectoryKeyBlockBytes, 0x14); - - var tempTimestampLeft = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1C); - var tempTimestampRight = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1E); - - bool dateCorrect; - - try - { - var tempTimestamp = (uint)((tempTimestampLeft << 16) + tempTimestampRight); - var year = (int)((tempTimestamp & YEAR_MASK) >> 25); - var month = (int)((tempTimestamp & MONTH_MASK) >> 21); - var day = (int)((tempTimestamp & DAY_MASK) >> 16); - var hour = (int)((tempTimestamp & HOUR_MASK) >> 8); - var minute = (int)(tempTimestamp & MINUTE_MASK); - year += 1900; - - if(year < 1940) - year += 100; - - AaruConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp_left = 0x{0:X4}", tempTimestampLeft); - AaruConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp_right = 0x{0:X4}", tempTimestampRight); - AaruConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp = 0x{0:X8}", tempTimestamp); - - AaruConsole.DebugWriteLine("ProDOS plugin", - "Datetime field year {0}, month {1}, day {2}, hour {3}, minute {4}.", year, - month, day, hour, minute); - - rootDirectoryKeyBlock.header.creation_time = new DateTime(year, month, day, hour, minute, 0); - dateCorrect = true; - } - catch(ArgumentOutOfRangeException) - { - dateCorrect = false; - } - - rootDirectoryKeyBlock.header.version = rootDirectoryKeyBlockBytes[0x20]; - rootDirectoryKeyBlock.header.min_version = rootDirectoryKeyBlockBytes[0x21]; - rootDirectoryKeyBlock.header.access = rootDirectoryKeyBlockBytes[0x22]; - rootDirectoryKeyBlock.header.entry_length = rootDirectoryKeyBlockBytes[0x23]; - rootDirectoryKeyBlock.header.entries_per_block = rootDirectoryKeyBlockBytes[0x24]; - - rootDirectoryKeyBlock.header.file_count = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x25); - rootDirectoryKeyBlock.header.bit_map_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x27); - rootDirectoryKeyBlock.header.total_blocks = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x29); - - if(apmFromHddOnCd) - sbInformation.AppendLine("ProDOS uses 512 bytes/sector while devices uses 2048 bytes/sector.").AppendLine(); - - if(rootDirectoryKeyBlock.header.version != VERSION1 || - rootDirectoryKeyBlock.header.min_version != VERSION1) - { - sbInformation.AppendLine("Warning! Detected unknown ProDOS version ProDOS filesystem."); - sbInformation.AppendLine("All of the following information may be incorrect"); - } - - if(rootDirectoryKeyBlock.header.version == VERSION1) - sbInformation.AppendLine("ProDOS version 1 used to create this volume."); - else - sbInformation.AppendFormat("Unknown ProDOS version with field {0} used to create this volume.", - rootDirectoryKeyBlock.header.version).AppendLine(); - - if(rootDirectoryKeyBlock.header.min_version == VERSION1) - sbInformation.AppendLine("ProDOS version 1 at least required for reading this volume."); - else - sbInformation. - AppendFormat("Unknown ProDOS version with field {0} is at least required for reading this volume.", - rootDirectoryKeyBlock.header.min_version).AppendLine(); - - sbInformation.AppendFormat("Volume name is {0}", rootDirectoryKeyBlock.header.volume_name).AppendLine(); - - if(dateCorrect) - sbInformation.AppendFormat("Volume created on {0}", rootDirectoryKeyBlock.header.creation_time). - AppendLine(); - - sbInformation.AppendFormat("{0} bytes per directory entry", rootDirectoryKeyBlock.header.entry_length). - AppendLine(); - - sbInformation.AppendFormat("{0} entries per directory block", rootDirectoryKeyBlock.header.entries_per_block). - AppendLine(); - - sbInformation.AppendFormat("{0} files in root directory", rootDirectoryKeyBlock.header.file_count).AppendLine(); - - sbInformation.AppendFormat("{0} blocks in volume", rootDirectoryKeyBlock.header.total_blocks).AppendLine(); - - sbInformation.AppendFormat("Bitmap starts at block {0}", rootDirectoryKeyBlock.header.bit_map_pointer). - AppendLine(); - - if((rootDirectoryKeyBlock.header.access & READ_ATTRIBUTE) == READ_ATTRIBUTE) - sbInformation.AppendLine("Volume can be read"); - - if((rootDirectoryKeyBlock.header.access & WRITE_ATTRIBUTE) == WRITE_ATTRIBUTE) - sbInformation.AppendLine("Volume can be written"); - - if((rootDirectoryKeyBlock.header.access & RENAME_ATTRIBUTE) == RENAME_ATTRIBUTE) - sbInformation.AppendLine("Volume can be renamed"); - - if((rootDirectoryKeyBlock.header.access & DESTROY_ATTRIBUTE) == DESTROY_ATTRIBUTE) - sbInformation.AppendLine("Volume can be destroyed"); - - if((rootDirectoryKeyBlock.header.access & BACKUP_ATTRIBUTE) == BACKUP_ATTRIBUTE) - sbInformation.AppendLine("Volume must be backed up"); - - if((rootDirectoryKeyBlock.header.access & RESERVED_ATTRIBUTE_MASK) != 0) - AaruConsole.DebugWriteLine("ProDOS plugin", "Reserved attributes are set: {0:X2}", - rootDirectoryKeyBlock.header.access); - - information = sbInformation.ToString(); - - XmlFsType = new FileSystemType - { - VolumeName = rootDirectoryKeyBlock.header.volume_name, - Files = rootDirectoryKeyBlock.header.file_count, - FilesSpecified = true, - Clusters = rootDirectoryKeyBlock.header.total_blocks, - Type = "ProDOS" - }; - - XmlFsType.ClusterSize = (uint)((partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / - XmlFsType.Clusters); - - if(!dateCorrect) - return; - - XmlFsType.CreationDate = rootDirectoryKeyBlock.header.creation_time; - XmlFsType.CreationDateSpecified = true; - } - - /// ProDOS directory entry, decoded structure - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct Entry - { - /// Type of file pointed by this entry Offset 0x00, mask 0xF0 - public byte storage_type; - /// Length of name_length pascal string Offset 0x00, mask 0x0F - public byte name_length; - /// Pascal string of file name Offset 0x01, 15 bytes - public string file_name; - /// Descriptor of internal structure of the file Offset 0x10, 1 byte - public byte file_type; - /// - /// Block address of master index block for tree files. Block address of index block for sapling files. Block - /// address of block for seedling files. Offset 0x11, 2 bytes - /// - public ushort key_pointer; - /// Blocks used by file or directory, including index blocks. Offset 0x13, 2 bytes - public ushort blocks_used; - /// Size of file in bytes Offset 0x15, 3 bytes - public uint EOF; - /// File creation datetime Offset 0x18, 4 bytes - public DateTime creation_time; - /// Version of ProDOS that created this file Offset 0x1C, 1 byte - public byte version; - /// Minimum version of ProDOS needed to access this file Offset 0x1D, 1 byte - public byte min_version; - /// File permissions Offset 0x1E, 1 byte - public byte access; - /// General purpose field to store additional information about file format Offset 0x1F, 2 bytes - public ushort aux_type; - /// File last modification date time Offset 0x21, 4 bytes - public DateTime last_mod; - /// Block address pointer to key block of the directory containing this entry Offset 0x25, 2 bytes - public ushort header_pointer; - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct RootDirectoryHeader - { - /// Constant 0x0F Offset 0x04, mask 0xF0 - public byte storage_type; - /// Length of volume_name pascal string Offset 0x04, mask 0x0F - public byte name_length; - /// The name of the volume. Offset 0x05, 15 bytes - public string volume_name; - /// Reserved for future expansion Offset 0x14, 8 bytes - public ulong reserved; - /// Creation time of the volume Offset 0x1C, 4 bytes - public DateTime creation_time; - /// Version number of the volume format Offset 0x20, 1 byte - public byte version; - /// Reserved for future use Offset 0x21, 1 byte - public byte min_version; - /// Permissions for the volume Offset 0x22, 1 byte - public byte access; - /// Length of an entry in this directory Const 0x27 Offset 0x23, 1 byte - public byte entry_length; - /// Number of entries per block Const 0x0D Offset 0x24, 1 byte - public byte entries_per_block; - /// Number of active files in this directory Offset 0x25, 2 bytes - public ushort file_count; - /// - /// Block address of the first block of the volume's bitmap, one for every 4096 blocks or fraction Offset 0x27, 2 - /// bytes - /// - public ushort bit_map_pointer; - /// Total number of blocks in the volume Offset 0x29, 2 bytes - public ushort total_blocks; - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct DirectoryHeader - { - /// Constant 0x0E Offset 0x04, mask 0xF0 - public byte storage_type; - /// Length of volume_name pascal string Offset 0x04, mask 0x0F - public byte name_length; - /// The name of the directory. Offset 0x05, 15 bytes - public string directory_name; - /// Reserved for future expansion Offset 0x14, 8 bytes - public ulong reserved; - /// Creation time of the volume Offset 0x1C, 4 bytes - public DateTime creation_time; - /// Version number of the volume format Offset 0x20, 1 byte - public byte version; - /// Reserved for future use Offset 0x21, 1 byte - public byte min_version; - /// Permissions for the volume Offset 0x22, 1 byte - public byte access; - /// Length of an entry in this directory Const 0x27 Offset 0x23, 1 byte - public byte entry_length; - /// Number of entries per block Const 0x0D Offset 0x24, 1 byte - public byte entries_per_block; - /// Number of active files in this directory Offset 0x25, 2 bytes - public ushort file_count; - /// Block address of parent directory block that contains this entry Offset 0x27, 2 bytes - public ushort parent_pointer; - /// Entry number within the block indicated in parent_pointer Offset 0x29, 1 byte - public byte parent_entry_number; - /// Length of the entry that holds this directory, in the parent entry Const 0x27 Offset 0x2A, 1 byte - public byte parent_entry_length; - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct DirectoryKeyBlock - { - /// Always 0 Offset 0x00, 2 bytes - public ushort zero; - /// Pointer to next directory block, 0 if last Offset 0x02, 2 bytes - public ushort next_pointer; - /// Directory header Offset 0x04, 39 bytes - public DirectoryHeader header; - /// Directory entries Offset 0x2F, 39 bytes each, 12 entries - public Entry[] entries; - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct RootDirectoryKeyBlock - { - /// Always 0 Offset 0x00, 2 bytes - public ushort zero; - /// Pointer to next directory block, 0 if last Offset 0x02, 2 bytes - public ushort next_pointer; - /// Directory header Offset 0x04, 39 bytes - public RootDirectoryHeader header; - /// Directory entries Offset 0x2F, 39 bytes each, 12 entries - public Entry[] entries; - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct DirectoryBlock - { - /// Pointer to previous directory block Offset 0x00, 2 bytes - public ushort zero; - /// Pointer to next directory block, 0 if last Offset 0x02, 2 bytes - public ushort next_pointer; - /// Directory entries Offset 0x2F, 39 bytes each, 13 entries - public Entry[] entries; - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct IndexBlock - { - /// Up to 256 pointers to blocks, 0 to indicate the block is sparsed (non-allocated) - public ushort[] block_pointer; - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct MasterIndexBlock - { - /// Up to 128 pointers to index blocks - public ushort[] index_block_pointer; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/ProDOS/Consts.cs b/Aaru.Filesystems/ProDOS/Consts.cs new file mode 100644 index 000000000..10a69478a --- /dev/null +++ b/Aaru.Filesystems/ProDOS/Consts.cs @@ -0,0 +1,75 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Apple ProDOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable NotAccessedField.Local + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Information from Apple ProDOS 8 Technical Reference +/// +/// Implements detection of Apple ProDOS filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class ProDOSPlugin +{ + const byte EMPTY_STORAGE_TYPE = 0x00; + /// A file that occupies one block or less + const byte SEEDLING_FILE_TYPE = 0x01; + /// A file that occupies between 2 and 256 blocks + const byte SAPLING_FILE_TYPE = 0x02; + /// A file that occupies between 257 and 32768 blocks + const byte TREE_FILE_TYPE = 0x03; + const byte PASCAL_AREA_TYPE = 0x04; + const byte SUBDIRECTORY_TYPE = 0x0D; + const byte SUBDIRECTORY_HEADER_TYPE = 0x0E; + const byte ROOT_DIRECTORY_TYPE = 0x0F; + + const byte VERSION1 = 0x00; + + const uint YEAR_MASK = 0xFE000000; + const uint MONTH_MASK = 0x1E00000; + const uint DAY_MASK = 0x1F0000; + const uint HOUR_MASK = 0x1F00; + const uint MINUTE_MASK = 0x3F; + + const byte DESTROY_ATTRIBUTE = 0x80; + const byte RENAME_ATTRIBUTE = 0x40; + const byte BACKUP_ATTRIBUTE = 0x20; + const byte WRITE_ATTRIBUTE = 0x02; + const byte READ_ATTRIBUTE = 0x01; + const byte RESERVED_ATTRIBUTE_MASK = 0x1C; + + const byte STORAGE_TYPE_MASK = 0xF0; + const byte NAME_LENGTH_MASK = 0x0F; + const byte ENTRY_LENGTH = 0x27; + const byte ENTRIES_PER_BLOCK = 0x0D; + + const string FS_TYPE = "prodos"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/ProDOS/Info.cs b/Aaru.Filesystems/ProDOS/Info.cs new file mode 100644 index 000000000..1d222238e --- /dev/null +++ b/Aaru.Filesystems/ProDOS/Info.cs @@ -0,0 +1,331 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Apple ProDOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable NotAccessedField.Local + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Claunia.Encoding; +using Encoding = System.Text.Encoding; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from Apple ProDOS 8 Technical Reference +/// +/// Implements detection of Apple ProDOS filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class ProDOSPlugin +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Length < 3) return false; + + var multiplier = (uint)(imagePlugin.Info.SectorSize == 256 ? 2 : 1); + + // Blocks 0 and 1 are boot code + ErrorNumber errno = + imagePlugin.ReadSectors(2 * multiplier + partition.Start, multiplier, out byte[] rootDirectoryKeyBlock); + + if(errno != ErrorNumber.NoError) return false; + + var apmFromHddOnCd = false; + + if(imagePlugin.Info.SectorSize is 2352 or 2448 or 2048) + { + errno = imagePlugin.ReadSectors(partition.Start, 2, out byte[] tmp); + + if(errno != ErrorNumber.NoError) return false; + + foreach(int offset in new[] + { + 0, 0x200, 0x400, 0x600, 0x800, 0xA00 + }.Where(offset => tmp.Length > offset + 0x200 && + BitConverter.ToUInt16(tmp, offset) == 0 && + (byte)((tmp[offset + 0x04] & STORAGE_TYPE_MASK) >> 4) == ROOT_DIRECTORY_TYPE && + tmp[offset + 0x23] == ENTRY_LENGTH && + tmp[offset + 0x24] == ENTRIES_PER_BLOCK)) + { + Array.Copy(tmp, offset, rootDirectoryKeyBlock, 0, 0x200); + apmFromHddOnCd = true; + + break; + } + } + + var prePointer = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0); + AaruConsole.DebugWriteLine(MODULE_NAME, "prePointer = {0}", prePointer); + + if(prePointer != 0) return false; + + var storageType = (byte)((rootDirectoryKeyBlock[0x04] & STORAGE_TYPE_MASK) >> 4); + AaruConsole.DebugWriteLine(MODULE_NAME, "storage_type = {0}", storageType); + + if(storageType != ROOT_DIRECTORY_TYPE) return false; + + byte entryLength = rootDirectoryKeyBlock[0x23]; + AaruConsole.DebugWriteLine(MODULE_NAME, "entry_length = {0}", entryLength); + + if(entryLength != ENTRY_LENGTH) return false; + + byte entriesPerBlock = rootDirectoryKeyBlock[0x24]; + AaruConsole.DebugWriteLine(MODULE_NAME, "entries_per_block = {0}", entriesPerBlock); + + if(entriesPerBlock != ENTRIES_PER_BLOCK) return false; + + var bitMapPointer = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x27); + AaruConsole.DebugWriteLine(MODULE_NAME, "bit_map_pointer = {0}", bitMapPointer); + + if(bitMapPointer > partition.End) return false; + + var totalBlocks = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x29); + + if(apmFromHddOnCd) totalBlocks /= 4; + + AaruConsole.DebugWriteLine(MODULE_NAME, + "{0} <= ({1} - {2} + 1)? {3}", + totalBlocks, + partition.End, + partition.Start, + totalBlocks <= partition.End - partition.Start + 1); + + return totalBlocks <= partition.End - partition.Start + 1; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= new Apple2c(); + information = ""; + metadata = new FileSystem(); + var sbInformation = new StringBuilder(); + var multiplier = (uint)(imagePlugin.Info.SectorSize == 256 ? 2 : 1); + + // Blocks 0 and 1 are boot code + ErrorNumber errno = imagePlugin.ReadSectors(2 * multiplier + partition.Start, + multiplier, + out byte[] rootDirectoryKeyBlockBytes); + + if(errno != ErrorNumber.NoError) return; + + var apmFromHddOnCd = false; + + if(imagePlugin.Info.SectorSize is 2352 or 2448 or 2048) + { + errno = imagePlugin.ReadSectors(partition.Start, 2, out byte[] tmp); + + if(errno != ErrorNumber.NoError) return; + + foreach(int offset in new[] + { + 0, 0x200, 0x400, 0x600, 0x800, 0xA00 + }.Where(offset => BitConverter.ToUInt16(tmp, offset) == 0 && + (byte)((tmp[offset + 0x04] & STORAGE_TYPE_MASK) >> 4) == ROOT_DIRECTORY_TYPE && + tmp[offset + 0x23] == ENTRY_LENGTH && + tmp[offset + 0x24] == ENTRIES_PER_BLOCK)) + { + Array.Copy(tmp, offset, rootDirectoryKeyBlockBytes, 0, 0x200); + apmFromHddOnCd = true; + + break; + } + } + + var rootDirectoryKeyBlock = new RootDirectoryKeyBlock + { + header = new RootDirectoryHeader(), + zero = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x00), + next_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x02) + }; + + rootDirectoryKeyBlock.header.storage_type = (byte)((rootDirectoryKeyBlockBytes[0x04] & STORAGE_TYPE_MASK) >> 4); + + rootDirectoryKeyBlock.header.name_length = (byte)(rootDirectoryKeyBlockBytes[0x04] & NAME_LENGTH_MASK); + var temporal = new byte[rootDirectoryKeyBlock.header.name_length]; + Array.Copy(rootDirectoryKeyBlockBytes, 0x05, temporal, 0, rootDirectoryKeyBlock.header.name_length); + rootDirectoryKeyBlock.header.volume_name = encoding.GetString(temporal); + rootDirectoryKeyBlock.header.reserved = BitConverter.ToUInt64(rootDirectoryKeyBlockBytes, 0x14); + + var tempTimestampLeft = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1C); + var tempTimestampRight = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1E); + + bool dateCorrect; + + try + { + var tempTimestamp = (uint)((tempTimestampLeft << 16) + tempTimestampRight); + var year = (int)((tempTimestamp & YEAR_MASK) >> 25); + var month = (int)((tempTimestamp & MONTH_MASK) >> 21); + var day = (int)((tempTimestamp & DAY_MASK) >> 16); + var hour = (int)((tempTimestamp & HOUR_MASK) >> 8); + var minute = (int)(tempTimestamp & MINUTE_MASK); + year += 1900; + + if(year < 1940) year += 100; + + AaruConsole.DebugWriteLine(MODULE_NAME, "temp_timestamp_left = 0x{0:X4}", tempTimestampLeft); + AaruConsole.DebugWriteLine(MODULE_NAME, "temp_timestamp_right = 0x{0:X4}", tempTimestampRight); + AaruConsole.DebugWriteLine(MODULE_NAME, "temp_timestamp = 0x{0:X8}", tempTimestamp); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Datetime_field_year_0_month_1_day_2_hour_3_minute_4, + year, + month, + day, + hour, + minute); + + rootDirectoryKeyBlock.header.creation_time = new DateTime(year, month, day, hour, minute, 0); + dateCorrect = true; + } + catch(ArgumentOutOfRangeException) + { + dateCorrect = false; + } + + rootDirectoryKeyBlock.header.version = rootDirectoryKeyBlockBytes[0x20]; + rootDirectoryKeyBlock.header.min_version = rootDirectoryKeyBlockBytes[0x21]; + rootDirectoryKeyBlock.header.access = rootDirectoryKeyBlockBytes[0x22]; + rootDirectoryKeyBlock.header.entry_length = rootDirectoryKeyBlockBytes[0x23]; + rootDirectoryKeyBlock.header.entries_per_block = rootDirectoryKeyBlockBytes[0x24]; + + rootDirectoryKeyBlock.header.file_count = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x25); + rootDirectoryKeyBlock.header.bit_map_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x27); + rootDirectoryKeyBlock.header.total_blocks = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x29); + + if(apmFromHddOnCd) + { + sbInformation.AppendLine(Localization.ProDOS_uses_512_bytes_sector_while_device_uses_2048_bytes_sector) + .AppendLine(); + } + + if(rootDirectoryKeyBlock.header.version != VERSION1 || rootDirectoryKeyBlock.header.min_version != VERSION1) + { + sbInformation.AppendLine(Localization.Warning_Detected_unknown_ProDOS_version_ProDOS_filesystem); + sbInformation.AppendLine(Localization.All_of_the_following_information_may_be_incorrect); + } + + if(rootDirectoryKeyBlock.header.version == VERSION1) + sbInformation.AppendLine(Localization.ProDOS_version_one_used_to_create_this_volume); + else + { + sbInformation.AppendFormat(Localization.Unknown_ProDOS_version_with_field_0_used_to_create_this_volume, + rootDirectoryKeyBlock.header.version) + .AppendLine(); + } + + if(rootDirectoryKeyBlock.header.min_version == VERSION1) + sbInformation.AppendLine(Localization.ProDOS_version_one_at_least_required_for_reading_this_volume); + else + { + sbInformation + .AppendFormat(Localization + .Unknown_ProDOS_version_with_field_0_is_at_least_required_for_reading_this_volume, + rootDirectoryKeyBlock.header.min_version) + .AppendLine(); + } + + sbInformation.AppendFormat(Localization.Volume_name_is_0, rootDirectoryKeyBlock.header.volume_name) + .AppendLine(); + + if(dateCorrect) + { + sbInformation.AppendFormat(Localization.Volume_created_on_0, rootDirectoryKeyBlock.header.creation_time) + .AppendLine(); + } + + sbInformation.AppendFormat(Localization._0_bytes_per_directory_entry, rootDirectoryKeyBlock.header.entry_length) + .AppendLine(); + + sbInformation.AppendFormat(Localization._0_entries_per_directory_block, + rootDirectoryKeyBlock.header.entries_per_block) + .AppendLine(); + + sbInformation.AppendFormat(Localization._0_files_in_root_directory, rootDirectoryKeyBlock.header.file_count) + .AppendLine(); + + sbInformation.AppendFormat(Localization._0_blocks_in_volume, rootDirectoryKeyBlock.header.total_blocks) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Bitmap_starts_at_block_0, rootDirectoryKeyBlock.header.bit_map_pointer) + .AppendLine(); + + if((rootDirectoryKeyBlock.header.access & READ_ATTRIBUTE) == READ_ATTRIBUTE) + sbInformation.AppendLine(Localization.Volume_can_be_read); + + if((rootDirectoryKeyBlock.header.access & WRITE_ATTRIBUTE) == WRITE_ATTRIBUTE) + sbInformation.AppendLine(Localization.Volume_can_be_written); + + if((rootDirectoryKeyBlock.header.access & RENAME_ATTRIBUTE) == RENAME_ATTRIBUTE) + sbInformation.AppendLine(Localization.Volume_can_be_renamed); + + if((rootDirectoryKeyBlock.header.access & DESTROY_ATTRIBUTE) == DESTROY_ATTRIBUTE) + sbInformation.AppendLine(Localization.Volume_can_be_destroyed); + + if((rootDirectoryKeyBlock.header.access & BACKUP_ATTRIBUTE) == BACKUP_ATTRIBUTE) + sbInformation.AppendLine(Localization.Volume_must_be_backed_up); + + // TODO: Fix mask + if((rootDirectoryKeyBlock.header.access & RESERVED_ATTRIBUTE_MASK) != 0) + { + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.Reserved_attributes_are_set_0, + rootDirectoryKeyBlock.header.access); + } + + information = sbInformation.ToString(); + + metadata = new FileSystem + { + VolumeName = rootDirectoryKeyBlock.header.volume_name, + Files = rootDirectoryKeyBlock.header.file_count, + Clusters = rootDirectoryKeyBlock.header.total_blocks, + Type = FS_TYPE + }; + + metadata.ClusterSize = + (uint)((partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / metadata.Clusters); + + if(!dateCorrect) return; + + metadata.CreationDate = rootDirectoryKeyBlock.header.creation_time; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ProDOS/ProDOS.cs b/Aaru.Filesystems/ProDOS/ProDOS.cs new file mode 100644 index 000000000..b934d1449 --- /dev/null +++ b/Aaru.Filesystems/ProDOS/ProDOS.cs @@ -0,0 +1,58 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ProDOS.cs +// Author(s) : Natalia Portillo +// +// Component : Apple ProDOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable NotAccessedField.Local + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from Apple ProDOS 8 Technical Reference +/// +/// Implements detection of Apple ProDOS filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class ProDOSPlugin : IFilesystem +{ + const string MODULE_NAME = "ProDOS plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.ProDOSPlugin_Name; + + /// + public Guid Id => new("43874265-7B8A-4739-BCF7-07F80D5932BF"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ProDOS/Structs.cs b/Aaru.Filesystems/ProDOS/Structs.cs new file mode 100644 index 000000000..5b809d7b9 --- /dev/null +++ b/Aaru.Filesystems/ProDOS/Structs.cs @@ -0,0 +1,224 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Apple ProDOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable NotAccessedField.Local + +using System; +using System.Diagnostics.CodeAnalysis; + +#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value + +namespace Aaru.Filesystems; + +// Information from Apple ProDOS 8 Technical Reference +/// +/// Implements detection of Apple ProDOS filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "InconsistentNaming")] +public sealed partial class ProDOSPlugin +{ +#region Nested type: DirectoryBlock + + struct DirectoryBlock + { + /// Pointer to previous directory block Offset 0x00, 2 bytes + public ushort zero; + /// Pointer to next directory block, 0 if last Offset 0x02, 2 bytes + public ushort next_pointer; + /// Directory entries Offset 0x2F, 39 bytes each, 13 entries + public Entry[] entries; + } + +#endregion + +#region Nested type: DirectoryHeader + + struct DirectoryHeader + { + /// Constant 0x0E Offset 0x04, mask 0xF0 + public byte storage_type; + /// Length of volume_name pascal string Offset 0x04, mask 0x0F + public byte name_length; + /// The name of the directory. Offset 0x05, 15 bytes + public string directory_name; + /// Reserved for future expansion Offset 0x14, 8 bytes + public ulong reserved; + /// Creation time of the volume Offset 0x1C, 4 bytes + public DateTime creation_time; + /// Version number of the volume format Offset 0x20, 1 byte + public byte version; + /// Reserved for future use Offset 0x21, 1 byte + public byte min_version; + /// Permissions for the volume Offset 0x22, 1 byte + public byte access; + /// Length of an entry in this directory Const 0x27 Offset 0x23, 1 byte + public byte entry_length; + /// Number of entries per block Const 0x0D Offset 0x24, 1 byte + public byte entries_per_block; + /// Number of active files in this directory Offset 0x25, 2 bytes + public ushort file_count; + /// Block address of parent directory block that contains this entry Offset 0x27, 2 bytes + public ushort parent_pointer; + /// Entry number within the block indicated in parent_pointer Offset 0x29, 1 byte + public byte parent_entry_number; + /// Length of the entry that holds this directory, in the parent entry Const 0x27 Offset 0x2A, 1 byte + public byte parent_entry_length; + } + +#endregion + +#region Nested type: DirectoryKeyBlock + + struct DirectoryKeyBlock + { + /// Always 0 Offset 0x00, 2 bytes + public ushort zero; + /// Pointer to next directory block, 0 if last Offset 0x02, 2 bytes + public ushort next_pointer; + /// Directory header Offset 0x04, 39 bytes + public DirectoryHeader header; + /// Directory entries Offset 0x2F, 39 bytes each, 12 entries + public Entry[] entries; + } + +#endregion + +#region Nested type: Entry + + /// ProDOS directory entry, decoded structure + struct Entry + { + /// Type of file pointed by this entry Offset 0x00, mask 0xF0 + public byte storage_type; + /// Length of name_length pascal string Offset 0x00, mask 0x0F + public byte name_length; + /// Pascal string of file name Offset 0x01, 15 bytes + public string file_name; + /// Descriptor of internal structure of the file Offset 0x10, 1 byte + public byte file_type; + /// + /// Block address of master index block for tree files. Block address of index block for sapling files. Block + /// address of block for seedling files. Offset 0x11, 2 bytes + /// + public ushort key_pointer; + /// Blocks used by file or directory, including index blocks. Offset 0x13, 2 bytes + public ushort blocks_used; + /// Size of file in bytes Offset 0x15, 3 bytes + public uint EOF; + /// File creation datetime Offset 0x18, 4 bytes + public DateTime creation_time; + /// Version of ProDOS that created this file Offset 0x1C, 1 byte + public byte version; + /// Minimum version of ProDOS needed to access this file Offset 0x1D, 1 byte + public byte min_version; + /// File permissions Offset 0x1E, 1 byte + public byte access; + /// General purpose field to store additional information about file format Offset 0x1F, 2 bytes + public ushort aux_type; + /// File last modification date time Offset 0x21, 4 bytes + public DateTime last_mod; + /// Block address pointer to key block of the directory containing this entry Offset 0x25, 2 bytes + public ushort header_pointer; + } + +#endregion + +#region Nested type: IndexBlock + + struct IndexBlock + { + /// Up to 256 pointers to blocks, 0 to indicate the block is sparsed (non-allocated) + public ushort[] block_pointer; + } + +#endregion + +#region Nested type: MasterIndexBlock + + struct MasterIndexBlock + { + /// Up to 128 pointers to index blocks + public ushort[] index_block_pointer; + } + +#endregion + +#region Nested type: RootDirectoryHeader + + struct RootDirectoryHeader + { + /// Constant 0x0F Offset 0x04, mask 0xF0 + public byte storage_type; + /// Length of volume_name pascal string Offset 0x04, mask 0x0F + public byte name_length; + /// The name of the volume. Offset 0x05, 15 bytes + public string volume_name; + /// Reserved for future expansion Offset 0x14, 8 bytes + public ulong reserved; + /// Creation time of the volume Offset 0x1C, 4 bytes + public DateTime creation_time; + /// Version number of the volume format Offset 0x20, 1 byte + public byte version; + /// Reserved for future use Offset 0x21, 1 byte + public byte min_version; + /// Permissions for the volume Offset 0x22, 1 byte + public byte access; + /// Length of an entry in this directory Const 0x27 Offset 0x23, 1 byte + public byte entry_length; + /// Number of entries per block Const 0x0D Offset 0x24, 1 byte + public byte entries_per_block; + /// Number of active files in this directory Offset 0x25, 2 bytes + public ushort file_count; + /// + /// Block address of the first block of the volume's bitmap, one for every 4096 blocks or fraction Offset 0x27, 2 + /// bytes + /// + public ushort bit_map_pointer; + /// Total number of blocks in the volume Offset 0x29, 2 bytes + public ushort total_blocks; + } + +#endregion + +#region Nested type: RootDirectoryKeyBlock + + struct RootDirectoryKeyBlock + { + /// Always 0 Offset 0x00, 2 bytes + public ushort zero; + /// Pointer to next directory block, 0 if last Offset 0x02, 2 bytes + public ushort next_pointer; + /// Directory header Offset 0x04, 39 bytes + public RootDirectoryHeader header; + /// Directory entries Offset 0x2F, 39 bytes each, 12 entries + public Entry[] entries; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/QNX4.cs b/Aaru.Filesystems/QNX4.cs deleted file mode 100644 index 66e6d47ff..000000000 --- a/Aaru.Filesystems/QNX4.cs +++ /dev/null @@ -1,282 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : QNX4.cs -// Author(s) : Natalia Portillo -// -// Component : QNX4 filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the QNX4 filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of QNX 4 filesystem -[SuppressMessage("ReSharper", "UnusedType.Local")] -public sealed class QNX4 : IFilesystem -{ - readonly byte[] _rootDirFname = - { - 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "QNX4 Plugin"; - /// - public Guid Id => new("E73A63FA-B5B0-48BF-BF82-DA5F0A8170D2"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start + 1 >= imagePlugin.Info.Sectors) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start + 1, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < 512) - return false; - - Superblock qnxSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - // Check root directory name - if(!_rootDirFname.SequenceEqual(qnxSb.rootDir.di_fname)) - return false; - - // Check sizes are multiple of blocks - if(qnxSb.rootDir.di_size % 512 != 0 || - qnxSb.inode.di_size % 512 != 0 || - qnxSb.boot.di_size % 512 != 0 || - qnxSb.altBoot.di_size % 512 != 0) - return false; - - // Check extents are not past device - if(qnxSb.rootDir.di_first_xtnt.Block + partition.Start >= partition.End || - qnxSb.inode.di_first_xtnt.Block + partition.Start >= partition.End || - qnxSb.boot.di_first_xtnt.Block + partition.Start >= partition.End || - qnxSb.altBoot.di_first_xtnt.Block + partition.Start >= partition.End) - return false; - - // Check inodes are in use - if((qnxSb.rootDir.di_status & 0x01) != 0x01 || - (qnxSb.inode.di_status & 0x01) != 0x01 || - (qnxSb.boot.di_status & 0x01) != 0x01) - return false; - - // All hail filesystems without identification marks - return true; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - ErrorNumber errno = imagePlugin.ReadSector(partition.Start + 1, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < 512) - return; - - Superblock qnxSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - // Too much useless information - /* - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_fname = {0}", CurrentEncoding.GetString(qnxSb.rootDir.di_fname)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_size = {0}", qnxSb.rootDir.di_size); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_first_xtnt.block = {0}", qnxSb.rootDir.di_first_xtnt.block); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_first_xtnt.length = {0}", qnxSb.rootDir.di_first_xtnt.length); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_xblk = {0}", qnxSb.rootDir.di_xblk); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_ftime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_mtime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_atime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_ctime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_num_xtnts = {0}", qnxSb.rootDir.di_num_xtnts); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_mode = {0}", Convert.ToString(qnxSb.rootDir.di_mode, 8)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_uid = {0}", qnxSb.rootDir.di_uid); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_gid = {0}", qnxSb.rootDir.di_gid); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_nlink = {0}", qnxSb.rootDir.di_nlink); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_zero = {0}", qnxSb.rootDir.di_zero); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_type = {0}", qnxSb.rootDir.di_type); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_status = {0}", qnxSb.rootDir.di_status); - - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_fname = {0}", CurrentEncoding.GetString(qnxSb.inode.di_fname)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_size = {0}", qnxSb.inode.di_size); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_first_xtnt.block = {0}", qnxSb.inode.di_first_xtnt.block); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_first_xtnt.length = {0}", qnxSb.inode.di_first_xtnt.length); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_xblk = {0}", qnxSb.inode.di_xblk); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_ftime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_mtime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_atime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_ctime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_num_xtnts = {0}", qnxSb.inode.di_num_xtnts); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_mode = {0}", Convert.ToString(qnxSb.inode.di_mode, 8)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_uid = {0}", qnxSb.inode.di_uid); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_gid = {0}", qnxSb.inode.di_gid); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_nlink = {0}", qnxSb.inode.di_nlink); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_zero = {0}", qnxSb.inode.di_zero); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_type = {0}", qnxSb.inode.di_type); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_status = {0}", qnxSb.inode.di_status); - - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_fname = {0}", CurrentEncoding.GetString(qnxSb.boot.di_fname)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_size = {0}", qnxSb.boot.di_size); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_first_xtnt.block = {0}", qnxSb.boot.di_first_xtnt.block); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_first_xtnt.length = {0}", qnxSb.boot.di_first_xtnt.length); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_xblk = {0}", qnxSb.boot.di_xblk); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_ftime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_mtime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_atime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_ctime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_num_xtnts = {0}", qnxSb.boot.di_num_xtnts); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_mode = {0}", Convert.ToString(qnxSb.boot.di_mode, 8)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_uid = {0}", qnxSb.boot.di_uid); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_gid = {0}", qnxSb.boot.di_gid); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_nlink = {0}", qnxSb.boot.di_nlink); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_zero = {0}", qnxSb.boot.di_zero); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_type = {0}", qnxSb.boot.di_type); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_status = {0}", qnxSb.boot.di_status); - - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_fname = {0}", CurrentEncoding.GetString(qnxSb.altBoot.di_fname)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_size = {0}", qnxSb.altBoot.di_size); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_first_xtnt.block = {0}", qnxSb.altBoot.di_first_xtnt.block); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_first_xtnt.length = {0}", qnxSb.altBoot.di_first_xtnt.length); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_xblk = {0}", qnxSb.altBoot.di_xblk); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_ftime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_mtime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_atime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_ctime)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_num_xtnts = {0}", qnxSb.altBoot.di_num_xtnts); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_mode = {0}", Convert.ToString(qnxSb.altBoot.di_mode, 8)); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_uid = {0}", qnxSb.altBoot.di_uid); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_gid = {0}", qnxSb.altBoot.di_gid); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_nlink = {0}", qnxSb.altBoot.di_nlink); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_zero = {0}", qnxSb.altBoot.di_zero); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_type = {0}", qnxSb.altBoot.di_type); - AaruConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_status = {0}", qnxSb.altBoot.di_status); - */ - - information = $"QNX4 filesystem\nCreated on {DateHandlers.UnixUnsignedToDateTime(qnxSb.rootDir.di_ftime)}\n"; - - XmlFsType = new FileSystemType - { - Type = "QNX4 filesystem", - Clusters = partition.Length, - ClusterSize = 512, - CreationDate = DateHandlers.UnixUnsignedToDateTime(qnxSb.rootDir.di_ftime), - CreationDateSpecified = true, - ModificationDate = DateHandlers.UnixUnsignedToDateTime(qnxSb.rootDir.di_mtime), - ModificationDateSpecified = true - }; - - XmlFsType.Bootable |= qnxSb.boot.di_size != 0 || qnxSb.altBoot.di_size != 0; - } - - struct Extent - { - public uint Block; - public uint Length; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Inode - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] di_fname; - public readonly uint di_size; - public readonly Extent di_first_xtnt; - public readonly uint di_xblk; - public readonly uint di_ftime; - public readonly uint di_mtime; - public readonly uint di_atime; - public readonly uint di_ctime; - public readonly ushort di_num_xtnts; - public readonly ushort di_mode; - public readonly ushort di_uid; - public readonly ushort di_gid; - public readonly ushort di_nlink; - public readonly uint di_zero; - public readonly byte di_type; - public readonly byte di_status; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct LinkInfo - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] - public readonly byte[] dl_fname; - public readonly uint dl_inode_blk; - public readonly byte dl_inode_ndx; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public readonly byte[] dl_spare; - public readonly byte dl_status; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ExtentBlock - { - public readonly uint next_xblk; - public readonly uint prev_xblk; - public readonly byte num_xtnts; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] spare; - public readonly uint num_blocks; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 60)] - public readonly Extent[] xtnts; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] signature; - public readonly Extent first_xtnt; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Superblock - { - public readonly Inode rootDir; - public readonly Inode inode; - public readonly Inode boot; - public readonly Inode altBoot; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/QNX4/Consts.cs b/Aaru.Filesystems/QNX4/Consts.cs new file mode 100644 index 000000000..0a6a73d91 --- /dev/null +++ b/Aaru.Filesystems/QNX4/Consts.cs @@ -0,0 +1,43 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : QNX4 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of QNX 4 filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class QNX4 +{ + const string FS_TYPE = "qnx4"; + readonly byte[] _rootDirFname = + [ + 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]; +} \ No newline at end of file diff --git a/Aaru.Filesystems/QNX4/Info.cs b/Aaru.Filesystems/QNX4/Info.cs new file mode 100644 index 000000000..594a3c83e --- /dev/null +++ b/Aaru.Filesystems/QNX4/Info.cs @@ -0,0 +1,193 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : QNX4 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of QNX 4 filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class QNX4 +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start + 1 >= imagePlugin.Info.Sectors) return false; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start + 1, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < 512) return false; + + Superblock qnxSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + // Check root directory name + if(!_rootDirFname.SequenceEqual(qnxSb.rootDir.di_fname)) return false; + + // Check sizes are multiple of blocks + if(qnxSb.rootDir.di_size % 512 != 0 || + qnxSb.inode.di_size % 512 != 0 || + qnxSb.boot.di_size % 512 != 0 || + qnxSb.altBoot.di_size % 512 != 0) + return false; + + // Check extents are not past device + if(qnxSb.rootDir.di_first_xtnt.Block + partition.Start >= partition.End || + qnxSb.inode.di_first_xtnt.Block + partition.Start >= partition.End || + qnxSb.boot.di_first_xtnt.Block + partition.Start >= partition.End || + qnxSb.altBoot.di_first_xtnt.Block + partition.Start >= partition.End) + return false; + + // Check inodes are in use + return (qnxSb.rootDir.di_status & 0x01) == 0x01 && + (qnxSb.inode.di_status & 0x01) == 0x01 && + (qnxSb.boot.di_status & 0x01) == 0x01; + + // All hail filesystems without identification marks + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + ErrorNumber errno = imagePlugin.ReadSector(partition.Start + 1, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < 512) return; + + Superblock qnxSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + // Too much useless information + /* + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_fname = {0}", CurrentEncoding.GetString(qnxSb.rootDir.di_fname)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_size = {0}", qnxSb.rootDir.di_size); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_first_xtnt.block = {0}", qnxSb.rootDir.di_first_xtnt.block); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_first_xtnt.length = {0}", qnxSb.rootDir.di_first_xtnt.length); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_xblk = {0}", qnxSb.rootDir.di_xblk); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_ftime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_mtime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_atime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_ctime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_num_xtnts = {0}", qnxSb.rootDir.di_num_xtnts); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_mode = {0}", Convert.ToString(qnxSb.rootDir.di_mode, 8)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_uid = {0}", qnxSb.rootDir.di_uid); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_gid = {0}", qnxSb.rootDir.di_gid); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_nlink = {0}", qnxSb.rootDir.di_nlink); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_zero = {0}", qnxSb.rootDir.di_zero); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_type = {0}", qnxSb.rootDir.di_type); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.rootDir.di_status = {0}", qnxSb.rootDir.di_status); + + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_fname = {0}", CurrentEncoding.GetString(qnxSb.inode.di_fname)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_size = {0}", qnxSb.inode.di_size); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_first_xtnt.block = {0}", qnxSb.inode.di_first_xtnt.block); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_first_xtnt.length = {0}", qnxSb.inode.di_first_xtnt.length); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_xblk = {0}", qnxSb.inode.di_xblk); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_ftime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_mtime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_atime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_ctime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_num_xtnts = {0}", qnxSb.inode.di_num_xtnts); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_mode = {0}", Convert.ToString(qnxSb.inode.di_mode, 8)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_uid = {0}", qnxSb.inode.di_uid); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_gid = {0}", qnxSb.inode.di_gid); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_nlink = {0}", qnxSb.inode.di_nlink); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_zero = {0}", qnxSb.inode.di_zero); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_type = {0}", qnxSb.inode.di_type); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.inode.di_status = {0}", qnxSb.inode.di_status); + + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_fname = {0}", CurrentEncoding.GetString(qnxSb.boot.di_fname)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_size = {0}", qnxSb.boot.di_size); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_first_xtnt.block = {0}", qnxSb.boot.di_first_xtnt.block); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_first_xtnt.length = {0}", qnxSb.boot.di_first_xtnt.length); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_xblk = {0}", qnxSb.boot.di_xblk); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_ftime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_mtime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_atime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_ctime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_num_xtnts = {0}", qnxSb.boot.di_num_xtnts); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_mode = {0}", Convert.ToString(qnxSb.boot.di_mode, 8)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_uid = {0}", qnxSb.boot.di_uid); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_gid = {0}", qnxSb.boot.di_gid); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_nlink = {0}", qnxSb.boot.di_nlink); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_zero = {0}", qnxSb.boot.di_zero); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_type = {0}", qnxSb.boot.di_type); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.boot.di_status = {0}", qnxSb.boot.di_status); + + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_fname = {0}", CurrentEncoding.GetString(qnxSb.altBoot.di_fname)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_size = {0}", qnxSb.altBoot.di_size); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_first_xtnt.block = {0}", qnxSb.altBoot.di_first_xtnt.block); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_first_xtnt.length = {0}", qnxSb.altBoot.di_first_xtnt.length); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_xblk = {0}", qnxSb.altBoot.di_xblk); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_ftime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_mtime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_atime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_ctime)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_num_xtnts = {0}", qnxSb.altBoot.di_num_xtnts); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_mode = {0}", Convert.ToString(qnxSb.altBoot.di_mode, 8)); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_uid = {0}", qnxSb.altBoot.di_uid); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_gid = {0}", qnxSb.altBoot.di_gid); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_nlink = {0}", qnxSb.altBoot.di_nlink); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_zero = {0}", qnxSb.altBoot.di_zero); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_type = {0}", qnxSb.altBoot.di_type); + AaruConsole.DebugWriteLine(MODULE_NAME, "qnxSb.altBoot.di_status = {0}", qnxSb.altBoot.di_status); + */ + + information = Localization.QNX4_filesystem + + "\n" + + string.Format(Localization.Created_on_0, + DateHandlers.UnixUnsignedToDateTime(qnxSb.rootDir.di_ftime)) + + "\n"; + + metadata = new FileSystem + { + Type = FS_TYPE, + Clusters = partition.Length, + ClusterSize = 512, + CreationDate = DateHandlers.UnixUnsignedToDateTime(qnxSb.rootDir.di_ftime), + ModificationDate = DateHandlers.UnixUnsignedToDateTime(qnxSb.rootDir.di_mtime) + }; + + metadata.Bootable |= qnxSb.boot.di_size != 0 || qnxSb.altBoot.di_size != 0; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/QNX4/QNX4.cs b/Aaru.Filesystems/QNX4/QNX4.cs new file mode 100644 index 000000000..f4035b0c8 --- /dev/null +++ b/Aaru.Filesystems/QNX4/QNX4.cs @@ -0,0 +1,55 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : QNX4.cs +// Author(s) : Natalia Portillo +// +// Component : QNX4 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of QNX 4 filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class QNX4 : IFilesystem +{ + // ReSharper disable once UnusedMember.Local + const string MODULE_NAME = "QNX4 plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.QNX4_Name; + + /// + public Guid Id => new("E73A63FA-B5B0-48BF-BF82-DA5F0A8170D2"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/QNX4/Structs.cs b/Aaru.Filesystems/QNX4/Structs.cs new file mode 100644 index 000000000..18166191c --- /dev/null +++ b/Aaru.Filesystems/QNX4/Structs.cs @@ -0,0 +1,125 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : QNX4 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of QNX 4 filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class QNX4 +{ +#region Nested type: Extent + +#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value + struct Extent + { + public uint Block; + public uint Length; + } +#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value + +#endregion + +#region Nested type: ExtentBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ExtentBlock + { + public readonly uint next_xblk; + public readonly uint prev_xblk; + public readonly byte num_xtnts; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] spare; + public readonly uint num_blocks; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 60)] + public readonly Extent[] xtnts; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] signature; + public readonly Extent first_xtnt; + } + +#endregion + +#region Nested type: Inode + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Inode + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] di_fname; + public readonly uint di_size; + public readonly Extent di_first_xtnt; + public readonly uint di_xblk; + public readonly uint di_ftime; + public readonly uint di_mtime; + public readonly uint di_atime; + public readonly uint di_ctime; + public readonly ushort di_num_xtnts; + public readonly ushort di_mode; + public readonly ushort di_uid; + public readonly ushort di_gid; + public readonly ushort di_nlink; + public readonly uint di_zero; + public readonly byte di_type; + public readonly byte di_status; + } + +#endregion + +#region Nested type: LinkInfo + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct LinkInfo + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] + public readonly byte[] dl_fname; + public readonly uint dl_inode_blk; + public readonly byte dl_inode_ndx; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public readonly byte[] dl_spare; + public readonly byte dl_status; + } + +#endregion + +#region Nested type: Superblock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Superblock + { + public readonly Inode rootDir; + public readonly Inode inode; + public readonly Inode boot; + public readonly Inode altBoot; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/QNX6.cs b/Aaru.Filesystems/QNX6.cs deleted file mode 100644 index b544dec77..000000000 --- a/Aaru.Filesystems/QNX6.cs +++ /dev/null @@ -1,250 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : QNX6.cs -// Author(s) : Natalia Portillo -// -// Component : QNX6 filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the QNX6 filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of QNX 6 filesystem -public sealed class QNX6 : IFilesystem -{ - const uint QNX6_SUPER_BLOCK_SIZE = 0x1000; - const uint QNX6_BOOT_BLOCKS_SIZE = 0x2000; - const uint QNX6_MAGIC = 0x68191122; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "QNX6 Plugin"; - /// - public Guid Id => new("3E610EA2-4D08-4D70-8947-830CD4C74FC0"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - uint sectors = QNX6_SUPER_BLOCK_SIZE / imagePlugin.Info.SectorSize; - uint bootSectors = QNX6_BOOT_BLOCKS_SIZE / imagePlugin.Info.SectorSize; - - if(partition.Start + bootSectors + sectors >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sectors, out byte[] audiSector); - - if(errno != ErrorNumber.NoError) - return false; - - errno = imagePlugin.ReadSectors(partition.Start + bootSectors, sectors, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < QNX6_SUPER_BLOCK_SIZE) - return false; - - AudiSuperBlock audiSb = Marshal.ByteArrayToStructureLittleEndian(audiSector); - - SuperBlock qnxSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - return qnxSb.magic == QNX6_MAGIC || audiSb.magic == QNX6_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - var sb = new StringBuilder(); - uint sectors = QNX6_SUPER_BLOCK_SIZE / imagePlugin.Info.SectorSize; - uint bootSectors = QNX6_BOOT_BLOCKS_SIZE / imagePlugin.Info.SectorSize; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sectors, out byte[] audiSector); - - if(errno != ErrorNumber.NoError) - return; - - errno = imagePlugin.ReadSectors(partition.Start + bootSectors, sectors, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < QNX6_SUPER_BLOCK_SIZE) - return; - - AudiSuperBlock audiSb = Marshal.ByteArrayToStructureLittleEndian(audiSector); - - SuperBlock qnxSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - bool audi = audiSb.magic == QNX6_MAGIC; - - if(audi) - { - sb.AppendLine("QNX6 (Audi) filesystem"); - sb.AppendFormat("Checksum: 0x{0:X8}", audiSb.checksum).AppendLine(); - sb.AppendFormat("Serial: 0x{0:X16}", audiSb.checksum).AppendLine(); - sb.AppendFormat("{0} bytes per block", audiSb.blockSize).AppendLine(); - sb.AppendFormat("{0} inodes free of {1}", audiSb.freeInodes, audiSb.numInodes).AppendLine(); - - sb.AppendFormat("{0} blocks ({1} bytes) free of {2} ({3} bytes)", audiSb.freeBlocks, - audiSb.freeBlocks * audiSb.blockSize, audiSb.numBlocks, - audiSb.numBlocks * audiSb.blockSize).AppendLine(); - - XmlFsType = new FileSystemType - { - Type = "QNX6 (Audi) filesystem", - Clusters = audiSb.numBlocks, - ClusterSize = audiSb.blockSize, - Bootable = true, - Files = audiSb.numInodes - audiSb.freeInodes, - FilesSpecified = true, - FreeClusters = audiSb.freeBlocks, - FreeClustersSpecified = true, - VolumeSerial = $"{audiSb.serial:X16}" - }; - - //xmlFSType.VolumeName = CurrentEncoding.GetString(audiSb.id); - - information = sb.ToString(); - - return; - } - - sb.AppendLine("QNX6 filesystem"); - sb.AppendFormat("Checksum: 0x{0:X8}", qnxSb.checksum).AppendLine(); - sb.AppendFormat("Serial: 0x{0:X16}", qnxSb.checksum).AppendLine(); - sb.AppendFormat("Created on {0}", DateHandlers.UnixUnsignedToDateTime(qnxSb.ctime)).AppendLine(); - sb.AppendFormat("Last mounted on {0}", DateHandlers.UnixUnsignedToDateTime(qnxSb.atime)).AppendLine(); - sb.AppendFormat("Flags: 0x{0:X8}", qnxSb.flags).AppendLine(); - sb.AppendFormat("Version1: 0x{0:X4}", qnxSb.version1).AppendLine(); - sb.AppendFormat("Version2: 0x{0:X4}", qnxSb.version2).AppendLine(); - - //sb.AppendFormat("Volume ID: \"{0}\"", CurrentEncoding.GetString(qnxSb.volumeid)).AppendLine(); - sb.AppendFormat("{0} bytes per block", qnxSb.blockSize).AppendLine(); - sb.AppendFormat("{0} inodes free of {1}", qnxSb.freeInodes, qnxSb.numInodes).AppendLine(); - - sb.AppendFormat("{0} blocks ({1} bytes) free of {2} ({3} bytes)", qnxSb.freeBlocks, - qnxSb.freeBlocks * qnxSb.blockSize, qnxSb.numBlocks, qnxSb.numBlocks * qnxSb.blockSize). - AppendLine(); - - XmlFsType = new FileSystemType - { - Type = "QNX6 filesystem", - Clusters = qnxSb.numBlocks, - ClusterSize = qnxSb.blockSize, - Bootable = true, - Files = qnxSb.numInodes - qnxSb.freeInodes, - FilesSpecified = true, - FreeClusters = qnxSb.freeBlocks, - FreeClustersSpecified = true, - VolumeSerial = $"{qnxSb.serial:X16}", - CreationDate = DateHandlers.UnixUnsignedToDateTime(qnxSb.ctime), - CreationDateSpecified = true, - ModificationDate = DateHandlers.UnixUnsignedToDateTime(qnxSb.atime), - ModificationDateSpecified = true - }; - - //xmlFSType.VolumeName = CurrentEncoding.GetString(qnxSb.volumeid); - - information = sb.ToString(); - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct RootNode - { - public readonly ulong size; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly uint[] pointers; - public readonly byte levels; - public readonly byte mode; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public readonly byte[] spare; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SuperBlock - { - public readonly uint magic; - public readonly uint checksum; - public readonly ulong serial; - public readonly uint ctime; - public readonly uint atime; - public readonly uint flags; - public readonly ushort version1; - public readonly ushort version2; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] volumeid; - public readonly uint blockSize; - public readonly uint numInodes; - public readonly uint freeInodes; - public readonly uint numBlocks; - public readonly uint freeBlocks; - public readonly uint allocationGroup; - public readonly RootNode inode; - public readonly RootNode bitmap; - public readonly RootNode longfile; - public readonly RootNode unknown; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct AudiSuperBlock - { - public readonly uint magic; - public readonly uint checksum; - public readonly ulong serial; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] spare1; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] id; - public readonly uint blockSize; - public readonly uint numInodes; - public readonly uint freeInodes; - public readonly uint numBlocks; - public readonly uint freeBlocks; - public readonly uint spare2; - public readonly RootNode inode; - public readonly RootNode bitmap; - public readonly RootNode longfile; - public readonly RootNode unknown; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/QNX6/Consts.cs b/Aaru.Filesystems/QNX6/Consts.cs new file mode 100644 index 000000000..1f0f17281 --- /dev/null +++ b/Aaru.Filesystems/QNX6/Consts.cs @@ -0,0 +1,40 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : QNX6 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of QNX 6 filesystem +public sealed partial class QNX6 +{ + const uint QNX6_SUPER_BLOCK_SIZE = 0x1000; + const uint QNX6_BOOT_BLOCKS_SIZE = 0x2000; + const uint QNX6_MAGIC = 0x68191122; + + const string FS_TYPE = "qnx6"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/QNX6/Info.cs b/Aaru.Filesystems/QNX6/Info.cs new file mode 100644 index 000000000..b013324af --- /dev/null +++ b/Aaru.Filesystems/QNX6/Info.cs @@ -0,0 +1,167 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : QNX6 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of QNX 6 filesystem +public sealed partial class QNX6 +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + uint sectors = QNX6_SUPER_BLOCK_SIZE / imagePlugin.Info.SectorSize; + uint bootSectors = QNX6_BOOT_BLOCKS_SIZE / imagePlugin.Info.SectorSize; + + if(partition.Start + bootSectors + sectors >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sectors, out byte[] audiSector); + + if(errno != ErrorNumber.NoError) return false; + + errno = imagePlugin.ReadSectors(partition.Start + bootSectors, sectors, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < QNX6_SUPER_BLOCK_SIZE) return false; + + AudiSuperBlock audiSb = Marshal.ByteArrayToStructureLittleEndian(audiSector); + + SuperBlock qnxSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + return qnxSb.magic == QNX6_MAGIC || audiSb.magic == QNX6_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + var sb = new StringBuilder(); + uint sectors = QNX6_SUPER_BLOCK_SIZE / imagePlugin.Info.SectorSize; + uint bootSectors = QNX6_BOOT_BLOCKS_SIZE / imagePlugin.Info.SectorSize; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sectors, out byte[] audiSector); + + if(errno != ErrorNumber.NoError) return; + + errno = imagePlugin.ReadSectors(partition.Start + bootSectors, sectors, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < QNX6_SUPER_BLOCK_SIZE) return; + + AudiSuperBlock audiSb = Marshal.ByteArrayToStructureLittleEndian(audiSector); + + SuperBlock qnxSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + bool audi = audiSb.magic == QNX6_MAGIC; + + if(audi) + { + sb.AppendLine(Localization.QNX6_Audi_filesystem); + sb.AppendFormat(Localization.Checksum_0_X8, audiSb.checksum).AppendLine(); + sb.AppendFormat(Localization.Serial_0_X16, audiSb.checksum).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_block, audiSb.blockSize).AppendLine(); + sb.AppendFormat(Localization._0_inodes_free_of_1, audiSb.freeInodes, audiSb.numInodes).AppendLine(); + + sb.AppendFormat(Localization._0_blocks_1_bytes_free_of_2_3_bytes, + audiSb.freeBlocks, + audiSb.freeBlocks * audiSb.blockSize, + audiSb.numBlocks, + audiSb.numBlocks * audiSb.blockSize) + .AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + Clusters = audiSb.numBlocks, + ClusterSize = audiSb.blockSize, + Bootable = true, + Files = audiSb.numInodes - audiSb.freeInodes, + FreeClusters = audiSb.freeBlocks, + VolumeSerial = $"{audiSb.serial:X16}" + }; + + //xmlFSType.VolumeName = CurrentEncoding.GetString(audiSb.id); + + information = sb.ToString(); + + return; + } + + sb.AppendLine(Localization.QNX6_filesystem); + sb.AppendFormat(Localization.Checksum_0_X8, qnxSb.checksum).AppendLine(); + sb.AppendFormat(Localization.Serial_0_X16, qnxSb.checksum).AppendLine(); + sb.AppendFormat(Localization.Created_on_0, DateHandlers.UnixUnsignedToDateTime(qnxSb.ctime)).AppendLine(); + sb.AppendFormat(Localization.Last_mounted_on_0, DateHandlers.UnixUnsignedToDateTime(qnxSb.atime)).AppendLine(); + sb.AppendFormat(Localization.Flags_0_X8, qnxSb.flags).AppendLine(); + sb.AppendFormat(Localization.Version1_0_X4, qnxSb.version1).AppendLine(); + sb.AppendFormat(Localization.Version2_0_X4, qnxSb.version2).AppendLine(); + + //sb.AppendFormat("Volume ID: \"{0}\"", CurrentEncoding.GetString(qnxSb.volumeid)).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_block, qnxSb.blockSize).AppendLine(); + sb.AppendFormat(Localization._0_inodes_free_of_1, qnxSb.freeInodes, qnxSb.numInodes).AppendLine(); + + sb.AppendFormat(Localization._0_blocks_1_bytes_free_of_2_3_bytes, + qnxSb.freeBlocks, + qnxSb.freeBlocks * qnxSb.blockSize, + qnxSb.numBlocks, + qnxSb.numBlocks * qnxSb.blockSize) + .AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + Clusters = qnxSb.numBlocks, + ClusterSize = qnxSb.blockSize, + Bootable = true, + Files = qnxSb.numInodes - qnxSb.freeInodes, + FreeClusters = qnxSb.freeBlocks, + VolumeSerial = $"{qnxSb.serial:X16}", + CreationDate = DateHandlers.UnixUnsignedToDateTime(qnxSb.ctime), + ModificationDate = DateHandlers.UnixUnsignedToDateTime(qnxSb.atime) + }; + + //xmlFSType.VolumeName = CurrentEncoding.GetString(qnxSb.volumeid); + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/QNX6/QNX6.cs b/Aaru.Filesystems/QNX6/QNX6.cs new file mode 100644 index 000000000..5ef4f2e5e --- /dev/null +++ b/Aaru.Filesystems/QNX6/QNX6.cs @@ -0,0 +1,50 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : QNX6.cs +// Author(s) : Natalia Portillo +// +// Component : QNX6 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of QNX 6 filesystem +public sealed partial class QNX6 : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.QNX6_Name; + + /// + public Guid Id => new("3E610EA2-4D08-4D70-8947-830CD4C74FC0"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/QNX6/Structs.cs b/Aaru.Filesystems/QNX6/Structs.cs new file mode 100644 index 000000000..4b82f5b8d --- /dev/null +++ b/Aaru.Filesystems/QNX6/Structs.cs @@ -0,0 +1,107 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : QNX6 filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of QNX 6 filesystem +public sealed partial class QNX6 +{ +#region Nested type: AudiSuperBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct AudiSuperBlock + { + public readonly uint magic; + public readonly uint checksum; + public readonly ulong serial; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] spare1; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] id; + public readonly uint blockSize; + public readonly uint numInodes; + public readonly uint freeInodes; + public readonly uint numBlocks; + public readonly uint freeBlocks; + public readonly uint spare2; + public readonly RootNode inode; + public readonly RootNode bitmap; + public readonly RootNode longfile; + public readonly RootNode unknown; + } + +#endregion + +#region Nested type: RootNode + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct RootNode + { + public readonly ulong size; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly uint[] pointers; + public readonly byte levels; + public readonly byte mode; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public readonly byte[] spare; + } + +#endregion + +#region Nested type: SuperBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SuperBlock + { + public readonly uint magic; + public readonly uint checksum; + public readonly ulong serial; + public readonly uint ctime; + public readonly uint atime; + public readonly uint flags; + public readonly ushort version1; + public readonly ushort version2; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] volumeid; + public readonly uint blockSize; + public readonly uint numInodes; + public readonly uint freeInodes; + public readonly uint numBlocks; + public readonly uint freeBlocks; + public readonly uint allocationGroup; + public readonly RootNode inode; + public readonly RootNode bitmap; + public readonly RootNode longfile; + public readonly RootNode unknown; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/RBF.cs b/Aaru.Filesystems/RBF.cs deleted file mode 100644 index d75a8f123..000000000 --- a/Aaru.Filesystems/RBF.cs +++ /dev/null @@ -1,405 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : RBF.cs -// Author(s) : Natalia Portillo -// -// Component : Random Block File filesystem plugin -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Random Block File filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the Locus filesystem -public sealed class RBF : IFilesystem -{ - /// Magic number for OS-9. Same for OS-9000? - const uint RBF_SYNC = 0x4372757A; - const uint RBF_CNYS = 0x7A757243; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "OS-9 Random Block File Plugin"; - /// - public Guid Id => new("E864E45B-0B52-4D29-A858-7BDFA9199FB2"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 256) - return false; - - // Documentation says ID should be sector 0 - // I've found that OS-9/X68000 has it on sector 4 - // I've read OS-9/Apple2 has it on sector 15 - foreach(int i in new[] - { - 0, 4, 15 - }) - { - var location = (ulong)i; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - if(partition.Start + location + sbSize >= imagePlugin.Info.Sectors) - break; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - IdSector rbfSb = Marshal.ByteArrayToStructureBigEndian(sector); - NewIdSector rbf9000Sb = Marshal.ByteArrayToStructureBigEndian(sector); - - AaruConsole.DebugWriteLine("RBF plugin", - "magic at {0} = 0x{1:X8} or 0x{2:X8} (expected 0x{3:X8} or 0x{4:X8})", location, - rbfSb.dd_sync, rbf9000Sb.rid_sync, RBF_SYNC, RBF_CNYS); - - if(rbfSb.dd_sync == RBF_SYNC || - rbf9000Sb.rid_sync is RBF_SYNC or RBF_CNYS) - return true; - } - - return false; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - if(imagePlugin.Info.SectorSize < 256) - return; - - var rbfSb = new IdSector(); - var rbf9000Sb = new NewIdSector(); - - foreach(int i in new[] - { - 0, 4, 15 - }) - { - var location = (ulong)i; - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < Marshal.SizeOf()) - return; - - rbfSb = Marshal.ByteArrayToStructureBigEndian(sector); - rbf9000Sb = Marshal.ByteArrayToStructureBigEndian(sector); - - AaruConsole.DebugWriteLine("RBF plugin", - "magic at {0} = 0x{1:X8} or 0x{2:X8} (expected 0x{3:X8} or 0x{4:X8})", location, - rbfSb.dd_sync, rbf9000Sb.rid_sync, RBF_SYNC, RBF_CNYS); - - if(rbfSb.dd_sync == RBF_SYNC || - rbf9000Sb.rid_sync is RBF_SYNC or RBF_CNYS) - break; - } - - if(rbfSb.dd_sync != RBF_SYNC && - rbf9000Sb.rid_sync != RBF_SYNC && - rbf9000Sb.rid_sync != RBF_CNYS) - return; - - if(rbf9000Sb.rid_sync == RBF_CNYS) - rbf9000Sb = (NewIdSector)Marshal.SwapStructureMembersEndian(rbf9000Sb); - - var sb = new StringBuilder(); - - sb.AppendLine("OS-9 Random Block File"); - - if(rbf9000Sb.rid_sync == RBF_SYNC) - { - sb.AppendFormat("Volume ID: {0:X8}", rbf9000Sb.rid_diskid).AppendLine(); - sb.AppendFormat("{0} blocks in volume", rbf9000Sb.rid_totblocks).AppendLine(); - sb.AppendFormat("{0} cylinders", rbf9000Sb.rid_cylinders).AppendLine(); - sb.AppendFormat("{0} blocks in cylinder 0", rbf9000Sb.rid_cyl0size).AppendLine(); - sb.AppendFormat("{0} blocks per cylinder", rbf9000Sb.rid_cylsize).AppendLine(); - sb.AppendFormat("{0} heads", rbf9000Sb.rid_heads).AppendLine(); - sb.AppendFormat("{0} bytes per block", rbf9000Sb.rid_blocksize).AppendLine(); - - // TODO: Convert to flags? - sb.AppendLine((rbf9000Sb.rid_format & 0x01) == 0x01 ? "Disk is double sided" : "Disk is single sided"); - - sb.AppendLine((rbf9000Sb.rid_format & 0x02) == 0x02 ? "Disk is double density" : "Disk is single density"); - - if((rbf9000Sb.rid_format & 0x10) == 0x10) - sb.AppendLine("Disk is 384 TPI"); - else if((rbf9000Sb.rid_format & 0x08) == 0x08) - sb.AppendLine("Disk is 192 TPI"); - else if((rbf9000Sb.rid_format & 0x04) == 0x04) - sb.AppendLine("Disk is 96 TPI or 135 TPI"); - else - sb.AppendLine("Disk is 48 TPI"); - - sb.AppendFormat("Allocation bitmap descriptor starts at block {0}", - rbf9000Sb.rid_bitmap == 0 ? 1 : rbf9000Sb.rid_bitmap).AppendLine(); - - if(rbf9000Sb.rid_firstboot > 0) - sb.AppendFormat("Debugger descriptor starts at block {0}", rbf9000Sb.rid_firstboot).AppendLine(); - - if(rbf9000Sb.rid_bootfile > 0) - sb.AppendFormat("Boot file descriptor starts at block {0}", rbf9000Sb.rid_bootfile).AppendLine(); - - sb.AppendFormat("Root directory descriptor starts at block {0}", rbf9000Sb.rid_rootdir).AppendLine(); - - sb.AppendFormat("Disk is owned by group {0} user {1}", rbf9000Sb.rid_group, rbf9000Sb.rid_owner). - AppendLine(); - - sb.AppendFormat("Volume was created on {0}", DateHandlers.UnixToDateTime(rbf9000Sb.rid_ctime)).AppendLine(); - - sb.AppendFormat("Volume's identification block was last written on {0}", - DateHandlers.UnixToDateTime(rbf9000Sb.rid_mtime)).AppendLine(); - - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(rbf9000Sb.rid_name, Encoding)).AppendLine(); - - XmlFsType = new FileSystemType - { - Type = "OS-9 Random Block File", - Bootable = rbf9000Sb.rid_bootfile > 0, - ClusterSize = rbf9000Sb.rid_blocksize, - Clusters = rbf9000Sb.rid_totblocks, - CreationDate = DateHandlers.UnixToDateTime(rbf9000Sb.rid_ctime), - CreationDateSpecified = true, - ModificationDate = DateHandlers.UnixToDateTime(rbf9000Sb.rid_mtime), - ModificationDateSpecified = true, - VolumeName = StringHandlers.CToString(rbf9000Sb.rid_name, Encoding), - VolumeSerial = $"{rbf9000Sb.rid_diskid:X8}" - }; - } - else - { - sb.AppendFormat("Volume ID: {0:X4}", rbfSb.dd_dsk).AppendLine(); - sb.AppendFormat("{0} blocks in volume", LSNToUInt32(rbfSb.dd_tot)).AppendLine(); - sb.AppendFormat("{0} tracks", rbfSb.dd_tks).AppendLine(); - sb.AppendFormat("{0} sectors per track", rbfSb.dd_spt).AppendLine(); - sb.AppendFormat("{0} bytes per sector", 256 << rbfSb.dd_lsnsize).AppendLine(); - - sb.AppendFormat("{0} sectors per cluster ({1} bytes)", rbfSb.dd_bit, - rbfSb.dd_bit * (256 << rbfSb.dd_lsnsize)).AppendLine(); - - // TODO: Convert to flags? - sb.AppendLine((rbfSb.dd_fmt & 0x01) == 0x01 ? "Disk is double sided" : "Disk is single sided"); - sb.AppendLine((rbfSb.dd_fmt & 0x02) == 0x02 ? "Disk is double density" : "Disk is single density"); - - if((rbfSb.dd_fmt & 0x10) == 0x10) - sb.AppendLine("Disk is 384 TPI"); - else if((rbfSb.dd_fmt & 0x08) == 0x08) - sb.AppendLine("Disk is 192 TPI"); - else if((rbfSb.dd_fmt & 0x04) == 0x04) - sb.AppendLine("Disk is 96 TPI or 135 TPI"); - else - sb.AppendLine("Disk is 48 TPI"); - - sb.AppendFormat("Allocation bitmap descriptor starts at block {0}", - rbfSb.dd_maplsn == 0 ? 1 : rbfSb.dd_maplsn).AppendLine(); - - sb.AppendFormat("{0} bytes in allocation bitmap", rbfSb.dd_map).AppendLine(); - - if(LSNToUInt32(rbfSb.dd_bt) > 0 && - rbfSb.dd_bsz > 0) - sb.AppendFormat("Boot file starts at block {0} and has {1} bytes", LSNToUInt32(rbfSb.dd_bt), - rbfSb.dd_bsz).AppendLine(); - - sb.AppendFormat("Root directory descriptor starts at block {0}", LSNToUInt32(rbfSb.dd_dir)).AppendLine(); - - sb.AppendFormat("Disk is owned by user {0}", rbfSb.dd_own).AppendLine(); - sb.AppendFormat("Volume was created on {0}", DateHandlers.Os9ToDateTime(rbfSb.dd_dat)).AppendLine(); - sb.AppendFormat("Volume attributes: {0:X2}", rbfSb.dd_att).AppendLine(); - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(rbfSb.dd_nam, Encoding)).AppendLine(); - - sb.AppendFormat("Path descriptor options: {0}", StringHandlers.CToString(rbfSb.dd_opt, Encoding)). - AppendLine(); - - XmlFsType = new FileSystemType - { - Type = "OS-9 Random Block File", - Bootable = LSNToUInt32(rbfSb.dd_bt) > 0 && rbfSb.dd_bsz > 0, - ClusterSize = (uint)(rbfSb.dd_bit * (256 << rbfSb.dd_lsnsize)), - Clusters = LSNToUInt32(rbfSb.dd_tot), - CreationDate = DateHandlers.Os9ToDateTime(rbfSb.dd_dat), - CreationDateSpecified = true, - VolumeName = StringHandlers.CToString(rbfSb.dd_nam, Encoding), - VolumeSerial = $"{rbfSb.dd_dsk:X4}" - }; - } - - information = sb.ToString(); - } - - static uint LSNToUInt32(byte[] lsn) - { - if(lsn == null || - lsn.Length != 3) - return 0; - - return (uint)((lsn[0] << 16) + (lsn[1] << 8) + lsn[2]); - } - - /// Identification sector. Wherever the sector this resides on, becomes LSN 0. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct IdSector - { - /// Sectors on disk - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] dd_tot; - /// Tracks - public readonly byte dd_tks; - /// Bytes in allocation map - public readonly ushort dd_map; - /// Sectors per cluster - public readonly ushort dd_bit; - /// LSN of root directory - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] dd_dir; - /// Owner ID - public readonly ushort dd_own; - /// Attributes - public readonly byte dd_att; - /// Disk ID - public readonly ushort dd_dsk; - /// Format byte - public readonly byte dd_fmt; - /// Sectors per track - public readonly ushort dd_spt; - /// Reserved - public readonly ushort dd_res; - /// LSN of boot file - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] dd_bt; - /// Size of boot file - public readonly ushort dd_bsz; - /// Creation date - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public readonly byte[] dd_dat; - /// Volume name - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] dd_nam; - /// Path options - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] dd_opt; - /// Reserved - public readonly byte reserved; - /// Magic number - public readonly uint dd_sync; - /// LSN of allocation map - public readonly uint dd_maplsn; - /// Size of an LSN - public readonly ushort dd_lsnsize; - /// Version ID - public readonly ushort dd_versid; - } - - /// - /// Identification sector. Wherever the sector this resides on, becomes LSN 0. Introduced on OS-9000, this can be - /// big or little endian. - /// - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct NewIdSector - { - /// Magic number - public readonly uint rid_sync; - /// Disk ID - public readonly uint rid_diskid; - /// Sectors on disk - public readonly uint rid_totblocks; - /// Cylinders - public readonly ushort rid_cylinders; - /// Sectors in cylinder 0 - public readonly ushort rid_cyl0size; - /// Sectors per cylinder - public readonly ushort rid_cylsize; - /// Heads - public readonly ushort rid_heads; - /// Bytes per sector - public readonly ushort rid_blocksize; - /// Disk format - public readonly ushort rid_format; - /// Flags - public readonly ushort rid_flags; - /// Padding - public readonly ushort rid_unused1; - /// Sector of allocation bitmap - public readonly uint rid_bitmap; - /// Sector of debugger FD - public readonly uint rid_firstboot; - /// Sector of bootfile FD - public readonly uint rid_bootfile; - /// Sector of root directory FD - public readonly uint rid_rootdir; - /// Group owner of media - public readonly ushort rid_group; - /// Owner of media - public readonly ushort rid_owner; - /// Creation time - public readonly uint rid_ctime; - /// Last write time for this structure - public readonly uint rid_mtime; - /// Volume name - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] rid_name; - /// Endian flag - public readonly byte rid_endflag; - /// Padding - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] rid_unused2; - /// Parity - public readonly uint rid_parity; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/RBF/Consts.cs b/Aaru.Filesystems/RBF/Consts.cs new file mode 100644 index 000000000..a8edef8bc --- /dev/null +++ b/Aaru.Filesystems/RBF/Consts.cs @@ -0,0 +1,40 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Random Block File filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Locus filesystem +public sealed partial class RBF +{ + /// Magic number for OS-9. Same for OS-9000? + const uint RBF_SYNC = 0x4372757A; + const uint RBF_CNYS = 0x7A757243; + + const string FS_TYPE = "rbf"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/RBF/Helpers.cs b/Aaru.Filesystems/RBF/Helpers.cs new file mode 100644 index 000000000..5f259e71d --- /dev/null +++ b/Aaru.Filesystems/RBF/Helpers.cs @@ -0,0 +1,41 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Helpers.cs +// Author(s) : Natalia Portillo +// +// Component : Random Block File filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Locus filesystem +public sealed partial class RBF +{ + static uint LSNToUInt32(byte[] lsn) + { + if(lsn is not { Length: 3 }) return 0; + + return (uint)((lsn[0] << 16) + (lsn[1] << 8) + lsn[2]); + } +} \ No newline at end of file diff --git a/Aaru.Filesystems/RBF/Info.cs b/Aaru.Filesystems/RBF/Info.cs new file mode 100644 index 000000000..0d9f60888 --- /dev/null +++ b/Aaru.Filesystems/RBF/Info.cs @@ -0,0 +1,287 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Random Block File filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Locus filesystem +public sealed partial class RBF +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 256) return false; + + // Documentation says ID should be sector 0 + // I've found that OS-9/X68000 has it on sector 4 + // I've read OS-9/Apple2 has it on sector 15 + foreach(int i in new[] + { + 0, 4, 15 + }) + { + var location = (ulong)i; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + if(partition.Start + location + sbSize >= imagePlugin.Info.Sectors) break; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + IdSector rbfSb = Marshal.ByteArrayToStructureBigEndian(sector); + NewIdSector rbf9000Sb = Marshal.ByteArrayToStructureBigEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.magic_at_0_equals_1_or_2_expected_3_or_4, + location, + rbfSb.dd_sync, + rbf9000Sb.rid_sync, + RBF_SYNC, + RBF_CNYS); + + if(rbfSb.dd_sync == RBF_SYNC || rbf9000Sb.rid_sync is RBF_SYNC or RBF_CNYS) return true; + } + + return false; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize < 256) return; + + var rbfSb = new IdSector(); + var rbf9000Sb = new NewIdSector(); + + foreach(int i in new[] + { + 0, 4, 15 + }) + { + var location = (ulong)i; + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < Marshal.SizeOf()) return; + + rbfSb = Marshal.ByteArrayToStructureBigEndian(sector); + rbf9000Sb = Marshal.ByteArrayToStructureBigEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.magic_at_0_equals_1_or_2_expected_3_or_4, + location, + rbfSb.dd_sync, + rbf9000Sb.rid_sync, + RBF_SYNC, + RBF_CNYS); + + if(rbfSb.dd_sync == RBF_SYNC || rbf9000Sb.rid_sync is RBF_SYNC or RBF_CNYS) break; + } + + if(rbfSb.dd_sync != RBF_SYNC && rbf9000Sb.rid_sync != RBF_SYNC && rbf9000Sb.rid_sync != RBF_CNYS) return; + + if(rbf9000Sb.rid_sync == RBF_CNYS) rbf9000Sb = (NewIdSector)Marshal.SwapStructureMembersEndian(rbf9000Sb); + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.OS_9_Random_Block_File); + + if(rbf9000Sb.rid_sync == RBF_SYNC) + { + sb.AppendFormat(Localization.Volume_ID_0_X8, rbf9000Sb.rid_diskid).AppendLine(); + sb.AppendFormat(Localization._0_blocks_in_volume, rbf9000Sb.rid_totblocks).AppendLine(); + sb.AppendFormat(Localization._0_cylinders, rbf9000Sb.rid_cylinders).AppendLine(); + sb.AppendFormat(Localization._0_blocks_in_cylinder_zero, rbf9000Sb.rid_cyl0size).AppendLine(); + sb.AppendFormat(Localization._0_blocks_per_cylinder, rbf9000Sb.rid_cylsize).AppendLine(); + sb.AppendFormat(Localization._0_heads, rbf9000Sb.rid_heads).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_block, rbf9000Sb.rid_blocksize).AppendLine(); + + // TODO: Convert to flags? + sb.AppendLine((rbf9000Sb.rid_format & 0x01) == 0x01 + ? Localization.Disk_is_double_sided + : Localization.Disk_is_single_sided); + + sb.AppendLine((rbf9000Sb.rid_format & 0x02) == 0x02 + ? Localization.Disk_is_double_density + : Localization.Disk_is_single_density); + + if((rbf9000Sb.rid_format & 0x10) == 0x10) + sb.AppendLine(Localization.Disk_is_384_TPI); + else if((rbf9000Sb.rid_format & 0x08) == 0x08) + sb.AppendLine(Localization.Disk_is_192_TPI); + else if((rbf9000Sb.rid_format & 0x04) == 0x04) + sb.AppendLine(Localization.Disk_is_96_TPI_or_135_TPI); + else + sb.AppendLine(Localization.Disk_is_48_TPI); + + sb.AppendFormat(Localization.Allocation_bitmap_descriptor_starts_at_block_0, + rbf9000Sb.rid_bitmap == 0 ? 1 : rbf9000Sb.rid_bitmap) + .AppendLine(); + + if(rbf9000Sb.rid_firstboot > 0) + { + sb.AppendFormat(Localization.Debugger_descriptor_starts_at_block_0, rbf9000Sb.rid_firstboot) + .AppendLine(); + } + + if(rbf9000Sb.rid_bootfile > 0) + { + sb.AppendFormat(Localization.Boot_file_descriptor_starts_at_block_0, rbf9000Sb.rid_bootfile) + .AppendLine(); + } + + sb.AppendFormat(Localization.Root_directory_descriptor_starts_at_block_0, rbf9000Sb.rid_rootdir) + .AppendLine(); + + sb.AppendFormat(Localization.Disk_is_owned_by_group_0_user_1, rbf9000Sb.rid_group, rbf9000Sb.rid_owner) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_was_created_on_0, DateHandlers.UnixToDateTime(rbf9000Sb.rid_ctime)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_identification_block_was_last_written_on_0, + DateHandlers.UnixToDateTime(rbf9000Sb.rid_mtime)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(rbf9000Sb.rid_name, encoding)) + .AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + Bootable = rbf9000Sb.rid_bootfile > 0, + ClusterSize = rbf9000Sb.rid_blocksize, + Clusters = rbf9000Sb.rid_totblocks, + CreationDate = DateHandlers.UnixToDateTime(rbf9000Sb.rid_ctime), + ModificationDate = DateHandlers.UnixToDateTime(rbf9000Sb.rid_mtime), + VolumeName = StringHandlers.CToString(rbf9000Sb.rid_name, encoding), + VolumeSerial = $"{rbf9000Sb.rid_diskid:X8}" + }; + } + else + { + sb.AppendFormat(Localization.Volume_ID_0_X4, rbfSb.dd_dsk).AppendLine(); + sb.AppendFormat(Localization._0_blocks_in_volume, LSNToUInt32(rbfSb.dd_tot)).AppendLine(); + sb.AppendFormat(Localization._0_tracks, rbfSb.dd_tks).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_track, rbfSb.dd_spt).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector, 256 << rbfSb.dd_lsnsize).AppendLine(); + + sb.AppendFormat(Localization._0_sectors_per_cluster_1_bytes, + rbfSb.dd_bit, + rbfSb.dd_bit * (256 << rbfSb.dd_lsnsize)) + .AppendLine(); + + // TODO: Convert to flags? + sb.AppendLine((rbfSb.dd_fmt & 0x01) == 0x01 + ? Localization.Disk_is_double_sided + : Localization.Disk_is_single_sided); + + sb.AppendLine((rbfSb.dd_fmt & 0x02) == 0x02 + ? Localization.Disk_is_double_density + : Localization.Disk_is_single_density); + + if((rbfSb.dd_fmt & 0x10) == 0x10) + sb.AppendLine(Localization.Disk_is_384_TPI); + else if((rbfSb.dd_fmt & 0x08) == 0x08) + sb.AppendLine(Localization.Disk_is_192_TPI); + else if((rbfSb.dd_fmt & 0x04) == 0x04) + sb.AppendLine(Localization.Disk_is_96_TPI_or_135_TPI); + else + sb.AppendLine(Localization.Disk_is_48_TPI); + + sb.AppendFormat(Localization.Allocation_bitmap_descriptor_starts_at_block_0, + rbfSb.dd_maplsn == 0 ? 1 : rbfSb.dd_maplsn) + .AppendLine(); + + sb.AppendFormat(Localization._0_bytes_in_allocation_bitmap, rbfSb.dd_map).AppendLine(); + + if(LSNToUInt32(rbfSb.dd_bt) > 0 && rbfSb.dd_bsz > 0) + { + sb.AppendFormat(Localization.Boot_file_starts_at_block_0_and_has_1_bytes, + LSNToUInt32(rbfSb.dd_bt), + rbfSb.dd_bsz) + .AppendLine(); + } + + sb.AppendFormat(Localization.Root_directory_descriptor_starts_at_block_0, LSNToUInt32(rbfSb.dd_dir)) + .AppendLine(); + + sb.AppendFormat(Localization.Disk_is_owned_by_user_0, rbfSb.dd_own).AppendLine(); + + sb.AppendFormat(Localization.Volume_was_created_on_0, DateHandlers.Os9ToDateTime(rbfSb.dd_dat)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_attributes_0, rbfSb.dd_att).AppendLine(); + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(rbfSb.dd_nam, encoding)).AppendLine(); + + sb.AppendFormat(Localization.Path_descriptor_options_0, StringHandlers.CToString(rbfSb.dd_opt, encoding)) + .AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + Bootable = LSNToUInt32(rbfSb.dd_bt) > 0 && rbfSb.dd_bsz > 0, + ClusterSize = (uint)(rbfSb.dd_bit * (256 << rbfSb.dd_lsnsize)), + Clusters = LSNToUInt32(rbfSb.dd_tot), + CreationDate = DateHandlers.Os9ToDateTime(rbfSb.dd_dat), + VolumeName = StringHandlers.CToString(rbfSb.dd_nam, encoding), + VolumeSerial = $"{rbfSb.dd_dsk:X4}" + }; + } + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/RBF/RBF.cs b/Aaru.Filesystems/RBF/RBF.cs new file mode 100644 index 000000000..dc5a51e01 --- /dev/null +++ b/Aaru.Filesystems/RBF/RBF.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : RBF.cs +// Author(s) : Natalia Portillo +// +// Component : Random Block File filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Locus filesystem +public sealed partial class RBF : IFilesystem +{ + const string MODULE_NAME = "RBF plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.RBF_Name; + + /// + public Guid Id => new("E864E45B-0B52-4D29-A858-7BDFA9199FB2"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/RBF/Structs.cs b/Aaru.Filesystems/RBF/Structs.cs new file mode 100644 index 000000000..77bd07467 --- /dev/null +++ b/Aaru.Filesystems/RBF/Structs.cs @@ -0,0 +1,155 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Random Block File filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Locus filesystem +public sealed partial class RBF +{ +#region Nested type: IdSector + + /// Identification sector. Wherever the sector this resides on, becomes LSN 0. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct IdSector + { + /// Sectors on disk + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] dd_tot; + /// Tracks + public readonly byte dd_tks; + /// Bytes in allocation map + public readonly ushort dd_map; + /// Sectors per cluster + public readonly ushort dd_bit; + /// LSN of root directory + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] dd_dir; + /// Owner ID + public readonly ushort dd_own; + /// Attributes + public readonly byte dd_att; + /// Disk ID + public readonly ushort dd_dsk; + /// Format byte + public readonly byte dd_fmt; + /// Sectors per track + public readonly ushort dd_spt; + /// Reserved + public readonly ushort dd_res; + /// LSN of boot file + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] dd_bt; + /// Size of boot file + public readonly ushort dd_bsz; + /// Creation date + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public readonly byte[] dd_dat; + /// Volume name + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] dd_nam; + /// Path options + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] dd_opt; + /// Reserved + public readonly byte reserved; + /// Magic number + public readonly uint dd_sync; + /// LSN of allocation map + public readonly uint dd_maplsn; + /// Size of an LSN + public readonly ushort dd_lsnsize; + /// Version ID + public readonly ushort dd_versid; + } + +#endregion + +#region Nested type: NewIdSector + + /// + /// Identification sector. Wherever the sector this resides on, becomes LSN 0. Introduced on OS-9000, this can be + /// big or little endian. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct NewIdSector + { + /// Magic number + public readonly uint rid_sync; + /// Disk ID + public readonly uint rid_diskid; + /// Sectors on disk + public readonly uint rid_totblocks; + /// Cylinders + public readonly ushort rid_cylinders; + /// Sectors in cylinder 0 + public readonly ushort rid_cyl0size; + /// Sectors per cylinder + public readonly ushort rid_cylsize; + /// Heads + public readonly ushort rid_heads; + /// Bytes per sector + public readonly ushort rid_blocksize; + /// Disk format + public readonly ushort rid_format; + /// Flags + public readonly ushort rid_flags; + /// Padding + public readonly ushort rid_unused1; + /// Sector of allocation bitmap + public readonly uint rid_bitmap; + /// Sector of debugger FD + public readonly uint rid_firstboot; + /// Sector of bootfile FD + public readonly uint rid_bootfile; + /// Sector of root directory FD + public readonly uint rid_rootdir; + /// Group owner of media + public readonly ushort rid_group; + /// Owner of media + public readonly ushort rid_owner; + /// Creation time + public readonly uint rid_ctime; + /// Last write time for this structure + public readonly uint rid_mtime; + /// Volume name + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] rid_name; + /// Endian flag + public readonly byte rid_endflag; + /// Padding + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] rid_unused2; + /// Parity + public readonly uint rid_parity; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/RT11/Consts.cs b/Aaru.Filesystems/RT11/Consts.cs new file mode 100644 index 000000000..9f779ea7a --- /dev/null +++ b/Aaru.Filesystems/RT11/Consts.cs @@ -0,0 +1,41 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : RT-11 file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the RT-11 file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Information from http://www.trailing-edge.com/~shoppa/rt11fs/ +/// +/// Implements detection of the DEC RT-11 filesystem +public sealed partial class RT11 +{ + const string FS_TYPE = "rt11"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/RT11/Info.cs b/Aaru.Filesystems/RT11/Info.cs new file mode 100644 index 000000000..7b0daf403 --- /dev/null +++ b/Aaru.Filesystems/RT11/Info.cs @@ -0,0 +1,126 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : RT-11 file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the RT-11 file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Claunia.Encoding; +using Encoding = System.Text.Encoding; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from http://www.trailing-edge.com/~shoppa/rt11fs/ +/// +/// Implements detection of the DEC RT-11 filesystem +public sealed partial class RT11 +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(1 + partition.Start >= partition.End) return false; + + var magicB = new byte[12]; + ErrorNumber errno = imagePlugin.ReadSector(1 + partition.Start, out byte[] hbSector); + + if(errno != ErrorNumber.NoError) return false; + + if(hbSector.Length < 512) return false; + + Array.Copy(hbSector, 0x1F0, magicB, 0, 12); + string magic = Encoding.ASCII.GetString(magicB); + + return magic == "DECRT11A "; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding = new Radix50(); + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + ErrorNumber errno = imagePlugin.ReadSector(1 + partition.Start, out byte[] hbSector); + + if(errno != ErrorNumber.NoError) return; + + HomeBlock homeblock = Marshal.ByteArrayToStructureLittleEndian(hbSector); + + /* TODO: Is this correct? + * Assembler: + * MOV address, R0 + * CLR R1 + * MOV #255., R2 + * 10$: ADD (R0)+, R1 + * SOB R2, 10$ + * MOV 1,@R0 + */ + ushort check = 0; + + for(var i = 0; i < 512; i += 2) check += BitConverter.ToUInt16(hbSector, i); + + sb.AppendFormat(Localization.Volume_format_is_0, + StringHandlers.SpacePaddedToString(homeblock.format, Encoding.ASCII)) + .AppendLine(); + + sb.AppendFormat(Localization._0_sectors_per_cluster_1_bytes, homeblock.cluster, homeblock.cluster * 512) + .AppendLine(); + + sb.AppendFormat(Localization.First_directory_segment_starts_at_block_0, homeblock.rootBlock).AppendLine(); + sb.AppendFormat(Localization.Volume_owner_is_0, encoding.GetString(homeblock.ownername).TrimEnd()).AppendLine(); + sb.AppendFormat(Localization.Volume_label_0, encoding.GetString(homeblock.volname).TrimEnd()).AppendLine(); + sb.AppendFormat(Localization.Checksum_0_calculated_1, homeblock.checksum, check).AppendLine(); + + imagePlugin.ReadSector(0, out byte[] bootBlock); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = (uint)(homeblock.cluster * 512), + Clusters = homeblock.cluster, + VolumeName = StringHandlers.SpacePaddedToString(homeblock.volname, encoding), + Bootable = !ArrayHelpers.ArrayIsNullOrEmpty(bootBlock) + }; + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/RT11/RT11.cs b/Aaru.Filesystems/RT11/RT11.cs new file mode 100644 index 000000000..e68710b4c --- /dev/null +++ b/Aaru.Filesystems/RT11/RT11.cs @@ -0,0 +1,55 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : RT11.cs +// Author(s) : Natalia Portillo +// +// Component : RT-11 file system plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the RT-11 file system and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from http://www.trailing-edge.com/~shoppa/rt11fs/ +/// +/// Implements detection of the DEC RT-11 filesystem +public sealed partial class RT11 : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.RT11_Name; + + /// + public Guid Id => new("DB3E2F98-8F98-463C-8126-E937843DA024"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/RT11.cs b/Aaru.Filesystems/RT11/Structs.cs similarity index 53% rename from Aaru.Filesystems/RT11.cs rename to Aaru.Filesystems/RT11/Structs.cs index 2a8409e5c..4a8c47df3 100644 --- a/Aaru.Filesystems/RT11.cs +++ b/Aaru.Filesystems/RT11/Structs.cs @@ -2,7 +2,7 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : RT11.cs +// Filename : Structs.cs // Author(s) : Natalia Portillo // // Component : RT-11 file system plugin. @@ -27,112 +27,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - -using System; using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Claunia.Encoding; -using Schemas; -using Encoding = System.Text.Encoding; -using Marshal = Aaru.Helpers.Marshal; + +namespace Aaru.Filesystems; // Information from http://www.trailing-edge.com/~shoppa/rt11fs/ /// /// Implements detection of the DEC RT-11 filesystem -public sealed class RT11 : IFilesystem +public sealed partial class RT11 { - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "RT-11 file system"; - /// - public Guid Id => new("DB3E2F98-8F98-463C-8126-E937843DA024"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(1 + partition.Start >= partition.End) - return false; - - var magicB = new byte[12]; - ErrorNumber errno = imagePlugin.ReadSector(1 + partition.Start, out byte[] hbSector); - - if(errno != ErrorNumber.NoError) - return false; - - if(hbSector.Length < 512) - return false; - - Array.Copy(hbSector, 0x1F0, magicB, 0, 12); - string magic = Encoding.ASCII.GetString(magicB); - - return magic == "DECRT11A "; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = new Radix50(); - information = ""; - - var sb = new StringBuilder(); - - ErrorNumber errno = imagePlugin.ReadSector(1 + partition.Start, out byte[] hbSector); - - if(errno != ErrorNumber.NoError) - return; - - HomeBlock homeblock = Marshal.ByteArrayToStructureLittleEndian(hbSector); - - /* TODO: Is this correct? - * Assembler: - * MOV address, R0 - * CLR R1 - * MOV #255., R2 - * 10$: ADD (R0)+, R1 - * SOB R2, 10$ - * MOV 1,@R0 - */ - ushort check = 0; - - for(var i = 0; i < 512; i += 2) - check += BitConverter.ToUInt16(hbSector, i); - - sb.AppendFormat("Volume format is {0}", StringHandlers.SpacePaddedToString(homeblock.format, Encoding.ASCII)). - AppendLine(); - - sb.AppendFormat("{0} sectors per cluster ({1} bytes)", homeblock.cluster, homeblock.cluster * 512).AppendLine(); - - sb.AppendFormat("First directory segment starts at block {0}", homeblock.rootBlock).AppendLine(); - sb.AppendFormat("Volume owner is \"{0}\"", Encoding.GetString(homeblock.ownername).TrimEnd()).AppendLine(); - sb.AppendFormat("Volume label: \"{0}\"", Encoding.GetString(homeblock.volname).TrimEnd()).AppendLine(); - sb.AppendFormat("Checksum: 0x{0:X4} (calculated 0x{1:X4})", homeblock.checksum, check).AppendLine(); - - imagePlugin.ReadSector(0, out byte[] bootBlock); - - XmlFsType = new FileSystemType - { - Type = "RT-11", - ClusterSize = (uint)(homeblock.cluster * 512), - Clusters = homeblock.cluster, - VolumeName = StringHandlers.SpacePaddedToString(homeblock.volname, Encoding), - Bootable = !ArrayHelpers.ArrayIsNullOrEmpty(bootBlock) - }; - - information = sb.ToString(); - } +#region Nested type: HomeBlock [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct HomeBlock @@ -181,4 +88,6 @@ public sealed class RT11 : IFilesystem /// Checksum of preceding 255 words (16 bit units) public readonly ushort checksum; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/ReFS.cs b/Aaru.Filesystems/ReFS.cs deleted file mode 100644 index b0c61764f..000000000 --- a/Aaru.Filesystems/ReFS.cs +++ /dev/null @@ -1,191 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : ReFS.cs -// Author(s) : Natalia Portillo -// -// Component : Resilient File System plugin -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Resilient File System and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of Microsoft's Resilient filesystem (ReFS) -public sealed class ReFS : IFilesystem -{ - const uint FSRS = 0x53525346; - readonly byte[] _signature = - { - 0x52, 0x65, 0x46, 0x53, 0x00, 0x00, 0x00, 0x00 - }; - /// - public string Name => "Resilient File System plugin"; - /// - public Guid Id => new("37766C4E-EBF5-4113-A712-B758B756ABD6"); - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - if(partition.Start + sbSize >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - VolumeHeader vhdr = Marshal.ByteArrayToStructureLittleEndian(sector); - - return vhdr.identifier == FSRS && ArrayHelpers.ArrayIsNullOrEmpty(vhdr.mustBeZero) && - vhdr.signature.SequenceEqual(_signature); - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = Encoding.UTF8; - information = ""; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - if(partition.Start + sbSize >= partition.End) - return; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < Marshal.SizeOf()) - return; - - VolumeHeader vhdr = Marshal.ByteArrayToStructureLittleEndian(sector); - - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.jump empty? = {0}", - ArrayHelpers.ArrayIsNullOrEmpty(vhdr.jump)); - - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.signature = {0}", - StringHandlers.CToString(vhdr.signature)); - - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.mustBeZero empty? = {0}", - ArrayHelpers.ArrayIsNullOrEmpty(vhdr.mustBeZero)); - - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.identifier = {0}", - StringHandlers.CToString(BitConverter.GetBytes(vhdr.identifier))); - - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.length = {0}", vhdr.length); - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.checksum = 0x{0:X4}", vhdr.checksum); - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.sectors = {0}", vhdr.sectors); - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.bytesPerSector = {0}", vhdr.bytesPerSector); - - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.sectorsPerCluster = {0}", vhdr.sectorsPerCluster); - - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown1 zero? = {0}", vhdr.unknown1 == 0); - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown2 zero? = {0}", vhdr.unknown2 == 0); - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown3 zero? = {0}", vhdr.unknown3 == 0); - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown4 zero? = {0}", vhdr.unknown4 == 0); - - AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown5 empty? = {0}", - ArrayHelpers.ArrayIsNullOrEmpty(vhdr.unknown5)); - - if(vhdr.identifier != FSRS || - !ArrayHelpers.ArrayIsNullOrEmpty(vhdr.mustBeZero) || - !vhdr.signature.SequenceEqual(_signature)) - return; - - var sb = new StringBuilder(); - - sb.AppendLine("Microsoft Resilient File System"); - sb.AppendFormat("Volume uses {0} bytes per sector", vhdr.bytesPerSector).AppendLine(); - - sb.AppendFormat("Volume uses {0} sectors per cluster ({1} bytes)", vhdr.sectorsPerCluster, - vhdr.sectorsPerCluster * vhdr.bytesPerSector).AppendLine(); - - sb.AppendFormat("Volume has {0} sectors ({1} bytes)", vhdr.sectors, vhdr.sectors * vhdr.bytesPerSector). - AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Type = "Resilient File System", - ClusterSize = vhdr.bytesPerSector * vhdr.sectorsPerCluster, - Clusters = vhdr.sectors / vhdr.sectorsPerCluster - }; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct VolumeHeader - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] signature; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public readonly byte[] mustBeZero; - public readonly uint identifier; - public readonly ushort length; - public readonly ushort checksum; - public readonly ulong sectors; - public readonly uint bytesPerSector; - public readonly uint sectorsPerCluster; - public readonly uint unknown1; - public readonly uint unknown2; - public readonly ulong unknown3; - public readonly ulong unknown4; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15872)] - public readonly byte[] unknown5; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/ReFS/Consts.cs b/Aaru.Filesystems/ReFS/Consts.cs new file mode 100644 index 000000000..35dd85e3d --- /dev/null +++ b/Aaru.Filesystems/ReFS/Consts.cs @@ -0,0 +1,39 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Resilient File System plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Microsoft's Resilient filesystem (ReFS) +public sealed partial class ReFS +{ + const uint FSRS = 0x53525346; + + const string FS_TYPE = "refs"; + readonly byte[] _signature = [0x52, 0x65, 0x46, 0x53, 0x00, 0x00, 0x00, 0x00]; +} \ No newline at end of file diff --git a/Aaru.Filesystems/ReFS/Info.cs b/Aaru.Filesystems/ReFS/Info.cs new file mode 100644 index 000000000..2bb4b0eea --- /dev/null +++ b/Aaru.Filesystems/ReFS/Info.cs @@ -0,0 +1,151 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Resilient File System plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Microsoft's Resilient filesystem (ReFS) +public sealed partial class ReFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + if(partition.Start + sbSize >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + VolumeHeader vhdr = Marshal.ByteArrayToStructureLittleEndian(sector); + + return vhdr.identifier == FSRS && + ArrayHelpers.ArrayIsNullOrEmpty(vhdr.mustBeZero) && + vhdr.signature.SequenceEqual(_signature); + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + if(partition.Start + sbSize >= partition.End) return; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < Marshal.SizeOf()) return; + + VolumeHeader vhdr = Marshal.ByteArrayToStructureLittleEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "VolumeHeader.jump empty? = {0}", + ArrayHelpers.ArrayIsNullOrEmpty(vhdr.jump)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "VolumeHeader.signature = {0}", + StringHandlers.CToString(vhdr.signature)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "VolumeHeader.mustBeZero empty? = {0}", + ArrayHelpers.ArrayIsNullOrEmpty(vhdr.mustBeZero)); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "VolumeHeader.identifier = {0}", + StringHandlers.CToString(BitConverter.GetBytes(vhdr.identifier))); + + AaruConsole.DebugWriteLine(MODULE_NAME, "VolumeHeader.length = {0}", vhdr.length); + AaruConsole.DebugWriteLine(MODULE_NAME, "VolumeHeader.checksum = 0x{0:X4}", vhdr.checksum); + AaruConsole.DebugWriteLine(MODULE_NAME, "VolumeHeader.sectors = {0}", vhdr.sectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "VolumeHeader.bytesPerSector = {0}", vhdr.bytesPerSector); + + AaruConsole.DebugWriteLine(MODULE_NAME, "VolumeHeader.sectorsPerCluster = {0}", vhdr.sectorsPerCluster); + + AaruConsole.DebugWriteLine(MODULE_NAME, "VolumeHeader.unknown1 zero? = {0}", vhdr.unknown1 == 0); + AaruConsole.DebugWriteLine(MODULE_NAME, "VolumeHeader.unknown2 zero? = {0}", vhdr.unknown2 == 0); + AaruConsole.DebugWriteLine(MODULE_NAME, "VolumeHeader.unknown3 zero? = {0}", vhdr.unknown3 == 0); + AaruConsole.DebugWriteLine(MODULE_NAME, "VolumeHeader.unknown4 zero? = {0}", vhdr.unknown4 == 0); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "VolumeHeader.unknown5 empty? = {0}", + ArrayHelpers.ArrayIsNullOrEmpty(vhdr.unknown5)); + + if(vhdr.identifier != FSRS || + !ArrayHelpers.ArrayIsNullOrEmpty(vhdr.mustBeZero) || + !vhdr.signature.SequenceEqual(_signature)) + return; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.Microsoft_Resilient_File_System); + sb.AppendFormat(Localization.Volume_uses_0_bytes_per_sector, vhdr.bytesPerSector).AppendLine(); + + sb.AppendFormat(Localization.Volume_uses_0_sectors_per_cluster_1_bytes, + vhdr.sectorsPerCluster, + vhdr.sectorsPerCluster * vhdr.bytesPerSector) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_has_0_sectors_1_bytes, vhdr.sectors, vhdr.sectors * vhdr.bytesPerSector) + .AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = vhdr.bytesPerSector * vhdr.sectorsPerCluster, + Clusters = vhdr.sectors / vhdr.sectorsPerCluster + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ReFS/ReFS.cs b/Aaru.Filesystems/ReFS/ReFS.cs new file mode 100644 index 000000000..67d1146d2 --- /dev/null +++ b/Aaru.Filesystems/ReFS/ReFS.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ReFS.cs +// Author(s) : Natalia Portillo +// +// Component : Resilient File System plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Microsoft's Resilient filesystem (ReFS) +public sealed partial class ReFS : IFilesystem +{ + const string MODULE_NAME = "ReFS plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.ReFS_Name; + + /// + public Guid Id => new("37766C4E-EBF5-4113-A712-B758B756ABD6"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ReFS/Structs.cs b/Aaru.Filesystems/ReFS/Structs.cs new file mode 100644 index 000000000..6ddcba522 --- /dev/null +++ b/Aaru.Filesystems/ReFS/Structs.cs @@ -0,0 +1,63 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Resilient File System plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of Microsoft's Resilient filesystem (ReFS) +public sealed partial class ReFS +{ +#region Nested type: VolumeHeader + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct VolumeHeader + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] signature; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public readonly byte[] mustBeZero; + public readonly uint identifier; + public readonly ushort length; + public readonly ushort checksum; + public readonly ulong sectors; + public readonly uint bytesPerSector; + public readonly uint sectorsPerCluster; + public readonly uint unknown1; + public readonly uint unknown2; + public readonly ulong unknown3; + public readonly ulong unknown4; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15872)] + public readonly byte[] unknown5; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Register.cs b/Aaru.Filesystems/Register.cs index 00982b5f1..4cbaef69b 100644 --- a/Aaru.Filesystems/Register.cs +++ b/Aaru.Filesystems/Register.cs @@ -7,10 +7,6 @@ // // Component : Core algorithms. // -// --[ Description ] ---------------------------------------------------------- -// -// Registers all plugins in this assembly. -// // --[ License ] -------------------------------------------------------------- // // Permission is hereby granted, free of charge, to any person obtaining a @@ -33,55 +29,14 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using Aaru.CommonTypes.Interfaces; + namespace Aaru.Filesystems; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Aaru.CommonTypes.Interfaces; - +// Needs to have the interface here so the source generator knows THIS IS the class +// ReSharper disable once RedundantExtendsListEntry /// -public sealed class Register : IPluginRegister -{ - /// - public List GetAllChecksumPlugins() => null; - - /// - public List GetAllFilesystemPlugins() => Assembly.GetExecutingAssembly().GetTypes(). - Where(t => t.GetInterfaces().Contains(typeof(IFilesystem))). - Where(t => t.IsClass).ToList(); - - /// - public List GetAllFilterPlugins() => null; - - /// - public List GetAllFloppyImagePlugins() => null; - - /// - public List GetAllMediaImagePlugins() => null; - - /// - public List GetAllPartitionPlugins() => null; - - /// - public List GetAllReadOnlyFilesystemPlugins() => Assembly.GetExecutingAssembly().GetTypes(). - Where(t => t.GetInterfaces(). - Contains(typeof(IReadOnlyFilesystem))). - Where(t => t.IsClass).ToList(); - - /// - public List GetAllWritableFloppyImagePlugins() => null; - - /// - public List GetAllWritableImagePlugins() => null; - - /// - public List GetAllArchivePlugins() => null; - - /// - public List GetAllByteAddressablePlugins() => null; -} \ No newline at end of file +public sealed partial class Register : IPluginRegister; \ No newline at end of file diff --git a/Aaru.Filesystems/Reiser.cs b/Aaru.Filesystems/Reiser.cs deleted file mode 100644 index c54c9d0ec..000000000 --- a/Aaru.Filesystems/Reiser.cs +++ /dev/null @@ -1,238 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Reiser.cs -// Author(s) : Natalia Portillo -// -// Component : Reiser filesystem plugin -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Reiser filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the Reiser v3 filesystem -public sealed class Reiser : IFilesystem -{ - const uint REISER_SUPER_OFFSET = 0x10000; - - readonly byte[] _magic35 = - { - 0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x46, 0x73, 0x00, 0x00 - }; - readonly byte[] _magic36 = - { - 0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x32, 0x46, 0x73, 0x00 - }; - readonly byte[] _magicJr = - { - 0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x33, 0x46, 0x73, 0x00 - }; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Reiser Filesystem Plugin"; - /// - public Guid Id => new("1D8CD8B8-27E6-410F-9973-D16409225FBA"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 512) - return false; - - uint sbAddr = REISER_SUPER_OFFSET / imagePlugin.Info.SectorSize; - - if(sbAddr == 0) - sbAddr = 1; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - if(partition.Start + sbAddr + sbSize >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - Superblock reiserSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - return _magic35.SequenceEqual(reiserSb.magic) || _magic36.SequenceEqual(reiserSb.magic) || - _magicJr.SequenceEqual(reiserSb.magic); - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - if(imagePlugin.Info.SectorSize < 512) - return; - - uint sbAddr = REISER_SUPER_OFFSET / imagePlugin.Info.SectorSize; - - if(sbAddr == 0) - sbAddr = 1; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < Marshal.SizeOf()) - return; - - Superblock reiserSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - if(!_magic35.SequenceEqual(reiserSb.magic) && - !_magic36.SequenceEqual(reiserSb.magic) && - !_magicJr.SequenceEqual(reiserSb.magic)) - return; - - var sb = new StringBuilder(); - - if(_magic35.SequenceEqual(reiserSb.magic)) - sb.AppendLine("Reiser 3.5 filesystem"); - else if(_magic36.SequenceEqual(reiserSb.magic)) - sb.AppendLine("Reiser 3.6 filesystem"); - else if(_magicJr.SequenceEqual(reiserSb.magic)) - sb.AppendLine("Reiser Jr. filesystem"); - - sb.AppendFormat("Volume has {0} blocks with {1} blocks free", reiserSb.block_count, reiserSb.free_blocks). - AppendLine(); - - sb.AppendFormat("{0} bytes per block", reiserSb.blocksize).AppendLine(); - sb.AppendFormat("Root directory resides on block {0}", reiserSb.root_block).AppendLine(); - - if(reiserSb.umount_state == 2) - sb.AppendLine("Volume has not been cleanly umounted"); - - sb.AppendFormat("Volume last checked on {0}", DateHandlers.UnixUnsignedToDateTime(reiserSb.last_check)). - AppendLine(); - - if(reiserSb.version >= 2) - { - sb.AppendFormat("Volume UUID: {0}", reiserSb.uuid).AppendLine(); - sb.AppendFormat("Volume name: {0}", Encoding.GetString(reiserSb.label)).AppendLine(); - } - - information = sb.ToString(); - - XmlFsType = new FileSystemType(); - - if(_magic35.SequenceEqual(reiserSb.magic)) - XmlFsType.Type = "Reiser 3.5 filesystem"; - else if(_magic36.SequenceEqual(reiserSb.magic)) - XmlFsType.Type = "Reiser 3.6 filesystem"; - else if(_magicJr.SequenceEqual(reiserSb.magic)) - XmlFsType.Type = "Reiser Jr. filesystem"; - - XmlFsType.ClusterSize = reiserSb.blocksize; - XmlFsType.Clusters = reiserSb.block_count; - XmlFsType.FreeClusters = reiserSb.free_blocks; - XmlFsType.FreeClustersSpecified = true; - XmlFsType.Dirty = reiserSb.umount_state == 2; - - if(reiserSb.version < 2) - return; - - XmlFsType.VolumeName = StringHandlers.CToString(reiserSb.label, Encoding); - XmlFsType.VolumeSerial = reiserSb.uuid.ToString(); - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct JournalParameters - { - public readonly uint journal_1stblock; - public readonly uint journal_dev; - public readonly uint journal_size; - public readonly uint journal_trans_max; - public readonly uint journal_magic; - public readonly uint journal_max_batch; - public readonly uint journal_max_commit_age; - public readonly uint journal_max_trans_age; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct Superblock - { - public readonly uint block_count; - public readonly uint free_blocks; - public readonly uint root_block; - public readonly JournalParameters journal; - public readonly ushort blocksize; - public readonly ushort oid_maxsize; - public readonly ushort oid_cursize; - public readonly ushort umount_state; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public readonly byte[] magic; - public readonly ushort fs_state; - public readonly uint hash_function_code; - public readonly ushort tree_height; - public readonly ushort bmap_nr; - public readonly ushort version; - public readonly ushort reserved_for_journal; - public readonly uint inode_generation; - public readonly uint flags; - public readonly Guid uuid; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] label; - public readonly ushort mnt_count; - public readonly ushort max_mnt_count; - public readonly uint last_check; - public readonly uint check_interval; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 76)] - public readonly byte[] unused; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/Reiser/Consts.cs b/Aaru.Filesystems/Reiser/Consts.cs new file mode 100644 index 000000000..8fded4a00 --- /dev/null +++ b/Aaru.Filesystems/Reiser/Consts.cs @@ -0,0 +1,42 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Reiser filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Reiser v3 filesystem +public sealed partial class Reiser +{ + const uint REISER_SUPER_OFFSET = 0x10000; + + const string FS_TYPE = "reiserfs"; + + readonly byte[] _magic35 = [0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x46, 0x73, 0x00, 0x00]; + readonly byte[] _magic36 = [0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x32, 0x46, 0x73, 0x00]; + readonly byte[] _magicJr = [0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x33, 0x46, 0x73, 0x00]; +} \ No newline at end of file diff --git a/Aaru.Filesystems/Reiser/Info.cs b/Aaru.Filesystems/Reiser/Info.cs new file mode 100644 index 000000000..3959f8bd7 --- /dev/null +++ b/Aaru.Filesystems/Reiser/Info.cs @@ -0,0 +1,147 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Reiser filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Linq; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Reiser v3 filesystem +public sealed partial class Reiser +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 512) return false; + + uint sbAddr = REISER_SUPER_OFFSET / imagePlugin.Info.SectorSize; + + if(sbAddr == 0) sbAddr = 1; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + if(partition.Start + sbAddr + sbSize >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + Superblock reiserSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + return _magic35.SequenceEqual(reiserSb.magic) || + _magic36.SequenceEqual(reiserSb.magic) || + _magicJr.SequenceEqual(reiserSb.magic); + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize < 512) return; + + uint sbAddr = REISER_SUPER_OFFSET / imagePlugin.Info.SectorSize; + + if(sbAddr == 0) sbAddr = 1; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < Marshal.SizeOf()) return; + + Superblock reiserSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + if(!_magic35.SequenceEqual(reiserSb.magic) && + !_magic36.SequenceEqual(reiserSb.magic) && + !_magicJr.SequenceEqual(reiserSb.magic)) + return; + + var sb = new StringBuilder(); + + if(_magic35.SequenceEqual(reiserSb.magic)) + sb.AppendLine(Localization.Reiser_3_5_filesystem); + else if(_magic36.SequenceEqual(reiserSb.magic)) + sb.AppendLine(Localization.Reiser_3_6_filesystem); + else if(_magicJr.SequenceEqual(reiserSb.magic)) sb.AppendLine(Localization.Reiser_Jr_filesystem); + + sb.AppendFormat(Localization.Volume_has_0_blocks_with_1_blocks_free, reiserSb.block_count, reiserSb.free_blocks) + .AppendLine(); + + sb.AppendFormat(Localization._0_bytes_per_block, reiserSb.blocksize).AppendLine(); + sb.AppendFormat(Localization.Root_directory_resides_on_block_0, reiserSb.root_block).AppendLine(); + + if(reiserSb.umount_state == 2) sb.AppendLine(Localization.Volume_has_not_been_cleanly_umounted); + + sb.AppendFormat(Localization.Volume_last_checked_on_0, DateHandlers.UnixUnsignedToDateTime(reiserSb.last_check)) + .AppendLine(); + + if(reiserSb.version >= 2) + { + sb.AppendFormat(Localization.Volume_UUID_0, reiserSb.uuid).AppendLine(); + sb.AppendFormat(Localization.Volume_name_0, encoding.GetString(reiserSb.label)).AppendLine(); + } + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = reiserSb.blocksize, + Clusters = reiserSb.block_count, + FreeClusters = reiserSb.free_blocks, + Dirty = reiserSb.umount_state == 2 + }; + + if(reiserSb.version < 2) return; + + metadata.VolumeName = StringHandlers.CToString(reiserSb.label, encoding); + metadata.VolumeSerial = reiserSb.uuid.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Reiser/Reiser.cs b/Aaru.Filesystems/Reiser/Reiser.cs new file mode 100644 index 000000000..af42d7bca --- /dev/null +++ b/Aaru.Filesystems/Reiser/Reiser.cs @@ -0,0 +1,50 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Reiser.cs +// Author(s) : Natalia Portillo +// +// Component : Reiser filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Reiser v3 filesystem +public sealed partial class Reiser : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.Reiser_Name; + + /// + public Guid Id => new("1D8CD8B8-27E6-410F-9973-D16409225FBA"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Reiser/Structs.cs b/Aaru.Filesystems/Reiser/Structs.cs new file mode 100644 index 000000000..4cb0dcade --- /dev/null +++ b/Aaru.Filesystems/Reiser/Structs.cs @@ -0,0 +1,90 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Reiser filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Reiser v3 filesystem +public sealed partial class Reiser +{ +#region Nested type: JournalParameters + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct JournalParameters + { + public readonly uint journal_1stblock; + public readonly uint journal_dev; + public readonly uint journal_size; + public readonly uint journal_trans_max; + public readonly uint journal_magic; + public readonly uint journal_max_batch; + public readonly uint journal_max_commit_age; + public readonly uint journal_max_trans_age; + } + +#endregion + +#region Nested type: Superblock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Superblock + { + public readonly uint block_count; + public readonly uint free_blocks; + public readonly uint root_block; + public readonly JournalParameters journal; + public readonly ushort blocksize; + public readonly ushort oid_maxsize; + public readonly ushort oid_cursize; + public readonly ushort umount_state; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public readonly byte[] magic; + public readonly ushort fs_state; + public readonly uint hash_function_code; + public readonly ushort tree_height; + public readonly ushort bmap_nr; + public readonly ushort version; + public readonly ushort reserved_for_journal; + public readonly uint inode_generation; + public readonly uint flags; + public readonly Guid uuid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] label; + public readonly ushort mnt_count; + public readonly ushort max_mnt_count; + public readonly uint last_check; + public readonly uint check_interval; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 76)] + public readonly byte[] unused; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Reiser4/Consts.cs b/Aaru.Filesystems/Reiser4/Consts.cs new file mode 100644 index 000000000..9257234e5 --- /dev/null +++ b/Aaru.Filesystems/Reiser4/Consts.cs @@ -0,0 +1,43 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Reiser4 filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Reiser v4 filesystem +public sealed partial class Reiser4 +{ + const uint REISER4_SUPER_OFFSET = 0x10000; + + const string FS_TYPE = "reiser4"; + + readonly byte[] _magic = + [ + 0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]; +} \ No newline at end of file diff --git a/Aaru.Filesystems/Reiser4.cs b/Aaru.Filesystems/Reiser4/Info.cs similarity index 51% rename from Aaru.Filesystems/Reiser4.cs rename to Aaru.Filesystems/Reiser4/Info.cs index 0ea950eb0..5fc56281e 100644 --- a/Aaru.Filesystems/Reiser4.cs +++ b/Aaru.Filesystems/Reiser4/Info.cs @@ -2,15 +2,11 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : Reiser4.cs +// Filename : Info.cs // Author(s) : Natalia Portillo // // Component : Reiser4 filesystem plugin // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Reiser4 filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,70 +23,45 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - -using System; using System.Linq; -using System.Runtime.InteropServices; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; /// /// Implements detection of the Reiser v4 filesystem -public sealed class Reiser4 : IFilesystem +public sealed partial class Reiser4 { - const uint REISER4_SUPER_OFFSET = 0x10000; - - readonly byte[] _magic = - { - 0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Reiser4 Filesystem Plugin"; - /// - public Guid Id => new("301F2D00-E8D5-4F04-934E-81DFB21D15BA"); - /// - public string Author => "Natalia Portillo"; +#region IFilesystem Members /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(imagePlugin.Info.SectorSize < 512) - return false; + if(imagePlugin.Info.SectorSize < 512) return false; uint sbAddr = REISER4_SUPER_OFFSET / imagePlugin.Info.SectorSize; - if(sbAddr == 0) - sbAddr = 1; + if(sbAddr == 0) sbAddr = 1; var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; - if(partition.Start + sbAddr + sbSize >= partition.End) - return false; + if(partition.Start + sbAddr + sbSize >= partition.End) return false; ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; - if(sector.Length < Marshal.SizeOf()) - return false; + if(sector.Length < Marshal.SizeOf()) return false; Superblock reiserSb = Marshal.ByteArrayToStructureLittleEndian(sector); @@ -98,66 +69,52 @@ public sealed class Reiser4 : IFilesystem } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); - if(imagePlugin.Info.SectorSize < 512) - return; + if(imagePlugin.Info.SectorSize < 512) return; uint sbAddr = REISER4_SUPER_OFFSET / imagePlugin.Info.SectorSize; - if(sbAddr == 0) - sbAddr = 1; + if(sbAddr == 0) sbAddr = 1; var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize, out byte[] sector); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; - if(sector.Length < Marshal.SizeOf()) - return; + if(sector.Length < Marshal.SizeOf()) return; Superblock reiserSb = Marshal.ByteArrayToStructureLittleEndian(sector); - if(!_magic.SequenceEqual(reiserSb.magic)) - return; + if(!_magic.SequenceEqual(reiserSb.magic)) return; var sb = new StringBuilder(); - sb.AppendLine("Reiser 4 filesystem"); - sb.AppendFormat("{0} bytes per block", reiserSb.blocksize).AppendLine(); - sb.AppendFormat("Volume disk format: {0}", reiserSb.diskformat).AppendLine(); - sb.AppendFormat("Volume UUID: {0}", reiserSb.uuid).AppendLine(); - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(reiserSb.label, Encoding)).AppendLine(); + sb.AppendLine(Localization.Reiser_4_filesystem); + sb.AppendFormat(Localization._0_bytes_per_block, reiserSb.blocksize).AppendLine(); + sb.AppendFormat(Localization.Volume_disk_format_0, reiserSb.diskformat).AppendLine(); + sb.AppendFormat(Localization.Volume_UUID_0, reiserSb.uuid).AppendLine(); + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(reiserSb.label, encoding)).AppendLine(); information = sb.ToString(); - XmlFsType = new FileSystemType + metadata = new FileSystem { - Type = "Reiser 4 filesystem", + Type = FS_TYPE, ClusterSize = reiserSb.blocksize, Clusters = (partition.End - partition.Start) * imagePlugin.Info.SectorSize / reiserSb.blocksize, - VolumeName = StringHandlers.CToString(reiserSb.label, Encoding), + VolumeName = StringHandlers.CToString(reiserSb.label, encoding), VolumeSerial = reiserSb.uuid.ToString() }; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Superblock - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] magic; - public readonly ushort diskformat; - public readonly ushort blocksize; - public readonly Guid uuid; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] label; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/Reiser4/Reiser4.cs b/Aaru.Filesystems/Reiser4/Reiser4.cs new file mode 100644 index 000000000..0ab3bbade --- /dev/null +++ b/Aaru.Filesystems/Reiser4/Reiser4.cs @@ -0,0 +1,50 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Reiser4.cs +// Author(s) : Natalia Portillo +// +// Component : Reiser4 filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Reiser v4 filesystem +public sealed partial class Reiser4 : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.Reiser4_Name; + + /// + public Guid Id => new("301F2D00-E8D5-4F04-934E-81DFB21D15BA"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Reiser4/Structs.cs b/Aaru.Filesystems/Reiser4/Structs.cs new file mode 100644 index 000000000..df1b8098c --- /dev/null +++ b/Aaru.Filesystems/Reiser4/Structs.cs @@ -0,0 +1,53 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Reiser4 filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Reiser v4 filesystem +public sealed partial class Reiser4 +{ +#region Nested type: Superblock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Superblock + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] magic; + public readonly ushort diskformat; + public readonly ushort blocksize; + public readonly Guid uuid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] label; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/SFS.cs b/Aaru.Filesystems/SFS.cs deleted file mode 100644 index fc552afb9..000000000 --- a/Aaru.Filesystems/SFS.cs +++ /dev/null @@ -1,178 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : SFS.cs -// Author(s) : Natalia Portillo -// -// Component : SmartFileSystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the SmartFileSystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the Smart File System -public sealed class SFS : IFilesystem -{ - /// Identifier for SFS v1 - const uint SFS_MAGIC = 0x53465300; - /// Identifier for SFS v2 - const uint SFS2_MAGIC = 0x53465302; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "SmartFileSystem"; - /// - public Guid Id => new("26550C19-3671-4A2D-BC2F-F20CEB7F48DC"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - var magic = BigEndianBitConverter.ToUInt32(sector, 0x00); - - return magic is SFS_MAGIC or SFS2_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - information = ""; - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); - ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] rootBlockSector); - - if(errno != ErrorNumber.NoError) - return; - - RootBlock rootBlock = Marshal.ByteArrayToStructureBigEndian(rootBlockSector); - - var sbInformation = new StringBuilder(); - - sbInformation.AppendLine("SmartFileSystem"); - - sbInformation.AppendFormat("Volume version {0}", rootBlock.version).AppendLine(); - - sbInformation.AppendFormat("Volume starts on device byte {0} and ends on byte {1}", rootBlock.firstbyte, - rootBlock.lastbyte).AppendLine(); - - sbInformation. - AppendFormat("Volume has {0} blocks of {1} bytes each", rootBlock.totalblocks, rootBlock.blocksize). - AppendLine(); - - sbInformation.AppendFormat("Volume created on {0}", - DateHandlers.UnixUnsignedToDateTime(rootBlock.datecreated).AddYears(8)).AppendLine(); - - sbInformation.AppendFormat("Bitmap starts in block {0}", rootBlock.bitmapbase).AppendLine(); - - sbInformation.AppendFormat("Admin space container starts in block {0}", rootBlock.adminspacecontainer). - AppendLine(); - - sbInformation.AppendFormat("Root object container starts in block {0}", rootBlock.rootobjectcontainer). - AppendLine(); - - sbInformation.AppendFormat("Root node of the extent B-tree resides in block {0}", rootBlock.extentbnoderoot). - AppendLine(); - - sbInformation.AppendFormat("Root node of the object B-tree resides in block {0}", rootBlock.objectnoderoot). - AppendLine(); - - if(rootBlock.bits.HasFlag(Flags.CaseSensitive)) - sbInformation.AppendLine("Volume is case sensitive"); - - if(rootBlock.bits.HasFlag(Flags.RecycledFolder)) - sbInformation.AppendLine("Volume moves deleted files to a recycled folder"); - - information = sbInformation.ToString(); - - XmlFsType = new FileSystemType - { - CreationDate = DateHandlers.UnixUnsignedToDateTime(rootBlock.datecreated).AddYears(8), - CreationDateSpecified = true, - Clusters = rootBlock.totalblocks, - ClusterSize = rootBlock.blocksize, - Type = "SmartFileSystem" - }; - } - - [Flags] - enum Flags : byte - { - RecycledFolder = 64, - CaseSensitive = 128 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct RootBlock - { - public readonly uint blockId; - public readonly uint blockChecksum; - public readonly uint blockSelfPointer; - public readonly ushort version; - public readonly ushort sequence; - public readonly uint datecreated; - public readonly Flags bits; - public readonly byte padding1; - public readonly ushort padding2; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public readonly uint[] reserved1; - public readonly ulong firstbyte; - public readonly ulong lastbyte; - public readonly uint totalblocks; - public readonly uint blocksize; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public readonly uint[] reserved2; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly uint[] reserved3; - public readonly uint bitmapbase; - public readonly uint adminspacecontainer; - public readonly uint rootobjectcontainer; - public readonly uint extentbnoderoot; - public readonly uint objectnoderoot; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly uint[] reserved4; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/SFS/Consts.cs b/Aaru.Filesystems/SFS/Consts.cs new file mode 100644 index 000000000..5c1ad187c --- /dev/null +++ b/Aaru.Filesystems/SFS/Consts.cs @@ -0,0 +1,41 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : SmartFileSystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Smart File System +public sealed partial class SFS +{ + /// Identifier for SFS v1 + const uint SFS_MAGIC = 0x53465300; + /// Identifier for SFS v2 + const uint SFS2_MAGIC = 0x53465302; + + const string FS_TYPE = "sfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/SFS/Enums.cs b/Aaru.Filesystems/SFS/Enums.cs new file mode 100644 index 000000000..55db3a509 --- /dev/null +++ b/Aaru.Filesystems/SFS/Enums.cs @@ -0,0 +1,47 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : SmartFileSystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Smart File System +public sealed partial class SFS +{ +#region Nested type: Flags + + [Flags] + enum Flags : byte + { + RecycledFolder = 64, + CaseSensitive = 128 + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/SFS/Info.cs b/Aaru.Filesystems/SFS/Info.cs new file mode 100644 index 000000000..52d29361d --- /dev/null +++ b/Aaru.Filesystems/SFS/Info.cs @@ -0,0 +1,123 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : SmartFileSystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Smart File System +public sealed partial class SFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + var magic = BigEndianBitConverter.ToUInt32(sector, 0x00); + + return magic is SFS_MAGIC or SFS2_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] rootBlockSector); + + if(errno != ErrorNumber.NoError) return; + + RootBlock rootBlock = Marshal.ByteArrayToStructureBigEndian(rootBlockSector); + + var sbInformation = new StringBuilder(); + + sbInformation.AppendLine(Localization.SmartFileSystem); + + sbInformation.AppendFormat(Localization.Volume_version_0, rootBlock.version).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_starts_on_device_byte_0_and_ends_on_byte_1, + rootBlock.firstbyte, + rootBlock.lastbyte) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_has_0_blocks_of_1_bytes_each, + rootBlock.totalblocks, + rootBlock.blocksize) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_created_on_0, + DateHandlers.UnixUnsignedToDateTime(rootBlock.datecreated).AddYears(8)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Bitmap_starts_at_block_0, rootBlock.bitmapbase).AppendLine(); + + sbInformation.AppendFormat(Localization.Admin_space_container_starts_in_block_0, rootBlock.adminspacecontainer) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Root_object_container_starts_in_block_0, rootBlock.rootobjectcontainer) + .AppendLine(); + + sbInformation + .AppendFormat(Localization.Root_node_of_the_extent_B_tree_resides_in_block_0, rootBlock.extentbnoderoot) + .AppendLine(); + + sbInformation + .AppendFormat(Localization.Root_node_of_the_object_B_tree_resides_in_block_0, rootBlock.objectnoderoot) + .AppendLine(); + + if(rootBlock.bits.HasFlag(Flags.CaseSensitive)) sbInformation.AppendLine(Localization.Volume_is_case_sensitive); + + if(rootBlock.bits.HasFlag(Flags.RecycledFolder)) + sbInformation.AppendLine(Localization.Volume_moves_deleted_files_to_a_recycled_folder); + + information = sbInformation.ToString(); + + metadata = new FileSystem + { + CreationDate = DateHandlers.UnixUnsignedToDateTime(rootBlock.datecreated).AddYears(8), + Clusters = rootBlock.totalblocks, + ClusterSize = rootBlock.blocksize, + Type = FS_TYPE + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/SFS/SFS.cs b/Aaru.Filesystems/SFS/SFS.cs new file mode 100644 index 000000000..e3569fb5a --- /dev/null +++ b/Aaru.Filesystems/SFS/SFS.cs @@ -0,0 +1,50 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SFS.cs +// Author(s) : Natalia Portillo +// +// Component : SmartFileSystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Smart File System +public sealed partial class SFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.SFS_Name; + + /// + public Guid Id => new("26550C19-3671-4A2D-BC2F-F20CEB7F48DC"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/SFS/Structs.cs b/Aaru.Filesystems/SFS/Structs.cs new file mode 100644 index 000000000..aa8a48717 --- /dev/null +++ b/Aaru.Filesystems/SFS/Structs.cs @@ -0,0 +1,71 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : SmartFileSystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Smart File System +public sealed partial class SFS +{ +#region Nested type: RootBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct RootBlock + { + public readonly uint blockId; + public readonly uint blockChecksum; + public readonly uint blockSelfPointer; + public readonly ushort version; + public readonly ushort sequence; + public readonly uint datecreated; + public readonly Flags bits; + public readonly byte padding1; + public readonly ushort padding2; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public readonly uint[] reserved1; + public readonly ulong firstbyte; + public readonly ulong lastbyte; + public readonly uint totalblocks; + public readonly uint blocksize; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public readonly uint[] reserved2; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly uint[] reserved3; + public readonly uint bitmapbase; + public readonly uint adminspacecontainer; + public readonly uint rootobjectcontainer; + public readonly uint extentbnoderoot; + public readonly uint objectnoderoot; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly uint[] reserved4; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/SolarFS.cs b/Aaru.Filesystems/SolarFS.cs deleted file mode 100644 index 172430aea..000000000 --- a/Aaru.Filesystems/SolarFS.cs +++ /dev/null @@ -1,220 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : SolarFS.cs -// Author(s) : Natalia Portillo -// -// Component : SolarOS filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the SolarOS filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; - -// Based on FAT's BPB, cannot find a FAT or directory -/// -/// Implements detection of the Solar OS filesystem -public sealed class SolarFS : IFilesystem -{ - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Solar_OS filesystem"; - /// - public Guid Id => new("EA3101C1-E777-4B4F-B5A3-8C57F50F6E65"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(2 + partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bpb); - - if(errno != ErrorNumber.NoError) - return false; - - var fsTypeB = new byte[8]; - - byte signature = bpb[0x25]; - Array.Copy(bpb, 0x35, fsTypeB, 0, 8); - string fsType = StringHandlers.CToString(fsTypeB); - - return signature == 0x29 && fsType == "SOL_FS "; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - var sb = new StringBuilder(); - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bpbSector); - - if(errno != ErrorNumber.NoError) - return; - - var bpb = new BiosParameterBlock - { - bps = BitConverter.ToUInt16(bpbSector, 0x0B), - root_ent = BitConverter.ToUInt16(bpbSector, 0x10), - sectors = BitConverter.ToUInt16(bpbSector, 0x12), - media = bpbSector[0x14], - spfat = BitConverter.ToUInt16(bpbSector, 0x15), - sptrk = BitConverter.ToUInt16(bpbSector, 0x17), - heads = BitConverter.ToUInt16(bpbSector, 0x19), - signature = bpbSector[0x25] - }; - - var bpbStrings = new byte[8]; - Array.Copy(bpbSector, 0x03, bpbStrings, 0, 8); - bpb.OEMName = StringHandlers.CToString(bpbStrings); - bpbStrings = new byte[8]; - Array.Copy(bpbSector, 0x2A, bpbStrings, 0, 11); - bpb.vol_name = StringHandlers.CToString(bpbStrings, Encoding); - bpbStrings = new byte[8]; - Array.Copy(bpbSector, 0x35, bpbStrings, 0, 8); - bpb.fs_type = StringHandlers.CToString(bpbStrings, Encoding); - - bpb.x86_jump = new byte[3]; - Array.Copy(bpbSector, 0x00, bpb.x86_jump, 0, 3); - bpb.unk1 = bpbSector[0x0D]; - bpb.unk2 = BitConverter.ToUInt16(bpbSector, 0x0E); - bpb.unk3 = new byte[10]; - Array.Copy(bpbSector, 0x1B, bpb.unk3, 0, 10); - bpb.unk4 = BitConverter.ToUInt32(bpbSector, 0x26); - - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.x86_jump: 0x{0:X2}{1:X2}{2:X2}", bpb.x86_jump[0], - bpb.x86_jump[1], bpb.x86_jump[2]); - - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.OEMName: \"{0}\"", bpb.OEMName); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.bps: {0}", bpb.bps); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.unk1: 0x{0:X2}", bpb.unk1); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.unk2: 0x{0:X4}", bpb.unk2); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.root_ent: {0}", bpb.root_ent); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.sectors: {0}", bpb.sectors); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.media: 0x{0:X2}", bpb.media); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.spfat: {0}", bpb.spfat); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.sptrk: {0}", bpb.sptrk); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.heads: {0}", bpb.heads); - - AaruConsole.DebugWriteLine("SolarFS plugin", - "BPB.unk3: 0x{0:X2}{1:X2}{2:X2}{3:X2}{4:X2}{5:X2}{6:X2}{7:X2}{8:X2}{9:X2}", - bpb.unk3[0], bpb.unk3[1], bpb.unk3[2], bpb.unk3[3], bpb.unk3[4], bpb.unk3[5], - bpb.unk3[6], bpb.unk3[7], bpb.unk3[8], bpb.unk3[9]); - - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.signature: 0x{0:X2}", bpb.signature); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.unk4: 0x{0:X8}", bpb.unk4); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.vol_name: \"{0}\"", bpb.vol_name); - AaruConsole.DebugWriteLine("SolarFS plugin", "BPB.fs_type: \"{0}\"", bpb.fs_type); - - sb.AppendLine("Solar_OS filesystem"); - sb.AppendFormat("Media descriptor: 0x{0:X2}", bpb.media).AppendLine(); - sb.AppendFormat("{0} bytes per sector", bpb.bps).AppendLine(); - - if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448) - { - if(bpb.bps != imagePlugin.Info.SectorSize) - sb. - AppendFormat("WARNING: Filesystem describes a {0} bytes/sector, while device describes a {1} bytes/sector", - bpb.bps, 2048).AppendLine(); - } - else if(bpb.bps != imagePlugin.Info.SectorSize) - sb. - AppendFormat("WARNING: Filesystem describes a {0} bytes/sector, while device describes a {1} bytes/sector", - bpb.bps, imagePlugin.Info.SectorSize).AppendLine(); - - sb.AppendFormat("{0} sectors on volume ({1} bytes)", bpb.sectors, bpb.sectors * bpb.bps).AppendLine(); - - if(bpb.sectors > imagePlugin.Info.Sectors) - sb.AppendFormat("WARNING: Filesystem describes a {0} sectors volume, bigger than device ({1} sectors)", - bpb.sectors, imagePlugin.Info.Sectors); - - sb.AppendFormat("{0} heads", bpb.heads).AppendLine(); - sb.AppendFormat("{0} sectors per track", bpb.sptrk).AppendLine(); - sb.AppendFormat("Volume name: {0}", bpb.vol_name).AppendLine(); - - XmlFsType = new FileSystemType - { - Type = "SolarFS", - Clusters = bpb.sectors, - ClusterSize = bpb.bps, - VolumeName = bpb.vol_name - }; - - information = sb.ToString(); - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct BiosParameterBlock - { - /// 0x00, x86 jump (3 bytes), jumps to 0x60 - public byte[] x86_jump; - /// 0x03, 8 bytes, "SOLAR_OS" - public string OEMName; - /// 0x0B, Bytes per sector - public ushort bps; - /// 0x0D, unknown, 0x01 - public byte unk1; - /// 0x0E, unknown, 0x0201 - public ushort unk2; - /// 0x10, Number of entries on root directory ? (no root directory found) - public ushort root_ent; - /// 0x12, Sectors in volume - public ushort sectors; - /// 0x14, Media descriptor - public byte media; - /// 0x15, Sectors per FAT ? (no FAT found) - public ushort spfat; - /// 0x17, Sectors per track - public ushort sptrk; - /// 0x19, Heads - public ushort heads; - /// 0x1B, unknown, 10 bytes, zero-filled - public byte[] unk3; - /// 0x25, 0x29 - public byte signature; - /// 0x26, unknown, zero-filled - public uint unk4; - /// 0x2A, 11 bytes, volume name, space-padded - public string vol_name; - /// 0x35, 8 bytes, "SOL_FS " - public string fs_type; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/SolarFS/Consts.cs b/Aaru.Filesystems/SolarFS/Consts.cs new file mode 100644 index 000000000..5cd038361 --- /dev/null +++ b/Aaru.Filesystems/SolarFS/Consts.cs @@ -0,0 +1,37 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : SolarOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Based on FAT's BPB, cannot find a FAT or directory +/// +/// Implements detection of the Solar OS filesystem +public sealed partial class SolarFS +{ + const string FS_TYPE = "solarfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/SolarFS/Info.cs b/Aaru.Filesystems/SolarFS/Info.cs new file mode 100644 index 000000000..20e6ad0d9 --- /dev/null +++ b/Aaru.Filesystems/SolarFS/Info.cs @@ -0,0 +1,192 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : SolarOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Based on FAT's BPB, cannot find a FAT or directory +/// +/// Implements detection of the Solar OS filesystem +public sealed partial class SolarFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(2 + partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bpb); + + if(errno != ErrorNumber.NoError) return false; + + var fsTypeB = new byte[8]; + + byte signature = bpb[0x25]; + Array.Copy(bpb, 0x35, fsTypeB, 0, 8); + string fsType = StringHandlers.CToString(fsTypeB); + + return signature == 0x29 && fsType == "SOL_FS "; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bpbSector); + + if(errno != ErrorNumber.NoError) return; + + var bpb = new BiosParameterBlock + { + bps = BitConverter.ToUInt16(bpbSector, 0x0B), + root_ent = BitConverter.ToUInt16(bpbSector, 0x10), + sectors = BitConverter.ToUInt16(bpbSector, 0x12), + media = bpbSector[0x14], + spfat = BitConverter.ToUInt16(bpbSector, 0x15), + sptrk = BitConverter.ToUInt16(bpbSector, 0x17), + heads = BitConverter.ToUInt16(bpbSector, 0x19), + signature = bpbSector[0x25] + }; + + var bpbStrings = new byte[8]; + Array.Copy(bpbSector, 0x03, bpbStrings, 0, 8); + bpb.OEMName = StringHandlers.CToString(bpbStrings); + bpbStrings = new byte[8]; + Array.Copy(bpbSector, 0x2A, bpbStrings, 0, 11); + bpb.vol_name = StringHandlers.CToString(bpbStrings, encoding); + bpbStrings = new byte[8]; + Array.Copy(bpbSector, 0x35, bpbStrings, 0, 8); + bpb.fs_type = StringHandlers.CToString(bpbStrings, encoding); + + bpb.x86_jump = new byte[3]; + Array.Copy(bpbSector, 0x00, bpb.x86_jump, 0, 3); + bpb.unk1 = bpbSector[0x0D]; + bpb.unk2 = BitConverter.ToUInt16(bpbSector, 0x0E); + bpb.unk3 = new byte[10]; + Array.Copy(bpbSector, 0x1B, bpb.unk3, 0, 10); + bpb.unk4 = BitConverter.ToUInt32(bpbSector, 0x26); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "BPB.x86_jump: 0x{0:X2}{1:X2}{2:X2}", + bpb.x86_jump[0], + bpb.x86_jump[1], + bpb.x86_jump[2]); + + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.OEMName: \"{0}\"", bpb.OEMName); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.bps: {0}", bpb.bps); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.unk1: 0x{0:X2}", bpb.unk1); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.unk2: 0x{0:X4}", bpb.unk2); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.root_ent: {0}", bpb.root_ent); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.sectors: {0}", bpb.sectors); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.media: 0x{0:X2}", bpb.media); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.spfat: {0}", bpb.spfat); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.sptrk: {0}", bpb.sptrk); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.heads: {0}", bpb.heads); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "BPB.unk3: 0x{0:X2}{1:X2}{2:X2}{3:X2}{4:X2}{5:X2}{6:X2}{7:X2}{8:X2}{9:X2}", + bpb.unk3[0], + bpb.unk3[1], + bpb.unk3[2], + bpb.unk3[3], + bpb.unk3[4], + bpb.unk3[5], + bpb.unk3[6], + bpb.unk3[7], + bpb.unk3[8], + bpb.unk3[9]); + + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.signature: 0x{0:X2}", bpb.signature); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.unk4: 0x{0:X8}", bpb.unk4); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.vol_name: \"{0}\"", bpb.vol_name); + AaruConsole.DebugWriteLine(MODULE_NAME, "BPB.fs_type: \"{0}\"", bpb.fs_type); + + sb.AppendLine(Localization.Solar_OS_filesystem); + sb.AppendFormat(Localization.Media_descriptor_0, bpb.media).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector, bpb.bps).AppendLine(); + + if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448) + { + if(bpb.bps != imagePlugin.Info.SectorSize) + { + sb.AppendFormat(Localization + .WARNING_Filesystem_describes_a_0_bytes_sector_while_device_describes_a_1_bytes_sector, + bpb.bps, + 2048) + .AppendLine(); + } + } + else if(bpb.bps != imagePlugin.Info.SectorSize) + { + sb.AppendFormat(Localization + .WARNING_Filesystem_describes_a_0_bytes_sector_while_device_describes_a_1_bytes_sector, + bpb.bps, + imagePlugin.Info.SectorSize) + .AppendLine(); + } + + sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, bpb.sectors, bpb.sectors * bpb.bps).AppendLine(); + + if(bpb.sectors > imagePlugin.Info.Sectors) + { + sb.AppendFormat(Localization.WARNING_Filesystem_describes_a_0_sectors_volume_bigger_than_device_1_sectors, + bpb.sectors, + imagePlugin.Info.Sectors); + } + + sb.AppendFormat(Localization._0_heads, bpb.heads).AppendLine(); + sb.AppendFormat(Localization._0_sectors_per_track, bpb.sptrk).AppendLine(); + sb.AppendFormat(Localization.Volume_name_0, bpb.vol_name).AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + Clusters = bpb.sectors, + ClusterSize = bpb.bps, + VolumeName = bpb.vol_name + }; + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/SolarFS/SolarFS.cs b/Aaru.Filesystems/SolarFS/SolarFS.cs new file mode 100644 index 000000000..24c3575f2 --- /dev/null +++ b/Aaru.Filesystems/SolarFS/SolarFS.cs @@ -0,0 +1,53 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SolarFS.cs +// Author(s) : Natalia Portillo +// +// Component : SolarOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Based on FAT's BPB, cannot find a FAT or directory +/// +/// Implements detection of the Solar OS filesystem +public sealed partial class SolarFS : IFilesystem +{ + const string MODULE_NAME = "SolarFS plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.SolarFS_Name; + + /// + public Guid Id => new("EA3101C1-E777-4B4F-B5A3-8C57F50F6E65"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/SolarFS/Structs.cs b/Aaru.Filesystems/SolarFS/Structs.cs new file mode 100644 index 000000000..0ba170c06 --- /dev/null +++ b/Aaru.Filesystems/SolarFS/Structs.cs @@ -0,0 +1,78 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : SolarOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Based on FAT's BPB, cannot find a FAT or directory +/// +/// Implements detection of the Solar OS filesystem +public sealed partial class SolarFS +{ +#region Nested type: BiosParameterBlock + + [SuppressMessage("ReSharper", "InconsistentNaming")] + struct BiosParameterBlock + { + /// 0x00, x86 jump (3 bytes), jumps to 0x60 + public byte[] x86_jump; + /// 0x03, 8 bytes, "SOLAR_OS" + public string OEMName; + /// 0x0B, Bytes per sector + public ushort bps; + /// 0x0D, unknown, 0x01 + public byte unk1; + /// 0x0E, unknown, 0x0201 + public ushort unk2; + /// 0x10, Number of entries on root directory ? (no root directory found) + public ushort root_ent; + /// 0x12, Sectors in volume + public ushort sectors; + /// 0x14, Media descriptor + public byte media; + /// 0x15, Sectors per FAT ? (no FAT found) + public ushort spfat; + /// 0x17, Sectors per track + public ushort sptrk; + /// 0x19, Heads + public ushort heads; + /// 0x1B, unknown, 10 bytes, zero-filled + public byte[] unk3; + /// 0x25, 0x29 + public byte signature; + /// 0x26, unknown, zero-filled + public uint unk4; + /// 0x2A, 11 bytes, volume name, space-padded + public string vol_name; + /// 0x35, 8 bytes, "SOL_FS " + public string fs_type; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Squash.cs b/Aaru.Filesystems/Squash.cs deleted file mode 100644 index b5678059b..000000000 --- a/Aaru.Filesystems/Squash.cs +++ /dev/null @@ -1,203 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Squash.cs -// Author(s) : Natalia Portillo -// -// Component : Squash file system plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Squash file system and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the squash filesystem -public sealed class Squash : IFilesystem -{ - /// Identifier for Squash - const uint SQUASH_MAGIC = 0x73717368; - const uint SQUASH_CIGAM = 0x68737173; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Squash filesystem"; - /// - public Guid Id => new("F8F6E46F-7A2A-48E3-9C0A-46AF4DC29E09"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - var magic = BitConverter.ToUInt32(sector, 0x00); - - return magic is SQUASH_MAGIC or SQUASH_CIGAM; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.UTF8; - information = ""; - ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - var magic = BitConverter.ToUInt32(sector, 0x00); - - var sqSb = new SuperBlock(); - var littleEndian = true; - - switch(magic) - { - case SQUASH_MAGIC: - sqSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - break; - case SQUASH_CIGAM: - sqSb = Marshal.ByteArrayToStructureBigEndian(sector); - littleEndian = false; - - break; - } - - var sbInformation = new StringBuilder(); - - sbInformation.AppendLine("Squash file system"); - sbInformation.AppendLine(littleEndian ? "Little-endian" : "Big-endian"); - sbInformation.AppendFormat("Volume version {0}.{1}", sqSb.s_major, sqSb.s_minor).AppendLine(); - sbInformation.AppendFormat("Volume has {0} bytes", sqSb.bytes_used).AppendLine(); - sbInformation.AppendFormat("Volume has {0} bytes per block", sqSb.block_size).AppendLine(); - - sbInformation.AppendFormat("Volume created on {0}", DateHandlers.UnixUnsignedToDateTime(sqSb.mkfs_time)). - AppendLine(); - - sbInformation.AppendFormat("Volume has {0} inodes", sqSb.inodes).AppendLine(); - - switch(sqSb.compression) - { - case (ushort)SquashCompression.Lz4: - sbInformation.AppendLine("Volume is compressed using LZ4"); - - break; - case (ushort)SquashCompression.Lzo: - sbInformation.AppendLine("Volume is compressed using LZO"); - - break; - case (ushort)SquashCompression.Lzma: - sbInformation.AppendLine("Volume is compressed using LZMA"); - - break; - case (ushort)SquashCompression.Xz: - sbInformation.AppendLine("Volume is compressed using XZ"); - - break; - case (ushort)SquashCompression.Zlib: - sbInformation.AppendLine("Volume is compressed using GZIP"); - - break; - case (ushort)SquashCompression.Zstd: - sbInformation.AppendLine("Volume is compressed using Zstandard"); - - break; - default: - sbInformation.AppendFormat("Volume is compressed using unknown algorithm {0}", sqSb.compression). - AppendLine(); - - break; - } - - information = sbInformation.ToString(); - - XmlFsType = new FileSystemType - { - Type = "Squash file system", - CreationDate = DateHandlers.UnixUnsignedToDateTime(sqSb.mkfs_time), - CreationDateSpecified = true, - Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / sqSb.block_size, - ClusterSize = sqSb.block_size, - Files = sqSb.inodes, - FilesSpecified = true, - FreeClusters = 0, - FreeClustersSpecified = true - }; - } - - enum SquashCompression : ushort - { - Zlib = 1, - Lzma = 2, - Lzo = 3, - Xz = 4, - Lz4 = 5, - Zstd = 6 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SuperBlock - { - public readonly uint magic; - public readonly uint inodes; - public readonly uint mkfs_time; - public readonly uint block_size; - public readonly uint fragments; - public readonly ushort compression; - public readonly ushort block_log; - public readonly ushort flags; - public readonly ushort no_ids; - public readonly ushort s_major; - public readonly ushort s_minor; - public readonly ulong root_inode; - public readonly ulong bytes_used; - public readonly ulong id_table_start; - public readonly ulong xattr_id_table_start; - public readonly ulong inode_table_start; - public readonly ulong directory_table_start; - public readonly ulong fragment_table_start; - public readonly ulong lookup_table_start; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/Squash/Consts.cs b/Aaru.Filesystems/Squash/Consts.cs new file mode 100644 index 000000000..b81b7015f --- /dev/null +++ b/Aaru.Filesystems/Squash/Consts.cs @@ -0,0 +1,40 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Squash file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the squash filesystem +public sealed partial class Squash +{ + /// Identifier for Squash + const uint SQUASH_MAGIC = 0x73717368; + const uint SQUASH_CIGAM = 0x68737173; + + const string FS_TYPE = "squashfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/Squash/Enums.cs b/Aaru.Filesystems/Squash/Enums.cs new file mode 100644 index 000000000..c55611a3a --- /dev/null +++ b/Aaru.Filesystems/Squash/Enums.cs @@ -0,0 +1,48 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Squash file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the squash filesystem +public sealed partial class Squash +{ +#region Nested type: SquashCompression + + enum SquashCompression : ushort + { + Zlib = 1, + Lzma = 2, + Lzo = 3, + Xz = 4, + Lz4 = 5, + Zstd = 6 + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Squash/Info.cs b/Aaru.Filesystems/Squash/Info.cs new file mode 100644 index 000000000..98624647e --- /dev/null +++ b/Aaru.Filesystems/Squash/Info.cs @@ -0,0 +1,149 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Squash file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the squash filesystem +public sealed partial class Squash +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + var magic = BitConverter.ToUInt32(sector, 0x00); + + return magic is SQUASH_MAGIC or SQUASH_CIGAM; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + var magic = BitConverter.ToUInt32(sector, 0x00); + + var sqSb = new SuperBlock(); + var littleEndian = true; + + switch(magic) + { + case SQUASH_MAGIC: + sqSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + break; + case SQUASH_CIGAM: + sqSb = Marshal.ByteArrayToStructureBigEndian(sector); + littleEndian = false; + + break; + } + + var sbInformation = new StringBuilder(); + + sbInformation.AppendLine(Localization.Squash_file_system); + sbInformation.AppendLine(littleEndian ? Localization.Little_endian : Localization.Big_endian); + sbInformation.AppendFormat(Localization.Volume_version_0_1, sqSb.s_major, sqSb.s_minor).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_bytes, sqSb.bytes_used).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_bytes_per_block, sqSb.block_size).AppendLine(); + + sbInformation + .AppendFormat(Localization.Volume_created_on_0, DateHandlers.UnixUnsignedToDateTime(sqSb.mkfs_time)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_has_0_inodes, sqSb.inodes).AppendLine(); + + switch(sqSb.compression) + { + case (ushort)SquashCompression.Lz4: + sbInformation.AppendLine(Localization.Volume_is_compressed_using_LZ4); + + break; + case (ushort)SquashCompression.Lzo: + sbInformation.AppendLine(Localization.Volume_is_compressed_using_LZO); + + break; + case (ushort)SquashCompression.Lzma: + sbInformation.AppendLine(Localization.Volume_is_compressed_using_LZMA); + + break; + case (ushort)SquashCompression.Xz: + sbInformation.AppendLine(Localization.Volume_is_compressed_using_XZ); + + break; + case (ushort)SquashCompression.Zlib: + sbInformation.AppendLine(Localization.Volume_is_compressed_using_GZIP); + + break; + case (ushort)SquashCompression.Zstd: + sbInformation.AppendLine(Localization.Volume_is_compressed_using_Zstandard); + + break; + default: + sbInformation + .AppendFormat(Localization.Volume_is_compressed_using_unknown_algorithm_0, sqSb.compression) + .AppendLine(); + + break; + } + + information = sbInformation.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + CreationDate = DateHandlers.UnixUnsignedToDateTime(sqSb.mkfs_time), + Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / sqSb.block_size, + ClusterSize = sqSb.block_size, + Files = sqSb.inodes, + FreeClusters = 0 + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Squash/Squash.cs b/Aaru.Filesystems/Squash/Squash.cs new file mode 100644 index 000000000..8fd4f26d7 --- /dev/null +++ b/Aaru.Filesystems/Squash/Squash.cs @@ -0,0 +1,50 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Squash.cs +// Author(s) : Natalia Portillo +// +// Component : Squash file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the squash filesystem +public sealed partial class Squash : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.Squash_Name; + + /// + public Guid Id => new("F8F6E46F-7A2A-48E3-9C0A-46AF4DC29E09"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Squash/Structs.cs b/Aaru.Filesystems/Squash/Structs.cs new file mode 100644 index 000000000..10a83cc61 --- /dev/null +++ b/Aaru.Filesystems/Squash/Structs.cs @@ -0,0 +1,64 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Squash file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the squash filesystem +public sealed partial class Squash +{ +#region Nested type: SuperBlock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SuperBlock + { + public readonly uint magic; + public readonly uint inodes; + public readonly uint mkfs_time; + public readonly uint block_size; + public readonly uint fragments; + public readonly ushort compression; + public readonly ushort block_log; + public readonly ushort flags; + public readonly ushort no_ids; + public readonly ushort s_major; + public readonly ushort s_minor; + public readonly ulong root_inode; + public readonly ulong bytes_used; + public readonly ulong id_table_start; + public readonly ulong xattr_id_table_start; + public readonly ulong inode_table_start; + public readonly ulong directory_table_start; + public readonly ulong fragment_table_start; + public readonly ulong lookup_table_start; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Symbian.cs b/Aaru.Filesystems/Symbian.cs deleted file mode 100644 index 02e2d377a..000000000 --- a/Aaru.Filesystems/Symbian.cs +++ /dev/null @@ -1,362 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Symbian.cs -// Author(s) : Natalia Portillo -// -// Component : Symbian plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies Symbian installer (.sis) packages and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -// Information from http://www.thoukydides.webspace.virginmedia.com/software/psifs/sis.html -// TODO: Implement support for disc images -/* - -namespace Aaru.Plugins -{ - class SymbianIS : Plugin - { - // Magics - private const uint SymbianMagic = 0x10000419; - private const uint EPOCMagic = 0x1000006D; - private const uint EPOC6Magic = 0x10003A12; - private const uint Symbian9Magic = 0x10201A7A; - - // Options - private const ushort IsUnicode = 0x0001; - private const ushort IsDistributable = 0x0002; - private const ushort NoCompress = 0x0008; - private const ushort ShutdownApps = 0x0010; - - // Types - private const ushort SISApp = 0x0000; // Application - private const ushort SISSystem = 0x0001; // System component (library) - private const ushort SISOption = 0x0002; // Optional component - private const ushort SISConfig = 0x0003; // Configures an application - private const ushort SISPatch = 0x0004; // Patch - private const ushort SISUpgrade = 0x0005; // Upgrade - - private enum LanguageCodes - { - Test, - EN, - FR, - GE, - SP, - IT, - SW, - DA, - NO, - FI, - AM, - SF, - SG, - PO, - TU, - IC, - RU, - HU, - DU, - BL, - AU, - BF, - AS, - NZ, - IF, - CS, - SK, - PL, - SL, - TC, - HK, - ZH, - JA, - TH, - AF, - SQ, - AH, - AR, - HY, - TL, - BE, - BN, - BG, - MY, - CA, - HR, - CE, - IE, - ZA, - ET, - FA, - CF, - GD, - KA, - EL, - CG, - GU, - HE, - HI, - IN, - GA, - SZ, - KN, - KK, - KM, - KO, - LO, - LV, - LT, - MK, - MS, - ML, - MR, - MO, - MN, - NN, - BP, - PA, - RO, - SR, - SI, - SO, - OS, - LS, - SH, - FS, - TA, - TE, - BO, - TI, - CT, - TK, - UK, - UR, - VI, - CY, - ZU - }; - - public SymbianIS() - { - base.Name = "Symbian Installation File Plugin"; - base.PluginUUID = new Guid("0ec84ec7-eae6-4196-83fe-943b3fe48dbd"); - } - - public override bool Identify(FileStream fileStream, long offset) - { - uint uid1, uid2, uid3; - BinaryReader br = new BinaryReader(fileStream); - - br.BaseStream.Seek(0 + offset, SeekOrigin.Begin); - - uid1 = br.Readuint(); - uid2 = br.Readuint(); - uid3 = br.Readuint(); - - if(uid1 == Symbian9Magic) - return true; - else if(uid3 == SymbianMagic) - { - if(uid2 == EPOCMagic || uid2 == EPOC6Magic) - return true; - else - return false; - } - - return false; - } - - public override void GetInformation (FileStream fileStream, long offset, out string information) - { - information = ""; - StringBuilder description = new StringBuilder(); - List languages = new List(); - Dictionary capabilities = new Dictionary(); - int ENpos = 0; - uint comp_len; - uint comp_name_ptr; - byte[] ComponentName_b; - string ComponentName = ""; - - SymbianHeader sh = new SymbianHeader(); - BinaryReader br = new BinaryReader(fileStream); - - br.BaseStream.Seek(0 + offset, SeekOrigin.Begin); - - sh.uid1 = br.Readuint(); - sh.uid2 = br.Readuint(); - sh.uid3 = br.Readuint(); - sh.uid4 = br.Readuint(); - sh.crc16 = br.Readushort(); - sh.languages = br.Readushort(); - sh.files = br.Readushort(); - sh.requisites = br.Readushort(); - sh.inst_lang = br.Readushort(); - sh.inst_files = br.Readushort(); - sh.inst_drive = br.Readushort(); - sh.capabilities = br.Readushort(); - sh.inst_version = br.Readuint(); - sh.options = br.Readushort(); - sh.type = br.Readushort(); - sh.major = br.Readushort(); - sh.minor = br.Readushort(); - sh.variant = br.Readuint(); - sh.lang_ptr = br.Readuint(); - sh.files_ptr = br.Readuint(); - sh.reqs_ptr = br.Readuint(); - sh.certs_ptr = br.Readuint(); - sh.comp_ptr = br.Readuint(); - sh.sig_ptr = br.Readuint(); - sh.caps_ptr = br.Readuint(); - sh.instspace = br.Readuint(); - sh.maxinsspc = br.Readuint(); - sh.reserved1 = br.Readulong(); - sh.reserved2 = br.Readulong(); - - // Go to enumerate languages - br.BaseStream.Seek(sh.lang_ptr + offset, SeekOrigin.Begin); - for(int i = 0; i < sh.languages; i++) - { - ushort language = br.Readushort(); - if(language == 0x0001) - ENpos = i; - languages.Add(((LanguageCodes)language).ToString("G")); - } - - // Go to component record - br.BaseStream.Seek(sh.comp_ptr + offset, SeekOrigin.Begin); - for(int i = 0; i < sh.languages; i++) - { - comp_len = br.Readuint(); - comp_name_ptr = br.Readuint(); - if(i == ENpos) - { - br.BaseStream.Seek(comp_name_ptr + offset, SeekOrigin.Begin); - ComponentName_b = new byte[comp_len]; - ComponentName_b = br.ReadBytes((int)comp_len); - ComponentName = Encoding.ASCII.GetString(ComponentName_b); - break; - } - } - - // Go to capabilities (???) - br.BaseStream.Seek(sh.caps_ptr + offset, SeekOrigin.Begin); - for(int i = 0; i < sh.capabilities; i++) - { - uint cap_key = br.Readuint(); - uint cap_value = br.Readuint(); - capabilities.Add(cap_key, cap_value); - } - - if(sh.uid1 == Symbian9Magic) - { - description.AppendLine("Symbian Installation File"); - description.AppendLine("SymbianOS 9.1 or later"); - description.AppendFormat("Application ID: 0x{0:X8}", sh.uid3).AppendLine(); - description.AppendFormat("UIDs checksum: 0x{0:X8}", sh.uid4).AppendLine(); - } - else if(sh.uid3 == SymbianMagic) - { - description.AppendLine("Symbian Installation File"); - - if(sh.uid2 == EPOCMagic) - description.AppendLine("SymbianOS 3 or later"); - else if (sh.uid2 == EPOC6Magic) - description.AppendLine("SymbianOS 6 or later"); - else - description.AppendFormat("Unknown EPOC magic 0x{0:X8}", sh.uid2).AppendLine(); - - description.AppendFormat("Application ID: 0x{0:X8}", sh.uid1).AppendLine(); - description.AppendFormat("UIDs checksum: 0x{0:X8}", sh.uid4).AppendLine(); - description.AppendFormat("CRC16 of header: 0x{0:X4}", sh.crc16).AppendLine(); - description.AppendLine(); - - switch(sh.type) - { - case SISApp: - description.AppendLine("SIS contains an application"); - break; - } - - description.AppendFormat("Component: {0} v{1}.{2}", ComponentName, sh.major, sh.minor).AppendLine(); - - description.AppendFormat("File contains {0} languages:", sh.languages).AppendLine(); - for(int i = 0; i < languages.Count; i++) - { - if(i>0) - description.Append(", "); - description.AppendFormat("{0}", languages[i]); - } - description.AppendLine(); - - description.AppendFormat("File contains {0} files (pointer: {1})", sh.files, sh.files_ptr).AppendLine(); - description.AppendFormat("File contains {0} requisites", sh.requisites).AppendLine(); -// description.AppendLine("Capabilities:"); -// foreach(KeyValuePair kvp in capabilities) -// description.AppendFormat("{0} = {1}", kvp.Key, kvp.Value).AppendLine(); - } - - information = description.ToString(); - } - - private struct SymbianHeader - { - public uint uid1; // Application UID before SymbianOS 9, magic after - public uint uid2; // EPOC release magic before SOS 9, NULLs after - public uint uid3; // Application UID after SOS 9, magic before - public uint uid4; // Checksum of UIDs 1 to 3 - public ushort crc16; // CRC16 of all header - public ushort languages; // Number of languages - public ushort files; // Number of files - public ushort requisites; // Number of requisites - public ushort inst_lang; // Installed language (only residual SIS) - public ushort inst_files; // Installed files (only residual SIS) - public ushort inst_drive; // Installed drive (only residual SIS), NULL or 0x0021 - public ushort capabilities; // Number of capabilities - public uint inst_version; // Version of Symbian Installer required - public ushort options; // Option flags - public ushort type; // Type - public ushort major; // Major version of application - public ushort minor; // Minor version of application - public uint variant; // Variant when SIS is a prerequisite for other SISs - public uint lang_ptr; // Pointer to language records - public uint files_ptr; // Pointer to file records - public uint reqs_ptr; // Pointer to requisite records - public uint certs_ptr; // Pointer to certificate records - public uint comp_ptr; // Pointer to component name record - // From EPOC Release 6 - public uint sig_ptr; // Pointer to signature record - public uint caps_ptr; // Pointer to capability records - public uint instspace; // Installed space (only residual SIS) - public uint maxinsspc; // Space required - public ulong reserved1; // Reserved - public ulong reserved2; // Reserved - } - } -} - -*/ - diff --git a/Aaru.Filesystems/SysV.cs b/Aaru.Filesystems/SysV.cs deleted file mode 100644 index 0ed84bd2f..000000000 --- a/Aaru.Filesystems/SysV.cs +++ /dev/null @@ -1,1120 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : SysV.cs -// Author(s) : Natalia Portillo -// -// Component : UNIX System V filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the UNIX System V filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -// ReSharper disable NotAccessedField.Local - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; - -// Information from the Linux kernel -/// -/// Implements detection of the UNIX System V filesystem -[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "UnusedMember.Local"), - SuppressMessage("ReSharper", "UnusedType.Local")] -public sealed class SysVfs : IFilesystem -{ - const uint XENIX_MAGIC = 0x002B5544; - const uint XENIX_CIGAM = 0x44552B00; - const uint SYSV_MAGIC = 0xFD187E20; - const uint SYSV_CIGAM = 0x207E18FD; - - // Rest have no magic. - // Per a Linux kernel, Coherent fs has following: - const string COH_FNAME = "noname"; - const string COH_FPACK = "nopack"; - const string COH_XXXXX = "xxxxx"; - const string COH_XXXXS = "xxxxx "; - const string COH_XXXXN = "xxxxx\n"; - - // SCO AFS - const ushort SCO_NFREE = 0xFFFF; - - // UNIX 7th Edition has nothing to detect it, so check for a valid filesystem is a must :( - const ushort V7_NICINOD = 100; - const ushort V7_NICFREE = 100; - const uint V7_MAXSIZE = 0x00FFFFFF; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "UNIX System V filesystem"; - /// - public Guid Id => new("9B8D016A-8561-400E-A12A-A198283C211D"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(2 + partition.Start >= partition.End) - return false; - - byte sb_size_in_sectors; - - if(imagePlugin.Info.SectorSize <= - 0x400) // Check if underlying device sector size is smaller than SuperBlock size - sb_size_in_sectors = (byte)(0x400 / imagePlugin.Info.SectorSize); - else - sb_size_in_sectors = 1; // If not a single sector can store it - - if(partition.End <= - partition.Start + 4 * (ulong)sb_size_in_sectors + - sb_size_in_sectors) // Device must be bigger than SB location + SB size + offset - return false; - - // Sectors in a cylinder - var spc = (int)(imagePlugin.Info.Heads * imagePlugin.Info.SectorsPerTrack); - - // Superblock can start on 0x000, 0x200, 0x600 and 0x800, not aligned, so we assume 16 (128 bytes/sector) sectors as a safe value - int[] locations = - { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - - // Superblock can also skip one cylinder (for boot) - spc - }; - - foreach(int i in locations.TakeWhile(i => (ulong)i + partition.Start + sb_size_in_sectors < - imagePlugin.Info.Sectors)) - { - ErrorNumber errno = - imagePlugin.ReadSectors((ulong)i + partition.Start, sb_size_in_sectors, out byte[] sb_sector); - - if(errno != ErrorNumber.NoError || - sb_sector.Length < 0x400) - continue; - - var magic = BitConverter.ToUInt32(sb_sector, 0x3F8); - - if(magic is XENIX_MAGIC or XENIX_CIGAM or SYSV_MAGIC or SYSV_CIGAM) - return true; - - magic = BitConverter.ToUInt32(sb_sector, 0x1F8); // System V magic location - - if(magic is SYSV_MAGIC or SYSV_CIGAM) - return true; - - magic = BitConverter.ToUInt32(sb_sector, 0x1F0); // XENIX 3 magic location - - if(magic is XENIX_MAGIC or XENIX_CIGAM) - return true; - - var coherent_string = new byte[6]; - Array.Copy(sb_sector, 0x1E4, coherent_string, 0, 6); // Coherent UNIX s_fname location - string s_fname = StringHandlers.CToString(coherent_string); - Array.Copy(sb_sector, 0x1EA, coherent_string, 0, 6); // Coherent UNIX s_fpack location - string s_fpack = StringHandlers.CToString(coherent_string); - - if(s_fname == COH_FNAME && s_fpack == COH_FPACK || - s_fname == COH_XXXXX && s_fpack == COH_XXXXX || - s_fname == COH_XXXXS && s_fpack == COH_XXXXN) - return true; - - // Now try to identify 7th edition - var s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); - var s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); - var s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0); - - if(s_fsize is <= 0 or >= 0xFFFFFFFF || - s_nfree is <= 0 or >= 0xFFFF || - s_ninode is <= 0 or >= 0xFFFF) - continue; - - if((s_fsize & 0xFF) == 0x00 && - (s_nfree & 0xFF) == 0x00 && - (s_ninode & 0xFF) == 0x00) - { - // Byteswap - s_fsize = ((s_fsize & 0xFF) << 24) + ((s_fsize & 0xFF00) << 8) + ((s_fsize & 0xFF0000) >> 8) + - ((s_fsize & 0xFF000000) >> 24); - - s_nfree = (ushort)(s_nfree >> 8); - s_ninode = (ushort)(s_ninode >> 8); - } - - if((s_fsize & 0xFF000000) != 0x00 || - (s_nfree & 0xFF00) != 0x00 || - (s_ninode & 0xFF00) != 0x00) - continue; - - if(s_fsize >= V7_MAXSIZE || - s_nfree >= V7_NICFREE || - s_ninode >= V7_NICINOD) - continue; - - if(s_fsize * 1024 == (partition.End - partition.Start) * imagePlugin.Info.SectorSize || - s_fsize * 512 == (partition.End - partition.Start) * imagePlugin.Info.SectorSize) - return true; - } - - return false; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - var sb = new StringBuilder(); - var bigEndian = false; // Start in little endian until we know what are we handling here - var start = 0; - var xenix = false; - var sysv = false; - var sys7th = false; - var coherent = false; - var xenix3 = false; - byte[] sb_sector; - byte sb_size_in_sectors; - var offset = 0; - - if(imagePlugin.Info.SectorSize <= - 0x400) // Check if underlying device sector size is smaller than SuperBlock size - sb_size_in_sectors = (byte)(0x400 / imagePlugin.Info.SectorSize); - else - sb_size_in_sectors = 1; // If not a single sector can store it - - // Sectors in a cylinder - var spc = (int)(imagePlugin.Info.Heads * imagePlugin.Info.SectorsPerTrack); - - // Superblock can start on 0x000, 0x200, 0x600 and 0x800, not aligned, so we assume 16 (128 bytes/sector) sectors as a safe value - int[] locations = - { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - - // Superblock can also skip one cylinder (for boot) - spc - }; - - ErrorNumber errno; - - foreach(int i in locations) - { - errno = imagePlugin.ReadSectors((ulong)i + partition.Start, sb_size_in_sectors, out sb_sector); - - if(errno != ErrorNumber.NoError) - continue; - - var magic = BitConverter.ToUInt32(sb_sector, 0x3F8); - - if(magic is XENIX_MAGIC or SYSV_MAGIC) - { - if(magic == SYSV_MAGIC) - { - sysv = true; - offset = 0x200; - } - else - xenix = true; - - start = i; - - break; - } - - if(magic is XENIX_CIGAM or SYSV_CIGAM) - { - bigEndian = true; // Big endian - - if(magic == SYSV_CIGAM) - { - sysv = true; - offset = 0x200; - } - else - xenix = true; - - start = i; - - break; - } - - magic = BitConverter.ToUInt32(sb_sector, 0x1F0); // XENIX 3 magic location - - if(magic == XENIX_MAGIC) - { - xenix3 = true; - start = i; - - break; - } - - if(magic == XENIX_CIGAM) - { - bigEndian = true; // Big endian - xenix3 = true; - start = i; - - break; - } - - magic = BitConverter.ToUInt32(sb_sector, 0x1F8); // XENIX magic location - - if(magic == SYSV_MAGIC) - { - sysv = true; - start = i; - - break; - } - - if(magic == SYSV_CIGAM) - { - bigEndian = true; // Big endian - sysv = true; - start = i; - - break; - } - - var coherent_string = new byte[6]; - Array.Copy(sb_sector, 0x1E4, coherent_string, 0, 6); // Coherent UNIX s_fname location - string s_fname = StringHandlers.CToString(coherent_string, Encoding); - Array.Copy(sb_sector, 0x1EA, coherent_string, 0, 6); // Coherent UNIX s_fpack location - string s_fpack = StringHandlers.CToString(coherent_string, Encoding); - - if(s_fname == COH_FNAME && s_fpack == COH_FPACK || - s_fname == COH_XXXXX && s_fpack == COH_XXXXX || - s_fname == COH_XXXXS && s_fpack == COH_XXXXN) - { - coherent = true; - start = i; - - break; - } - - // Now try to identify 7th edition - var s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); - var s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); - var s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0); - - if(s_fsize is <= 0 or >= 0xFFFFFFFF || - s_nfree is <= 0 or >= 0xFFFF || - s_ninode is <= 0 or >= 0xFFFF) - continue; - - if((s_fsize & 0xFF) == 0x00 && - (s_nfree & 0xFF) == 0x00 && - (s_ninode & 0xFF) == 0x00) - { - // Byteswap - s_fsize = ((s_fsize & 0xFF) << 24) + ((s_fsize & 0xFF00) << 8) + ((s_fsize & 0xFF0000) >> 8) + - ((s_fsize & 0xFF000000) >> 24); - - s_nfree = (ushort)(s_nfree >> 8); - s_ninode = (ushort)(s_ninode >> 8); - } - - if((s_fsize & 0xFF000000) != 0x00 || - (s_nfree & 0xFF00) != 0x00 || - (s_ninode & 0xFF00) != 0x00) - continue; - - if(s_fsize >= V7_MAXSIZE || - s_nfree >= V7_NICFREE || - s_ninode >= V7_NICINOD) - continue; - - if(s_fsize * 1024 != (partition.End - partition.Start) * imagePlugin.Info.SectorSize && - s_fsize * 512 != (partition.End - partition.Start) * imagePlugin.Info.SectorSize) - continue; - - sys7th = true; - start = i; - - break; - } - - if(!sys7th && - !sysv && - !coherent && - !xenix && - !xenix3) - return; - - XmlFsType = new FileSystemType(); - - if(xenix || xenix3) - { - var xenix_strings = new byte[6]; - var xnx_sb = new XenixSuperBlock(); - errno = imagePlugin.ReadSectors((ulong)start + partition.Start, sb_size_in_sectors, out sb_sector); - - if(errno != ErrorNumber.NoError) - return; - - if(xenix3) - { - xnx_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000); - xnx_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); - xnx_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); - xnx_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0); - xnx_sb.s_flock = sb_sector[0x19A]; - xnx_sb.s_ilock = sb_sector[0x19B]; - xnx_sb.s_fmod = sb_sector[0x19C]; - xnx_sb.s_ronly = sb_sector[0x19D]; - xnx_sb.s_time = BitConverter.ToInt32(sb_sector, 0x19E); - xnx_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1A2); - xnx_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1A6); - xnx_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x1A8); - xnx_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x1AA); - xnx_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x1AC); - xnx_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x1AE); - Array.Copy(sb_sector, 0x1B0, xenix_strings, 0, 6); - xnx_sb.s_fname = StringHandlers.CToString(xenix_strings, Encoding); - Array.Copy(sb_sector, 0x1B6, xenix_strings, 0, 6); - xnx_sb.s_fpack = StringHandlers.CToString(xenix_strings, Encoding); - xnx_sb.s_clean = sb_sector[0x1BC]; - xnx_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x1F0); - xnx_sb.s_type = BitConverter.ToUInt32(sb_sector, 0x1F4); - } - else - { - xnx_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000); - xnx_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); - xnx_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); - xnx_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x198); - xnx_sb.s_flock = sb_sector[0x262]; - xnx_sb.s_ilock = sb_sector[0x263]; - xnx_sb.s_fmod = sb_sector[0x264]; - xnx_sb.s_ronly = sb_sector[0x265]; - xnx_sb.s_time = BitConverter.ToInt32(sb_sector, 0x266); - xnx_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x26A); - xnx_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x26E); - xnx_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x270); - xnx_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x272); - xnx_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x274); - xnx_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x276); - Array.Copy(sb_sector, 0x278, xenix_strings, 0, 6); - xnx_sb.s_fname = StringHandlers.CToString(xenix_strings, Encoding); - Array.Copy(sb_sector, 0x27E, xenix_strings, 0, 6); - xnx_sb.s_fpack = StringHandlers.CToString(xenix_strings, Encoding); - xnx_sb.s_clean = sb_sector[0x284]; - xnx_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x3F8); - xnx_sb.s_type = BitConverter.ToUInt32(sb_sector, 0x3FC); - } - - if(bigEndian) - { - xnx_sb.s_isize = Swapping.Swap(xnx_sb.s_isize); - xnx_sb.s_fsize = Swapping.Swap(xnx_sb.s_fsize); - xnx_sb.s_nfree = Swapping.Swap(xnx_sb.s_nfree); - xnx_sb.s_ninode = Swapping.Swap(xnx_sb.s_ninode); - xnx_sb.s_time = Swapping.Swap(xnx_sb.s_time); - xnx_sb.s_tfree = Swapping.Swap(xnx_sb.s_tfree); - xnx_sb.s_tinode = Swapping.Swap(xnx_sb.s_tinode); - xnx_sb.s_cylblks = Swapping.Swap(xnx_sb.s_cylblks); - xnx_sb.s_gapblks = Swapping.Swap(xnx_sb.s_gapblks); - xnx_sb.s_dinfo0 = Swapping.Swap(xnx_sb.s_dinfo0); - xnx_sb.s_dinfo1 = Swapping.Swap(xnx_sb.s_dinfo1); - xnx_sb.s_magic = Swapping.Swap(xnx_sb.s_magic); - xnx_sb.s_type = Swapping.Swap(xnx_sb.s_type); - } - - uint bs = 512; - sb.AppendLine("XENIX filesystem"); - XmlFsType.Type = "XENIX fs"; - - switch(xnx_sb.s_type) - { - case 1: - sb.AppendLine("512 bytes per block"); - XmlFsType.ClusterSize = 512; - - break; - case 2: - sb.AppendLine("1024 bytes per block"); - bs = 1024; - XmlFsType.ClusterSize = 1024; - - break; - case 3: - sb.AppendLine("2048 bytes per block"); - bs = 2048; - XmlFsType.ClusterSize = 2048; - - break; - default: - sb.AppendFormat("Unknown s_type value: 0x{0:X8}", xnx_sb.s_type).AppendLine(); - - break; - } - - if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448) - { - if(bs != 2048) - sb. - AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/sector", - bs, 2048).AppendLine(); - } - else - { - if(bs != imagePlugin.Info.SectorSize) - sb. - AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/sector", - bs, imagePlugin.Info.SectorSize).AppendLine(); - } - - sb.AppendFormat("{0} zones on volume ({1} bytes)", xnx_sb.s_fsize, xnx_sb.s_fsize * bs).AppendLine(); - - sb.AppendFormat("{0} free zones on volume ({1} bytes)", xnx_sb.s_tfree, xnx_sb.s_tfree * bs).AppendLine(); - - sb.AppendFormat("{0} free blocks on list ({1} bytes)", xnx_sb.s_nfree, xnx_sb.s_nfree * bs).AppendLine(); - - sb.AppendFormat("{0} blocks per cylinder ({1} bytes)", xnx_sb.s_cylblks, xnx_sb.s_cylblks * bs). - AppendLine(); - - sb.AppendFormat("{0} blocks per gap ({1} bytes)", xnx_sb.s_gapblks, xnx_sb.s_gapblks * bs).AppendLine(); - sb.AppendFormat("First data zone: {0}", xnx_sb.s_isize).AppendLine(); - sb.AppendFormat("{0} free inodes on volume", xnx_sb.s_tinode).AppendLine(); - sb.AppendFormat("{0} free inodes on list", xnx_sb.s_ninode).AppendLine(); - - if(xnx_sb.s_flock > 0) - sb.AppendLine("Free block list is locked"); - - if(xnx_sb.s_ilock > 0) - sb.AppendLine("inode cache is locked"); - - if(xnx_sb.s_fmod > 0) - sb.AppendLine("Superblock is being modified"); - - if(xnx_sb.s_ronly > 0) - sb.AppendLine("Volume is mounted read-only"); - - sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UnixToDateTime(xnx_sb.s_time)).AppendLine(); - - if(xnx_sb.s_time != 0) - { - XmlFsType.ModificationDate = DateHandlers.UnixToDateTime(xnx_sb.s_time); - XmlFsType.ModificationDateSpecified = true; - } - - sb.AppendFormat("Volume name: {0}", xnx_sb.s_fname).AppendLine(); - XmlFsType.VolumeName = xnx_sb.s_fname; - sb.AppendFormat("Pack name: {0}", xnx_sb.s_fpack).AppendLine(); - - if(xnx_sb.s_clean == 0x46) - sb.AppendLine("Volume is clean"); - else - { - sb.AppendLine("Volume is dirty"); - XmlFsType.Dirty = true; - } - } - - if(sysv) - { - errno = imagePlugin.ReadSectors((ulong)start + partition.Start, sb_size_in_sectors, out sb_sector); - - if(errno != ErrorNumber.NoError) - return; - - var sysv_strings = new byte[6]; - - var sysv_sb = new SystemVRelease4SuperBlock - { - s_type = BitConverter.ToUInt32(sb_sector, 0x1FC + offset) - }; - - if(bigEndian) - sysv_sb.s_type = Swapping.Swap(sysv_sb.s_type); - - uint bs = 512; - - switch(sysv_sb.s_type) - { - case 1: - XmlFsType.ClusterSize = 512; - - break; - case 2: - bs = 1024; - XmlFsType.ClusterSize = 1024; - - break; - case 3: - bs = 2048; - XmlFsType.ClusterSize = 2048; - - break; - default: - sb.AppendFormat("Unknown s_type value: 0x{0:X8}", sysv_sb.s_type).AppendLine(); - - break; - } - - sysv_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002 + offset); - - if(bigEndian) - sysv_sb.s_fsize = Swapping.Swap(sysv_sb.s_fsize); - - bool sysvr4 = sysv_sb.s_fsize * bs <= 0 || sysv_sb.s_fsize * bs != partition.Size; - - if(sysvr4) - { - sysv_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000 + offset); - sysv_sb.s_state = BitConverter.ToUInt32(sb_sector, 0x1F4 + offset); - sysv_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x1F8 + offset); - sysv_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x004 + offset); - sysv_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x008 + offset); - sysv_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D4 + offset); - sysv_sb.s_flock = sb_sector[0x1A0 + offset]; - sysv_sb.s_ilock = sb_sector[0x1A1 + offset]; - sysv_sb.s_fmod = sb_sector[0x1A2 + offset]; - sysv_sb.s_ronly = sb_sector[0x1A3 + offset]; - sysv_sb.s_time = BitConverter.ToUInt32(sb_sector, 0x1A4 + offset); - sysv_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x1A8 + offset); - sysv_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x1AA + offset); - sysv_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x1AC + offset); - sysv_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x1AE + offset); - sysv_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1B0 + offset); - sysv_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1B4 + offset); - Array.Copy(sb_sector, 0x1B6 + offset, sysv_strings, 0, 6); - sysv_sb.s_fname = StringHandlers.CToString(sysv_strings, Encoding); - Array.Copy(sb_sector, 0x1BC + offset, sysv_strings, 0, 6); - sysv_sb.s_fpack = StringHandlers.CToString(sysv_strings, Encoding); - sb.AppendLine("System V Release 4 filesystem"); - XmlFsType.Type = "SVR4 fs"; - } - else - { - sysv_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000 + offset); - sysv_sb.s_state = BitConverter.ToUInt32(sb_sector, 0x1F4 + offset); - sysv_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x1F8 + offset); - sysv_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002 + offset); - sysv_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006 + offset); - sysv_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0 + offset); - sysv_sb.s_flock = sb_sector[0x19A + offset]; - sysv_sb.s_ilock = sb_sector[0x19B + offset]; - sysv_sb.s_fmod = sb_sector[0x19C + offset]; - sysv_sb.s_ronly = sb_sector[0x19D + offset]; - sysv_sb.s_time = BitConverter.ToUInt32(sb_sector, 0x19E + offset); - sysv_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x1A2 + offset); - sysv_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x1A4 + offset); - sysv_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x1A6 + offset); - sysv_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x1A8 + offset); - sysv_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1AA + offset); - sysv_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1AE + offset); - Array.Copy(sb_sector, 0x1B0 + offset, sysv_strings, 0, 6); - sysv_sb.s_fname = StringHandlers.CToString(sysv_strings, Encoding); - Array.Copy(sb_sector, 0x1B6 + offset, sysv_strings, 0, 6); - sysv_sb.s_fpack = StringHandlers.CToString(sysv_strings, Encoding); - sb.AppendLine("System V Release 2 filesystem"); - XmlFsType.Type = "SVR2 fs"; - } - - if(bigEndian) - { - sysv_sb.s_isize = Swapping.Swap(sysv_sb.s_isize); - sysv_sb.s_state = Swapping.Swap(sysv_sb.s_state); - sysv_sb.s_magic = Swapping.Swap(sysv_sb.s_magic); - sysv_sb.s_fsize = Swapping.Swap(sysv_sb.s_fsize); - sysv_sb.s_nfree = Swapping.Swap(sysv_sb.s_nfree); - sysv_sb.s_ninode = Swapping.Swap(sysv_sb.s_ninode); - sysv_sb.s_time = Swapping.Swap(sysv_sb.s_time); - sysv_sb.s_cylblks = Swapping.Swap(sysv_sb.s_cylblks); - sysv_sb.s_gapblks = Swapping.Swap(sysv_sb.s_gapblks); - sysv_sb.s_dinfo0 = Swapping.Swap(sysv_sb.s_dinfo0); - sysv_sb.s_dinfo1 = Swapping.Swap(sysv_sb.s_dinfo1); - sysv_sb.s_tfree = Swapping.Swap(sysv_sb.s_tfree); - sysv_sb.s_tinode = Swapping.Swap(sysv_sb.s_tinode); - } - - sb.AppendFormat("{0} bytes per block", bs).AppendLine(); - - XmlFsType.Clusters = sysv_sb.s_fsize; - sb.AppendFormat("{0} zones on volume ({1} bytes)", sysv_sb.s_fsize, sysv_sb.s_fsize * bs).AppendLine(); - - sb.AppendFormat("{0} free zones on volume ({1} bytes)", sysv_sb.s_tfree, sysv_sb.s_tfree * bs).AppendLine(); - - sb.AppendFormat("{0} free blocks on list ({1} bytes)", sysv_sb.s_nfree, sysv_sb.s_nfree * bs).AppendLine(); - - sb.AppendFormat("{0} blocks per cylinder ({1} bytes)", sysv_sb.s_cylblks, sysv_sb.s_cylblks * bs). - AppendLine(); - - sb.AppendFormat("{0} blocks per gap ({1} bytes)", sysv_sb.s_gapblks, sysv_sb.s_gapblks * bs).AppendLine(); - - sb.AppendFormat("First data zone: {0}", sysv_sb.s_isize).AppendLine(); - sb.AppendFormat("{0} free inodes on volume", sysv_sb.s_tinode).AppendLine(); - sb.AppendFormat("{0} free inodes on list", sysv_sb.s_ninode).AppendLine(); - - if(sysv_sb.s_flock > 0) - sb.AppendLine("Free block list is locked"); - - if(sysv_sb.s_ilock > 0) - sb.AppendLine("inode cache is locked"); - - if(sysv_sb.s_fmod > 0) - sb.AppendLine("Superblock is being modified"); - - if(sysv_sb.s_ronly > 0) - sb.AppendLine("Volume is mounted read-only"); - - sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UnixUnsignedToDateTime(sysv_sb.s_time)). - AppendLine(); - - if(sysv_sb.s_time != 0) - { - XmlFsType.ModificationDate = DateHandlers.UnixUnsignedToDateTime(sysv_sb.s_time); - XmlFsType.ModificationDateSpecified = true; - } - - sb.AppendFormat("Volume name: {0}", sysv_sb.s_fname).AppendLine(); - XmlFsType.VolumeName = sysv_sb.s_fname; - sb.AppendFormat("Pack name: {0}", sysv_sb.s_fpack).AppendLine(); - - if(sysv_sb.s_state == 0x7C269D38 - sysv_sb.s_time) - sb.AppendLine("Volume is clean"); - else - { - sb.AppendLine("Volume is dirty"); - XmlFsType.Dirty = true; - } - } - - if(coherent) - { - errno = imagePlugin.ReadSectors((ulong)start + partition.Start, sb_size_in_sectors, out sb_sector); - - if(errno != ErrorNumber.NoError) - return; - - var coh_sb = new CoherentSuperBlock(); - var coh_strings = new byte[6]; - - coh_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000); - coh_sb.s_fsize = Swapping.PDPFromLittleEndian(BitConverter.ToUInt32(sb_sector, 0x002)); - coh_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); - coh_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x108); - coh_sb.s_flock = sb_sector[0x1D2]; - coh_sb.s_ilock = sb_sector[0x1D3]; - coh_sb.s_fmod = sb_sector[0x1D4]; - coh_sb.s_ronly = sb_sector[0x1D5]; - coh_sb.s_time = Swapping.PDPFromLittleEndian(BitConverter.ToUInt32(sb_sector, 0x1D6)); - coh_sb.s_tfree = Swapping.PDPFromLittleEndian(BitConverter.ToUInt32(sb_sector, 0x1DA)); - coh_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1DE); - coh_sb.s_int_m = BitConverter.ToUInt16(sb_sector, 0x1E0); - coh_sb.s_int_n = BitConverter.ToUInt16(sb_sector, 0x1E2); - Array.Copy(sb_sector, 0x1E4, coh_strings, 0, 6); - coh_sb.s_fname = StringHandlers.CToString(coh_strings, Encoding); - Array.Copy(sb_sector, 0x1EA, coh_strings, 0, 6); - coh_sb.s_fpack = StringHandlers.CToString(coh_strings, Encoding); - - XmlFsType.Type = "Coherent fs"; - XmlFsType.ClusterSize = 512; - XmlFsType.Clusters = coh_sb.s_fsize; - - sb.AppendLine("Coherent UNIX filesystem"); - - if(imagePlugin.Info.SectorSize != 512) - sb.AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/sector", - 512, 2048).AppendLine(); - - sb.AppendFormat("{0} zones on volume ({1} bytes)", coh_sb.s_fsize, coh_sb.s_fsize * 512).AppendLine(); - - sb.AppendFormat("{0} free zones on volume ({1} bytes)", coh_sb.s_tfree, coh_sb.s_tfree * 512).AppendLine(); - - sb.AppendFormat("{0} free blocks on list ({1} bytes)", coh_sb.s_nfree, coh_sb.s_nfree * 512).AppendLine(); - - sb.AppendFormat("First data zone: {0}", coh_sb.s_isize).AppendLine(); - sb.AppendFormat("{0} free inodes on volume", coh_sb.s_tinode).AppendLine(); - sb.AppendFormat("{0} free inodes on list", coh_sb.s_ninode).AppendLine(); - - if(coh_sb.s_flock > 0) - sb.AppendLine("Free block list is locked"); - - if(coh_sb.s_ilock > 0) - sb.AppendLine("inode cache is locked"); - - if(coh_sb.s_fmod > 0) - sb.AppendLine("Superblock is being modified"); - - if(coh_sb.s_ronly > 0) - sb.AppendLine("Volume is mounted read-only"); - - sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UnixUnsignedToDateTime(coh_sb.s_time)). - AppendLine(); - - if(coh_sb.s_time != 0) - { - XmlFsType.ModificationDate = DateHandlers.UnixUnsignedToDateTime(coh_sb.s_time); - XmlFsType.ModificationDateSpecified = true; - } - - sb.AppendFormat("Volume name: {0}", coh_sb.s_fname).AppendLine(); - XmlFsType.VolumeName = coh_sb.s_fname; - sb.AppendFormat("Pack name: {0}", coh_sb.s_fpack).AppendLine(); - } - - if(sys7th) - { - errno = imagePlugin.ReadSectors((ulong)start + partition.Start, sb_size_in_sectors, out sb_sector); - - if(errno != ErrorNumber.NoError) - return; - - var v7_sb = new UNIX7thEditionSuperBlock(); - var sys7_strings = new byte[6]; - - v7_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000); - v7_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); - v7_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); - v7_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0); - v7_sb.s_flock = sb_sector[0x19A]; - v7_sb.s_ilock = sb_sector[0x19B]; - v7_sb.s_fmod = sb_sector[0x19C]; - v7_sb.s_ronly = sb_sector[0x19D]; - v7_sb.s_time = BitConverter.ToUInt32(sb_sector, 0x19E); - v7_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1A2); - v7_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1A6); - v7_sb.s_int_m = BitConverter.ToUInt16(sb_sector, 0x1A8); - v7_sb.s_int_n = BitConverter.ToUInt16(sb_sector, 0x1AA); - Array.Copy(sb_sector, 0x1AC, sys7_strings, 0, 6); - v7_sb.s_fname = StringHandlers.CToString(sys7_strings, Encoding); - Array.Copy(sb_sector, 0x1B2, sys7_strings, 0, 6); - v7_sb.s_fpack = StringHandlers.CToString(sys7_strings, Encoding); - - XmlFsType.Type = "UNIX 7th Edition fs"; - XmlFsType.ClusterSize = 512; - XmlFsType.Clusters = v7_sb.s_fsize; - sb.AppendLine("UNIX 7th Edition filesystem"); - - if(imagePlugin.Info.SectorSize != 512) - sb.AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/sector", - 512, 2048).AppendLine(); - - sb.AppendFormat("{0} zones on volume ({1} bytes)", v7_sb.s_fsize, v7_sb.s_fsize * 512).AppendLine(); - - sb.AppendFormat("{0} free zones on volume ({1} bytes)", v7_sb.s_tfree, v7_sb.s_tfree * 512).AppendLine(); - - sb.AppendFormat("{0} free blocks on list ({1} bytes)", v7_sb.s_nfree, v7_sb.s_nfree * 512).AppendLine(); - sb.AppendFormat("First data zone: {0}", v7_sb.s_isize).AppendLine(); - sb.AppendFormat("{0} free inodes on volume", v7_sb.s_tinode).AppendLine(); - sb.AppendFormat("{0} free inodes on list", v7_sb.s_ninode).AppendLine(); - - if(v7_sb.s_flock > 0) - sb.AppendLine("Free block list is locked"); - - if(v7_sb.s_ilock > 0) - sb.AppendLine("inode cache is locked"); - - if(v7_sb.s_fmod > 0) - sb.AppendLine("Superblock is being modified"); - - if(v7_sb.s_ronly > 0) - sb.AppendLine("Volume is mounted read-only"); - - sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UnixUnsignedToDateTime(v7_sb.s_time)). - AppendLine(); - - if(v7_sb.s_time != 0) - { - XmlFsType.ModificationDate = DateHandlers.UnixUnsignedToDateTime(v7_sb.s_time); - XmlFsType.ModificationDateSpecified = true; - } - - sb.AppendFormat("Volume name: {0}", v7_sb.s_fname).AppendLine(); - XmlFsType.VolumeName = v7_sb.s_fname; - sb.AppendFormat("Pack name: {0}", v7_sb.s_fpack).AppendLine(); - } - - information = sb.ToString(); - } - - // Old XENIX use different offsets - struct XenixSuperBlock - { - /// 0x000, index of first data zone - public ushort s_isize; - /// 0x002, total number of zones of this volume - public uint s_fsize; - - // the start of the free block list: - /// 0x006, blocks in s_free, <=100 - public ushort s_nfree; - /// 0x008, 100 entries, 50 entries for Xenix 3, first free block list chunk - public uint[] s_free; - - // the cache of free inodes: - /// 0x198 (0xD0), number of inodes in s_inode, <= 100 - public ushort s_ninode; - /// 0x19A (0xD2), 100 entries, some free inodes - public ushort[] s_inode; - /// 0x262 (0x19A), free block list manipulation lock - public byte s_flock; - /// 0x263 (0x19B), inode cache manipulation lock - public byte s_ilock; - /// 0x264 (0x19C), superblock modification flag - public byte s_fmod; - /// 0x265 (0x19D), read-only mounted flag - public byte s_ronly; - /// 0x266 (0x19E), time of last superblock update - public int s_time; - /// 0x26A (0x1A2), total number of free zones - public uint s_tfree; - /// 0x26E (0x1A6), total number of free inodes - public ushort s_tinode; - /// 0x270 (0x1A8), blocks per cylinder - public ushort s_cylblks; - /// 0x272 (0x1AA), blocks per gap - public ushort s_gapblks; - /// 0x274 (0x1AC), device information ?? - public ushort s_dinfo0; - /// 0x276 (0x1AE), device information ?? - public ushort s_dinfo1; - /// 0x278 (0x1B0), 6 bytes, volume name - public string s_fname; - /// 0x27E (0x1B6), 6 bytes, pack name - public string s_fpack; - /// 0x284 (0x1BC), 0x46 if volume is clean - public byte s_clean; - /// 0x285 (0x1BD), 371 bytes, 51 bytes for Xenix 3 - public byte[] s_fill; - /// 0x3F8 (0x1F0), magic - public uint s_magic; - /// 0x3FC (0x1F4), filesystem type (1 = 512 bytes/blk, 2 = 1024 bytes/blk, 3 = 2048 bytes/blk) - public uint s_type; - } - - struct SystemVRelease4SuperBlock - { - /// 0x000, index of first data zone - public ushort s_isize; - /// 0x002, padding - public ushort s_pad0; - /// 0x004, total number of zones of this volume - public uint s_fsize; - - // the start of the free block list: - /// 0x008, blocks in s_free, <=100 - public ushort s_nfree; - /// 0x00A, padding - public ushort s_pad1; - /// 0x00C, 50 entries, first free block list chunk - public uint[] s_free; - - // the cache of free inodes: - /// 0x0D4, number of inodes in s_inode, <= 100 - public ushort s_ninode; - /// 0x0D6, padding - public ushort s_pad2; - /// 0x0D8, 100 entries, some free inodes - public ushort[] s_inode; - /// 0x1A0, free block list manipulation lock - public byte s_flock; - /// 0x1A1, inode cache manipulation lock - public byte s_ilock; - /// 0x1A2, superblock modification flag - public byte s_fmod; - /// 0x1A3, read-only mounted flag - public byte s_ronly; - /// 0x1A4, time of last superblock update - public uint s_time; - /// 0x1A8, blocks per cylinder - public ushort s_cylblks; - /// 0x1AA, blocks per gap - public ushort s_gapblks; - /// 0x1AC, device information ?? - public ushort s_dinfo0; - /// 0x1AE, device information ?? - public ushort s_dinfo1; - /// 0x1B0, total number of free zones - public uint s_tfree; - /// 0x1B4, total number of free inodes - public ushort s_tinode; - /// 0x1B6, padding - public ushort s_pad3; - /// 0x1B8, 6 bytes, volume name - public string s_fname; - /// 0x1BE, 6 bytes, pack name - public string s_fpack; - /// 0x1C4, 48 bytes - public byte[] s_fill; - /// 0x1F4, if s_state == (0x7C269D38 - s_time) then filesystem is clean - public uint s_state; - /// 0x1F8, magic - public uint s_magic; - /// 0x1FC, filesystem type (1 = 512 bytes/blk, 2 = 1024 bytes/blk) - public uint s_type; - } - - struct SystemVRelease2SuperBlock - { - /// 0x000, index of first data zone - public ushort s_isize; - /// 0x002, total number of zones of this volume - public uint s_fsize; - - // the start of the free block list: - /// 0x006, blocks in s_free, <=100 - public ushort s_nfree; - /// 0x008, 50 entries, first free block list chunk - public uint[] s_free; - - // the cache of free inodes: - /// 0x0D0, number of inodes in s_inode, <= 100 - public ushort s_ninode; - /// 0x0D2, 100 entries, some free inodes - public ushort[] s_inode; - /// 0x19A, free block list manipulation lock - public byte s_flock; - /// 0x19B, inode cache manipulation lock - public byte s_ilock; - /// 0x19C, superblock modification flag - public byte s_fmod; - /// 0x19D, read-only mounted flag - public byte s_ronly; - /// 0x19E, time of last superblock update - public uint s_time; - /// 0x1A2, blocks per cylinder - public ushort s_cylblks; - /// 0x1A4, blocks per gap - public ushort s_gapblks; - /// 0x1A6, device information ?? - public ushort s_dinfo0; - /// 0x1A8, device information ?? - public ushort s_dinfo1; - /// 0x1AA, total number of free zones - public uint s_tfree; - /// 0x1AE, total number of free inodes - public ushort s_tinode; - /// 0x1B0, 6 bytes, volume name - public string s_fname; - /// 0x1B6, 6 bytes, pack name - public string s_fpack; - /// 0x1BC, 56 bytes - public byte[] s_fill; - /// 0x1F4, if s_state == (0x7C269D38 - s_time) then filesystem is clean - public uint s_state; - /// 0x1F8, magic - public uint s_magic; - /// 0x1FC, filesystem type (1 = 512 bytes/blk, 2 = 1024 bytes/blk) - public uint s_type; - } - - struct UNIX7thEditionSuperBlock - { - /// 0x000, index of first data zone - public ushort s_isize; - /// 0x002, total number of zones of this volume - public uint s_fsize; - - // the start of the free block list: - /// 0x006, blocks in s_free, <=100 - public ushort s_nfree; - /// 0x008, 50 entries, first free block list chunk - public uint[] s_free; - - // the cache of free inodes: - /// 0x0D0, number of inodes in s_inode, <= 100 - public ushort s_ninode; - /// 0x0D2, 100 entries, some free inodes - public ushort[] s_inode; - /// 0x19A, free block list manipulation lock - public byte s_flock; - /// 0x19B, inode cache manipulation lock - public byte s_ilock; - /// 0x19C, superblock modification flag - public byte s_fmod; - /// 0x19D, read-only mounted flag - public byte s_ronly; - /// 0x19E, time of last superblock update - public uint s_time; - /// 0x1A2, total number of free zones - public uint s_tfree; - /// 0x1A6, total number of free inodes - public ushort s_tinode; - /// 0x1A8, interleave factor - public ushort s_int_m; - /// 0x1AA, interleave factor - public ushort s_int_n; - /// 0x1AC, 6 bytes, volume name - public string s_fname; - /// 0x1B2, 6 bytes, pack name - public string s_fpack; - } - - struct CoherentSuperBlock - { - /// 0x000, index of first data zone - public ushort s_isize; - /// 0x002, total number of zones of this volume - public uint s_fsize; - - // the start of the free block list: - /// 0x006, blocks in s_free, <=100 - public ushort s_nfree; - /// 0x008, 64 entries, first free block list chunk - public uint[] s_free; - - // the cache of free inodes: - /// 0x108, number of inodes in s_inode, <= 100 - public ushort s_ninode; - /// 0x10A, 100 entries, some free inodes - public ushort[] s_inode; - /// 0x1D2, free block list manipulation lock - public byte s_flock; - /// 0x1D3, inode cache manipulation lock - public byte s_ilock; - /// 0x1D4, superblock modification flag - public byte s_fmod; - /// 0x1D5, read-only mounted flag - public byte s_ronly; - /// 0x1D6, time of last superblock update - public uint s_time; - /// 0x1DE, total number of free zones - public uint s_tfree; - /// 0x1E2, total number of free inodes - public ushort s_tinode; - /// 0x1E4, interleave factor - public ushort s_int_m; - /// 0x1E6, interleave factor - public ushort s_int_n; - /// 0x1E8, 6 bytes, volume name - public string s_fname; - /// 0x1EE, 6 bytes, pack name - public string s_fpack; - /// 0x1F4, zero-filled - public uint s_unique; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/SysV/Consts.cs b/Aaru.Filesystems/SysV/Consts.cs new file mode 100644 index 000000000..0c35fa39d --- /dev/null +++ b/Aaru.Filesystems/SysV/Consts.cs @@ -0,0 +1,69 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : UNIX System V filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable NotAccessedField.Local + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the UNIX System V filesystem +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class SysVfs +{ + const uint XENIX_MAGIC = 0x002B5544; + const uint XENIX_CIGAM = 0x44552B00; + const uint SYSV_MAGIC = 0xFD187E20; + const uint SYSV_CIGAM = 0x207E18FD; + + // Rest have no magic. + // Per a Linux kernel, Coherent fs has following: + const string COH_FNAME = "noname"; + const string COH_FPACK = "nopack"; + const string COH_XXXXX = "xxxxx"; + const string COH_XXXXS = "xxxxx "; + const string COH_XXXXN = "xxxxx\n"; + + // SCO AFS + const ushort SCO_NFREE = 0xFFFF; + + // UNIX 7th Edition has nothing to detect it, so check for a valid filesystem is a must :( + const ushort V7_NICINOD = 100; + const ushort V7_NICFREE = 100; + const uint V7_MAXSIZE = 0x00FFFFFF; + + const string FS_TYPE_XENIX = "xenixfs"; + const string FS_TYPE_SVR4 = "sysv_r4"; + const string FS_TYPE_SVR2 = "sysv_r2"; + const string FS_TYPE_COHERENT = "coherent"; + const string FS_TYPE_UNIX7 = "unix7fs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/SysV/Info.cs b/Aaru.Filesystems/SysV/Info.cs new file mode 100644 index 000000000..3fe27dcbc --- /dev/null +++ b/Aaru.Filesystems/SysV/Info.cs @@ -0,0 +1,805 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : UNIX System V filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable NotAccessedField.Local + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the UNIX System V filesystem +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class SysVfs +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(2 + partition.Start >= partition.End) return false; + + byte sb_size_in_sectors; + + if(imagePlugin.Info.SectorSize <= + 0x400) // Check if underlying device sector size is smaller than SuperBlock size + sb_size_in_sectors = (byte)(0x400 / imagePlugin.Info.SectorSize); + else + sb_size_in_sectors = 1; // If not a single sector can store it + + if(partition.End <= + partition.Start + + 4 * (ulong)sb_size_in_sectors + + sb_size_in_sectors) // Device must be bigger than SB location + SB size + offset + return false; + + // Sectors in a cylinder + var spc = (int)(imagePlugin.Info.Heads * imagePlugin.Info.SectorsPerTrack); + + // Superblock can start on 0x000, 0x200, 0x600 and 0x800, not aligned, so we assume 16 (128 bytes/sector) sectors as a safe value + int[] locations = + [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + + // Superblock can also skip one cylinder (for boot) + spc + ]; + + foreach(int i in locations.TakeWhile(i => (ulong)i + partition.Start + sb_size_in_sectors < + imagePlugin.Info.Sectors)) + { + ErrorNumber errno = + imagePlugin.ReadSectors((ulong)i + partition.Start, sb_size_in_sectors, out byte[] sb_sector); + + if(errno != ErrorNumber.NoError || sb_sector.Length < 0x400) continue; + + var magic = BitConverter.ToUInt32(sb_sector, 0x3F8); + + if(magic is XENIX_MAGIC or XENIX_CIGAM or SYSV_MAGIC or SYSV_CIGAM) return true; + + magic = BitConverter.ToUInt32(sb_sector, 0x1F8); // System V magic location + + if(magic is SYSV_MAGIC or SYSV_CIGAM) return true; + + magic = BitConverter.ToUInt32(sb_sector, 0x1F0); // XENIX 3 magic location + + if(magic is XENIX_MAGIC or XENIX_CIGAM) return true; + + var coherent_string = new byte[6]; + Array.Copy(sb_sector, 0x1E4, coherent_string, 0, 6); // Coherent UNIX s_fname location + string s_fname = StringHandlers.CToString(coherent_string); + Array.Copy(sb_sector, 0x1EA, coherent_string, 0, 6); // Coherent UNIX s_fpack location + string s_fpack = StringHandlers.CToString(coherent_string); + + if(s_fname == COH_FNAME && s_fpack == COH_FPACK || + s_fname == COH_XXXXX && s_fpack == COH_XXXXX || + s_fname == COH_XXXXS && s_fpack == COH_XXXXN) + return true; + + // Now try to identify 7th edition + var s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); + var s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); + var s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0); + + if(s_fsize is <= 0 or >= 0xFFFFFFFF || s_nfree is <= 0 or >= 0xFFFF || s_ninode is <= 0 or >= 0xFFFF) + continue; + + if((s_fsize & 0xFF) == 0x00 && (s_nfree & 0xFF) == 0x00 && (s_ninode & 0xFF) == 0x00) + { + // Byteswap + s_fsize = ((s_fsize & 0xFF) << 24) + + ((s_fsize & 0xFF00) << 8) + + ((s_fsize & 0xFF0000) >> 8) + + ((s_fsize & 0xFF000000) >> 24); + + s_nfree = (ushort)(s_nfree >> 8); + s_ninode = (ushort)(s_ninode >> 8); + } + + if((s_fsize & 0xFF000000) != 0x00 || (s_nfree & 0xFF00) != 0x00 || (s_ninode & 0xFF00) != 0x00) continue; + + if(s_fsize >= V7_MAXSIZE || s_nfree >= V7_NICFREE || s_ninode >= V7_NICINOD) continue; + + if(s_fsize * 1024 == (partition.End - partition.Start) * imagePlugin.Info.SectorSize || + s_fsize * 512 == (partition.End - partition.Start) * imagePlugin.Info.SectorSize) + return true; + } + + return false; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + var bigEndian = false; // Start in little endian until we know what are we handling here + var start = 0; + var xenix = false; + var sysv = false; + var sys7th = false; + var coherent = false; + var xenix3 = false; + byte[] sb_sector; + byte sb_size_in_sectors; + var offset = 0; + + if(imagePlugin.Info.SectorSize <= + 0x400) // Check if underlying device sector size is smaller than SuperBlock size + sb_size_in_sectors = (byte)(0x400 / imagePlugin.Info.SectorSize); + else + sb_size_in_sectors = 1; // If not a single sector can store it + + // Sectors in a cylinder + var spc = (int)(imagePlugin.Info.Heads * imagePlugin.Info.SectorsPerTrack); + + // Superblock can start on 0x000, 0x200, 0x600 and 0x800, not aligned, so we assume 16 (128 bytes/sector) sectors as a safe value + int[] locations = + [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + + // Superblock can also skip one cylinder (for boot) + spc + ]; + + ErrorNumber errno; + + foreach(int i in locations) + { + errno = imagePlugin.ReadSectors((ulong)i + partition.Start, sb_size_in_sectors, out sb_sector); + + if(errno != ErrorNumber.NoError) continue; + + var magic = BitConverter.ToUInt32(sb_sector, 0x3F8); + + if(magic is XENIX_MAGIC or SYSV_MAGIC) + { + if(magic == SYSV_MAGIC) + { + sysv = true; + offset = 0x200; + } + else + xenix = true; + + start = i; + + break; + } + + if(magic is XENIX_CIGAM or SYSV_CIGAM) + { + bigEndian = true; // Big endian + + if(magic == SYSV_CIGAM) + { + sysv = true; + offset = 0x200; + } + else + xenix = true; + + start = i; + + break; + } + + magic = BitConverter.ToUInt32(sb_sector, 0x1F0); // XENIX 3 magic location + + if(magic == XENIX_MAGIC) + { + xenix3 = true; + start = i; + + break; + } + + if(magic == XENIX_CIGAM) + { + bigEndian = true; // Big endian + xenix3 = true; + start = i; + + break; + } + + magic = BitConverter.ToUInt32(sb_sector, 0x1F8); // XENIX magic location + + if(magic == SYSV_MAGIC) + { + sysv = true; + start = i; + + break; + } + + if(magic == SYSV_CIGAM) + { + bigEndian = true; // Big endian + sysv = true; + start = i; + + break; + } + + var coherent_string = new byte[6]; + Array.Copy(sb_sector, 0x1E4, coherent_string, 0, 6); // Coherent UNIX s_fname location + string s_fname = StringHandlers.CToString(coherent_string, encoding); + Array.Copy(sb_sector, 0x1EA, coherent_string, 0, 6); // Coherent UNIX s_fpack location + string s_fpack = StringHandlers.CToString(coherent_string, encoding); + + if(s_fname == COH_FNAME && s_fpack == COH_FPACK || + s_fname == COH_XXXXX && s_fpack == COH_XXXXX || + s_fname == COH_XXXXS && s_fpack == COH_XXXXN) + { + coherent = true; + start = i; + + break; + } + + // Now try to identify 7th edition + var s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); + var s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); + var s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0); + + if(s_fsize is <= 0 or >= 0xFFFFFFFF || s_nfree is <= 0 or >= 0xFFFF || s_ninode is <= 0 or >= 0xFFFF) + continue; + + if((s_fsize & 0xFF) == 0x00 && (s_nfree & 0xFF) == 0x00 && (s_ninode & 0xFF) == 0x00) + { + // Byteswap + s_fsize = ((s_fsize & 0xFF) << 24) + + ((s_fsize & 0xFF00) << 8) + + ((s_fsize & 0xFF0000) >> 8) + + ((s_fsize & 0xFF000000) >> 24); + + s_nfree = (ushort)(s_nfree >> 8); + s_ninode = (ushort)(s_ninode >> 8); + } + + if((s_fsize & 0xFF000000) != 0x00 || (s_nfree & 0xFF00) != 0x00 || (s_ninode & 0xFF00) != 0x00) continue; + + if(s_fsize >= V7_MAXSIZE || s_nfree >= V7_NICFREE || s_ninode >= V7_NICINOD) continue; + + if(s_fsize * 1024 != (partition.End - partition.Start) * imagePlugin.Info.SectorSize && + s_fsize * 512 != (partition.End - partition.Start) * imagePlugin.Info.SectorSize) + continue; + + sys7th = true; + start = i; + + break; + } + + if(!sys7th && !sysv && !coherent && !xenix && !xenix3) return; + + metadata = new FileSystem(); + + if(xenix || xenix3) + { + var xenix_strings = new byte[6]; + var xnx_sb = new XenixSuperBlock(); + errno = imagePlugin.ReadSectors((ulong)start + partition.Start, sb_size_in_sectors, out sb_sector); + + if(errno != ErrorNumber.NoError) return; + + if(xenix3) + { + xnx_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000); + xnx_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); + xnx_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); + xnx_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0); + xnx_sb.s_flock = sb_sector[0x19A]; + xnx_sb.s_ilock = sb_sector[0x19B]; + xnx_sb.s_fmod = sb_sector[0x19C]; + xnx_sb.s_ronly = sb_sector[0x19D]; + xnx_sb.s_time = BitConverter.ToInt32(sb_sector, 0x19E); + xnx_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1A2); + xnx_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1A6); + xnx_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x1A8); + xnx_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x1AA); + xnx_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x1AC); + xnx_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x1AE); + Array.Copy(sb_sector, 0x1B0, xenix_strings, 0, 6); + xnx_sb.s_fname = StringHandlers.CToString(xenix_strings, encoding); + Array.Copy(sb_sector, 0x1B6, xenix_strings, 0, 6); + xnx_sb.s_fpack = StringHandlers.CToString(xenix_strings, encoding); + xnx_sb.s_clean = sb_sector[0x1BC]; + xnx_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x1F0); + xnx_sb.s_type = BitConverter.ToUInt32(sb_sector, 0x1F4); + } + else + { + xnx_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000); + xnx_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); + xnx_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); + xnx_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x198); + xnx_sb.s_flock = sb_sector[0x262]; + xnx_sb.s_ilock = sb_sector[0x263]; + xnx_sb.s_fmod = sb_sector[0x264]; + xnx_sb.s_ronly = sb_sector[0x265]; + xnx_sb.s_time = BitConverter.ToInt32(sb_sector, 0x266); + xnx_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x26A); + xnx_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x26E); + xnx_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x270); + xnx_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x272); + xnx_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x274); + xnx_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x276); + Array.Copy(sb_sector, 0x278, xenix_strings, 0, 6); + xnx_sb.s_fname = StringHandlers.CToString(xenix_strings, encoding); + Array.Copy(sb_sector, 0x27E, xenix_strings, 0, 6); + xnx_sb.s_fpack = StringHandlers.CToString(xenix_strings, encoding); + xnx_sb.s_clean = sb_sector[0x284]; + xnx_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x3F8); + xnx_sb.s_type = BitConverter.ToUInt32(sb_sector, 0x3FC); + } + + if(bigEndian) + { + xnx_sb.s_isize = Swapping.Swap(xnx_sb.s_isize); + xnx_sb.s_fsize = Swapping.Swap(xnx_sb.s_fsize); + xnx_sb.s_nfree = Swapping.Swap(xnx_sb.s_nfree); + xnx_sb.s_ninode = Swapping.Swap(xnx_sb.s_ninode); + xnx_sb.s_time = Swapping.Swap(xnx_sb.s_time); + xnx_sb.s_tfree = Swapping.Swap(xnx_sb.s_tfree); + xnx_sb.s_tinode = Swapping.Swap(xnx_sb.s_tinode); + xnx_sb.s_cylblks = Swapping.Swap(xnx_sb.s_cylblks); + xnx_sb.s_gapblks = Swapping.Swap(xnx_sb.s_gapblks); + xnx_sb.s_dinfo0 = Swapping.Swap(xnx_sb.s_dinfo0); + xnx_sb.s_dinfo1 = Swapping.Swap(xnx_sb.s_dinfo1); + xnx_sb.s_magic = Swapping.Swap(xnx_sb.s_magic); + xnx_sb.s_type = Swapping.Swap(xnx_sb.s_type); + } + + uint bs = 512; + sb.AppendLine(Localization.XENIX_filesystem); + metadata.Type = FS_TYPE_XENIX; + + switch(xnx_sb.s_type) + { + case 1: + sb.AppendLine(Localization._512_bytes_per_block); + metadata.ClusterSize = 512; + + break; + case 2: + sb.AppendLine(Localization._1024_bytes_per_block); + bs = 1024; + metadata.ClusterSize = 1024; + + break; + case 3: + sb.AppendLine(Localization._2048_bytes_per_block); + bs = 2048; + metadata.ClusterSize = 2048; + + break; + default: + sb.AppendFormat(Localization.Unknown_s_type_value_0, xnx_sb.s_type).AppendLine(); + + break; + } + + if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448) + { + if(bs != 2048) + { + sb.AppendFormat(Localization + .WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block, + bs, + 2048) + .AppendLine(); + } + } + else + { + if(bs != imagePlugin.Info.SectorSize) + { + sb.AppendFormat(Localization + .WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block, + bs, + imagePlugin.Info.SectorSize) + .AppendLine(); + } + } + + sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, xnx_sb.s_fsize, xnx_sb.s_fsize * bs).AppendLine(); + + sb.AppendFormat(Localization._0_free_zones_on_volume_1_bytes, xnx_sb.s_tfree, xnx_sb.s_tfree * bs) + .AppendLine(); + + sb.AppendFormat(Localization._0_free_blocks_on_list_1_bytes, xnx_sb.s_nfree, xnx_sb.s_nfree * bs) + .AppendLine(); + + sb.AppendFormat(Localization._0_blocks_per_cylinder_1_bytes, xnx_sb.s_cylblks, xnx_sb.s_cylblks * bs) + .AppendLine(); + + sb.AppendFormat(Localization._0_blocks_per_gap_1_bytes, xnx_sb.s_gapblks, xnx_sb.s_gapblks * bs) + .AppendLine(); + + sb.AppendFormat(Localization.First_data_zone_0, xnx_sb.s_isize).AppendLine(); + sb.AppendFormat(Localization._0_free_inodes_on_volume, xnx_sb.s_tinode).AppendLine(); + sb.AppendFormat(Localization._0_free_inodes_on_list, xnx_sb.s_ninode).AppendLine(); + + if(xnx_sb.s_flock > 0) sb.AppendLine(Localization.Free_block_list_is_locked); + + if(xnx_sb.s_ilock > 0) sb.AppendLine(Localization.inode_cache_is_locked); + + if(xnx_sb.s_fmod > 0) sb.AppendLine(Localization.Superblock_is_being_modified); + + if(xnx_sb.s_ronly > 0) sb.AppendLine(Localization.Volume_is_mounted_read_only); + + sb.AppendFormat(Localization.Superblock_last_updated_on_0, DateHandlers.UnixToDateTime(xnx_sb.s_time)) + .AppendLine(); + + if(xnx_sb.s_time != 0) metadata.ModificationDate = DateHandlers.UnixToDateTime(xnx_sb.s_time); + + sb.AppendFormat(Localization.Volume_name_0, xnx_sb.s_fname).AppendLine(); + metadata.VolumeName = xnx_sb.s_fname; + sb.AppendFormat(Localization.Pack_name_0, xnx_sb.s_fpack).AppendLine(); + + if(xnx_sb.s_clean == 0x46) + sb.AppendLine(Localization.Volume_is_clean); + else + { + sb.AppendLine(Localization.Volume_is_dirty); + metadata.Dirty = true; + } + } + + if(sysv) + { + errno = imagePlugin.ReadSectors((ulong)start + partition.Start, sb_size_in_sectors, out sb_sector); + + if(errno != ErrorNumber.NoError) return; + + var sysv_strings = new byte[6]; + + var sysv_sb = new SystemVRelease4SuperBlock + { + s_type = BitConverter.ToUInt32(sb_sector, 0x1FC + offset) + }; + + if(bigEndian) sysv_sb.s_type = Swapping.Swap(sysv_sb.s_type); + + uint bs = 512; + + switch(sysv_sb.s_type) + { + case 1: + metadata.ClusterSize = 512; + + break; + case 2: + bs = 1024; + metadata.ClusterSize = 1024; + + break; + case 3: + bs = 2048; + metadata.ClusterSize = 2048; + + break; + default: + sb.AppendFormat(Localization.Unknown_s_type_value_0, sysv_sb.s_type).AppendLine(); + + break; + } + + sysv_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002 + offset); + + if(bigEndian) sysv_sb.s_fsize = Swapping.Swap(sysv_sb.s_fsize); + + bool sysvr4 = sysv_sb.s_fsize * bs <= 0 || sysv_sb.s_fsize * bs != partition.Size; + + if(sysvr4) + { + sysv_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000 + offset); + sysv_sb.s_state = BitConverter.ToUInt32(sb_sector, 0x1F4 + offset); + sysv_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x1F8 + offset); + sysv_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x004 + offset); + sysv_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x008 + offset); + sysv_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D4 + offset); + sysv_sb.s_flock = sb_sector[0x1A0 + offset]; + sysv_sb.s_ilock = sb_sector[0x1A1 + offset]; + sysv_sb.s_fmod = sb_sector[0x1A2 + offset]; + sysv_sb.s_ronly = sb_sector[0x1A3 + offset]; + sysv_sb.s_time = BitConverter.ToUInt32(sb_sector, 0x1A4 + offset); + sysv_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x1A8 + offset); + sysv_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x1AA + offset); + sysv_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x1AC + offset); + sysv_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x1AE + offset); + sysv_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1B0 + offset); + sysv_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1B4 + offset); + Array.Copy(sb_sector, 0x1B6 + offset, sysv_strings, 0, 6); + sysv_sb.s_fname = StringHandlers.CToString(sysv_strings, encoding); + Array.Copy(sb_sector, 0x1BC + offset, sysv_strings, 0, 6); + sysv_sb.s_fpack = StringHandlers.CToString(sysv_strings, encoding); + sb.AppendLine(Localization.System_V_Release_4_filesystem); + metadata.Type = FS_TYPE_SVR4; + } + else + { + sysv_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000 + offset); + sysv_sb.s_state = BitConverter.ToUInt32(sb_sector, 0x1F4 + offset); + sysv_sb.s_magic = BitConverter.ToUInt32(sb_sector, 0x1F8 + offset); + sysv_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002 + offset); + sysv_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006 + offset); + sysv_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0 + offset); + sysv_sb.s_flock = sb_sector[0x19A + offset]; + sysv_sb.s_ilock = sb_sector[0x19B + offset]; + sysv_sb.s_fmod = sb_sector[0x19C + offset]; + sysv_sb.s_ronly = sb_sector[0x19D + offset]; + sysv_sb.s_time = BitConverter.ToUInt32(sb_sector, 0x19E + offset); + sysv_sb.s_cylblks = BitConverter.ToUInt16(sb_sector, 0x1A2 + offset); + sysv_sb.s_gapblks = BitConverter.ToUInt16(sb_sector, 0x1A4 + offset); + sysv_sb.s_dinfo0 = BitConverter.ToUInt16(sb_sector, 0x1A6 + offset); + sysv_sb.s_dinfo1 = BitConverter.ToUInt16(sb_sector, 0x1A8 + offset); + sysv_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1AA + offset); + sysv_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1AE + offset); + Array.Copy(sb_sector, 0x1B0 + offset, sysv_strings, 0, 6); + sysv_sb.s_fname = StringHandlers.CToString(sysv_strings, encoding); + Array.Copy(sb_sector, 0x1B6 + offset, sysv_strings, 0, 6); + sysv_sb.s_fpack = StringHandlers.CToString(sysv_strings, encoding); + sb.AppendLine(Localization.System_V_Release_2_filesystem); + metadata.Type = FS_TYPE_SVR2; + } + + if(bigEndian) + { + sysv_sb.s_isize = Swapping.Swap(sysv_sb.s_isize); + sysv_sb.s_state = Swapping.Swap(sysv_sb.s_state); + sysv_sb.s_magic = Swapping.Swap(sysv_sb.s_magic); + sysv_sb.s_fsize = Swapping.Swap(sysv_sb.s_fsize); + sysv_sb.s_nfree = Swapping.Swap(sysv_sb.s_nfree); + sysv_sb.s_ninode = Swapping.Swap(sysv_sb.s_ninode); + sysv_sb.s_time = Swapping.Swap(sysv_sb.s_time); + sysv_sb.s_cylblks = Swapping.Swap(sysv_sb.s_cylblks); + sysv_sb.s_gapblks = Swapping.Swap(sysv_sb.s_gapblks); + sysv_sb.s_dinfo0 = Swapping.Swap(sysv_sb.s_dinfo0); + sysv_sb.s_dinfo1 = Swapping.Swap(sysv_sb.s_dinfo1); + sysv_sb.s_tfree = Swapping.Swap(sysv_sb.s_tfree); + sysv_sb.s_tinode = Swapping.Swap(sysv_sb.s_tinode); + } + + sb.AppendFormat(Localization._0_bytes_per_block, bs).AppendLine(); + + metadata.Clusters = sysv_sb.s_fsize; + + sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, sysv_sb.s_fsize, sysv_sb.s_fsize * bs) + .AppendLine(); + + sb.AppendFormat(Localization._0_free_zones_on_volume_1_bytes, sysv_sb.s_tfree, sysv_sb.s_tfree * bs) + .AppendLine(); + + sb.AppendFormat(Localization._0_free_blocks_on_list_1_bytes, sysv_sb.s_nfree, sysv_sb.s_nfree * bs) + .AppendLine(); + + sb.AppendFormat(Localization._0_blocks_per_cylinder_1_bytes, sysv_sb.s_cylblks, sysv_sb.s_cylblks * bs) + .AppendLine(); + + sb.AppendFormat(Localization._0_blocks_per_gap_1_bytes, sysv_sb.s_gapblks, sysv_sb.s_gapblks * bs) + .AppendLine(); + + sb.AppendFormat(Localization.First_data_zone_0, sysv_sb.s_isize).AppendLine(); + sb.AppendFormat(Localization._0_free_inodes_on_volume, sysv_sb.s_tinode).AppendLine(); + sb.AppendFormat(Localization._0_free_inodes_on_list, sysv_sb.s_ninode).AppendLine(); + + if(sysv_sb.s_flock > 0) sb.AppendLine(Localization.Free_block_list_is_locked); + + if(sysv_sb.s_ilock > 0) sb.AppendLine(Localization.inode_cache_is_locked); + + if(sysv_sb.s_fmod > 0) sb.AppendLine(Localization.Superblock_is_being_modified); + + if(sysv_sb.s_ronly > 0) sb.AppendLine(Localization.Volume_is_mounted_read_only); + + sb.AppendFormat(Localization.Superblock_last_updated_on_0, + DateHandlers.UnixUnsignedToDateTime(sysv_sb.s_time)) + .AppendLine(); + + if(sysv_sb.s_time != 0) metadata.ModificationDate = DateHandlers.UnixUnsignedToDateTime(sysv_sb.s_time); + + sb.AppendFormat(Localization.Volume_name_0, sysv_sb.s_fname).AppendLine(); + metadata.VolumeName = sysv_sb.s_fname; + sb.AppendFormat(Localization.Pack_name_0, sysv_sb.s_fpack).AppendLine(); + + if(sysv_sb.s_state == 0x7C269D38 - sysv_sb.s_time) + sb.AppendLine(Localization.Volume_is_clean); + else + { + sb.AppendLine(Localization.Volume_is_dirty); + metadata.Dirty = true; + } + } + + if(coherent) + { + errno = imagePlugin.ReadSectors((ulong)start + partition.Start, sb_size_in_sectors, out sb_sector); + + if(errno != ErrorNumber.NoError) return; + + var coh_sb = new CoherentSuperBlock(); + var coh_strings = new byte[6]; + + coh_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000); + coh_sb.s_fsize = Swapping.PDPFromLittleEndian(BitConverter.ToUInt32(sb_sector, 0x002)); + coh_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); + coh_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x108); + coh_sb.s_flock = sb_sector[0x1D2]; + coh_sb.s_ilock = sb_sector[0x1D3]; + coh_sb.s_fmod = sb_sector[0x1D4]; + coh_sb.s_ronly = sb_sector[0x1D5]; + coh_sb.s_time = Swapping.PDPFromLittleEndian(BitConverter.ToUInt32(sb_sector, 0x1D6)); + coh_sb.s_tfree = Swapping.PDPFromLittleEndian(BitConverter.ToUInt32(sb_sector, 0x1DA)); + coh_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1DE); + coh_sb.s_int_m = BitConverter.ToUInt16(sb_sector, 0x1E0); + coh_sb.s_int_n = BitConverter.ToUInt16(sb_sector, 0x1E2); + Array.Copy(sb_sector, 0x1E4, coh_strings, 0, 6); + coh_sb.s_fname = StringHandlers.CToString(coh_strings, encoding); + Array.Copy(sb_sector, 0x1EA, coh_strings, 0, 6); + coh_sb.s_fpack = StringHandlers.CToString(coh_strings, encoding); + + metadata.Type = FS_TYPE_COHERENT; + metadata.ClusterSize = 512; + metadata.Clusters = coh_sb.s_fsize; + + sb.AppendLine(Localization.Coherent_UNIX_filesystem); + + if(imagePlugin.Info.SectorSize != 512) + { + sb.AppendFormat(Localization + .WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block, + 512, + 2048) + .AppendLine(); + } + + sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, coh_sb.s_fsize, coh_sb.s_fsize * 512).AppendLine(); + + sb.AppendFormat(Localization._0_free_zones_on_volume_1_bytes, coh_sb.s_tfree, coh_sb.s_tfree * 512) + .AppendLine(); + + sb.AppendFormat(Localization._0_free_blocks_on_list_1_bytes, coh_sb.s_nfree, coh_sb.s_nfree * 512) + .AppendLine(); + + sb.AppendFormat(Localization.First_data_zone_0, coh_sb.s_isize).AppendLine(); + sb.AppendFormat(Localization._0_free_inodes_on_volume, coh_sb.s_tinode).AppendLine(); + sb.AppendFormat(Localization._0_free_inodes_on_list, coh_sb.s_ninode).AppendLine(); + + if(coh_sb.s_flock > 0) sb.AppendLine(Localization.Free_block_list_is_locked); + + if(coh_sb.s_ilock > 0) sb.AppendLine(Localization.inode_cache_is_locked); + + if(coh_sb.s_fmod > 0) sb.AppendLine(Localization.Superblock_is_being_modified); + + if(coh_sb.s_ronly > 0) sb.AppendLine(Localization.Volume_is_mounted_read_only); + + sb.AppendFormat(Localization.Superblock_last_updated_on_0, + DateHandlers.UnixUnsignedToDateTime(coh_sb.s_time)) + .AppendLine(); + + if(coh_sb.s_time != 0) metadata.ModificationDate = DateHandlers.UnixUnsignedToDateTime(coh_sb.s_time); + + sb.AppendFormat(Localization.Volume_name_0, coh_sb.s_fname).AppendLine(); + metadata.VolumeName = coh_sb.s_fname; + sb.AppendFormat(Localization.Pack_name_0, coh_sb.s_fpack).AppendLine(); + } + + if(sys7th) + { + errno = imagePlugin.ReadSectors((ulong)start + partition.Start, sb_size_in_sectors, out sb_sector); + + if(errno != ErrorNumber.NoError) return; + + var v7_sb = new UNIX7thEditionSuperBlock(); + var sys7_strings = new byte[6]; + + v7_sb.s_isize = BitConverter.ToUInt16(sb_sector, 0x000); + v7_sb.s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); + v7_sb.s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); + v7_sb.s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0); + v7_sb.s_flock = sb_sector[0x19A]; + v7_sb.s_ilock = sb_sector[0x19B]; + v7_sb.s_fmod = sb_sector[0x19C]; + v7_sb.s_ronly = sb_sector[0x19D]; + v7_sb.s_time = BitConverter.ToUInt32(sb_sector, 0x19E); + v7_sb.s_tfree = BitConverter.ToUInt32(sb_sector, 0x1A2); + v7_sb.s_tinode = BitConverter.ToUInt16(sb_sector, 0x1A6); + v7_sb.s_int_m = BitConverter.ToUInt16(sb_sector, 0x1A8); + v7_sb.s_int_n = BitConverter.ToUInt16(sb_sector, 0x1AA); + Array.Copy(sb_sector, 0x1AC, sys7_strings, 0, 6); + v7_sb.s_fname = StringHandlers.CToString(sys7_strings, encoding); + Array.Copy(sb_sector, 0x1B2, sys7_strings, 0, 6); + v7_sb.s_fpack = StringHandlers.CToString(sys7_strings, encoding); + + metadata.Type = FS_TYPE_UNIX7; + metadata.ClusterSize = 512; + metadata.Clusters = v7_sb.s_fsize; + sb.AppendLine(Localization.UNIX_7th_Edition_filesystem); + + if(imagePlugin.Info.SectorSize != 512) + { + sb.AppendFormat(Localization + .WARNING_Filesystem_indicates_0_bytes_block_while_device_indicates_1_bytes_block, + 512, + 2048) + .AppendLine(); + } + + sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, v7_sb.s_fsize, v7_sb.s_fsize * 512).AppendLine(); + + sb.AppendFormat(Localization._0_free_zones_on_volume_1_bytes, v7_sb.s_tfree, v7_sb.s_tfree * 512) + .AppendLine(); + + sb.AppendFormat(Localization._0_free_blocks_on_list_1_bytes, v7_sb.s_nfree, v7_sb.s_nfree * 512) + .AppendLine(); + + sb.AppendFormat(Localization.First_data_zone_0, v7_sb.s_isize).AppendLine(); + sb.AppendFormat(Localization._0_free_inodes_on_volume, v7_sb.s_tinode).AppendLine(); + sb.AppendFormat(Localization._0_free_inodes_on_list, v7_sb.s_ninode).AppendLine(); + + if(v7_sb.s_flock > 0) sb.AppendLine(Localization.Free_block_list_is_locked); + + if(v7_sb.s_ilock > 0) sb.AppendLine(Localization.inode_cache_is_locked); + + if(v7_sb.s_fmod > 0) sb.AppendLine(Localization.Superblock_is_being_modified); + + if(v7_sb.s_ronly > 0) sb.AppendLine(Localization.Volume_is_mounted_read_only); + + sb.AppendFormat(Localization.Superblock_last_updated_on_0, + DateHandlers.UnixUnsignedToDateTime(v7_sb.s_time)) + .AppendLine(); + + if(v7_sb.s_time != 0) metadata.ModificationDate = DateHandlers.UnixUnsignedToDateTime(v7_sb.s_time); + + sb.AppendFormat(Localization.Volume_name_0, v7_sb.s_fname).AppendLine(); + metadata.VolumeName = v7_sb.s_fname; + sb.AppendFormat(Localization.Pack_name_0, v7_sb.s_fpack).AppendLine(); + } + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/SysV/Structs.cs b/Aaru.Filesystems/SysV/Structs.cs new file mode 100644 index 000000000..3b25294fe --- /dev/null +++ b/Aaru.Filesystems/SysV/Structs.cs @@ -0,0 +1,329 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : UNIX System V filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable NotAccessedField.Local + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the UNIX System V filesystem +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class SysVfs +{ +#region Nested type: CoherentSuperBlock + +#pragma warning disable CS0649 + struct CoherentSuperBlock + { + /// 0x000, index of first data zone + public ushort s_isize; + /// 0x002, total number of zones of this volume + public uint s_fsize; + + // the start of the free block list: + /// 0x006, blocks in s_free, <=100 + public ushort s_nfree; + /// 0x008, 64 entries, first free block list chunk + public uint[] s_free; + + // the cache of free inodes: + /// 0x108, number of inodes in s_inode, <= 100 + public ushort s_ninode; + /// 0x10A, 100 entries, some free inodes + public ushort[] s_inode; + /// 0x1D2, free block list manipulation lock + public byte s_flock; + /// 0x1D3, inode cache manipulation lock + public byte s_ilock; + /// 0x1D4, superblock modification flag + public byte s_fmod; + /// 0x1D5, read-only mounted flag + public byte s_ronly; + /// 0x1D6, time of last superblock update + public uint s_time; + /// 0x1DE, total number of free zones + public uint s_tfree; + /// 0x1E2, total number of free inodes + public ushort s_tinode; + /// 0x1E4, interleave factor + public ushort s_int_m; + /// 0x1E6, interleave factor + public ushort s_int_n; + /// 0x1E8, 6 bytes, volume name + public string s_fname; + /// 0x1EE, 6 bytes, pack name + public string s_fpack; + /// 0x1F4, zero-filled + public uint s_unique; + } +#pragma warning restore CS0649 + +#endregion + +#region Nested type: SystemVRelease2SuperBlock + +#pragma warning disable CS0649 + struct SystemVRelease2SuperBlock + { + /// 0x000, index of first data zone + public ushort s_isize; + /// 0x002, total number of zones of this volume + public uint s_fsize; + + // the start of the free block list: + /// 0x006, blocks in s_free, <=100 + public ushort s_nfree; + /// 0x008, 50 entries, first free block list chunk + public uint[] s_free; + + // the cache of free inodes: + /// 0x0D0, number of inodes in s_inode, <= 100 + public ushort s_ninode; + /// 0x0D2, 100 entries, some free inodes + public ushort[] s_inode; + /// 0x19A, free block list manipulation lock + public byte s_flock; + /// 0x19B, inode cache manipulation lock + public byte s_ilock; + /// 0x19C, superblock modification flag + public byte s_fmod; + /// 0x19D, read-only mounted flag + public byte s_ronly; + /// 0x19E, time of last superblock update + public uint s_time; + /// 0x1A2, blocks per cylinder + public ushort s_cylblks; + /// 0x1A4, blocks per gap + public ushort s_gapblks; + /// 0x1A6, device information ?? + public ushort s_dinfo0; + /// 0x1A8, device information ?? + public ushort s_dinfo1; + /// 0x1AA, total number of free zones + public uint s_tfree; + /// 0x1AE, total number of free inodes + public ushort s_tinode; + /// 0x1B0, 6 bytes, volume name + public string s_fname; + /// 0x1B6, 6 bytes, pack name + public string s_fpack; + /// 0x1BC, 56 bytes + public byte[] s_fill; + /// 0x1F4, if s_state == (0x7C269D38 - s_time) then filesystem is clean + public uint s_state; + /// 0x1F8, magic + public uint s_magic; + /// 0x1FC, filesystem type (1 = 512 bytes/blk, 2 = 1024 bytes/blk) + public uint s_type; + } +#pragma warning restore CS0649 + +#endregion + +#region Nested type: SystemVRelease4SuperBlock + +#pragma warning disable CS0649 + struct SystemVRelease4SuperBlock + { + /// 0x000, index of first data zone + public ushort s_isize; + /// 0x002, padding + public ushort s_pad0; + /// 0x004, total number of zones of this volume + public uint s_fsize; + + // the start of the free block list: + /// 0x008, blocks in s_free, <=100 + public ushort s_nfree; + /// 0x00A, padding + public ushort s_pad1; + /// 0x00C, 50 entries, first free block list chunk + public uint[] s_free; + + // the cache of free inodes: + /// 0x0D4, number of inodes in s_inode, <= 100 + public ushort s_ninode; + /// 0x0D6, padding + public ushort s_pad2; + /// 0x0D8, 100 entries, some free inodes + public ushort[] s_inode; + /// 0x1A0, free block list manipulation lock + public byte s_flock; + /// 0x1A1, inode cache manipulation lock + public byte s_ilock; + /// 0x1A2, superblock modification flag + public byte s_fmod; + /// 0x1A3, read-only mounted flag + public byte s_ronly; + /// 0x1A4, time of last superblock update + public uint s_time; + /// 0x1A8, blocks per cylinder + public ushort s_cylblks; + /// 0x1AA, blocks per gap + public ushort s_gapblks; + /// 0x1AC, device information ?? + public ushort s_dinfo0; + /// 0x1AE, device information ?? + public ushort s_dinfo1; + /// 0x1B0, total number of free zones + public uint s_tfree; + /// 0x1B4, total number of free inodes + public ushort s_tinode; + /// 0x1B6, padding + public ushort s_pad3; + /// 0x1B8, 6 bytes, volume name + public string s_fname; + /// 0x1BE, 6 bytes, pack name + public string s_fpack; + /// 0x1C4, 48 bytes + public byte[] s_fill; + /// 0x1F4, if s_state == (0x7C269D38 - s_time) then filesystem is clean + public uint s_state; + /// 0x1F8, magic + public uint s_magic; + /// 0x1FC, filesystem type (1 = 512 bytes/blk, 2 = 1024 bytes/blk) + public uint s_type; + } +#pragma warning restore CS0649 + +#endregion + +#region Nested type: UNIX7thEditionSuperBlock + +#pragma warning disable CS0649 + struct UNIX7thEditionSuperBlock + { + /// 0x000, index of first data zone + public ushort s_isize; + /// 0x002, total number of zones of this volume + public uint s_fsize; + + // the start of the free block list: + /// 0x006, blocks in s_free, <=100 + public ushort s_nfree; + /// 0x008, 50 entries, first free block list chunk + public uint[] s_free; + + // the cache of free inodes: + /// 0x0D0, number of inodes in s_inode, <= 100 + public ushort s_ninode; + /// 0x0D2, 100 entries, some free inodes + public ushort[] s_inode; + /// 0x19A, free block list manipulation lock + public byte s_flock; + /// 0x19B, inode cache manipulation lock + public byte s_ilock; + /// 0x19C, superblock modification flag + public byte s_fmod; + /// 0x19D, read-only mounted flag + public byte s_ronly; + /// 0x19E, time of last superblock update + public uint s_time; + /// 0x1A2, total number of free zones + public uint s_tfree; + /// 0x1A6, total number of free inodes + public ushort s_tinode; + /// 0x1A8, interleave factor + public ushort s_int_m; + /// 0x1AA, interleave factor + public ushort s_int_n; + /// 0x1AC, 6 bytes, volume name + public string s_fname; + /// 0x1B2, 6 bytes, pack name + public string s_fpack; + } +#pragma warning restore CS0649 + +#endregion + +#region Nested type: XenixSuperBlock + + // Old XENIX use different offsets +#pragma warning disable CS0649 + struct XenixSuperBlock + { + /// 0x000, index of first data zone + public ushort s_isize; + /// 0x002, total number of zones of this volume + public uint s_fsize; + + // the start of the free block list: + /// 0x006, blocks in s_free, <=100 + public ushort s_nfree; + /// 0x008, 100 entries, 50 entries for Xenix 3, first free block list chunk + public uint[] s_free; + + // the cache of free inodes: + /// 0x198 (0xD0), number of inodes in s_inode, <= 100 + public ushort s_ninode; + /// 0x19A (0xD2), 100 entries, some free inodes + public ushort[] s_inode; + /// 0x262 (0x19A), free block list manipulation lock + public byte s_flock; + /// 0x263 (0x19B), inode cache manipulation lock + public byte s_ilock; + /// 0x264 (0x19C), superblock modification flag + public byte s_fmod; + /// 0x265 (0x19D), read-only mounted flag + public byte s_ronly; + /// 0x266 (0x19E), time of last superblock update + public int s_time; + /// 0x26A (0x1A2), total number of free zones + public uint s_tfree; + /// 0x26E (0x1A6), total number of free inodes + public ushort s_tinode; + /// 0x270 (0x1A8), blocks per cylinder + public ushort s_cylblks; + /// 0x272 (0x1AA), blocks per gap + public ushort s_gapblks; + /// 0x274 (0x1AC), device information ?? + public ushort s_dinfo0; + /// 0x276 (0x1AE), device information ?? + public ushort s_dinfo1; + /// 0x278 (0x1B0), 6 bytes, volume name + public string s_fname; + /// 0x27E (0x1B6), 6 bytes, pack name + public string s_fpack; + /// 0x284 (0x1BC), 0x46 if volume is clean + public byte s_clean; + /// 0x285 (0x1BD), 371 bytes, 51 bytes for Xenix 3 + public byte[] s_fill; + /// 0x3F8 (0x1F0), magic + public uint s_magic; + /// 0x3FC (0x1F4), filesystem type (1 = 512 bytes/blk, 2 = 1024 bytes/blk, 3 = 2048 bytes/blk) + public uint s_type; + } +#pragma warning restore CS0649 + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/SysV/SysV.cs b/Aaru.Filesystems/SysV/SysV.cs new file mode 100644 index 000000000..5e1c5d445 --- /dev/null +++ b/Aaru.Filesystems/SysV/SysV.cs @@ -0,0 +1,57 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : SysV.cs +// Author(s) : Natalia Portillo +// +// Component : UNIX System V filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// ReSharper disable NotAccessedField.Local + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the UNIX System V filesystem +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class SysVfs : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.SysVfs_Name; + + /// + public Guid Id => new("9B8D016A-8561-400E-A12A-A198283C211D"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/UCSDPascal/Consts.cs b/Aaru.Filesystems/UCSDPascal/Consts.cs index a0e5aaac1..0815cc339 100644 --- a/Aaru.Filesystems/UCSDPascal/Consts.cs +++ b/Aaru.Filesystems/UCSDPascal/Consts.cs @@ -27,17 +27,21 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.UCSDPascal; - using System.Diagnostics.CodeAnalysis; +namespace Aaru.Filesystems; + // Information from Call-A.P.P.L.E. Pascal Disk Directory Structure [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed partial class PascalPlugin { + const string FS_TYPE = "ucsd"; + +#region Nested type: PascalFileKind + enum PascalFileKind : short { /// Disk volume entry @@ -59,4 +63,6 @@ public sealed partial class PascalPlugin /// Security, not used Secure } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/UCSDPascal/Dir.cs b/Aaru.Filesystems/UCSDPascal/Dir.cs index 7db730362..16d24879f 100644 --- a/Aaru.Filesystems/UCSDPascal/Dir.cs +++ b/Aaru.Filesystems/UCSDPascal/Dir.cs @@ -27,33 +27,33 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.UCSDPascal; - using System; -using System.Collections.Generic; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; +namespace Aaru.Filesystems; + // Information from Call-A.P.P.L.E. Pascal Disk Directory Structure public sealed partial class PascalPlugin { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber ReadDir(string path, out List contents) + public ErrorNumber OpenDir(string path, out IDirNode node) { - contents = null; + node = null; - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; - if(!string.IsNullOrEmpty(path) && - string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) + if(!string.IsNullOrEmpty(path) && string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0) return ErrorNumber.NotSupported; - contents = _fileEntries.Select(ent => StringHandlers.PascalToString(ent.Filename, Encoding)).ToList(); + var contents = _fileEntries.Select(ent => StringHandlers.PascalToString(ent.Filename, _encoding)).ToList(); if(_debug) { @@ -63,6 +63,44 @@ public sealed partial class PascalPlugin contents.Sort(); + node = new PascalDirNode + { + Path = path, + Contents = contents.ToArray(), + Position = 0 + }; + return ErrorNumber.NoError; } + + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) + { + filename = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not PascalDirNode mynode) return ErrorNumber.InvalidArgument; + + if(mynode.Position < 0) return ErrorNumber.InvalidArgument; + + if(mynode.Position >= mynode.Contents.Length) return ErrorNumber.NoError; + + filename = mynode.Contents[mynode.Position++]; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not PascalDirNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Position = -1; + mynode.Contents = null; + + return ErrorNumber.NoError; + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/UCSDPascal/File.cs b/Aaru.Filesystems/UCSDPascal/File.cs index c16d93d53..87f1962e5 100644 --- a/Aaru.Filesystems/UCSDPascal/File.cs +++ b/Aaru.Filesystems/UCSDPascal/File.cs @@ -7,10 +7,6 @@ // // Component : U.C.S.D. Pascal filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Methods to handle files. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,48 +23,41 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.UCSDPascal; - using System; using System.Linq; using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Helpers; +namespace Aaru.Filesystems; + // Information from Call-A.P.P.L.E. Pascal Disk Directory Structure public sealed partial class PascalPlugin { - /// - public ErrorNumber MapBlock(string path, long fileBlock, out long deviceBlock) - { - deviceBlock = 0; - - return !_mounted ? ErrorNumber.AccessDenied : ErrorNumber.NotImplemented; - } +#region IReadOnlyFilesystem Members /// public ErrorNumber GetAttributes(string path, out FileAttributes attributes) { attributes = new FileAttributes(); - if(!_mounted) - return ErrorNumber.AccessDenied; + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; ErrorNumber error = GetFileEntry(path, out _); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; attributes = FileAttributes.File; @@ -76,36 +65,37 @@ public sealed partial class PascalPlugin } /// - public ErrorNumber Read(string path, long offset, long size, ref byte[] buf) + public ErrorNumber OpenFile(string path, out IFileNode node) { - if(!_mounted) - return ErrorNumber.AccessDenied; + node = null; + + if(!_mounted) return ErrorNumber.AccessDenied; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; byte[] file; - if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || - string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0)) + if(_debug && + (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || + string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0)) file = string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ? _catalogBlocks : _bootBlocks; else { ErrorNumber error = GetFileEntry(path, out PascalFileEntry entry); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; error = _device.ReadSectors((ulong)entry.FirstBlock * _multiplier, - (uint)(entry.LastBlock - entry.FirstBlock) * _multiplier, out byte[] tmp); + (uint)(entry.LastBlock - entry.FirstBlock) * _multiplier, + out byte[] tmp); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; file = new byte[(entry.LastBlock - entry.FirstBlock - 1) * _device.Info.SectorSize * _multiplier + entry.LastBytes]; @@ -113,15 +103,46 @@ public sealed partial class PascalPlugin Array.Copy(tmp, 0, file, 0, file.Length); } - if(offset >= file.Length) - return ErrorNumber.EINVAL; + node = new PascalFileNode + { + Path = path, + Length = file.Length, + Offset = 0, + Cache = file + }; - if(size + offset >= file.Length) - size = file.Length - offset; + return ErrorNumber.NoError; + } - buf = new byte[size]; + /// + public ErrorNumber CloseFile(IFileNode node) + { + if(!_mounted) return ErrorNumber.AccessDenied; - Array.Copy(file, offset, buf, 0, size); + if(node is not PascalFileNode mynode) return ErrorNumber.InvalidArgument; + + mynode.Cache = null; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) + { + read = 0; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(buffer is null || buffer.Length < length) return ErrorNumber.InvalidArgument; + + if(node is not PascalFileNode mynode) return ErrorNumber.InvalidArgument; + + read = length; + + if(length + mynode.Offset >= mynode.Length) read = mynode.Length - mynode.Offset; + + Array.Copy(mynode.Cache, mynode.Offset, buffer, 0, read); + mynode.Offset += read; return ErrorNumber.NoError; } @@ -132,15 +153,16 @@ public sealed partial class PascalPlugin stat = null; string[] pathElements = path.Split(new[] - { - '/' - }, StringSplitOptions.RemoveEmptyEntries); + { + '/' + }, + StringSplitOptions.RemoveEmptyEntries); - if(pathElements.Length != 1) - return ErrorNumber.NotSupported; + if(pathElements.Length != 1) return ErrorNumber.NotSupported; if(_debug) - if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || + { + if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 || string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0) { stat = new FileEntryInfo @@ -164,11 +186,11 @@ public sealed partial class PascalPlugin return ErrorNumber.NoError; } + } ErrorNumber error = GetFileEntry(path, out PascalFileEntry entry); - if(error != ErrorNumber.NoError) - return error; + if(error != ErrorNumber.NoError) return error; stat = new FileEntryInfo { @@ -183,16 +205,19 @@ public sealed partial class PascalPlugin return ErrorNumber.NoError; } +#endregion + ErrorNumber GetFileEntry(string path, out PascalFileEntry entry) { entry = new PascalFileEntry(); - foreach(PascalFileEntry ent in _fileEntries.Where(ent => - string.Compare(path, - StringHandlers.PascalToString(ent.Filename, - Encoding), - StringComparison. - InvariantCultureIgnoreCase) == 0)) + foreach(PascalFileEntry ent in _fileEntries.Where(ent => string.Compare(path, + StringHandlers + .PascalToString(ent.Filename, + _encoding), + StringComparison + .InvariantCultureIgnoreCase) == + 0)) { entry = ent; diff --git a/Aaru.Filesystems/UCSDPascal/Info.cs b/Aaru.Filesystems/UCSDPascal/Info.cs index 1a005aff0..b7eb3351d 100644 --- a/Aaru.Filesystems/UCSDPascal/Info.cs +++ b/Aaru.Filesystems/UCSDPascal/Info.cs @@ -27,30 +27,31 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.UCSDPascal; - using System; using System.Text; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Helpers; using Claunia.Encoding; -using Schemas; using Encoding = System.Text.Encoding; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; // Information from Call-A.P.P.L.E. Pascal Disk Directory Structure public sealed partial class PascalPlugin { +#region IReadOnlyFilesystem Members + /// public bool Identify(IMediaImage imagePlugin, Partition partition) { - if(partition.Length < 3) - return false; + if(partition.Length < 3) return false; _multiplier = (uint)(imagePlugin.Info.SectorSize == 256 ? 2 : 1); @@ -58,8 +59,7 @@ public sealed partial class PascalPlugin ErrorNumber errno = imagePlugin.ReadSectors(_multiplier * 2 + partition.Start, _multiplier, out byte[] volBlock); - if(errno != ErrorNumber.NoError) - return false; + if(errno != ErrorNumber.NoError) return false; // On Apple II, it's little endian // TODO: Fix @@ -81,20 +81,19 @@ public sealed partial class PascalPlugin Array.Copy(volBlock, 0x06, volEntry.VolumeName, 0, 8); - AaruConsole.DebugWriteLine("UCSD Pascal Plugin", "volEntry.firstBlock = {0}", volEntry.FirstBlock); - AaruConsole.DebugWriteLine("UCSD Pascal Plugin", "volEntry.lastBlock = {0}", volEntry.LastBlock); - AaruConsole.DebugWriteLine("UCSD Pascal Plugin", "volEntry.entryType = {0}", volEntry.EntryType); + AaruConsole.DebugWriteLine(MODULE_NAME, "volEntry.firstBlock = {0}", volEntry.FirstBlock); + AaruConsole.DebugWriteLine(MODULE_NAME, "volEntry.lastBlock = {0}", volEntry.LastBlock); + AaruConsole.DebugWriteLine(MODULE_NAME, "volEntry.entryType = {0}", volEntry.EntryType); - // AaruConsole.DebugWriteLine("UCSD Pascal Plugin", "volEntry.volumeName = {0}", volEntry.VolumeName); - AaruConsole.DebugWriteLine("UCSD Pascal Plugin", "volEntry.blocks = {0}", volEntry.Blocks); - AaruConsole.DebugWriteLine("UCSD Pascal Plugin", "volEntry.files = {0}", volEntry.Files); - AaruConsole.DebugWriteLine("UCSD Pascal Plugin", "volEntry.dummy = {0}", volEntry.Dummy); - AaruConsole.DebugWriteLine("UCSD Pascal Plugin", "volEntry.lastBoot = {0}", volEntry.LastBoot); - AaruConsole.DebugWriteLine("UCSD Pascal Plugin", "volEntry.tail = {0}", volEntry.Tail); + // AaruConsole.DebugWriteLine(MODULE_NAME, "volEntry.volumeName = {0}", volEntry.VolumeName); + AaruConsole.DebugWriteLine(MODULE_NAME, "volEntry.blocks = {0}", volEntry.Blocks); + AaruConsole.DebugWriteLine(MODULE_NAME, "volEntry.files = {0}", volEntry.Files); + AaruConsole.DebugWriteLine(MODULE_NAME, "volEntry.dummy = {0}", volEntry.Dummy); + AaruConsole.DebugWriteLine(MODULE_NAME, "volEntry.lastBoot = {0}", volEntry.LastBoot); + AaruConsole.DebugWriteLine(MODULE_NAME, "volEntry.tail = {0}", volEntry.Tail); // First block is always 0 (even is it's sector 2) - if(volEntry.FirstBlock != 0) - return false; + if(volEntry.FirstBlock != 0) return false; // Last volume record block must be after first block, and before end of device if(volEntry.LastBlock <= volEntry.FirstBlock || @@ -102,40 +101,35 @@ public sealed partial class PascalPlugin return false; // Volume record entry type must be volume or secure - if(volEntry.EntryType != PascalFileKind.Volume && - volEntry.EntryType != PascalFileKind.Secure) - return false; + if(volEntry.EntryType != PascalFileKind.Volume && volEntry.EntryType != PascalFileKind.Secure) return false; // Volume name is max 7 characters - if(volEntry.VolumeName[0] > 7) - return false; + if(volEntry.VolumeName[0] > 7) return false; // Volume blocks is equal to volume sectors - if(volEntry.Blocks < 0 || - (ulong)volEntry.Blocks != imagePlugin.Info.Sectors / _multiplier) - return false; + if(volEntry.Blocks < 0 || (ulong)volEntry.Blocks != imagePlugin.Info.Sectors / _multiplier) return false; // There can be not less than zero files return volEntry.Files >= 0; } /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) { - Encoding = encoding ?? new Apple2(); + encoding ??= new Apple2(); var sbInformation = new StringBuilder(); + metadata = new FileSystem(); information = ""; _multiplier = (uint)(imagePlugin.Info.SectorSize == 256 ? 2 : 1); - if(imagePlugin.Info.Sectors < 3) - return; + if(imagePlugin.Info.Sectors < 3) return; // Blocks 0 and 1 are boot code ErrorNumber errno = imagePlugin.ReadSectors(_multiplier * 2 + partition.Start, _multiplier, out byte[] volBlock); - if(errno != ErrorNumber.NoError) - return; + if(errno != ErrorNumber.NoError) return; // On Apple //, it's little endian // TODO: Fix @@ -158,8 +152,7 @@ public sealed partial class PascalPlugin Array.Copy(volBlock, 0x06, volEntry.VolumeName, 0, 8); // First block is always 0 (even is it's sector 2) - if(volEntry.FirstBlock != 0) - return; + if(volEntry.FirstBlock != 0) return; // Last volume record block must be after first block, and before end of device if(volEntry.LastBlock <= volEntry.FirstBlock || @@ -167,48 +160,47 @@ public sealed partial class PascalPlugin return; // Volume record entry type must be volume or secure - if(volEntry.EntryType != PascalFileKind.Volume && - volEntry.EntryType != PascalFileKind.Secure) - return; + if(volEntry.EntryType != PascalFileKind.Volume && volEntry.EntryType != PascalFileKind.Secure) return; // Volume name is max 7 characters - if(volEntry.VolumeName[0] > 7) - return; + if(volEntry.VolumeName[0] > 7) return; // Volume blocks is equal to volume sectors - if(volEntry.Blocks < 0 || - (ulong)volEntry.Blocks != imagePlugin.Info.Sectors / _multiplier) - return; + if(volEntry.Blocks < 0 || (ulong)volEntry.Blocks != imagePlugin.Info.Sectors / _multiplier) return; // There can be not less than zero files - if(volEntry.Files < 0) - return; + if(volEntry.Files < 0) return; - sbInformation.AppendFormat("Volume record spans from block {0} to block {1}", volEntry.FirstBlock, - volEntry.LastBlock).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_record_spans_from_block_0_to_block_1, + volEntry.FirstBlock, + volEntry.LastBlock) + .AppendLine(); - sbInformation.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(volEntry.VolumeName, Encoding)). - AppendLine(); + sbInformation + .AppendFormat(Localization.Volume_name_0, StringHandlers.PascalToString(volEntry.VolumeName, encoding)) + .AppendLine(); - sbInformation.AppendFormat("Volume has {0} blocks", volEntry.Blocks).AppendLine(); - sbInformation.AppendFormat("Volume has {0} files", volEntry.Files).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_blocks, volEntry.Blocks).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_files, volEntry.Files).AppendLine(); - sbInformation.AppendFormat("Volume last booted at {0}", DateHandlers.UcsdPascalToDateTime(volEntry.LastBoot)). - AppendLine(); + sbInformation + .AppendFormat(Localization.Volume_last_booted_on_0, DateHandlers.UcsdPascalToDateTime(volEntry.LastBoot)) + .AppendLine(); information = sbInformation.ToString(); imagePlugin.ReadSectors(partition.Start, _multiplier * 2, out byte[] boot); - XmlFsType = new FileSystemType + metadata = new FileSystem { - Bootable = !ArrayHelpers.ArrayIsNullOrEmpty(boot), - Clusters = (ulong)volEntry.Blocks, - ClusterSize = imagePlugin.Info.SectorSize, - Files = (ulong)volEntry.Files, - FilesSpecified = true, - Type = "UCSD Pascal", - VolumeName = StringHandlers.PascalToString(volEntry.VolumeName, Encoding) + Bootable = !ArrayHelpers.ArrayIsNullOrEmpty(boot), + Clusters = (ulong)volEntry.Blocks, + ClusterSize = imagePlugin.Info.SectorSize, + Files = (ulong)volEntry.Files, + Type = FS_TYPE, + VolumeName = StringHandlers.PascalToString(volEntry.VolumeName, encoding) }; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/UCSDPascal/Structs.cs b/Aaru.Filesystems/UCSDPascal/Structs.cs index c3cfb2b40..f1bc818f8 100644 --- a/Aaru.Filesystems/UCSDPascal/Structs.cs +++ b/Aaru.Filesystems/UCSDPascal/Structs.cs @@ -27,17 +27,79 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.UCSDPascal; - using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; // Information from Call-A.P.P.L.E. Pascal Disk Directory Structure [SuppressMessage("ReSharper", "NotAccessedField.Local")] public sealed partial class PascalPlugin { +#region Nested type: PascalDirNode + + sealed class PascalDirNode : IDirNode + { + internal string[] Contents; + internal int Position; + +#region IDirNode Members + + /// + public string Path { get; init; } + +#endregion + } + +#endregion + +#region Nested type: PascalFileEntry + + struct PascalFileEntry + { + /// 0x00, first block of file + public short FirstBlock; + /// 0x02, last block of file + public short LastBlock; + /// 0x04, entry type + public PascalFileKind EntryType; + /// 0x06, file name + public byte[] Filename; + /// 0x16, bytes used in last block + public short LastBytes; + /// 0x18, modification time + public short ModificationTime; + } + +#endregion + +#region Nested type: PascalFileNode + + sealed class PascalFileNode : IFileNode + { + internal byte[] Cache; + +#region IFileNode Members + + /// + public string Path { get; init; } + + /// + public long Length { get; init; } + + /// + public long Offset { get; set; } + +#endregion + } + +#endregion + +#region Nested type: PascalVolumeEntry + struct PascalVolumeEntry { /// 0x00, first block of volume entry @@ -60,19 +122,5 @@ public sealed partial class PascalPlugin public int Tail; } - struct PascalFileEntry - { - /// 0x00, first block of file - public short FirstBlock; - /// 0x02, last block of file - public short LastBlock; - /// 0x04, entry type - public PascalFileKind EntryType; - /// 0x06, file name - public byte[] Filename; - /// 0x16, bytes used in last block - public short LastBytes; - /// 0x18, modification time - public short ModificationTime; - } +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/UCSDPascal/Super.cs b/Aaru.Filesystems/UCSDPascal/Super.cs index b2de9036c..58cd2c926 100644 --- a/Aaru.Filesystems/UCSDPascal/Super.cs +++ b/Aaru.Filesystems/UCSDPascal/Super.cs @@ -27,47 +27,46 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.UCSDPascal; - using System; using System.Collections.Generic; -using Aaru.CommonTypes; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Helpers; using Claunia.Encoding; -using Schemas; using Encoding = System.Text.Encoding; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; // Information from Call-A.P.P.L.E. Pascal Disk Directory Structure public sealed partial class PascalPlugin { +#region IReadOnlyFilesystem Members + /// - public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, - Dictionary options, string @namespace) + public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, + Dictionary options, string @namespace) { - _device = imagePlugin; - Encoding = encoding ?? new Apple2(); + _device = imagePlugin; + _encoding = encoding ?? new Apple2(); options ??= GetDefaultOptions(); - if(options.TryGetValue("debug", out string debugString)) - bool.TryParse(debugString, out _debug); + if(options.TryGetValue("debug", out string debugString)) bool.TryParse(debugString, out _debug); - if(_device.Info.Sectors < 3) - return ErrorNumber.InvalidArgument; + if(_device.Info.Sectors < 3) return ErrorNumber.InvalidArgument; _multiplier = (uint)(imagePlugin.Info.SectorSize == 256 ? 2 : 1); // Blocks 0 and 1 are boot code ErrorNumber errno = _device.ReadSectors(_multiplier * 2, _multiplier, out _catalogBlocks); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; // On Apple //, it's little endian // TODO: Fix @@ -99,12 +98,11 @@ public sealed partial class PascalPlugin (uint)(_mountedVolEntry.LastBlock - _mountedVolEntry.FirstBlock - 2) * _multiplier, out _catalogBlocks); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; var offset = 26; - _fileEntries = new List(); + _fileEntries = []; while(offset + 26 < _catalogBlocks.Length) { @@ -120,27 +118,23 @@ public sealed partial class PascalPlugin Array.Copy(_catalogBlocks, offset + 0x06, entry.Filename, 0, 16); - if(entry.Filename[0] <= 15 && - entry.Filename[0] > 0) - _fileEntries.Add(entry); + if(entry.Filename[0] <= 15 && entry.Filename[0] > 0) _fileEntries.Add(entry); offset += 26; } errno = _device.ReadSectors(0, 2 * _multiplier, out _bootBlocks); - if(errno != ErrorNumber.NoError) - return errno; + if(errno != ErrorNumber.NoError) return errno; - XmlFsType = new FileSystemType + Metadata = new FileSystem { - Bootable = !ArrayHelpers.ArrayIsNullOrEmpty(_bootBlocks), - Clusters = (ulong)_mountedVolEntry.Blocks, - ClusterSize = _device.Info.SectorSize, - Files = (ulong)_mountedVolEntry.Files, - FilesSpecified = true, - Type = "UCSD Pascal", - VolumeName = StringHandlers.PascalToString(_mountedVolEntry.VolumeName, Encoding) + Bootable = !ArrayHelpers.ArrayIsNullOrEmpty(_bootBlocks), + Clusters = (ulong)_mountedVolEntry.Blocks, + ClusterSize = _device.Info.SectorSize, + Files = (ulong)_mountedVolEntry.Files, + Type = FS_TYPE, + VolumeName = StringHandlers.PascalToString(_mountedVolEntry.VolumeName, _encoding) }; _mounted = true; @@ -167,14 +161,15 @@ public sealed partial class PascalPlugin Files = (ulong)_mountedVolEntry.Files, FreeBlocks = 0, PluginId = Id, - Type = "UCSD Pascal" + Type = FS_TYPE }; stat.FreeBlocks = (ulong)(_mountedVolEntry.Blocks - (_mountedVolEntry.LastBlock - _mountedVolEntry.FirstBlock)); - foreach(PascalFileEntry entry in _fileEntries) - stat.FreeBlocks -= (ulong)(entry.LastBlock - entry.FirstBlock); + foreach(PascalFileEntry entry in _fileEntries) stat.FreeBlocks -= (ulong)(entry.LastBlock - entry.FirstBlock); return ErrorNumber.NotImplemented; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/UCSDPascal/UCSDPascal.cs b/Aaru.Filesystems/UCSDPascal/UCSDPascal.cs index 35ab08c7e..8546c2c55 100644 --- a/Aaru.Filesystems/UCSDPascal/UCSDPascal.cs +++ b/Aaru.Filesystems/UCSDPascal/UCSDPascal.cs @@ -27,43 +27,48 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems.UCSDPascal; - using System; using System.Collections.Generic; using System.Text; +using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; -using Schemas; + +namespace Aaru.Filesystems; // Information from Call-A.P.P.L.E. Pascal Disk Directory Structure /// /// Implements the U.C.S.D. Pascal filesystem public sealed partial class PascalPlugin : IReadOnlyFilesystem { + const string MODULE_NAME = "U.C.S.D. Pascal Plugin"; byte[] _bootBlocks; byte[] _catalogBlocks; bool _debug; IMediaImage _device; + Encoding _encoding; List _fileEntries; bool _mounted; PascalVolumeEntry _mountedVolEntry; /// Apple II disks use 256 bytes / sector, but filesystem assumes it's 512 bytes / sector uint _multiplier; +#region IReadOnlyFilesystem Members + /// - public FileSystemType XmlFsType { get; private set; } + public string Name => Localization.PascalPlugin_Name; + /// - public string Name => "U.C.S.D. Pascal filesystem"; + public FileSystem Metadata { get; private set; } + /// public Guid Id => new("B0AC2CB5-72AA-473A-9200-270B5A2C2D53"); + /// - public Encoding Encoding { get; private set; } - /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public ErrorNumber ListXAttr(string path, out List xattrs) @@ -91,6 +96,8 @@ public sealed partial class PascalPlugin : IReadOnlyFilesystem /// public Dictionary Namespaces => null; +#endregion + static Dictionary GetDefaultOptions() => new() { { diff --git a/Aaru.Filesystems/UDF.cs b/Aaru.Filesystems/UDF.cs deleted file mode 100644 index 2ba4d1e0d..000000000 --- a/Aaru.Filesystems/UDF.cs +++ /dev/null @@ -1,580 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : UDF.cs -// Author(s) : Natalia Portillo -// -// Component : Universal Disk Format plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Universal Disk Format and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// TODO: Detect bootable -/// -/// Implements detection of the Universal Disk Format filesystem -[SuppressMessage("ReSharper", "UnusedMember.Local")] -public sealed class UDF : IFilesystem -{ - readonly byte[] _magic = - { - 0x2A, 0x4F, 0x53, 0x54, 0x41, 0x20, 0x55, 0x44, 0x46, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x6C, 0x69, 0x61, 0x6E, - 0x74, 0x00, 0x00, 0x00, 0x00 - }; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Universal Disk Format"; - /// - public Guid Id => new("83976FEC-A91B-464B-9293-56C719461BAB"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - // UDF needs at least that - if(partition.End - partition.Start < 256) - return false; - - // UDF needs at least that - if(imagePlugin.Info.SectorSize < 512) - return false; - - byte[] sector; - var anchor = new AnchorVolumeDescriptorPointer(); - - // All positions where anchor may reside, with the ratio between 512 and 2048bps - ulong[][] positions = - { - new ulong[] - { - 256, 1 - }, - new ulong[] - { - 512, 1 - }, - new ulong[] - { - partition.End - 256, 1 - }, - new ulong[] - { - partition.End, 1 - }, - new ulong[] - { - 1024, 4 - }, - new ulong[] - { - 2048, 4 - }, - new ulong[] - { - partition.End - 1024, 4 - }, - new ulong[] - { - partition.End - 4, 4 - } - }; - - var anchorFound = false; - uint ratio = 1; - - foreach(ulong[] position in positions.Where(position => position[0] + partition.Start + position[1] <= - partition.End && position[0] < partition.End)) - { - ErrorNumber errno = imagePlugin.ReadSectors(position[0], (uint)position[1], out sector); - - if(errno != ErrorNumber.NoError) - continue; - - anchor = Marshal.ByteArrayToStructureLittleEndian(sector); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagIdentifier = {0}", anchor.tag.tagIdentifier); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.tag.descriptorVersion = {0}", - anchor.tag.descriptorVersion); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagChecksum = 0x{0:X2}", anchor.tag.tagChecksum); - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.tag.reserved = {0}", anchor.tag.reserved); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagSerialNumber = {0}", anchor.tag.tagSerialNumber); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.tag.descriptorCrc = 0x{0:X4}", anchor.tag.descriptorCrc); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.tag.descriptorCrcLength = {0}", - anchor.tag.descriptorCrcLength); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagLocation = {0}", anchor.tag.tagLocation); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.mainVolumeDescriptorSequenceExtent.length = {0}", - anchor.mainVolumeDescriptorSequenceExtent.length); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.mainVolumeDescriptorSequenceExtent.location = {0}", - anchor.mainVolumeDescriptorSequenceExtent.location); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.reserveVolumeDescriptorSequenceExtent.length = {0}", - anchor.reserveVolumeDescriptorSequenceExtent.length); - - AaruConsole.DebugWriteLine("UDF Plugin", "anchor.reserveVolumeDescriptorSequenceExtent.location = {0}", - anchor.reserveVolumeDescriptorSequenceExtent.location); - - if(anchor.tag.tagIdentifier != TagIdentifier.AnchorVolumeDescriptorPointer || - anchor.tag.tagLocation != position[0] / position[1] || - anchor.mainVolumeDescriptorSequenceExtent.location * position[1] + partition.Start >= partition.End) - continue; - - anchorFound = true; - ratio = (uint)position[1]; - - break; - } - - if(!anchorFound) - return false; - - ulong count = 0; - - while(count < 256) - { - ErrorNumber errno = - imagePlugin. - ReadSectors(partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location * ratio + count * ratio, - ratio, out sector); - - if(errno != ErrorNumber.NoError) - { - count++; - - continue; - } - - var tagId = (TagIdentifier)BitConverter.ToUInt16(sector, 0); - var location = BitConverter.ToUInt32(sector, 0x0C); - - if(location == partition.Start / ratio + anchor.mainVolumeDescriptorSequenceExtent.location + count) - { - if(tagId == TagIdentifier.TerminatingDescriptor) - break; - - if(tagId == TagIdentifier.LogicalVolumeDescriptor) - { - LogicalVolumeDescriptor lvd = - Marshal.ByteArrayToStructureLittleEndian(sector); - - return _magic.SequenceEqual(lvd.domainIdentifier.identifier); - } - } - else - break; - - count++; - } - - return false; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - information = ""; - ErrorNumber errno; - - // UDF is always UTF-8 - Encoding = Encoding.UTF8; - byte[] sector; - - var sbInformation = new StringBuilder(); - - sbInformation.AppendLine("Universal Disk Format"); - - var anchor = new AnchorVolumeDescriptorPointer(); - - // All positions where anchor may reside, with the ratio between 512 and 2048bps - ulong[][] positions = - { - new ulong[] - { - 256, 1 - }, - new ulong[] - { - 512, 1 - }, - new ulong[] - { - partition.End - 256, 1 - }, - new ulong[] - { - partition.End, 1 - }, - new ulong[] - { - 1024, 4 - }, - new ulong[] - { - 2048, 4 - }, - new ulong[] - { - partition.End - 1024, 4 - }, - new ulong[] - { - partition.End - 4, 4 - } - }; - - uint ratio = 1; - - foreach(ulong[] position in positions) - { - errno = imagePlugin.ReadSectors(position[0], (uint)position[1], out sector); - - if(errno != ErrorNumber.NoError) - continue; - - anchor = Marshal.ByteArrayToStructureLittleEndian(sector); - - if(anchor.tag.tagIdentifier != TagIdentifier.AnchorVolumeDescriptorPointer || - anchor.tag.tagLocation != position[0] / position[1] || - anchor.mainVolumeDescriptorSequenceExtent.location + partition.Start >= partition.End) - continue; - - ratio = (uint)position[1]; - - break; - } - - ulong count = 0; - - var pvd = new PrimaryVolumeDescriptor(); - var lvd = new LogicalVolumeDescriptor(); - LogicalVolumeIntegrityDescriptor lvid; - var lvidiu = new LogicalVolumeIntegrityDescriptorImplementationUse(); - - while(count < 256) - { - errno = - imagePlugin. - ReadSectors(partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location * ratio + count * ratio, - ratio, out sector); - - if(errno != ErrorNumber.NoError) - continue; - - var tagId = (TagIdentifier)BitConverter.ToUInt16(sector, 0); - var location = BitConverter.ToUInt32(sector, 0x0C); - - if(location == partition.Start / ratio + anchor.mainVolumeDescriptorSequenceExtent.location + count) - { - if(tagId == TagIdentifier.TerminatingDescriptor) - break; - - switch(tagId) - { - case TagIdentifier.LogicalVolumeDescriptor: - lvd = Marshal.ByteArrayToStructureLittleEndian(sector); - - break; - case TagIdentifier.PrimaryVolumeDescriptor: - pvd = Marshal.ByteArrayToStructureLittleEndian(sector); - - break; - } - } - else - break; - - count++; - } - - errno = imagePlugin.ReadSectors(lvd.integritySequenceExtent.location * ratio, ratio, out sector); - - if(errno != ErrorNumber.NoError) - return; - - lvid = Marshal.ByteArrayToStructureLittleEndian(sector); - - if(lvid.tag.tagIdentifier == TagIdentifier.LogicalVolumeIntegrityDescriptor && - lvid.tag.tagLocation == lvd.integritySequenceExtent.location) - lvidiu = - Marshal.ByteArrayToStructureLittleEndian(sector, - (int)(lvid.numberOfPartitions * 8 + 80), - System.Runtime.InteropServices.Marshal.SizeOf(lvidiu)); - else - lvid = new LogicalVolumeIntegrityDescriptor(); - - sbInformation.AppendFormat("Volume is number {0} of {1}", pvd.volumeSequenceNumber, - pvd.maximumVolumeSequenceNumber).AppendLine(); - - sbInformation.AppendFormat("Volume set identifier: {0}", - StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier)).AppendLine(); - - sbInformation.AppendFormat("Volume name: {0}", StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier)). - AppendLine(); - - sbInformation.AppendFormat("Volume uses {0} bytes per block", lvd.logicalBlockSize).AppendLine(); - - sbInformation.AppendFormat("Volume was last written in {0}", EcmaToDateTime(lvid.recordingDateTime)). - AppendLine(); - - sbInformation.AppendFormat("Volume contains {0} partitions", lvid.numberOfPartitions).AppendLine(); - - sbInformation.AppendFormat("Volume contains {0} files and {1} directories", lvidiu.files, lvidiu.directories). - AppendLine(); - - sbInformation.AppendFormat("Volume conforms to {0}", - Encoding.GetString(lvd.domainIdentifier.identifier).TrimEnd('\u0000')).AppendLine(); - - sbInformation.AppendFormat("Volume was last written by: {0}", - Encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000')). - AppendLine(); - - sbInformation.AppendFormat("Volume requires UDF version {0}.{1:X2} to be read", - Convert.ToInt32($"{(lvidiu.minimumReadUDF & 0xFF00) >> 8}", 10), - Convert.ToInt32($"{lvidiu.minimumReadUDF & 0xFF}", 10)).AppendLine(); - - sbInformation.AppendFormat("Volume requires UDF version {0}.{1:X2} to be written to", - Convert.ToInt32($"{(lvidiu.minimumWriteUDF & 0xFF00) >> 8}", 10), - Convert.ToInt32($"{lvidiu.minimumWriteUDF & 0xFF}", 10)).AppendLine(); - - sbInformation.AppendFormat("Volume cannot be written by any UDF version higher than {0}.{1:X2}", - Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}", 10), - Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10)).AppendLine(); - - XmlFsType = new FileSystemType - { - Type = - $"UDF v{Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}", 10)}.{Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10):X2}", - ApplicationIdentifier = Encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000'), - ClusterSize = lvd.logicalBlockSize, - ModificationDate = EcmaToDateTime(lvid.recordingDateTime), - ModificationDateSpecified = true, - Files = lvidiu.files, - FilesSpecified = true, - VolumeName = StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier), - VolumeSetIdentifier = StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier), - VolumeSerial = StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier), - SystemIdentifier = Encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000') - }; - - XmlFsType.Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / - XmlFsType.ClusterSize; - - information = sbInformation.ToString(); - } - - static DateTime EcmaToDateTime(Timestamp timestamp) => DateHandlers.EcmaToDateTime(timestamp.typeAndZone, - timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second, - timestamp.centiseconds, timestamp.hundredsMicroseconds, timestamp.microseconds); - - [Flags] - enum EntityFlags : byte - { - Dirty = 0x01, - Protected = 0x02 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct EntityIdentifier - { - /// Entity flags - public readonly EntityFlags flags; - /// Structure identifier - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 23)] - public readonly byte[] identifier; - /// Structure data - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] identifierSuffix; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Timestamp - { - public readonly ushort typeAndZone; - public readonly short year; - public readonly byte month; - public readonly byte day; - public readonly byte hour; - public readonly byte minute; - public readonly byte second; - public readonly byte centiseconds; - public readonly byte hundredsMicroseconds; - public readonly byte microseconds; - } - - enum TagIdentifier : ushort - { - PrimaryVolumeDescriptor = 1, - AnchorVolumeDescriptorPointer = 2, - VolumeDescriptorPointer = 3, - ImplementationUseVolumeDescriptor = 4, - PartitionDescriptor = 5, - LogicalVolumeDescriptor = 6, - UnallocatedSpaceDescriptor = 7, - TerminatingDescriptor = 8, - LogicalVolumeIntegrityDescriptor = 9 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DescriptorTag - { - public readonly TagIdentifier tagIdentifier; - public readonly ushort descriptorVersion; - public readonly byte tagChecksum; - public readonly byte reserved; - public readonly ushort tagSerialNumber; - public readonly ushort descriptorCrc; - public readonly ushort descriptorCrcLength; - public readonly uint tagLocation; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ExtentDescriptor - { - public readonly uint length; - public readonly uint location; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct CharacterSpecification - { - public readonly byte type; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 63)] - public readonly byte[] information; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct AnchorVolumeDescriptorPointer - { - public readonly DescriptorTag tag; - public readonly ExtentDescriptor mainVolumeDescriptorSequenceExtent; - public readonly ExtentDescriptor reserveVolumeDescriptorSequenceExtent; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 480)] - public readonly byte[] reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct PrimaryVolumeDescriptor - { - public readonly DescriptorTag tag; - public readonly uint volumeDescriptorSequenceNumber; - public readonly uint primaryVolumeDescriptorNumber; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] volumeIdentifier; - public readonly ushort volumeSequenceNumber; - public readonly ushort maximumVolumeSequenceNumber; - public readonly ushort interchangeLevel; - public readonly ushort maximumInterchangeLevel; - public readonly uint characterSetList; - public readonly uint maximumCharacterSetList; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public readonly byte[] volumeSetIdentifier; - public readonly CharacterSpecification descriptorCharacterSet; - public readonly CharacterSpecification explanatoryCharacterSet; - public readonly ExtentDescriptor volumeAbstract; - public readonly ExtentDescriptor volumeCopyright; - public readonly EntityIdentifier applicationIdentifier; - public readonly Timestamp recordingDateTime; - public readonly EntityIdentifier implementationIdentifier; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] implementationUse; - public readonly uint predecessorVolumeDescriptorSequenceLocation; - public readonly ushort flags; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)] - public readonly byte[] reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct LogicalVolumeDescriptor - { - public readonly DescriptorTag tag; - public readonly uint volumeDescriptorSequenceNumber; - public readonly CharacterSpecification descriptorCharacterSet; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public readonly byte[] logicalVolumeIdentifier; - public readonly uint logicalBlockSize; - public readonly EntityIdentifier domainIdentifier; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] logicalVolumeContentsUse; - public readonly uint mapTableLength; - public readonly uint numberOfPartitionMaps; - public readonly EntityIdentifier implementationIdentifier; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public readonly byte[] implementationUse; - public readonly ExtentDescriptor integritySequenceExtent; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct LogicalVolumeIntegrityDescriptor - { - public readonly DescriptorTag tag; - public readonly Timestamp recordingDateTime; - public readonly uint integrityType; - public readonly ExtentDescriptor nextIntegrityExtent; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] logicalVolumeContentsUse; - public readonly uint numberOfPartitions; - public readonly uint lengthOfImplementationUse; - - // Follows uint[numberOfPartitions] freeSpaceTable; - // Follows uint[numberOfPartitions] sizeTable; - // Follows byte[lengthOfImplementationUse] implementationUse; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct LogicalVolumeIntegrityDescriptorImplementationUse - { - public readonly EntityIdentifier implementationId; - public readonly uint files; - public readonly uint directories; - public readonly ushort minimumReadUDF; - public readonly ushort minimumWriteUDF; - public readonly ushort maximumWriteUDF; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/UDF/Consts.cs b/Aaru.Filesystems/UDF/Consts.cs new file mode 100644 index 000000000..ee92395a6 --- /dev/null +++ b/Aaru.Filesystems/UDF/Consts.cs @@ -0,0 +1,45 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Universal Disk Format plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// TODO: Detect bootable +/// +/// Implements detection of the Universal Disk Format filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class UDF +{ + const string FS_TYPE = "udf"; + readonly byte[] _magic = + [ + 0x2A, 0x4F, 0x53, 0x54, 0x41, 0x20, 0x55, 0x44, 0x46, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x6C, 0x69, 0x61, 0x6E, + 0x74, 0x00, 0x00, 0x00, 0x00 + ]; +} \ No newline at end of file diff --git a/Aaru.Filesystems/UDF/Enums.cs b/Aaru.Filesystems/UDF/Enums.cs new file mode 100644 index 000000000..a178ffcee --- /dev/null +++ b/Aaru.Filesystems/UDF/Enums.cs @@ -0,0 +1,50 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Universal Disk Format plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// TODO: Detect bootable +/// +/// Implements detection of the Universal Disk Format filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class UDF +{ +#region Nested type: EntityFlags + + [Flags] + enum EntityFlags : byte + { + Dirty = 0x01, + Protected = 0x02 + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/UDF/Helpers.cs b/Aaru.Filesystems/UDF/Helpers.cs new file mode 100644 index 000000000..14b2de856 --- /dev/null +++ b/Aaru.Filesystems/UDF/Helpers.cs @@ -0,0 +1,51 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Helpers.cs +// Author(s) : Natalia Portillo +// +// Component : Universal Disk Format plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.Helpers; + +namespace Aaru.Filesystems; + +// TODO: Detect bootable +/// +/// Implements detection of the Universal Disk Format filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class UDF +{ + static DateTime EcmaToDateTime(Timestamp timestamp) => DateHandlers.EcmaToDateTime(timestamp.typeAndZone, + timestamp.year, + timestamp.month, + timestamp.day, + timestamp.hour, + timestamp.minute, + timestamp.second, + timestamp.centiseconds, + timestamp.hundredsMicroseconds, + timestamp.microseconds); +} \ No newline at end of file diff --git a/Aaru.Filesystems/UDF/Info.cs b/Aaru.Filesystems/UDF/Info.cs new file mode 100644 index 000000000..749527b38 --- /dev/null +++ b/Aaru.Filesystems/UDF/Info.cs @@ -0,0 +1,340 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Universal Disk Format plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// TODO: Detect bootable +/// +/// Implements detection of the Universal Disk Format filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class UDF +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + // UDF needs at least that + if(partition.End - partition.Start < 256) return false; + + // UDF needs at least that + if(imagePlugin.Info.SectorSize < 512) return false; + + var anchor = new AnchorVolumeDescriptorPointer(); + + // All positions where anchor may reside, with the ratio between 512 and 2048bps + ulong[][] positions = + [ + [256, 1], [512, 1], [partition.End - 256, 1], [partition.End, 1], [1024, 4], [2048, 4], + [partition.End - 1024, 4], [partition.End - 4, 4] + ]; + + var anchorFound = false; + uint ratio = 1; + byte[] sector = null; + + foreach(ulong[] position in from position in + positions.Where(position => + position[0] + partition.Start + position[1] <= + partition.End && + position[0] < partition.End) + let errno = imagePlugin.ReadSectors(position[0], (uint)position[1], out sector) + where errno == ErrorNumber.NoError + select position) + { + anchor = Marshal.ByteArrayToStructureLittleEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, "anchor.tag.tagIdentifier = {0}", anchor.tag.tagIdentifier); + + AaruConsole.DebugWriteLine(MODULE_NAME, "anchor.tag.descriptorVersion = {0}", anchor.tag.descriptorVersion); + + AaruConsole.DebugWriteLine(MODULE_NAME, "anchor.tag.tagChecksum = 0x{0:X2}", anchor.tag.tagChecksum); + AaruConsole.DebugWriteLine(MODULE_NAME, "anchor.tag.reserved = {0}", anchor.tag.reserved); + + AaruConsole.DebugWriteLine(MODULE_NAME, "anchor.tag.tagSerialNumber = {0}", anchor.tag.tagSerialNumber); + + AaruConsole.DebugWriteLine(MODULE_NAME, "anchor.tag.descriptorCrc = 0x{0:X4}", anchor.tag.descriptorCrc); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "anchor.tag.descriptorCrcLength = {0}", + anchor.tag.descriptorCrcLength); + + AaruConsole.DebugWriteLine(MODULE_NAME, "anchor.tag.tagLocation = {0}", anchor.tag.tagLocation); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "anchor.mainVolumeDescriptorSequenceExtent.length = {0}", + anchor.mainVolumeDescriptorSequenceExtent.length); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "anchor.mainVolumeDescriptorSequenceExtent.location = {0}", + anchor.mainVolumeDescriptorSequenceExtent.location); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "anchor.reserveVolumeDescriptorSequenceExtent.length = {0}", + anchor.reserveVolumeDescriptorSequenceExtent.length); + + AaruConsole.DebugWriteLine(MODULE_NAME, + "anchor.reserveVolumeDescriptorSequenceExtent.location = {0}", + anchor.reserveVolumeDescriptorSequenceExtent.location); + + if(anchor.tag.tagIdentifier != TagIdentifier.AnchorVolumeDescriptorPointer || + anchor.tag.tagLocation != position[0] / position[1] || + anchor.mainVolumeDescriptorSequenceExtent.location * position[1] + partition.Start >= partition.End) + continue; + + anchorFound = true; + ratio = (uint)position[1]; + + break; + } + + if(!anchorFound) return false; + + ulong count = 0; + + while(count < 256) + { + ErrorNumber errno = + imagePlugin.ReadSectors(partition.Start + + anchor.mainVolumeDescriptorSequenceExtent.location * ratio + + count * ratio, + ratio, + out sector); + + if(errno != ErrorNumber.NoError) + { + count++; + + continue; + } + + var tagId = (TagIdentifier)BitConverter.ToUInt16(sector, 0); + var location = BitConverter.ToUInt32(sector, 0x0C); + + if(location == partition.Start / ratio + anchor.mainVolumeDescriptorSequenceExtent.location + count) + { + if(tagId == TagIdentifier.TerminatingDescriptor) break; + + if(tagId == TagIdentifier.LogicalVolumeDescriptor) + { + LogicalVolumeDescriptor lvd = + Marshal.ByteArrayToStructureLittleEndian(sector); + + return _magic.SequenceEqual(lvd.domainIdentifier.identifier); + } + } + else + break; + + count++; + } + + return false; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + ErrorNumber errno; + metadata = new FileSystem(); + + // UDF is always UTF-8 + encoding = Encoding.UTF8; + byte[] sector; + + var sbInformation = new StringBuilder(); + + sbInformation.AppendLine(Localization.Universal_Disk_Format); + + var anchor = new AnchorVolumeDescriptorPointer(); + + // All positions where anchor may reside, with the ratio between 512 and 2048bps + ulong[][] positions = + [ + [256, 1], [512, 1], [partition.End - 256, 1], [partition.End, 1], [1024, 4], [2048, 4], + [partition.End - 1024, 4], [partition.End - 4, 4] + ]; + + uint ratio = 1; + + foreach(ulong[] position in positions) + { + errno = imagePlugin.ReadSectors(position[0], (uint)position[1], out sector); + + if(errno != ErrorNumber.NoError) continue; + + anchor = Marshal.ByteArrayToStructureLittleEndian(sector); + + if(anchor.tag.tagIdentifier != TagIdentifier.AnchorVolumeDescriptorPointer || + anchor.tag.tagLocation != position[0] / position[1] || + anchor.mainVolumeDescriptorSequenceExtent.location + partition.Start >= partition.End) + continue; + + ratio = (uint)position[1]; + + break; + } + + ulong count = 0; + + var pvd = new PrimaryVolumeDescriptor(); + var lvd = new LogicalVolumeDescriptor(); + var lvidiu = new LogicalVolumeIntegrityDescriptorImplementationUse(); + + while(count < 256) + { + errno = imagePlugin.ReadSectors(partition.Start + + anchor.mainVolumeDescriptorSequenceExtent.location * ratio + + count * ratio, + ratio, + out sector); + + if(errno != ErrorNumber.NoError) continue; + + var tagId = (TagIdentifier)BitConverter.ToUInt16(sector, 0); + var location = BitConverter.ToUInt32(sector, 0x0C); + + if(location == partition.Start / ratio + anchor.mainVolumeDescriptorSequenceExtent.location + count) + { + if(tagId == TagIdentifier.TerminatingDescriptor) break; + + switch(tagId) + { + case TagIdentifier.LogicalVolumeDescriptor: + lvd = Marshal.ByteArrayToStructureLittleEndian(sector); + + break; + case TagIdentifier.PrimaryVolumeDescriptor: + pvd = Marshal.ByteArrayToStructureLittleEndian(sector); + + break; + } + } + else + break; + + count++; + } + + errno = imagePlugin.ReadSectors(lvd.integritySequenceExtent.location * ratio, ratio, out sector); + + if(errno != ErrorNumber.NoError) return; + + LogicalVolumeIntegrityDescriptor lvid = + Marshal.ByteArrayToStructureLittleEndian(sector); + + if(lvid.tag.tagIdentifier == TagIdentifier.LogicalVolumeIntegrityDescriptor && + lvid.tag.tagLocation == lvd.integritySequenceExtent.location) + { + lvidiu = Marshal.ByteArrayToStructureLittleEndian(sector, + (int)(lvid.numberOfPartitions * 8 + 80), + System.Runtime.InteropServices.Marshal.SizeOf(lvidiu)); + } + else + lvid = new LogicalVolumeIntegrityDescriptor(); + + sbInformation.AppendFormat(Localization.Volume_is_number_0_of_1, + pvd.volumeSequenceNumber, + pvd.maximumVolumeSequenceNumber) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_set_identifier_0, + StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier)) + .AppendLine(); + + sbInformation + .AppendFormat(Localization.Volume_name_0, StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_uses_0_bytes_per_block, lvd.logicalBlockSize).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_was_last_written_on_0, EcmaToDateTime(lvid.recordingDateTime)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_contains_0_partitions, lvid.numberOfPartitions).AppendLine(); + + sbInformation + .AppendFormat(Localization.Volume_contains_0_files_and_1_directories, lvidiu.files, lvidiu.directories) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_conforms_to_0, + encoding.GetString(lvd.domainIdentifier.identifier).TrimEnd('\u0000')) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_was_last_written_by_0, + encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000')) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_requires_UDF_version_0_1_to_be_read, + Convert.ToInt32($"{(lvidiu.minimumReadUDF & 0xFF00) >> 8}", 10), + Convert.ToInt32($"{lvidiu.minimumReadUDF & 0xFF}", 10)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_requires_UDF_version_0_1_to_be_written_to, + Convert.ToInt32($"{(lvidiu.minimumWriteUDF & 0xFF00) >> 8}", 10), + Convert.ToInt32($"{lvidiu.minimumWriteUDF & 0xFF}", 10)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_cannot_be_written_by_any_UDF_version_higher_than_0_1, + Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}", 10), + Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10)) + .AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ApplicationIdentifier = encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000'), + ClusterSize = lvd.logicalBlockSize, + ModificationDate = EcmaToDateTime(lvid.recordingDateTime), + Files = lvidiu.files, + VolumeName = StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier), + VolumeSetIdentifier = StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier), + VolumeSerial = StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier), + SystemIdentifier = encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000') + }; + + metadata.Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / metadata.ClusterSize; + + information = sbInformation.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/UDF/Structs.cs b/Aaru.Filesystems/UDF/Structs.cs new file mode 100644 index 000000000..a2575e51c --- /dev/null +++ b/Aaru.Filesystems/UDF/Structs.cs @@ -0,0 +1,241 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Universal Disk Format plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// TODO: Detect bootable +/// +/// Implements detection of the Universal Disk Format filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class UDF +{ +#region Nested type: AnchorVolumeDescriptorPointer + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct AnchorVolumeDescriptorPointer + { + public readonly DescriptorTag tag; + public readonly ExtentDescriptor mainVolumeDescriptorSequenceExtent; + public readonly ExtentDescriptor reserveVolumeDescriptorSequenceExtent; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 480)] + public readonly byte[] reserved; + } + +#endregion + +#region Nested type: CharacterSpecification + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct CharacterSpecification + { + public readonly byte type; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 63)] + public readonly byte[] information; + } + +#endregion + +#region Nested type: DescriptorTag + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DescriptorTag + { + public readonly TagIdentifier tagIdentifier; + public readonly ushort descriptorVersion; + public readonly byte tagChecksum; + public readonly byte reserved; + public readonly ushort tagSerialNumber; + public readonly ushort descriptorCrc; + public readonly ushort descriptorCrcLength; + public readonly uint tagLocation; + } + +#endregion + +#region Nested type: EntityIdentifier + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct EntityIdentifier + { + /// Entity flags + public readonly EntityFlags flags; + /// Structure identifier + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 23)] + public readonly byte[] identifier; + /// Structure data + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] identifierSuffix; + } + +#endregion + +#region Nested type: ExtentDescriptor + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ExtentDescriptor + { + public readonly uint length; + public readonly uint location; + } + +#endregion + +#region Nested type: LogicalVolumeDescriptor + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct LogicalVolumeDescriptor + { + public readonly DescriptorTag tag; + public readonly uint volumeDescriptorSequenceNumber; + public readonly CharacterSpecification descriptorCharacterSet; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public readonly byte[] logicalVolumeIdentifier; + public readonly uint logicalBlockSize; + public readonly EntityIdentifier domainIdentifier; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] logicalVolumeContentsUse; + public readonly uint mapTableLength; + public readonly uint numberOfPartitionMaps; + public readonly EntityIdentifier implementationIdentifier; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public readonly byte[] implementationUse; + public readonly ExtentDescriptor integritySequenceExtent; + } + +#endregion + +#region Nested type: LogicalVolumeIntegrityDescriptor + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct LogicalVolumeIntegrityDescriptor + { + public readonly DescriptorTag tag; + public readonly Timestamp recordingDateTime; + public readonly uint integrityType; + public readonly ExtentDescriptor nextIntegrityExtent; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] logicalVolumeContentsUse; + public readonly uint numberOfPartitions; + public readonly uint lengthOfImplementationUse; + + // Follows uint[numberOfPartitions] freeSpaceTable; + // Follows uint[numberOfPartitions] sizeTable; + // Follows byte[lengthOfImplementationUse] implementationUse; + } + +#endregion + +#region Nested type: LogicalVolumeIntegrityDescriptorImplementationUse + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct LogicalVolumeIntegrityDescriptorImplementationUse + { + public readonly EntityIdentifier implementationId; + public readonly uint files; + public readonly uint directories; + public readonly ushort minimumReadUDF; + public readonly ushort minimumWriteUDF; + public readonly ushort maximumWriteUDF; + } + +#endregion + +#region Nested type: PrimaryVolumeDescriptor + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct PrimaryVolumeDescriptor + { + public readonly DescriptorTag tag; + public readonly uint volumeDescriptorSequenceNumber; + public readonly uint primaryVolumeDescriptorNumber; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] volumeIdentifier; + public readonly ushort volumeSequenceNumber; + public readonly ushort maximumVolumeSequenceNumber; + public readonly ushort interchangeLevel; + public readonly ushort maximumInterchangeLevel; + public readonly uint characterSetList; + public readonly uint maximumCharacterSetList; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public readonly byte[] volumeSetIdentifier; + public readonly CharacterSpecification descriptorCharacterSet; + public readonly CharacterSpecification explanatoryCharacterSet; + public readonly ExtentDescriptor volumeAbstract; + public readonly ExtentDescriptor volumeCopyright; + public readonly EntityIdentifier applicationIdentifier; + public readonly Timestamp recordingDateTime; + public readonly EntityIdentifier implementationIdentifier; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] implementationUse; + public readonly uint predecessorVolumeDescriptorSequenceLocation; + public readonly ushort flags; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)] + public readonly byte[] reserved; + } + +#endregion + +#region Nested type: TagIdentifier + + enum TagIdentifier : ushort + { + PrimaryVolumeDescriptor = 1, + AnchorVolumeDescriptorPointer = 2, + VolumeDescriptorPointer = 3, + ImplementationUseVolumeDescriptor = 4, + PartitionDescriptor = 5, + LogicalVolumeDescriptor = 6, + UnallocatedSpaceDescriptor = 7, + TerminatingDescriptor = 8, + LogicalVolumeIntegrityDescriptor = 9 + } + +#endregion + +#region Nested type: Timestamp + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Timestamp + { + public readonly ushort typeAndZone; + public readonly short year; + public readonly byte month; + public readonly byte day; + public readonly byte hour; + public readonly byte minute; + public readonly byte second; + public readonly byte centiseconds; + public readonly byte hundredsMicroseconds; + public readonly byte microseconds; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/UDF/UDF.cs b/Aaru.Filesystems/UDF/UDF.cs new file mode 100644 index 000000000..0e3649d8f --- /dev/null +++ b/Aaru.Filesystems/UDF/UDF.cs @@ -0,0 +1,55 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : UDF.cs +// Author(s) : Natalia Portillo +// +// Component : Universal Disk Format plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// TODO: Detect bootable +/// +/// Implements detection of the Universal Disk Format filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class UDF : IFilesystem +{ + const string MODULE_NAME = "UDF Plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.UDF_Name; + + /// + public Guid Id => new("83976FEC-A91B-464B-9293-56C719461BAB"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/UNICOS/Consts.cs b/Aaru.Filesystems/UNICOS/Consts.cs new file mode 100644 index 000000000..b312b2b6a --- /dev/null +++ b/Aaru.Filesystems/UNICOS/Consts.cs @@ -0,0 +1,44 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : UNICOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// UNICOS is ILP64 so let's think everything is 64-bit + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the Cray UNICOS filesystem +public sealed partial class UNICOS +{ + const int NC1_MAXPART = 64; + const int NC1_MAXIREG = 4; + + const ulong UNICOS_MAGIC = 0x6e6331667331636e; + const ulong UNICOS_SECURE = 0xcd076d1771d670cd; + + const string FS_TYPE = "unicos"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/UNICOS/Info.cs b/Aaru.Filesystems/UNICOS/Info.cs new file mode 100644 index 000000000..d80103046 --- /dev/null +++ b/Aaru.Filesystems/UNICOS/Info.cs @@ -0,0 +1,131 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : UNICOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// UNICOS is ILP64 so let's think everything is 64-bit + +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the Cray UNICOS filesystem +public sealed partial class UNICOS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 512) return false; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + if(partition.Start + sbSize >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + Superblock unicosSb = Marshal.ByteArrayToStructureBigEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, Localization.magic_equals_0_expected_1, unicosSb.s_magic, UNICOS_MAGIC); + + return unicosSb.s_magic == UNICOS_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize < 512) return; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < Marshal.SizeOf()) return; + + Superblock unicosSb = Marshal.ByteArrayToStructureBigEndian(sector); + + if(unicosSb.s_magic != UNICOS_MAGIC) return; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.UNICOS_filesystem); + + if(unicosSb.s_secure == UNICOS_SECURE) sb.AppendLine(Localization.Volume_is_secure); + + sb.AppendFormat(Localization.Volume_contains_0_partitions, unicosSb.s_npart).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector, unicosSb.s_iounit).AppendLine(); + sb.AppendLine(Localization._4096_bytes_per_block); + sb.AppendFormat(Localization._0_data_blocks_in_volume, unicosSb.s_fsize).AppendLine(); + sb.AppendFormat(Localization.Root_resides_on_inode_0, unicosSb.s_root).AppendLine(); + sb.AppendFormat(Localization._0_inodes_in_volume, unicosSb.s_isize).AppendLine(); + + sb.AppendFormat(Localization.Volume_last_updated_on_0, DateHandlers.UnixToDateTime(unicosSb.s_time)) + .AppendLine(); + + if(unicosSb.s_error > 0) + sb.AppendFormat(Localization.Volume_is_dirty_error_code_equals_0, unicosSb.s_error).AppendLine(); + + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(unicosSb.s_fname, encoding)).AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = 4096, + Clusters = (ulong)unicosSb.s_fsize, + VolumeName = StringHandlers.CToString(unicosSb.s_fname, encoding), + ModificationDate = DateHandlers.UnixToDateTime(unicosSb.s_time) + }; + + metadata.Dirty |= unicosSb.s_error > 0; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/UNICOS.cs b/Aaru.Filesystems/UNICOS/Structs.cs similarity index 54% rename from Aaru.Filesystems/UNICOS.cs rename to Aaru.Filesystems/UNICOS/Structs.cs index 877bcf7e7..46d696fdc 100644 --- a/Aaru.Filesystems/UNICOS.cs +++ b/Aaru.Filesystems/UNICOS/Structs.cs @@ -2,15 +2,11 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : UNICOS.cs +// Filename : Structs.cs // Author(s) : Natalia Portillo // // Component : UNICOS filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the UNICOS filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,153 +23,30 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ // UNICOS is ILP64 so let's think everything is 64-bit -using blkno_t = System.Int64; -using daddr_t = System.Int64; -using dev_t = System.Int64; -using extent_t = System.Int64; -using ino_t = System.Int64; -using time_t = System.Int64; + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using blkno_t = long; +using daddr_t = long; +using dev_t = long; +using extent_t = long; +using ino_t = long; +using time_t = long; namespace Aaru.Filesystems; -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - /// /// Implements detection for the Cray UNICOS filesystem -public sealed class UNICOS : IFilesystem +public sealed partial class UNICOS { - const int NC1_MAXPART = 64; - const int NC1_MAXIREG = 4; +#region Nested type: nc1fdev_sb - const ulong UNICOS_MAGIC = 0x6e6331667331636e; - const ulong UNICOS_SECURE = 0xcd076d1771d670cd; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "UNICOS Filesystem Plugin"; - /// - public Guid Id => new("61712F04-066C-44D5-A2A0-1E44C66B33F0"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 512) - return false; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - if(partition.Start + sbSize >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - Superblock unicosSb = Marshal.ByteArrayToStructureBigEndian(sector); - - AaruConsole.DebugWriteLine("UNICOS plugin", "magic = 0x{0:X16} (expected 0x{1:X16})", unicosSb.s_magic, - UNICOS_MAGIC); - - return unicosSb.s_magic == UNICOS_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - if(imagePlugin.Info.SectorSize < 512) - return; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < Marshal.SizeOf()) - return; - - Superblock unicosSb = Marshal.ByteArrayToStructureBigEndian(sector); - - if(unicosSb.s_magic != UNICOS_MAGIC) - return; - - var sb = new StringBuilder(); - - sb.AppendLine("UNICOS filesystem"); - - if(unicosSb.s_secure == UNICOS_SECURE) - sb.AppendLine("Volume is secure"); - - sb.AppendFormat("Volume contains {0} partitions", unicosSb.s_npart).AppendLine(); - sb.AppendFormat("{0} bytes per sector", unicosSb.s_iounit).AppendLine(); - sb.AppendLine("4096 bytes per block"); - sb.AppendFormat("{0} data blocks in volume", unicosSb.s_fsize).AppendLine(); - sb.AppendFormat("Root resides on inode {0}", unicosSb.s_root).AppendLine(); - sb.AppendFormat("{0} inodes in volume", unicosSb.s_isize).AppendLine(); - sb.AppendFormat("Volume last updated on {0}", DateHandlers.UnixToDateTime(unicosSb.s_time)).AppendLine(); - - if(unicosSb.s_error > 0) - sb.AppendFormat("Volume is dirty, error code = 0x{0:X16}", unicosSb.s_error).AppendLine(); - - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(unicosSb.s_fname, Encoding)).AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Type = "UNICOS filesystem", - ClusterSize = 4096, - Clusters = (ulong)unicosSb.s_fsize, - VolumeName = StringHandlers.CToString(unicosSb.s_fname, Encoding), - ModificationDate = DateHandlers.UnixToDateTime(unicosSb.s_time), - ModificationDateSpecified = true - }; - - XmlFsType.Dirty |= unicosSb.s_error > 0; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "InconsistentNaming")] - readonly struct nc1ireg_sb - { - public readonly ushort i_unused; /* reserved */ - public readonly ushort i_nblk; /* number of blocks */ - public readonly uint i_sblk; /* start block number */ - } - - [StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "InconsistentNaming")] + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [SuppressMessage("ReSharper", "InconsistentNaming")] readonly struct nc1fdev_sb { public readonly long fd_name; /* Physical device name */ @@ -183,8 +56,26 @@ public sealed class UNICOS : IFilesystem public readonly nc1ireg_sb[] fd_ireg; /* Inode regions */ } - [StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "InconsistentNaming"), - SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] +#endregion + +#region Nested type: nc1ireg_sb + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [SuppressMessage("ReSharper", "InconsistentNaming")] + readonly struct nc1ireg_sb + { + public readonly ushort i_unused; /* reserved */ + public readonly ushort i_nblk; /* number of blocks */ + public readonly uint i_sblk; /* start block number */ + } + +#endregion + +#region Nested type: Superblock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [SuppressMessage("ReSharper", "InconsistentNaming")] + [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] readonly struct Superblock { public readonly ulong s_magic; /* magic number to indicate file system type */ @@ -246,4 +137,6 @@ public sealed class UNICOS : IFilesystem [MarshalAs(UnmanagedType.ByValArray, SizeConst = 91)] public readonly long[] s_fill; /* reserved */ } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/UNICOS/UNICOS.cs b/Aaru.Filesystems/UNICOS/UNICOS.cs new file mode 100644 index 000000000..a92ba47d9 --- /dev/null +++ b/Aaru.Filesystems/UNICOS/UNICOS.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : UNICOS.cs +// Author(s) : Natalia Portillo +// +// Component : UNICOS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +// UNICOS is ILP64 so let's think everything is 64-bit + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection for the Cray UNICOS filesystem +public sealed partial class UNICOS : IFilesystem +{ + const string MODULE_NAME = "UNICOS plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.UNICOS_Name; + + /// + public Guid Id => new("61712F04-066C-44D5-A2A0-1E44C66B33F0"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/UNIXBFS.cs b/Aaru.Filesystems/UNIXBFS.cs deleted file mode 100644 index 815a52e57..000000000 --- a/Aaru.Filesystems/UNIXBFS.cs +++ /dev/null @@ -1,160 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : UNIXBFS.cs -// Author(s) : Natalia Portillo -// -// Component : UnixWare boot filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the UnixWare boot filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; - -// Information from the Linux kernel -/// -/// Implements detection of the UNIX boot filesystem -public sealed class BFS : IFilesystem -{ - const uint BFS_MAGIC = 0x1BADFACE; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "UNIX Boot filesystem"; - /// - public Guid Id => new("1E6E0DA6-F7E4-494C-80C6-CB5929E96155"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(2 + partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] tmp); - - if(errno != ErrorNumber.NoError) - return false; - - var magic = BitConverter.ToUInt32(tmp, 0); - - return magic == BFS_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - var sb = new StringBuilder(); - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bfsSbSector); - - if(errno != ErrorNumber.NoError) - return; - - var sbStrings = new byte[6]; - - var bfsSb = new SuperBlock - { - s_magic = BitConverter.ToUInt32(bfsSbSector, 0x00), - s_start = BitConverter.ToUInt32(bfsSbSector, 0x04), - s_end = BitConverter.ToUInt32(bfsSbSector, 0x08), - s_from = BitConverter.ToUInt32(bfsSbSector, 0x0C), - s_to = BitConverter.ToUInt32(bfsSbSector, 0x10), - s_bfrom = BitConverter.ToInt32(bfsSbSector, 0x14), - s_bto = BitConverter.ToInt32(bfsSbSector, 0x18) - }; - - Array.Copy(bfsSbSector, 0x1C, sbStrings, 0, 6); - bfsSb.s_fsname = StringHandlers.CToString(sbStrings, Encoding); - Array.Copy(bfsSbSector, 0x22, sbStrings, 0, 6); - bfsSb.s_volume = StringHandlers.CToString(sbStrings, Encoding); - - AaruConsole.DebugWriteLine("BFS plugin", "bfs_sb.s_magic: 0x{0:X8}", bfsSb.s_magic); - AaruConsole.DebugWriteLine("BFS plugin", "bfs_sb.s_start: 0x{0:X8}", bfsSb.s_start); - AaruConsole.DebugWriteLine("BFS plugin", "bfs_sb.s_end: 0x{0:X8}", bfsSb.s_end); - AaruConsole.DebugWriteLine("BFS plugin", "bfs_sb.s_from: 0x{0:X8}", bfsSb.s_from); - AaruConsole.DebugWriteLine("BFS plugin", "bfs_sb.s_to: 0x{0:X8}", bfsSb.s_to); - AaruConsole.DebugWriteLine("BFS plugin", "bfs_sb.s_bfrom: 0x{0:X8}", bfsSb.s_bfrom); - AaruConsole.DebugWriteLine("BFS plugin", "bfs_sb.s_bto: 0x{0:X8}", bfsSb.s_bto); - AaruConsole.DebugWriteLine("BFS plugin", "bfs_sb.s_fsname: 0x{0}", bfsSb.s_fsname); - AaruConsole.DebugWriteLine("BFS plugin", "bfs_sb.s_volume: 0x{0}", bfsSb.s_volume); - - sb.AppendLine("UNIX Boot filesystem"); - - sb.AppendFormat("Volume goes from byte {0} to byte {1}, for {2} bytes", bfsSb.s_start, bfsSb.s_end, - bfsSb.s_end - bfsSb.s_start).AppendLine(); - - sb.AppendFormat("Filesystem name: {0}", bfsSb.s_fsname).AppendLine(); - sb.AppendFormat("Volume name: {0}", bfsSb.s_volume).AppendLine(); - - XmlFsType = new FileSystemType - { - Type = "BFS", - VolumeName = bfsSb.s_volume, - ClusterSize = imagePlugin.Info.SectorSize, - Clusters = partition.End - partition.Start + 1 - }; - - information = sb.ToString(); - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct SuperBlock - { - /// 0x00, 0x1BADFACE - public uint s_magic; - /// 0x04, start in bytes of volume - public uint s_start; - /// 0x08, end in bytes of volume - public uint s_end; - /// 0x0C, unknown :p - public uint s_from; - /// 0x10, unknown :p - public uint s_to; - /// 0x14, unknown :p - public int s_bfrom; - /// 0x18, unknown :p - public int s_bto; - /// 0x1C, 6 bytes, filesystem name - public string s_fsname; - /// 0x22, 6 bytes, volume name - public string s_volume; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/UNIXBFS/Consts.cs b/Aaru.Filesystems/UNIXBFS/Consts.cs new file mode 100644 index 000000000..c9c8c6f9b --- /dev/null +++ b/Aaru.Filesystems/UNIXBFS/Consts.cs @@ -0,0 +1,39 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : UnixWare boot filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the UNIX boot filesystem +public sealed partial class BFS +{ + const uint BFS_MAGIC = 0x1BADFACE; + + const string FS_TYPE = "bfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/UNIXBFS/Info.cs b/Aaru.Filesystems/UNIXBFS/Info.cs new file mode 100644 index 000000000..98298e2e5 --- /dev/null +++ b/Aaru.Filesystems/UNIXBFS/Info.cs @@ -0,0 +1,125 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : UnixWare boot filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the UNIX boot filesystem +public sealed partial class BFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(2 + partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] tmp); + + if(errno != ErrorNumber.NoError) return false; + + var magic = BitConverter.ToUInt32(tmp, 0); + + return magic == BFS_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] bfsSbSector); + + if(errno != ErrorNumber.NoError) return; + + var sbStrings = new byte[6]; + + var bfsSb = new SuperBlock + { + s_magic = BitConverter.ToUInt32(bfsSbSector, 0x00), + s_start = BitConverter.ToUInt32(bfsSbSector, 0x04), + s_end = BitConverter.ToUInt32(bfsSbSector, 0x08), + s_from = BitConverter.ToUInt32(bfsSbSector, 0x0C), + s_to = BitConverter.ToUInt32(bfsSbSector, 0x10), + s_bfrom = BitConverter.ToInt32(bfsSbSector, 0x14), + s_bto = BitConverter.ToInt32(bfsSbSector, 0x18) + }; + + Array.Copy(bfsSbSector, 0x1C, sbStrings, 0, 6); + bfsSb.s_fsname = StringHandlers.CToString(sbStrings, encoding); + Array.Copy(bfsSbSector, 0x22, sbStrings, 0, 6); + bfsSb.s_volume = StringHandlers.CToString(sbStrings, encoding); + + AaruConsole.DebugWriteLine(MODULE_NAME, "bfs_sb.s_magic: 0x{0:X8}", bfsSb.s_magic); + AaruConsole.DebugWriteLine(MODULE_NAME, "bfs_sb.s_start: 0x{0:X8}", bfsSb.s_start); + AaruConsole.DebugWriteLine(MODULE_NAME, "bfs_sb.s_end: 0x{0:X8}", bfsSb.s_end); + AaruConsole.DebugWriteLine(MODULE_NAME, "bfs_sb.s_from: 0x{0:X8}", bfsSb.s_from); + AaruConsole.DebugWriteLine(MODULE_NAME, "bfs_sb.s_to: 0x{0:X8}", bfsSb.s_to); + AaruConsole.DebugWriteLine(MODULE_NAME, "bfs_sb.s_bfrom: 0x{0:X8}", bfsSb.s_bfrom); + AaruConsole.DebugWriteLine(MODULE_NAME, "bfs_sb.s_bto: 0x{0:X8}", bfsSb.s_bto); + AaruConsole.DebugWriteLine(MODULE_NAME, "bfs_sb.s_fsname: 0x{0}", bfsSb.s_fsname); + AaruConsole.DebugWriteLine(MODULE_NAME, "bfs_sb.s_volume: 0x{0}", bfsSb.s_volume); + + sb.AppendLine(Localization.UNIX_Boot_Filesystem); + + sb.AppendFormat(Localization.Volume_goes_from_byte_0_to_byte_1_for_2_bytes, + bfsSb.s_start, + bfsSb.s_end, + bfsSb.s_end - bfsSb.s_start) + .AppendLine(); + + sb.AppendFormat(Localization.Filesystem_name_0, bfsSb.s_fsname).AppendLine(); + sb.AppendFormat(Localization.Volume_name_0, bfsSb.s_volume).AppendLine(); + + metadata = new FileSystem + { + Type = FS_TYPE, + VolumeName = bfsSb.s_volume, + ClusterSize = imagePlugin.Info.SectorSize, + Clusters = partition.End - partition.Start + 1 + }; + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/UNIXBFS/Structs.cs b/Aaru.Filesystems/UNIXBFS/Structs.cs new file mode 100644 index 000000000..2c0969c92 --- /dev/null +++ b/Aaru.Filesystems/UNIXBFS/Structs.cs @@ -0,0 +1,64 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : UnixWare boot filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the UNIX boot filesystem +public sealed partial class BFS +{ +#region Nested type: SuperBlock + + [SuppressMessage("ReSharper", "InconsistentNaming")] + struct SuperBlock + { + /// 0x00, 0x1BADFACE + public uint s_magic; + /// 0x04, start in bytes of volume + public uint s_start; + /// 0x08, end in bytes of volume + public uint s_end; + /// 0x0C, unknown :p + public uint s_from; + /// 0x10, unknown :p + public uint s_to; + /// 0x14, unknown :p + public int s_bfrom; + /// 0x18, unknown :p + public int s_bto; + /// 0x1C, 6 bytes, filesystem name + public string s_fsname; + /// 0x22, 6 bytes, volume name + public string s_volume; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/UNIXBFS/UNIXBFS.cs b/Aaru.Filesystems/UNIXBFS/UNIXBFS.cs new file mode 100644 index 000000000..57e0ef9d8 --- /dev/null +++ b/Aaru.Filesystems/UNIXBFS/UNIXBFS.cs @@ -0,0 +1,53 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : UNIXBFS.cs +// Author(s) : Natalia Portillo +// +// Component : UnixWare boot filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the UNIX boot filesystem +public sealed partial class BFS : IFilesystem +{ + const string MODULE_NAME = "BFS plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.BFS_Name; + + /// + public Guid Id => new("1E6E0DA6-F7E4-494C-80C6-CB5929E96155"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/VMfs.cs b/Aaru.Filesystems/VMfs.cs deleted file mode 100644 index 8943a0d49..000000000 --- a/Aaru.Filesystems/VMfs.cs +++ /dev/null @@ -1,167 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : VMfs.cs -// Author(s) : Natalia Portillo -// -// Component : VMware file system plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the VMware file system and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of the VMware filesystem -[SuppressMessage("ReSharper", "UnusedType.Local"), SuppressMessage("ReSharper", "IdentifierTypo"), - SuppressMessage("ReSharper", "UnusedMember.Local")] -public sealed class VMfs : IFilesystem -{ - /// Identifier for VMfs - const uint VMFS_MAGIC = 0xC001D00D; - const uint VMFS_BASE = 0x00100000; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "VMware filesystem"; - /// - public Guid Id => new("EE52BDB8-B49C-4122-A3DA-AD21CBE79843"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(partition.Start >= partition.End) - return false; - - ulong vmfsSuperOff = VMFS_BASE / imagePlugin.Info.SectorSize; - - if(partition.Start + vmfsSuperOff > partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start + vmfsSuperOff, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - var magic = BitConverter.ToUInt32(sector, 0x00); - - return magic == VMFS_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.UTF8; - information = ""; - ulong vmfsSuperOff = VMFS_BASE / imagePlugin.Info.SectorSize; - ErrorNumber errno = imagePlugin.ReadSector(partition.Start + vmfsSuperOff, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - VolumeInfo volInfo = Marshal.ByteArrayToStructureLittleEndian(sector); - - var sbInformation = new StringBuilder(); - - sbInformation.AppendLine("VMware file system"); - - var ctimeSecs = (uint)(volInfo.ctime / 1000000); - var ctimeNanoSecs = (uint)(volInfo.ctime % 1000000); - var mtimeSecs = (uint)(volInfo.mtime / 1000000); - var mtimeNanoSecs = (uint)(volInfo.mtime % 1000000); - - sbInformation.AppendFormat("Volume version {0}", volInfo.version).AppendLine(); - - sbInformation.AppendFormat("Volume name {0}", StringHandlers.CToString(volInfo.name, Encoding)).AppendLine(); - - sbInformation.AppendFormat("Volume size {0} bytes", volInfo.size * 256).AppendLine(); - sbInformation.AppendFormat("Volume UUID {0}", volInfo.uuid).AppendLine(); - - sbInformation. - AppendFormat("Volume created on {0}", DateHandlers.UnixUnsignedToDateTime(ctimeSecs, ctimeNanoSecs)). - AppendLine(); - - sbInformation.AppendFormat("Volume last modified on {0}", - DateHandlers.UnixUnsignedToDateTime(mtimeSecs, mtimeNanoSecs)).AppendLine(); - - information = sbInformation.ToString(); - - XmlFsType = new FileSystemType - { - Type = "VMware file system", - CreationDate = DateHandlers.UnixUnsignedToDateTime(ctimeSecs, ctimeNanoSecs), - CreationDateSpecified = true, - ModificationDate = DateHandlers.UnixUnsignedToDateTime(mtimeSecs, mtimeNanoSecs), - ModificationDateSpecified = true, - Clusters = volInfo.size * 256 / imagePlugin.Info.SectorSize, - ClusterSize = imagePlugin.Info.SectorSize, - VolumeSerial = volInfo.uuid.ToString() - }; - } - - [Flags] - enum Flags : byte - { - RecyledFolder = 64, - CaseSensitive = 128 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct VolumeInfo - { - public readonly uint magic; - public readonly uint version; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public readonly byte[] unknown1; - public readonly byte lun; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] unknown2; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] - public readonly byte[] name; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 49)] - public readonly byte[] unknown3; - public readonly uint size; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)] - public readonly byte[] unknown4; - public readonly Guid uuid; - public readonly ulong ctime; - public readonly ulong mtime; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/VMfs/Consts.cs b/Aaru.Filesystems/VMfs/Consts.cs new file mode 100644 index 000000000..a4761461a --- /dev/null +++ b/Aaru.Filesystems/VMfs/Consts.cs @@ -0,0 +1,43 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : VMware file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the VMware filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "IdentifierTypo")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class VMfs +{ + /// Identifier for VMfs + const uint VMFS_MAGIC = 0xC001D00D; + const uint VMFS_BASE = 0x00100000; +} \ No newline at end of file diff --git a/Aaru.Filesystems/VMfs/Info.cs b/Aaru.Filesystems/VMfs/Info.cs new file mode 100644 index 000000000..a9cbe78f1 --- /dev/null +++ b/Aaru.Filesystems/VMfs/Info.cs @@ -0,0 +1,122 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : VMware file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the VMware filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "IdentifierTypo")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class VMfs +{ + const string FS_TYPE = "vmfs"; + +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(partition.Start >= partition.End) return false; + + ulong vmfsSuperOff = VMFS_BASE / imagePlugin.Info.SectorSize; + + if(partition.Start + vmfsSuperOff > partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start + vmfsSuperOff, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + var magic = BitConverter.ToUInt32(sector, 0x00); + + return magic == VMFS_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.UTF8; + information = ""; + metadata = new FileSystem(); + ulong vmfsSuperOff = VMFS_BASE / imagePlugin.Info.SectorSize; + ErrorNumber errno = imagePlugin.ReadSector(partition.Start + vmfsSuperOff, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + VolumeInfo volInfo = Marshal.ByteArrayToStructureLittleEndian(sector); + + var sbInformation = new StringBuilder(); + + sbInformation.AppendLine(Localization.VMware_file_system); + + var ctimeSecs = (uint)(volInfo.ctime / 1000000); + var ctimeNanoSecs = (uint)(volInfo.ctime % 1000000); + var mtimeSecs = (uint)(volInfo.mtime / 1000000); + var mtimeNanoSecs = (uint)(volInfo.mtime % 1000000); + + sbInformation.AppendFormat(Localization.Volume_version_0, volInfo.version).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(volInfo.name, encoding)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_size_0_bytes, volInfo.size * 256).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_UUID_0, volInfo.uuid).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_created_on_0, + DateHandlers.UnixUnsignedToDateTime(ctimeSecs, ctimeNanoSecs)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_last_modified_on_0, + DateHandlers.UnixUnsignedToDateTime(mtimeSecs, mtimeNanoSecs)) + .AppendLine(); + + information = sbInformation.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + CreationDate = DateHandlers.UnixUnsignedToDateTime(ctimeSecs, ctimeNanoSecs), + ModificationDate = DateHandlers.UnixUnsignedToDateTime(mtimeSecs, mtimeNanoSecs), + Clusters = volInfo.size * 256 / imagePlugin.Info.SectorSize, + ClusterSize = imagePlugin.Info.SectorSize, + VolumeSerial = volInfo.uuid.ToString() + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/VMfs/Structs.cs b/Aaru.Filesystems/VMfs/Structs.cs new file mode 100644 index 000000000..f7fe7f2d2 --- /dev/null +++ b/Aaru.Filesystems/VMfs/Structs.cs @@ -0,0 +1,67 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : VMware file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the VMware filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "IdentifierTypo")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class VMfs +{ +#region Nested type: VolumeInfo + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct VolumeInfo + { + public readonly uint magic; + public readonly uint version; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public readonly byte[] unknown1; + public readonly byte lun; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] unknown2; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] + public readonly byte[] name; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 49)] + public readonly byte[] unknown3; + public readonly uint size; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)] + public readonly byte[] unknown4; + public readonly Guid uuid; + public readonly ulong ctime; + public readonly ulong mtime; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/VMfs/VMfs.cs b/Aaru.Filesystems/VMfs/VMfs.cs new file mode 100644 index 000000000..01dc4e0d7 --- /dev/null +++ b/Aaru.Filesystems/VMfs/VMfs.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : VMfs.cs +// Author(s) : Natalia Portillo +// +// Component : VMware file system plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the VMware filesystem +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "IdentifierTypo")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class VMfs : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.VMfs_Name; + + /// + public Guid Id => new("EE52BDB8-B49C-4122-A3DA-AD21CBE79843"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/VxFS/Consts.cs b/Aaru.Filesystems/VxFS/Consts.cs new file mode 100644 index 000000000..6be66cf10 --- /dev/null +++ b/Aaru.Filesystems/VxFS/Consts.cs @@ -0,0 +1,40 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Veritas File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Veritas filesystem +public sealed partial class VxFS +{ + /// Identifier for VxFS + const uint VXFS_MAGIC = 0xA501FCF5; + const uint VXFS_BASE = 0x400; + + const string FS_TYPE = "vxfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/VxFS/Info.cs b/Aaru.Filesystems/VxFS/Info.cs new file mode 100644 index 000000000..e1fdce973 --- /dev/null +++ b/Aaru.Filesystems/VxFS/Info.cs @@ -0,0 +1,116 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Veritas File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Veritas filesystem +public sealed partial class VxFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + ulong vmfsSuperOff = VXFS_BASE / imagePlugin.Info.SectorSize; + + if(partition.Start + vmfsSuperOff >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(partition.Start + vmfsSuperOff, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + var magic = BitConverter.ToUInt32(sector, 0x00); + + return magic == VXFS_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.UTF8; + information = ""; + metadata = new FileSystem(); + ulong vmfsSuperOff = VXFS_BASE / imagePlugin.Info.SectorSize; + ErrorNumber errno = imagePlugin.ReadSector(partition.Start + vmfsSuperOff, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + SuperBlock vxSb = Marshal.ByteArrayToStructureLittleEndian(sector); + + var sbInformation = new StringBuilder(); + + sbInformation.AppendLine(Localization.Veritas_file_system); + + sbInformation.AppendFormat(Localization.Volume_version_0, vxSb.vs_version).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(vxSb.vs_fname, encoding)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_has_0_blocks_of_1_bytes_each, vxSb.vs_bsize, vxSb.vs_size) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_has_0_inodes_per_block, vxSb.vs_inopb).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_free_inodes, vxSb.vs_ifree).AppendLine(); + sbInformation.AppendFormat(Localization.Volume_has_0_free_blocks, vxSb.vs_free).AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_created_on_0, + DateHandlers.UnixUnsignedToDateTime(vxSb.vs_ctime, vxSb.vs_cutime)) + .AppendLine(); + + sbInformation.AppendFormat(Localization.Volume_last_modified_on_0, + DateHandlers.UnixUnsignedToDateTime(vxSb.vs_wtime, vxSb.vs_wutime)) + .AppendLine(); + + if(vxSb.vs_clean != 0) sbInformation.AppendLine(Localization.Volume_is_dirty); + + information = sbInformation.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + CreationDate = DateHandlers.UnixUnsignedToDateTime(vxSb.vs_ctime, vxSb.vs_cutime), + ModificationDate = DateHandlers.UnixUnsignedToDateTime(vxSb.vs_wtime, vxSb.vs_wutime), + Clusters = (ulong)vxSb.vs_size, + ClusterSize = (uint)vxSb.vs_bsize, + Dirty = vxSb.vs_clean != 0, + FreeClusters = (ulong)vxSb.vs_free + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/VxFS.cs b/Aaru.Filesystems/VxFS/Structs.cs similarity index 66% rename from Aaru.Filesystems/VxFS.cs rename to Aaru.Filesystems/VxFS/Structs.cs index 0fc6c7e26..b83730093 100644 --- a/Aaru.Filesystems/VxFS.cs +++ b/Aaru.Filesystems/VxFS/Structs.cs @@ -2,15 +2,11 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : VxFS.cs +// Filename : Structs.cs // Author(s) : Natalia Portillo // // Component : Veritas File System plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Veritas file system and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,110 +23,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using System.Runtime.InteropServices; + namespace Aaru.Filesystems; -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - /// /// Implements detection of the Veritas filesystem -public sealed class VxFS : IFilesystem +public sealed partial class VxFS { - /// Identifier for VxFS - const uint VXFS_MAGIC = 0xA501FCF5; - const uint VXFS_BASE = 0x400; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Veritas filesystem"; - /// - public Guid Id => new("EC372605-7687-453C-8BEA-7E0DFF79CB03"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - ulong vmfsSuperOff = VXFS_BASE / imagePlugin.Info.SectorSize; - - if(partition.Start + vmfsSuperOff >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(partition.Start + vmfsSuperOff, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - var magic = BitConverter.ToUInt32(sector, 0x00); - - return magic == VXFS_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.UTF8; - information = ""; - ulong vmfsSuperOff = VXFS_BASE / imagePlugin.Info.SectorSize; - ErrorNumber errno = imagePlugin.ReadSector(partition.Start + vmfsSuperOff, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - SuperBlock vxSb = Marshal.ByteArrayToStructureLittleEndian(sector); - - var sbInformation = new StringBuilder(); - - sbInformation.AppendLine("Veritas file system"); - - sbInformation.AppendFormat("Volume version {0}", vxSb.vs_version).AppendLine(); - - sbInformation.AppendFormat("Volume name {0}", StringHandlers.CToString(vxSb.vs_fname, Encoding)).AppendLine(); - - sbInformation.AppendFormat("Volume has {0} blocks of {1} bytes each", vxSb.vs_bsize, vxSb.vs_size).AppendLine(); - - sbInformation.AppendFormat("Volume has {0} inodes per block", vxSb.vs_inopb).AppendLine(); - sbInformation.AppendFormat("Volume has {0} free inodes", vxSb.vs_ifree).AppendLine(); - sbInformation.AppendFormat("Volume has {0} free blocks", vxSb.vs_free).AppendLine(); - - sbInformation.AppendFormat("Volume created on {0}", - DateHandlers.UnixUnsignedToDateTime(vxSb.vs_ctime, vxSb.vs_cutime)).AppendLine(); - - sbInformation.AppendFormat("Volume last modified on {0}", - DateHandlers.UnixUnsignedToDateTime(vxSb.vs_wtime, vxSb.vs_wutime)).AppendLine(); - - if(vxSb.vs_clean != 0) - sbInformation.AppendLine("Volume is dirty"); - - information = sbInformation.ToString(); - - XmlFsType = new FileSystemType - { - Type = "Veritas file system", - CreationDate = DateHandlers.UnixUnsignedToDateTime(vxSb.vs_ctime, vxSb.vs_cutime), - CreationDateSpecified = true, - ModificationDate = DateHandlers.UnixUnsignedToDateTime(vxSb.vs_wtime, vxSb.vs_wutime), - ModificationDateSpecified = true, - Clusters = (ulong)vxSb.vs_size, - ClusterSize = (uint)vxSb.vs_bsize, - Dirty = vxSb.vs_clean != 0, - FreeClusters = (ulong)vxSb.vs_free, - FreeClustersSpecified = true - }; - } +#region Nested type: SuperBlock [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct SuperBlock @@ -278,4 +182,6 @@ public sealed class VxFS : IFilesystem /// checksum of V2 RO public readonly int vs_checksum2; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filesystems/VxFS/VxFS.cs b/Aaru.Filesystems/VxFS/VxFS.cs new file mode 100644 index 000000000..04e751c09 --- /dev/null +++ b/Aaru.Filesystems/VxFS/VxFS.cs @@ -0,0 +1,50 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : VxFS.cs +// Author(s) : Natalia Portillo +// +// Component : Veritas File System plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of the Veritas filesystem +public sealed partial class VxFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.VxFS_Name; + + /// + public Guid Id => new("EC372605-7687-453C-8BEA-7E0DFF79CB03"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/XFS.cs b/Aaru.Filesystems/XFS.cs deleted file mode 100644 index 06499f26a..000000000 --- a/Aaru.Filesystems/XFS.cs +++ /dev/null @@ -1,306 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : XFS.cs -// Author(s) : Natalia Portillo -// -// Component : XFS filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the XFS filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements detection of SGI's XFS -public sealed class XFS : IFilesystem -{ - const uint XFS_MAGIC = 0x58465342; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "XFS Filesystem Plugin"; - /// - public Guid Id => new("1D8CD8B8-27E6-410F-9973-D16409225FBA"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 512) - return false; - - // Misaligned - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) - { - var sbSize = (uint)((Marshal.SizeOf() + 0x400) / imagePlugin.Info.SectorSize); - - if((Marshal.SizeOf() + 0x400) % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - var sbpiece = new byte[Marshal.SizeOf()]; - - foreach(int location in new[] - { - 0, 0x200, 0x400 - }) - { - Array.Copy(sector, location, sbpiece, 0, Marshal.SizeOf()); - - Superblock xfsSb = Marshal.ByteArrayToStructureBigEndian(sbpiece); - - AaruConsole.DebugWriteLine("XFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8})", location, - xfsSb.magicnum, XFS_MAGIC); - - if(xfsSb.magicnum == XFS_MAGIC) - return true; - } - } - else - foreach(int i in new[] - { - 0, 1, 2 - }) - { - var location = (ulong)i; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - continue; - - if(sector.Length < Marshal.SizeOf()) - return false; - - Superblock xfsSb = Marshal.ByteArrayToStructureBigEndian(sector); - - AaruConsole.DebugWriteLine("XFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8})", location, - xfsSb.magicnum, XFS_MAGIC); - - if(xfsSb.magicnum == XFS_MAGIC) - return true; - } - - return false; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - if(imagePlugin.Info.SectorSize < 512) - return; - - var xfsSb = new Superblock(); - - // Misaligned - if(imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) - { - var sbSize = (uint)((Marshal.SizeOf() + 0x400) / imagePlugin.Info.SectorSize); - - if((Marshal.SizeOf() + 0x400) % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError || - sector.Length < Marshal.SizeOf()) - return; - - var sbpiece = new byte[Marshal.SizeOf()]; - - foreach(int location in new[] - { - 0, 0x200, 0x400 - }) - { - Array.Copy(sector, location, sbpiece, 0, Marshal.SizeOf()); - - xfsSb = Marshal.ByteArrayToStructureBigEndian(sbpiece); - - AaruConsole.DebugWriteLine("XFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8})", location, - xfsSb.magicnum, XFS_MAGIC); - - if(xfsSb.magicnum == XFS_MAGIC) - break; - } - } - else - foreach(int i in new[] - { - 0, 1, 2 - }) - { - var location = (ulong)i; - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError || - sector.Length < Marshal.SizeOf()) - return; - - xfsSb = Marshal.ByteArrayToStructureBigEndian(sector); - - AaruConsole.DebugWriteLine("XFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8})", location, - xfsSb.magicnum, XFS_MAGIC); - - if(xfsSb.magicnum == XFS_MAGIC) - break; - } - - if(xfsSb.magicnum != XFS_MAGIC) - return; - - var sb = new StringBuilder(); - - sb.AppendLine("XFS filesystem"); - sb.AppendFormat("Filesystem version {0}", xfsSb.version & 0xF).AppendLine(); - sb.AppendFormat("{0} bytes per sector", xfsSb.sectsize).AppendLine(); - sb.AppendFormat("{0} bytes per block", xfsSb.blocksize).AppendLine(); - sb.AppendFormat("{0} bytes per inode", xfsSb.inodesize).AppendLine(); - sb.AppendFormat("{0} data blocks in volume, {1} free", xfsSb.dblocks, xfsSb.fdblocks).AppendLine(); - sb.AppendFormat("{0} blocks per allocation group", xfsSb.agblocks).AppendLine(); - sb.AppendFormat("{0} allocation groups in volume", xfsSb.agcount).AppendLine(); - sb.AppendFormat("{0} inodes in volume, {1} free", xfsSb.icount, xfsSb.ifree).AppendLine(); - - if(xfsSb.inprogress > 0) - sb.AppendLine("fsck in progress"); - - sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(xfsSb.fname, Encoding)).AppendLine(); - sb.AppendFormat("Volume UUID: {0}", xfsSb.uuid).AppendLine(); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Type = "XFS filesystem", - ClusterSize = xfsSb.blocksize, - Clusters = xfsSb.dblocks, - FreeClusters = xfsSb.fdblocks, - FreeClustersSpecified = true, - Files = xfsSb.icount - xfsSb.ifree, - FilesSpecified = true, - Dirty = xfsSb.inprogress > 0, - VolumeName = StringHandlers.CToString(xfsSb.fname, Encoding), - VolumeSerial = xfsSb.uuid.ToString() - }; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Superblock - { - public readonly uint magicnum; - public readonly uint blocksize; - public readonly ulong dblocks; - public readonly ulong rblocks; - public readonly ulong rextents; - public readonly Guid uuid; - public readonly ulong logstat; - public readonly ulong rootino; - public readonly ulong rbmino; - public readonly ulong rsumino; - public readonly uint rextsize; - public readonly uint agblocks; - public readonly uint agcount; - public readonly uint rbmblocks; - public readonly uint logblocks; - public readonly ushort version; - public readonly ushort sectsize; - public readonly ushort inodesize; - public readonly ushort inopblock; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public readonly byte[] fname; - public readonly byte blocklog; - public readonly byte sectlog; - public readonly byte inodelog; - public readonly byte inopblog; - public readonly byte agblklog; - public readonly byte rextslog; - public readonly byte inprogress; - public readonly byte imax_pct; - public readonly ulong icount; - public readonly ulong ifree; - public readonly ulong fdblocks; - public readonly ulong frextents; - public readonly ulong uquotino; - public readonly ulong gquotino; - public readonly ushort qflags; - public readonly byte flags; - public readonly byte shared_vn; - public readonly ulong inoalignmt; - public readonly ulong unit; - public readonly ulong width; - public readonly byte dirblklog; - public readonly byte logsectlog; - public readonly ushort logsectsize; - public readonly uint logsunit; - public readonly uint features2; - public readonly uint bad_features2; - public readonly uint features_compat; - public readonly uint features_ro_compat; - public readonly uint features_incompat; - public readonly uint features_log_incompat; - - // This field is little-endian while rest of superblock is big-endian - public readonly uint crc; - public readonly uint spino_align; - public readonly ulong pquotino; - public readonly ulong lsn; - public readonly Guid meta_uuid; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/XFS/Consts.cs b/Aaru.Filesystems/XFS/Consts.cs new file mode 100644 index 000000000..4fd62d60f --- /dev/null +++ b/Aaru.Filesystems/XFS/Consts.cs @@ -0,0 +1,38 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : XFS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +/// +/// Implements detection of SGI's XFS +public sealed partial class XFS +{ + const uint XFS_MAGIC = 0x58465342; + + const string FS_TYPE = "xfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/XFS/Info.cs b/Aaru.Filesystems/XFS/Info.cs new file mode 100644 index 000000000..a7d2c3407 --- /dev/null +++ b/Aaru.Filesystems/XFS/Info.cs @@ -0,0 +1,224 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : XFS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of SGI's XFS +public sealed partial class XFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 512) return false; + + // Misaligned + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) + { + var sbSize = (uint)((Marshal.SizeOf() + 0x400) / imagePlugin.Info.SectorSize); + + if((Marshal.SizeOf() + 0x400) % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + var sbpiece = new byte[Marshal.SizeOf()]; + + foreach(int location in new[] + { + 0, 0x200, 0x400 + }) + { + Array.Copy(sector, location, sbpiece, 0, Marshal.SizeOf()); + + Superblock xfsSb = Marshal.ByteArrayToStructureBigEndian(sbpiece); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.magic_at_0_X3_equals_1_expected_2, + location, + xfsSb.magicnum, + XFS_MAGIC); + + if(xfsSb.magicnum == XFS_MAGIC) return true; + } + } + else + { + foreach(int i in new[] + { + 0, 1, 2 + }) + { + var location = (ulong)i; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) continue; + + if(sector.Length < Marshal.SizeOf()) return false; + + Superblock xfsSb = Marshal.ByteArrayToStructureBigEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.magic_at_0_equals_1_expected_2, + location, + xfsSb.magicnum, + XFS_MAGIC); + + if(xfsSb.magicnum == XFS_MAGIC) return true; + } + } + + return false; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize < 512) return; + + var xfsSb = new Superblock(); + + // Misaligned + if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc) + { + var sbSize = (uint)((Marshal.SizeOf() + 0x400) / imagePlugin.Info.SectorSize); + + if((Marshal.SizeOf() + 0x400) % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError || sector.Length < Marshal.SizeOf()) return; + + var sbpiece = new byte[Marshal.SizeOf()]; + + foreach(int location in new[] + { + 0, 0x200, 0x400 + }) + { + Array.Copy(sector, location, sbpiece, 0, Marshal.SizeOf()); + + xfsSb = Marshal.ByteArrayToStructureBigEndian(sbpiece); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.magic_at_0_X3_equals_1_expected_2, + location, + xfsSb.magicnum, + XFS_MAGIC); + + if(xfsSb.magicnum == XFS_MAGIC) break; + } + } + else + { + foreach(int i in new[] + { + 0, 1, 2 + }) + { + var location = (ulong)i; + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start + location, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError || sector.Length < Marshal.SizeOf()) return; + + xfsSb = Marshal.ByteArrayToStructureBigEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, + Localization.magic_at_0_equals_1_expected_2, + location, + xfsSb.magicnum, + XFS_MAGIC); + + if(xfsSb.magicnum == XFS_MAGIC) break; + } + } + + if(xfsSb.magicnum != XFS_MAGIC) return; + + var sb = new StringBuilder(); + + sb.AppendLine(Localization.XFS_filesystem); + sb.AppendFormat(Localization.Filesystem_version_0, xfsSb.version & 0xF).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_sector, xfsSb.sectsize).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_block, xfsSb.blocksize).AppendLine(); + sb.AppendFormat(Localization._0_bytes_per_inode, xfsSb.inodesize).AppendLine(); + sb.AppendFormat(Localization._0_data_blocks_in_volume_1_free, xfsSb.dblocks, xfsSb.fdblocks).AppendLine(); + sb.AppendFormat(Localization._0_blocks_per_allocation_group, xfsSb.agblocks).AppendLine(); + sb.AppendFormat(Localization._0_allocation_groups_in_volume, xfsSb.agcount).AppendLine(); + sb.AppendFormat(Localization._0_inodes_in_volume_1_free, xfsSb.icount, xfsSb.ifree).AppendLine(); + + if(xfsSb.inprogress > 0) sb.AppendLine(Localization.fsck_in_progress); + + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(xfsSb.fname, encoding)).AppendLine(); + sb.AppendFormat(Localization.Volume_UUID_0, xfsSb.uuid).AppendLine(); + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE, + ClusterSize = xfsSb.blocksize, + Clusters = xfsSb.dblocks, + FreeClusters = xfsSb.fdblocks, + Files = xfsSb.icount - xfsSb.ifree, + Dirty = xfsSb.inprogress > 0, + VolumeName = StringHandlers.CToString(xfsSb.fname, encoding), + VolumeSerial = xfsSb.uuid.ToString() + }; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/XFS/Structs.cs b/Aaru.Filesystems/XFS/Structs.cs new file mode 100644 index 000000000..b7b9d3064 --- /dev/null +++ b/Aaru.Filesystems/XFS/Structs.cs @@ -0,0 +1,104 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : XFS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of SGI's XFS +public sealed partial class XFS +{ +#region Nested type: Superblock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Superblock + { + public readonly uint magicnum; + public readonly uint blocksize; + public readonly ulong dblocks; + public readonly ulong rblocks; + public readonly ulong rextents; + public readonly Guid uuid; + public readonly ulong logstat; + public readonly ulong rootino; + public readonly ulong rbmino; + public readonly ulong rsumino; + public readonly uint rextsize; + public readonly uint agblocks; + public readonly uint agcount; + public readonly uint rbmblocks; + public readonly uint logblocks; + public readonly ushort version; + public readonly ushort sectsize; + public readonly ushort inodesize; + public readonly ushort inopblock; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public readonly byte[] fname; + public readonly byte blocklog; + public readonly byte sectlog; + public readonly byte inodelog; + public readonly byte inopblog; + public readonly byte agblklog; + public readonly byte rextslog; + public readonly byte inprogress; + public readonly byte imax_pct; + public readonly ulong icount; + public readonly ulong ifree; + public readonly ulong fdblocks; + public readonly ulong frextents; + public readonly ulong uquotino; + public readonly ulong gquotino; + public readonly ushort qflags; + public readonly byte flags; + public readonly byte shared_vn; + public readonly ulong inoalignmt; + public readonly ulong unit; + public readonly ulong width; + public readonly byte dirblklog; + public readonly byte logsectlog; + public readonly ushort logsectsize; + public readonly uint logsunit; + public readonly uint features2; + public readonly uint bad_features2; + public readonly uint features_compat; + public readonly uint features_ro_compat; + public readonly uint features_incompat; + public readonly uint features_log_incompat; + + // This field is little-endian while rest of superblock is big-endian + public readonly uint crc; + public readonly uint spino_align; + public readonly ulong pquotino; + public readonly ulong lsn; + public readonly Guid meta_uuid; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/XFS/XFS.cs b/Aaru.Filesystems/XFS/XFS.cs new file mode 100644 index 000000000..e18784aa6 --- /dev/null +++ b/Aaru.Filesystems/XFS/XFS.cs @@ -0,0 +1,52 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : XFS.cs +// Author(s) : Natalia Portillo +// +// Component : XFS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements detection of SGI's XFS +public sealed partial class XFS : IFilesystem +{ + const string MODULE_NAME = "XFS plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.XFS_Name; + + /// + public Guid Id => new("1D8CD8B8-27E6-410F-9973-D16409225FBA"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Xia.cs b/Aaru.Filesystems/Xia.cs deleted file mode 100644 index e927e4181..000000000 --- a/Aaru.Filesystems/Xia.cs +++ /dev/null @@ -1,218 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Xia.cs -// Author(s) : Natalia Portillo -// -// Component : Xia filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Xia filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Information from the Linux kernel -/// -/// Implements detection for the Xia filesystem -[SuppressMessage("ReSharper", "UnusedMember.Local"), SuppressMessage("ReSharper", "UnusedType.Local")] -public sealed class Xia : IFilesystem -{ - const uint XIAFS_SUPER_MAGIC = 0x012FD16D; - const uint XIAFS_ROOT_INO = 1; - const uint XIAFS_BAD_INO = 2; - const int XIAFS_MAX_LINK = 64000; - const int XIAFS_DIR_SIZE = 12; - const int XIAFS_NUM_BLOCK_POINTERS = 10; - const int XIAFS_NAME_LEN = 248; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Xia filesystem"; - /// - public Guid Id => new("169E1DE5-24F2-4EF6-A04D-A4B2CA66DE9D"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - int sbSizeInBytes = Marshal.SizeOf(); - var sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize); - - if(sbSizeInBytes % imagePlugin.Info.SectorSize > 0) - sbSizeInSectors++; - - if(sbSizeInSectors + partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSizeInSectors, out byte[] sbSector); - - if(errno != ErrorNumber.NoError) - return false; - - SuperBlock supblk = Marshal.ByteArrayToStructureLittleEndian(sbSector); - - return supblk.s_magic == XIAFS_SUPER_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - var sb = new StringBuilder(); - - int sbSizeInBytes = Marshal.SizeOf(); - var sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize); - - if(sbSizeInBytes % imagePlugin.Info.SectorSize > 0) - sbSizeInSectors++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSizeInSectors, out byte[] sbSector); - - if(errno != ErrorNumber.NoError) - return; - - SuperBlock supblk = Marshal.ByteArrayToStructureLittleEndian(sbSector); - - sb.AppendFormat("{0} bytes per zone", supblk.s_zone_size).AppendLine(); - - sb.AppendFormat("{0} zones in volume ({1} bytes)", supblk.s_nzones, supblk.s_nzones * supblk.s_zone_size). - AppendLine(); - - sb.AppendFormat("{0} inodes", supblk.s_ninodes).AppendLine(); - - sb.AppendFormat("{0} data zones ({1} bytes)", supblk.s_ndatazones, supblk.s_ndatazones * supblk.s_zone_size). - AppendLine(); - - sb.AppendFormat("{0} imap zones ({1} bytes)", supblk.s_imap_zones, supblk.s_imap_zones * supblk.s_zone_size). - AppendLine(); - - sb.AppendFormat("{0} zmap zones ({1} bytes)", supblk.s_zmap_zones, supblk.s_zmap_zones * supblk.s_zone_size). - AppendLine(); - - sb.AppendFormat("First data zone: {0}", supblk.s_firstdatazone).AppendLine(); - - sb.AppendFormat("Maximum filesize is {0} bytes ({1} MiB)", supblk.s_max_size, supblk.s_max_size / 1048576). - AppendLine(); - - sb.AppendFormat("{0} zones reserved for kernel images ({1} bytes)", supblk.s_kernzones, - supblk.s_kernzones * supblk.s_zone_size).AppendLine(); - - sb.AppendFormat("First kernel zone: {0}", supblk.s_firstkernzone).AppendLine(); - - XmlFsType = new FileSystemType - { - Bootable = !ArrayHelpers.ArrayIsNullOrEmpty(supblk.s_boot_segment), - Clusters = supblk.s_nzones, - ClusterSize = supblk.s_zone_size, - Type = "Xia filesystem" - }; - - information = sb.ToString(); - } - - /// Xia superblock - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct SuperBlock - { - /// 1st sector reserved for boot - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] - public readonly byte[] s_boot_segment; - /// the name says it - public readonly uint s_zone_size; - /// volume size, zone aligned - public readonly uint s_nzones; - /// # of inodes - public readonly uint s_ninodes; - /// # of data zones - public readonly uint s_ndatazones; - /// # of imap zones - public readonly uint s_imap_zones; - /// # of zmap zones - public readonly uint s_zmap_zones; - /// first data zone - public readonly uint s_firstdatazone; - /// z size = 1KB << z shift - public readonly uint s_zone_shift; - /// max size of a single file - public readonly uint s_max_size; - /// reserved - public readonly uint s_reserved0; - /// reserved - public readonly uint s_reserved1; - /// reserved - public readonly uint s_reserved2; - /// reserved - public readonly uint s_reserved3; - /// first kernel zone - public readonly uint s_firstkernzone; - /// kernel size in zones - public readonly uint s_kernzones; - /// magic number for xiafs - public readonly uint s_magic; - } - - /// Xia directory entry - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DirectoryEntry - { - public readonly uint d_ino; - public readonly ushort d_rec_len; - public readonly byte d_name_len; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = XIAFS_NAME_LEN + 1)] - public readonly byte[] d_name; - } - - /// Xia inode - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Inode - { - public readonly ushort i_mode; - public readonly ushort i_nlinks; - public readonly ushort i_uid; - public readonly ushort i_gid; - public readonly uint i_size; - public readonly uint i_ctime; - public readonly uint i_atime; - public readonly uint i_mtime; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = XIAFS_NUM_BLOCK_POINTERS)] - public readonly uint[] i_zone; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/Xia/Consts.cs b/Aaru.Filesystems/Xia/Consts.cs new file mode 100644 index 000000000..c3dfc44fb --- /dev/null +++ b/Aaru.Filesystems/Xia/Consts.cs @@ -0,0 +1,47 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Xia filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection for the Xia filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class Xia +{ + const uint XIAFS_SUPER_MAGIC = 0x012FD16D; + const uint XIAFS_ROOT_INO = 1; + const uint XIAFS_BAD_INO = 2; + const int XIAFS_MAX_LINK = 64000; + const int XIAFS_DIR_SIZE = 12; + const int XIAFS_NUM_BLOCK_POINTERS = 10; + const int XIAFS_NAME_LEN = 248; +} \ No newline at end of file diff --git a/Aaru.Filesystems/Xia/Info.cs b/Aaru.Filesystems/Xia/Info.cs new file mode 100644 index 000000000..c6e14c659 --- /dev/null +++ b/Aaru.Filesystems/Xia/Info.cs @@ -0,0 +1,135 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Xia filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection for the Xia filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class Xia +{ + const string FS_TYPE = "xia"; + +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + int sbSizeInBytes = Marshal.SizeOf(); + var sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize); + + if(sbSizeInBytes % imagePlugin.Info.SectorSize > 0) sbSizeInSectors++; + + if(sbSizeInSectors + partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSizeInSectors, out byte[] sbSector); + + if(errno != ErrorNumber.NoError) return false; + + SuperBlock supblk = Marshal.ByteArrayToStructureLittleEndian(sbSector); + + return supblk.s_magic == XIAFS_SUPER_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + int sbSizeInBytes = Marshal.SizeOf(); + var sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize); + + if(sbSizeInBytes % imagePlugin.Info.SectorSize > 0) sbSizeInSectors++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSizeInSectors, out byte[] sbSector); + + if(errno != ErrorNumber.NoError) return; + + SuperBlock supblk = Marshal.ByteArrayToStructureLittleEndian(sbSector); + + sb.AppendFormat(Localization._0_bytes_per_zone, supblk.s_zone_size).AppendLine(); + + sb.AppendFormat(Localization._0_zones_in_volume_1_bytes, supblk.s_nzones, supblk.s_nzones * supblk.s_zone_size) + .AppendLine(); + + sb.AppendFormat(Localization._0_inodes, supblk.s_ninodes).AppendLine(); + + sb.AppendFormat(Localization._0_data_zones_1_bytes, + supblk.s_ndatazones, + supblk.s_ndatazones * supblk.s_zone_size) + .AppendLine(); + + sb.AppendFormat(Localization._0_imap_zones_1_bytes, + supblk.s_imap_zones, + supblk.s_imap_zones * supblk.s_zone_size) + .AppendLine(); + + sb.AppendFormat(Localization._0_zmap_zones_1_bytes, + supblk.s_zmap_zones, + supblk.s_zmap_zones * supblk.s_zone_size) + .AppendLine(); + + sb.AppendFormat(Localization.First_data_zone_0, supblk.s_firstdatazone).AppendLine(); + + sb.AppendFormat(Localization.Maximum_filesize_is_0_bytes_1_MiB, supblk.s_max_size, supblk.s_max_size / 1048576) + .AppendLine(); + + sb.AppendFormat(Localization._0_zones_reserved_for_kernel_images_1_bytes, + supblk.s_kernzones, + supblk.s_kernzones * supblk.s_zone_size) + .AppendLine(); + + sb.AppendFormat(Localization.First_kernel_zone_0, supblk.s_firstkernzone).AppendLine(); + + metadata = new FileSystem + { + Bootable = !ArrayHelpers.ArrayIsNullOrEmpty(supblk.s_boot_segment), + Clusters = supblk.s_nzones, + ClusterSize = supblk.s_zone_size, + Type = FS_TYPE + }; + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Xia/Structs.cs b/Aaru.Filesystems/Xia/Structs.cs new file mode 100644 index 000000000..b4fd20709 --- /dev/null +++ b/Aaru.Filesystems/Xia/Structs.cs @@ -0,0 +1,120 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Xia filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection for the Xia filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class Xia +{ +#region Nested type: DirectoryEntry + + /// Xia directory entry + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DirectoryEntry + { + public readonly uint d_ino; + public readonly ushort d_rec_len; + public readonly byte d_name_len; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = XIAFS_NAME_LEN + 1)] + public readonly byte[] d_name; + } + +#endregion + +#region Nested type: Inode + + /// Xia inode + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Inode + { + public readonly ushort i_mode; + public readonly ushort i_nlinks; + public readonly ushort i_uid; + public readonly ushort i_gid; + public readonly uint i_size; + public readonly uint i_ctime; + public readonly uint i_atime; + public readonly uint i_mtime; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = XIAFS_NUM_BLOCK_POINTERS)] + public readonly uint[] i_zone; + } + +#endregion + +#region Nested type: SuperBlock + + /// Xia superblock + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct SuperBlock + { + /// 1st sector reserved for boot + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] + public readonly byte[] s_boot_segment; + /// the name says it + public readonly uint s_zone_size; + /// volume size, zone aligned + public readonly uint s_nzones; + /// # of inodes + public readonly uint s_ninodes; + /// # of data zones + public readonly uint s_ndatazones; + /// # of imap zones + public readonly uint s_imap_zones; + /// # of zmap zones + public readonly uint s_zmap_zones; + /// first data zone + public readonly uint s_firstdatazone; + /// z size = 1KB << z shift + public readonly uint s_zone_shift; + /// max size of a single file + public readonly uint s_max_size; + /// reserved + public readonly uint s_reserved0; + /// reserved + public readonly uint s_reserved1; + /// reserved + public readonly uint s_reserved2; + /// reserved + public readonly uint s_reserved3; + /// first kernel zone + public readonly uint s_firstkernzone; + /// kernel size in zones + public readonly uint s_kernzones; + /// magic number for xiafs + public readonly uint s_magic; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/Xia/Xia.cs b/Aaru.Filesystems/Xia/Xia.cs new file mode 100644 index 000000000..e0ece0b3f --- /dev/null +++ b/Aaru.Filesystems/Xia/Xia.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Xia.cs +// Author(s) : Natalia Portillo +// +// Component : Xia filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection for the Xia filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +public sealed partial class Xia : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.Xia_Name; + + /// + public Guid Id => new("169E1DE5-24F2-4EF6-A04D-A4B2CA66DE9D"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ZFS/Consts.cs b/Aaru.Filesystems/ZFS/Consts.cs new file mode 100644 index 000000000..fd7845cde --- /dev/null +++ b/Aaru.Filesystems/ZFS/Consts.cs @@ -0,0 +1,74 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : ZFS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/* + * The ZFS on-disk structure is quite undocumented, so this has been checked using several test images and reading the comments and headers (but not the code) + * of ZFS-On-Linux. + * + * The most basic structure, the vdev label, is as follows: + * 8KiB of blank space + * 8KiB reserved for boot code, stored as a ZIO block with magic and checksum + * 112KiB of nvlist, usually encoded using XDR + * 128KiB of copies of the 1KiB uberblock + * + * Two vdev labels, L0 and L1 are stored at the start of the vdev. + * Another two, L2 and L3 are stored at the end. + * + * The nvlist is nothing more than a double linked list of name/value pairs where name is a string and value is an arbitrary type (and can be an array of it). + * On-disk they are stored sequentially (no pointers) and can be encoded in XDR (an old Sun serialization method that stores everything as 4 bytes chunks) or + * natively (that is as the host natively stores that values, for example on Intel an extended float would be 10 bytes (80 bit). + * It can also be encoded little or big endian. + * Because of this variations, ZFS stored a header indicating the used encoding and endianess before the encoded nvlist. + */ +/// +/// Implements detection for the Zettabyte File System (ZFS) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "NotAccessedField.Local")] +public sealed partial class ZFS +{ + const ulong ZEC_MAGIC = 0x0210DA7AB10C7A11; + const ulong ZEC_CIGAM = 0x117A0CB17ADA1002; + + // These parameters define how the nvlist is stored + const byte NVS_LITTLE_ENDIAN = 1; + const byte NVS_BIG_ENDIAN = 0; + const byte NVS_NATIVE = 0; + const byte NVS_XDR = 1; + + const ulong UBERBLOCK_MAGIC = 0x00BAB10C; + + const uint ZFS_MAGIC = 0x58465342; + + const string FS_TYPE = "zfs"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/ZFS/Enums.cs b/Aaru.Filesystems/ZFS/Enums.cs new file mode 100644 index 000000000..307e03784 --- /dev/null +++ b/Aaru.Filesystems/ZFS/Enums.cs @@ -0,0 +1,95 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : ZFS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/* + * The ZFS on-disk structure is quite undocumented, so this has been checked using several test images and reading the comments and headers (but not the code) + * of ZFS-On-Linux. + * + * The most basic structure, the vdev label, is as follows: + * 8KiB of blank space + * 8KiB reserved for boot code, stored as a ZIO block with magic and checksum + * 112KiB of nvlist, usually encoded using XDR + * 128KiB of copies of the 1KiB uberblock + * + * Two vdev labels, L0 and L1 are stored at the start of the vdev. + * Another two, L2 and L3 are stored at the end. + * + * The nvlist is nothing more than a double linked list of name/value pairs where name is a string and value is an arbitrary type (and can be an array of it). + * On-disk they are stored sequentially (no pointers) and can be encoded in XDR (an old Sun serialization method that stores everything as 4 bytes chunks) or + * natively (that is as the host natively stores that values, for example on Intel an extended float would be 10 bytes (80 bit). + * It can also be encoded little or big endian. + * Because of this variations, ZFS stored a header indicating the used encoding and endianess before the encoded nvlist. + */ +/// +/// Implements detection for the Zettabyte File System (ZFS) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "NotAccessedField.Local")] +public sealed partial class ZFS +{ +#region Nested type: NVS_DataTypes + + enum NVS_DataTypes : uint + { + DATA_TYPE_UNKNOWN = 0, + DATA_TYPE_BOOLEAN, + DATA_TYPE_BYTE, + DATA_TYPE_INT16, + DATA_TYPE_UINT16, + DATA_TYPE_INT32, + DATA_TYPE_UINT32, + DATA_TYPE_INT64, + DATA_TYPE_UINT64, + DATA_TYPE_STRING, + DATA_TYPE_BYTE_ARRAY, + DATA_TYPE_INT16_ARRAY, + DATA_TYPE_UINT16_ARRAY, + DATA_TYPE_INT32_ARRAY, + DATA_TYPE_UINT32_ARRAY, + DATA_TYPE_INT64_ARRAY, + DATA_TYPE_UINT64_ARRAY, + DATA_TYPE_STRING_ARRAY, + DATA_TYPE_HRTIME, + DATA_TYPE_NVLIST, + DATA_TYPE_NVLIST_ARRAY, + DATA_TYPE_BOOLEAN_VALUE, + DATA_TYPE_INT8, + DATA_TYPE_UINT8, + DATA_TYPE_BOOLEAN_ARRAY, + DATA_TYPE_INT8_ARRAY, + DATA_TYPE_UINT8_ARRAY, + DATA_TYPE_DOUBLE + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ZFS.cs b/Aaru.Filesystems/ZFS/Helpers.cs similarity index 61% rename from Aaru.Filesystems/ZFS.cs rename to Aaru.Filesystems/ZFS/Helpers.cs index ede2119c7..884f9b52d 100644 --- a/Aaru.Filesystems/ZFS.cs +++ b/Aaru.Filesystems/ZFS/Helpers.cs @@ -2,15 +2,11 @@ // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // -// Filename : ZFS.cs +// Filename : Helpers.cs // Author(s) : Natalia Portillo // // Component : ZFS filesystem plugin. // -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the ZFS filesystem and shows information. -// // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify @@ -27,21 +23,16 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filesystems; - using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; -using Schemas; + +namespace Aaru.Filesystems; /* * The ZFS on-disk structure is quite undocumented, so this has been checked using several test images and reading the comments and headers (but not the code) @@ -64,141 +55,12 @@ using Schemas; */ /// /// Implements detection for the Zettabyte File System (ZFS) -[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "UnusedType.Local"), - SuppressMessage("ReSharper", "UnusedMember.Local"), SuppressMessage("ReSharper", "NotAccessedField.Local")] -public sealed class ZFS : IFilesystem +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "NotAccessedField.Local")] +public sealed partial class ZFS { - const ulong ZEC_MAGIC = 0x0210DA7AB10C7A11; - const ulong ZEC_CIGAM = 0x117A0CB17ADA1002; - - // These parameters define how the nvlist is stored - const byte NVS_LITTLE_ENDIAN = 1; - const byte NVS_BIG_ENDIAN = 0; - const byte NVS_NATIVE = 0; - const byte NVS_XDR = 1; - - const ulong UBERBLOCK_MAGIC = 0x00BAB10C; - - const uint ZFS_MAGIC = 0x58465342; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "ZFS Filesystem Plugin"; - /// - public Guid Id => new("0750014F-A714-4692-A369-E23F6EC3659C"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 512) - return false; - - byte[] sector; - ulong magic; - ErrorNumber errno; - - if(partition.Start + 31 < partition.End) - { - errno = imagePlugin.ReadSector(partition.Start + 31, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - magic = BitConverter.ToUInt64(sector, 0x1D8); - - if(magic is ZEC_MAGIC or ZEC_CIGAM) - return true; - } - - if(partition.Start + 16 >= partition.End) - return false; - - errno = imagePlugin.ReadSector(partition.Start + 16, out sector); - - if(errno != ErrorNumber.NoError) - return false; - - magic = BitConverter.ToUInt64(sector, 0x1D8); - - return magic is ZEC_MAGIC or ZEC_CIGAM; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - // ZFS is always UTF-8 - Encoding = Encoding.UTF8; - information = ""; - ErrorNumber errno; - - if(imagePlugin.Info.SectorSize < 512) - return; - - byte[] sector; - ulong magic; - - ulong nvlistOff = 32; - uint nvlistLen = 114688 / imagePlugin.Info.SectorSize; - - if(partition.Start + 31 < partition.End) - { - errno = imagePlugin.ReadSector(partition.Start + 31, out sector); - - if(errno != ErrorNumber.NoError) - return; - - magic = BitConverter.ToUInt64(sector, 0x1D8); - - if(magic is ZEC_MAGIC or ZEC_CIGAM) - nvlistOff = 32; - } - - if(partition.Start + 16 < partition.End) - { - errno = imagePlugin.ReadSector(partition.Start + 16, out sector); - - if(errno != ErrorNumber.NoError) - return; - - magic = BitConverter.ToUInt64(sector, 0x1D8); - - if(magic is ZEC_MAGIC or ZEC_CIGAM) - nvlistOff = 17; - } - - var sb = new StringBuilder(); - sb.AppendLine("ZFS filesystem"); - - errno = imagePlugin.ReadSectors(partition.Start + nvlistOff, nvlistLen, out byte[] nvlist); - - if(errno != ErrorNumber.NoError) - return; - - sb.AppendLine(!DecodeNvList(nvlist, out Dictionary decodedNvList) ? "Could not decode nvlist" - : PrintNvList(decodedNvList)); - - information = sb.ToString(); - - XmlFsType = new FileSystemType - { - Type = "ZFS filesystem" - }; - - if(decodedNvList.TryGetValue("name", out NVS_Item tmpObj)) - XmlFsType.VolumeName = (string)tmpObj.value; - - if(decodedNvList.TryGetValue("guid", out tmpObj)) - XmlFsType.VolumeSerial = $"{(ulong)tmpObj.value}"; - - if(decodedNvList.TryGetValue("pool_guid", out tmpObj)) - XmlFsType.VolumeSetIdentifier = $"{(ulong)tmpObj.value}"; - } - static bool DecodeNvList(byte[] nvlist, out Dictionary decodedNvList) { var tmp = new byte[nvlist.Length - 4]; @@ -210,16 +72,14 @@ public sealed class ZFS : IFilesystem } // TODO: Decode native nvlist + // ReSharper disable once UnusedParameter.Local static bool DecodeNvList(byte[] nvlist, out Dictionary decodedNvList, bool xdr, bool littleEndian) { decodedNvList = new Dictionary(); - if(nvlist == null || - nvlist.Length < 16) - return false; + if(nvlist == null || nvlist.Length < 16) return false; - if(!xdr) - return false; + if(!xdr) return false; var offset = 8; @@ -231,8 +91,7 @@ public sealed class ZFS : IFilesystem item.encodedSize = BigEndianBitConverter.ToUInt32(nvlist, offset); // Finished - if(item.encodedSize == 0) - break; + if(item.encodedSize == 0) break; offset += 4; item.decodedSize = BigEndianBitConverter.ToUInt32(nvlist, offset); @@ -240,8 +99,7 @@ public sealed class ZFS : IFilesystem var nameLength = BigEndianBitConverter.ToUInt32(nvlist, offset); offset += 4; - if(nameLength % 4 > 0) - nameLength += 4 - nameLength % 4; + if(nameLength % 4 > 0) nameLength += 4 - nameLength % 4; var nameBytes = new byte[nameLength]; Array.Copy(nvlist, offset, nameBytes, 0, nameLength); @@ -295,8 +153,7 @@ public sealed class ZFS : IFilesystem Array.Copy(nvlist, offset, byteArray, 0, item.elements); offset += (int)item.elements; - if(item.elements % 4 > 0) - offset += 4 - (int)(item.elements % 4); + if(item.elements % 4 > 0) offset += 4 - (int)(item.elements % 4); item.value = byteArray; } @@ -433,8 +290,7 @@ public sealed class ZFS : IFilesystem item.value = sbyteArray; - if(sbyteArray.Length % 4 > 0) - offset += 4 - sbyteArray.Length % 4; + if(sbyteArray.Length % 4 > 0) offset += 4 - sbyteArray.Length % 4; } else { @@ -458,8 +314,7 @@ public sealed class ZFS : IFilesystem stringArray[i] = StringHandlers.CToString(strBytes); offset += (int)strLength; - if(strLength % 4 > 0) - offset += 4 - (int)(strLength % 4); + if(strLength % 4 > 0) offset += 4 - (int)(strLength % 4); } item.value = stringArray; @@ -473,8 +328,7 @@ public sealed class ZFS : IFilesystem item.value = StringHandlers.CToString(strBytes); offset += (int)strLength; - if(strLength % 4 > 0) - offset += 4 - (int)(strLength % 4); + if(strLength % 4 > 0) offset += 4 - (int)(strLength % 4); } break; @@ -545,8 +399,7 @@ public sealed class ZFS : IFilesystem break; case NVS_DataTypes.DATA_TYPE_NVLIST: - if(item.elements > 1) - goto default; + if(item.elements > 1) goto default; var subListBytes = new byte[item.encodedSize - (offset - currOff)]; Array.Copy(nvlist, offset, subListBytes, 0, subListBytes.Length); @@ -582,7 +435,7 @@ public sealed class ZFS : IFilesystem { if(item.elements == 0) { - sb.AppendFormat("{0} is not set", item.name).AppendLine(); + sb.AppendFormat(Localization._0_is_not_set, item.name).AppendLine(); continue; } @@ -593,10 +446,12 @@ public sealed class ZFS : IFilesystem case NVS_DataTypes.DATA_TYPE_BOOLEAN_ARRAY: case NVS_DataTypes.DATA_TYPE_BOOLEAN_VALUE: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((bool[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((bool[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (bool)item.value).AppendLine(); + sb.Append($"{item.name} = {(bool)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_BYTE: @@ -604,116 +459,151 @@ public sealed class ZFS : IFilesystem case NVS_DataTypes.DATA_TYPE_UINT8: case NVS_DataTypes.DATA_TYPE_UINT8_ARRAY: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((byte[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((byte[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (byte)item.value).AppendLine(); + sb.Append($"{item.name} = {(byte)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_DOUBLE: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((double[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((double[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (double)item.value).AppendLine(); + sb.Append($"{item.name} = {(double)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_HRTIME: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((DateTime[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((DateTime[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (DateTime)item.value).AppendLine(); + sb.Append($"{item.name} = {(DateTime)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_INT16: case NVS_DataTypes.DATA_TYPE_INT16_ARRAY: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((short[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((short[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (short)item.value).AppendLine(); + sb.Append($"{item.name} = {(short)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_INT32: case NVS_DataTypes.DATA_TYPE_INT32_ARRAY: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((int[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((int[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (int)item.value).AppendLine(); + sb.Append($"{item.name} = {(int)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_INT64: case NVS_DataTypes.DATA_TYPE_INT64_ARRAY: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((long[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((long[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (long)item.value).AppendLine(); + sb.Append($"{item.name} = {(long)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_INT8: case NVS_DataTypes.DATA_TYPE_INT8_ARRAY: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((sbyte[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((sbyte[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (sbyte)item.value).AppendLine(); + sb.Append($"{item.name} = {(sbyte)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_STRING: case NVS_DataTypes.DATA_TYPE_STRING_ARRAY: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((string[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((string[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (string)item.value).AppendLine(); + sb.Append($"{item.name} = {(string)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_UINT16: case NVS_DataTypes.DATA_TYPE_UINT16_ARRAY: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((ushort[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((ushort[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (ushort)item.value).AppendLine(); + sb.Append($"{item.name} = {(ushort)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_UINT32: case NVS_DataTypes.DATA_TYPE_UINT32_ARRAY: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((uint[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((uint[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (uint)item.value).AppendLine(); + sb.Append($"{item.name} = {(uint)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_UINT64: case NVS_DataTypes.DATA_TYPE_UINT64_ARRAY: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = {2}", item.name, i, ((ulong[])item.value)[i]).AppendLine(); + sb.Append($"{item.name}[{i}] = {((ulong[])item.value)[i]}").AppendLine(); + } else - sb.AppendFormat("{0} = {1}", item.name, (ulong)item.value).AppendLine(); + sb.Append($"{item.name} = {(ulong)item.value}").AppendLine(); break; case NVS_DataTypes.DATA_TYPE_NVLIST: if(item.elements == 1) - sb.AppendFormat("{0} =\n{1}", item.name, PrintNvList((Dictionary)item.value)). - AppendLine(); + { + sb.Append($"{item.name} =\n{PrintNvList((Dictionary)item.value)}") + .AppendLine(); + } else - sb.AppendFormat("{0} = {1} elements nvlist[], unable to print", item.name, item.elements). - AppendLine(); + { + sb.AppendFormat(Localization._0_equals_1_elements_nvlist_array_unable_to_print, + item.name, + item.elements) + .AppendLine(); + } break; default: if(item.elements > 1) + { for(var i = 0; i < item.elements; i++) - sb.AppendFormat("{0}[{1}] = Unknown data type {2}", item.name, i, item.dataType). - AppendLine(); + { + sb.AppendFormat(Localization._0_1_equals_unknown_data_type_2, item.name, i, item.dataType) + .AppendLine(); + } + } else - sb.AppendFormat("{0} = Unknown data type {1}", item.name, item.dataType).AppendLine(); + { + sb.AppendFormat(Localization._0_equals_unknown_data_type_1, item.name, item.dataType) + .AppendLine(); + } break; } @@ -721,129 +611,4 @@ public sealed class ZFS : IFilesystem return sb.ToString(); } - - struct ZIO_Checksum - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public ulong[] word; - } - - /// - /// There is an empty ZIO at sector 16 or sector 31, with magic and checksum, to detect it is really ZFS I - /// suppose. - /// - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ZIO_Empty - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 472)] - public readonly byte[] empty; - public readonly ulong magic; - public readonly ZIO_Checksum checksum; - } - - /// This structure indicates which encoding method and endianness is used to encode the nvlist - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct NVS_Method - { - public readonly byte encoding; - public readonly byte endian; - public readonly byte reserved1; - public readonly byte reserved2; - } - - /// This structure gives information about the encoded nvlist - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct NVS_XDR_Header - { - public readonly NVS_Method encodingAndEndian; - public readonly uint version; - public readonly uint flags; - } - - enum NVS_DataTypes : uint - { - DATA_TYPE_UNKNOWN = 0, - DATA_TYPE_BOOLEAN, - DATA_TYPE_BYTE, - DATA_TYPE_INT16, - DATA_TYPE_UINT16, - DATA_TYPE_INT32, - DATA_TYPE_UINT32, - DATA_TYPE_INT64, - DATA_TYPE_UINT64, - DATA_TYPE_STRING, - DATA_TYPE_BYTE_ARRAY, - DATA_TYPE_INT16_ARRAY, - DATA_TYPE_UINT16_ARRAY, - DATA_TYPE_INT32_ARRAY, - DATA_TYPE_UINT32_ARRAY, - DATA_TYPE_INT64_ARRAY, - DATA_TYPE_UINT64_ARRAY, - DATA_TYPE_STRING_ARRAY, - DATA_TYPE_HRTIME, - DATA_TYPE_NVLIST, - DATA_TYPE_NVLIST_ARRAY, - DATA_TYPE_BOOLEAN_VALUE, - DATA_TYPE_INT8, - DATA_TYPE_UINT8, - DATA_TYPE_BOOLEAN_ARRAY, - DATA_TYPE_INT8_ARRAY, - DATA_TYPE_UINT8_ARRAY, - DATA_TYPE_DOUBLE - } - - /// This represent an encoded nvpair (an item of an nvlist) - struct NVS_Item - { - /// Size in bytes when encoded in XDR - public uint encodedSize; - /// Size in bytes when decoded - public uint decodedSize; - /// On disk, it is null-padded for alignment to 4 bytes and prepended by a 4 byte length indicator - public string name; - /// Data type - public NVS_DataTypes dataType; - /// How many elements are here - public uint elements; - /// On disk size is relative to and always aligned to 4 bytes - public object value; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct DVA - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public readonly ulong[] word; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SPA_BlockPointer - { - /// Data virtual address - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly DVA[] dataVirtualAddress; - /// Block properties - public readonly ulong properties; - /// Reserved for future expansion - public readonly ulong[] padding; - /// TXG when block was allocated - public readonly ulong birthTxg; - /// Transaction group at birth - public readonly ulong birth; - /// Fill count - public readonly ulong fill; - public readonly ZIO_Checksum checksum; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ZFS_Uberblock - { - public readonly ulong magic; - public readonly ulong spaVersion; - public readonly ulong lastTxg; - public readonly ulong guidSum; - public readonly ulong timestamp; - public readonly SPA_BlockPointer mosPtr; - public readonly ulong softwareVersion; - } } \ No newline at end of file diff --git a/Aaru.Filesystems/ZFS/Info.cs b/Aaru.Filesystems/ZFS/Info.cs new file mode 100644 index 000000000..aba3933f1 --- /dev/null +++ b/Aaru.Filesystems/ZFS/Info.cs @@ -0,0 +1,165 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : ZFS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/* + * The ZFS on-disk structure is quite undocumented, so this has been checked using several test images and reading the comments and headers (but not the code) + * of ZFS-On-Linux. + * + * The most basic structure, the vdev label, is as follows: + * 8KiB of blank space + * 8KiB reserved for boot code, stored as a ZIO block with magic and checksum + * 112KiB of nvlist, usually encoded using XDR + * 128KiB of copies of the 1KiB uberblock + * + * Two vdev labels, L0 and L1 are stored at the start of the vdev. + * Another two, L2 and L3 are stored at the end. + * + * The nvlist is nothing more than a double linked list of name/value pairs where name is a string and value is an arbitrary type (and can be an array of it). + * On-disk they are stored sequentially (no pointers) and can be encoded in XDR (an old Sun serialization method that stores everything as 4 bytes chunks) or + * natively (that is as the host natively stores that values, for example on Intel an extended float would be 10 bytes (80 bit). + * It can also be encoded little or big endian. + * Because of this variations, ZFS stored a header indicating the used encoding and endianess before the encoded nvlist. + */ +/// +/// Implements detection for the Zettabyte File System (ZFS) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "NotAccessedField.Local")] +public sealed partial class ZFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 512) return false; + + byte[] sector; + ulong magic; + ErrorNumber errno; + + if(partition.Start + 31 < partition.End) + { + errno = imagePlugin.ReadSector(partition.Start + 31, out sector); + + if(errno != ErrorNumber.NoError) return false; + + magic = BitConverter.ToUInt64(sector, 0x1D8); + + if(magic is ZEC_MAGIC or ZEC_CIGAM) return true; + } + + if(partition.Start + 16 >= partition.End) return false; + + errno = imagePlugin.ReadSector(partition.Start + 16, out sector); + + if(errno != ErrorNumber.NoError) return false; + + magic = BitConverter.ToUInt64(sector, 0x1D8); + + return magic is ZEC_MAGIC or ZEC_CIGAM; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + // ZFS is always UTF-8 + information = ""; + metadata = new FileSystem(); + ErrorNumber errno; + + if(imagePlugin.Info.SectorSize < 512) return; + + byte[] sector; + ulong magic; + + ulong nvlistOff = 32; + uint nvlistLen = 114688 / imagePlugin.Info.SectorSize; + + if(partition.Start + 31 < partition.End) + { + errno = imagePlugin.ReadSector(partition.Start + 31, out sector); + + if(errno != ErrorNumber.NoError) return; + + magic = BitConverter.ToUInt64(sector, 0x1D8); + + if(magic is ZEC_MAGIC or ZEC_CIGAM) nvlistOff = 32; + } + + if(partition.Start + 16 < partition.End) + { + errno = imagePlugin.ReadSector(partition.Start + 16, out sector); + + if(errno != ErrorNumber.NoError) return; + + magic = BitConverter.ToUInt64(sector, 0x1D8); + + if(magic is ZEC_MAGIC or ZEC_CIGAM) nvlistOff = 17; + } + + var sb = new StringBuilder(); + sb.AppendLine(Localization.ZFS_filesystem); + + errno = imagePlugin.ReadSectors(partition.Start + nvlistOff, nvlistLen, out byte[] nvlist); + + if(errno != ErrorNumber.NoError) return; + + sb.AppendLine(!DecodeNvList(nvlist, out Dictionary decodedNvList) + ? "Could not decode nvlist" + : PrintNvList(decodedNvList)); + + information = sb.ToString(); + + metadata = new FileSystem + { + Type = FS_TYPE + }; + + if(decodedNvList.TryGetValue("name", out NVS_Item tmpObj)) metadata.VolumeName = (string)tmpObj.value; + + if(decodedNvList.TryGetValue("guid", out tmpObj)) metadata.VolumeSerial = $"{(ulong)tmpObj.value}"; + + if(decodedNvList.TryGetValue("pool_guid", out tmpObj)) metadata.VolumeSetIdentifier = $"{(ulong)tmpObj.value}"; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ZFS/Structs.cs b/Aaru.Filesystems/ZFS/Structs.cs new file mode 100644 index 000000000..8b705b5a1 --- /dev/null +++ b/Aaru.Filesystems/ZFS/Structs.cs @@ -0,0 +1,187 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : ZFS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/* + * The ZFS on-disk structure is quite undocumented, so this has been checked using several test images and reading the comments and headers (but not the code) + * of ZFS-On-Linux. + * + * The most basic structure, the vdev label, is as follows: + * 8KiB of blank space + * 8KiB reserved for boot code, stored as a ZIO block with magic and checksum + * 112KiB of nvlist, usually encoded using XDR + * 128KiB of copies of the 1KiB uberblock + * + * Two vdev labels, L0 and L1 are stored at the start of the vdev. + * Another two, L2 and L3 are stored at the end. + * + * The nvlist is nothing more than a double linked list of name/value pairs where name is a string and value is an arbitrary type (and can be an array of it). + * On-disk they are stored sequentially (no pointers) and can be encoded in XDR (an old Sun serialization method that stores everything as 4 bytes chunks) or + * natively (that is as the host natively stores that values, for example on Intel an extended float would be 10 bytes (80 bit). + * It can also be encoded little or big endian. + * Because of this variations, ZFS stored a header indicating the used encoding and endianess before the encoded nvlist. + */ +/// +/// Implements detection for the Zettabyte File System (ZFS) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "NotAccessedField.Local")] +public sealed partial class ZFS +{ +#region Nested type: DVA + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct DVA + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public readonly ulong[] word; + } + +#endregion + +#region Nested type: NVS_Item + + /// This represent an encoded nvpair (an item of an nvlist) + struct NVS_Item + { + /// Size in bytes when encoded in XDR + public uint encodedSize; + /// Size in bytes when decoded + public uint decodedSize; + /// On disk, it is null-padded for alignment to 4 bytes and prepended by a 4 byte length indicator + public string name; + /// Data type + public NVS_DataTypes dataType; + /// How many elements are here + public uint elements; + /// On disk size is relative to and always aligned to 4 bytes + public object value; + } + +#endregion + +#region Nested type: NVS_Method + + /// This structure indicates which encoding method and endianness is used to encode the nvlist + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct NVS_Method + { + public readonly byte encoding; + public readonly byte endian; + public readonly byte reserved1; + public readonly byte reserved2; + } + +#endregion + +#region Nested type: NVS_XDR_Header + + /// This structure gives information about the encoded nvlist + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct NVS_XDR_Header + { + public readonly NVS_Method encodingAndEndian; + public readonly uint version; + public readonly uint flags; + } + +#endregion + +#region Nested type: SPA_BlockPointer + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SPA_BlockPointer + { + /// Data virtual address + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly DVA[] dataVirtualAddress; + /// Block properties + public readonly ulong properties; + /// Reserved for future expansion + public readonly ulong[] padding; + /// TXG when block was allocated + public readonly ulong birthTxg; + /// Transaction group at birth + public readonly ulong birth; + /// Fill count + public readonly ulong fill; + public readonly ZIO_Checksum checksum; + } + +#endregion + +#region Nested type: ZFS_Uberblock + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ZFS_Uberblock + { + public readonly ulong magic; + public readonly ulong spaVersion; + public readonly ulong lastTxg; + public readonly ulong guidSum; + public readonly ulong timestamp; + public readonly SPA_BlockPointer mosPtr; + public readonly ulong softwareVersion; + } + +#endregion + +#region Nested type: ZIO_Checksum + +#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value + struct ZIO_Checksum + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public ulong[] word; + } +#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value + +#endregion + +#region Nested type: ZIO_Empty + + /// + /// There is an empty ZIO at sector 16 or sector 31, with magic and checksum, to detect it is really ZFS I + /// suppose. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ZIO_Empty + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 472)] + public readonly byte[] empty; + public readonly ulong magic; + public readonly ZIO_Checksum checksum; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ZFS/ZFS.cs b/Aaru.Filesystems/ZFS/ZFS.cs new file mode 100644 index 000000000..638d5472d --- /dev/null +++ b/Aaru.Filesystems/ZFS/ZFS.cs @@ -0,0 +1,74 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ZFS.cs +// Author(s) : Natalia Portillo +// +// Component : ZFS filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/* + * The ZFS on-disk structure is quite undocumented, so this has been checked using several test images and reading the comments and headers (but not the code) + * of ZFS-On-Linux. + * + * The most basic structure, the vdev label, is as follows: + * 8KiB of blank space + * 8KiB reserved for boot code, stored as a ZIO block with magic and checksum + * 112KiB of nvlist, usually encoded using XDR + * 128KiB of copies of the 1KiB uberblock + * + * Two vdev labels, L0 and L1 are stored at the start of the vdev. + * Another two, L2 and L3 are stored at the end. + * + * The nvlist is nothing more than a double linked list of name/value pairs where name is a string and value is an arbitrary type (and can be an array of it). + * On-disk they are stored sequentially (no pointers) and can be encoded in XDR (an old Sun serialization method that stores everything as 4 bytes chunks) or + * natively (that is as the host natively stores that values, for example on Intel an extended float would be 10 bytes (80 bit). + * It can also be encoded little or big endian. + * Because of this variations, ZFS stored a header indicating the used encoding and endianess before the encoded nvlist. + */ +/// +/// Implements detection for the Zettabyte File System (ZFS) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedType.Local")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +[SuppressMessage("ReSharper", "NotAccessedField.Local")] +public sealed partial class ZFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.ZFS_Name; + + /// + public Guid Id => new("0750014F-A714-4692-A369-E23F6EC3659C"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/dump.cs b/Aaru.Filesystems/dump.cs deleted file mode 100644 index df1426c13..000000000 --- a/Aaru.Filesystems/dump.cs +++ /dev/null @@ -1,434 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : dump.cs -// Author(s) : Natalia Portillo -// -// Component : dump(8) file system plugin -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies backups created with dump(8) shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -using ufs_daddr_t = System.Int32; - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Console; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -/// -/// Implements identification of a dump(8) image (virtual filesystem on a file) -[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "UnusedMember.Local")] -public sealed class dump : IFilesystem -{ - /// Magic number for old dump - const ushort OFS_MAGIC = 60011; - /// Magic number for new dump - const uint NFS_MAGIC = 60012; - /// Magic number for AIX dump - const uint XIX_MAGIC = 60013; - /// Magic number for UFS2 dump - const uint UFS2_MAGIC = 0x19540119; - /// Magic number for old dump - const uint OFS_CIGAM = 0x6BEA0000; - /// Magic number for new dump - const uint NFS_CIGAM = 0x6CEA0000; - /// Magic number for AIX dump - const uint XIX_CIGAM = 0x6DEA0000; - /// Magic number for UFS2 dump - const uint UFS2_CIGAM = 0x19015419; - - const int TP_BSIZE = 1024; - - /// Dump tape header - const short TS_TAPE = 1; - /// Beginning of file record - const short TS_INODE = 2; - /// Map of inodes on tape - const short TS_BITS = 3; - /// Continuation of file record - const short TS_ADDR = 4; - /// Map of inodes deleted since last dump - const short TS_END = 5; - /// Inode bitmap - const short TS_CLRI = 6; - const short TS_ACL = 7; - const short TS_PCL = 8; - - const int TP_NINDIR = TP_BSIZE / 2; - const int LBLSIZE = 16; - const int NAMELEN = 64; - - const int NDADDR = 12; - const int NIADDR = 3; - - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "dump(8) Plugin"; - /// - public Guid Id => new("E53B4D28-C858-4800-B092-DDAE80D361B9"); - /// - public FileSystemType XmlFsType { get; private set; } - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 512) - return false; - - // It should be start of a tape or floppy or file - if(partition.Start != 0) - return false; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return false; - - if(sector.Length < Marshal.SizeOf()) - return false; - - spcl16 oldHdr = Marshal.ByteArrayToStructureLittleEndian(sector); - spcl_aix aixHdr = Marshal.ByteArrayToStructureLittleEndian(sector); - s_spcl newHdr = Marshal.ByteArrayToStructureLittleEndian(sector); - - AaruConsole.DebugWriteLine("dump(8) plugin", "old magic = 0x{0:X8}", oldHdr.c_magic); - AaruConsole.DebugWriteLine("dump(8) plugin", "aix magic = 0x{0:X8}", aixHdr.c_magic); - AaruConsole.DebugWriteLine("dump(8) plugin", "new magic = 0x{0:X8}", newHdr.c_magic); - - return oldHdr.c_magic == OFS_MAGIC || aixHdr.c_magic is XIX_MAGIC or XIX_CIGAM || newHdr.c_magic == OFS_MAGIC || - newHdr.c_magic == NFS_MAGIC || newHdr.c_magic == OFS_CIGAM || newHdr.c_magic == NFS_CIGAM || - newHdr.c_magic == UFS2_MAGIC || newHdr.c_magic == UFS2_CIGAM; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - if(imagePlugin.Info.SectorSize < 512) - return; - - if(partition.Start != 0) - return; - - var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); - - if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) - sbSize++; - - ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); - - if(errno != ErrorNumber.NoError) - return; - - if(sector.Length < Marshal.SizeOf()) - return; - - spcl16 oldHdr = Marshal.ByteArrayToStructureLittleEndian(sector); - spcl_aix aixHdr = Marshal.ByteArrayToStructureLittleEndian(sector); - s_spcl newHdr = Marshal.ByteArrayToStructureLittleEndian(sector); - - var useOld = false; - var useAix = false; - - if(newHdr.c_magic == OFS_MAGIC || - newHdr.c_magic == NFS_MAGIC || - newHdr.c_magic == OFS_CIGAM || - newHdr.c_magic == NFS_CIGAM || - newHdr.c_magic == UFS2_MAGIC || - newHdr.c_magic == UFS2_CIGAM) - { - if(newHdr.c_magic == OFS_CIGAM || - newHdr.c_magic == NFS_CIGAM || - newHdr.c_magic == UFS2_CIGAM) - newHdr = Marshal.ByteArrayToStructureBigEndian(sector); - } - else if(aixHdr.c_magic is XIX_MAGIC or XIX_CIGAM) - { - useAix = true; - - if(aixHdr.c_magic == XIX_CIGAM) - aixHdr = Marshal.ByteArrayToStructureBigEndian(sector); - } - else if(oldHdr.c_magic == OFS_MAGIC) - { - useOld = true; - - // Swap PDP-11 endian - oldHdr.c_date = (int)Swapping.PDPFromLittleEndian((uint)oldHdr.c_date); - oldHdr.c_ddate = (int)Swapping.PDPFromLittleEndian((uint)oldHdr.c_ddate); - } - else - { - information = "Could not read dump(8) header block"; - - return; - } - - var sb = new StringBuilder(); - - XmlFsType = new FileSystemType - { - ClusterSize = 1024, - Clusters = partition.Size / 1024 - }; - - if(useOld) - { - XmlFsType.Type = "Old 16-bit dump(8)"; - sb.AppendLine(XmlFsType.Type); - - if(oldHdr.c_date > 0) - { - XmlFsType.CreationDate = DateHandlers.UnixToDateTime(oldHdr.c_date); - XmlFsType.CreationDateSpecified = true; - sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine(); - } - - if(oldHdr.c_ddate > 0) - { - XmlFsType.BackupDate = DateHandlers.UnixToDateTime(oldHdr.c_ddate); - XmlFsType.BackupDateSpecified = true; - sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine(); - } - - sb.AppendFormat("Dump volume number: {0}", oldHdr.c_volume).AppendLine(); - } - else if(useAix) - { - XmlFsType.Type = "AIX dump(8)"; - sb.AppendLine(XmlFsType.Type); - - if(aixHdr.c_date > 0) - { - XmlFsType.CreationDate = DateHandlers.UnixToDateTime(aixHdr.c_date); - XmlFsType.CreationDateSpecified = true; - sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine(); - } - - if(aixHdr.c_ddate > 0) - { - XmlFsType.BackupDate = DateHandlers.UnixToDateTime(aixHdr.c_ddate); - XmlFsType.BackupDateSpecified = true; - sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine(); - } - - sb.AppendFormat("Dump volume number: {0}", aixHdr.c_volume).AppendLine(); - } - else - { - XmlFsType.Type = "dump(8)"; - sb.AppendLine(XmlFsType.Type); - - if(newHdr.c_ndate > 0) - { - XmlFsType.CreationDate = DateHandlers.UnixToDateTime(newHdr.c_ndate); - XmlFsType.CreationDateSpecified = true; - sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine(); - } - else if(newHdr.c_date > 0) - { - XmlFsType.CreationDate = DateHandlers.UnixToDateTime(newHdr.c_date); - XmlFsType.CreationDateSpecified = true; - sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine(); - } - - if(newHdr.c_nddate > 0) - { - XmlFsType.BackupDate = DateHandlers.UnixToDateTime(newHdr.c_nddate); - XmlFsType.BackupDateSpecified = true; - sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine(); - } - else if(newHdr.c_ddate > 0) - { - XmlFsType.BackupDate = DateHandlers.UnixToDateTime(newHdr.c_ddate); - XmlFsType.BackupDateSpecified = true; - sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine(); - } - - sb.AppendFormat("Dump volume number: {0}", newHdr.c_volume).AppendLine(); - sb.AppendFormat("Dump level: {0}", newHdr.c_level).AppendLine(); - string dumpname = StringHandlers.CToString(newHdr.c_label); - - if(!string.IsNullOrEmpty(dumpname)) - { - XmlFsType.VolumeName = dumpname; - sb.AppendFormat("Dump label: {0}", dumpname).AppendLine(); - } - - string str = StringHandlers.CToString(newHdr.c_filesys); - - if(!string.IsNullOrEmpty(str)) - sb.AppendFormat("Dumped filesystem name: {0}", str).AppendLine(); - - str = StringHandlers.CToString(newHdr.c_dev); - - if(!string.IsNullOrEmpty(str)) - sb.AppendFormat("Dumped device: {0}", str).AppendLine(); - - str = StringHandlers.CToString(newHdr.c_host); - - if(!string.IsNullOrEmpty(str)) - sb.AppendFormat("Dump hostname: {0}", str).AppendLine(); - } - - information = sb.ToString(); - } - - // Old 16-bit format record - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct spcl16 - { - /// Record type - public readonly short c_type; - /// Dump date - public int c_date; - /// Previous dump date - public int c_ddate; - /// Dump volume number - public readonly short c_volume; - /// Logical block of this record - public readonly int c_tapea; - /// Inode number - public readonly ushort c_inumber; - /// Magic number - public readonly ushort c_magic; - /// Record checksum - public readonly int c_checksum; - - // Unneeded for now - /* - struct dinode c_dinode; - int c_count; - char c_addr[BSIZE]; - */ - } - - // 32-bit AIX format record - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct spcl_aix - { - /// Record type - public readonly int c_type; - /// Dump date - public readonly int c_date; - /// Previous dump date - public readonly int c_ddate; - /// Dump volume number - public readonly int c_volume; - /// Logical block of this record - public readonly int c_tapea; - public readonly uint c_inumber; - public readonly uint c_magic; - public readonly int c_checksum; - - // Unneeded for now - /* - public bsd_dinode bsd_c_dinode; - public int c_count; - public char c_addr[TP_NINDIR]; - public int xix_flag; - public dinode xix_dinode; - */ - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct s_spcl - { - public readonly int c_type; /* record type (see below) */ - public readonly int c_date; /* date of this dump */ - public readonly int c_ddate; /* date of previous dump */ - public readonly int c_volume; /* dump volume number */ - public readonly int c_tapea; /* logical block of this record */ - public readonly uint c_inumber; /* number of inode */ - public readonly int c_magic; /* magic number (see above) */ - public readonly int c_checksum; /* record checksum */ - public readonly dinode c_dinode; /* ownership and mode of inode */ - public readonly int c_count; /* number of valid c_addr entries */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TP_NINDIR)] - public readonly byte[] c_addr; /* 1 => data; 0 => hole in inode */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = LBLSIZE)] - public readonly byte[] c_label; /* dump label */ - public readonly int c_level; /* level of this dump */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)] - public readonly byte[] c_filesys; /* name of dumpped file system */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)] - public readonly byte[] c_dev; /* name of dumpped device */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)] - public readonly byte[] c_host; /* name of dumpped host */ - public readonly int c_flags; /* additional information */ - public readonly int c_firstrec; /* first record on volume */ - public readonly long c_ndate; /* date of this dump */ - public readonly long c_nddate; /* date of previous dump */ - public readonly long c_ntapea; /* logical block of this record */ - public readonly long c_nfirstrec; /* first record on volume */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly int[] c_spare; /* reserved for future uses */ - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct dinode - { - public readonly ushort di_mode; /* 0: IFMT, permissions; see below. */ - public readonly short di_nlink; /* 2: File link count. */ - public readonly int inumber; /* 4: Lfs: inode number. */ - public readonly ulong di_size; /* 8: File byte count. */ - public readonly int di_atime; /* 16: Last access time. */ - public readonly int di_atimensec; /* 20: Last access time. */ - public readonly int di_mtime; /* 24: Last modified time. */ - public readonly int di_mtimensec; /* 28: Last modified time. */ - public readonly int di_ctime; /* 32: Last inode change time. */ - public readonly int di_ctimensec; /* 36: Last inode change time. */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = NDADDR)] - public readonly int[] di_db; /* 40: Direct disk blocks. */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = NIADDR)] - public readonly int[] di_ib; /* 88: Indirect disk blocks. */ - public readonly uint di_flags; /* 100: Status flags (chflags). */ - public readonly uint di_blocks; /* 104: Blocks actually held. */ - public readonly int di_gen; /* 108: Generation number. */ - public readonly uint di_uid; /* 112: File owner. */ - public readonly uint di_gid; /* 116: File group. */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public readonly int[] di_spare; /* 120: Reserved; currently unused */ - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/dump/Consts.cs b/Aaru.Filesystems/dump/Consts.cs new file mode 100644 index 000000000..4dd59add0 --- /dev/null +++ b/Aaru.Filesystems/dump/Consts.cs @@ -0,0 +1,85 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : dump(8) file system plugin +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies backups created with dump(8) shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +/// +/// Implements identification of a dump(8) image (virtual filesystem on a file) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class Dump +{ + /// Magic number for old dump + const ushort OFS_MAGIC = 60011; + /// Magic number for new dump + const uint NFS_MAGIC = 60012; + /// Magic number for AIX dump + const uint XIX_MAGIC = 60013; + /// Magic number for UFS2 dump + const uint UFS2_MAGIC = 0x19540119; + /// Magic number for old dump + const uint OFS_CIGAM = 0x6BEA0000; + /// Magic number for new dump + const uint NFS_CIGAM = 0x6CEA0000; + /// Magic number for AIX dump + const uint XIX_CIGAM = 0x6DEA0000; + /// Magic number for UFS2 dump + const uint UFS2_CIGAM = 0x19015419; + + const int TP_BSIZE = 1024; + + /// Dump tape header + const short TS_TAPE = 1; + /// Beginning of file record + const short TS_INODE = 2; + /// Map of inodes on tape + const short TS_BITS = 3; + /// Continuation of file record + const short TS_ADDR = 4; + /// Map of inodes deleted since last dump + const short TS_END = 5; + /// Inode bitmap + const short TS_CLRI = 6; + const short TS_ACL = 7; + const short TS_PCL = 8; + + const int TP_NINDIR = TP_BSIZE / 2; + const int LBLSIZE = 16; + const int NAMELEN = 64; + + const int NDADDR = 12; + const int NIADDR = 3; + + const string FS_TYPE = "dump"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/dump/Info.cs b/Aaru.Filesystems/dump/Info.cs new file mode 100644 index 000000000..823055b5a --- /dev/null +++ b/Aaru.Filesystems/dump/Info.cs @@ -0,0 +1,250 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : dump(8) file system plugin +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies backups created with dump(8) shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Console; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +/// +/// Implements identification of a dump(8) image (virtual filesystem on a file) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class Dump +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 512) return false; + + // It should be start of a tape or floppy or file + if(partition.Start != 0) return false; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return false; + + if(sector.Length < Marshal.SizeOf()) return false; + + spcl16 oldHdr = Marshal.ByteArrayToStructureLittleEndian(sector); + spcl_aix aixHdr = Marshal.ByteArrayToStructureLittleEndian(sector); + s_spcl newHdr = Marshal.ByteArrayToStructureLittleEndian(sector); + + AaruConsole.DebugWriteLine(MODULE_NAME, "old magic = 0x{0:X8}", oldHdr.c_magic); + AaruConsole.DebugWriteLine(MODULE_NAME, "aix magic = 0x{0:X8}", aixHdr.c_magic); + AaruConsole.DebugWriteLine(MODULE_NAME, "new magic = 0x{0:X8}", newHdr.c_magic); + + return oldHdr.c_magic == OFS_MAGIC || + aixHdr.c_magic is XIX_MAGIC or XIX_CIGAM || + newHdr.c_magic == OFS_MAGIC || + newHdr.c_magic == NFS_MAGIC || + newHdr.c_magic == OFS_CIGAM || + newHdr.c_magic == NFS_CIGAM || + newHdr.c_magic == UFS2_MAGIC || + newHdr.c_magic == UFS2_CIGAM; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + + if(imagePlugin.Info.SectorSize < 512) return; + + if(partition.Start != 0) return; + + var sbSize = (uint)(Marshal.SizeOf() / imagePlugin.Info.SectorSize); + + if(Marshal.SizeOf() % imagePlugin.Info.SectorSize != 0) sbSize++; + + ErrorNumber errno = imagePlugin.ReadSectors(partition.Start, sbSize, out byte[] sector); + + if(errno != ErrorNumber.NoError) return; + + if(sector.Length < Marshal.SizeOf()) return; + + spcl16 oldHdr = Marshal.ByteArrayToStructureLittleEndian(sector); + spcl_aix aixHdr = Marshal.ByteArrayToStructureLittleEndian(sector); + s_spcl newHdr = Marshal.ByteArrayToStructureLittleEndian(sector); + + var useOld = false; + var useAix = false; + + if(newHdr.c_magic == OFS_MAGIC || + newHdr.c_magic == NFS_MAGIC || + newHdr.c_magic == OFS_CIGAM || + newHdr.c_magic == NFS_CIGAM || + newHdr.c_magic == UFS2_MAGIC || + newHdr.c_magic == UFS2_CIGAM) + { + if(newHdr.c_magic == OFS_CIGAM || newHdr.c_magic == NFS_CIGAM || newHdr.c_magic == UFS2_CIGAM) + newHdr = Marshal.ByteArrayToStructureBigEndian(sector); + } + else if(aixHdr.c_magic is XIX_MAGIC or XIX_CIGAM) + { + useAix = true; + + if(aixHdr.c_magic == XIX_CIGAM) aixHdr = Marshal.ByteArrayToStructureBigEndian(sector); + } + else if(oldHdr.c_magic == OFS_MAGIC) + { + useOld = true; + + // Swap PDP-11 endian + oldHdr.c_date = (int)Swapping.PDPFromLittleEndian((uint)oldHdr.c_date); + oldHdr.c_ddate = (int)Swapping.PDPFromLittleEndian((uint)oldHdr.c_ddate); + } + else + { + information = Localization.Could_not_read_dump_8_header_block; + + return; + } + + var sb = new StringBuilder(); + + metadata = new FileSystem + { + ClusterSize = 1024, + Clusters = partition.Size / 1024 + }; + + if(useOld) + { + metadata.Type = Localization.Old_16_bit_dump_8; + sb.AppendLine(metadata.Type); + + if(oldHdr.c_date > 0) + { + metadata.CreationDate = DateHandlers.UnixToDateTime(oldHdr.c_date); + sb.AppendFormat(Localization.Dump_created_on_0, metadata.CreationDate).AppendLine(); + } + + if(oldHdr.c_ddate > 0) + { + metadata.BackupDate = DateHandlers.UnixToDateTime(oldHdr.c_ddate); + sb.AppendFormat(Localization.Previous_dump_created_on_0, metadata.BackupDate).AppendLine(); + } + + sb.AppendFormat(Localization.Dump_volume_number_0, oldHdr.c_volume).AppendLine(); + } + else if(useAix) + { + metadata.Type = FS_TYPE; + sb.AppendLine(metadata.Type); + + if(aixHdr.c_date > 0) + { + metadata.CreationDate = DateHandlers.UnixToDateTime(aixHdr.c_date); + + sb.AppendFormat(Localization.Dump_created_on_0, metadata.CreationDate).AppendLine(); + } + + if(aixHdr.c_ddate > 0) + { + metadata.BackupDate = DateHandlers.UnixToDateTime(aixHdr.c_ddate); + sb.AppendFormat(Localization.Previous_dump_created_on_0, metadata.BackupDate).AppendLine(); + } + + sb.AppendFormat(Localization.Dump_volume_number_0, aixHdr.c_volume).AppendLine(); + } + else + { + metadata.Type = FS_TYPE; + sb.AppendLine(metadata.Type); + + if(newHdr.c_ndate > 0) + { + metadata.CreationDate = DateHandlers.UnixToDateTime(newHdr.c_ndate); + + sb.AppendFormat(Localization.Dump_created_on_0, metadata.CreationDate).AppendLine(); + } + else if(newHdr.c_date > 0) + { + metadata.CreationDate = DateHandlers.UnixToDateTime(newHdr.c_date); + + sb.AppendFormat(Localization.Dump_created_on_0, metadata.CreationDate).AppendLine(); + } + + if(newHdr.c_nddate > 0) + { + metadata.BackupDate = DateHandlers.UnixToDateTime(newHdr.c_nddate); + sb.AppendFormat(Localization.Previous_dump_created_on_0, metadata.BackupDate).AppendLine(); + } + else if(newHdr.c_ddate > 0) + { + metadata.BackupDate = DateHandlers.UnixToDateTime(newHdr.c_ddate); + sb.AppendFormat(Localization.Previous_dump_created_on_0, metadata.BackupDate).AppendLine(); + } + + sb.AppendFormat(Localization.Dump_volume_number_0, newHdr.c_volume).AppendLine(); + sb.AppendFormat(Localization.Dump_level_0, newHdr.c_level).AppendLine(); + string dumpname = StringHandlers.CToString(newHdr.c_label); + + if(!string.IsNullOrEmpty(dumpname)) + { + metadata.VolumeName = dumpname; + sb.AppendFormat(Localization.Dump_label_0, dumpname).AppendLine(); + } + + string str = StringHandlers.CToString(newHdr.c_filesys); + + if(!string.IsNullOrEmpty(str)) sb.AppendFormat(Localization.Dumped_filesystem_name_0, str).AppendLine(); + + str = StringHandlers.CToString(newHdr.c_dev); + + if(!string.IsNullOrEmpty(str)) sb.AppendFormat(Localization.Dumped_device_0, str).AppendLine(); + + str = StringHandlers.CToString(newHdr.c_host); + + if(!string.IsNullOrEmpty(str)) sb.AppendFormat(Localization.Dump_hostname_0, str).AppendLine(); + } + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/dump/Structs.cs b/Aaru.Filesystems/dump/Structs.cs new file mode 100644 index 000000000..62368055d --- /dev/null +++ b/Aaru.Filesystems/dump/Structs.cs @@ -0,0 +1,176 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : dump(8) file system plugin +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies backups created with dump(8) shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +/// +/// Implements identification of a dump(8) image (virtual filesystem on a file) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class Dump +{ +#region Nested type: DInode + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DInode + { + public readonly ushort di_mode; /* 0: IFMT, permissions; see below. */ + public readonly short di_nlink; /* 2: File link count. */ + public readonly int inumber; /* 4: Lfs: inode number. */ + public readonly ulong di_size; /* 8: File byte count. */ + public readonly int di_atime; /* 16: Last access time. */ + public readonly int di_atimensec; /* 20: Last access time. */ + public readonly int di_mtime; /* 24: Last modified time. */ + public readonly int di_mtimensec; /* 28: Last modified time. */ + public readonly int di_ctime; /* 32: Last inode change time. */ + public readonly int di_ctimensec; /* 36: Last inode change time. */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = NDADDR)] + public readonly int[] di_db; /* 40: Direct disk blocks. */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = NIADDR)] + public readonly int[] di_ib; /* 88: Indirect disk blocks. */ + public readonly uint di_flags; /* 100: Status flags (chflags). */ + public readonly uint di_blocks; /* 104: Blocks actually held. */ + public readonly int di_gen; /* 108: Generation number. */ + public readonly uint di_uid; /* 112: File owner. */ + public readonly uint di_gid; /* 116: File group. */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public readonly int[] di_spare; /* 120: Reserved; currently unused */ + } + +#endregion + +#region Nested type: s_spcl + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct s_spcl + { + public readonly int c_type; /* record type (see below) */ + public readonly int c_date; /* date of this dump */ + public readonly int c_ddate; /* date of previous dump */ + public readonly int c_volume; /* dump volume number */ + public readonly int c_tapea; /* logical block of this record */ + public readonly uint c_inumber; /* number of inode */ + public readonly int c_magic; /* magic number (see above) */ + public readonly int c_checksum; /* record checksum */ + public readonly DInode c_dinode; /* ownership and mode of inode */ + public readonly int c_count; /* number of valid c_addr entries */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TP_NINDIR)] + public readonly byte[] c_addr; /* 1 => data; 0 => hole in inode */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = LBLSIZE)] + public readonly byte[] c_label; /* dump label */ + public readonly int c_level; /* level of this dump */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)] + public readonly byte[] c_filesys; /* name of dumpped file system */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)] + public readonly byte[] c_dev; /* name of dumpped device */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)] + public readonly byte[] c_host; /* name of dumpped host */ + public readonly int c_flags; /* additional information */ + public readonly int c_firstrec; /* first record on volume */ + public readonly long c_ndate; /* date of this dump */ + public readonly long c_nddate; /* date of previous dump */ + public readonly long c_ntapea; /* logical block of this record */ + public readonly long c_nfirstrec; /* first record on volume */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly int[] c_spare; /* reserved for future uses */ + } + +#endregion + +#region Nested type: spcl_aix + + // 32-bit AIX format record + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct spcl_aix + { + /// Record type + public readonly int c_type; + /// Dump date + public readonly int c_date; + /// Previous dump date + public readonly int c_ddate; + /// Dump volume number + public readonly int c_volume; + /// Logical block of this record + public readonly int c_tapea; + public readonly uint c_inumber; + public readonly uint c_magic; + public readonly int c_checksum; + + // Unneeded for now + /* + public bsd_dinode bsd_c_dinode; + public int c_count; + public char c_addr[TP_NINDIR]; + public int xix_flag; + public dinode xix_dinode; + */ + } + +#endregion + +#region Nested type: spcl16 + + // Old 16-bit format record + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct spcl16 + { + /// Record type + public readonly short c_type; + /// Dump date + public int c_date; + /// Previous dump date + public int c_ddate; + /// Dump volume number + public readonly short c_volume; + /// Logical block of this record + public readonly int c_tapea; + /// Inode number + public readonly ushort c_inumber; + /// Magic number + public readonly ushort c_magic; + /// Record checksum + public readonly int c_checksum; + + // Unneeded for now + /* + struct dinode c_dinode; + int c_count; + char c_addr[BSIZE]; + */ + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/dump/dump.cs b/Aaru.Filesystems/dump/dump.cs new file mode 100644 index 000000000..6120eab4c --- /dev/null +++ b/Aaru.Filesystems/dump/dump.cs @@ -0,0 +1,59 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : dump.cs +// Author(s) : Natalia Portillo +// +// Component : dump(8) file system plugin +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies backups created with dump(8) shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +/// Implements identification of a dump(8) image (virtual filesystem on a file) +[SuppressMessage("ReSharper", "InconsistentNaming")] +[SuppressMessage("ReSharper", "UnusedMember.Local")] +public sealed partial class Dump : IFilesystem +{ + const string MODULE_NAME = "dump(8) plugin"; + +#region IFilesystem Members + + /// + public string Name => Localization.dump_Name; + + /// + public Guid Id => new("E53B4D28-C858-4800-B092-DDAE80D361B9"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/exFAT.cs b/Aaru.Filesystems/exFAT.cs deleted file mode 100644 index f53b81aa6..000000000 --- a/Aaru.Filesystems/exFAT.cs +++ /dev/null @@ -1,257 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : exFAT.cs -// Author(s) : Natalia Portillo -// -// Component : Microsoft exFAT filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Microsoft exFAT filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Information from https://www.sans.org/reading-room/whitepapers/forensics/reverse-engineering-microsoft-exfat-file-system-33274 -/// -/// Implements detection of the exFAT filesystem -[SuppressMessage("ReSharper", "UnusedMember.Local")] -// ReSharper disable once InconsistentNaming -public sealed class exFAT : IFilesystem -{ - readonly Guid _oemFlashParameterGuid = new("0A0C7E46-3399-4021-90C8-FA6D389C4BA2"); - - readonly byte[] _signature = - { - 0x45, 0x58, 0x46, 0x41, 0x54, 0x20, 0x20, 0x20 - }; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Microsoft Extended File Allocation Table"; - /// - public Guid Id => new("8271D088-1533-4CB3-AC28-D802B68BB95C"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(12 + partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] vbrSector); - - if(errno != ErrorNumber.NoError) - return false; - - if(vbrSector.Length < 512) - return false; - - VolumeBootRecord vbr = Marshal.ByteArrayToStructureLittleEndian(vbrSector); - - return _signature.SequenceEqual(vbr.signature); - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - var sb = new StringBuilder(); - XmlFsType = new FileSystemType(); - - ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] vbrSector); - - if(errno != ErrorNumber.NoError) - return; - - VolumeBootRecord vbr = Marshal.ByteArrayToStructureLittleEndian(vbrSector); - - errno = imagePlugin.ReadSector(9 + partition.Start, out byte[] parametersSector); - - if(errno != ErrorNumber.NoError) - return; - - OemParameterTable parametersTable = - Marshal.ByteArrayToStructureLittleEndian(parametersSector); - - errno = imagePlugin.ReadSector(11 + partition.Start, out byte[] chkSector); - - if(errno != ErrorNumber.NoError) - return; - - ChecksumSector chksector = Marshal.ByteArrayToStructureLittleEndian(chkSector); - - sb.AppendLine("Microsoft exFAT"); - sb.AppendFormat("Partition offset: {0}", vbr.offset).AppendLine(); - - sb.AppendFormat("Volume has {0} sectors of {1} bytes each for a total of {2} bytes", vbr.sectors, - 1 << vbr.sectorShift, vbr.sectors * (ulong)(1 << vbr.sectorShift)).AppendLine(); - - sb.AppendFormat("Volume uses clusters of {0} sectors ({1} bytes) each", 1 << vbr.clusterShift, - (1 << vbr.sectorShift) * (1 << vbr.clusterShift)).AppendLine(); - - sb.AppendFormat("First FAT starts at sector {0} and runs for {1} sectors", vbr.fatOffset, vbr.fatLength). - AppendLine(); - - sb.AppendFormat("Volume uses {0} FATs", vbr.fats).AppendLine(); - - sb.AppendFormat("Cluster heap starts at sector {0}, contains {1} clusters and is {2}% used", - vbr.clusterHeapOffset, vbr.clusterHeapLength, vbr.heapUsage).AppendLine(); - - sb.AppendFormat("Root directory starts at cluster {0}", vbr.rootDirectoryCluster).AppendLine(); - - sb.AppendFormat("Filesystem revision is {0}.{1:D2}", (vbr.revision & 0xFF00) >> 8, vbr.revision & 0xFF). - AppendLine(); - - sb.AppendFormat("Volume serial number: {0:X8}", vbr.volumeSerial).AppendLine(); - sb.AppendFormat("BIOS drive is {0:X2}h", vbr.drive).AppendLine(); - - if(vbr.flags.HasFlag(VolumeFlags.SecondFatActive)) - sb.AppendLine("2nd FAT is in use"); - - if(vbr.flags.HasFlag(VolumeFlags.VolumeDirty)) - sb.AppendLine("Volume is dirty"); - - if(vbr.flags.HasFlag(VolumeFlags.MediaFailure)) - sb.AppendLine("Underlying media presented errors"); - - var count = 1; - - foreach(OemParameter parameter in parametersTable.parameters) - { - if(parameter.OemParameterType == _oemFlashParameterGuid) - { - sb.AppendFormat("OEM Parameters {0}:", count).AppendLine(); - sb.AppendFormat("\t{0} bytes in erase block", parameter.eraseBlockSize).AppendLine(); - sb.AppendFormat("\t{0} bytes per page", parameter.pageSize).AppendLine(); - sb.AppendFormat("\t{0} spare blocks", parameter.spareBlocks).AppendLine(); - sb.AppendFormat("\t{0} nanoseconds random access time", parameter.randomAccessTime).AppendLine(); - sb.AppendFormat("\t{0} nanoseconds program time", parameter.programTime).AppendLine(); - sb.AppendFormat("\t{0} nanoseconds read cycle time", parameter.readCycleTime).AppendLine(); - sb.AppendFormat("\t{0} nanoseconds write cycle time", parameter.writeCycleTime).AppendLine(); - } - else if(parameter.OemParameterType != Guid.Empty) - sb.AppendFormat("Found unknown parameter type {0}", parameter.OemParameterType).AppendLine(); - - count++; - } - - sb.AppendFormat("Checksum 0x{0:X8}", chksector.checksum[0]).AppendLine(); - - XmlFsType.ClusterSize = (uint)((1 << vbr.sectorShift) * (1 << vbr.clusterShift)); - XmlFsType.Clusters = vbr.clusterHeapLength; - XmlFsType.Dirty = vbr.flags.HasFlag(VolumeFlags.VolumeDirty); - XmlFsType.Type = "exFAT"; - XmlFsType.VolumeSerial = $"{vbr.volumeSerial:X8}"; - - information = sb.ToString(); - } - - [Flags] - enum VolumeFlags : ushort - { - SecondFatActive = 1, - VolumeDirty = 2, - MediaFailure = 4, - ClearToZero = 8 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct VolumeBootRecord - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public readonly byte[] jump; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public readonly byte[] signature; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 53)] - public readonly byte[] zero; - public readonly ulong offset; - public readonly ulong sectors; - public readonly uint fatOffset; - public readonly uint fatLength; - public readonly uint clusterHeapOffset; - public readonly uint clusterHeapLength; - public readonly uint rootDirectoryCluster; - public readonly uint volumeSerial; - public readonly ushort revision; - public readonly VolumeFlags flags; - public readonly byte sectorShift; - public readonly byte clusterShift; - public readonly byte fats; - public readonly byte drive; - public readonly byte heapUsage; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 53)] - public readonly byte[] reserved; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 53)] - public readonly byte[] bootCode; - public readonly ushort bootSignature; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct OemParameter - { - public readonly Guid OemParameterType; - public readonly uint eraseBlockSize; - public readonly uint pageSize; - public readonly uint spareBlocks; - public readonly uint randomAccessTime; - public readonly uint programTime; - public readonly uint readCycleTime; - public readonly uint writeCycleTime; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct OemParameterTable - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public readonly OemParameter[] parameters; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] padding; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct ChecksumSector - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public readonly uint[] checksum; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/exFAT/Consts.cs b/Aaru.Filesystems/exFAT/Consts.cs new file mode 100644 index 000000000..3d2288b4d --- /dev/null +++ b/Aaru.Filesystems/exFAT/Consts.cs @@ -0,0 +1,45 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Microsoft exFAT filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Information from https://www.sans.org/reading-room/whitepapers/forensics/reverse-engineering-microsoft-exfat-file-system-33274 +/// +/// Implements detection of the exFAT filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] + +// ReSharper disable once InconsistentNaming +public sealed partial class exFAT +{ + const string FS_TYPE = "exfat"; + readonly Guid _oemFlashParameterGuid = new("0A0C7E46-3399-4021-90C8-FA6D389C4BA2"); + readonly byte[] _signature = "EXFAT "u8.ToArray(); +} \ No newline at end of file diff --git a/Aaru.Filesystems/exFAT/Enums.cs b/Aaru.Filesystems/exFAT/Enums.cs new file mode 100644 index 000000000..0260ea3ba --- /dev/null +++ b/Aaru.Filesystems/exFAT/Enums.cs @@ -0,0 +1,54 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Enums.cs +// Author(s) : Natalia Portillo +// +// Component : Microsoft exFAT filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Information from https://www.sans.org/reading-room/whitepapers/forensics/reverse-engineering-microsoft-exfat-file-system-33274 +/// +/// Implements detection of the exFAT filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] + +// ReSharper disable once InconsistentNaming +public sealed partial class exFAT +{ +#region Nested type: VolumeFlags + + [Flags] + enum VolumeFlags : ushort + { + SecondFatActive = 1, + VolumeDirty = 2, + MediaFailure = 4, + ClearToZero = 8 + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/exFAT/Info.cs b/Aaru.Filesystems/exFAT/Info.cs new file mode 100644 index 000000000..1b5842c41 --- /dev/null +++ b/Aaru.Filesystems/exFAT/Info.cs @@ -0,0 +1,174 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Microsoft exFAT filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from https://www.sans.org/reading-room/whitepapers/forensics/reverse-engineering-microsoft-exfat-file-system-33274 +/// +/// Implements detection of the exFAT filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] + +// ReSharper disable once InconsistentNaming +public sealed partial class exFAT +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(12 + partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] vbrSector); + + if(errno != ErrorNumber.NoError) return false; + + if(vbrSector.Length < 512) return false; + + VolumeBootRecord vbr = Marshal.ByteArrayToStructureLittleEndian(vbrSector); + + return _signature.SequenceEqual(vbr.signature); + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + + var sb = new StringBuilder(); + metadata = new FileSystem(); + + ErrorNumber errno = imagePlugin.ReadSector(0 + partition.Start, out byte[] vbrSector); + + if(errno != ErrorNumber.NoError) return; + + VolumeBootRecord vbr = Marshal.ByteArrayToStructureLittleEndian(vbrSector); + + errno = imagePlugin.ReadSector(9 + partition.Start, out byte[] parametersSector); + + if(errno != ErrorNumber.NoError) return; + + OemParameterTable parametersTable = + Marshal.ByteArrayToStructureLittleEndian(parametersSector); + + errno = imagePlugin.ReadSector(11 + partition.Start, out byte[] chkSector); + + if(errno != ErrorNumber.NoError) return; + + ChecksumSector chksector = Marshal.ByteArrayToStructureLittleEndian(chkSector); + + sb.AppendLine(Localization.Microsoft_exFAT); + sb.AppendFormat(Localization.Partition_offset_0, vbr.offset).AppendLine(); + + sb.AppendFormat(Localization.Volume_has_0_sectors_of_1_bytes_each_for_a_total_of_2_bytes, + vbr.sectors, + 1 << vbr.sectorShift, + vbr.sectors * (ulong)(1 << vbr.sectorShift)) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_uses_clusters_of_0_sectors_1_bytes_each, + 1 << vbr.clusterShift, + (1 << vbr.sectorShift) * (1 << vbr.clusterShift)) + .AppendLine(); + + sb.AppendFormat(Localization.First_FAT_starts_at_sector_0_and_runs_for_1_sectors, vbr.fatOffset, vbr.fatLength) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_uses_0_FATs, vbr.fats).AppendLine(); + + sb.AppendFormat(Localization.Cluster_heap_starts_at_sector_0_contains_1_clusters_and_is_2_used, + vbr.clusterHeapOffset, + vbr.clusterHeapLength, + vbr.heapUsage) + .AppendLine(); + + sb.AppendFormat(Localization.Root_directory_starts_at_cluster_0, vbr.rootDirectoryCluster).AppendLine(); + + sb.AppendFormat(Localization.Filesystem_revision_is_0_1, (vbr.revision & 0xFF00) >> 8, vbr.revision & 0xFF) + .AppendLine(); + + sb.AppendFormat(Localization.Volume_serial_number_0_X8, vbr.volumeSerial).AppendLine(); + sb.AppendFormat(Localization.BIOS_drive_is_0, vbr.drive).AppendLine(); + + if(vbr.flags.HasFlag(VolumeFlags.SecondFatActive)) sb.AppendLine(Localization.Second_FAT_is_in_use); + + if(vbr.flags.HasFlag(VolumeFlags.VolumeDirty)) sb.AppendLine(Localization.Volume_is_dirty); + + if(vbr.flags.HasFlag(VolumeFlags.MediaFailure)) sb.AppendLine(Localization.Underlying_media_presented_errors); + + var count = 1; + + foreach(OemParameter parameter in parametersTable.parameters) + { + if(parameter.OemParameterType == _oemFlashParameterGuid) + { + sb.AppendFormat(Localization.OEM_Parameters_0, count).AppendLine(); + sb.AppendFormat("\t" + Localization._0_bytes_in_erase_block, parameter.eraseBlockSize).AppendLine(); + sb.AppendFormat("\t" + Localization._0_bytes_per_page, parameter.pageSize).AppendLine(); + sb.AppendFormat("\t" + Localization._0_spare_blocks, parameter.spareBlocks).AppendLine(); + + sb.AppendFormat("\t" + Localization._0_nanoseconds_random_access_time, parameter.randomAccessTime) + .AppendLine(); + + sb.AppendFormat("\t" + Localization._0_nanoseconds_program_time, parameter.programTime).AppendLine(); + + sb.AppendFormat("\t" + Localization._0_nanoseconds_read_cycle_time, parameter.readCycleTime) + .AppendLine(); + + sb.AppendFormat("\t" + Localization._0_nanoseconds_write_cycle_time, parameter.writeCycleTime) + .AppendLine(); + } + else if(parameter.OemParameterType != Guid.Empty) + sb.AppendFormat(Localization.Found_unknown_parameter_type_0, parameter.OemParameterType).AppendLine(); + + count++; + } + + sb.AppendFormat(Localization.Checksum_0_X8, chksector.checksum[0]).AppendLine(); + + metadata.ClusterSize = (uint)((1 << vbr.sectorShift) * (1 << vbr.clusterShift)); + metadata.Clusters = vbr.clusterHeapLength; + metadata.Dirty = vbr.flags.HasFlag(VolumeFlags.VolumeDirty); + metadata.Type = FS_TYPE; + metadata.VolumeSerial = $"{vbr.volumeSerial:X8}"; + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/exFAT/Structs.cs b/Aaru.Filesystems/exFAT/Structs.cs new file mode 100644 index 000000000..fc372659c --- /dev/null +++ b/Aaru.Filesystems/exFAT/Structs.cs @@ -0,0 +1,120 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Microsoft exFAT filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Information from https://www.sans.org/reading-room/whitepapers/forensics/reverse-engineering-microsoft-exfat-file-system-33274 +/// +/// Implements detection of the exFAT filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] + +// ReSharper disable once InconsistentNaming +public sealed partial class exFAT +{ +#region Nested type: ChecksumSector + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct ChecksumSector + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public readonly uint[] checksum; + } + +#endregion + +#region Nested type: OemParameter + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct OemParameter + { + public readonly Guid OemParameterType; + public readonly uint eraseBlockSize; + public readonly uint pageSize; + public readonly uint spareBlocks; + public readonly uint randomAccessTime; + public readonly uint programTime; + public readonly uint readCycleTime; + public readonly uint writeCycleTime; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] reserved; + } + +#endregion + +#region Nested type: OemParameterTable + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct OemParameterTable + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public readonly OemParameter[] parameters; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] padding; + } + +#endregion + +#region Nested type: VolumeBootRecord + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct VolumeBootRecord + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public readonly byte[] jump; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public readonly byte[] signature; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 53)] + public readonly byte[] zero; + public readonly ulong offset; + public readonly ulong sectors; + public readonly uint fatOffset; + public readonly uint fatLength; + public readonly uint clusterHeapOffset; + public readonly uint clusterHeapLength; + public readonly uint rootDirectoryCluster; + public readonly uint volumeSerial; + public readonly ushort revision; + public readonly VolumeFlags flags; + public readonly byte sectorShift; + public readonly byte clusterShift; + public readonly byte fats; + public readonly byte drive; + public readonly byte heapUsage; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 53)] + public readonly byte[] reserved; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 53)] + public readonly byte[] bootCode; + public readonly ushort bootSignature; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/exFAT/exFAT.cs b/Aaru.Filesystems/exFAT/exFAT.cs new file mode 100644 index 000000000..af25bd7fe --- /dev/null +++ b/Aaru.Filesystems/exFAT/exFAT.cs @@ -0,0 +1,55 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : exFAT.cs +// Author(s) : Natalia Portillo +// +// Component : Microsoft exFAT filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from https://www.sans.org/reading-room/whitepapers/forensics/reverse-engineering-microsoft-exfat-file-system-33274 +/// +/// Implements detection of the exFAT filesystem +[SuppressMessage("ReSharper", "UnusedMember.Local")] + +// ReSharper disable once InconsistentNaming +public sealed partial class exFAT : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.exFAT_Name; + + /// + public Guid Id => new("8271D088-1533-4CB3-AC28-D802B68BB95C"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ext2FS.cs b/Aaru.Filesystems/ext2FS.cs deleted file mode 100644 index 740a899bb..000000000 --- a/Aaru.Filesystems/ext2FS.cs +++ /dev/null @@ -1,998 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : ext2FS.cs -// Author(s) : Natalia Portillo -// -// Component : Linux extended filesystem 2, 3 and 4 plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Linux extended filesystem 2, 3 and 4 and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; -using Schemas; -using Marshal = Aaru.Helpers.Marshal; - -// Information from the Linux kernel -/// -/// Implements detection of the Linux extended filesystem v2, v3 and v4 -[SuppressMessage("ReSharper", "UnusedMember.Local")] - -// ReSharper disable once InconsistentNaming -public sealed class ext2FS : IFilesystem -{ - const int SB_POS = 0x400; - - /// Same magic for ext2, ext3 and ext4 - const ushort EXT2_MAGIC = 0xEF53; - - const ushort EXT2_MAGIC_OLD = 0xEF51; - - // ext? filesystem states - /// Cleanly-unmounted volume - const ushort EXT2_VALID_FS = 0x0001; - /// Dirty volume - const ushort EXT2_ERROR_FS = 0x0002; - /// Recovering orphan files - const ushort EXT3_ORPHAN_FS = 0x0004; - - // ext? default mount flags - /// Enable debugging messages - const uint EXT2_DEFM_DEBUG = 0x000001; - /// Emulates BSD behaviour on new file creation - const uint EXT2_DEFM_BSDGROUPS = 0x000002; - /// Enable user xattrs - const uint EXT2_DEFM_XATTR_USER = 0x000004; - /// Enable POSIX ACLs - const uint EXT2_DEFM_ACL = 0x000008; - /// Use 16bit UIDs - const uint EXT2_DEFM_UID16 = 0x000010; - /// Journal data mode - const uint EXT3_DEFM_JMODE_DATA = 0x000040; - /// Journal ordered mode - const uint EXT3_DEFM_JMODE_ORDERED = 0x000080; - /// Journal writeback mode - const uint EXT3_DEFM_JMODE_WBACK = 0x000100; - - // Behaviour on errors - /// Continue execution - const ushort EXT2_ERRORS_CONTINUE = 1; - /// Remount fs read-only - const ushort EXT2_ERRORS_RO = 2; - /// Panic - const ushort EXT2_ERRORS_PANIC = 3; - - // OS codes - const uint EXT2_OS_LINUX = 0; - const uint EXT2_OS_HURD = 1; - const uint EXT2_OS_MASIX = 2; - const uint EXT2_OS_FREEBSD = 3; - const uint EXT2_OS_LITES = 4; - - // Revision levels - /// The good old (original) format - const uint EXT2_GOOD_OLD_REV = 0; - /// V2 format w/ dynamic inode sizes - const uint EXT2_DYNAMIC_REV = 1; - - // Compatible features - /// Pre-allocate directories - const uint EXT2_FEATURE_COMPAT_DIR_PREALLOC = 0x00000001; - /// imagic inodes ? - const uint EXT2_FEATURE_COMPAT_IMAGIC_INODES = 0x00000002; - /// Has journal (it's ext3) - const uint EXT3_FEATURE_COMPAT_HAS_JOURNAL = 0x00000004; - /// EA blocks - const uint EXT2_FEATURE_COMPAT_EXT_ATTR = 0x00000008; - /// Online filesystem resize reservations - const uint EXT2_FEATURE_COMPAT_RESIZE_INO = 0x00000010; - /// Can use hashed indexes on directories - const uint EXT2_FEATURE_COMPAT_DIR_INDEX = 0x00000020; - - // Read-only compatible features - /// Reduced number of superblocks - const uint EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER = 0x00000001; - /// Can have files bigger than 2GiB - const uint EXT2_FEATURE_RO_COMPAT_LARGE_FILE = 0x00000002; - /// Use B-Tree for directories - const uint EXT2_FEATURE_RO_COMPAT_BTREE_DIR = 0x00000004; - /// Can have files bigger than 2TiB *ext4* - const uint EXT4_FEATURE_RO_COMPAT_HUGE_FILE = 0x00000008; - /// Group descriptor checksums and sparse inode table *ext4* - const uint EXT4_FEATURE_RO_COMPAT_GDT_CSUM = 0x00000010; - /// More than 32000 directory entries *ext4* - const uint EXT4_FEATURE_RO_COMPAT_DIR_NLINK = 0x00000020; - /// Nanosecond timestamps and creation time *ext4* - const uint EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE = 0x00000040; - - // Incompatible features - /// Uses compression - const uint EXT2_FEATURE_INCOMPAT_COMPRESSION = 0x00000001; - /// Filetype in directory entries - const uint EXT2_FEATURE_INCOMPAT_FILETYPE = 0x00000002; - /// Journal needs recovery *ext3* - const uint EXT3_FEATURE_INCOMPAT_RECOVER = 0x00000004; - /// Has journal on another device *ext3* - const uint EXT3_FEATURE_INCOMPAT_JOURNAL_DEV = 0x00000008; - /// Reduced block group backups - const uint EXT2_FEATURE_INCOMPAT_META_BG = 0x00000010; - /// Volume use extents *ext4* - const uint EXT4_FEATURE_INCOMPAT_EXTENTS = 0x00000040; - /// Supports volumes bigger than 2^32 blocks *ext4* - - // ReSharper disable once InconsistentNaming - const uint EXT4_FEATURE_INCOMPAT_64BIT = 0x00000080; - /// Multi-mount protection *ext4* - const uint EXT4_FEATURE_INCOMPAT_MMP = 0x00000100; - /// Flexible block group metadata location *ext4* - const uint EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x00000200; - /// EA in inode *ext4* - const uint EXT4_FEATURE_INCOMPAT_EA_INODE = 0x00000400; - /// Data can reside in directory entry *ext4* - const uint EXT4_FEATURE_INCOMPAT_DIRDATA = 0x00001000; - - // Miscellaneous filesystem flags - /// Signed dirhash in use - const uint EXT2_FLAGS_SIGNED_HASH = 0x00000001; - /// Unsigned dirhash in use - const uint EXT2_FLAGS_UNSIGNED_HASH = 0x00000002; - /// Testing development code - const uint EXT2_FLAGS_TEST_FILESYS = 0x00000004; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public Encoding Encoding { get; private set; } - /// - public string Name => "Linux extended Filesystem 2, 3 and 4"; - /// - public Guid Id => new("6AA91B88-150B-4A7B-AD56-F84FB2DF4184"); - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - ulong sbSectorOff = SB_POS / imagePlugin.Info.SectorSize; - uint sbOff = SB_POS % imagePlugin.Info.SectorSize; - - if(sbSectorOff + partition.Start >= partition.End) - return false; - - int sbSizeInBytes = Marshal.SizeOf(); - var sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize); - - if(sbSizeInBytes % imagePlugin.Info.SectorSize > 0) - sbSizeInSectors++; - - ErrorNumber errno = - imagePlugin.ReadSectors(sbSectorOff + partition.Start, sbSizeInSectors, out byte[] sbSector); - - if(errno != ErrorNumber.NoError) - return false; - - var sb = new byte[sbSizeInBytes]; - - if(sbOff + sbSizeInBytes > sbSector.Length) - return false; - - Array.Copy(sbSector, sbOff, sb, 0, sbSizeInBytes); - - var magic = BitConverter.ToUInt16(sb, 0x038); - - return magic is EXT2_MAGIC or EXT2_MAGIC_OLD; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - var sb = new StringBuilder(); - - var newExt2 = false; - var ext3 = false; - var ext4 = false; - - int sbSizeInBytes = Marshal.SizeOf(); - var sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize); - - if(sbSizeInBytes % imagePlugin.Info.SectorSize > 0) - sbSizeInSectors++; - - ulong sbSectorOff = SB_POS / imagePlugin.Info.SectorSize; - uint sbOff = SB_POS % imagePlugin.Info.SectorSize; - - ErrorNumber errno = - imagePlugin.ReadSectors(sbSectorOff + partition.Start, sbSizeInSectors, out byte[] sbSector); - - if(errno != ErrorNumber.NoError) - return; - - var sblock = new byte[sbSizeInBytes]; - Array.Copy(sbSector, sbOff, sblock, 0, sbSizeInBytes); - SuperBlock supblk = Marshal.ByteArrayToStructureLittleEndian(sblock); - - XmlFsType = new FileSystemType(); - - switch(supblk.magic) - { - case EXT2_MAGIC_OLD: - sb.AppendLine("ext2 (old) filesystem"); - XmlFsType.Type = "ext2"; - - break; - case EXT2_MAGIC: - ext3 |= (supblk.ftr_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) == EXT3_FEATURE_COMPAT_HAS_JOURNAL || - (supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) == EXT3_FEATURE_INCOMPAT_RECOVER || - (supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV; - - if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) == EXT4_FEATURE_RO_COMPAT_HUGE_FILE || - (supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) == EXT4_FEATURE_RO_COMPAT_GDT_CSUM || - (supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_DIR_NLINK) == EXT4_FEATURE_RO_COMPAT_DIR_NLINK || - (supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) == EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE || - (supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_64BIT) == EXT4_FEATURE_INCOMPAT_64BIT || - (supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_MMP) == EXT4_FEATURE_INCOMPAT_MMP || - (supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) == EXT4_FEATURE_INCOMPAT_FLEX_BG || - (supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_EA_INODE) == EXT4_FEATURE_INCOMPAT_EA_INODE || - (supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA) == EXT4_FEATURE_INCOMPAT_DIRDATA) - { - ext3 = false; - ext4 = true; - } - - newExt2 |= !ext3 && !ext4; - - if(newExt2) - { - sb.AppendLine("ext2 filesystem"); - XmlFsType.Type = "ext2"; - } - - if(ext3) - { - sb.AppendLine("ext3 filesystem"); - XmlFsType.Type = "ext3"; - } - - if(ext4) - { - sb.AppendLine("ext4 filesystem"); - XmlFsType.Type = "ext4"; - } - - break; - default: - information = "Not a ext2/3/4 filesystem" + Environment.NewLine; - - return; - } - - string extOs; - - switch(supblk.creator_os) - { - case EXT2_OS_FREEBSD: - extOs = "FreeBSD"; - - break; - case EXT2_OS_HURD: - extOs = "Hurd"; - - break; - case EXT2_OS_LINUX: - extOs = "Linux"; - - break; - case EXT2_OS_LITES: - extOs = "Lites"; - - break; - case EXT2_OS_MASIX: - extOs = "MasIX"; - - break; - default: - extOs = $"Unknown OS ({supblk.creator_os})"; - - break; - } - - XmlFsType.SystemIdentifier = extOs; - - if(supblk.mkfs_t > 0) - { - sb.AppendFormat("Volume was created on {0} for {1}", DateHandlers.UnixUnsignedToDateTime(supblk.mkfs_t), - extOs).AppendLine(); - - XmlFsType.CreationDate = DateHandlers.UnixUnsignedToDateTime(supblk.mkfs_t); - XmlFsType.CreationDateSpecified = true; - } - else - sb.AppendFormat("Volume was created for {0}", extOs).AppendLine(); - - var tempBytes = new byte[8]; - ulong blocks, reserved, free; - - if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_64BIT) == EXT4_FEATURE_INCOMPAT_64BIT) - { - byte[] tempLo = BitConverter.GetBytes(supblk.blocks); - byte[] tempHi = BitConverter.GetBytes(supblk.blocks_hi); - tempBytes[0] = tempLo[0]; - tempBytes[1] = tempLo[1]; - tempBytes[2] = tempLo[2]; - tempBytes[3] = tempLo[3]; - tempBytes[4] = tempHi[0]; - tempBytes[5] = tempHi[1]; - tempBytes[6] = tempHi[2]; - tempBytes[7] = tempHi[3]; - blocks = BitConverter.ToUInt64(tempBytes, 0); - - tempLo = BitConverter.GetBytes(supblk.reserved_blocks); - tempHi = BitConverter.GetBytes(supblk.reserved_blocks_hi); - tempBytes[0] = tempLo[0]; - tempBytes[1] = tempLo[1]; - tempBytes[2] = tempLo[2]; - tempBytes[3] = tempLo[3]; - tempBytes[4] = tempHi[0]; - tempBytes[5] = tempHi[1]; - tempBytes[6] = tempHi[2]; - tempBytes[7] = tempHi[3]; - reserved = BitConverter.ToUInt64(tempBytes, 0); - - tempLo = BitConverter.GetBytes(supblk.free_blocks); - tempHi = BitConverter.GetBytes(supblk.free_blocks_hi); - tempBytes[0] = tempLo[0]; - tempBytes[1] = tempLo[1]; - tempBytes[2] = tempLo[2]; - tempBytes[3] = tempLo[3]; - tempBytes[4] = tempHi[0]; - tempBytes[5] = tempHi[1]; - tempBytes[6] = tempHi[2]; - tempBytes[7] = tempHi[3]; - free = BitConverter.ToUInt64(tempBytes, 0); - } - else - { - blocks = supblk.blocks; - reserved = supblk.reserved_blocks; - free = supblk.free_blocks; - } - - if(supblk.block_size == 0) // Then it is 1024 bytes - supblk.block_size = 1024; - - sb.AppendFormat("Volume has {0} blocks of {1} bytes, for a total of {2} bytes", blocks, - 1024 << (int)supblk.block_size, blocks * (ulong)(1024 << (int)supblk.block_size)).AppendLine(); - - XmlFsType.Clusters = blocks; - XmlFsType.ClusterSize = (uint)(1024 << (int)supblk.block_size); - - if(supblk.mount_t > 0 || - supblk.mount_c > 0) - { - if(supblk.mount_t > 0) - sb.AppendFormat("Last mounted on {0}", DateHandlers.UnixUnsignedToDateTime(supblk.mount_t)). - AppendLine(); - - if(supblk.max_mount_c != -1) - sb.AppendFormat("Volume has been mounted {0} times of a maximum of {1} mounts before checking", - supblk.mount_c, supblk.max_mount_c).AppendLine(); - else - sb.AppendFormat("Volume has been mounted {0} times with no maximum no. of mounts before checking", - supblk.mount_c).AppendLine(); - - if(!string.IsNullOrEmpty(StringHandlers.CToString(supblk.last_mount_dir, Encoding))) - sb.AppendFormat("Last mounted on: \"{0}\"", StringHandlers.CToString(supblk.last_mount_dir, Encoding)). - AppendLine(); - - if(!string.IsNullOrEmpty(StringHandlers.CToString(supblk.mount_options, Encoding))) - sb.AppendFormat("Last used mount options were: {0}", - StringHandlers.CToString(supblk.mount_options, Encoding)).AppendLine(); - } - else - { - sb.AppendLine("Volume has never been mounted"); - - if(supblk.max_mount_c != -1) - sb.AppendFormat("Volume can be mounted {0} times before checking", supblk.max_mount_c).AppendLine(); - else - sb.AppendLine("Volume has no maximum no. of mounts before checking"); - } - - if(supblk.check_t > 0) - if(supblk.check_inv > 0) - sb.AppendFormat("Last checked on {0} (should check every {1} seconds)", - DateHandlers.UnixUnsignedToDateTime(supblk.check_t), supblk.check_inv).AppendLine(); - else - sb.AppendFormat("Last checked on {0}", DateHandlers.UnixUnsignedToDateTime(supblk.check_t)). - AppendLine(); - else - { - if(supblk.check_inv > 0) - sb.AppendFormat("Volume has never been checked (should check every {0})", supblk.check_inv). - AppendLine(); - else - sb.AppendLine("Volume has never been checked"); - } - - if(supblk.write_t > 0) - { - sb.AppendFormat("Last written on {0}", DateHandlers.UnixUnsignedToDateTime(supblk.write_t)).AppendLine(); - - XmlFsType.ModificationDate = DateHandlers.UnixUnsignedToDateTime(supblk.write_t); - XmlFsType.ModificationDateSpecified = true; - } - else - sb.AppendLine("Volume has never been written"); - - XmlFsType.Dirty = true; - - switch(supblk.state) - { - case EXT2_VALID_FS: - sb.AppendLine("Volume is clean"); - XmlFsType.Dirty = false; - - break; - case EXT2_ERROR_FS: - sb.AppendLine("Volume is dirty"); - - break; - case EXT3_ORPHAN_FS: - sb.AppendLine("Volume is recovering orphan files"); - - break; - default: - sb.AppendFormat("Volume is in an unknown state ({0})", supblk.state).AppendLine(); - - break; - } - - if(!string.IsNullOrEmpty(StringHandlers.CToString(supblk.volume_name, Encoding))) - { - sb.AppendFormat("Volume name: \"{0}\"", StringHandlers.CToString(supblk.volume_name, Encoding)). - AppendLine(); - - XmlFsType.VolumeName = StringHandlers.CToString(supblk.volume_name, Encoding); - } - - switch(supblk.err_behaviour) - { - case EXT2_ERRORS_CONTINUE: - sb.AppendLine("On errors, filesystem should continue"); - - break; - case EXT2_ERRORS_RO: - sb.AppendLine("On errors, filesystem should remount read-only"); - - break; - case EXT2_ERRORS_PANIC: - sb.AppendLine("On errors, filesystem should panic"); - - break; - default: - sb.AppendFormat("On errors filesystem will do an unknown thing ({0})", supblk.err_behaviour). - AppendLine(); - - break; - } - - if(supblk.revision > 0) - sb.AppendFormat("Filesystem revision: {0}.{1}", supblk.revision, supblk.minor_revision).AppendLine(); - - if(supblk.uuid != Guid.Empty) - { - sb.AppendFormat("Volume UUID: {0}", supblk.uuid).AppendLine(); - XmlFsType.VolumeSerial = supblk.uuid.ToString(); - } - - if(supblk.kbytes_written > 0) - sb.AppendFormat("{0} KiB has been written on volume", supblk.kbytes_written).AppendLine(); - - sb.AppendFormat("{0} reserved and {1} free blocks", reserved, free).AppendLine(); - XmlFsType.FreeClusters = free; - XmlFsType.FreeClustersSpecified = true; - - sb.AppendFormat("{0} inodes with {1} free inodes ({2}%)", supblk.inodes, supblk.free_inodes, - supblk.free_inodes * 100 / supblk.inodes).AppendLine(); - - if(supblk.first_inode > 0) - sb.AppendFormat("First inode is {0}", supblk.first_inode).AppendLine(); - - if(supblk.frag_size > 0) - sb.AppendFormat("{0} bytes per fragment", supblk.frag_size).AppendLine(); - - if(supblk.blocks_per_grp > 0 && - supblk.flags_per_grp > 0 && - supblk.inodes_per_grp > 0) - sb.AppendFormat("{0} blocks, {1} flags and {2} inodes per group", supblk.blocks_per_grp, - supblk.flags_per_grp, supblk.inodes_per_grp).AppendLine(); - - if(supblk.first_block > 0) - sb.AppendFormat("{0} is first data block", supblk.first_block).AppendLine(); - - sb.AppendFormat("Default UID: {0}, GID: {1}", supblk.default_uid, supblk.default_gid).AppendLine(); - - if(supblk.block_group_no > 0) - sb.AppendFormat("Block group number is {0}", supblk.block_group_no).AppendLine(); - - if(supblk.desc_grp_size > 0) - sb.AppendFormat("Group descriptor size is {0} bytes", supblk.desc_grp_size).AppendLine(); - - if(supblk.first_meta_bg > 0) - sb.AppendFormat("First metablock group is {0}", supblk.first_meta_bg).AppendLine(); - - if(supblk.raid_stride > 0) - sb.AppendFormat("RAID stride: {0}", supblk.raid_stride).AppendLine(); - - if(supblk.raid_stripe_width > 0) - sb.AppendFormat("{0} blocks on all data disks", supblk.raid_stripe_width).AppendLine(); - - if(supblk.mmp_interval > 0 && - supblk.mmp_block > 0) - sb.AppendFormat("{0} seconds for multi-mount protection wait, on block {1}", supblk.mmp_interval, - supblk.mmp_block).AppendLine(); - - if(supblk.flex_bg_grp_size > 0) - sb.AppendFormat("{0} Flexible block group size", supblk.flex_bg_grp_size).AppendLine(); - - if(supblk.hash_seed_1 > 0 && - supblk.hash_seed_2 > 0 && - supblk.hash_seed_3 > 0 && - supblk.hash_seed_4 > 0) - sb.AppendFormat("Hash seed: {0:X8}{1:X8}{2:X8}{3:X8}, version {4}", supblk.hash_seed_1, supblk.hash_seed_2, - supblk.hash_seed_3, supblk.hash_seed_4, supblk.hash_version).AppendLine(); - - if((supblk.ftr_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) == EXT3_FEATURE_COMPAT_HAS_JOURNAL || - (supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) - { - sb.AppendLine("Volume is journaled"); - - if(supblk.journal_uuid != Guid.Empty) - sb.AppendFormat("Journal UUID: {0}", supblk.journal_uuid).AppendLine(); - - sb.AppendFormat("Journal has inode {0}", supblk.journal_inode).AppendLine(); - - if((supblk.ftr_compat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV && - supblk.journal_dev > 0) - sb.AppendFormat("Journal is on device {0}", supblk.journal_dev).AppendLine(); - - if(supblk.jnl_backup_type > 0) - sb.AppendFormat("Journal backup type: {0}", supblk.jnl_backup_type).AppendLine(); - - if(supblk.last_orphan > 0) - sb.AppendFormat("Last orphaned inode is {0}", supblk.last_orphan).AppendLine(); - else - sb.AppendLine("There are no orphaned inodes"); - } - - if(ext4) - { - if(supblk.snapshot_id > 0) - sb. - AppendFormat("Active snapshot has ID {0}, on inode {1}, with {2} blocks reserved, list starting on block {3}", - supblk.snapshot_id, supblk.snapshot_inum, supblk.snapshot_blocks, - supblk.snapshot_list).AppendLine(); - - if(supblk.error_count > 0) - { - sb.AppendFormat("{0} errors registered", supblk.error_count).AppendLine(); - - sb.AppendFormat("First error occurred on {0}, last on {1}", - DateHandlers.UnixUnsignedToDateTime(supblk.first_error_t), - DateHandlers.UnixUnsignedToDateTime(supblk.last_error_t)).AppendLine(); - - sb.AppendFormat("First error inode is {0}, last is {1}", supblk.first_error_inode, - supblk.last_error_inode).AppendLine(); - - sb.AppendFormat("First error block is {0}, last is {1}", supblk.first_error_block, - supblk.last_error_block).AppendLine(); - - sb.AppendFormat("First error function is \"{0}\", last is \"{1}\"", supblk.first_error_func, - supblk.last_error_func).AppendLine(); - } - } - - sb.AppendFormat("Flags…:").AppendLine(); - - if((supblk.flags & EXT2_FLAGS_SIGNED_HASH) == EXT2_FLAGS_SIGNED_HASH) - sb.AppendLine("Signed directory hash is in use"); - - if((supblk.flags & EXT2_FLAGS_UNSIGNED_HASH) == EXT2_FLAGS_UNSIGNED_HASH) - sb.AppendLine("Unsigned directory hash is in use"); - - if((supblk.flags & EXT2_FLAGS_TEST_FILESYS) == EXT2_FLAGS_TEST_FILESYS) - sb.AppendLine("Volume is testing development code"); - - if((supblk.flags & 0xFFFFFFF8) != 0) - sb.AppendFormat("Unknown set flags: {0:X8}", supblk.flags); - - sb.AppendLine(); - - sb.AppendFormat("Default mount options…:").AppendLine(); - - if((supblk.default_mnt_opts & EXT2_DEFM_DEBUG) == EXT2_DEFM_DEBUG) - sb.AppendLine("(debug): Enable debugging code"); - - if((supblk.default_mnt_opts & EXT2_DEFM_BSDGROUPS) == EXT2_DEFM_BSDGROUPS) - sb.AppendLine("(bsdgroups): Emulate BSD behaviour when creating new files"); - - if((supblk.default_mnt_opts & EXT2_DEFM_XATTR_USER) == EXT2_DEFM_XATTR_USER) - sb.AppendLine("(user_xattr): Enable user-specified extended attributes"); - - if((supblk.default_mnt_opts & EXT2_DEFM_ACL) == EXT2_DEFM_ACL) - sb.AppendLine("(acl): Enable POSIX ACLs"); - - if((supblk.default_mnt_opts & EXT2_DEFM_UID16) == EXT2_DEFM_UID16) - sb.AppendLine("(uid16): Disable 32bit UIDs and GIDs"); - - if((supblk.default_mnt_opts & EXT3_DEFM_JMODE_DATA) == EXT3_DEFM_JMODE_DATA) - sb.AppendLine("(journal_data): Journal data and metadata"); - - if((supblk.default_mnt_opts & EXT3_DEFM_JMODE_ORDERED) == EXT3_DEFM_JMODE_ORDERED) - sb.AppendLine("(journal_data_ordered): Write data before journaling metadata"); - - if((supblk.default_mnt_opts & EXT3_DEFM_JMODE_WBACK) == EXT3_DEFM_JMODE_WBACK) - sb.AppendLine("(journal_data_writeback): Write journal before data"); - - if((supblk.default_mnt_opts & 0xFFFFFE20) != 0) - sb.AppendFormat("Unknown set default mount options: {0:X8}", supblk.default_mnt_opts); - - sb.AppendLine(); - - sb.AppendFormat("Compatible features…:").AppendLine(); - - if((supblk.ftr_compat & EXT2_FEATURE_COMPAT_DIR_PREALLOC) == EXT2_FEATURE_COMPAT_DIR_PREALLOC) - sb.AppendLine("Pre-allocate directories"); - - if((supblk.ftr_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES) == EXT2_FEATURE_COMPAT_IMAGIC_INODES) - sb.AppendLine("imagic inodes ?"); - - if((supblk.ftr_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) == EXT3_FEATURE_COMPAT_HAS_JOURNAL) - sb.AppendLine("Has journal (ext3)"); - - if((supblk.ftr_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) == EXT2_FEATURE_COMPAT_EXT_ATTR) - sb.AppendLine("Has extended attribute blocks"); - - if((supblk.ftr_compat & EXT2_FEATURE_COMPAT_RESIZE_INO) == EXT2_FEATURE_COMPAT_RESIZE_INO) - sb.AppendLine("Has online filesystem resize reservations"); - - if((supblk.ftr_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) == EXT2_FEATURE_COMPAT_DIR_INDEX) - sb.AppendLine("Can use hashed indexes on directories"); - - if((supblk.ftr_compat & 0xFFFFFFC0) != 0) - sb.AppendFormat("Unknown compatible features: {0:X8}", supblk.ftr_compat); - - sb.AppendLine(); - - sb.AppendFormat("Compatible features if read-only…:").AppendLine(); - - if((supblk.ftr_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) == EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) - sb.AppendLine("Reduced number of superblocks"); - - if((supblk.ftr_ro_compat & EXT2_FEATURE_RO_COMPAT_LARGE_FILE) == EXT2_FEATURE_RO_COMPAT_LARGE_FILE) - sb.AppendLine("Can have files bigger than 2GiB"); - - if((supblk.ftr_ro_compat & EXT2_FEATURE_RO_COMPAT_BTREE_DIR) == EXT2_FEATURE_RO_COMPAT_BTREE_DIR) - sb.AppendLine("Uses B-Tree for directories"); - - if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) == EXT4_FEATURE_RO_COMPAT_HUGE_FILE) - sb.AppendLine("Can have files bigger than 2TiB (ext4)"); - - if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) == EXT4_FEATURE_RO_COMPAT_GDT_CSUM) - sb.AppendLine("Group descriptor checksums and sparse inode table (ext4)"); - - if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_DIR_NLINK) == EXT4_FEATURE_RO_COMPAT_DIR_NLINK) - sb.AppendLine("More than 32000 directory entries (ext4)"); - - if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) == EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) - sb.AppendLine("Supports nanosecond timestamps and creation time (ext4)"); - - if((supblk.ftr_ro_compat & 0xFFFFFF80) != 0) - sb.AppendFormat("Unknown read-only compatible features: {0:X8}", supblk.ftr_ro_compat); - - sb.AppendLine(); - - sb.AppendFormat("Incompatible features…:").AppendLine(); - - if((supblk.ftr_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) == EXT2_FEATURE_INCOMPAT_COMPRESSION) - sb.AppendLine("Uses compression"); - - if((supblk.ftr_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE) == EXT2_FEATURE_INCOMPAT_FILETYPE) - sb.AppendLine("Filetype in directory entries"); - - if((supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) == EXT3_FEATURE_INCOMPAT_RECOVER) - sb.AppendLine("Journal needs recovery (ext3)"); - - if((supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) - sb.AppendLine("Has journal on another device (ext3)"); - - if((supblk.ftr_incompat & EXT2_FEATURE_INCOMPAT_META_BG) == EXT2_FEATURE_INCOMPAT_META_BG) - sb.AppendLine("Reduced block group backups"); - - if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_EXTENTS) == EXT4_FEATURE_INCOMPAT_EXTENTS) - sb.AppendLine("Volume use extents (ext4)"); - - if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_64BIT) == EXT4_FEATURE_INCOMPAT_64BIT) - sb.AppendLine("Supports volumes bigger than 2^32 blocks (ext4)"); - - if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_MMP) == EXT4_FEATURE_INCOMPAT_MMP) - sb.AppendLine("Multi-mount protection (ext4)"); - - if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) == EXT4_FEATURE_INCOMPAT_FLEX_BG) - sb.AppendLine("Flexible block group metadata location (ext4)"); - - if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_EA_INODE) == EXT4_FEATURE_INCOMPAT_EA_INODE) - sb.AppendLine("Extended attributes can reside in inode (ext4)"); - - if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA) == EXT4_FEATURE_INCOMPAT_DIRDATA) - sb.AppendLine("Data can reside in directory entry (ext4)"); - - if((supblk.ftr_incompat & 0xFFFFF020) != 0) - sb.AppendFormat("Unknown incompatible features: {0:X8}", supblk.ftr_incompat); - - information = sb.ToString(); - } - - /// ext2/3/4 superblock - [StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "InconsistentNaming")] - struct SuperBlock - { - /// 0x000, inodes on volume - public readonly uint inodes; - /// 0x004, blocks on volume - public readonly uint blocks; - /// 0x008, reserved blocks - public readonly uint reserved_blocks; - /// 0x00C, free blocks count - public readonly uint free_blocks; - /// 0x010, free inodes count - public readonly uint free_inodes; - /// 0x014, first data block - public readonly uint first_block; - /// 0x018, block size - public uint block_size; - /// 0x01C, fragment size - public readonly int frag_size; - /// 0x020, blocks per group - public readonly uint blocks_per_grp; - /// 0x024, fragments per group - public readonly uint flags_per_grp; - /// 0x028, inodes per group - public readonly uint inodes_per_grp; - /// 0x02C, last mount time - public readonly uint mount_t; - /// 0x030, last write time - public readonly uint write_t; - /// 0x034, mounts count - public readonly ushort mount_c; - /// 0x036, max mounts - public readonly short max_mount_c; - /// 0x038, (little endian) - public readonly ushort magic; - /// 0x03A, filesystem state - public readonly ushort state; - /// 0x03C, behaviour on errors - public readonly ushort err_behaviour; - /// 0x03E, From 0.5b onward - public readonly ushort minor_revision; - /// 0x040, last check time - public readonly uint check_t; - /// 0x044, max time between checks - public readonly uint check_inv; - - // From 0.5a onward - /// 0x048, Creation OS - public readonly uint creator_os; - /// 0x04C, Revison level - public readonly uint revision; - /// 0x050, Default UID for reserved blocks - public readonly ushort default_uid; - /// 0x052, Default GID for reserved blocks - public readonly ushort default_gid; - - // From 0.5b onward - /// 0x054, First unreserved inode - public readonly uint first_inode; - /// 0x058, inode size - public readonly ushort inode_size; - /// 0x05A, Block group number of THIS superblock - public readonly ushort block_group_no; - /// 0x05C, Compatible features set - public readonly uint ftr_compat; - /// 0x060, Incompatible features set - public readonly uint ftr_incompat; - - // Found on Linux 2.0.40 - /// 0x064, Read-only compatible features set - public readonly uint ftr_ro_compat; - - // Found on Linux 2.1.132 - /// 0x068, 16 bytes, UUID - public readonly Guid uuid; - /// 0x078, 16 bytes, volume name - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] volume_name; - /// 0x088, 64 bytes, where last mounted - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] last_mount_dir; - /// 0x0C8, Usage bitmap algorithm, for compression - public readonly uint algo_usage_bmp; - /// 0x0CC, Block to try to preallocate - public readonly byte prealloc_blks; - /// 0x0CD, Blocks to try to preallocate for directories - public readonly byte prealloc_dir_blks; - /// 0x0CE, Per-group desc for online growth - public readonly ushort rsrvd_gdt_blocks; - - // Found on Linux 2.4 - // ext3 - /// 0x0D0, 16 bytes, UUID of journal superblock - public readonly Guid journal_uuid; - /// 0x0E0, inode no. of journal file - public readonly uint journal_inode; - /// 0x0E4, device no. of journal file - public readonly uint journal_dev; - /// 0x0E8, Start of list of inodes to delete - public readonly uint last_orphan; - /// 0x0EC, First byte of 128bit HTREE hash seed - public readonly uint hash_seed_1; - /// 0x0F0, Second byte of 128bit HTREE hash seed - public readonly uint hash_seed_2; - /// 0x0F4, Third byte of 128bit HTREE hash seed - public readonly uint hash_seed_3; - /// 0x0F8, Fourth byte of 128bit HTREE hash seed - public readonly uint hash_seed_4; - /// 0x0FC, Hash version - public readonly byte hash_version; - /// 0x0FD, Journal backup type - public readonly byte jnl_backup_type; - /// 0x0FE, Size of group descriptor - public readonly ushort desc_grp_size; - /// 0x100, Default mount options - public readonly uint default_mnt_opts; - /// 0x104, First metablock block group - public readonly uint first_meta_bg; - - // Introduced with ext4, some can be ext3 - /// 0x108, Filesystem creation time - public readonly uint mkfs_t; - - /// Backup of the journal inode - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public readonly uint[] jnl_blocks; - - // Following 3 fields are valid if EXT4_FEATURE_COMPAT_64BIT is set - /// 0x14C, High 32bits of blocks no. - public readonly uint blocks_hi; - /// 0x150, High 32bits of reserved blocks no. - public readonly uint reserved_blocks_hi; - /// 0x154, High 32bits of free blocks no. - public readonly uint free_blocks_hi; - /// 0x158, inodes minimal size in bytes - public readonly ushort min_inode_size; - /// 0x15A, Bytes reserved by new inodes - public readonly ushort rsv_inode_size; - /// 0x15C, Flags - public readonly uint flags; - /// 0x160, RAID stride - public readonly ushort raid_stride; - /// 0x162, Waiting seconds in MMP check - public readonly ushort mmp_interval; - /// 0x164, Block for multi-mount protection - public readonly ulong mmp_block; - /// 0x16C, Blocks on all data disks (N*stride) - public readonly uint raid_stripe_width; - /// 0x170, FLEX_BG group size - public readonly byte flex_bg_grp_size; - /// 0x171 Metadata checksum algorithm - public readonly byte checksum_type; - /// 0x172 Versioning level for encryption - public readonly byte encryption_level; - /// 0x173 Padding - public readonly ushort padding; - - // Following are introduced with ext4 - /// 0x174, Kibibytes written in volume lifetime - public readonly ulong kbytes_written; - /// 0x17C, Active snapshot inode number - public readonly uint snapshot_inum; - /// 0x180, Active snapshot sequential ID - public readonly uint snapshot_id; - /// 0x184, Reserved blocks for active snapshot's future use - public readonly ulong snapshot_blocks; - /// 0x18C, inode number of the on-disk start of the snapshot list - public readonly uint snapshot_list; - - // Optional ext4 error-handling features - /// 0x190, total registered filesystem errors - public readonly uint error_count; - /// 0x194, time on first error - public readonly uint first_error_t; - /// 0x198, inode involved in first error - public readonly uint first_error_inode; - /// 0x19C, block involved of first error - public readonly ulong first_error_block; - /// 0x1A0, 32 bytes, function where the error happened - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] first_error_func; - /// 0x1B0, line number where error happened - public readonly uint first_error_line; - /// 0x1B4, time of most recent error - public readonly uint last_error_t; - /// 0x1B8, inode involved in last error - public readonly uint last_error_inode; - /// 0x1BC, line number where error happened - public readonly uint last_error_line; - /// 0x1C0, block involved of last error - public readonly ulong last_error_block; - /// 0x1C8, 32 bytes, function where the error happened - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public readonly byte[] last_error_func; - - // End of optional error-handling features - - // 0x1D8, 64 bytes, last used mount options
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public readonly byte[] mount_options; - - /// Inode for user quota - public readonly uint usr_quota_inum; - /// Inode for group quota - public readonly uint grp_quota_inum; - /// Overhead clusters in volume - public readonly uint overhead_clusters; - /// Groups with sparse_super2 SBs - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public readonly uint[] backup_bgs; - /// Encryption algorithms in use - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public readonly byte[] encrypt_algos; - /// Salt used for string2key algorithm - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] encrypt_pw_salt; - /// Inode number of lost+found - public readonly uint lpf_inum; - /// Inode number for tracking project quota - public readonly uint prj_quota_inum; - /// crc32c(uuid) if csum_seed is set - public readonly uint checksum_seed; - /// Reserved - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 98)] - public readonly byte[] reserved; - /// crc32c(superblock) - public readonly uint checksum; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/ext2FS/Consts.cs b/Aaru.Filesystems/ext2FS/Consts.cs new file mode 100644 index 000000000..81cd6c2eb --- /dev/null +++ b/Aaru.Filesystems/ext2FS/Consts.cs @@ -0,0 +1,166 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Linux extended filesystem 2, 3 and 4 plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Linux extended filesystem 2, 3 and 4 and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the Linux extended filesystem v2, v3 and v4 +[SuppressMessage("ReSharper", "UnusedMember.Local")] + +// ReSharper disable once InconsistentNaming +public sealed partial class ext2FS +{ + const int SB_POS = 0x400; + + /// Same magic for ext2, ext3 and ext4 + const ushort EXT2_MAGIC = 0xEF53; + + const ushort EXT2_MAGIC_OLD = 0xEF51; + + // ext? filesystem states + /// Cleanly-unmounted volume + const ushort EXT2_VALID_FS = 0x0001; + /// Dirty volume + const ushort EXT2_ERROR_FS = 0x0002; + /// Recovering orphan files + const ushort EXT3_ORPHAN_FS = 0x0004; + + // ext? default mount flags + /// Enable debugging messages + const uint EXT2_DEFM_DEBUG = 0x000001; + /// Emulates BSD behaviour on new file creation + const uint EXT2_DEFM_BSDGROUPS = 0x000002; + /// Enable user xattrs + const uint EXT2_DEFM_XATTR_USER = 0x000004; + /// Enable POSIX ACLs + const uint EXT2_DEFM_ACL = 0x000008; + /// Use 16bit UIDs + const uint EXT2_DEFM_UID16 = 0x000010; + /// Journal data mode + const uint EXT3_DEFM_JMODE_DATA = 0x000040; + /// Journal ordered mode + const uint EXT3_DEFM_JMODE_ORDERED = 0x000080; + /// Journal writeback mode + const uint EXT3_DEFM_JMODE_WBACK = 0x000100; + + // Behaviour on errors + /// Continue execution + const ushort EXT2_ERRORS_CONTINUE = 1; + /// Remount fs read-only + const ushort EXT2_ERRORS_RO = 2; + /// Panic + const ushort EXT2_ERRORS_PANIC = 3; + + // OS codes + const uint EXT2_OS_LINUX = 0; + const uint EXT2_OS_HURD = 1; + const uint EXT2_OS_MASIX = 2; + const uint EXT2_OS_FREEBSD = 3; + const uint EXT2_OS_LITES = 4; + + // Revision levels + /// The good old (original) format + const uint EXT2_GOOD_OLD_REV = 0; + /// V2 format w/ dynamic inode sizes + const uint EXT2_DYNAMIC_REV = 1; + + // Compatible features + /// Pre-allocate directories + const uint EXT2_FEATURE_COMPAT_DIR_PREALLOC = 0x00000001; + /// imagic inodes ? + const uint EXT2_FEATURE_COMPAT_IMAGIC_INODES = 0x00000002; + /// Has journal (it's ext3) + const uint EXT3_FEATURE_COMPAT_HAS_JOURNAL = 0x00000004; + /// EA blocks + const uint EXT2_FEATURE_COMPAT_EXT_ATTR = 0x00000008; + /// Online filesystem resize reservations + const uint EXT2_FEATURE_COMPAT_RESIZE_INO = 0x00000010; + /// Can use hashed indexes on directories + const uint EXT2_FEATURE_COMPAT_DIR_INDEX = 0x00000020; + + // Read-only compatible features + /// Reduced number of superblocks + const uint EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER = 0x00000001; + /// Can have files bigger than 2GiB + const uint EXT2_FEATURE_RO_COMPAT_LARGE_FILE = 0x00000002; + /// Use B-Tree for directories + const uint EXT2_FEATURE_RO_COMPAT_BTREE_DIR = 0x00000004; + /// Can have files bigger than 2TiB *ext4* + const uint EXT4_FEATURE_RO_COMPAT_HUGE_FILE = 0x00000008; + /// Group descriptor checksums and sparse inode table *ext4* + const uint EXT4_FEATURE_RO_COMPAT_GDT_CSUM = 0x00000010; + /// More than 32000 directory entries *ext4* + const uint EXT4_FEATURE_RO_COMPAT_DIR_NLINK = 0x00000020; + /// Nanosecond timestamps and creation time *ext4* + const uint EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE = 0x00000040; + + // Incompatible features + /// Uses compression + const uint EXT2_FEATURE_INCOMPAT_COMPRESSION = 0x00000001; + /// Filetype in directory entries + const uint EXT2_FEATURE_INCOMPAT_FILETYPE = 0x00000002; + /// Journal needs recovery *ext3* + const uint EXT3_FEATURE_INCOMPAT_RECOVER = 0x00000004; + /// Has journal on another device *ext3* + const uint EXT3_FEATURE_INCOMPAT_JOURNAL_DEV = 0x00000008; + /// Reduced block group backups + const uint EXT2_FEATURE_INCOMPAT_META_BG = 0x00000010; + /// Volume use extents *ext4* + const uint EXT4_FEATURE_INCOMPAT_EXTENTS = 0x00000040; + /// Supports volumes bigger than 2^32 blocks *ext4* + + // ReSharper disable once InconsistentNaming + const uint EXT4_FEATURE_INCOMPAT_64BIT = 0x00000080; + /// Multi-mount protection *ext4* + const uint EXT4_FEATURE_INCOMPAT_MMP = 0x00000100; + /// Flexible block group metadata location *ext4* + const uint EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x00000200; + /// EA in inode *ext4* + const uint EXT4_FEATURE_INCOMPAT_EA_INODE = 0x00000400; + /// Data can reside in directory entry *ext4* + const uint EXT4_FEATURE_INCOMPAT_DIRDATA = 0x00001000; + + // Miscellaneous filesystem flags + /// Signed dirhash in use + const uint EXT2_FLAGS_SIGNED_HASH = 0x00000001; + /// Unsigned dirhash in use + const uint EXT2_FLAGS_UNSIGNED_HASH = 0x00000002; + /// Testing development code + const uint EXT2_FLAGS_TEST_FILESYS = 0x00000004; + + const string FS_TYPE_EXT2 = "ext2"; + const string FS_TYPE_EXT3 = "ext3"; + const string FS_TYPE_EXT4 = "ext4"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/ext2FS/Info.cs b/Aaru.Filesystems/ext2FS/Info.cs new file mode 100644 index 000000000..6a061d046 --- /dev/null +++ b/Aaru.Filesystems/ext2FS/Info.cs @@ -0,0 +1,669 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Linux extended filesystem 2, 3 and 4 plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Linux extended filesystem 2, 3 and 4 and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the Linux extended filesystem v2, v3 and v4 +[SuppressMessage("ReSharper", "UnusedMember.Local")] + +// ReSharper disable once InconsistentNaming +public sealed partial class ext2FS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + ulong sbSectorOff = SB_POS / imagePlugin.Info.SectorSize; + uint sbOff = SB_POS % imagePlugin.Info.SectorSize; + + if(sbSectorOff + partition.Start >= partition.End) return false; + + int sbSizeInBytes = Marshal.SizeOf(); + var sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize); + + if(sbSizeInBytes % imagePlugin.Info.SectorSize > 0) sbSizeInSectors++; + + ErrorNumber errno = + imagePlugin.ReadSectors(sbSectorOff + partition.Start, sbSizeInSectors, out byte[] sbSector); + + if(errno != ErrorNumber.NoError) return false; + + var sb = new byte[sbSizeInBytes]; + + if(sbOff + sbSizeInBytes > sbSector.Length) return false; + + Array.Copy(sbSector, sbOff, sb, 0, sbSizeInBytes); + + var magic = BitConverter.ToUInt16(sb, 0x038); + + return magic is EXT2_MAGIC or EXT2_MAGIC_OLD; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + encoding ??= Encoding.GetEncoding("iso-8859-15"); + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + var newExt2 = false; + var ext3 = false; + var ext4 = false; + + int sbSizeInBytes = Marshal.SizeOf(); + var sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize); + + if(sbSizeInBytes % imagePlugin.Info.SectorSize > 0) sbSizeInSectors++; + + ulong sbSectorOff = SB_POS / imagePlugin.Info.SectorSize; + uint sbOff = SB_POS % imagePlugin.Info.SectorSize; + + ErrorNumber errno = + imagePlugin.ReadSectors(sbSectorOff + partition.Start, sbSizeInSectors, out byte[] sbSector); + + if(errno != ErrorNumber.NoError) return; + + var sblock = new byte[sbSizeInBytes]; + Array.Copy(sbSector, sbOff, sblock, 0, sbSizeInBytes); + SuperBlock supblk = Marshal.ByteArrayToStructureLittleEndian(sblock); + + metadata = new FileSystem(); + + switch(supblk.magic) + { + case EXT2_MAGIC_OLD: + sb.AppendLine(Localization.ext2_old_filesystem); + metadata.Type = FS_TYPE_EXT2; + + break; + case EXT2_MAGIC: + ext3 |= (supblk.ftr_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) == EXT3_FEATURE_COMPAT_HAS_JOURNAL || + (supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) == EXT3_FEATURE_INCOMPAT_RECOVER || + (supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV; + + if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) == EXT4_FEATURE_RO_COMPAT_HUGE_FILE || + (supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) == EXT4_FEATURE_RO_COMPAT_GDT_CSUM || + (supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_DIR_NLINK) == EXT4_FEATURE_RO_COMPAT_DIR_NLINK || + (supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) == EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE || + (supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_64BIT) == EXT4_FEATURE_INCOMPAT_64BIT || + (supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_MMP) == EXT4_FEATURE_INCOMPAT_MMP || + (supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) == EXT4_FEATURE_INCOMPAT_FLEX_BG || + (supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_EA_INODE) == EXT4_FEATURE_INCOMPAT_EA_INODE || + (supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA) == EXT4_FEATURE_INCOMPAT_DIRDATA) + { + ext3 = false; + ext4 = true; + } + + newExt2 |= !ext3 && !ext4; + + if(newExt2) + { + sb.AppendLine(Localization.ext2_filesystem); + metadata.Type = FS_TYPE_EXT2; + } + + if(ext3) + { + sb.AppendLine(Localization.ext3_filesystem); + metadata.Type = FS_TYPE_EXT3; + } + + if(ext4) + { + sb.AppendLine(Localization.ext4_filesystem); + metadata.Type = FS_TYPE_EXT4; + } + + break; + default: + information = Localization.Not_an_ext2_3_4_filesystem + Environment.NewLine; + + return; + } + + string extOs = supblk.creator_os switch + { + EXT2_OS_FREEBSD => "FreeBSD", + EXT2_OS_HURD => "Hurd", + EXT2_OS_LINUX => "Linux", + EXT2_OS_LITES => "Lites", + EXT2_OS_MASIX => "MasIX", + _ => string.Format(Localization.Unknown_OS_0, supblk.creator_os) + }; + + metadata.SystemIdentifier = extOs; + + if(supblk.mkfs_t > 0) + { + sb.AppendFormat(Localization.Volume_was_created_on_0_for_1, + DateHandlers.UnixUnsignedToDateTime(supblk.mkfs_t), + extOs) + .AppendLine(); + + metadata.CreationDate = DateHandlers.UnixUnsignedToDateTime(supblk.mkfs_t); + } + else + sb.AppendFormat(Localization.Volume_was_created_for_0, extOs).AppendLine(); + + var tempBytes = new byte[8]; + ulong blocks, reserved, free; + + if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_64BIT) == EXT4_FEATURE_INCOMPAT_64BIT) + { + byte[] tempLo = BitConverter.GetBytes(supblk.blocks); + byte[] tempHi = BitConverter.GetBytes(supblk.blocks_hi); + tempBytes[0] = tempLo[0]; + tempBytes[1] = tempLo[1]; + tempBytes[2] = tempLo[2]; + tempBytes[3] = tempLo[3]; + tempBytes[4] = tempHi[0]; + tempBytes[5] = tempHi[1]; + tempBytes[6] = tempHi[2]; + tempBytes[7] = tempHi[3]; + blocks = BitConverter.ToUInt64(tempBytes, 0); + + tempLo = BitConverter.GetBytes(supblk.reserved_blocks); + tempHi = BitConverter.GetBytes(supblk.reserved_blocks_hi); + tempBytes[0] = tempLo[0]; + tempBytes[1] = tempLo[1]; + tempBytes[2] = tempLo[2]; + tempBytes[3] = tempLo[3]; + tempBytes[4] = tempHi[0]; + tempBytes[5] = tempHi[1]; + tempBytes[6] = tempHi[2]; + tempBytes[7] = tempHi[3]; + reserved = BitConverter.ToUInt64(tempBytes, 0); + + tempLo = BitConverter.GetBytes(supblk.free_blocks); + tempHi = BitConverter.GetBytes(supblk.free_blocks_hi); + tempBytes[0] = tempLo[0]; + tempBytes[1] = tempLo[1]; + tempBytes[2] = tempLo[2]; + tempBytes[3] = tempLo[3]; + tempBytes[4] = tempHi[0]; + tempBytes[5] = tempHi[1]; + tempBytes[6] = tempHi[2]; + tempBytes[7] = tempHi[3]; + free = BitConverter.ToUInt64(tempBytes, 0); + } + else + { + blocks = supblk.blocks; + reserved = supblk.reserved_blocks; + free = supblk.free_blocks; + } + + if(supblk.block_size == 0) // Then it is 1024 bytes + supblk.block_size = 1024; + + sb.AppendFormat(Localization.Volume_has_0_blocks_of_1_bytes_for_a_total_of_2_bytes, + blocks, + 1024 << (int)supblk.block_size, + blocks * (ulong)(1024 << (int)supblk.block_size)) + .AppendLine(); + + metadata.Clusters = blocks; + metadata.ClusterSize = (uint)(1024 << (int)supblk.block_size); + + if(supblk.mount_t > 0 || supblk.mount_c > 0) + { + if(supblk.mount_t > 0) + { + sb.AppendFormat(Localization.Last_mounted_on_0, DateHandlers.UnixUnsignedToDateTime(supblk.mount_t)) + .AppendLine(); + } + + if(supblk.max_mount_c != -1) + { + sb.AppendFormat(Localization.Volume_has_been_mounted_0_times_of_a_maximum_of_1_mounts_before_checking, + supblk.mount_c, + supblk.max_mount_c) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization + .Volume_has_been_mounted_0_times_with_no_maximum_no_of_mounts_before_checking, + supblk.mount_c) + .AppendLine(); + } + + if(!string.IsNullOrEmpty(StringHandlers.CToString(supblk.last_mount_dir, encoding))) + { + sb.AppendFormat(Localization.Last_mounted_at_0, + StringHandlers.CToString(supblk.last_mount_dir, encoding)) + .AppendLine(); + } + + if(!string.IsNullOrEmpty(StringHandlers.CToString(supblk.mount_options, encoding))) + { + sb.AppendFormat(Localization.Last_used_mount_options_were_0, + StringHandlers.CToString(supblk.mount_options, encoding)) + .AppendLine(); + } + } + else + { + sb.AppendLine(Localization.Volume_has_never_been_mounted); + + if(supblk.max_mount_c != -1) + { + sb.AppendFormat(Localization.Volume_can_be_mounted_0_times_before_checking, supblk.max_mount_c) + .AppendLine(); + } + else + sb.AppendLine(Localization.Volume_has_no_maximum_no_of_mounts_before_checking); + } + + if(supblk.check_t > 0) + { + if(supblk.check_inv > 0) + { + sb.AppendFormat(Localization.Last_checked_on_0_should_check_every_1_seconds, + DateHandlers.UnixUnsignedToDateTime(supblk.check_t), + supblk.check_inv) + .AppendLine(); + } + else + { + sb.AppendFormat(Localization.Last_checked_on_0, DateHandlers.UnixUnsignedToDateTime(supblk.check_t)) + .AppendLine(); + } + } + else + { + if(supblk.check_inv > 0) + { + sb.AppendFormat(Localization.Volume_has_never_been_checked_should_check_every_0_, supblk.check_inv) + .AppendLine(); + } + else + sb.AppendLine(Localization.Volume_has_never_been_checked); + } + + if(supblk.write_t > 0) + { + sb.AppendFormat(Localization.Last_written_on_0, DateHandlers.UnixUnsignedToDateTime(supblk.write_t)) + .AppendLine(); + + metadata.ModificationDate = DateHandlers.UnixUnsignedToDateTime(supblk.write_t); + } + else + sb.AppendLine("Volume has never been written"); + + metadata.Dirty = true; + + switch(supblk.state) + { + case EXT2_VALID_FS: + sb.AppendLine(Localization.Volume_is_clean); + metadata.Dirty = false; + + break; + case EXT2_ERROR_FS: + sb.AppendLine(Localization.Volume_is_dirty); + + break; + case EXT3_ORPHAN_FS: + sb.AppendLine(Localization.Volume_is_recovering_orphan_files); + + break; + default: + sb.AppendFormat(Localization.Volume_is_in_an_unknown_state_0, supblk.state).AppendLine(); + + break; + } + + if(!string.IsNullOrEmpty(StringHandlers.CToString(supblk.volume_name, encoding))) + { + sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(supblk.volume_name, encoding)) + .AppendLine(); + + metadata.VolumeName = StringHandlers.CToString(supblk.volume_name, encoding); + } + + switch(supblk.err_behaviour) + { + case EXT2_ERRORS_CONTINUE: + sb.AppendLine(Localization.On_errors_filesystem_should_continue); + + break; + case EXT2_ERRORS_RO: + sb.AppendLine(Localization.On_errors_filesystem_should_remount_read_only); + + break; + case EXT2_ERRORS_PANIC: + sb.AppendLine(Localization.On_errors_filesystem_should_panic); + + break; + default: + sb.AppendFormat(Localization.On_errors_filesystem_will_do_an_unknown_thing_0, supblk.err_behaviour) + .AppendLine(); + + break; + } + + if(supblk.revision > 0) + sb.AppendFormat(Localization.Filesystem_revision_0_1, supblk.revision, supblk.minor_revision).AppendLine(); + + if(supblk.uuid != Guid.Empty) + { + sb.AppendFormat(Localization.Volume_UUID_0, supblk.uuid).AppendLine(); + metadata.VolumeSerial = supblk.uuid.ToString(); + } + + if(supblk.kbytes_written > 0) + sb.AppendFormat(Localization._0_KiB_has_been_written_on_volume, supblk.kbytes_written).AppendLine(); + + sb.AppendFormat(Localization._0_reserved_and_1_free_blocks, reserved, free).AppendLine(); + metadata.FreeClusters = free; + + sb.AppendFormat(Localization._0_inodes_with_1_free_inodes_2, + supblk.inodes, + supblk.free_inodes, + supblk.free_inodes * 100 / supblk.inodes) + .AppendLine(); + + if(supblk.first_inode > 0) sb.AppendFormat(Localization.First_inode_is_0, supblk.first_inode).AppendLine(); + + if(supblk.frag_size > 0) sb.AppendFormat(Localization._0_bytes_per_fragment, supblk.frag_size).AppendLine(); + + if(supblk.blocks_per_grp > 0 && supblk is { flags_per_grp: > 0, inodes_per_grp: > 0 }) + { + sb.AppendFormat(Localization._0_blocks_1_flags_and_2_inodes_per_group, + supblk.blocks_per_grp, + supblk.flags_per_grp, + supblk.inodes_per_grp) + .AppendLine(); + } + + if(supblk.first_block > 0) + sb.AppendFormat(Localization._0_is_first_data_block, supblk.first_block).AppendLine(); + + sb.AppendFormat(Localization.Default_UID_0_GID_1, supblk.default_uid, supblk.default_gid).AppendLine(); + + if(supblk.block_group_no > 0) + sb.AppendFormat(Localization.Block_group_number_is_0, supblk.block_group_no).AppendLine(); + + if(supblk.desc_grp_size > 0) + sb.AppendFormat(Localization.Group_descriptor_size_is_0_bytes, supblk.desc_grp_size).AppendLine(); + + if(supblk.first_meta_bg > 0) + sb.AppendFormat(Localization.First_metablock_group_is_0, supblk.first_meta_bg).AppendLine(); + + if(supblk.raid_stride > 0) sb.AppendFormat(Localization.RAID_stride_0, supblk.raid_stride).AppendLine(); + + if(supblk.raid_stripe_width > 0) + sb.AppendFormat(Localization._0_blocks_on_all_data_disks, supblk.raid_stripe_width).AppendLine(); + + if(supblk is { mmp_interval: > 0, mmp_block: > 0 }) + { + sb.AppendFormat(Localization._0_seconds_for_multi_mount_protection_wait_on_block_1, + supblk.mmp_interval, + supblk.mmp_block) + .AppendLine(); + } + + if(supblk.flex_bg_grp_size > 0) + sb.AppendFormat(Localization._0_Flexible_block_group_size, supblk.flex_bg_grp_size).AppendLine(); + + if(supblk is { hash_seed_1: > 0, hash_seed_2: > 0 } and { hash_seed_3: > 0, hash_seed_4: > 0 }) + { + sb.AppendFormat(Localization.Hash_seed_0_1_2_3_version_4, + supblk.hash_seed_1, + supblk.hash_seed_2, + supblk.hash_seed_3, + supblk.hash_seed_4, + supblk.hash_version) + .AppendLine(); + } + + if((supblk.ftr_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) == EXT3_FEATURE_COMPAT_HAS_JOURNAL || + (supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + { + sb.AppendLine(Localization.Volume_is_journaled); + + if(supblk.journal_uuid != Guid.Empty) + sb.AppendFormat(Localization.Journal_UUID_0, supblk.journal_uuid).AppendLine(); + + sb.AppendFormat(Localization.Journal_has_inode_0, supblk.journal_inode).AppendLine(); + + if((supblk.ftr_compat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV && + supblk.journal_dev > 0) + sb.AppendFormat(Localization.Journal_is_on_device_0, supblk.journal_dev).AppendLine(); + + if(supblk.jnl_backup_type > 0) + sb.AppendFormat(Localization.Journal_backup_type_0, supblk.jnl_backup_type).AppendLine(); + + if(supblk.last_orphan > 0) + sb.AppendFormat(Localization.Last_orphaned_inode_is_0, supblk.last_orphan).AppendLine(); + else + sb.AppendLine(Localization.There_are_no_orphaned_inodes); + } + + if(ext4) + { + if(supblk.snapshot_id > 0) + { + sb.AppendFormat(Localization + .Active_snapshot_has_ID_0_on_inode_1_with_2_blocks_reserved_list_starting_on_block_3, + supblk.snapshot_id, + supblk.snapshot_inum, + supblk.snapshot_blocks, + supblk.snapshot_list) + .AppendLine(); + } + + if(supblk.error_count > 0) + { + sb.AppendFormat(Localization._0_errors_registered, supblk.error_count).AppendLine(); + + sb.AppendFormat(Localization.First_error_occurred_on_0_last_on_1, + DateHandlers.UnixUnsignedToDateTime(supblk.first_error_t), + DateHandlers.UnixUnsignedToDateTime(supblk.last_error_t)) + .AppendLine(); + + sb.AppendFormat(Localization.First_error_inode_is_0_last_is_1, + supblk.first_error_inode, + supblk.last_error_inode) + .AppendLine(); + + sb.AppendFormat(Localization.First_error_block_is_0_last_is_1, + supblk.first_error_block, + supblk.last_error_block) + .AppendLine(); + + sb.AppendFormat(Localization.First_error_function_is_0_last_is_1, + supblk.first_error_func, + supblk.last_error_func) + .AppendLine(); + } + } + + sb.AppendFormat(Localization.Flags_ellipsis).AppendLine(); + + if((supblk.flags & EXT2_FLAGS_SIGNED_HASH) == EXT2_FLAGS_SIGNED_HASH) + sb.AppendLine(Localization.Signed_directory_hash_is_in_use); + + if((supblk.flags & EXT2_FLAGS_UNSIGNED_HASH) == EXT2_FLAGS_UNSIGNED_HASH) + sb.AppendLine(Localization.Unsigned_directory_hash_is_in_use); + + if((supblk.flags & EXT2_FLAGS_TEST_FILESYS) == EXT2_FLAGS_TEST_FILESYS) + sb.AppendLine(Localization.Volume_is_testing_development_code); + + if((supblk.flags & 0xFFFFFFF8) != 0) sb.AppendFormat(Localization.Unknown_set_flags_0, supblk.flags); + + sb.AppendLine(); + + sb.AppendFormat(Localization.Default_mount_options).AppendLine(); + + if((supblk.default_mnt_opts & EXT2_DEFM_DEBUG) == EXT2_DEFM_DEBUG) + sb.AppendLine(Localization.debug_Enable_debugging_code); + + if((supblk.default_mnt_opts & EXT2_DEFM_BSDGROUPS) == EXT2_DEFM_BSDGROUPS) + sb.AppendLine(Localization.bsdgroups_Emulate_BSD_behaviour_when_creating_new_files); + + if((supblk.default_mnt_opts & EXT2_DEFM_XATTR_USER) == EXT2_DEFM_XATTR_USER) + sb.AppendLine(Localization.user_xattr_Enable_user_specified_extended_attributes); + + if((supblk.default_mnt_opts & EXT2_DEFM_ACL) == EXT2_DEFM_ACL) + sb.AppendLine(Localization.acl_Enable_POSIX_ACLs); + + if((supblk.default_mnt_opts & EXT2_DEFM_UID16) == EXT2_DEFM_UID16) + sb.AppendLine(Localization.uid16_Disable_32bit_UIDs_and_GIDs); + + if((supblk.default_mnt_opts & EXT3_DEFM_JMODE_DATA) == EXT3_DEFM_JMODE_DATA) + sb.AppendLine(Localization.journal_data_Journal_data_and_metadata); + + if((supblk.default_mnt_opts & EXT3_DEFM_JMODE_ORDERED) == EXT3_DEFM_JMODE_ORDERED) + sb.AppendLine(Localization.journal_data_ordered_Write_data_before_journaling_metadata); + + if((supblk.default_mnt_opts & EXT3_DEFM_JMODE_WBACK) == EXT3_DEFM_JMODE_WBACK) + sb.AppendLine(Localization.journal_data_writeback_Write_journal_before_data); + + if((supblk.default_mnt_opts & 0xFFFFFE20) != 0) + sb.AppendFormat(Localization.Unknown_set_default_mount_options_0, supblk.default_mnt_opts); + + sb.AppendLine(); + + sb.AppendFormat(Localization.Compatible_features).AppendLine(); + + if((supblk.ftr_compat & EXT2_FEATURE_COMPAT_DIR_PREALLOC) == EXT2_FEATURE_COMPAT_DIR_PREALLOC) + sb.AppendLine(Localization.Pre_allocate_directories); + + if((supblk.ftr_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES) == EXT2_FEATURE_COMPAT_IMAGIC_INODES) + sb.AppendLine(Localization.imagic_inodes__); + + if((supblk.ftr_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) == EXT3_FEATURE_COMPAT_HAS_JOURNAL) + sb.AppendLine(Localization.Has_journal_ext3); + + if((supblk.ftr_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) == EXT2_FEATURE_COMPAT_EXT_ATTR) + sb.AppendLine(Localization.Has_extended_attribute_blocks); + + if((supblk.ftr_compat & EXT2_FEATURE_COMPAT_RESIZE_INO) == EXT2_FEATURE_COMPAT_RESIZE_INO) + sb.AppendLine(Localization.Has_online_filesystem_resize_reservations); + + if((supblk.ftr_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) == EXT2_FEATURE_COMPAT_DIR_INDEX) + sb.AppendLine(Localization.Can_use_hashed_indexes_on_directories); + + if((supblk.ftr_compat & 0xFFFFFFC0) != 0) + sb.AppendFormat(Localization.Unknown_compatible_features_0, supblk.ftr_compat); + + sb.AppendLine(); + + sb.AppendFormat(Localization.Compatible_features_if_read_only).AppendLine(); + + if((supblk.ftr_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) == EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) + sb.AppendLine(Localization.Reduced_number_of_superblocks); + + if((supblk.ftr_ro_compat & EXT2_FEATURE_RO_COMPAT_LARGE_FILE) == EXT2_FEATURE_RO_COMPAT_LARGE_FILE) + sb.AppendLine(Localization.Can_have_files_bigger_than_2GiB); + + if((supblk.ftr_ro_compat & EXT2_FEATURE_RO_COMPAT_BTREE_DIR) == EXT2_FEATURE_RO_COMPAT_BTREE_DIR) + sb.AppendLine(Localization.Uses_B_Tree_for_directories); + + if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) == EXT4_FEATURE_RO_COMPAT_HUGE_FILE) + sb.AppendLine(Localization.Can_have_files_bigger_than_2TiB_ext4); + + if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) == EXT4_FEATURE_RO_COMPAT_GDT_CSUM) + sb.AppendLine(Localization.Group_descriptor_checksums_and_sparse_inode_table_ext4); + + if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_DIR_NLINK) == EXT4_FEATURE_RO_COMPAT_DIR_NLINK) + sb.AppendLine(Localization.More_than_32000_directory_entries_ext4); + + if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) == EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) + sb.AppendLine(Localization.Supports_nanosecond_timestamps_and_creation_time_ext4); + + if((supblk.ftr_ro_compat & 0xFFFFFF80) != 0) + sb.AppendFormat(Localization.Unknown_read_only_compatible_features_0, supblk.ftr_ro_compat); + + sb.AppendLine(); + + sb.AppendFormat(Localization.Incompatible_features).AppendLine(); + + if((supblk.ftr_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) == EXT2_FEATURE_INCOMPAT_COMPRESSION) + sb.AppendLine(Localization.Uses_compression); + + if((supblk.ftr_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE) == EXT2_FEATURE_INCOMPAT_FILETYPE) + sb.AppendLine(Localization.Filetype_in_directory_entries); + + if((supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) == EXT3_FEATURE_INCOMPAT_RECOVER) + sb.AppendLine(Localization.Journal_needs_recovery_ext3); + + if((supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + sb.AppendLine(Localization.Has_journal_on_another_device_ext3); + + if((supblk.ftr_incompat & EXT2_FEATURE_INCOMPAT_META_BG) == EXT2_FEATURE_INCOMPAT_META_BG) + sb.AppendLine(Localization.Reduced_block_group_backups); + + if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_EXTENTS) == EXT4_FEATURE_INCOMPAT_EXTENTS) + sb.AppendLine(Localization.Volume_use_extents_ext4); + + if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_64BIT) == EXT4_FEATURE_INCOMPAT_64BIT) + sb.AppendLine(Localization.Supports_volumes_bigger_than_2_32_blocks_ext4); + + if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_MMP) == EXT4_FEATURE_INCOMPAT_MMP) + sb.AppendLine(Localization.Multi_mount_protection_ext4); + + if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) == EXT4_FEATURE_INCOMPAT_FLEX_BG) + sb.AppendLine(Localization.Flexible_block_group_metadata_location_ext4); + + if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_EA_INODE) == EXT4_FEATURE_INCOMPAT_EA_INODE) + sb.AppendLine(Localization.Extended_attributes_can_reside_in_inode_ext4); + + if((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA) == EXT4_FEATURE_INCOMPAT_DIRDATA) + sb.AppendLine(Localization.Data_can_reside_in_directory_entry_ext4); + + if((supblk.ftr_incompat & 0xFFFFF020) != 0) + sb.AppendFormat(Localization.Unknown_incompatible_features_0, supblk.ftr_incompat); + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ext2FS/Structs.cs b/Aaru.Filesystems/ext2FS/Structs.cs new file mode 100644 index 000000000..abd94123f --- /dev/null +++ b/Aaru.Filesystems/ext2FS/Structs.cs @@ -0,0 +1,281 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Linux extended filesystem 2, 3 and 4 plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Linux extended filesystem 2, 3 and 4 and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the Linux extended filesystem v2, v3 and v4 +[SuppressMessage("ReSharper", "UnusedMember.Local")] + +// ReSharper disable once InconsistentNaming +public sealed partial class ext2FS +{ +#region Nested type: SuperBlock + + /// ext2/3/4 superblock + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [SuppressMessage("ReSharper", "InconsistentNaming")] + struct SuperBlock + { + /// 0x000, inodes on volume + public readonly uint inodes; + /// 0x004, blocks on volume + public readonly uint blocks; + /// 0x008, reserved blocks + public readonly uint reserved_blocks; + /// 0x00C, free blocks count + public readonly uint free_blocks; + /// 0x010, free inodes count + public readonly uint free_inodes; + /// 0x014, first data block + public readonly uint first_block; + /// 0x018, block size + public uint block_size; + /// 0x01C, fragment size + public readonly int frag_size; + /// 0x020, blocks per group + public readonly uint blocks_per_grp; + /// 0x024, fragments per group + public readonly uint flags_per_grp; + /// 0x028, inodes per group + public readonly uint inodes_per_grp; + /// 0x02C, last mount time + public readonly uint mount_t; + /// 0x030, last write time + public readonly uint write_t; + /// 0x034, mounts count + public readonly ushort mount_c; + /// 0x036, max mounts + public readonly short max_mount_c; + /// 0x038, (little endian) + public readonly ushort magic; + /// 0x03A, filesystem state + public readonly ushort state; + /// 0x03C, behaviour on errors + public readonly ushort err_behaviour; + /// 0x03E, From 0.5b onward + public readonly ushort minor_revision; + /// 0x040, last check time + public readonly uint check_t; + /// 0x044, max time between checks + public readonly uint check_inv; + + // From 0.5a onward + /// 0x048, Creation OS + public readonly uint creator_os; + /// 0x04C, Revison level + public readonly uint revision; + /// 0x050, Default UID for reserved blocks + public readonly ushort default_uid; + /// 0x052, Default GID for reserved blocks + public readonly ushort default_gid; + + // From 0.5b onward + /// 0x054, First unreserved inode + public readonly uint first_inode; + /// 0x058, inode size + public readonly ushort inode_size; + /// 0x05A, Block group number of THIS superblock + public readonly ushort block_group_no; + /// 0x05C, Compatible features set + public readonly uint ftr_compat; + /// 0x060, Incompatible features set + public readonly uint ftr_incompat; + + // Found on Linux 2.0.40 + /// 0x064, Read-only compatible features set + public readonly uint ftr_ro_compat; + + // Found on Linux 2.1.132 + /// 0x068, 16 bytes, UUID + public readonly Guid uuid; + /// 0x078, 16 bytes, volume name + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] volume_name; + /// 0x088, 64 bytes, where last mounted + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] last_mount_dir; + /// 0x0C8, Usage bitmap algorithm, for compression + public readonly uint algo_usage_bmp; + /// 0x0CC, Block to try to preallocate + public readonly byte prealloc_blks; + /// 0x0CD, Blocks to try to preallocate for directories + public readonly byte prealloc_dir_blks; + /// 0x0CE, Per-group desc for online growth + public readonly ushort rsrvd_gdt_blocks; + + // Found on Linux 2.4 + // ext3 + /// 0x0D0, 16 bytes, UUID of journal superblock + public readonly Guid journal_uuid; + /// 0x0E0, inode no. of journal file + public readonly uint journal_inode; + /// 0x0E4, device no. of journal file + public readonly uint journal_dev; + /// 0x0E8, Start of list of inodes to delete + public readonly uint last_orphan; + /// 0x0EC, First byte of 128bit HTREE hash seed + public readonly uint hash_seed_1; + /// 0x0F0, Second byte of 128bit HTREE hash seed + public readonly uint hash_seed_2; + /// 0x0F4, Third byte of 128bit HTREE hash seed + public readonly uint hash_seed_3; + /// 0x0F8, Fourth byte of 128bit HTREE hash seed + public readonly uint hash_seed_4; + /// 0x0FC, Hash version + public readonly byte hash_version; + /// 0x0FD, Journal backup type + public readonly byte jnl_backup_type; + /// 0x0FE, Size of group descriptor + public readonly ushort desc_grp_size; + /// 0x100, Default mount options + public readonly uint default_mnt_opts; + /// 0x104, First metablock block group + public readonly uint first_meta_bg; + + // Introduced with ext4, some can be ext3 + /// 0x108, Filesystem creation time + public readonly uint mkfs_t; + + /// Backup of the journal inode + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] + public readonly uint[] jnl_blocks; + + // Following 3 fields are valid if EXT4_FEATURE_COMPAT_64BIT is set + /// 0x14C, High 32bits of blocks no. + public readonly uint blocks_hi; + /// 0x150, High 32bits of reserved blocks no. + public readonly uint reserved_blocks_hi; + /// 0x154, High 32bits of free blocks no. + public readonly uint free_blocks_hi; + /// 0x158, inodes minimal size in bytes + public readonly ushort min_inode_size; + /// 0x15A, Bytes reserved by new inodes + public readonly ushort rsv_inode_size; + /// 0x15C, Flags + public readonly uint flags; + /// 0x160, RAID stride + public readonly ushort raid_stride; + /// 0x162, Waiting seconds in MMP check + public readonly ushort mmp_interval; + /// 0x164, Block for multi-mount protection + public readonly ulong mmp_block; + /// 0x16C, Blocks on all data disks (N*stride) + public readonly uint raid_stripe_width; + /// 0x170, FLEX_BG group size + public readonly byte flex_bg_grp_size; + /// 0x171 Metadata checksum algorithm + public readonly byte checksum_type; + /// 0x172 Versioning level for encryption + public readonly byte encryption_level; + /// 0x173 Padding + public readonly ushort padding; + + // Following are introduced with ext4 + /// 0x174, Kibibytes written in volume lifetime + public readonly ulong kbytes_written; + /// 0x17C, Active snapshot inode number + public readonly uint snapshot_inum; + /// 0x180, Active snapshot sequential ID + public readonly uint snapshot_id; + /// 0x184, Reserved blocks for active snapshot's future use + public readonly ulong snapshot_blocks; + /// 0x18C, inode number of the on-disk start of the snapshot list + public readonly uint snapshot_list; + + // Optional ext4 error-handling features + /// 0x190, total registered filesystem errors + public readonly uint error_count; + /// 0x194, time on first error + public readonly uint first_error_t; + /// 0x198, inode involved in first error + public readonly uint first_error_inode; + /// 0x19C, block involved of first error + public readonly ulong first_error_block; + /// 0x1A0, 32 bytes, function where the error happened + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] first_error_func; + /// 0x1B0, line number where error happened + public readonly uint first_error_line; + /// 0x1B4, time of most recent error + public readonly uint last_error_t; + /// 0x1B8, inode involved in last error + public readonly uint last_error_inode; + /// 0x1BC, line number where error happened + public readonly uint last_error_line; + /// 0x1C0, block involved of last error + public readonly ulong last_error_block; + /// 0x1C8, 32 bytes, function where the error happened + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly byte[] last_error_func; + + // End of optional error-handling features + + // 0x1D8, 64 bytes, last used mount options
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public readonly byte[] mount_options; + + /// Inode for user quota + public readonly uint usr_quota_inum; + /// Inode for group quota + public readonly uint grp_quota_inum; + /// Overhead clusters in volume + public readonly uint overhead_clusters; + /// Groups with sparse_super2 SBs + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public readonly uint[] backup_bgs; + /// Encryption algorithms in use + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly byte[] encrypt_algos; + /// Salt used for string2key algorithm + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] encrypt_pw_salt; + /// Inode number of lost+found + public readonly uint lpf_inum; + /// Inode number for tracking project quota + public readonly uint prj_quota_inum; + /// crc32c(uuid) if csum_seed is set + public readonly uint checksum_seed; + /// Reserved + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 98)] + public readonly byte[] reserved; + /// crc32c(superblock) + public readonly uint checksum; + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/ext2FS/ext2FS.cs b/Aaru.Filesystems/ext2FS/ext2FS.cs new file mode 100644 index 000000000..9df9f5a1f --- /dev/null +++ b/Aaru.Filesystems/ext2FS/ext2FS.cs @@ -0,0 +1,59 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : ext2FS.cs +// Author(s) : Natalia Portillo +// +// Component : Linux extended filesystem 2, 3 and 4 plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Linux extended filesystem 2, 3 and 4 and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the Linux extended filesystem v2, v3 and v4 +[SuppressMessage("ReSharper", "UnusedMember.Local")] + +// ReSharper disable once InconsistentNaming +public sealed partial class ext2FS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.ext2FS_Name_Linux_extended_Filesystem_2_3_and_4; + + /// + public Guid Id => new("6AA91B88-150B-4A7B-AD56-F84FB2DF4184"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/extFS.cs b/Aaru.Filesystems/extFS.cs deleted file mode 100644 index f430334a1..000000000 --- a/Aaru.Filesystems/extFS.cs +++ /dev/null @@ -1,192 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : extFS.cs -// Author(s) : Natalia Portillo -// -// Component : Linux extended filesystem plugin. -// -// --[ Description ] ---------------------------------------------------------- -// -// Identifies the Linux extended filesystem and shows information. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -namespace Aaru.Filesystems; - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Text; -using Aaru.CommonTypes; -using Aaru.CommonTypes.Enums; -using Aaru.CommonTypes.Interfaces; -using Schemas; - -// Information from the Linux kernel -/// -/// Implements detection of the Linux extended filesystem -// ReSharper disable once InconsistentNaming -public sealed class extFS : IFilesystem -{ - const int SB_POS = 0x400; - - /// ext superblock magic - const ushort EXT_MAGIC = 0x137D; - - /// - public FileSystemType XmlFsType { get; private set; } - /// - public string Name => "Linux extended Filesystem"; - /// - public Guid Id => new("076CB3A2-08C2-4D69-BC8A-FCAA2E502BE2"); - /// - public Encoding Encoding { get; private set; } - /// - public string Author => "Natalia Portillo"; - - /// - public bool Identify(IMediaImage imagePlugin, Partition partition) - { - if(imagePlugin.Info.SectorSize < 512) - return false; - - ulong sbSectorOff = SB_POS / imagePlugin.Info.SectorSize; - uint sbOff = SB_POS % imagePlugin.Info.SectorSize; - - if(sbSectorOff + partition.Start >= partition.End) - return false; - - ErrorNumber errno = imagePlugin.ReadSector(sbSectorOff + partition.Start, out byte[] sbSector); - - if(errno != ErrorNumber.NoError) - return false; - - var sb = new byte[512]; - - if(sbOff + 512 > sbSector.Length) - return false; - - Array.Copy(sbSector, sbOff, sb, 0, 512); - - var magic = BitConverter.ToUInt16(sb, 0x038); - - return magic == EXT_MAGIC; - } - - /// - public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) - { - Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); - information = ""; - - var sb = new StringBuilder(); - - if(imagePlugin.Info.SectorSize < 512) - return; - - ulong sbSectorOff = SB_POS / imagePlugin.Info.SectorSize; - uint sbOff = SB_POS % imagePlugin.Info.SectorSize; - - if(sbSectorOff + partition.Start >= partition.End) - return; - - ErrorNumber errno = imagePlugin.ReadSector(sbSectorOff + partition.Start, out byte[] sblock); - - if(errno != ErrorNumber.NoError) - return; - - var sbSector = new byte[512]; - Array.Copy(sblock, sbOff, sbSector, 0, 512); - - var extSb = new SuperBlock - { - inodes = BitConverter.ToUInt32(sbSector, 0x000), - zones = BitConverter.ToUInt32(sbSector, 0x004), - firstfreeblk = BitConverter.ToUInt32(sbSector, 0x008), - freecountblk = BitConverter.ToUInt32(sbSector, 0x00C), - firstfreeind = BitConverter.ToUInt32(sbSector, 0x010), - freecountind = BitConverter.ToUInt32(sbSector, 0x014), - firstdatazone = BitConverter.ToUInt32(sbSector, 0x018), - logzonesize = BitConverter.ToUInt32(sbSector, 0x01C), - maxsize = BitConverter.ToUInt32(sbSector, 0x020) - }; - - sb.AppendLine("ext filesystem"); - sb.AppendFormat("{0} zones on volume", extSb.zones); - sb.AppendFormat("{0} free blocks ({1} bytes)", extSb.freecountblk, extSb.freecountblk * 1024); - - sb.AppendFormat("{0} inodes on volume, {1} free ({2}%)", extSb.inodes, extSb.freecountind, - extSb.freecountind * 100 / extSb.inodes); - - sb.AppendFormat("First free inode is {0}", extSb.firstfreeind); - sb.AppendFormat("First free block is {0}", extSb.firstfreeblk); - sb.AppendFormat("First data zone is {0}", extSb.firstdatazone); - sb.AppendFormat("Log zone size: {0}", extSb.logzonesize); - sb.AppendFormat("Max zone size: {0}", extSb.maxsize); - - XmlFsType = new FileSystemType - { - Type = "ext", - FreeClusters = extSb.freecountblk, - FreeClustersSpecified = true, - ClusterSize = 1024, - Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / 1024 - }; - - information = sb.ToString(); - } - - /// ext superblock - [SuppressMessage("ReSharper", "InconsistentNaming")] - struct SuperBlock - { - /// 0x000, inodes on volume - public uint inodes; - /// 0x004, zones on volume - public uint zones; - /// 0x008, first free block - public uint firstfreeblk; - /// 0x00C, free blocks count - public uint freecountblk; - /// 0x010, first free inode - public uint firstfreeind; - /// 0x014, free inodes count - public uint freecountind; - /// 0x018, first data zone - public uint firstdatazone; - /// 0x01C, log zone size - public uint logzonesize; - /// 0x020, max zone size - public uint maxsize; - /// 0x024, reserved - public uint reserved1; - /// 0x028, reserved - public uint reserved2; - /// 0x02C, reserved - public uint reserved3; - /// 0x030, reserved - public uint reserved4; - /// 0x034, reserved - public uint reserved5; - /// 0x038, 0x137D (little endian) - public ushort magic; - } -} \ No newline at end of file diff --git a/Aaru.Filesystems/extFS/Consts.cs b/Aaru.Filesystems/extFS/Consts.cs new file mode 100644 index 000000000..a9a0f3d0a --- /dev/null +++ b/Aaru.Filesystems/extFS/Consts.cs @@ -0,0 +1,44 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Consts.cs +// Author(s) : Natalia Portillo +// +// Component : Linux extended filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the Linux extended filesystem + +// ReSharper disable once InconsistentNaming +public sealed partial class extFS +{ + const int SB_POS = 0x400; + + /// ext superblock magic + const ushort EXT_MAGIC = 0x137D; + + const string FS_TYPE = "ext"; +} \ No newline at end of file diff --git a/Aaru.Filesystems/extFS/Info.cs b/Aaru.Filesystems/extFS/Info.cs new file mode 100644 index 000000000..e3d3533f5 --- /dev/null +++ b/Aaru.Filesystems/extFS/Info.cs @@ -0,0 +1,135 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Info.cs +// Author(s) : Natalia Portillo +// +// Component : Linux extended filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Text; +using Aaru.CommonTypes.AaruMetadata; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; +using Partition = Aaru.CommonTypes.Partition; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the Linux extended filesystem + +// ReSharper disable once InconsistentNaming +public sealed partial class extFS +{ +#region IFilesystem Members + + /// + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(imagePlugin.Info.SectorSize < 512) return false; + + ulong sbSectorOff = SB_POS / imagePlugin.Info.SectorSize; + uint sbOff = SB_POS % imagePlugin.Info.SectorSize; + + if(sbSectorOff + partition.Start >= partition.End) return false; + + ErrorNumber errno = imagePlugin.ReadSector(sbSectorOff + partition.Start, out byte[] sbSector); + + if(errno != ErrorNumber.NoError) return false; + + var sb = new byte[512]; + + if(sbOff + 512 > sbSector.Length) return false; + + Array.Copy(sbSector, sbOff, sb, 0, 512); + + var magic = BitConverter.ToUInt16(sb, 0x038); + + return magic == EXT_MAGIC; + } + + /// + public void GetInformation(IMediaImage imagePlugin, Partition partition, Encoding encoding, out string information, + out FileSystem metadata) + { + information = ""; + metadata = new FileSystem(); + + var sb = new StringBuilder(); + + if(imagePlugin.Info.SectorSize < 512) return; + + ulong sbSectorOff = SB_POS / imagePlugin.Info.SectorSize; + uint sbOff = SB_POS % imagePlugin.Info.SectorSize; + + if(sbSectorOff + partition.Start >= partition.End) return; + + ErrorNumber errno = imagePlugin.ReadSector(sbSectorOff + partition.Start, out byte[] sblock); + + if(errno != ErrorNumber.NoError) return; + + var sbSector = new byte[512]; + Array.Copy(sblock, sbOff, sbSector, 0, 512); + + var extSb = new SuperBlock + { + inodes = BitConverter.ToUInt32(sbSector, 0x000), + zones = BitConverter.ToUInt32(sbSector, 0x004), + firstfreeblk = BitConverter.ToUInt32(sbSector, 0x008), + freecountblk = BitConverter.ToUInt32(sbSector, 0x00C), + firstfreeind = BitConverter.ToUInt32(sbSector, 0x010), + freecountind = BitConverter.ToUInt32(sbSector, 0x014), + firstdatazone = BitConverter.ToUInt32(sbSector, 0x018), + logzonesize = BitConverter.ToUInt32(sbSector, 0x01C), + maxsize = BitConverter.ToUInt32(sbSector, 0x020) + }; + + sb.AppendLine(Localization.ext_filesystem); + sb.AppendFormat(Localization._0_zones_in_volume, extSb.zones); + sb.AppendFormat(Localization._0_free_blocks_1_bytes, extSb.freecountblk, extSb.freecountblk * 1024); + + sb.AppendFormat(Localization._0_inodes_in_volume_1_free_2, + extSb.inodes, + extSb.freecountind, + extSb.freecountind * 100 / extSb.inodes); + + sb.AppendFormat(Localization.First_free_inode_is_0, extSb.firstfreeind); + sb.AppendFormat(Localization.First_free_block_is_0, extSb.firstfreeblk); + sb.AppendFormat(Localization.First_data_zone_is_0, extSb.firstdatazone); + sb.AppendFormat(Localization.Log_zone_size_0, extSb.logzonesize); + sb.AppendFormat(Localization.Max_zone_size_0, extSb.maxsize); + + metadata = new FileSystem + { + Type = FS_TYPE, + FreeClusters = extSb.freecountblk, + ClusterSize = 1024, + Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / 1024 + }; + + information = sb.ToString(); + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/extFS/Structs.cs b/Aaru.Filesystems/extFS/Structs.cs new file mode 100644 index 000000000..8802ba922 --- /dev/null +++ b/Aaru.Filesystems/extFS/Structs.cs @@ -0,0 +1,81 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Structs.cs +// Author(s) : Natalia Portillo +// +// Component : Linux extended filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the Linux extended filesystem + +// ReSharper disable once InconsistentNaming +public sealed partial class extFS +{ +#region Nested type: SuperBlock + + /// ext superblock +#pragma warning disable CS0649 + [SuppressMessage("ReSharper", "InconsistentNaming")] + struct SuperBlock + { + /// 0x000, inodes on volume + public uint inodes; + /// 0x004, zones on volume + public uint zones; + /// 0x008, first free block + public uint firstfreeblk; + /// 0x00C, free blocks count + public uint freecountblk; + /// 0x010, first free inode + public uint firstfreeind; + /// 0x014, free inodes count + public uint freecountind; + /// 0x018, first data zone + public uint firstdatazone; + /// 0x01C, log zone size + public uint logzonesize; + /// 0x020, max zone size + public uint maxsize; + /// 0x024, reserved + public uint reserved1; + /// 0x028, reserved + public uint reserved2; + /// 0x02C, reserved + public uint reserved3; + /// 0x030, reserved + public uint reserved4; + /// 0x034, reserved + public uint reserved5; + /// 0x038, 0x137D (little endian) + public ushort magic; + } +#pragma warning restore CS0649 + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filesystems/extFS/extFS.cs b/Aaru.Filesystems/extFS/extFS.cs new file mode 100644 index 000000000..642e959b7 --- /dev/null +++ b/Aaru.Filesystems/extFS/extFS.cs @@ -0,0 +1,53 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : extFS.cs +// Author(s) : Natalia Portillo +// +// Component : Linux extended filesystem plugin. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +// Information from the Linux kernel +/// +/// Implements detection of the Linux extended filesystem + +// ReSharper disable once InconsistentNaming +public sealed partial class extFS : IFilesystem +{ +#region IFilesystem Members + + /// + public string Name => Localization.extFS_Name; + + /// + public Guid Id => new("076CB3A2-08C2-4D69-BC8A-FCAA2E502BE2"); + + /// + public string Author => Authors.NataliaPortillo; + +#endregion +} \ No newline at end of file diff --git a/Aaru.Filters/Aaru.Filters.csproj b/Aaru.Filters/Aaru.Filters.csproj index 91f6e49ec..1221ee946 100644 --- a/Aaru.Filters/Aaru.Filters.csproj +++ b/Aaru.Filters/Aaru.Filters.csproj @@ -1,118 +1,105 @@  - - Debug - AnyCPU - 2.0 - {D571B8EF-903D-4353-BDD5-B834F9F029EF} - Library - Aaru.Filters - Aaru.Filters - $(Version) - false - true - 6.0.0-alpha8 - Claunia.com - Copyright © 2011-2022 Natalia Portillo - Aaru Data Preservation Suite - Aaru.Filters - $(Version) - net6.0 - 10 - File filters used by the Aaru Data Preservation Suite. - https://github.com/aaru-dps/ - LGPL-2.1-only - https://github.com/aaru-dps/Aaru - true - en-US - true - true - snupkg - Natalia Portillo <claunia@claunia.com> - true - - - $(Version)+{chash:8} - true - true - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - true - bin\Release - prompt - 4 - false - - - - - - - - - - - - - - - - - - - LICENSE.LGPL - - - - - - - - - - - - - - - - - - - - - - - - - - - - /Library/Frameworks/Mono.framework/Versions/Current/lib/mono - /usr/lib/mono - /usr/local/lib/mono - - $(BaseFrameworkPathOverrideForMono)/4.0-api - $(BaseFrameworkPathOverrideForMono)/4.5-api - $(BaseFrameworkPathOverrideForMono)/4.5.1-api - $(BaseFrameworkPathOverrideForMono)/4.5.2-api - $(BaseFrameworkPathOverrideForMono)/4.6-api - $(BaseFrameworkPathOverrideForMono)/4.6.1-api - $(BaseFrameworkPathOverrideForMono)/4.6.2-api - $(BaseFrameworkPathOverrideForMono)/4.7-api - $(BaseFrameworkPathOverrideForMono)/4.7.1-api - true - - $(FrameworkPathOverride)/Facades;$(AssemblySearchPaths) - + + 2.0 + {D571B8EF-903D-4353-BDD5-B834F9F029EF} + Library + Aaru.Filters + Aaru.Filters + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru.Filters + $(Version) + net8.0 + 12 + File filters used by the Aaru Data Preservation Suite. + https://github.com/aaru-dps/ + LGPL-2.1-only + https://github.com/aaru-dps/Aaru + true + en-US + true + true + snupkg + Natalia Portillo <claunia@claunia.com> + true + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} + true + true + + + + LICENSE.LGPL + + + ResXFileCodeGenerator + Localization.Designer.cs + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + \ No newline at end of file diff --git a/Aaru.Filters/Aaru.Filters.csproj.DotSettings b/Aaru.Filters/Aaru.Filters.csproj.DotSettings new file mode 100644 index 000000000..10e52454d --- /dev/null +++ b/Aaru.Filters/Aaru.Filters.csproj.DotSettings @@ -0,0 +1,5 @@ + + True \ No newline at end of file diff --git a/Aaru.Filters/AppleDouble.cs b/Aaru.Filters/AppleDouble.cs index b271a675b..c5f3e3bdc 100644 --- a/Aaru.Filters/AppleDouble.cs +++ b/Aaru.Filters/AppleDouble.cs @@ -27,11 +27,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filters; - using System; using System.Diagnostics.CodeAnalysis; using System.IO; @@ -40,52 +38,40 @@ using System.Runtime.InteropServices; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; +using Aaru.Helpers.IO; using Marshal = Aaru.Helpers.Marshal; +namespace Aaru.Filters; + /// /// Decodes AppleDouble files [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed class AppleDouble : IFilter { - const uint MAGIC = 0x00051607; - const uint VERSION = 0x00010000; - const uint VERSION2 = 0x00020000; - readonly byte[] _dosHome = - { - 0x4D, 0x53, 0x2D, 0x44, 0x4F, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; + const uint MAGIC = 0x00051607; + const uint VERSION = 0x00010000; + const uint VERSION2 = 0x00020000; + readonly byte[] _dosHome = "MS-DOS "u8.ToArray(); + readonly byte[] _macintoshHome = "Macintosh "u8.ToArray(); + readonly byte[] _osxHome = "Mac OS X "u8.ToArray(); + readonly byte[] _proDosHome = "ProDOS "u8.ToArray(); + readonly byte[] _unixHome = "Unix "u8.ToArray(); + readonly byte[] _vmsHome = "VAX VMS "u8.ToArray(); + Entry _dataFork; + Header _header; + string _headerPath; + Entry _rsrcFork; - readonly byte[] _macintoshHome = - { - 0x4D, 0x61, 0x63, 0x69, 0x6E, 0x74, 0x6F, 0x73, 0x68, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; - readonly byte[] _osxHome = - { - 0x4D, 0x61, 0x63, 0x20, 0x4F, 0x53, 0x20, 0x58, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; - readonly byte[] _proDosHome = - { - 0x50, 0x72, 0x6F, 0x44, 0x4F, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; - readonly byte[] _unixHome = - { - 0x55, 0x6E, 0x69, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; - readonly byte[] _vmsHome = - { - 0x56, 0x41, 0x58, 0x20, 0x56, 0x4D, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; - Entry _dataFork; - Header _header; - string _headerPath; - Entry _rsrcFork; +#region IFilter Members /// - public string Name => "AppleDouble"; + public string Name => Localization.AppleDouble_Name; + /// public Guid Id => new("1B2165EE-C9DF-4B21-BBBB-9E5892B2DF4D"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public void Close() {} @@ -123,10 +109,12 @@ public sealed class AppleDouble : IFilter /// public Stream GetResourceForkStream() { - if(_rsrcFork.length == 0) - return null; + if(_rsrcFork.length == 0) return null; - return new OffsetStream(_headerPath, FileMode.Open, FileAccess.Read, _rsrcFork.offset, + return new OffsetStream(_headerPath, + FileMode.Open, + FileAccess.Read, + _rsrcFork.offset, _rsrcFork.offset + _rsrcFork.length - 1); } @@ -148,9 +136,7 @@ public sealed class AppleDouble : IFilter parentFolder ??= ""; - if(filename is null || - filenameNoExt is null) - return false; + if(filename is null || filenameNoExt is null) return false; // Prepend data fork name with "R." string proDosAppleDouble = System.IO.Path.Combine(parentFolder, "R." + filename); @@ -184,13 +170,11 @@ public sealed class AppleDouble : IFilter if(prodosStream.Length > 26) { var prodosB = new byte[26]; - prodosStream.Read(prodosB, 0, 26); + prodosStream.EnsureRead(prodosB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(prodosB); prodosStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - return true; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) return true; } } @@ -202,13 +186,11 @@ public sealed class AppleDouble : IFilter if(unixStream.Length > 26) { var unixB = new byte[26]; - unixStream.Read(unixB, 0, 26); + unixStream.EnsureRead(unixB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(unixB); unixStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - return true; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) return true; } } @@ -220,13 +202,11 @@ public sealed class AppleDouble : IFilter if(dosStream.Length > 26) { var dosB = new byte[26]; - dosStream.Read(dosB, 0, 26); + dosStream.EnsureRead(dosB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(dosB); dosStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - return true; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) return true; } } @@ -238,13 +218,11 @@ public sealed class AppleDouble : IFilter if(doslStream.Length > 26) { var doslB = new byte[26]; - doslStream.Read(doslB, 0, 26); + doslStream.EnsureRead(doslB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(doslB); doslStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - return true; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) return true; } } @@ -256,13 +234,11 @@ public sealed class AppleDouble : IFilter if(netatalkStream.Length > 26) { var netatalkB = new byte[26]; - netatalkStream.Read(netatalkB, 0, 26); + netatalkStream.EnsureRead(netatalkB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(netatalkB); netatalkStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - return true; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) return true; } } @@ -274,13 +250,11 @@ public sealed class AppleDouble : IFilter if(daveStream.Length > 26) { var daveB = new byte[26]; - daveStream.Read(daveB, 0, 26); + daveStream.EnsureRead(daveB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(daveB); daveStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - return true; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) return true; } } @@ -292,31 +266,27 @@ public sealed class AppleDouble : IFilter if(osxStream.Length > 26) { var osxB = new byte[26]; - osxStream.Read(osxB, 0, 26); + osxStream.EnsureRead(osxB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(osxB); osxStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - return true; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) return true; } } // Check AppleDouble created by UnAr (from The Unarchiver) - if(!File.Exists(unArAppleDouble)) - return false; + if(!File.Exists(unArAppleDouble)) return false; var unarStream = new FileStream(unArAppleDouble, FileMode.Open, FileAccess.Read); - if(unarStream.Length <= 26) - return false; + if(unarStream.Length <= 26) return false; var unarB = new byte[26]; - unarStream.Read(unarB, 0, 26); + unarStream.EnsureRead(unarB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(unarB); unarStream.Close(); - return _header.magic == MAGIC && _header.version is VERSION or VERSION2; + return _header is { magic: MAGIC, version: VERSION or VERSION2 }; } // Now way to have two files in a single byte array @@ -336,9 +306,7 @@ public sealed class AppleDouble : IFilter parentFolder ??= ""; - if(filename is null || - filenameNoExt is null) - return ErrorNumber.InvalidArgument; + if(filename is null || filenameNoExt is null) return ErrorNumber.InvalidArgument; // Prepend data fork name with "R." string proDosAppleDouble = System.IO.Path.Combine(parentFolder, "R." + filename); @@ -372,13 +340,11 @@ public sealed class AppleDouble : IFilter if(prodosStream.Length > 26) { var prodosB = new byte[26]; - prodosStream.Read(prodosB, 0, 26); + prodosStream.EnsureRead(prodosB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(prodosB); prodosStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - _headerPath = proDosAppleDouble; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) _headerPath = proDosAppleDouble; } } @@ -390,13 +356,11 @@ public sealed class AppleDouble : IFilter if(unixStream.Length > 26) { var unixB = new byte[26]; - unixStream.Read(unixB, 0, 26); + unixStream.EnsureRead(unixB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(unixB); unixStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - _headerPath = unixAppleDouble; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) _headerPath = unixAppleDouble; } } @@ -408,13 +372,11 @@ public sealed class AppleDouble : IFilter if(dosStream.Length > 26) { var dosB = new byte[26]; - dosStream.Read(dosB, 0, 26); + dosStream.EnsureRead(dosB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(dosB); dosStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - _headerPath = dosAppleDouble; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) _headerPath = dosAppleDouble; } } @@ -426,13 +388,11 @@ public sealed class AppleDouble : IFilter if(doslStream.Length > 26) { var doslB = new byte[26]; - doslStream.Read(doslB, 0, 26); + doslStream.EnsureRead(doslB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(doslB); doslStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - _headerPath = dosAppleDoubleLower; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) _headerPath = dosAppleDoubleLower; } } @@ -444,13 +404,11 @@ public sealed class AppleDouble : IFilter if(netatalkStream.Length > 26) { var netatalkB = new byte[26]; - netatalkStream.Read(netatalkB, 0, 26); + netatalkStream.EnsureRead(netatalkB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(netatalkB); netatalkStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - _headerPath = netatalkAppleDouble; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) _headerPath = netatalkAppleDouble; } } @@ -462,13 +420,11 @@ public sealed class AppleDouble : IFilter if(daveStream.Length > 26) { var daveB = new byte[26]; - daveStream.Read(daveB, 0, 26); + daveStream.EnsureRead(daveB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(daveB); daveStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - _headerPath = daveAppleDouble; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) _headerPath = daveAppleDouble; } } @@ -480,13 +436,11 @@ public sealed class AppleDouble : IFilter if(osxStream.Length > 26) { var osxB = new byte[26]; - osxStream.Read(osxB, 0, 26); + osxStream.EnsureRead(osxB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(osxB); osxStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - _headerPath = osxAppleDouble; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) _headerPath = osxAppleDouble; } } @@ -498,25 +452,22 @@ public sealed class AppleDouble : IFilter if(unarStream.Length > 26) { var unarB = new byte[26]; - unarStream.Read(unarB, 0, 26); + unarStream.EnsureRead(unarB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(unarB); unarStream.Close(); - if(_header.magic == MAGIC && - _header.version is VERSION or VERSION2) - _headerPath = unArAppleDouble; + if(_header is { magic: MAGIC, version: VERSION or VERSION2 }) _headerPath = unArAppleDouble; } } // TODO: More appropriate error - if(_headerPath is null) - return ErrorNumber.NotSupported; + if(_headerPath is null) return ErrorNumber.NotSupported; var fs = new FileStream(_headerPath, FileMode.Open, FileAccess.Read); fs.Seek(0, SeekOrigin.Begin); var hdrB = new byte[26]; - fs.Read(hdrB, 0, 26); + fs.EnsureRead(hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); var entries = new Entry[_header.entries]; @@ -524,7 +475,7 @@ public sealed class AppleDouble : IFilter for(var i = 0; i < _header.entries; i++) { var entry = new byte[12]; - fs.Read(entry, 0, 12); + fs.EnsureRead(entry, 0, 12); entries[i] = Marshal.ByteArrayToStructureBigEndian(entry); } @@ -532,6 +483,7 @@ public sealed class AppleDouble : IFilter LastWriteTime = CreationTime; foreach(Entry entry in entries) + { switch((EntryId)entry.id) { case EntryId.DataFork: @@ -540,7 +492,7 @@ public sealed class AppleDouble : IFilter case EntryId.FileDates: fs.Seek(entry.offset, SeekOrigin.Begin); var datesB = new byte[16]; - fs.Read(datesB, 0, 16); + fs.EnsureRead(datesB, 0, 16); FileDates dates = Marshal.ByteArrayToStructureBigEndian(datesB); @@ -551,7 +503,7 @@ public sealed class AppleDouble : IFilter case EntryId.FileInfo: fs.Seek(entry.offset, SeekOrigin.Begin); var finfo = new byte[entry.length]; - fs.Read(finfo, 0, finfo.Length); + fs.EnsureRead(finfo, 0, finfo.Length); if(_macintoshHome.SequenceEqual(_header.homeFilesystem)) { @@ -587,6 +539,7 @@ public sealed class AppleDouble : IFilter break; } + } _dataFork = new Entry { @@ -606,6 +559,34 @@ public sealed class AppleDouble : IFilter return ErrorNumber.NoError; } +#endregion + +#region Nested type: DOSFileInfo + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct DOSFileInfo + { + public readonly ushort modificationDate; + public readonly ushort modificationTime; + public readonly ushort attributes; + } + +#endregion + +#region Nested type: Entry + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Entry + { + public uint id; + public readonly uint offset; + public uint length; + } + +#endregion + +#region Nested type: EntryId + enum EntryId : uint { Invalid = 0, @@ -626,23 +607,9 @@ public sealed class AppleDouble : IFilter DirectoryID = 15 } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Header - { - public readonly uint magic; - public readonly uint version; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] homeFilesystem; - public readonly ushort entries; - } +#endregion - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct Entry - { - public uint id; - public readonly uint offset; - public uint length; - } +#region Nested type: FileDates [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct FileDates @@ -653,6 +620,24 @@ public sealed class AppleDouble : IFilter public readonly uint accessDate; } +#endregion + +#region Nested type: Header + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Header + { + public readonly uint magic; + public readonly uint version; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] homeFilesystem; + public readonly ushort entries; + } + +#endregion + +#region Nested type: MacFileInfo + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct MacFileInfo { @@ -662,21 +647,9 @@ public sealed class AppleDouble : IFilter public readonly uint accessDate; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct UnixFileInfo - { - public readonly uint creationDate; - public readonly uint accessDate; - public readonly uint modificationDate; - } +#endregion - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DOSFileInfo - { - public readonly ushort modificationDate; - public readonly ushort modificationTime; - public readonly ushort attributes; - } +#region Nested type: ProDOSFileInfo [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct ProDOSFileInfo @@ -688,4 +661,18 @@ public sealed class AppleDouble : IFilter public readonly ushort fileType; public readonly uint auxType; } + +#endregion + +#region Nested type: UnixFileInfo + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct UnixFileInfo + { + public readonly uint creationDate; + public readonly uint accessDate; + public readonly uint modificationDate; + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filters/AppleSingle.cs b/Aaru.Filters/AppleSingle.cs index 120cde87a..10106c405 100644 --- a/Aaru.Filters/AppleSingle.cs +++ b/Aaru.Filters/AppleSingle.cs @@ -27,11 +27,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filters; - using System; using System.Diagnostics.CodeAnalysis; using System.IO; @@ -40,54 +38,42 @@ using System.Runtime.InteropServices; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; +using Aaru.Helpers.IO; using Marshal = Aaru.Helpers.Marshal; +namespace Aaru.Filters; + /// /// Decodes AppleSingle files [SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed class AppleSingle : IFilter { - const uint MAGIC = 0x00051600; - const uint VERSION = 0x00010000; - const uint VERSION2 = 0x00020000; - readonly byte[] _dosHome = - { - 0x4D, 0x53, 0x2D, 0x44, 0x4F, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; + const uint MAGIC = 0x00051600; + const uint VERSION = 0x00010000; + const uint VERSION2 = 0x00020000; + readonly byte[] _dosHome = "MS-DOS "u8.ToArray(); + readonly byte[] _macintoshHome = "Macintosh "u8.ToArray(); + readonly byte[] _osxHome = "Mac OS X "u8.ToArray(); + readonly byte[] _proDosHome = "ProDOS "u8.ToArray(); + readonly byte[] _unixHome = "Unix "u8.ToArray(); + readonly byte[] _vmsHome = "VAX VMS "u8.ToArray(); + byte[] _bytes; + Entry _dataFork; + Header _header; + bool _isBytes, _isStream, _isPath; + Entry _rsrcFork; + Stream _stream; - readonly byte[] _macintoshHome = - { - 0x4D, 0x61, 0x63, 0x69, 0x6E, 0x74, 0x6F, 0x73, 0x68, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; - readonly byte[] _osxHome = - { - 0x4D, 0x61, 0x63, 0x20, 0x4F, 0x53, 0x20, 0x58, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; - readonly byte[] _proDosHome = - { - 0x50, 0x72, 0x6F, 0x44, 0x4F, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; - readonly byte[] _unixHome = - { - 0x55, 0x6E, 0x69, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; - readonly byte[] _vmsHome = - { - 0x56, 0x41, 0x58, 0x20, 0x56, 0x4D, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 - }; - byte[] _bytes; - Entry _dataFork; - Header _header; - bool _isBytes, _isStream, _isPath; - Entry _rsrcFork; - Stream _stream; +#region IFilter Members /// - public string Name => "AppleSingle"; + public string Name => Localization.AppleSingle_Name; + /// public Guid Id => new("A69B20E8-F4D3-42BB-BD2B-4A7263394A05"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public void Close() @@ -111,18 +97,20 @@ public sealed class AppleSingle : IFilter /// public Stream GetDataForkStream() { - if(_dataFork.length == 0) - return null; + if(_dataFork.length == 0) return null; - if(_isBytes) - return new OffsetStream(_bytes, _dataFork.offset, _dataFork.offset + _dataFork.length - 1); + if(_isBytes) return new OffsetStream(_bytes, _dataFork.offset, _dataFork.offset + _dataFork.length - 1); - if(_isStream) - return new OffsetStream(_stream, _dataFork.offset, _dataFork.offset + _dataFork.length - 1); + if(_isStream) return new OffsetStream(_stream, _dataFork.offset, _dataFork.offset + _dataFork.length - 1); if(_isPath) - return new OffsetStream(BasePath, FileMode.Open, FileAccess.Read, _dataFork.offset, + { + return new OffsetStream(BasePath, + FileMode.Open, + FileAccess.Read, + _dataFork.offset, _dataFork.offset + _dataFork.length - 1); + } return null; } @@ -148,18 +136,20 @@ public sealed class AppleSingle : IFilter /// public Stream GetResourceForkStream() { - if(_rsrcFork.length == 0) - return null; + if(_rsrcFork.length == 0) return null; - if(_isBytes) - return new OffsetStream(_bytes, _rsrcFork.offset, _rsrcFork.offset + _rsrcFork.length - 1); + if(_isBytes) return new OffsetStream(_bytes, _rsrcFork.offset, _rsrcFork.offset + _rsrcFork.length - 1); - if(_isStream) - return new OffsetStream(_stream, _rsrcFork.offset, _rsrcFork.offset + _rsrcFork.length - 1); + if(_isStream) return new OffsetStream(_stream, _rsrcFork.offset, _rsrcFork.offset + _rsrcFork.length - 1); if(_isPath) - return new OffsetStream(BasePath, FileMode.Open, FileAccess.Read, _rsrcFork.offset, + { + return new OffsetStream(BasePath, + FileMode.Open, + FileAccess.Read, + _rsrcFork.offset, _rsrcFork.offset + _rsrcFork.length - 1); + } return null; } @@ -170,50 +160,44 @@ public sealed class AppleSingle : IFilter /// public bool Identify(byte[] buffer) { - if(buffer == null || - buffer.Length < 26) - return false; + if(buffer == null || buffer.Length < 26) return false; var hdrB = new byte[26]; Array.Copy(buffer, 0, hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); - return _header.magic == MAGIC && _header.version is VERSION or VERSION2; + return _header is { magic: MAGIC, version: VERSION or VERSION2 }; } /// public bool Identify(Stream stream) { - if(stream == null || - stream.Length < 26) - return false; + if(stream == null || stream.Length < 26) return false; var hdrB = new byte[26]; stream.Seek(0, SeekOrigin.Begin); - stream.Read(hdrB, 0, 26); + stream.EnsureRead(hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); - return _header.magic == MAGIC && _header.version is VERSION or VERSION2; + return _header is { magic: MAGIC, version: VERSION or VERSION2 }; } /// public bool Identify(string path) { - if(!File.Exists(path)) - return false; + if(!File.Exists(path)) return false; var fstream = new FileStream(path, FileMode.Open, FileAccess.Read); - if(fstream.Length < 26) - return false; + if(fstream.Length < 26) return false; var hdrB = new byte[26]; - fstream.Read(hdrB, 0, 26); + fstream.EnsureRead(hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); fstream.Close(); - return _header.magic == MAGIC && _header.version is VERSION or VERSION2; + return _header is { magic: MAGIC, version: VERSION or VERSION2 }; } /// @@ -223,7 +207,7 @@ public sealed class AppleSingle : IFilter ms.Seek(0, SeekOrigin.Begin); var hdrB = new byte[26]; - ms.Read(hdrB, 0, 26); + ms.EnsureRead(hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); var entries = new Entry[_header.entries]; @@ -231,7 +215,7 @@ public sealed class AppleSingle : IFilter for(var i = 0; i < _header.entries; i++) { var entry = new byte[12]; - ms.Read(entry, 0, 12); + ms.EnsureRead(entry, 0, 12); entries[i] = Marshal.ByteArrayToStructureBigEndian(entry); } @@ -239,6 +223,7 @@ public sealed class AppleSingle : IFilter LastWriteTime = CreationTime; foreach(Entry entry in entries) + { switch((AppleSingleEntryID)entry.id) { case AppleSingleEntryID.DataFork: @@ -248,7 +233,7 @@ public sealed class AppleSingle : IFilter case AppleSingleEntryID.FileDates: ms.Seek(entry.offset, SeekOrigin.Begin); var datesB = new byte[16]; - ms.Read(datesB, 0, 16); + ms.EnsureRead(datesB, 0, 16); FileDates dates = Marshal.ByteArrayToStructureBigEndian(datesB); @@ -259,7 +244,7 @@ public sealed class AppleSingle : IFilter case AppleSingleEntryID.FileInfo: ms.Seek(entry.offset, SeekOrigin.Begin); var finfo = new byte[entry.length]; - ms.Read(finfo, 0, finfo.Length); + ms.EnsureRead(finfo, 0, finfo.Length); if(_macintoshHome.SequenceEqual(_header.homeFilesystem)) { @@ -295,6 +280,7 @@ public sealed class AppleSingle : IFilter break; } + } ms.Close(); _isBytes = true; @@ -309,7 +295,7 @@ public sealed class AppleSingle : IFilter stream.Seek(0, SeekOrigin.Begin); var hdrB = new byte[26]; - stream.Read(hdrB, 0, 26); + stream.EnsureRead(hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); var entries = new Entry[_header.entries]; @@ -317,7 +303,7 @@ public sealed class AppleSingle : IFilter for(var i = 0; i < _header.entries; i++) { var entry = new byte[12]; - stream.Read(entry, 0, 12); + stream.EnsureRead(entry, 0, 12); entries[i] = Marshal.ByteArrayToStructureBigEndian(entry); } @@ -325,6 +311,7 @@ public sealed class AppleSingle : IFilter LastWriteTime = CreationTime; foreach(Entry entry in entries) + { switch((AppleSingleEntryID)entry.id) { case AppleSingleEntryID.DataFork: @@ -334,7 +321,7 @@ public sealed class AppleSingle : IFilter case AppleSingleEntryID.FileDates: stream.Seek(entry.offset, SeekOrigin.Begin); var datesB = new byte[16]; - stream.Read(datesB, 0, 16); + stream.EnsureRead(datesB, 0, 16); FileDates dates = Marshal.ByteArrayToStructureBigEndian(datesB); @@ -345,7 +332,7 @@ public sealed class AppleSingle : IFilter case AppleSingleEntryID.FileInfo: stream.Seek(entry.offset, SeekOrigin.Begin); var finfo = new byte[entry.length]; - stream.Read(finfo, 0, finfo.Length); + stream.EnsureRead(finfo, 0, finfo.Length); if(_macintoshHome.SequenceEqual(_header.homeFilesystem)) { @@ -381,6 +368,7 @@ public sealed class AppleSingle : IFilter break; } + } stream.Seek(0, SeekOrigin.Begin); _isStream = true; @@ -396,7 +384,7 @@ public sealed class AppleSingle : IFilter fs.Seek(0, SeekOrigin.Begin); var hdrB = new byte[26]; - fs.Read(hdrB, 0, 26); + fs.EnsureRead(hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); var entries = new Entry[_header.entries]; @@ -404,7 +392,7 @@ public sealed class AppleSingle : IFilter for(var i = 0; i < _header.entries; i++) { var entry = new byte[12]; - fs.Read(entry, 0, 12); + fs.EnsureRead(entry, 0, 12); entries[i] = Marshal.ByteArrayToStructureBigEndian(entry); } @@ -412,6 +400,7 @@ public sealed class AppleSingle : IFilter LastWriteTime = CreationTime; foreach(Entry entry in entries) + { switch((AppleSingleEntryID)entry.id) { case AppleSingleEntryID.DataFork: @@ -421,7 +410,7 @@ public sealed class AppleSingle : IFilter case AppleSingleEntryID.FileDates: fs.Seek(entry.offset, SeekOrigin.Begin); var datesB = new byte[16]; - fs.Read(datesB, 0, 16); + fs.EnsureRead(datesB, 0, 16); FileDates dates = Marshal.ByteArrayToStructureBigEndian(datesB); @@ -432,7 +421,7 @@ public sealed class AppleSingle : IFilter case AppleSingleEntryID.FileInfo: fs.Seek(entry.offset, SeekOrigin.Begin); var finfo = new byte[entry.length]; - fs.Read(finfo, 0, finfo.Length); + fs.EnsureRead(finfo, 0, finfo.Length); if(_macintoshHome.SequenceEqual(_header.homeFilesystem)) { @@ -468,6 +457,7 @@ public sealed class AppleSingle : IFilter break; } + } fs.Close(); _isPath = true; @@ -476,6 +466,10 @@ public sealed class AppleSingle : IFilter return ErrorNumber.NoError; } +#endregion + +#region Nested type: AppleSingleEntryID + enum AppleSingleEntryID : uint { Invalid = 0, @@ -496,16 +490,22 @@ public sealed class AppleSingle : IFilter DirectoryID = 15 } +#endregion + +#region Nested type: DOSFileInfo + [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct Header + readonly struct DOSFileInfo { - public readonly uint magic; - public readonly uint version; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public readonly byte[] homeFilesystem; - public readonly ushort entries; + public readonly ushort modificationDate; + public readonly ushort modificationTime; + public readonly ushort attributes; } +#endregion + +#region Nested type: Entry + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct Entry { @@ -514,6 +514,10 @@ public sealed class AppleSingle : IFilter public readonly uint length; } +#endregion + +#region Nested type: FileDates + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct FileDates { @@ -523,6 +527,24 @@ public sealed class AppleSingle : IFilter public readonly uint accessDate; } +#endregion + +#region Nested type: Header + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct Header + { + public readonly uint magic; + public readonly uint version; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public readonly byte[] homeFilesystem; + public readonly ushort entries; + } + +#endregion + +#region Nested type: MacFileInfo + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct MacFileInfo { @@ -532,21 +554,9 @@ public sealed class AppleSingle : IFilter public readonly uint accessDate; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct UnixFileInfo - { - public readonly uint creationDate; - public readonly uint accessDate; - public readonly uint modificationDate; - } +#endregion - [StructLayout(LayoutKind.Sequential, Pack = 1)] - readonly struct DOSFileInfo - { - public readonly ushort modificationDate; - public readonly ushort modificationTime; - public readonly ushort attributes; - } +#region Nested type: ProDOSFileInfo [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct ProDOSFileInfo @@ -558,4 +568,18 @@ public sealed class AppleSingle : IFilter public readonly ushort fileType; public readonly uint auxType; } + +#endregion + +#region Nested type: UnixFileInfo + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + readonly struct UnixFileInfo + { + public readonly uint creationDate; + public readonly uint accessDate; + public readonly uint modificationDate; + } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filters/Authors.cs b/Aaru.Filters/Authors.cs new file mode 100644 index 000000000..26a4974d0 --- /dev/null +++ b/Aaru.Filters/Authors.cs @@ -0,0 +1,37 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Authors.cs +// Author(s) : Natalia Portillo +// +// Component : Filters. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2024 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.Filters; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +static class Authors +{ + internal const string NataliaPortillo = "Natalia Portillo"; +} \ No newline at end of file diff --git a/Aaru.Filters/BZip2.cs b/Aaru.Filters/BZip2.cs index c29195c63..42ed7548e 100644 --- a/Aaru.Filters/BZip2.cs +++ b/Aaru.Filters/BZip2.cs @@ -27,17 +27,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filters; - using System; using System.IO; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Aaru.Helpers.IO; using Ionic.BZip2; +namespace Aaru.Filters; + /// /// Decompress bz2 files while reading public class BZip2 : IFilter @@ -45,12 +47,16 @@ public class BZip2 : IFilter Stream _dataStream; Stream _innerStream; +#region IFilter Members + /// - public string Name => "BZip2"; + public string Name => Localization.BZip2_Name; + /// public Guid Id => new("FCCFB0C3-32EF-40D8-9714-2333F6AC72A9"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public void Close() @@ -78,15 +84,10 @@ public class BZip2 : IFilter /// public bool Identify(byte[] buffer) { - if(buffer[0] != 0x42 || - buffer[1] != 0x5A || - buffer[2] != 0x68 || - buffer[3] < 0x31 || - buffer[3] > 0x39) + if(buffer[0] != 0x42 || buffer[1] != 0x5A || buffer[2] != 0x68 || buffer[3] < 0x31 || buffer[3] > 0x39) return false; - if(buffer.Length <= 512) - return true; + if(buffer.Length <= 512) return true; return buffer[^512] != 0x6B || buffer[^511] != 0x6F || buffer[^510] != 0x6C || buffer[^509] != 0x79; } @@ -97,21 +98,16 @@ public class BZip2 : IFilter var buffer = new byte[4]; stream.Seek(0, SeekOrigin.Begin); - stream.Read(buffer, 0, 4); + stream.EnsureRead(buffer, 0, 4); stream.Seek(0, SeekOrigin.Begin); - if(buffer[0] != 0x42 || - buffer[1] != 0x5A || - buffer[2] != 0x68 || - buffer[3] < 0x31 || - buffer[3] > 0x39) + if(buffer[0] != 0x42 || buffer[1] != 0x5A || buffer[2] != 0x68 || buffer[3] < 0x31 || buffer[3] > 0x39) return false; - if(stream.Length <= 512) - return true; + if(stream.Length <= 512) return true; stream.Seek(-512, SeekOrigin.End); - stream.Read(buffer, 0, 4); + stream.EnsureRead(buffer, 0, 4); stream.Seek(0, SeekOrigin.Begin); // Check it is not an UDIF @@ -121,28 +117,22 @@ public class BZip2 : IFilter /// public bool Identify(string path) { - if(!File.Exists(path)) - return false; + if(!File.Exists(path)) return false; var stream = new FileStream(path, FileMode.Open, FileAccess.Read); var buffer = new byte[4]; stream.Seek(0, SeekOrigin.Begin); - stream.Read(buffer, 0, 4); + stream.EnsureRead(buffer, 0, 4); stream.Seek(0, SeekOrigin.Begin); - if(buffer[0] != 0x42 || - buffer[1] != 0x5A || - buffer[2] != 0x68 || - buffer[3] < 0x31 || - buffer[3] > 0x39) + if(buffer[0] != 0x42 || buffer[1] != 0x5A || buffer[2] != 0x68 || buffer[3] < 0x31 || buffer[3] > 0x39) return false; - if(stream.Length <= 512) - return true; + if(stream.Length <= 512) return true; stream.Seek(-512, SeekOrigin.End); - stream.Read(buffer, 0, 4); + stream.EnsureRead(buffer, 0, 4); stream.Seek(0, SeekOrigin.Begin); // Check it is not an UDIF @@ -210,14 +200,16 @@ public class BZip2 : IFilter { get { - if(BasePath?.EndsWith(".bz2", StringComparison.InvariantCultureIgnoreCase) == true) - return BasePath.Substring(0, BasePath.Length - 4); + if(BasePath?.EndsWith(".bz2", StringComparison.InvariantCultureIgnoreCase) == true) return BasePath[..^4]; return BasePath?.EndsWith(".bzip2", StringComparison.InvariantCultureIgnoreCase) == true - ? BasePath.Substring(0, BasePath.Length - 6) : BasePath; + ? BasePath[..^6] + : BasePath; } } /// public string ParentFolder => System.IO.Path.GetDirectoryName(BasePath); + +#endregion } \ No newline at end of file diff --git a/Aaru.Filters/GZip.cs b/Aaru.Filters/GZip.cs index 09cffcf4c..688a4eb21 100644 --- a/Aaru.Filters/GZip.cs +++ b/Aaru.Filters/GZip.cs @@ -27,17 +27,18 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filters; - using System; using System.IO; using System.IO.Compression; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; +using Aaru.Helpers.IO; + +namespace Aaru.Filters; /// /// Decompress gzip files while reading @@ -47,12 +48,16 @@ public sealed class GZip : IFilter uint _decompressedSize; Stream _zStream; +#region IFilter Members + /// - public string Name => "GZip"; + public string Name => Localization.GZip_Name; + /// public Guid Id => new("F4996661-4A29-42C9-A2C7-3904EF40F3B0"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public void Close() @@ -86,7 +91,7 @@ public sealed class GZip : IFilter var buffer = new byte[3]; stream.Seek(0, SeekOrigin.Begin); - stream.Read(buffer, 0, 3); + stream.EnsureRead(buffer, 0, 3); stream.Seek(0, SeekOrigin.Begin); return buffer[0] == 0x1F && buffer[1] == 0x8B && buffer[2] == 0x08; @@ -95,14 +100,13 @@ public sealed class GZip : IFilter /// public bool Identify(string path) { - if(!File.Exists(path)) - return false; + if(!File.Exists(path)) return false; var stream = new FileStream(path, FileMode.Open, FileAccess.Read); var buffer = new byte[3]; stream.Seek(0, SeekOrigin.Begin); - stream.Read(buffer, 0, 3); + stream.EnsureRead(buffer, 0, 3); stream.Seek(0, SeekOrigin.Begin); return buffer[0] == 0x1F && buffer[1] == 0x8B && buffer[2] == 0x08; @@ -118,9 +122,9 @@ public sealed class GZip : IFilter BasePath = null; _dataStream.Seek(4, SeekOrigin.Begin); - _dataStream.Read(mtimeB, 0, 4); + _dataStream.EnsureRead(mtimeB, 0, 4); _dataStream.Seek(-4, SeekOrigin.End); - _dataStream.Read(isizeB, 0, 4); + _dataStream.EnsureRead(isizeB, 0, 4); _dataStream.Seek(0, SeekOrigin.Begin); var mtime = BitConverter.ToUInt32(mtimeB, 0); @@ -145,9 +149,9 @@ public sealed class GZip : IFilter BasePath = null; _dataStream.Seek(4, SeekOrigin.Begin); - _dataStream.Read(mtimeB, 0, 4); + _dataStream.EnsureRead(mtimeB, 0, 4); _dataStream.Seek(-4, SeekOrigin.End); - _dataStream.Read(isizeB, 0, 4); + _dataStream.EnsureRead(isizeB, 0, 4); _dataStream.Seek(0, SeekOrigin.Begin); var mtime = BitConverter.ToUInt32(mtimeB, 0); @@ -172,9 +176,9 @@ public sealed class GZip : IFilter BasePath = System.IO.Path.GetFullPath(path); _dataStream.Seek(4, SeekOrigin.Begin); - _dataStream.Read(mtimeB, 0, 4); + _dataStream.EnsureRead(mtimeB, 0, 4); _dataStream.Seek(-4, SeekOrigin.End); - _dataStream.Read(isizeB, 0, 4); + _dataStream.EnsureRead(isizeB, 0, 4); _dataStream.Seek(0, SeekOrigin.Begin); var mtime = BitConverter.ToUInt32(mtimeB, 0); @@ -209,14 +213,16 @@ public sealed class GZip : IFilter { get { - if(BasePath?.EndsWith(".gz", StringComparison.InvariantCultureIgnoreCase) == true) - return BasePath.Substring(0, BasePath.Length - 3); + if(BasePath?.EndsWith(".gz", StringComparison.InvariantCultureIgnoreCase) == true) return BasePath[..^3]; return BasePath?.EndsWith(".gzip", StringComparison.InvariantCultureIgnoreCase) == true - ? BasePath.Substring(0, BasePath.Length - 5) : BasePath; + ? BasePath[..^5] + : BasePath; } } /// public string ParentFolder => System.IO.Path.GetDirectoryName(BasePath); + +#endregion } \ No newline at end of file diff --git a/Aaru.Filters/LZip.cs b/Aaru.Filters/LZip.cs index b7f2ab207..044dae4eb 100644 --- a/Aaru.Filters/LZip.cs +++ b/Aaru.Filters/LZip.cs @@ -27,18 +27,20 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filters; - using System; using System.IO; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Aaru.Helpers.IO; using SharpCompress.Compressors; using SharpCompress.Compressors.LZMA; +namespace Aaru.Filters; + /// /// Decompress lzip files while reading public sealed class LZip : IFilter @@ -46,12 +48,16 @@ public sealed class LZip : IFilter Stream _dataStream; Stream _innerStream; +#region IFilter Members + /// - public string Name => "LZip"; + public string Name => Localization.LZip_Name; + /// public Guid Id => new("09D715E9-20C0-48B1-A8D9-D8897CEC57C9"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public void Close() @@ -77,8 +83,11 @@ public sealed class LZip : IFilter public bool HasResourceFork => false; /// - public bool Identify(byte[] buffer) => buffer[0] == 0x4C && buffer[1] == 0x5A && buffer[2] == 0x49 && - buffer[3] == 0x50 && buffer[4] == 0x01; + public bool Identify(byte[] buffer) => buffer[0] == 0x4C && + buffer[1] == 0x5A && + buffer[2] == 0x49 && + buffer[3] == 0x50 && + buffer[4] == 0x01; /// public bool Identify(Stream stream) @@ -86,7 +95,7 @@ public sealed class LZip : IFilter var buffer = new byte[5]; stream.Seek(0, SeekOrigin.Begin); - stream.Read(buffer, 0, 5); + stream.EnsureRead(buffer, 0, 5); stream.Seek(0, SeekOrigin.Begin); return buffer[0] == 0x4C && buffer[1] == 0x5A && buffer[2] == 0x49 && buffer[3] == 0x50 && buffer[4] == 0x01; @@ -95,14 +104,13 @@ public sealed class LZip : IFilter /// public bool Identify(string path) { - if(!File.Exists(path)) - return false; + if(!File.Exists(path)) return false; var stream = new FileStream(path, FileMode.Open, FileAccess.Read); var buffer = new byte[5]; stream.Seek(0, SeekOrigin.Begin); - stream.Read(buffer, 0, 5); + stream.EnsureRead(buffer, 0, 5); stream.Seek(0, SeekOrigin.Begin); return buffer[0] == 0x4C && buffer[1] == 0x5A && buffer[2] == 0x49 && buffer[3] == 0x50 && buffer[4] == 0x01; @@ -131,7 +139,7 @@ public sealed class LZip : IFilter LastWriteTime = CreationTime; var tmp = new byte[8]; _dataStream.Seek(-16, SeekOrigin.End); - _dataStream.Read(tmp, 0, 8); + _dataStream.EnsureRead(tmp, 0, 8); DataForkLength = BitConverter.ToInt64(tmp, 0); _dataStream.Seek(0, SeekOrigin.Begin); _innerStream = new ForcedSeekStream(DataForkLength, _dataStream, CompressionMode.Decompress); @@ -150,7 +158,7 @@ public sealed class LZip : IFilter LastWriteTime = fi.LastWriteTimeUtc; var tmp = new byte[8]; _dataStream.Seek(-16, SeekOrigin.End); - _dataStream.Read(tmp, 0, 8); + _dataStream.EnsureRead(tmp, 0, 8); DataForkLength = BitConverter.ToInt64(tmp, 0); _dataStream.Seek(0, SeekOrigin.Begin); _innerStream = new ForcedSeekStream(DataForkLength, _dataStream, CompressionMode.Decompress); @@ -178,14 +186,16 @@ public sealed class LZip : IFilter { get { - if(BasePath?.EndsWith(".lz", StringComparison.InvariantCultureIgnoreCase) == true) - return BasePath.Substring(0, BasePath.Length - 3); + if(BasePath?.EndsWith(".lz", StringComparison.InvariantCultureIgnoreCase) == true) return BasePath[..^3]; return BasePath?.EndsWith(".lzip", StringComparison.InvariantCultureIgnoreCase) == true - ? BasePath.Substring(0, BasePath.Length - 5) : BasePath; + ? BasePath[..^5] + : BasePath; } } /// public string ParentFolder => System.IO.Path.GetDirectoryName(BasePath); + +#endregion } \ No newline at end of file diff --git a/Aaru.Filters/Localization/Localization.Designer.cs b/Aaru.Filters/Localization/Localization.Designer.cs new file mode 100644 index 000000000..acb88643f --- /dev/null +++ b/Aaru.Filters/Localization/Localization.Designer.cs @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Aaru.Filters { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Localization { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Localization() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aaru.Filters.Localization.Localization", typeof(Localization).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to AppleDouble. + /// + internal static string AppleDouble_Name { + get { + return ResourceManager.GetString("AppleDouble_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AppleSingle. + /// + internal static string AppleSingle_Name { + get { + return ResourceManager.GetString("AppleSingle_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BZip2. + /// + internal static string BZip2_Name { + get { + return ResourceManager.GetString("BZip2_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to GZip. + /// + internal static string GZip_Name { + get { + return ResourceManager.GetString("GZip_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to LZip. + /// + internal static string LZip_Name { + get { + return ResourceManager.GetString("LZip_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MacBinary. + /// + internal static string MacBinary_Name { + get { + return ResourceManager.GetString("MacBinary_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PCExchange. + /// + internal static string PcExchange_Name { + get { + return ResourceManager.GetString("PcExchange_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XZ. + /// + internal static string XZ_Name { + get { + return ResourceManager.GetString("XZ_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No filter. + /// + internal static string ZZZNoFilter_Name { + get { + return ResourceManager.GetString("ZZZNoFilter_Name", resourceCulture); + } + } + } +} diff --git a/Aaru.Filters/Localization/Localization.es.resx b/Aaru.Filters/Localization/Localization.es.resx new file mode 100644 index 000000000..43bbdf342 --- /dev/null +++ b/Aaru.Filters/Localization/Localization.es.resx @@ -0,0 +1,46 @@ + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + AppleDouble + + + AppleSingle + + + BZip2 + + + GZip + + + LZip + + + MacBinary + + + PCExchange + + + XZ + + + Sin filtro + + \ No newline at end of file diff --git a/Aaru.Filters/Localization/Localization.resx b/Aaru.Filters/Localization/Localization.resx new file mode 100644 index 000000000..7f910c6ec --- /dev/null +++ b/Aaru.Filters/Localization/Localization.resx @@ -0,0 +1,53 @@ + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + AppleDouble + + + AppleSingle + + + BZip2 + + + GZip + + + LZip + + + MacBinary + + + PCExchange + + + XZ + + + No filter + + \ No newline at end of file diff --git a/Aaru.Filters/MacBinary.cs b/Aaru.Filters/MacBinary.cs index 3d2c5d87a..61d539b63 100644 --- a/Aaru.Filters/MacBinary.cs +++ b/Aaru.Filters/MacBinary.cs @@ -27,11 +27,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filters; - using System; using System.IO; using System.Runtime.InteropServices; @@ -39,8 +37,11 @@ using System.Text; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; +using Aaru.Helpers.IO; using Marshal = Aaru.Helpers.Marshal; +namespace Aaru.Filters; + // TODO: Interpret fdScript /// /// Decodes MacBinary files @@ -54,12 +55,16 @@ public sealed class MacBinary : IFilter long _rsrcForkOff; Stream _stream; +#region IFilter Members + /// - public string Name => "MacBinary"; + public string Name => Localization.MacBinary_Name; + /// public Guid Id => new("D7C321D3-E51F-45DF-A150-F6BFDF0D7704"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public void Close() @@ -83,18 +88,20 @@ public sealed class MacBinary : IFilter /// public Stream GetDataForkStream() { - if(_header.dataLength == 0) - return null; + if(_header.dataLength == 0) return null; - if(_isBytes) - return new OffsetStream(_bytes, _dataForkOff, _dataForkOff + _header.dataLength - 1); + if(_isBytes) return new OffsetStream(_bytes, _dataForkOff, _dataForkOff + _header.dataLength - 1); - if(_isStream) - return new OffsetStream(_stream, _dataForkOff, _dataForkOff + _header.dataLength - 1); + if(_isStream) return new OffsetStream(_stream, _dataForkOff, _dataForkOff + _header.dataLength - 1); if(_isPath) - return new OffsetStream(BasePath, FileMode.Open, FileAccess.Read, _dataForkOff, + { + return new OffsetStream(BasePath, + FileMode.Open, + FileAccess.Read, + _dataForkOff, _dataForkOff + _header.dataLength - 1); + } return null; } @@ -120,18 +127,20 @@ public sealed class MacBinary : IFilter /// public Stream GetResourceForkStream() { - if(_header.resourceLength == 0) - return null; + if(_header.resourceLength == 0) return null; - if(_isBytes) - return new OffsetStream(_bytes, _rsrcForkOff, _rsrcForkOff + _header.resourceLength - 1); + if(_isBytes) return new OffsetStream(_bytes, _rsrcForkOff, _rsrcForkOff + _header.resourceLength - 1); - if(_isStream) - return new OffsetStream(_stream, _rsrcForkOff, _rsrcForkOff + _header.resourceLength - 1); + if(_isStream) return new OffsetStream(_stream, _rsrcForkOff, _rsrcForkOff + _header.resourceLength - 1); if(_isPath) - return new OffsetStream(BasePath, FileMode.Open, FileAccess.Read, _rsrcForkOff, + { + return new OffsetStream(BasePath, + FileMode.Open, + FileAccess.Read, + _rsrcForkOff, _rsrcForkOff + _header.resourceLength - 1); + } return null; } @@ -142,55 +151,61 @@ public sealed class MacBinary : IFilter /// public bool Identify(byte[] buffer) { - if(buffer == null || - buffer.Length < 128) - return false; + if(buffer == null || buffer.Length < 128) return false; var hdrB = new byte[128]; Array.Copy(buffer, 0, hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); - return _header.magic == MAGIC || _header.version == 0 && _header.filename[0] > 0 && _header.filename[0] < 64 && - _header.zero1 == 0 && _header.zero2 == 0 && _header.reserved == 0 && + return _header.magic == MAGIC || + _header.version == 0 && + _header.filename[0] > 0 && + _header.filename[0] < 64 && + _header.zero1 == 0 && + _header is { zero2: 0, reserved: 0 } && (_header.dataLength > 0 || _header.resourceLength > 0); } /// public bool Identify(Stream stream) { - if(stream == null || - stream.Length < 128) - return false; + if(stream == null || stream.Length < 128) return false; var hdrB = new byte[128]; stream.Seek(0, SeekOrigin.Begin); - stream.Read(hdrB, 0, 128); + stream.EnsureRead(hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); - return _header.magic == MAGIC || _header.version == 0 && _header.filename[0] > 0 && _header.filename[0] < 64 && - _header.zero1 == 0 && _header.zero2 == 0 && _header.reserved == 0 && + return _header.magic == MAGIC || + _header.version == 0 && + _header.filename[0] > 0 && + _header.filename[0] < 64 && + _header.zero1 == 0 && + _header is { zero2: 0, reserved: 0 } && (_header.dataLength > 0 || _header.resourceLength > 0); } /// public bool Identify(string path) { - if(!File.Exists(path)) - return false; + if(!File.Exists(path)) return false; var fstream = new FileStream(path, FileMode.Open, FileAccess.Read); - if(fstream.Length < 128) - return false; + if(fstream.Length < 128) return false; var hdrB = new byte[128]; - fstream.Read(hdrB, 0, 128); + fstream.EnsureRead(hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); fstream.Close(); - return _header.magic == MAGIC || _header.version == 0 && _header.filename[0] > 0 && _header.filename[0] < 64 && - _header.zero1 == 0 && _header.zero2 == 0 && _header.reserved == 0 && + return _header.magic == MAGIC || + _header.version == 0 && + _header.filename[0] > 0 && + _header.filename[0] < 64 && + _header.zero1 == 0 && + _header is { zero2: 0, reserved: 0 } && (_header.dataLength > 0 || _header.resourceLength > 0); } @@ -201,20 +216,18 @@ public sealed class MacBinary : IFilter ms.Seek(0, SeekOrigin.Begin); var hdrB = new byte[128]; - ms.Read(hdrB, 0, 128); + ms.EnsureRead(hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); uint blocks = 1; blocks += (uint)(_header.secondaryHeaderLength / 128); - if(_header.secondaryHeaderLength % 128 > 0) - blocks++; + if(_header.secondaryHeaderLength % 128 > 0) blocks++; _dataForkOff = blocks * 128; blocks += _header.dataLength / 128; - if(_header.dataLength % 128 > 0) - blocks++; + if(_header.dataLength % 128 > 0) blocks++; _rsrcForkOff = blocks * 128; @@ -235,20 +248,18 @@ public sealed class MacBinary : IFilter stream.Seek(0, SeekOrigin.Begin); var hdrB = new byte[128]; - stream.Read(hdrB, 0, 128); + stream.EnsureRead(hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); uint blocks = 1; blocks += (uint)(_header.secondaryHeaderLength / 128); - if(_header.secondaryHeaderLength % 128 > 0) - blocks++; + if(_header.secondaryHeaderLength % 128 > 0) blocks++; _dataForkOff = blocks * 128; blocks += _header.dataLength / 128; - if(_header.dataLength % 128 > 0) - blocks++; + if(_header.dataLength % 128 > 0) blocks++; _rsrcForkOff = blocks * 128; @@ -270,20 +281,18 @@ public sealed class MacBinary : IFilter fs.Seek(0, SeekOrigin.Begin); var hdrB = new byte[128]; - fs.Read(hdrB, 0, 128); + fs.EnsureRead(hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian
(hdrB); uint blocks = 1; blocks += (uint)(_header.secondaryHeaderLength / 128); - if(_header.secondaryHeaderLength % 128 > 0) - blocks++; + if(_header.secondaryHeaderLength % 128 > 0) blocks++; _dataForkOff = blocks * 128; blocks += _header.dataLength / 128; - if(_header.dataLength % 128 > 0) - blocks++; + if(_header.dataLength % 128 > 0) blocks++; _rsrcForkOff = blocks * 128; @@ -298,6 +307,10 @@ public sealed class MacBinary : IFilter return ErrorNumber.NoError; } +#endregion + +#region Nested type: Header + [StructLayout(LayoutKind.Sequential, Pack = 1)] struct Header { @@ -337,21 +350,24 @@ public sealed class MacBinary : IFilter /// 0x65, Low byte of Finder flags public readonly byte finderFlags2; - #region MacBinary III +#region MacBinary III + /// 0x66, magic identifier, "mBIN" public readonly uint magic; /// 0x6A, fdScript from fxInfo, identifies codepage of filename public readonly byte fdScript; /// 0x6B, fdXFlags from fxInfo, extended Mac OS 8 finder flags public readonly byte fdXFlags; - #endregion MacBinary III + +#endregion MacBinary III /// 0x6C, unused public readonly ulong reserved; /// 0x74, Total unpacked files public readonly uint totalPackedFiles; - #region MacBinary II +#region MacBinary II + /// 0x78, Length of secondary header public readonly ushort secondaryHeaderLength; /// 0x7A, version number of MacBinary that wrote this file, starts at 129 @@ -360,9 +376,12 @@ public sealed class MacBinary : IFilter public readonly byte minVersion; /// 0x7C, CRC of previous bytes public readonly short crc; - #endregion MacBinary II + +#endregion MacBinary II /// 0x7E, Reserved for computer type and OS ID public readonly short computerID; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filters/OffsetStream.cs b/Aaru.Filters/OffsetStream.cs deleted file mode 100644 index 6fe5dad43..000000000 --- a/Aaru.Filters/OffsetStream.cs +++ /dev/null @@ -1,684 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : OffsetStream.cs -// Author(s) : Natalia Portillo -// -// Component : Filters. -// -// --[ Description ] ---------------------------------------------------------- -// -// Provides a stream that's a subset of another stream. -// -// --[ License ] -------------------------------------------------------------- -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo -// ****************************************************************************/ - -#if !NETSTANDARD2_0 - -#endif - -namespace Aaru.Filters -{ - using System; - using System.IO; - using Microsoft.Win32.SafeHandles; - - /// Creates a stream that is a subset of another stream. - /// - public sealed class OffsetStream : Stream - { - readonly Stream _baseStream; - readonly long _streamEnd; - readonly long _streamStart; - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified stream, both inclusive. - /// - /// Base stream - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(Stream stream, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = stream; - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified file, both inclusive. - /// - /// A relative or absolute path for the file that the stream will encapsulate. - /// One of the enumeration values that determines how to open or create the file. - /// - /// A bitwise combination of the enumeration values that determines how the file can be accessed by a - /// object. - /// - /// - /// A bitwise combination of the enumeration values that determines how the file will be shared by - /// processes. - /// - /// - /// A positive Int32 value greater than 0 indicating the buffer size. The default buffer size is - /// 4096. - /// - /// A bitwise combination of the enumeration values that specifies additional file options. - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, - FileOptions options, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new FileStream(path, mode, access, share, bufferSize, options); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified file, both inclusive. - /// - /// A file handle for the file that the stream will encapsulate. - /// - /// A bitwise combination of the enumeration values that determines how the file can be accessed by a - /// object. - /// - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(SafeFileHandle handle, FileAccess access, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new FileStream(handle, access); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified file, both inclusive. - /// - /// A file handle for the file that the stream will encapsulate. - /// - /// A bitwise combination of the enumeration values that determines how the file can be accessed by a - /// object. - /// - /// - /// A positive Int32 value greater than 0 indicating the buffer size. The default buffer size is - /// 4096. - /// - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(SafeFileHandle handle, FileAccess access, int bufferSize, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new FileStream(handle, access, bufferSize); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified file, both inclusive. - /// - /// A file handle for the file that the stream will encapsulate. - /// - /// A bitwise combination of the enumeration values that determines how the file can be accessed by a - /// object. - /// - /// - /// A positive Int32 value greater than 0 indicating the buffer size. The default buffer size is - /// 4096. - /// - /// Specifies whether to use asynchronous I/O or synchronous I/O. - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync, long start, - long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new FileStream(handle, access, bufferSize, isAsync); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified file, both inclusive. - /// - /// A relative or absolute path for the file that the stream will encapsulate. - /// One of the enumeration values that determines how to open or create the file. - /// - /// A bitwise combination of the enumeration values that determines how the file can be accessed by a - /// object. - /// - /// - /// A bitwise combination of the enumeration values that determines how the file will be shared by - /// processes. - /// - /// - /// A positive Int32 value greater than 0 indicating the buffer size. The default buffer size is - /// 4096. - /// - /// Specifies whether to use asynchronous I/O or synchronous I/O. - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, - bool useAsync, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new FileStream(path, mode, access, share, bufferSize, useAsync); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified file, both inclusive. - /// - /// A relative or absolute path for the file that the stream will encapsulate. - /// One of the enumeration values that determines how to open or create the file. - /// - /// A bitwise combination of the enumeration values that determines how the file can be accessed by a - /// object. - /// - /// - /// A bitwise combination of the enumeration values that determines how the file will be shared by - /// processes. - /// - /// - /// A positive Int32 value greater than 0 indicating the buffer size. The default buffer size is - /// 4096. - /// - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, long start, - long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new FileStream(path, mode, access, share, bufferSize); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified file, both inclusive. - /// - /// A relative or absolute path for the file that the stream will encapsulate. - /// One of the enumeration values that determines how to open or create the file. - /// - /// A bitwise combination of the enumeration values that determines how the file can be accessed by a - /// object. - /// - /// - /// A bitwise combination of the enumeration values that determines how the file will be shared by - /// processes. - /// - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(string path, FileMode mode, FileAccess access, FileShare share, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new FileStream(path, mode, access, share); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified file, both inclusive. - /// - /// A relative or absolute path for the file that the stream will encapsulate. - /// One of the enumeration values that determines how to open or create the file. - /// - /// A bitwise combination of the enumeration values that determines how the file can be accessed by a - /// object. - /// - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(string path, FileMode mode, FileAccess access, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new FileStream(path, mode, access); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified file, both inclusive. - /// - /// A relative or absolute path for the file that the stream will encapsulate. - /// One of the enumeration values that determines how to open or create the file. - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(string path, FileMode mode, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new FileStream(path, mode); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified byte array, both inclusive. - /// - /// The array of unsigned bytes to add at the end of this stream. - /// The index into at which the stream begins. - /// The length in bytes to add to the end of the current stream. - /// The setting of the CanWrite property, currently ignored. - /// Currently ignored. - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(byte[] buffer, int index, int count, bool writable, bool publiclyVisible, long start, - long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new MemoryStream(buffer, index, count, writable, publiclyVisible); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified byte array, both inclusive. - /// - /// The array of unsigned bytes to add at the end of this stream. - /// The index into at which the stream begins. - /// The length in bytes to add to the end of the current stream. - /// The setting of the CanWrite property, currently ignored. - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(byte[] buffer, int index, int count, bool writable, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new MemoryStream(buffer, index, count, writable); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified byte array, both inclusive. - /// - /// The array of unsigned bytes to add at the end of this stream. - /// The index into at which the stream begins. - /// The length in bytes to add to the end of the current stream. - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(byte[] buffer, int index, int count, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new MemoryStream(buffer, index, count); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified byte array, both inclusive. - /// - /// The array of unsigned bytes to add at the end of this stream. - /// The setting of the CanWrite property, currently ignored. - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(byte[] buffer, bool writable, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new MemoryStream(buffer, writable); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - /// - /// Initializes a stream that only allows reading from to of the - /// specified byte array, both inclusive. - /// - /// The array of unsigned bytes to add at the end of this stream. - /// Start position - /// Last readable position - /// Invalid range - public OffsetStream(byte[] buffer, long start, long end) - { - if(start < 0) - throw new ArgumentOutOfRangeException(nameof(start), "Start can't be a negative number."); - - if(end < 0) - throw new ArgumentOutOfRangeException(nameof(end), "End can't be a negative number."); - - _streamStart = start; - _streamEnd = end; - - _baseStream = new MemoryStream(buffer); - - if(end > _baseStream.Length) - throw new ArgumentOutOfRangeException(nameof(end), "End is after stream end."); - - _baseStream.Position = start; - } - - /// - public override bool CanRead => _baseStream.CanRead; - - /// - public override bool CanSeek => _baseStream.CanSeek; - - /// - public override bool CanWrite => _baseStream.CanWrite; - - /// - public override long Length => _streamEnd - _streamStart + 1; - - /// - public override long Position - { - get => _baseStream.Position - _streamStart; - - set - { - if(value + _streamStart > _streamEnd) - throw new IOException("Cannot set position past stream end."); - - _baseStream.Position = value + _streamStart; - } - } - - ~OffsetStream() - { - _baseStream.Close(); - _baseStream.Dispose(); - } - - /// - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, - object state) - { - if(_baseStream.Position + count > _streamEnd) - throw new IOException("Cannot read past stream end."); - - return _baseStream.BeginRead(buffer, offset, count, callback, state); - } - - /// - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, - object state) - { - if(_baseStream.Position + count > _streamEnd) - throw new IOException("Cannot write past stream end."); - - return _baseStream.BeginWrite(buffer, offset, count, callback, state); - } - - /// - public override void Close() => _baseStream.Close(); - - /// - public override int EndRead(IAsyncResult asyncResult) => _baseStream.EndRead(asyncResult); - - /// - public override void EndWrite(IAsyncResult asyncResult) => _baseStream.EndWrite(asyncResult); - - /// - public override int ReadByte() => _baseStream.Position == _streamEnd + 1 ? -1 : _baseStream.ReadByte(); - - /// - public override void WriteByte(byte value) - { - if(_baseStream.Position + 1 > _streamEnd) - throw new IOException("Cannot write past stream end."); - - _baseStream.WriteByte(value); - } - - /// - public override void Flush() => _baseStream.Flush(); - - /// - public override int Read(byte[] buffer, int offset, int count) - { - if(_baseStream.Position + count > _streamEnd + 1) - throw new IOException("Cannot read past stream end."); - - return _baseStream.Read(buffer, offset, count); - } - - /// - public override long Seek(long offset, SeekOrigin origin) - { - switch(origin) - { - case SeekOrigin.Begin: - if(offset + _streamStart > _streamEnd) - throw new IOException("Cannot seek past stream end."); - - return _baseStream.Seek(offset + _streamStart, SeekOrigin.Begin) - _streamStart; - case SeekOrigin.End: - if(offset - (_baseStream.Length - _streamEnd) < _streamStart) - throw new IOException("Cannot seek before stream start."); - - return _baseStream.Seek(offset - (_baseStream.Length - _streamEnd), SeekOrigin.End) - _streamStart; - default: - if(offset + _baseStream.Position > _streamEnd) - throw new IOException("Cannot seek past stream end."); - - return _baseStream.Seek(offset, SeekOrigin.Current) - _streamStart; - } - } - - /// - public override void SetLength(long value) => - throw new NotSupportedException("Growing OffsetStream is not supported."); - - /// - public override void Write(byte[] buffer, int offset, int count) - { - if(_baseStream.Position + count > _streamEnd) - throw new IOException("Cannot write past stream end."); - - _baseStream.Write(buffer, offset, count); - } - } -} \ No newline at end of file diff --git a/Aaru.Filters/PCExchange.cs b/Aaru.Filters/PCExchange.cs index fef643665..9fbb672fb 100644 --- a/Aaru.Filters/PCExchange.cs +++ b/Aaru.Filters/PCExchange.cs @@ -28,11 +28,9 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filters; - using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -44,6 +42,8 @@ using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; using Marshal = System.Runtime.InteropServices.Marshal; +namespace Aaru.Filters; + /// /// Decodes PCExchange files [SuppressMessage("ReSharper", "UnusedMember.Local")] @@ -55,12 +55,16 @@ public sealed class PcExchange : IFilter string _dataPath; string _rsrcPath; +#region IFilter Members + /// - public string Name => "PCExchange"; + public string Name => Localization.PcExchange_Name; + /// public Guid Id => new("9264EB9F-D634-4F9B-BE12-C24CD44988C6"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public void Close() {} @@ -114,25 +118,24 @@ public sealed class PcExchange : IFilter parentFolder ??= ""; - if(!File.Exists(System.IO.Path.Combine(parentFolder, FINDER_INFO))) - return false; + if(!File.Exists(System.IO.Path.Combine(parentFolder, FINDER_INFO))) return false; - if(!Directory.Exists(System.IO.Path.Combine(parentFolder, RESOURCES))) - return false; + if(!Directory.Exists(System.IO.Path.Combine(parentFolder, RESOURCES))) return false; string baseFilename = System.IO.Path.GetFileName(path); var dataFound = false; var rsrcFound = false; - var finderDatStream = new FileStream(System.IO.Path.Combine(parentFolder, FINDER_INFO), FileMode.Open, + var finderDatStream = new FileStream(System.IO.Path.Combine(parentFolder, FINDER_INFO), + FileMode.Open, FileAccess.Read); while(finderDatStream.Position + 0x5C <= finderDatStream.Length) { var datEntry = new Entry(); var datEntryB = new byte[Marshal.SizeOf(datEntry)]; - finderDatStream.Read(datEntryB, 0, Marshal.SizeOf(datEntry)); + finderDatStream.EnsureRead(datEntryB, 0, Marshal.SizeOf(datEntry)); datEntry = Helpers.Marshal.ByteArrayToStructureBigEndian(datEntryB); // TODO: Add support for encoding on filters @@ -141,17 +144,15 @@ public sealed class PcExchange : IFilter var tmpDosNameB = new byte[8]; var tmpDosExtB = new byte[3]; Array.Copy(datEntry.dosName, 0, tmpDosNameB, 0, 8); - Array.Copy(datEntry.dosName, 8, tmpDosExtB, 0, 3); + Array.Copy(datEntry.dosName, 8, tmpDosExtB, 0, 3); - string dosName = Encoding.ASCII.GetString(tmpDosNameB).Trim() + "." + + string dosName = Encoding.ASCII.GetString(tmpDosNameB).Trim() + + "." + Encoding.ASCII.GetString(tmpDosExtB).Trim(); string dosNameLow = dosName.ToLower(CultureInfo.CurrentCulture); - if(baseFilename != macName && - baseFilename != dosName && - baseFilename != dosNameLow) - continue; + if(baseFilename != macName && baseFilename != dosName && baseFilename != dosNameLow) continue; dataFound |= File.Exists(System.IO.Path.Combine(parentFolder, macName ?? throw new InvalidOperationException())) || @@ -183,14 +184,15 @@ public sealed class PcExchange : IFilter parentFolder ??= ""; - var finderDatStream = new FileStream(System.IO.Path.Combine(parentFolder, FINDER_INFO), FileMode.Open, + var finderDatStream = new FileStream(System.IO.Path.Combine(parentFolder, FINDER_INFO), + FileMode.Open, FileAccess.Read); while(finderDatStream.Position + 0x5C <= finderDatStream.Length) { var datEntry = new Entry(); var datEntryB = new byte[Marshal.SizeOf(datEntry)]; - finderDatStream.Read(datEntryB, 0, Marshal.SizeOf(datEntry)); + finderDatStream.EnsureRead(datEntryB, 0, Marshal.SizeOf(datEntry)); datEntry = Helpers.Marshal.ByteArrayToStructureBigEndian(datEntryB); string macName = StringHandlers.PascalToString(datEntry.macName, Encoding.GetEncoding("macintosh")); @@ -198,17 +200,15 @@ public sealed class PcExchange : IFilter var tmpDosNameB = new byte[8]; var tmpDosExtB = new byte[3]; Array.Copy(datEntry.dosName, 0, tmpDosNameB, 0, 8); - Array.Copy(datEntry.dosName, 8, tmpDosExtB, 0, 3); + Array.Copy(datEntry.dosName, 8, tmpDosExtB, 0, 3); - string dosName = Encoding.ASCII.GetString(tmpDosNameB).Trim() + "." + + string dosName = Encoding.ASCII.GetString(tmpDosNameB).Trim() + + "." + Encoding.ASCII.GetString(tmpDosExtB).Trim(); string dosNameLow = dosName.ToLower(CultureInfo.CurrentCulture); - if(baseFilename != macName && - baseFilename != dosName && - baseFilename != dosNameLow) - continue; + if(baseFilename != macName && baseFilename != dosName && baseFilename != dosNameLow) continue; if(File.Exists(System.IO.Path.Combine(parentFolder, macName ?? throw new InvalidOperationException()))) _dataPath = System.IO.Path.Combine(parentFolder, macName); @@ -242,6 +242,10 @@ public sealed class PcExchange : IFilter return ErrorNumber.NoError; } +#endregion + +#region Nested type: Entry + [StructLayout(LayoutKind.Sequential, Pack = 1)] readonly struct Entry { @@ -278,4 +282,6 @@ public sealed class PcExchange : IFilter /// Unknown, flags? public readonly byte unknown3; } + +#endregion } \ No newline at end of file diff --git a/Aaru.Filters/Register.cs b/Aaru.Filters/Register.cs index 36e85fd0c..ec250b5b6 100644 --- a/Aaru.Filters/Register.cs +++ b/Aaru.Filters/Register.cs @@ -33,52 +33,14 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ +using Aaru.CommonTypes.Interfaces; + namespace Aaru.Filters; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Aaru.CommonTypes.Interfaces; - +// Needs to have the interface here so the source generator knows THIS IS the class +// ReSharper disable once RedundantExtendsListEntry /// -public class Register : IPluginRegister -{ - /// - public List GetAllChecksumPlugins() => null; - - /// - public List GetAllFilesystemPlugins() => null; - - /// - public List GetAllFilterPlugins() => Assembly.GetExecutingAssembly().GetTypes(). - Where(t => t.GetInterfaces().Contains(typeof(IFilter))). - Where(t => t.IsClass).ToList(); - - /// - public List GetAllFloppyImagePlugins() => null; - - /// - public List GetAllMediaImagePlugins() => null; - - /// - public List GetAllPartitionPlugins() => null; - - /// - public List GetAllReadOnlyFilesystemPlugins() => null; - - /// - public List GetAllWritableFloppyImagePlugins() => null; - - /// - public List GetAllWritableImagePlugins() => null; - - /// - public List GetAllArchivePlugins() => null; - - /// - public List GetAllByteAddressablePlugins() => null; -} \ No newline at end of file +public sealed partial class Register : IPluginRegister; \ No newline at end of file diff --git a/Aaru.Filters/XZ.cs b/Aaru.Filters/XZ.cs index 6d2ff2970..3acd09ad9 100644 --- a/Aaru.Filters/XZ.cs +++ b/Aaru.Filters/XZ.cs @@ -27,17 +27,19 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filters; - using System; using System.IO; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; +using Aaru.Helpers; +using Aaru.Helpers.IO; using SharpCompress.Compressors.Xz; +namespace Aaru.Filters; + /// /// Decompress xz files while reading public sealed class XZ : IFilter @@ -45,12 +47,16 @@ public sealed class XZ : IFilter Stream _dataStream; Stream _innerStream; +#region IFilter Members + /// - public string Name => "XZ"; + public string Name => Localization.XZ_Name; + /// public Guid Id => new("666A8617-0444-4C05-9F4F-DF0FD758D0D2"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public void Close() @@ -76,9 +82,14 @@ public sealed class XZ : IFilter public bool HasResourceFork => false; /// - public bool Identify(byte[] buffer) => buffer[0] == 0xFD && buffer[1] == 0x37 && buffer[2] == 0x7A && - buffer[3] == 0x58 && buffer[4] == 0x5A && buffer[5] == 0x00 && - buffer[^2] == 0x59 && buffer[^1] == 0x5A; + public bool Identify(byte[] buffer) => buffer[0] == 0xFD && + buffer[1] == 0x37 && + buffer[2] == 0x7A && + buffer[3] == 0x58 && + buffer[4] == 0x5A && + buffer[5] == 0x00 && + buffer[^2] == 0x59 && + buffer[^1] == 0x5A; /// public bool Identify(Stream stream) @@ -86,40 +97,49 @@ public sealed class XZ : IFilter var buffer = new byte[6]; var footer = new byte[2]; - if(stream.Length < 8) - return false; + if(stream.Length < 8) return false; stream.Seek(0, SeekOrigin.Begin); - stream.Read(buffer, 0, 6); + stream.EnsureRead(buffer, 0, 6); stream.Seek(-2, SeekOrigin.End); - stream.Read(footer, 0, 2); + stream.EnsureRead(footer, 0, 2); stream.Seek(0, SeekOrigin.Begin); - return buffer[0] == 0xFD && buffer[1] == 0x37 && buffer[2] == 0x7A && buffer[3] == 0x58 && buffer[4] == 0x5A && - buffer[5] == 0x00 && footer[0] == 0x59 && footer[1] == 0x5A; + return buffer[0] == 0xFD && + buffer[1] == 0x37 && + buffer[2] == 0x7A && + buffer[3] == 0x58 && + buffer[4] == 0x5A && + buffer[5] == 0x00 && + footer[0] == 0x59 && + footer[1] == 0x5A; } /// public bool Identify(string path) { - if(!File.Exists(path)) - return false; + if(!File.Exists(path)) return false; var stream = new FileStream(path, FileMode.Open, FileAccess.Read); var buffer = new byte[6]; var footer = new byte[2]; - if(stream.Length < 8) - return false; + if(stream.Length < 8) return false; stream.Seek(0, SeekOrigin.Begin); - stream.Read(buffer, 0, 6); + stream.EnsureRead(buffer, 0, 6); stream.Seek(-2, SeekOrigin.End); - stream.Read(footer, 0, 2); + stream.EnsureRead(footer, 0, 2); stream.Seek(0, SeekOrigin.Begin); - return buffer[0] == 0xFD && buffer[1] == 0x37 && buffer[2] == 0x7A && buffer[3] == 0x58 && buffer[4] == 0x5A && - buffer[5] == 0x00 && footer[0] == 0x59 && footer[1] == 0x5A; + return buffer[0] == 0xFD && + buffer[1] == 0x37 && + buffer[2] == 0x7A && + buffer[3] == 0x58 && + buffer[4] == 0x5A && + buffer[5] == 0x00 && + footer[0] == 0x59 && + footer[1] == 0x5A; } /// @@ -183,17 +203,19 @@ public sealed class XZ : IFilter { get { - if(BasePath?.EndsWith(".xz", StringComparison.InvariantCultureIgnoreCase) == true) - return BasePath.Substring(0, BasePath.Length - 3); + if(BasePath?.EndsWith(".xz", StringComparison.InvariantCultureIgnoreCase) == true) return BasePath[..^3]; return BasePath?.EndsWith(".xzip", StringComparison.InvariantCultureIgnoreCase) == true - ? BasePath.Substring(0, BasePath.Length - 5) : BasePath; + ? BasePath[..^5] + : BasePath; } } /// public string ParentFolder => System.IO.Path.GetDirectoryName(BasePath); +#endregion + void GuessSize() { DataForkLength = 0; @@ -201,7 +223,7 @@ public sealed class XZ : IFilter // Seek to footer backwards size field _dataStream.Seek(-8, SeekOrigin.End); var tmp = new byte[4]; - _dataStream.Read(tmp, 0, 4); + _dataStream.EnsureRead(tmp, 0, 4); uint backwardSize = (BitConverter.ToUInt32(tmp, 0) + 1) * 4; // Seek to first indexed record @@ -209,38 +231,40 @@ public sealed class XZ : IFilter // Skip compressed size tmp = new byte[backwardSize - 2]; - _dataStream.Read(tmp, 0, tmp.Length); + _dataStream.EnsureRead(tmp, 0, tmp.Length); ulong number = 0; int ignore = Decode(tmp, tmp.Length, ref number); // Get compressed size _dataStream.Seek(-12 - (backwardSize - 2 - ignore), SeekOrigin.End); tmp = new byte[backwardSize - 2 - ignore]; - _dataStream.Read(tmp, 0, tmp.Length); + _dataStream.EnsureRead(tmp, 0, tmp.Length); Decode(tmp, tmp.Length, ref number); DataForkLength = (long)number; _dataStream.Seek(0, SeekOrigin.Begin); } - int Decode(byte[] buf, int sizeMax, ref ulong num) + static int Decode(byte[] buf, int sizeMax, ref ulong num) { - if(sizeMax == 0) - return 0; + switch(sizeMax) + { + case 0: + return 0; + case > 9: + sizeMax = 9; - if(sizeMax > 9) - sizeMax = 9; + break; + } num = (ulong)(buf[0] & 0x7F); var i = 0; while((buf[i++] & 0x80) == 0x80) { - if(i >= sizeMax || - buf[i] == 0x00) - return 0; + if(i >= sizeMax || buf[i] == 0x00) return 0; - num |= (ulong)(buf[i] & 0x7F) << (i * 7); + num |= (ulong)(buf[i] & 0x7F) << i * 7; } return i; diff --git a/Aaru.Filters/ZZZNoFilter.cs b/Aaru.Filters/ZZZNoFilter.cs index 6b8cef7d9..6495508e9 100644 --- a/Aaru.Filters/ZZZNoFilter.cs +++ b/Aaru.Filters/ZZZNoFilter.cs @@ -27,28 +27,32 @@ // License along with this library; if not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Filters; - using System; using System.IO; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; +namespace Aaru.Filters; + /// /// No filter for reading files not recognized by any filter public sealed class ZZZNoFilter : IFilter { Stream _dataStream; +#region IFilter Members + /// - public string Name => "No filter"; + public string Name => Localization.ZZZNoFilter_Name; + /// public Guid Id => new("12345678-AAAA-BBBB-CCCC-123456789000"); + /// - public string Author => "Natalia Portillo"; + public string Author => Authors.NataliaPortillo; /// public void Close() @@ -74,10 +78,10 @@ public sealed class ZZZNoFilter : IFilter public bool HasResourceFork => false; /// - public bool Identify(byte[] buffer) => buffer != null && buffer.Length > 0; + public bool Identify(byte[] buffer) => buffer is { Length: > 0 }; /// - public bool Identify(Stream stream) => stream != null && stream.Length > 0; + public bool Identify(Stream stream) => stream is { Length: > 0 }; /// public bool Identify(string path) => File.Exists(path); @@ -136,4 +140,6 @@ public sealed class ZZZNoFilter : IFilter /// public string ParentFolder => System.IO.Path.GetDirectoryName(BasePath); + +#endregion } \ No newline at end of file diff --git a/Aaru.Generators/Aaru.Generators.csproj b/Aaru.Generators/Aaru.Generators.csproj new file mode 100644 index 000000000..9614ddf03 --- /dev/null +++ b/Aaru.Generators/Aaru.Generators.csproj @@ -0,0 +1,54 @@ + + + + netstandard2.0 + latest + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/Aaru.Generators/PluginRegisterGenerator.cs b/Aaru.Generators/PluginRegisterGenerator.cs new file mode 100644 index 000000000..6bfa6d162 --- /dev/null +++ b/Aaru.Generators/PluginRegisterGenerator.cs @@ -0,0 +1,405 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Aaru.Generators; + +[Generator] +public class PluginRegisterGenerator : ISourceGenerator +{ +#region ISourceGenerator Members + + /// + public void Initialize(GeneratorInitializationContext context) => + + // Nothing to do + context.RegisterForSyntaxNotifications(() => new PluginFinder()); + + /// + public void Execute(GeneratorExecutionContext context) + { + /* + #if DEBUG + if(!Debugger.IsAttached) + { + Debugger.Launch(); + } + #endif + */ + + ClassDeclarationSyntax pluginRegister = ((PluginFinder)context.SyntaxReceiver)?.Register; + + if(pluginRegister == null) return; + + var @namespace = + (pluginRegister.Ancestors().FirstOrDefault(x => x is FileScopedNamespaceDeclarationSyntax) as + FileScopedNamespaceDeclarationSyntax)?.Name.ToString(); + + @namespace ??= + (pluginRegister.Ancestors().FirstOrDefault(x => x is NamespaceDeclarationSyntax) as + NamespaceDeclarationSyntax)?.ToString(); + + string className = pluginRegister.Identifier.Text; + + List archives = ((PluginFinder)context.SyntaxReceiver)?.Archives; + List checksums = ((PluginFinder)context.SyntaxReceiver)?.Checksums; + List fileSystems = ((PluginFinder)context.SyntaxReceiver)?.FileSystems; + List filters = ((PluginFinder)context.SyntaxReceiver)?.Filters; + List floppyImagePlugins = ((PluginFinder)context.SyntaxReceiver)?.FloppyImagePlugins; + List partitionPlugins = ((PluginFinder)context.SyntaxReceiver)?.PartitionPlugins; + List mediaImagePlugins = ((PluginFinder)context.SyntaxReceiver)?.MediaImagePlugins; + List readOnlyFileSystems = ((PluginFinder)context.SyntaxReceiver)?.ReadOnlyFileSystems; + List writableFloppyImagePlugins = ((PluginFinder)context.SyntaxReceiver)?.WritableFloppyImagePlugins; + List writableImagePlugins = ((PluginFinder)context.SyntaxReceiver)?.WritableImagePlugins; + List byteAddressableImagePlugins = ((PluginFinder)context.SyntaxReceiver)?.ByteAddressableImagePlugins; + + StringBuilder sb = new(); + + sb.AppendLine(""" + // /*************************************************************************** + // Aaru Data Preservation Suite + // ---------------------------------------------------------------------------- + // + // Filename : Register.g.cs + // Author(s) : Natalia Portillo + // + // --[ Description ] ---------------------------------------------------------- + // + // Registers all plugins in this assembly. + // + // --[ License ] -------------------------------------------------------------- + // + // Permission is hereby granted, free of charge, to any person obtaining a + // copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to + // permit persons to whom the Software is furnished to do so, subject to + // the following conditions: + // + // The above copyright notice and this permission notice shall be included + // in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + // + // ---------------------------------------------------------------------------- + // Copyright © 2011-2024 Natalia Portillo + // ****************************************************************************/ + """); + + sb.AppendLine(); + sb.AppendLine("using System;"); + sb.AppendLine("using System.Collections.Generic;"); + sb.AppendLine("using Aaru.CommonTypes.Interfaces;"); + sb.AppendLine("using Microsoft.Extensions.DependencyInjection;"); + sb.AppendLine(); + sb.AppendLine($"namespace {@namespace};"); + sb.AppendLine(); + sb.AppendLine($"public sealed partial class {className} : IPluginRegister"); + sb.AppendLine("{"); + + if(archives?.Count > 0) + { + sb.AppendLine(" public void RegisterArchivePlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in archives.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterArchivePlugins(IServiceCollection services) {}"); + + sb.AppendLine(); + + if(checksums?.Count > 0) + { + sb.AppendLine(" public void RegisterChecksumPlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in checksums.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterChecksumPlugins(IServiceCollection services) {}"); + + sb.AppendLine(); + + if(fileSystems?.Count > 0) + { + sb.AppendLine(" public void RegisterFilesystemPlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in fileSystems.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterFilesystemPlugins(IServiceCollection services) {}"); + + sb.AppendLine(); + + if(filters?.Count > 0) + { + sb.AppendLine(" public void RegisterFilterPlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in filters.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterFilterPlugins(IServiceCollection services) {}"); + + sb.AppendLine(); + + if(floppyImagePlugins?.Count > 0) + { + sb.AppendLine(" public void RegisterFloppyImagePlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in floppyImagePlugins.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterFloppyImagePlugins(IServiceCollection services) {}"); + + sb.AppendLine(); + + if(mediaImagePlugins?.Count > 0) + { + sb.AppendLine(" public void RegisterMediaImagePlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in mediaImagePlugins.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterMediaImagePlugins(IServiceCollection services) {}"); + + sb.AppendLine(); + + if(partitionPlugins?.Count > 0) + { + sb.AppendLine(" public void RegisterPartitionPlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in partitionPlugins.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterPartitionPlugins(IServiceCollection services) {}"); + + sb.AppendLine(); + + if(readOnlyFileSystems?.Count > 0) + { + sb.AppendLine(" public void RegisterReadOnlyFilesystemPlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in readOnlyFileSystems.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterReadOnlyFilesystemPlugins(IServiceCollection services) {}"); + + sb.AppendLine(); + + if(writableFloppyImagePlugins?.Count > 0) + { + sb.AppendLine(" public void RegisterWritableFloppyImagePlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in writableFloppyImagePlugins.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterWritableFloppyImagePlugins(IServiceCollection services) {}"); + + sb.AppendLine(); + + if(writableImagePlugins?.Count > 0) + { + sb.AppendLine(" public void RegisterWritableImagePlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in writableImagePlugins.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterWritableImagePlugins(IServiceCollection services) {}"); + + sb.AppendLine(); + + if(byteAddressableImagePlugins?.Count > 0) + { + sb.AppendLine(" public void RegisterByteAddressablePlugins(IServiceCollection services)"); + sb.AppendLine(" {"); + + foreach(string plugin in byteAddressableImagePlugins.Distinct()) + sb.AppendLine($" services.AddTransient();"); + + sb.AppendLine(" }"); + } + else + sb.AppendLine(" public void RegisterByteAddressablePlugins(IServiceCollection services) {}"); + + sb.AppendLine("}"); + + context.AddSource("Register.g.cs", sb.ToString()); + } + +#endregion + +#region Nested type: PluginFinder + + sealed class PluginFinder : ISyntaxReceiver + { + public List Archives { get; } = []; + public List Checksums { get; } = []; + public List FileSystems { get; } = []; + public List Filters { get; } = []; + public List FloppyImagePlugins { get; } = []; + public List MediaImagePlugins { get; } = []; + public List PartitionPlugins { get; } = []; + public List ReadOnlyFileSystems { get; } = []; + public List WritableFloppyImagePlugins { get; } = []; + public List WritableImagePlugins { get; } = []; + public List ByteAddressableImagePlugins { get; } = []; + public ClassDeclarationSyntax Register { get; private set; } + +#region ISyntaxReceiver Members + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if(syntaxNode is not ClassDeclarationSyntax plugin) return; + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText == + "IPluginRegister") == + true) + Register = plugin; + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText == + "IArchive") == + true) + if(!Archives.Contains(plugin.Identifier.Text)) + Archives.Add(plugin.Identifier.Text); + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText == + "IChecksum") == + true) + if(!Checksums.Contains(plugin.Identifier.Text)) + Checksums.Add(plugin.Identifier.Text); + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText == + "IFilesystem") == + true) + if(!FileSystems.Contains(plugin.Identifier.Text)) + FileSystems.Add(plugin.Identifier.Text); + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText == + "IFilter") == + true) + if(!Filters.Contains(plugin.Identifier.Text)) + Filters.Add(plugin.Identifier.Text); + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText == + "IFloppyImage") == + true) + if(!FloppyImagePlugins.Contains(plugin.Identifier.Text)) + FloppyImagePlugins.Add(plugin.Identifier.Text); + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText is "IMediaImage" + or "IOpticalMediaImage" + or "IFloppyImage" + or "ITapeImage") == + true) + if(!MediaImagePlugins.Contains(plugin.Identifier.Text)) + MediaImagePlugins.Add(plugin.Identifier.Text); + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText == + "IPartition") == + true) + if(!PartitionPlugins.Contains(plugin.Identifier.Text)) + PartitionPlugins.Add(plugin.Identifier.Text); + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText == + "IReadOnlyFilesystem") == + true) + { + if(!ReadOnlyFileSystems.Contains(plugin.Identifier.Text)) + ReadOnlyFileSystems.Add(plugin.Identifier.Text); + } + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText == + "IWritableFloppyImage") == + true) + { + if(!WritableFloppyImagePlugins.Contains(plugin.Identifier.Text)) + WritableFloppyImagePlugins.Add(plugin.Identifier.Text); + } + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText is "IWritableImage" + or "IWritableOpticalImage" + or "IWritableTapeImage" + or "IByteAddressableImage") == + true) + { + if(!WritableImagePlugins.Contains(plugin.Identifier.Text)) + WritableImagePlugins.Add(plugin.Identifier.Text); + } + + if(plugin.BaseList?.Types.Any(t => ((t as SimpleBaseTypeSyntax)?.Type as IdentifierNameSyntax)?.Identifier + .ValueText == + "IByteAddressableImage") == + true) + { + if(!ByteAddressableImagePlugins.Contains(plugin.Identifier.Text)) + ByteAddressableImagePlugins.Add(plugin.Identifier.Text); + } + + MediaImagePlugins.AddRange(WritableImagePlugins.Where(t => !ByteAddressableImagePlugins.Contains(t))); + FileSystems.AddRange(ReadOnlyFileSystems); + } + +#endregion + } + +#endregion +} \ No newline at end of file diff --git a/Aaru.Gui/Aaru.Gui.csproj b/Aaru.Gui/Aaru.Gui.csproj index da064d918..7a2ee28b3 100644 --- a/Aaru.Gui/Aaru.Gui.csproj +++ b/Aaru.Gui/Aaru.Gui.csproj @@ -1,452 +1,482 @@  - - Aaru.Gui - Aaru.Gui - $(Version) - true - 6.0.0-alpha8 - Claunia.com - Copyright © 2011-2022 Natalia Portillo - Aaru Data Preservation Suite - Aaru Data Preservation Suite - $(Version) - net6.0 - CS0649,CS0169 - 10 - Natalia Portillo <claunia@claunia.com> - true - - - $(Version)+{chash:8} built by {mname} in $(Configuration){!:, modified} - true - true - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - %(Filename) - - - Designer - - - - Designer - - - Designer - - - Designer - - - Designer - - - Designer - - - About.xaml - - - Console.xaml - - - Encodings.xaml - - - DeviceInfo.xaml - - - FileSystem.xaml - - - ImageInfo.xaml - - - MediaInfo.xaml - - - Partition.xaml - - - Subdirectory.xaml - - - AtaInfo.xaml - - - BlurayInfo.xaml - - - CompactDiscInfo.xaml - - - DvdInfo.xaml - - - DvdWritableInfo.xaml - - - PcmciaInfo.xaml - - - ScsiInfo.xaml - - - XboxInfo.xaml - - - DecodeMediaTags.xaml - - - ImageChecksum.xaml - - - ImageConvert.xaml - - - ImageEntropy.xaml - - - ImageSidecar.xaml - - - ImageVerify.xaml - - - MediaDump.xaml - - - MediaScan.xaml - - - ViewSector.xaml - - - - - - - - LICENSE - - - - - - - /Library/Frameworks/Mono.framework/Versions/Current/lib/mono - /usr/lib/mono - /usr/local/lib/mono - - $(BaseFrameworkPathOverrideForMono)/4.0-api - $(BaseFrameworkPathOverrideForMono)/4.5-api - $(BaseFrameworkPathOverrideForMono)/4.5.1-api - $(BaseFrameworkPathOverrideForMono)/4.5.2-api - $(BaseFrameworkPathOverrideForMono)/4.6-api - $(BaseFrameworkPathOverrideForMono)/4.6.1-api - $(BaseFrameworkPathOverrideForMono)/4.6.2-api - $(BaseFrameworkPathOverrideForMono)/4.7-api - $(BaseFrameworkPathOverrideForMono)/4.7.1-api - true - - $(FrameworkPathOverride)/Facades;$(AssemblySearchPaths) - + + Aaru.Gui + Aaru.Gui + $(Version) + true + 6.0.0-alpha9 + Claunia.com + Copyright © 2011-2024 Natalia Portillo + Aaru Data Preservation Suite + Aaru Data Preservation Suite + $(Version) + net8.0 + CS0649,CS0169 + 12 + Natalia Portillo <claunia@claunia.com> + true + true + + + CS1591;CS1574 + + + + + + + $(Version)+{chash:8} built by {mname} in $(Configuration){!:, modified} + true + true + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %(Filename) + + + Designer + + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + About.xaml + + + Console.xaml + + + Encodings.xaml + + + DeviceInfo.xaml + + + FileSystem.xaml + + + ImageInfo.xaml + + + MediaInfo.xaml + + + Partition.xaml + + + Subdirectory.xaml + + + AtaInfo.xaml + + + BlurayInfo.xaml + + + CompactDiscInfo.xaml + + + DvdInfo.xaml + + + DvdWritableInfo.xaml + + + PcmciaInfo.xaml + + + ScsiInfo.xaml + + + XboxInfo.xaml + + + DecodeMediaTags.xaml + + + ImageChecksum.xaml + + + ImageConvert.xaml + + + ImageEntropy.xaml + + + ImageSidecar.xaml + + + ImageVerify.xaml + + + MediaDump.xaml + + + MediaScan.xaml + + + ViewSector.xaml + + + + + + + + LICENSE + + \ No newline at end of file diff --git a/Aaru.Gui/App.xaml b/Aaru.Gui/App.xaml index 3051f633a..a42e0dc8a 100644 --- a/Aaru.Gui/App.xaml +++ b/Aaru.Gui/App.xaml @@ -28,25 +28,30 @@ // along with this program. If not, see . // // ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ -// Copyright © 2011‐2020 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ --> - + - - - + + - - - + + + \ No newline at end of file diff --git a/Aaru.Gui/App.xaml.cs b/Aaru.Gui/App.xaml.cs index 7634ba224..34f8e7539 100644 --- a/Aaru.Gui/App.xaml.cs +++ b/Aaru.Gui/App.xaml.cs @@ -27,16 +27,12 @@ // along with this program. If not, see . // // ---------------------------------------------------------------------------- -// Copyright © 2011-2022 Natalia Portillo +// Copyright © 2011-2024 Natalia Portillo // ****************************************************************************/ - - // ReSharper disable UnusedMember.Local // ReSharper disable UnusedParameter.Local -namespace Aaru.Gui; - using System; using Aaru.Gui.ViewModels.Windows; using Aaru.Gui.Views.Windows; @@ -45,6 +41,8 @@ using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; +namespace Aaru.Gui; + public sealed class App : Application { public override void Initialize() => AvaloniaXamlLoader.Load(this); @@ -65,8 +63,7 @@ public sealed class App : Application void OnSplashFinished(object sender, EventArgs e) { - if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)) - return; + if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return; // Ensure not exit desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown; @@ -85,10 +82,13 @@ public sealed class App : Application void OnAboutClicked(object sender, EventArgs args) { - if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime - { - MainWindow: MainWindow { DataContext: MainWindowViewModel mainWindowViewModel } - })) + if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime + { + MainWindow: MainWindow + { + DataContext: MainWindowViewModel mainWindowViewModel + } + }) return; mainWindowViewModel.ExecuteAboutCommand(); @@ -96,10 +96,13 @@ public sealed class App : Application void OnQuitClicked(object sender, EventArgs args) { - if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime - { - MainWindow: MainWindow { DataContext: MainWindowViewModel mainWindowViewModel } - })) + if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime + { + MainWindow: MainWindow + { + DataContext: MainWindowViewModel mainWindowViewModel + } + }) return; mainWindowViewModel.ExecuteExitCommand(); @@ -107,10 +110,13 @@ public sealed class App : Application void OnPreferencesClicked(object sender, EventArgs args) { - if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime - { - MainWindow: MainWindow { DataContext: MainWindowViewModel mainWindowViewModel } - })) + if(ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime + { + MainWindow: MainWindow + { + DataContext: MainWindowViewModel mainWindowViewModel + } + }) return; mainWindowViewModel.ExecuteSettingsCommand(); diff --git a/Aaru.Gui/Assets/Logos/Media/AIT1.svg b/Aaru.Gui/Assets/Logos/Media/AIT1.svg index e523af994..9116d5024 100644 --- a/Aaru.Gui/Assets/Logos/Media/AIT1.svg +++ b/Aaru.Gui/Assets/Logos/Media/AIT1.svg @@ -5,7 +5,7 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - + @@ -32,75 +32,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/AIT1Turbo.svg b/Aaru.Gui/Assets/Logos/Media/AIT1Turbo.svg index e523af994..9116d5024 100644 --- a/Aaru.Gui/Assets/Logos/Media/AIT1Turbo.svg +++ b/Aaru.Gui/Assets/Logos/Media/AIT1Turbo.svg @@ -5,7 +5,7 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - + @@ -32,75 +32,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/AIT2.svg b/Aaru.Gui/Assets/Logos/Media/AIT2.svg index e523af994..9116d5024 100644 --- a/Aaru.Gui/Assets/Logos/Media/AIT2.svg +++ b/Aaru.Gui/Assets/Logos/Media/AIT2.svg @@ -5,7 +5,7 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - + @@ -32,75 +32,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/AIT2Turbo.svg b/Aaru.Gui/Assets/Logos/Media/AIT2Turbo.svg index e523af994..9116d5024 100644 --- a/Aaru.Gui/Assets/Logos/Media/AIT2Turbo.svg +++ b/Aaru.Gui/Assets/Logos/Media/AIT2Turbo.svg @@ -5,7 +5,7 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - + @@ -32,75 +32,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/AIT3.svg b/Aaru.Gui/Assets/Logos/Media/AIT3.svg index e523af994..9116d5024 100644 --- a/Aaru.Gui/Assets/Logos/Media/AIT3.svg +++ b/Aaru.Gui/Assets/Logos/Media/AIT3.svg @@ -5,7 +5,7 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - + @@ -32,75 +32,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/AIT3Ex.svg b/Aaru.Gui/Assets/Logos/Media/AIT3Ex.svg index e523af994..9116d5024 100644 --- a/Aaru.Gui/Assets/Logos/Media/AIT3Ex.svg +++ b/Aaru.Gui/Assets/Logos/Media/AIT3Ex.svg @@ -5,7 +5,7 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - + @@ -32,75 +32,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/AIT3Turbo.svg b/Aaru.Gui/Assets/Logos/Media/AIT3Turbo.svg index e523af994..9116d5024 100644 --- a/Aaru.Gui/Assets/Logos/Media/AIT3Turbo.svg +++ b/Aaru.Gui/Assets/Logos/Media/AIT3Turbo.svg @@ -5,7 +5,7 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - + @@ -32,75 +32,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/AIT4.svg b/Aaru.Gui/Assets/Logos/Media/AIT4.svg index e523af994..9116d5024 100644 --- a/Aaru.Gui/Assets/Logos/Media/AIT4.svg +++ b/Aaru.Gui/Assets/Logos/Media/AIT4.svg @@ -5,7 +5,7 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - + @@ -32,75 +32,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/AIT5.svg b/Aaru.Gui/Assets/Logos/Media/AIT5.svg index e523af994..9116d5024 100644 --- a/Aaru.Gui/Assets/Logos/Media/AIT5.svg +++ b/Aaru.Gui/Assets/Logos/Media/AIT5.svg @@ -5,7 +5,7 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - + @@ -32,75 +32,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/AITETurbo.svg b/Aaru.Gui/Assets/Logos/Media/AITETurbo.svg index e523af994..9116d5024 100644 --- a/Aaru.Gui/Assets/Logos/Media/AITETurbo.svg +++ b/Aaru.Gui/Assets/Logos/Media/AITETurbo.svg @@ -5,7 +5,7 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - + @@ -32,75 +32,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/BDR.svg b/Aaru.Gui/Assets/Logos/Media/BDR.svg index 867965521..8e0756e16 100644 --- a/Aaru.Gui/Assets/Logos/Media/BDR.svg +++ b/Aaru.Gui/Assets/Logos/Media/BDR.svg @@ -5,55 +5,55 @@ enable-background="new -0.744 82.256 386 207" xml:space="preserve" style="overflow:visible">image/svg+xml - - + + - - - - - - - - - - - - - - - + d="m 91.59,237.719 c -0.693,0 -3.053,0.693 -5.135,3.746 -2.081,3.053 -11.518,18.596 -13.183,21.51 -1.805,2.914 -1.249,4.164 0.693,4.164 1.665,0 2.082,0 4.163,0 1.943,0 3.747,-2.221 4.441,-3.748 0.972,-1.387 12.073,-19.428 13.877,-22.063 1.526,-2.638 0.556,-3.607 -0.694,-3.607 -1.108,-0.002 -4.162,-0.002 -4.162,-0.002 z" + id="path2" style="fill:#0095d5"/> + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/BDRE.svg b/Aaru.Gui/Assets/Logos/Media/BDRE.svg index 867965521..8e0756e16 100644 --- a/Aaru.Gui/Assets/Logos/Media/BDRE.svg +++ b/Aaru.Gui/Assets/Logos/Media/BDRE.svg @@ -5,55 +5,55 @@ enable-background="new -0.744 82.256 386 207" xml:space="preserve" style="overflow:visible">image/svg+xml - - + + - - - - - - - - - - - - - - - + d="m 91.59,237.719 c -0.693,0 -3.053,0.693 -5.135,3.746 -2.081,3.053 -11.518,18.596 -13.183,21.51 -1.805,2.914 -1.249,4.164 0.693,4.164 1.665,0 2.082,0 4.163,0 1.943,0 3.747,-2.221 4.441,-3.748 0.972,-1.387 12.073,-19.428 13.877,-22.063 1.526,-2.638 0.556,-3.607 -0.694,-3.607 -1.108,-0.002 -4.162,-0.002 -4.162,-0.002 z" + id="path2" style="fill:#0095d5"/> + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/BDREXL.svg b/Aaru.Gui/Assets/Logos/Media/BDREXL.svg index 867965521..8e0756e16 100644 --- a/Aaru.Gui/Assets/Logos/Media/BDREXL.svg +++ b/Aaru.Gui/Assets/Logos/Media/BDREXL.svg @@ -5,55 +5,55 @@ enable-background="new -0.744 82.256 386 207" xml:space="preserve" style="overflow:visible">image/svg+xml - - + + - - - - - - - - - - - - - - - + d="m 91.59,237.719 c -0.693,0 -3.053,0.693 -5.135,3.746 -2.081,3.053 -11.518,18.596 -13.183,21.51 -1.805,2.914 -1.249,4.164 0.693,4.164 1.665,0 2.082,0 4.163,0 1.943,0 3.747,-2.221 4.441,-3.748 0.972,-1.387 12.073,-19.428 13.877,-22.063 1.526,-2.638 0.556,-3.607 -0.694,-3.607 -1.108,-0.002 -4.162,-0.002 -4.162,-0.002 z" + id="path2" style="fill:#0095d5"/> + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/BDROM.svg b/Aaru.Gui/Assets/Logos/Media/BDROM.svg index 867965521..8e0756e16 100644 --- a/Aaru.Gui/Assets/Logos/Media/BDROM.svg +++ b/Aaru.Gui/Assets/Logos/Media/BDROM.svg @@ -5,55 +5,55 @@ enable-background="new -0.744 82.256 386 207" xml:space="preserve" style="overflow:visible">image/svg+xml - - + + - - - - - - - - - - - - - - - + d="m 91.59,237.719 c -0.693,0 -3.053,0.693 -5.135,3.746 -2.081,3.053 -11.518,18.596 -13.183,21.51 -1.805,2.914 -1.249,4.164 0.693,4.164 1.665,0 2.082,0 4.163,0 1.943,0 3.747,-2.221 4.441,-3.748 0.972,-1.387 12.073,-19.428 13.877,-22.063 1.526,-2.638 0.556,-3.607 -0.694,-3.607 -1.108,-0.002 -4.162,-0.002 -4.162,-0.002 z" + id="path2" style="fill:#0095d5"/> + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/BDRXL.svg b/Aaru.Gui/Assets/Logos/Media/BDRXL.svg index 867965521..8e0756e16 100644 --- a/Aaru.Gui/Assets/Logos/Media/BDRXL.svg +++ b/Aaru.Gui/Assets/Logos/Media/BDRXL.svg @@ -5,55 +5,55 @@ enable-background="new -0.744 82.256 386 207" xml:space="preserve" style="overflow:visible">image/svg+xml - - + + - - - - - - - - - - - - - - - + d="m 91.59,237.719 c -0.693,0 -3.053,0.693 -5.135,3.746 -2.081,3.053 -11.518,18.596 -13.183,21.51 -1.805,2.914 -1.249,4.164 0.693,4.164 1.665,0 2.082,0 4.163,0 1.943,0 3.747,-2.221 4.441,-3.748 0.972,-1.387 12.073,-19.428 13.877,-22.063 1.526,-2.638 0.556,-3.607 -0.694,-3.607 -1.108,-0.002 -4.162,-0.002 -4.162,-0.002 z" + id="path2" style="fill:#0095d5"/> + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/CD.svg b/Aaru.Gui/Assets/Logos/Media/CD.svg index c32d52d58..a8f4e9225 100644 --- a/Aaru.Gui/Assets/Logos/Media/CD.svg +++ b/Aaru.Gui/Assets/Logos/Media/CD.svg @@ -4,33 +4,33 @@ viewBox="0 0 4.4973901 2.17768" version="1.0" width="4.4973903in" height="2.17768in" xml:space="preserve">image/svg+xml - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Digital Audio Tape + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Digital Audio Tape \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/DAT320.svg b/Aaru.Gui/Assets/Logos/Media/DAT320.svg index 73c18c6a3..57d6784c7 100644 --- a/Aaru.Gui/Assets/Logos/Media/DAT320.svg +++ b/Aaru.Gui/Assets/Logos/Media/DAT320.svg @@ -6,7 +6,7 @@ height="155.23462" width="272.0712" xml:space="preserve">image/svg+xml - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Digital Audio Tape + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Digital Audio Tape \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/DAT72.svg b/Aaru.Gui/Assets/Logos/Media/DAT72.svg index 73c18c6a3..57d6784c7 100644 --- a/Aaru.Gui/Assets/Logos/Media/DAT72.svg +++ b/Aaru.Gui/Assets/Logos/Media/DAT72.svg @@ -6,7 +6,7 @@ height="155.23462" width="272.0712" xml:space="preserve">image/svg+xml - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Digital Audio Tape + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Digital Audio Tape \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/DDS1.svg b/Aaru.Gui/Assets/Logos/Media/DDS1.svg index e93c08f81..50fc467be 100644 --- a/Aaru.Gui/Assets/Logos/Media/DDS1.svg +++ b/Aaru.Gui/Assets/Logos/Media/DDS1.svg @@ -2,44 +2,44 @@ - - - - image/svg+xml - - - - - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DDS2.svg b/Aaru.Gui/Assets/Logos/Media/DDS2.svg index e93c08f81..50fc467be 100644 --- a/Aaru.Gui/Assets/Logos/Media/DDS2.svg +++ b/Aaru.Gui/Assets/Logos/Media/DDS2.svg @@ -2,44 +2,44 @@ - - - - image/svg+xml - - - - - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DDS3.svg b/Aaru.Gui/Assets/Logos/Media/DDS3.svg index e93c08f81..50fc467be 100644 --- a/Aaru.Gui/Assets/Logos/Media/DDS3.svg +++ b/Aaru.Gui/Assets/Logos/Media/DDS3.svg @@ -2,44 +2,44 @@ - - - - image/svg+xml - - - - - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DDS4.svg b/Aaru.Gui/Assets/Logos/Media/DDS4.svg index e93c08f81..50fc467be 100644 --- a/Aaru.Gui/Assets/Logos/Media/DDS4.svg +++ b/Aaru.Gui/Assets/Logos/Media/DDS4.svg @@ -2,44 +2,44 @@ - - - - image/svg+xml - - - - - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DLTtapeIII.svg b/Aaru.Gui/Assets/Logos/Media/DLTtapeIII.svg index 06aa58aff..5efd543ae 100644 --- a/Aaru.Gui/Assets/Logos/Media/DLTtapeIII.svg +++ b/Aaru.Gui/Assets/Logos/Media/DLTtapeIII.svg @@ -2,31 +2,31 @@ - - - - image/svg+xml - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DLTtapeIIIxt.svg b/Aaru.Gui/Assets/Logos/Media/DLTtapeIIIxt.svg index 06aa58aff..5efd543ae 100644 --- a/Aaru.Gui/Assets/Logos/Media/DLTtapeIIIxt.svg +++ b/Aaru.Gui/Assets/Logos/Media/DLTtapeIIIxt.svg @@ -2,31 +2,31 @@ - - - - image/svg+xml - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DLTtapeIV.svg b/Aaru.Gui/Assets/Logos/Media/DLTtapeIV.svg index 06aa58aff..5efd543ae 100644 --- a/Aaru.Gui/Assets/Logos/Media/DLTtapeIV.svg +++ b/Aaru.Gui/Assets/Logos/Media/DLTtapeIV.svg @@ -2,31 +2,31 @@ - - - - image/svg+xml - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DLTtapeS4.svg b/Aaru.Gui/Assets/Logos/Media/DLTtapeS4.svg index 06aa58aff..5efd543ae 100644 --- a/Aaru.Gui/Assets/Logos/Media/DLTtapeS4.svg +++ b/Aaru.Gui/Assets/Logos/Media/DLTtapeS4.svg @@ -2,31 +2,31 @@ - - - - image/svg+xml - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DVDDownload.svg b/Aaru.Gui/Assets/Logos/Media/DVDDownload.svg index f486420b7..e25ee8bbd 100644 --- a/Aaru.Gui/Assets/Logos/Media/DVDDownload.svg +++ b/Aaru.Gui/Assets/Logos/Media/DVDDownload.svg @@ -2,23 +2,23 @@ - - - - image/svg+xml - - DVD logo - - - - - DVD logo - - - - + + + + image/svg+xml + + DVD logo + + + + + DVD logo + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DVDPR.svg b/Aaru.Gui/Assets/Logos/Media/DVDPR.svg index 7dcc7121b..f0ece5aa3 100644 --- a/Aaru.Gui/Assets/Logos/Media/DVDPR.svg +++ b/Aaru.Gui/Assets/Logos/Media/DVDPR.svg @@ -5,20 +5,20 @@ id="metadata8">image/svg+xml - - + \ No newline at end of file + id="path16" style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="M 77.3242,0 69.8594,23.2344 H 74.418 L 80.6406,3.68359 h 0.0664 l 6.2305,19.55081 h 4.6172 L 84.0195,0 h -6.6953"/> \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/DVDPRDL.svg b/Aaru.Gui/Assets/Logos/Media/DVDPRDL.svg index c02238464..42b1d3df5 100644 --- a/Aaru.Gui/Assets/Logos/Media/DVDPRDL.svg +++ b/Aaru.Gui/Assets/Logos/Media/DVDPRDL.svg @@ -5,8 +5,8 @@ id="metadata8">image/svg+xml - - + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/DVDPRW.svg b/Aaru.Gui/Assets/Logos/Media/DVDPRW.svg index 423e2a0e6..83b44b108 100644 --- a/Aaru.Gui/Assets/Logos/Media/DVDPRW.svg +++ b/Aaru.Gui/Assets/Logos/Media/DVDPRW.svg @@ -5,8 +5,8 @@ id="metadata8">image/svg+xml - - + - - - - image/svg+xml - - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DVDRAM.svg b/Aaru.Gui/Assets/Logos/Media/DVDRAM.svg index a85f0a1a2..f65125457 100644 --- a/Aaru.Gui/Assets/Logos/Media/DVDRAM.svg +++ b/Aaru.Gui/Assets/Logos/Media/DVDRAM.svg @@ -5,25 +5,25 @@ id="metadata8">image/svg+xml - - - - - - - - \ No newline at end of file + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/DVDROM.svg b/Aaru.Gui/Assets/Logos/Media/DVDROM.svg index 14608d221..1fc279254 100644 --- a/Aaru.Gui/Assets/Logos/Media/DVDROM.svg +++ b/Aaru.Gui/Assets/Logos/Media/DVDROM.svg @@ -1,20 +1,20 @@ - - - - - - - - - + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DVDRW.svg b/Aaru.Gui/Assets/Logos/Media/DVDRW.svg index 0dbb72b68..dc6c7919b 100644 --- a/Aaru.Gui/Assets/Logos/Media/DVDRW.svg +++ b/Aaru.Gui/Assets/Logos/Media/DVDRW.svg @@ -2,34 +2,34 @@ - - - - image/svg+xml - - - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DigitalAudioTape.svg b/Aaru.Gui/Assets/Logos/Media/DigitalAudioTape.svg index 73c18c6a3..57d6784c7 100644 --- a/Aaru.Gui/Assets/Logos/Media/DigitalAudioTape.svg +++ b/Aaru.Gui/Assets/Logos/Media/DigitalAudioTape.svg @@ -6,7 +6,7 @@ height="155.23462" width="272.0712" xml:space="preserve">image/svg+xml - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Digital Audio Tape + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Digital Audio Tape \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/Ditto.svg b/Aaru.Gui/Assets/Logos/Media/Ditto.svg index d0e0295c9..2e2ada61f 100644 --- a/Aaru.Gui/Assets/Logos/Media/Ditto.svg +++ b/Aaru.Gui/Assets/Logos/Media/Ditto.svg @@ -2,20 +2,20 @@ - - - - image/svg+xml - - - - - - - - + + + + image/svg+xml + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/DittoMax.svg b/Aaru.Gui/Assets/Logos/Media/DittoMax.svg index d0e0295c9..2e2ada61f 100644 --- a/Aaru.Gui/Assets/Logos/Media/DittoMax.svg +++ b/Aaru.Gui/Assets/Logos/Media/DittoMax.svg @@ -2,20 +2,20 @@ - - - - image/svg+xml - - - - - - - - + + + + image/svg+xml + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/ExpressCard34.svg b/Aaru.Gui/Assets/Logos/Media/ExpressCard34.svg index a99c5c9d0..75140478d 100644 --- a/Aaru.Gui/Assets/Logos/Media/ExpressCard34.svg +++ b/Aaru.Gui/Assets/Logos/Media/ExpressCard34.svg @@ -2,34 +2,34 @@ - - - - image/svg+xml - - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/ExpressCard54.svg b/Aaru.Gui/Assets/Logos/Media/ExpressCard54.svg index a99c5c9d0..75140478d 100644 --- a/Aaru.Gui/Assets/Logos/Media/ExpressCard54.svg +++ b/Aaru.Gui/Assets/Logos/Media/ExpressCard54.svg @@ -2,34 +2,34 @@ - - - - image/svg+xml - - - - - - - - - - - - - + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/Aaru.Gui/Assets/Logos/Media/GDR.svg b/Aaru.Gui/Assets/Logos/Media/GDR.svg index 39e7155af..7245a1eda 100644 --- a/Aaru.Gui/Assets/Logos/Media/GDR.svg +++ b/Aaru.Gui/Assets/Logos/Media/GDR.svg @@ -5,27 +5,27 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/GDROM.svg b/Aaru.Gui/Assets/Logos/Media/GDROM.svg index 39e7155af..7245a1eda 100644 --- a/Aaru.Gui/Assets/Logos/Media/GDROM.svg +++ b/Aaru.Gui/Assets/Logos/Media/GDROM.svg @@ -5,27 +5,27 @@ x="0px" id="Layer_1" version="1.1">image/svg+xml - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/Aaru.Gui/Assets/Logos/Media/GOD.svg b/Aaru.Gui/Assets/Logos/Media/GOD.svg index 27c5e7b12..242bb503d 100644 --- a/Aaru.Gui/Assets/Logos/Media/GOD.svg +++ b/Aaru.Gui/Assets/Logos/Media/GOD.svg @@ -5,8 +5,8 @@ version="1.1">image/svg+xml - - - + - - - - - + d="M47.7,386.2v8.8H11.5v22.4h26.4v-6.2H22.6v-9.4h25.7c0,0,0,10.2,0,17.1c-0.1,2.9-5.8,8.6-9,8.6c-5.9,0-22,0-29.5,0 c-4.2,0-9.9-5.7-9.9-8.6c0-8.7,0-17.3,0-24.7c0-4.8,3.1-8,7.2-8C14,386.2,47.7,386.2,47.7,386.2z"/> + + + + + + d="M350,409.9v10.6c0,3.7-2.8,6.5-11.3,6.5c-7.6,0-33.2,0-33.2,0v-41.3c0,0,33.6,0,38.8,0c3.6,0,5.6,2.1,5.6,5.7 c0,2.9,0,10.1,0,11.3c0,0.9-1.2,2.4-4,2.4c0,0.2,0,0,0,0.8C347.9,405.9,350,408,350,409.9z M339.5,416.4c0-1,0-3.5,0-4.8 c0-1.3-0.3-1.7-0.8-1.7c-1,0-21.8,0-21.8,0v7.3c0,0,15.7,0,21,0C339.1,417.2,339.5,416.8,339.5,416.4z M339.5,400.2 c0-1,0-3.5,0-4.8c0-1.3-0.3-1.6-0.8-1.6c-1,0-21.8,0-21.8,0v7.3c0,0,15.7,0,21,0C339.1,401,339.5,400.6,339.5,400.2z"/> - - - + + + - + - - - - - - + points="8.7,343.6 8.7,374.3 14.4,374.3 14.4,351.7 26.5,374.3 32.9,374.3 32.9,343.6 26.5,343.6 26.5,362.1 16.8,343.6 "/> + + + + + + + d="M336.4,349.3v19.5c0,1.5-4.2,5.6-6.6,5.6c-4.9,0-17.7,0-17.7,0v-30.8c0,0,12.6,0,16.1,0 C333.2,343.6,336.4,346.8,336.4,349.3z M330.6,367.1c0-2.1,0-11.7,0-16.1c0-0.6-1.9-2.5-3.2-2.5c-2.5,0-9.7,0-9.7,0v21.8 c0,0,6.9,0,9.7,0C328.4,370.3,330.6,368.1,330.6,367.1z"/> - + + d="M388.9,350.9c0,2.2,0,11.7,0,16.1c0,4.6-3.5,8.1-8.8,8.1c0,0,0,0-0.1,0c-4.6,0-3.3,0-8.1,0h-0.1c-5.2,0-8.6-3.2-8.8-7.7 c0-0.2,0-0.3,0-0.5c0-3.1,0-13.1,0-16.1c0-0.6,0-0.9,0-0.9c0-3.1,3.3-6.4,7.3-6.4c2.9,0,11.3,0,11.3,0 C386.3,343.6,388.9,346.1,388.9,350.9z M382.4,366.3c0-0.8,0-13.2,0-14.6c0-1.2-2.1-3.3-3.2-3.3c-1.2,0-6.4,0-6.4,0 c-1.7,0-3.3,1.6-3.3,3.1c0,1,0,13.2,0,14.7c0,2.3,0.9,3.2,2.5,3.2c1.4,0,5.4,0,7.3,0C380.8,369.5,382.4,367.8,382.4,366.3z"/> - + - + + x1="122.3997" gradientUnits="userSpaceOnUse" id="SVGID_1_"> - + - + - + + class="st1"/> - + - + - + - + + x1="197.8562" gradientUnits="userSpaceOnUse" id="SVGID_2_"> - + - + -